K8s快速入門
1 介紹
- google開源的容器化管理工具
- 機器數(shù)量十幾臺、上百臺時,就可以考慮使用k8s
- 高可用、自動容災恢復、灰度更新、一鍵回滾歷史版本、方便伸縮擴展等
k8s集群架構:
通常:一主多從
- master:主節(jié)點,控制平臺,不需要很高性能,不跑任務,通常一個就行了,也可以開多個主節(jié)點來提高集群可用度。
- worker:工作節(jié)點,可以是虛擬機或物理計算機,任務都在這里跑,機器性能需要好點;通常都有很多個,可以不斷加機器擴大集群;每個工作節(jié)點由主節(jié)點管理
k8s中重要概念:
- pod
豆莢,K8S 調度、管理的最小單位,一個 Pod 可以包含一個或多個容器,每個 Pod 有自己的虛擬IP。一個工作節(jié)點可以有多個 pod,主節(jié)點會考量負載自動調度 pod 到哪個節(jié)點運行。
- k8s組件
- kube-apiserver: API服務器,公開了k8s API
- etcd:鍵值數(shù)據(jù)庫(類比redis),保存所有集群的數(shù)據(jù)
- kube-scheduler:調用Pod到哪個節(jié)點運行
- kube-controller:集群控制器
- cloud-controller:與云服務商交互
2 安裝k8s集群
k8s-集群搭建的三種方式,目前主流的搭建k8s集群的方式有kubeadm、minikube,二進制包。
- kubeadm
- 是一個工具,用于快速搭建kubernetes集群,目前應該是比較方便和推薦的,簡單易用
- kubeadm是Kubernetes 1.4開始新增的特性
- kubeadm init 以及 kubeadm join 這兩個命令可以快速創(chuàng)建 kubernetes 集群
- minikube
- 一般用于本地開發(fā)、測試和學習,不能用于生產環(huán)境
- 是一個工具,minikube快速搭建一個運行在本地的單節(jié)點的Kubernetes
- 二進制包
- 在官網下載相關的組件的二進制包,上面的兩個是工具,可以快速搭建集群,也就是相當于用程序腳本幫我們裝好了集群,前兩者屬于自動部署,簡化部署操作,自動部署屏蔽了很多細節(jié),使得對各個模塊感知很少,遇到問題很難排查,如果手動安裝,對kubernetes理解也會更全面。
- 目前生產環(huán)境的主流搭建方式,已在生產環(huán)境驗證,kubeadm也可以搭建生產環(huán)境
注意:本教程以minikube為主
2.1 通過minikube
①前期準備
minikube 是一個本地k8s,聚焦于快捷構建k8s學習與開發(fā)環(huán)境,在有虛擬化的環(huán)境運行 minikube start即可運行。
注意:
需要先有docker環(huán)境- 如果沒有docker環(huán)境的,參考:https://editor.csdn.net/md/?articleId=127816970
- 注意:CPU至少要兩顆
②安裝minikube
# 1. 下載minikuke包
curl -Lo minikube https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.18.1/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
# 2. 添加鏡像
sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 3. 安裝kubectl
sudo yum install -y kubectl
# 4. 初始化minikube
minikube start --driver=docker
# 如果報錯The "docker" driver should not be used with root privileges.
# 則執(zhí)行如下命令
minikube start --force --driver=docker
bug:
- 執(zhí)行命令:rm -f /var/run/yum.pid,如果害怕強制停止引發(fā)錯誤的話,可以等待一會兒,過一會兒,錯誤會自動解決
![]()
- 如果是使用vmware的話,報錯:centos7開機無法進入圖形界面,出現(xiàn)sda assuming drive cache write through報錯信息,
- 解決方案:
修改 /etc/modprobe.d/dccp-blacklist.conf 內容,加入 blacklist intel_rapl
vim /etc/modprobe.d/dccp-blacklist.conf
blacklist intel_rapl
- 如果報錯X Exiting due to K8S_INSTALL_FAILED: updating control plane: downloading binaries: downloading kube…
- 解決方案:
# 1. 刪除docker中的minikube
minikube delete
# 2. 重新下載并啟動[如果是root賬戶則執(zhí)行下面命令時,添加上 --force, 反之則刪除]
minikube start --force --kubernetes-version=v1.23.8 --image-mirror-country='cn' --image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
最后結果:
③配置kubectl
我們上面已經安裝了minikube,因此有兩個選擇:有kubectl 來替代minikube kubectl --或者直接安裝kubectl
用kubectl
來替代minikube kubectl --
,–不能省略
方法一:設置alias
# 1. 添加臨時alias【或者修改配置文件設置永久的】
alias kubectl="minikube kubectl --"
# 或者設置永久的alias
# echo "alias kubectl=minikube kubectl --" >> ~/.bashrc
# source ~/.bashrc
查看所有pod:kubectl get pod -A 等價于minikube kubectl – get pods -A
方法二:安裝kubectl
#2. 直接安裝kubectl
# 修改鏡像地址
sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 安裝kubectl
sudo yum install -y kubectl
完成之后執(zhí)行命令查看所有pod:
kubectl get pod -A
結果:
2.2 裸機搭建
- 主節(jié)點需要組件:
- docker(也可以是其他容器運行時,如:Mesos等)
- kubectl集群命令行交互工具
- kubeadm集群初始化工具
- 工作節(jié)點需要組件:
- docker(或其他容器運行時)
- kubelet管理Pod和容器,確保他們健康穩(wěn)定運行
- kube-proxy網絡代理,負責網絡相關工作
①購買云服務器
騰訊云 TKE(控制臺搜索容器)
登錄阿里云控制臺 - 產品搜索 Kubernetes
- 購買好3臺云服務器【cpu至少2核,內存最好2G以上】
- 根據(jù)需求,自行選擇購買模式,我這里選擇按量付費
- 基礎配置:
- 網絡配置:
因為我們本身不需要使用太多流量,所以這里我直接選擇按量付費
②配置云服務器
1. 每個節(jié)點設置主機名并修改hosts
# 每個節(jié)點分別設置對應主機名[標識]
hostnamectl set-hostname master
hostnamectl set-hostname node1
hostnamectl set-hostname node2
# 修改hosts文件【ip選擇云服務器內網的ip】
# 每個云服務器都需要配置,配置完之后,服務器之間可以互ping
vim /etc/hosts
10.206.0.11 node1
10.206.0.6 node2
10.206.0.13 master
測試是否可以互通
2. 關閉SE(security enhance) Linux
# 所有節(jié)點關閉 SELinux
setenforce 0
sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
3. 所有服務器關閉防火墻(云服務器默認關閉)
# 所有節(jié)點確保防火墻關閉
systemctl stop firewalld
systemctl disable firewalld
4. 添加安裝源安裝對應組件(docker-ce、kubelet、kubectl、kubeadm)
以下命令均是所有結點(云服務器)執(zhí)行
# 添加 k8s 安裝源
cat <<EOF > kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
mv kubernetes.repo /etc/yum.repos.d/
# 添加 Docker 安裝源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安裝所需組件
yum install -y kubelet-1.22.4 kubectl-1.22.4 kubeadm-1.22.4 docker-ce
# 設置開啟自啟
systemctl enable kubelet
systemctl start kubelet
systemctl enable docker
systemctl start docker
5. 修改docker配置
# kubernetes 官方推薦 docker 等使用 systemd 作為 cgroupdriver,否則 kubelet 啟動不了
cat <<EOF > daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://ud6340vz.mirror.aliyuncs.com"]
}
EOF
mv daemon.json /etc/docker/
# 重啟生效
systemctl daemon-reload
systemctl restart docker
6. kubeadm初始化集群(僅在master節(jié)點執(zhí)行)
初始化集群控制臺:
# 初始化集群控制臺 Control plane
# 失敗了可以用 kubeadm reset 重置
kubeadm init --image-repository=registry.aliyuncs.com/google_containers
# 執(zhí)行上面命令之后會生成kubeadm join xxx,記得把 kubeadm join xxx 保存起來
# 忘記了重新獲?。簁ubeadm token create --print-join-command
保存好上圖綠色框出來的部分,該命令是將其他節(jié)點加入master集群
kubeadm join 10.206.0.13:6443 --token xxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxx
復制授權文件(master節(jié)點(master云服務器)執(zhí)行)
# 復制授權文件,以便 kubectl 可以有權限訪問集群
# 如果你其他節(jié)點需要訪問集群,需要從主節(jié)點復制這個文件過去其他節(jié)點
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 在其他機器上創(chuàng)建 ~/.kube/config 文件也能通過 kubectl 訪問到集群
7. 將工作節(jié)點加入集群(只在工作節(jié)點執(zhí)行:node1、node2)
執(zhí)行開始保存好的kubeadm join xxx
- 注意:需要將
\
去掉之后執(zhí)行,如下:
kubeadm join 10.206.0.13:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxxxxx
8. master節(jié)點上安裝網絡插件
注意:只在master節(jié)點執(zhí)行以下命令來安裝網絡插件,否則node一直是Not Ready狀態(tài)
# 很有可能國內網絡訪問不到這個資源,你可以網上找找國內的源安裝 flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 如果上面的插件安裝失敗,可以選用 Weave,下面的命令二選一就可以了。
kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
kubectl apply -f http://static.corecore.cn/weave.v2.8.1.yaml
# 更多其他網路插件查看下面介紹,自行網上找 yaml 安裝
https://blog.csdn.net/ChaITSimpleLove/article/details/117809007
結果:
相關插件安裝
①kubectl命令自動補全(命令)
- 安裝bash-completion
sudo yum -y install bash-completion
source /usr/share/bash-completion/bash_completion
- 查看是否安裝成功:
- type _init_completion
![]()
- 導入補全腳本
echo ‘source <(kubectl completion bash)’ >>~/.bashrc- 添加腳本到目錄【需要切換為root用戶】
kubectl completion bash >/etc/bash_completion.d/kubectl- 重啟shell之后生效
3 部署應用到集群(pod、deployment)
3.1 部署方式(命令、文件)
部署方式主要有兩種:通過命令方式或者通過yml配置文件方式
- 通過命令直接部署
kubectl run testapp --image=ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1
- 通過yml配置文件方式
- 配置單個Pod:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
# 定義容器,可以多個
containers:
- name: test-k8s # 容器名字
image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 鏡像
- 配置為Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
# 部署名字
name: test-k8s
spec:
replicas: 2
# 用來查找關聯(lián)的 Pod,所有標簽都匹配才行
selector:
matchLabels:
app: test-k8s
# 定義 Pod 相關數(shù)據(jù)
template:
metadata:
labels:
app: test-k8s
spec:
# 定義容器,可以多個
containers:
- name: test-k8s # 容器名字
image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 鏡像
Deployment是通過label來關聯(lián)Pods
總結:deployment、service與pod關系
①deployment根據(jù)Pod的標簽關聯(lián)到Pod,是為了管理pod的生命周期
②service根據(jù)Pod的標簽關聯(lián)到pod,是為了讓外部訪問到pod,給pod做負載均衡
- 需要注意:
- deployment控制器關聯(lián)的Pod,Pod的name和hostname(如果不手動指定)就是deployment控制器的Name
- StatefulSet控制器關聯(lián)的Pod,Pod的Name和Hostname(如果不手動指定)就是StatefulSet控制器的Name + 序號
3.2 部署應用實戰(zhàn)及命令
①部署
部署一個node.js web應用,源碼地址:GitHub,如果遇到網絡問題打不開,也可以直接使用下方的app.yaml
app.yaml
apiVersion: apps/v1
# 表示類型為Deployment
kind: Deployment
metadata:
# 部署名字
name: test-k8s
spec:
replicas: 5
# 用來查找關聯(lián)的 Pod,所有標簽都匹配才行
selector:
matchLabels:
app: test-k8s
# 定義 Pod 相關數(shù)據(jù)
template:
metadata:
labels:
# 標簽
app: test-k8s
spec:
# 定義容器,可以多個【這一部分就是上面的單個pod】
containers:
- name: test-k8s # 容器名字【需要與labels對應】
image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 鏡像[上傳到了騰訊云]
注意:粘貼的時候通過:set paste進入粘貼模式,否則vim會自動對yaml文件進行排版
# 在master執(zhí)行部署命令
kubectl apply -f app.yaml
- bug1:云服務器中的node節(jié)點執(zhí)行部署的時候報錯
原因:kubectl 需要kubernetes-admin來運行
# 1. 通過命令遠程復制文件
scp /etc/kubernetes/admin.conf 175.27.128.45:/etc/kubernetes/admin.conf
# 或者直接將master節(jié)點上的admin.conf下載到本地,然后通過ftp傳輸?shù)絥ode節(jié)點
# 2. 配置環(huán)境變量
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
# 3. 使環(huán)境變量生效
source ~/.bash_profile
重新嘗試,結果:
- bug2:k8s pod一直處于ContainerCreating狀態(tài)
# 查看pod詳細信息
kubectl describe pod pod-name
發(fā)現(xiàn)報錯信息:network: open /run/flannel/subnet.env: no such file or directory
- 解決辦法:
# 1. 在每個節(jié)點上創(chuàng)建/run/flannel/subnet.env
vim /run/flannel/subnet.env
# 2. 寫入以下內容,等待一會兒即可恢復
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
# 3. 重新在master節(jié)點執(zhí)行kubectl apply -f app.yml
kubectl apply -f app.yml
結果:
本次部署,在node1、node2均有pod
②實戰(zhàn)命令
1. 部署應用(kubectl apply -f app.yaml)
# 部署應用
kubectl apply -f app.yaml
報錯:error: error validating “app.yaml”: error validating data: apiVersion not set; if you choose to ignore these errors, turn validation off with --validate=false
從中我們看到是因為缺少了apiVersion,后來排查發(fā)現(xiàn)是vim的
:set paste
模式下,我們要先按下i
,進入插入模式之后再復制
2. 查看deployment(kubectl get deployment)
# 查看deployment
kubectl get deployment
3. 查看pod(kubectl get pod -o wide)
# 查看pod
kubectl get pod -o wide
4. 查看pod詳情(kubectl describe pod pod-name)
# 查看pod詳情
kubectl describe pod test-k8s-8598bbb8c6-62c8m
5. 查看log(kubectl logs pod-name)
# 查看log
kubectl logs test-k8s-8598bbb8c6-ngmw9
# 持續(xù)查看日志
kubectl logs test-k8s-8598bbb8c6-ngmw9 -f
6. 進入pod容器終端(kubectl exec -it pod-name – base)
# 進入pod容器終端,如果pod中有多個容器,則可以 -c container-name 可以指定進入哪個容器
kubectl exec -it pod-name -- bash
# kubectl exec -it test-k8s-8598bbb8c6-knztk -- bash
7. 伸縮擴展副本(kubectl scale deployment deployment-name --replicas=5)
# 通過命令行
kubectl scale deploymnet test-k8s --replicas=5
# 或者通過修改yaml中的replicas配置項值,然后應用文件
kubectl apply -f xxx.yaml
8. 把集群內端口映射到節(jié)點(kubectl port-forward pod-name 8090:8080)
# 8090(外面端口):8080(容器里面端口)
kubectl port-forward pod-name 8090:8080
# kubectl port-forward test-k8s-8598bbb8c6-2ff7w 8090:8080
9. 查看歷史(kubectl rollout history deployment deployment-name)
kubectl rollout history deployment deployment-name
# kubectl rollout history deployment test-k8s
10. 回到上個版本(kubectl rollout undo deployment deployment-name)
kubectl rollout undo deployment deployment-name
# kubectl rollout undo deployment test-k8s
11. 回到指定版本(kubectl rollout undo deployment deployment-name --to-revision=2)
kubectl rollout undo deployment deployment-name --to-revision=2
# kubectl rollout undo deployment test-k8s --to-revision=2
12. 刪除部署(kubectl delete deployment deployment-name)
kubectl delete deployment deployment-name
# kubectl delete deployment test-k8s
③存在的問題
目前Deployment的部署方式存在以下幾個問題:
- 每次只能訪問一個Pod,沒有負載均衡的自動轉發(fā)到不同Pod
- 訪問的時候需要端口轉發(fā)
- Pod重新創(chuàng)建之后IP就變化了,名字也會跟著變化,不便于管理
4 Service
注意:
這里我選擇使用安裝了minikube的linux實驗
因為Deployment的部署方式存在以下幾個問題:
- 每次只能訪問一個Pod,沒有自動負載均衡
- 訪問的時候需要端口轉發(fā)
- Pod重創(chuàng)之后IP和名字都會發(fā)生變化
service特性:
- Service通過label關聯(lián)對應的Pod
- Service生命周期不跟Pod綁定,不會因為Pod重新創(chuàng)建而改變IP
- 提供了負載均衡功能,自動轉發(fā)流量到不同Pod
- 可以對集群外部提供訪問端口
- 集群內部可通過服務名字訪問
4.1 創(chuàng)建service(默認:ClusterIP,集群內部訪問)
① 首先啟動minikube(安裝配置參考本文2.1節(jié))并啟動一個Pod
app.yaml:
apiVersion: apps/v1
# 表示類型為Deployment
kind: Deployment
metadata:
# 部署名字
name: test-k8s
spec:
replicas: 5
# 用來查找關聯(lián)的 Pod,所有標簽都匹配才行
selector:
matchLabels:
app: test-k8s
# 定義 Pod 相關數(shù)據(jù)
template:
metadata:
labels:
# 標簽
app: test-k8s
spec:
# 定義容器,可以多個【這一部分就是上面的單個pod】
containers:
- name: test-k8s # 容器名字【需要與labels對應】
image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 鏡像[上傳到了騰訊云]
鏡像已經放在了騰訊云上,主要是一個簡單的js代碼,有兩個頁面:index page和hello,訪問的同時會打印出hostname
# 啟動minikube
minikube start --force --driver=docker
# 啟動pod
kubectl apply -f app.yaml
②創(chuàng)建一個service,通過標簽test-k8s
跟對應的Pod關聯(lián)上
service.yaml
apiVersion: v1
kind: Service
metadata:
name: test-k8s
spec:
selector:
app: test-k8s
type: ClusterIP # 默認
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
# 應用配置
kubectl apply -f service.yaml
③查看service服務
# kubectl get service
kubectl get svc
④ 查看服務詳情
kubectl describe svc test-k8s
# kubectl describe svc service-name
從上圖我們可以發(fā)現(xiàn),Endpoints是各個Pod的IP,也就是他會把流量轉發(fā)到這些節(jié)點
- 服務的默認類型時ClusterIP,只能在集群內部訪問,因此我們可以進入到Pod里面訪問
# kubectl exec -it pod-name -- bash # 進入容器內部執(zhí)行curl命令訪問
# curl http://service-name:port # 訪問內容
curl http://test-k8s:8080
拓展:如果要在集群外部訪問,我們也可以通過端口轉發(fā)實現(xiàn)(臨時使用)
kubectl port-forward service/test-k8s 8888:8080
- kubectl port-forward service/service-name 主機port:容器內部port
- 如果使用的是minikube,也可以這樣 minikebu service test-k8s
![]()
- 注意:使用虛擬機的不能在本機windows瀏覽器直接輸入虛擬機ip訪問,因為此時虛擬機是容器的宿主機,如果要呈現(xiàn)效果,只有在虛擬機上打開瀏覽器訪問
4.2 對外暴露服務
上面我們是通過端口轉發(fā)的方式臨時讓外面訪問到集群里面的服務,如果我們想直接把集群服務暴露出來,我們可以直接使用
NodePort
和Loadbalancer
類型的service
①單個端口
- 將service.yaml配置文件中的Type模式改為
NodePort
并在ports模塊下添加nodePort
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: test-k8s
spec:
selector:
app: test-k8s
# 默認 ClusterIP 集群內可訪問,NodePort 節(jié)點可訪問,LoadBalancer 負載均衡模式(需要負載均衡器才可用)
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
nodePort: 31000 # 節(jié)點端口,范圍固定 30000 ~ 32767
- 應用并測試
訪問的時候需要關閉防火墻:systemctl stop firewalld
# 重新應用service.yaml
kubectl apply -f service.yaml
# 訪問
curl http://localhost:31000/hello/easydoc
從上圖中我們可以看到網頁的信息被轉發(fā)到了不同Pod并且是有負載均衡的
注意:
如果你是用 minikube,因為是模擬集群,你的電腦并不是節(jié)點,節(jié)點是 minikube 模擬出來的,所以你并不能直接在電腦上訪問到服務
Loadbalancer 也可以對外提供服務,這需要一個負載均衡器的支持,因為它需要生成一個新的 IP 對外服務,否則狀態(tài)就一直是 pendding,這個很少用了,后面我們會講更高端的 Ingress 來代替它。
②多端口
如果使用多端口,我們必須配置 ports下面的name
apiVersion: v1
kind: Service
metadata:
name: test-k8s
spec:
selector:
app: test-k8s
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
name: test-k8s # 必須配置
targetPort: 8080 # 容器端口
nodePort: 31000 # 節(jié)點端口,范圍固定 30000 ~ 32767
- port: 8090
name: test-other
targetPort: 8090
nodePort: 32000
③總結
k8s的service有不同的類型,下面是說明
類型 | 說明 |
---|---|
ClusterIP | 默認的,僅在集群內可訪問 |
NodePort | 暴露端口到節(jié)點,提供了集群外部訪問的入口,端口范圍固定:30000~32767 |
LoadBalancer | 需要負載均衡器(通常都需要云服務商提供,裸機可以安裝METALLB測試),會額外生成一個IP對外服務;K8S支持的負載均衡器:負載均衡器 |
Headless | 適合數(shù)據(jù)庫,ClusterIP設置為None就變成Headless了,不會再分配IP |
5 Statefulset(有狀態(tài)應用)
- 特點:會固定每個Pod名字,但是IP不固定;用于管理有狀態(tài)應用,如數(shù)據(jù)庫等
- 不足:Pod重建后,數(shù)據(jù)庫的內容會丟失,不能持久化
5.1 部署
StatefulSet是用來管理有狀態(tài)的應用,例如數(shù)據(jù)庫。
前面我們部署的應用,都是不需要存儲數(shù)據(jù),不需要記住狀態(tài)的,可以隨意擴充副本,每個副本都是一樣的,可以替代的。
- 但是像數(shù)據(jù)庫、Redis這類有狀態(tài)的,則不能隨意擴充副本
- StatefulSet會固定每個Pod的名字,但是Pod的IP不固定
- 編寫mongo.yaml配置文件
mongo.yaml:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
serviceName: mongodb
replicas: 3
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongo
image: mongo:4.4
# IfNotPresent 僅本地沒有鏡像時才遠程拉,Always 永遠都是從遠程拉,Never 永遠只用本地鏡像,本地沒有則報錯
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: mongodb
spec:
selector:
app: mongodb
type: ClusterIP
# HeadLess
clusterIP: None
ports:
- port: 27017
targetPort: 27017
- 執(zhí)行命令部署
kubectl apply -f mongo.yaml
5.2 特性
- Service的Cluster-IP是空的,Pod名字也是固定的
- Pod創(chuàng)建和銷毀是有順序的,創(chuàng)建是順序的,銷毀是逆序的
- Pod重建不會改變名字,但是會改變IP,因此不要使用IP直連
Endpoints 會多一個 hostname:
訪問時,如果直接使用Service名字連接,會隨機轉發(fā)請求
- 要連接指定Pod,可以這樣
pod-name.service-name
- 運行一個臨時Pod連接數(shù)據(jù)測試如下:
kubectl run mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.4.10-debian-10-r20 --command -- bash
Web應用連接MongoDB
在集群內部,我們可以通過服務名字訪問到不同服務:
- 指定連接第一個:mongodb-0.mongodb
![]()
# 獲取所有信息
kubectl get all
6 數(shù)據(jù)持久化
StatefulSet雖然可以保證Pod的name一定,但是Pod重啟之后會丟失數(shù)據(jù),因此我們需要讓數(shù)據(jù)持久化
- k8s集群不會為我們處理數(shù)據(jù)的持久化存儲,所以我們可以專門掛在一個磁盤來確保數(shù)據(jù)的安全
- 本地存儲:可以掛載某個節(jié)點上的目錄,但是這需要限定Pod在這個節(jié)點上運行
- 云存儲:不限定節(jié)點,不受集群影響,安全穩(wěn)定;需要云服務商提供,裸機集群是沒有的
- NFS(network file system):不限定節(jié)點,不受集群影響
6.1 hostPath掛載示例
把節(jié)點上的一個目錄掛載到Pod,但是已經不推薦使用了
優(yōu):配置方式簡單,需要手動指定Pod跑在某個固定的節(jié)點
缺:僅供單節(jié)點測試使用,不適用于多節(jié)點集群
- minikube 提供了 hostPath 存儲
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
serviceName: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongo
image: mongo:4.4
# IfNotPresent 僅本地沒有鏡像時才遠程拉,Always 永遠都是從遠程拉,Never 永遠只用本地鏡像,本地沒有則報錯
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data/db # 容器里面的掛載路徑
name: mongo-data # 卷名字,必須跟下面定義的名字一致
volumes:
- name: mongo-data # 卷名字
hostPath:
path: /data/mongo-data # 節(jié)點上的路徑
type: DirectoryOrCreate # 指向一個目錄,不存在時自動創(chuàng)建
6.2 更高級抽象(SC、PV、PVC)
6.2.1 Storage Class(SC)
將存儲卷分為不同的種類,例如:SSD、普通磁盤、本地磁盤,按需使用。文檔
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
iopsPerGB: "10"
fsType: ext4
6.2.2 Persistent Volume(PV)
描述卷的具體信息,例如磁盤代銷,訪問模式。文檔
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodata
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem # Filesystem(文件系統(tǒng)) Block(塊)
accessModes:
- ReadWriteOnce # 卷可以被一個節(jié)點以讀寫方式掛載
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /root/data
nodeAffinity:
required:
# 通過 hostname 限定在某個節(jié)點創(chuàng)建存儲卷
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node2
6.2.3 Persistent Volume Claim(PVC)
對存儲需求的一個聲明,可以理解為一個申請單,系統(tǒng)根據(jù)這個申請單去找一個合適的PV,還可以根據(jù)PVC自動創(chuàng)建PV。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodata
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "local-storage"
resources:
requests:
storage: 2Gi
6.2.4 為什么要有多層抽象
- 更好的分工,運維人員提供好存儲,開發(fā)人員不需要關注磁盤細節(jié),只需要寫一個申請單
- 方便云服務商提供不同類型的,配置細節(jié)不需要開發(fā)者關注,只需要一個申請單
- 動態(tài)創(chuàng)建,開發(fā)人員寫好申請單后,供應商可以根據(jù)需求自動創(chuàng)建所需存儲卷
6.3 云服務商存儲掛載
6.4 本地存儲掛在
不支持動態(tài)創(chuàng)建,需要提前創(chuàng)建好
三個存儲抽象文件可以合在一起寫,通過---
分隔開
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
image: mongo:5.0
imagePullPolicy: IfNotPresent
name: mongo
volumeMounts:
- mountPath: /data/db
name: mongo-data
volumes:
- name: mongo-data
persistentVolumeClaim:
claimName: mongodata
---
apiVersion: v1
kind: Service
metadata:
name: mongodb
spec:
clusterIP: None
ports:
- port: 27017
protocol: TCP
targetPort: 27017
selector:
app: mongodb
type: ClusterIP
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodata
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem # Filesystem(文件系統(tǒng)) Block(塊)
accessModes:
- ReadWriteOnce # 卷可以被一個節(jié)點以讀寫方式掛載
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /root/data
nodeAffinity:
required:
# 通過 hostname 限定在某個節(jié)點創(chuàng)建存儲卷
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node2
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodata
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "local-storage"
resources:
requests:
storage: 2Gi
現(xiàn)有問題:
當前數(shù)據(jù)庫的連接地址是寫死在代碼里的,另外還有數(shù)據(jù)庫的密碼需要配置。
- 后續(xù)處理:configMap
7 Configmap & Secret(配置)
7.1 Configmap
像我們上面搭建的mongodb,對于數(shù)據(jù)庫來說連接地址是可能根據(jù)部署環(huán)境而變化的,我們不應該寫死在代碼了。
- k8s為我們提供了ConfigMap,可以方便的配置一些變量
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mongo-config
data:
mongoHost: mongodb-0.mongodb
# 應用配置文件
kubectl apply -f configmap.yaml
# 查看
kubectl configmap mongo-config -o yaml
7.2 Secret
對于一些重要的數(shù)據(jù),例如:密碼、TOKEN等,我們可以放到secret中。文檔、配置證書
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mongo-secret
# Opaque 用戶定義的任意數(shù)據(jù),更多類型介紹 https://kubernetes.io/zh/docs/concepts/configuration/secret/#secret-types
type: Opaque
data:
# 數(shù)據(jù)要 base64。https://tools.fun/base64.html
mongo-username: bW9uZ291c2Vy
mongo-password: bW9uZ29wYXNz
# 應用
kubectl apply -f secret.yaml
# 查看
kubectl get secret mongo-secret -o yaml
①作為環(huán)境變量使用
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
spec:
replicas: 3
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongo
image: mongo:4.4
# IfNotPresent 僅本地沒有鏡像時才遠程拉,Always 永遠都是從遠程拉,Never 永遠只用本地鏡像,本地沒有則報錯
imagePullPolicy: IfNotPresent
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongo-secret
key: mongo-password
# Secret 的所有數(shù)據(jù)定義為容器的環(huán)境變量,Secret 中的鍵名稱為 Pod 中的環(huán)境變量名稱
# envFrom:
# - secretRef:
# name: mongo-secret
②掛在為文件(更適合證書文件)
掛在后,會在容器對應路徑生成文件,一個key一個文件,內容就是value。文檔
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
8 Helm & namespace(軟件庫 & 命名空間)
8.1 Helm
①介紹
Helm類似npm、pip、docker hub,可以為一個軟件庫,可以方便快速的為集群安裝一些第三方軟件。
- 使用Helm可以非常方便的搭建出來MongoDB/MySQL副本集群,YAML文件別人也替我們寫好了,可以直接使用。官網、應用中心
②安裝Helm
安裝文檔
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
③通過Helm搭建Mongo集群
# 安裝
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-mongo bitnami/mongodb
# 指定密碼和架構
helm install my-mongo bitnami/mongodb --set architecture="replicaset",auth.rootPassword="mongopass"
# 刪除
helm ls
helm delete my-mongo
# 查看密碼
kubectl get secret my-mongo-mongodb -o json
kubectl get secret my-mongo-mongodb -o yaml > secret.yaml
# 臨時運行一個包含 mongo client 的 debian 系統(tǒng)
kubectl run mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.4.10-debian-10-r20 --command -- bash
# 進去 mongodb
mongo --host "my-mongo-mongodb" -u root -p mongopass
# 也可以轉發(fā)集群里的端口到宿主機訪問 mongodb
kubectl port-forward svc/my-mongo-mongodb 27017:27018
8.2 namespace
如果一個集群中部署了多個應用,所有應用都在一起,就不太好管理,也可能導致名字沖突等。
- namespace:命名空間,把應用劃分到不同的空間,方便管理
# 創(chuàng)建命名空間
kubectl create namespace testapp
# 部署應用到指定的命名空間
kubectl apply -f app.yml --namespace testapp
# 查詢
kubectl get pod --namespace kube-system
但是,每次命令都加上
--namespace
會很繁瑣
- 我們可以使用kubens>快速切換namespace
- kubens下載地址:https://github.com/ahmetb/kubectx
- 下載好之后配置好環(huán)境變量就可以使用了
9 Ingress(統(tǒng)一訪問入口)
9.1 介紹
Ingress為外部訪問集群提供了一個統(tǒng)一入口,避免了對外暴露集群端口
- 功能類似于Nginx(基于nginx做了擴展,Lua腳本),可以根據(jù)域名、路徑將請求轉發(fā)到不同Service
- 可以配置https
與LoadBalancer區(qū)別?
- LoadBalancer需要對外暴露端口,不安全
- LoadBalancer無法根據(jù)域名、路徑將流量轉發(fā)到不同Service,多個Service需要開啟多個LoadBalancer
- 功能單一,無法配置https
9.2 使用(云服務廠商為例)
要使用Ingress,需要一個負載均衡器 + Ingress Controller
- 如果是裸機(bare metal)搭建的集群,需要我們自己安裝一個負載均衡插件,我們可以安裝METALLB
文檔:
Minikube中部署Ingress Controller:nginx
Helm中安裝:Nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-example
spec:
ingressClassName: nginx
rules:
- host: tools.fun
http:
paths:
- path: /easydoc
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /svnbucket
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
騰訊云配置Ingress:文章來源:http://www.zghlxwxcb.cn/news/detail-474065.html
參考文章:
https://blog.csdn.net/qq_21187515/article/details/101460039
https://blog.csdn.net/haohaifeng002/article/details/116788698文章來源地址http://www.zghlxwxcb.cn/news/detail-474065.html
到了這里,關于K8s全套快速入門的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!