一、K8S介紹及部署
1 應用的部署方式演變
部署應用程序的方式上,主要經歷了三個階段:
傳統部署:互聯網早期,會直接將應用程序部署在物理機上
-
優點:簡單,不需要其它技術的參與
-
缺點:不能為應用程序定義資源使用邊界,很難合理地分配計算資源,而且程序之間容易產生影響
虛擬化部署:可以在一臺物理機上運行多個虛擬機,每個虛擬機都是獨立的一個環境
-
優點:程序環境不會相互產生影響,提供了一定程度的安全性
-
缺點:增加了操作系統,浪費了部分資源
容器化部署:與虛擬化類似,但是共享了操作系統
[!NOTE]
容器化部署方式給帶來很多的便利,但是也會出現一些問題,比如說:
- 一個容器故障停機了,怎么樣讓另外一個容器立刻啟動去替補停機的容器
- 當并發訪問量變大的時候,怎么樣做到橫向擴展容器數量
2 容器編排應用
為了解決這些容器編排問題,就產生了一些容器編排的軟件:
- Swarm:Docker自己的容器編排工具
- Mesos:Apache的一個資源統一管控的工具,需要和Marathon結合使用
- Kubernetes:Google開源的的容器編排工具
3 kubernetes 簡介
- 在Docker 作為高級容器引擎快速發展的同時,在Google內部,容器技術已經應用了很多年
- Borg系統運行管理著成千上萬的容器應用。
- Kubernetes項目來源于Borg,可以說是集結了Borg設計思想的精華,并且吸收了Borg系統中的經驗和教訓。
- Kubernetes對計算資源進行了更高層次的抽象,通過將容器進行細致的組合,將最終的應用服務交給用戶。
kubernetes的本質是一組服務器集群,它可以在集群的每個節點上運行特定的程序,來對節點中的容器進行管理。目的是實現資源管理的自動化,主要提供了如下的主要功能:
- 自我修復:一旦某一個容器崩潰,能夠在1秒中左右迅速啟動新的容器
- 彈性伸縮:可以根據需要,自動對集群中正在運行的容器數量進行調整
- 服務發現:服務可以通過自動發現的形式找到它所依賴的服務
- 負載均衡:如果一個服務起動了多個容器,能夠自動實現請求的負載均衡
- 版本回退:如果發現新發布的程序版本有問題,可以立即回退到原來的版本
- 存儲編排:可以根據容器自身的需求自動創建存儲卷
4 K8S的設計架構
1.4.1 K8S各個組件用途
一個kubernetes集群主要是由控制節點(master)、**工作節點(node)**構成,每個節點上都會安裝不同的組件
1 master:集群的控制平面,負責集群的決策
-
ApiServer : 資源操作的唯一入口,接收用戶輸入的命令,提供認證、授權、API注冊和發現等機制
-
Scheduler : 負責集群資源調度,按照預定的調度策略將Pod調度到相應的node節點上
-
ControllerManager : 負責維護集群的狀態,比如程序部署安排、故障檢測、自動擴展、滾動更新等
-
Etcd :負責存儲集群中各種資源對象的信息
2 node:集群的數據平面,負責為容器提供運行環境
- kubelet:負責維護容器的生命周期,同時也負責Volume(CVI)和網絡(CNI)的管理
- Container runtime:負責鏡像管理以及Pod和容器的真正運行(CRI)
- kube-proxy:負責為Service提供cluster內部的服務發現和負載均衡
1.4.2 K8S 各組件之間的調用關系
當我們要運行一個web服務時
-
kubernetes環境啟動之后,
master
和node
都會將自身的信息存儲到etcd數據庫中 -
web服務的安裝請求會首先被發送到master節點的apiServer組件
-
apiServer組件會調用scheduler組件來決定到底應該把這個服務安裝到哪個node節點上
在此時,它會從
etcd
中讀取各個node節點的信息,然后按照一定的算法進行選擇,并將結果告知apiServer -
apiServer調用controller-manager去調度Node節點安裝web服務
-
kubelet接收到指令后,會通知docker,然后由docker來啟動一個web服務的pod
-
如果需要訪問web服務,就需要通過
kube-proxy
來對pod產生訪問的代理
1.4.3 K8S 的常用名詞
-
Master:集群控制節點,每個集群需要至少一個master節點負責集群的管控
-
Node:工作負載節點,由master分配容器到這些node工作節點上,然后node節點上的
-
Pod:kubernetes的最小控制單元,容器都是運行在pod中的,一個pod中可以有1個或者多個容器
-
Controller:控制器,通過它來實現對pod的管理,比如啟動pod、停止pod、伸縮pod的數量等等
-
Service:pod對外服務的統一入口,下面可以維護者同一類的多個pod
-
Label:標簽,用于對pod進行分類,同一類pod會擁有相同的標簽
-
NameSpace:命名空間,用來隔離pod的運行環境
1.4.4 k8S的分層架構
- 核心層:Kubernetes最核心的功能,對外提供API構建高層的應用,對內提供插件式應用執行環境
- 應用層:部署(無狀態應用、有狀態應用、批處理任務、集群應用等)和路由(服務發現、DNS解析等)
- 管理層:系統度量(如基礎設施、容器和網絡的度量),自動化(如自動擴展、動態Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等)
- 接口層:kubectl命令行工具、客戶端SDK以及集群聯邦
- 生態系統:在接口層之上的龐大容器集群管理調度的生態系統,可以劃分為兩個范疇
- Kubernetes外部:日志、監控、配置管理、CI、CD、Workflow、FaaS、OTS應用、ChatOps等
- Kubernetes內部:CRI、CNI、CVI、鏡像倉庫、Cloud Provider、集群自身的配置和管理等
二 K8S集群環境搭建
2.1 k8s中容器的管理方式
K8S 集群創建方式有3種:
centainerd
默認情況下,K8S在創建集群時使用的方式
docker
Docker使用的普記錄最高,雖然K8S在1.24版本后已經費力了kubelet對docker的支持,但時可以借助cri-docker方式來實現集群創建
cri-o
CRI-O的方式是Kubernetes創建容器最直接的一種方式,在創建集群的時候,需要借助于cri-o插件的方式來實現Kubernetes集群的創建。
[!NOTE]
docker 和cri-o 這兩種方式要對kubelet程序的啟動參數進行設置
2.2 k8s 集群部署
1. 前置任務部署
- 全部主機都要設置
- 把swap給禁用掉
]# systemctl mask swap.target
]# swapoff -a
]#重啟主機,無輸出即可
#swapon -s]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Feb 19 17:38:40 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 0 0
UUID=ddb06c77-c9da-4e92-afd7-53cd76e6a94a /boot xfs defaults 0 0
#/dev/mapper/rhel-swap swap swap defaults 0 0
/dev/cdrom /media iso9660 defaults 0 0]# systemctl daemon-reload[root@k8s-master ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.147.10 K8s_slave1.zym.org
192.168.147.20 K8s_slave2.zym.org
192.168.147.100 K8s_master.zym.org
192.168.147.200 reg.zym.org
harbor配置
mkdir -p packages
cd packages
scp docker.tar.gz root@192.168.147.100:/root/packages
scp docker.tar.gz root@192.168.147.10:/root/packages
scp docker.tar.gz root@192.168.147.20:/root/packagestar zxf docker.tar.gz
dnf install *.rpm -yvim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true
#########################systemctl enable --now docker.service#安裝harbor
tar zxf harbor-offline-installer-v2.5.4.tgz
mkdir -p /data/certscd /root/packages/harbor/
cp harbor.yml.tmpl harbor.ymlvim harbor.yml
hostname: reg.zym.org
certificate: /data/certs/zym.org.crt
private_key: /data/certs/zym.org.key
harbor_admin_password: 123456
######################################./install.sh --with-chartmuseum
#證書
mkdir -p /data/certs
openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout /data/certs/zym.org.key \
> -addext "subjectAltName = DNS:reg.zym.org" \
> -x509 -days 365 -out /data/certs/zym.org.crtCountry Name (2 letter code) [XX]:CN
State or Province Name (full name) []:guangxi
Locality Name (eg, city) [Default City]:cenxi
Organization Name (eg, company) [Default Company Ltd]:youeryuan
Organizational Unit Name (eg, section) []:harbor
Common Name (eg, your name or your server's hostname) []:reg.zym.org
Email Address []:admin.zym@zym.org
K8s節點
#檢測SELinux是否為該狀態
[root@K8smaster ~]# getenforce
Disabledtar zxf docker.tar.gz
dnf install *.rpm -yvim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true
###########################在Harbor傳輸密鑰
[root@Harbor ~]# for i in 100 10 20; do ssh -l root 192.168.147.$i mkdir -p /etc/docker/certs.d; scp /data/certs/zym.org.crt root@192.168.147.$i:/etc/docker/certs.d/ca.crt; done#繼續配置節點
vim /etc/docker/daemon.json
{"registry-mirrors" : ["https://reg.zym.org"]
}
#指定的是Harbor倉庫的主機地址systemctl enable --now docker.service
登錄進Harbor倉庫
[root@K8smaster ~]# cd /etc/docker/certs.d
[root@K8smaster certs.d]# mkdir -p reg.zym.org
[root@K8smaster certs.d]# mv ca.crt reg.zym.org/
[root@K8smaster certs.d]# ls
reg.zym.org
[root@K8smaster certs.d]# docker login reg.zym.org
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-storesLogin Succeeded
2. 安裝K8s
三臺主機均安裝
#此為源碼安裝
[root@K8smaster ~]# mkdir -p mnt
[root@K8smaster ~]# cd mnt/
[root@K8smaster mnt]# ls
cri-dockerd-0.3.14-3.el8.x86_64.rpm k8s-1.30.tar.gz libcgroup-0.41-19.el8.x86_64.rpm
[root@K8smaster mnt]# dnf install *.rpm -y[root@K8smaster ~]# vim /lib/systemd/system/cri-docker.service
#指定網絡插件名稱及基礎容器鏡像
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.zym.org/k8s/pause:3.9[root@K8smaster ~]# systemctl daemon-reload
[root@K8smaster ~]# systemctl enable --now cri-docker.service[root@K8smaster mnt]# tar zxf k8s-1.30.tar.gz
[root@K8smaster mnt]# dnf install *.rpm -y#設置kubectl命令補齊功能---僅需在主機上配置
[root@k8s-master ~]# dnf install bash-completion -y
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@k8s-master ~]# source ~/.bashrc
或者使用軟件倉庫安裝
#部署軟件倉庫,添加K8S源
[root@k8s-master ~]# vim /etc/yum.repos.d/k8s.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm
gpgcheck=0#安裝軟件
[root@k8s-master ~]# dnf install kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 -y
3. 在master節點拉取K8S所需鏡像
[root@K8smaster mnt]# docker load -i k8s_docker_images-1.30.tardocker images | awk '/google/{print $1":"$2}' | awk -F / '{system("docker tag "$0" reg.zym.org/k8s/"$3)}'[root@K8smaster ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
reg.zym.org/k8s/kube-apiserver v1.30.0 c42f13656d0b 15 months ago 117MB
registry.aliyuncs.com/google_containers/kube-apiserver v1.30.0 c42f13656d0b 15 months ago 117MB
reg.zym.org/k8s/kube-controller-manager v1.30.0 c7aad43836fa 15 months ago 111MB
registry.aliyuncs.com/google_containers/kube-controller-manager v1.30.0 c7aad43836fa 15 months ago 111MB
reg.zym.org/k8s/kube-scheduler v1.30.0 259c8277fcbb 15 months ago 62MB
registry.aliyuncs.com/google_containers/kube-scheduler v1.30.0 259c8277fcbb 15 months ago 62MB
reg.zym.org/k8s/kube-proxy v1.30.0 a0bf559e280c 15 months ago 84.7MB
registry.aliyuncs.com/google_containers/kube-proxy v1.30.0 a0bf559e280c 15 months ago 84.7MB
reg.zym.org/k8s/etcd 3.5.12-0 3861cfcd7c04 18 months ago 149MB
registry.aliyuncs.com/google_containers/etcd 3.5.12-0 3861cfcd7c04 18 months ago 149MB
reg.zym.org/k8s/coredns v1.11.1 cbb01a7bd410 24 months ago 59.8MB
registry.aliyuncs.com/google_containers/coredns v1.11.1 cbb01a7bd410 24 months ago 59.8MB
reg.zym.org/k8s/pause 3.9 e6f181688397 2 years ago 744kB
registry.aliyuncs.com/google_containers/pause 3.9 e6f181688397 2 years ago 744kB#鏡像上傳
[root@K8smaster ~]# docker images | awk '/zym/{system("docker push " $1":"$2)}'
4. 集群初始化
#啟動kubelet服務
[root@K8smaster ~]# systemctl enable --now kubelet.service[root@K8smaster ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository reg.zym.org/k8s --kubernetes-version v1.30.0 --cri-socket=unix:///var/run/cri-dockerd.sock#指定集群配置文件變量
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
[root@K8smaster ~]# source ~/.bash_profile#當前節點沒有就緒,因為還沒有安裝網絡插件,容器沒有運行
[root@K8smaster ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster.zym.org NotReady control-plane 66s v1.30.0
[root@K8smaster mnt]# docker load -i flannel-0.25.5.tag.gz
[root@K8smaster mnt]# docker tag flannel/flannel:v0.25.5 reg.zym.org/flannel/flannel:v0.25.5
#在Harbor倉庫中創建flannel倉庫,權限需為公開
[root@K8smaster mnt]# docker push reg.zym.org/flannel/flannel:v0.25.5[root@K8smaster mnt]# docker tag flannel/flannel-cni-plugin:v1.5.1-flannel1 reg.zym.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
[root@K8smaster mnt]# docker push reg.zym.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
查看倉庫
[root@K8smaster mnt]# vim kube-flannel.yml146: image: flannel/flannel:v0.25.5
173: image: flannel/flannel-cni-plugin:v1.5.1-flannel1
184: image: flannel/flannel:v0.25.5[root@K8smaster mnt]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created[root@K8smaster mnt]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster.zym.org Ready control-plane 19m v1.30.0
查看
kubectl get namespaces
5. 添加工作節點
[root@K8smaster mnt]# kubeadm token create --print-join-command
kubeadm join 192.168.147.100:6443 --token cqu5z7.42608w7amd9v3tyg --discovery-token-ca-cert-hash sha256:2fe2b3cdf1c4ee177ce102e6ce2d8ec54322f23609e2c506e62c0b2576bab069#在slave上運行該命令
kubeadm join 192.168.147.100:6443 --token cqu5z7.42608w7amd9v3tyg --discovery-token-ca-cert-hash sha256:2fe2b3cdf1c4ee177ce102e6ce2d8ec54322f23609e2c506e62c0b2576bab069 --cri-socket=unix:///var/run/cri-dockerd.sock#在最后查看節點,狀態均為Ready,安裝成功
[root@K8smaster ~]# kubectl get nodes
一個為控制器節點,兩個工作節點
6.鏡像上傳Harbor倉庫
上傳后,集群中可以獲取鏡像
#上傳busyboxplus鏡像
[root@Harbor docker-images]# docker load -i busyboxplus.tar.gz
[root@Harbor docker-images]# docker tag busyboxplus:latest reg.zym.org/library/busyboxplus:latest
[root@Harbor docker-images]# docker push reg.zym.org/library/busyboxplus:latest
二、K8s中的pod管理以及優化
(一)K8s的資源
2.1 資源管理介紹
- K8s為一個集群系統,可以在集群中部署各種服務
- 在K8s中可以理解為資源,通過操作資源管理運行K8s
- 部署服務為,在集群中運行容器,將指定的程序在容器中運行
- pod為最小的管理單元,pod相當于進程,容器為線程;容器要在pod中運行
- 要通過pod控制器進行管理容器,服務的訪問是由kubernetes提供的
Service
資源來實現
2.2資源的運行方式
-
命令操作K8s資源—命令式對象管理
kubectl run nginx-pod --image=nginx:latest --port=80
-
apply命令和配置文件操作資源—聲明式對象配置
kubectl apply -f nginx-pod.yaml
-
命令配置和配置文件操作資源—命令式對象配置
- 創建之后,不可以覆蓋更新
kubectl create/patch -f nginx-pod.yaml
各方式區別
類型 | 適用環境 | 優點 | 缺點 |
---|---|---|---|
命令式對象管理 | 測試 | 簡單 | 只能操作活動對象,無法審計、跟蹤 |
命令式對象配置 | 開發 | 可以審計、跟蹤 | 項目大時,配置文件多,操作麻煩 |
聲明式對象配置 | 開發 | 支持目錄操作 | 意外情況下難以調試 |
2.2.1 命令式對象管理
kubectl命令的語法如下:
kubectl [command] [type] [name] [flags]
comand:指定要對資源執行的操作,例如create、get、delete
type:指定資源類型,比如deployment、pod、service
name:指定資源的名稱,名稱大小寫敏感
flags:指定額外的可選參數
# 查看所有pod
kubectl get pods# 查看某個pod
kubectl get pod <pod_name># 查看某個pod,以yaml格式展示結果
kubectl get pod <pod_name> -o yaml
2.2.2 資源的類型
kubernetes中所有的內容都抽象為資源
kubectl api-resources
常用資源類型
kubect 常見命令操作
2.2.3 基本命令的示例
kubectl的官方詳細說明:https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
顯示集群版本和信息
#顯示集群版本
[root@k8s-master ~]# kubectl version
Client Version: v1.30.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.30.0#顯示集群信息
[root@k8s-master ~]# kubectl cluster-info
Kubernetes control plane is running at https://172.25.254.100:6443
CoreDNS is running at https://172.25.254.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
2.2.4 運行和調試命令示例
pod基本使用
#運行pod
[root@k8s-master ~]# kubectl run testpod --image nginx:1.23 #需要與倉庫的版本一致,默認是為latest
pod/testpod created[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
testpod 1/1 Running 0 7s#進入pod
[root@K8smaster ~]# kubectl attach testpod -it#刪除pod
[root@K8smaster ~]# kubectl delete pod liveness#查看pod詳細信息
[root@k8s-master ~]# kubectl describe pods -o wide#刪除多個pod
[root@k8s-master ~]# kubectl delete deployments.apps zym
暴露端口,使得可以直接訪問容器
#端口暴漏
[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d14h[root@k8s-master ~]# kubectl expose pod testpod --port 80 --target-port 80
service/testpod exposed[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d14h
testpod ClusterIP 10.106.78.42 <none> 80/TCP 18s
[root@k8s-master ~]# curl 10.106.78.42
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
結果截圖:
*查看報錯資源日志
#查看資源日志
[root@k8s-master ~]# kubectl logs pods/testpod#testpod為開啟pod的名稱
pod交互運行
#運行交互pod
[root@k8s-master ~]# kubectl run -it testpod --image busyboxIf you don't see a command prompt, try pressing enter.
/ #
/ # #ctrl+pq退出不停止pod#運行非交互pod
[root@k8s-master ~]# kubectl run nginx --image nginx
pod/nginx created#進入到已經運行的容器,且容器有交互環境
[root@k8s-master ~]# kubectl attach pods/testpod -it
If you don't see a command prompt, try pressing enter.
/ #
/ ##在已經運行的pod中運行指定命令
[root@k8s-master ~]# kubectl exec -it pods/nginx /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx:/#
控制器創建
#創建一個webcluster控制器,控制器中pod數量為2
[root@k8s-master ~]# kubectl create deployment webcluseter --image nginx --replicas 2
#查看控制器
[root@k8s-master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
web 3/3 3 3 69m
#編輯控制器配置
[root@k8s-master ~]# kubectl edit deployments.apps web
@@@@省略內容@@@@@@
spec:progressDeadlineSeconds: 600replicas: 2[root@k8s-master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
web 2/2 2 2 73m
#利用補丁更改控制器配置
[root@k8s-master ~]# kubectl patch deployments.apps web -p '{"spec":{"replicas":4}}'
deployment.apps/web patched
[root@k8s-master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
web 4/4 4 4 74m
*資源刪除
#刪除資源
[root@k8s-master ~]# kubectl delete deployments.apps web
deployment.apps "web" deleted
2.3 高級命令示例
#管理資源標簽
[root@k8s-master ~]# kubectl run nginx --image nginx
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 12s run=nginx[root@k8s-master ~]# kubectl label pods nginx app=lee
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 57s app=lee,run=nginx#更改標簽
[root@k8s-master ~]# kubectl label pods nginx app=webcluster --overwrite#刪除標簽
[root@k8s-master ~]# kubectl label pods nginx app-
pod/nginx unlabeled
[root@k8s-master ~]# kubectl get pods nginx --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 7m56s run=nginx#標簽時控制器識別pod示例的標識
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 11m run=nginx
webcluster-7c584f774b-66zbd 1/1 Running 0 2m10s app=webcluster,pod-template-hash=7c584f774b
webcluster-7c584f774b-9x2x2 1/1 Running 0 35m app=webcluster,pod-template-hash=7c584f774b#刪除pod上的標簽
root@k8s-master ~]# kubectl label pods webcluster-7c584f774b-66zbd app-
pod/webcluster-7c584f774b-66zbd unlabeled#控制器會重新啟動新pod
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 11m run=nginx
webcluster-7c584f774b-66zbd 1/1 Running 0 2m39s pod-template-hash=7c584f774b
webcluster-7c584f774b-9x2x2 1/1 Running 0 36m app=webcluster,pod-template-hash=7c584f774b
webcluster-7c584f774b-hgprn 1/1 Running 0 2s app=webcluster,pod-template-hash=7c584f774b
(二)pod是什么?
- Pod是可以創建和管理Kubernetes計算的最小可部署單元
- 一個Pod代表著集群中運行的一個進程,每個pod都有一個唯一的ip
- 一個pod類似一個豌豆莢,包含一個或多個容器(通常是docker)
- 多個容器間共享IPC、Network和UTC namespace
2.1 創建自主式pod
在生產中不推薦
優點 | 缺點 |
---|---|
靈活性高—可以精確控制 Pod 的各種配置參數,包括容器的鏡像、資源限制、環境變量、命令和參數等,滿足特定的應用需求 | 管理復雜—如果需要管理大量的 Pod,手動創建和維護會變得非常繁瑣和耗時。難以實現自動化的擴縮容、故障恢復等操作 |
學習和調試方便—于學習 Kubernetes 的原理和機制非常有幫助,通過手動創建 Pod 可以深入了解 Pod 的結構和配置方式。在調試問題時,可以更直接地觀察和調整 Pod 的設置 | 缺乏高級功能—無法自動享受 Kubernetes 提供的高級功能,如自動部署、滾動更新、服務發現等。這可能導致應用的部署和管理效率低下 |
適用于特殊場景—在一些特殊情況下,如進行一次性任務、快速驗證概念或在資源受限的環境中進行特定配置時,手動創建 Pod 可能是一種有效的方式 | 可維護性差—動創建的 Pod 在更新應用版本或修改配置時需要手動干預,容易出現錯誤,并且難以保證一致性。相比之下,通過聲明式配置或使用 Kubernetes 的部署工具可以更方便地進行應用的維護和更新 |
#查看所有pods
[root@k8s-master ~]# kubectl get pods
No resources found in default namespace.#建立一個名為zym的pod
[root@k8s-master ~]# kubectl run zym --image nginx
pod/timinglee created[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
zym 1/1 Running 0 6s#顯示pod的較為詳細的信息
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
zym 1/1 Running 0 11s 10.244.1.17 k8s-node1.zym.org <none> <none>
2.2 利用控制器管理pod(推薦)
高可用性和可靠性:
- 自動故障恢復:如果一個 Pod 失敗或被刪除,控制器會自動創建新的 Pod 來維持期望的副本數量。確保應用始終處于可用狀態,減少因單個 Pod 故障導致的服務中斷。
- 健康檢查和自愈:可以配置控制器對 Pod 進行健康檢查(如存活探針和就緒探針)。如果 Pod 不健康,控制器會采取適當的行動,如重啟 Pod 或刪除并重新創建它,以保證應用的正常運行。
可擴展性:
- 輕松擴縮容:可以通過簡單的命令或配置更改來增加或減少 Pod 的數量,以滿足不同的工作負載需求。例如,在高流量期間可以快速擴展以處理更多請求,在低流量期間可以縮容以節省資源。
- 水平自動擴縮容(HPA):可以基于自定義指標(如 CPU 利用率、內存使用情況或應用特定的指標)自動調整 Pod 的數量,實現動態的資源分配和成本優化
版本管理和更新:
- 滾動更新:對于 Deployment 等控制器,可以執行滾動更新來逐步替換舊版本的 Pod 為新版本,確保應用在更新過程中始終保持可用。可以控制更新的速率和策略,以減少對用戶的影響
- 回滾:如果更新出現問題,可以輕松回滾到上一個穩定版本,保證應用的穩定性和可靠性
聲明式配置:
- 簡潔的配置方式:使用 YAML 或 JSON 格式的聲明式配置文件來定義應用的部署需求。這種方式使得配置易于理解、維護和版本控制,同時也方便團隊協作
- 期望狀態管理:只需要定義應用的期望狀態(如副本數量、容器鏡像等),控制器會自動調整實際狀態與期望狀態保持一致。無需手動管理每個 Pod 的創建和刪除,提高了管理效率
服務發現和負載均衡:
- 自動注冊和發現:Kubernetes 中的服務(Service)可以自動發現由控制器管理的 Pod,并將流量路由到它們。這使得應用的服務發現和負載均衡變得簡單和可靠,無需手動配置負載均衡器
- 流量分發:可以根據不同的策略(如輪詢、隨機等)將請求分發到不同的 Pod,提高應用的性能和可用性
多環境一致性:
- 一致的部署方式:在不同的環境(如開發、測試、生產)中,可以使用相同的控制器和配置來部署應用,確保應用在不同環境中的行為一致。這有助于減少部署差異和錯誤,提高開發和運維效率
示例:
#建立控制器并自動運行pod
[root@k8s-master ~]# kubectl create deployment timinglee --image nginx
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
timinglee-859fbf84d6-mrjvx 1/1 Running 0 37m#為pod擴容
[root@k8s-master ~]# kubectl scale deployment timinglee --replicas 6
deployment.apps/timinglee scaled[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
timinglee-859fbf84d6-8rgkz 0/1 ContainerCreating 0 1s
timinglee-859fbf84d6-ddndl 0/1 ContainerCreating 0 1s
timinglee-859fbf84d6-m4r9l 0/1 ContainerCreating 0 1s
timinglee-859fbf84d6-mrjvx 1/1 Running 0 37m
timinglee-859fbf84d6-tsn97 1/1 Running 0 20s
timinglee-859fbf84d6-xgskk 0/1 ContainerCreating 0 1s#為timinglee縮容
root@k8s-master ~]# kubectl scale deployment timinglee --replicas 2
deployment.apps/timinglee scaled[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
timinglee-859fbf84d6-mrjvx 1/1 Running 0 38m
timinglee-859fbf84d6-tsn97 1/1 Running 0 73s
2.3 應用版本的更新
#利用控制器建立pod
[root@k8s-master ~]# kubectl create deployment timinglee --image myapp:v1 --replicas 2
deployment.apps/timinglee created#暴漏端口
[root@k8s-master ~]# kubectl expose deployment timinglee --port 80 --target-port 80
service/timinglee exposed
[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d17h
timinglee ClusterIP 10.110.195.120 <none> 80/TCP 8s#訪問服務
[root@k8s-master ~]# curl 10.110.195.120
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master ~]# curl 10.110.195.120
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master ~]# curl 10.110.195.120#查看歷史版本
[root@k8s-master ~]# kubectl rollout history deployment timinglee
deployment.apps/timinglee
REVISION CHANGE-CAUSE
1 <none>#更新控制器鏡像版本
[root@k8s-master ~]# kubectl set image deployments/timinglee myapp=myapp:v2
deployment.apps/timinglee image updated#查看歷史版本
[root@k8s-master ~]# kubectl rollout history deployment timinglee
deployment.apps/timinglee
REVISION CHANGE-CAUSE
1 <none>
2 <none>#訪問內容測試
[root@k8s-master ~]# curl 10.110.195.120
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s-master ~]# curl 10.110.195.120#版本回滾
[root@k8s-master ~]# kubectl rollout undo deployment timinglee --to-revision 1
deployment.apps/timinglee rolled back
[root@k8s-master ~]# curl 10.110.195.120
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
2.4 用yaml文件部署應用
yaml文件優點
優點 | 聲明式的配置 | 靈活性和可擴展性 | 能與工具集成 |
---|---|---|---|
清晰表達期望狀態 | 豐富的配置選項 | 與 CI/CD 流程集成 | |
可重復性和版本控制 | 組合和擴展 | 命令行工具支持 |
- 聲明式配置
- 以聲明式的方式描述應用的部署需求,包括副本數量、容器配置、網絡設置等,得配置易于理解和維護
- 配置文件可以被版本控制,確保在不同環境中的部署一致性,也可以回滾到之前版本
2.4.1 配置參數說明
參數名稱 | 類型 | 參數說明 |
---|---|---|
version | String | 這里是指的是K8S API的版本,目前基本上是v1,可以用kubectl api-versions命令查詢 |
kind | String | 這里指的是yaml文件定義的資源類型和角色,比如:Pod |
metadata | Object | 元數據對象,固定值就寫metadata |
metadata.name | String | 元數據對象的名字,這里由我們編寫,比如命名Pod的名字 |
metadata.namespace | String | 元數據對象的命名空間,由我們自身定義 |
Spec | Object | 詳細定義對象,固定值寫Spec |
參數名稱 類型 參數說明
Spec #Object #詳細定義對象,固定值就寫Specspec.containers[] #list #這里是Spec對象的容器列表定義,是個列表spec.containers[].name #String #這里定義容器的名字spec.containers[].image #string #這里定義要用到的鏡像名稱spec.containers[].imagePullPolicy #String #定義鏡像拉取策略,有三個值可選:#a.Always: 每次都嘗試重新#b. IfNotPresent:如果本地有鏡像就使用本地鏡像#c.Never:表示僅使用本地鏡像spec.containers[].command[] #list #指定容器運行時啟動的命令,若未指定則運行容器打包時指定的命令 |spec.containers[].args[] #list #指定容器運行參數,可以指定多個spec.containers[].workingDir#String #指定容器工作目錄
spec.containers[].volumeMounts[]#list #指定容器內部的存儲卷配置
spec.containers[].volumeMounts[].name#String #指定可以被容器掛載的存儲卷的名稱
spec.containers[].volumeMounts[].mountPath#String #指定可以被容器掛載的存儲卷的路徑
spec.containers[].volumeMounts[].readOnly#String #設置存儲卷路徑的讀寫模式,ture或false,默認為讀寫模式
spec.containers[].ports[]#list #指定容器需要用到的端口列表
spec.containers[].ports[].name#String #指定端口名稱
spec.containers[].ports[].containerPort#String #指定容器需要監聽的端口號
spec.containers[] ports[].hostPort#String #指定容器所在主機需要監聽的端口號,默認跟上面containerPort相同,注意設置了hostPort同一臺主機無法啟動該容器的相同副本(因為主機的端口號不能相同,這樣會沖突)| spec.containers[].ports[].protocol | String | 指定端口協議,支持TCP和UDP,默認值為TCP
| spec.containers[].env[] | list | 指定容器運行前需設置的環境變量列表
| spec.containers[].env[].name | String | 指定環境變量名稱
| spec.containers[].env[].value | String | 指定環境變量值
| spec.containers[].resources | Object | 指定資源限制和資源請求的值(這里開始就是設置容器的資源上限)
| spec.containers[].resources.limits | Object | 指定設置容器運行時資源的運行上限
| spec.containers[].resources.limits.cpu | String | 指定CPU的限制,單位為核心數,1=1000m
| spec.containers[].resources.limits.memory | String | 指定MEM內存的限制,單位為MIB、GiB
| spec.containers[].resources.requests | Object | 指定容器啟動和調度時的限制設置
| spec.containers[].resources.requests.cpu | String | CPU請求,單位為core數,容器啟動時初始化可用數量
| spec.containers[].resources.requests.memory | String | 內存請求,單位為MIB、GIB,容器啟動的初始化可用數量| spec.restartPolicy | string | 定義Pod的重啟策略,默認值為Always.(1)Always: Pod-旦終止運行,無論容器是如何 終止的,kubelet服務都將重啟它 (2)OnFailure: 只有Pod以非零退出碼終止時,kubelet才會重啟該容器。如果容器正常結束(退出碼為0),則kubelet將不會重啟它(3) Never: Pod終止后,kubelet將退出碼報告給Master,不會重啟該
spec.nodeSelector | Object | 定義Node的Label過濾標簽,以key:value格式指定spec.imagePullSecrets | Object | 定義pull鏡像時使用secret名稱,以name:secretkey格式指定
pec.hostNetwork | Boolean | 定義是否使用主機網絡模式,默認值為false。設置true表示使用宿主機網絡,不使用docker網橋,同時設置了true將無法在同一臺宿主機 上啟動第二個副本
2.5 yaml編寫示例
用命令獲取yaml模板,以下均編寫yaml配置文件
kubectl run zym --image myapp:v1 --dry-run=client -o yaml > pod.yml
示例1:運行簡單的單個容器pod
apiVersion: v1
kind: Pod
metadata:labels:run: timing #pod標簽name: timinglee #pod名稱
spec:containers:- image: myapp:v1 #pod鏡像name: timinglee #容器名稱
示例2:運行多個容器pod
!注意:如果多個容器運行在一個pod中,資源共享的同時在使用相同資源時也會干擾,比如端口占用
apiVersion: v1
kind: Pod
metadata:labels:run: timingname: timinglee
spec:containers:- image: nginx:latestname: web1- image: nginx:latestname: web2
[root@k8s-master ~]# kubectl apply -f pod.yml
pod/timinglee created#有一臺啟動失敗
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
timinglee 1/2 Error 1 (14s ago) 18s
#查看日志
[root@k8s-master ~]# kubectl logs timinglee web2
2024/08/31 12:43:20 [emerg] 1#1: bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
2024/08/31 12:43:20 [notice] 1#1: try again to bind() after 500ms
2024/08/31 12:43:20 [emerg] 1#1: still could not bind()
nginx: [emerg] still could not bind()
[!NOTE]
在一個pod中開啟多個容器時一定要確保容器彼此不能互相干擾
apiVersion: v1
kind: Pod
metadata:labels:run: timingname: timinglee
spec:containers:- image: nginx:latestname: web1- image: busybox:latestname: busyboxcommand: ["/bin/sh","-c","sleep 1000000"][root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
timinglee 2/2 Running 0 19s
示例3:端口映射
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:containers:- image: myapp:v1name: myapp1ports:- name: httpcontainerPort: 80 #映射端口hostPort: 80protocol: TCP#測試
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test 1/1 Running 0 12s 10.244.1.2 k8s-node1.zym.org <none> <none>
示例4:設定環境變量
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:containers:- image: busybox:latestname: busyboxcommand: ["/bin/sh","-c","echo $NAME;sleep 3000000"]env:- name: NAMEvalue: timinglee #環境變量設定[root@k8s-master ~]# kubectl logs pods/test busybox
timinglee
示例5:資源限制
!注意
資源限制會影響pod的Qos Class資源優先級,資源優先級分為Guaranteed > Burstable > BestEffort
QoS(Quality of Service)即服務質量
資源設定 優先級類型 資源限定未設定 BestEffort 資源限定設定且最大和最小不一致 Burstable-次敏感型 資源限定設定且最大和最小一致,內存和CPU均要設定 Guaranteed-敏感型
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:containers:- image: myapp:v1name: myappresources:limits: #pod使用資源的最高限制 cpu: 500mmemory: 100Mrequests: #pod期望使用資源量,不能大于limitscpu: 500mmemory: 100M
root@k8s-master ~]# kubectl apply -f pod.yml
pod/test created[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test 1/1 Running 0 3s[root@k8s-master ~]# kubectl describe pods testLimits:cpu: 500mmemory: 100MRequests:cpu: 500mmemory: 100M
QoS Class: Guaranteed
示例6:容器啟動管理
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:restartPolicy: Always #啟動管理containers:- image: myapp:v1name: myapp
Always: 要確保運行,掉了要重新運行
Never:不管該Pod還能否運行
示例7:選擇運行節點
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:nodeSelector:kubernetes.io/hostname: k8s-node1 #選擇運行節點restartPolicy: Alwayscontainers:- image: myapp:v1name: myapp
示例8:共享宿主機網絡
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:labels:run: timingleename: test
spec:hostNetwork: truerestartPolicy: Alwayscontainers:- image: busybox:latestname: busyboxcommand: ["/bin/sh","-c","sleep 100000"][root@k8s-master ~]# kubectl apply -f pod.yml
pod/test created[root@k8s-master ~]# kubectl exec -it pods/test -c busybox -- /bin/sh
/ #ipconfig
三、K8S的管理
(一)POD的生命周期
3.1 init容器
- pod中是先于應用容器的啟動
- 與普通容器區別
- 每個均要運行到完成
- 不支持
Readiness
,init容器需要在pod容器運行之前運行完成 - 每一個容器需要運行成功后,再運行下一個
- 如果pod里的init容器啟動失敗,k8s會不斷進行重啟,直到init容器啟動成功
3.1.1 容器的功能
- Init 容器可以包含安裝過程中應用容器中不存在的實用工具或個性化代碼
- Init 容器可以安全地運行這些工具,避免這些工具導致應用鏡像的安全性降低
- 應用鏡像的創建者和部署者可以各自獨立工作
- Init 容器能以不同于Pod內應用容器的文件系統視圖運行;init容器可具有訪問 Secrets 的權限,而應用容器不能夠訪問
- 由于 Init 容器必須在應用容器啟動之前運行完成;因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會并行啟動
3.1.2 INIT 容器示例
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:labels:name: initpodname: initpod
spec:containers:- image: myapp:v1name: myappinitContainers:- name: init-myserviceimage: busyboxcommand: ["sh","-c","until test -e /testfile;do echo wating for myservice; sleep 2;done"] #檢測/testfile下的test文件是否存在#測試
[root@k8s-master ~]# kubectl apply -f pod.yml
pod/initpod created
[root@k8s-master ~]# kubectl get pods
顯示init容器正在運行中,因為該容器中沒有目標文件,會處于該狀態
#每兩秒刷新啟動
[root@k8s-master ~]# kubectl logs pods/initpod init-myservice
wating for myservice
wating for myservice
wating for myservice
wating for myservice
wating for myservice
wating for myservice#添加所需的目標文件
[root@k8s-master ~]# kubectl exec pods/initpod -c init-myservice -- /bin/sh -c "touch /testfile"[root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE
initpod 1/1 Running 0 62s
3.2 三種探針
選擇執行在容器上運行的三種探針執行
-
存活探針–livenessProbe:會持續檢測該容器是否正常運行,啟動不了的話,會把之前啟動的給刪了,然后受到重啟策略影響,重新開一個新的容器
如果容器不設定存活探針話,會默認狀態為success
-
就緒探針–readinessProbe:容器是否準備好服務請求,就緒探測失敗,端點控制器將從與 Pod 匹配的所有 Service 的端點中刪除該 Pod 的 IP 地址。初始延遲之前的就緒狀態默認為失敗
-
啟動探針–startupProbe:容器中的應用是否已經啟動,提供了啟動探測(startup probe),則禁用所有其他探測,直到它成功為止;啟動探測失敗的話,會將容器刪除,重新啟動容器
ReadinessProbe 與 LivenessProbe 的區別
- 當檢測失敗后,將 Pod 的
IP:Port
從對應的 EndPoint 列表中刪除 - 當檢測失敗后,將殺死容器并根據
Pod 的重啟策略
來決定作出對應的措施
StartupProbe 與 ReadinessProbe、LivenessProbe 的區別
- 當三個探針同時存在,
先執行 StartupProbe 探針
,其他兩個探針將會被暫時禁用,直到 pod滿足啟動探針配置的條件
,其他 2 個探針啟動;不滿足按照規則重啟容器。 - 另外兩種探針在容器啟動后,會按照配置,直到容器消亡才停止探測,而 StartupProbe 探針只是在容器啟動后按照配置滿足一次后,不在進行后續的探測。
3.2.1 探針示例
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:labels:name: livenessname: liveness
spec:containers:- image: myapp:v1name: myapplivenessProbe:tcpSocket: #檢測端口存在性port: 8080initialDelaySeconds: 3 #容器啟動后要等待多少秒后就探針開始工作,默認是 0speriodSeconds: 1 #執行探測的時間間隔,默認為 10stimeoutSeconds: 1 #探針執行檢測請求后,等待響應的超時時間,默認為 1s#測試:
[root@k8s-master ~]# kubectl apply -f pod.yml
pod/liveness created
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness 0/1 CrashLoopBackOff 2 (7s ago) 22s[root@k8s-master ~]# kubectl describe pods
可以看到因為無法連接該8080端口,在持續的刪除重啟
四、k8s中的控制器
(一)控制器的說明
控制器是管理pod的一種手段
- 自主Pod—pod退出或意外關閉后不會被重新創建
- 控制器管理的Pod—在控制器的生命周期里,始終維持 Pod 的副本數目
Pod控制器是管理pod的中間層,使用Pod控制器之后,只需要告訴Pod控制器,想要多少個什么樣的Pod就可以了,它會創建出滿足條件的Pod并確保每一個Pod資源處于用戶期望的目標狀態。如果Pod資源在運行中出現故障,它會基于指定策略重新編排Pod
當建立控制器后,會把期望值寫入etcd,k8s中的apiserver檢索etcd中我們保存的期望狀態,并對比pod的當前狀態,如果出現差異代碼自驅動立即恢復
(二)常用控制器的類型
控制器名稱 | 控制器用途 |
---|---|
ReplicaSet | ReplicaSet 確保任何時間都有指定數量的 Pod 副本在運行 |
Deployment | 一個 Deployment 為 Pod 和 ReplicaSet 提供聲明式的更新能力 |
DaemonSet | DaemonSet 確保全指定節點上運行一個 Pod 的副本 |
StatefulSet | StatefulSet 是用來管理有狀態應用的工作負載 API 對象。 |
Job | 執行批處理任務,僅執行一次任務,保證任務的一個或多個Pod成功結束 |
CronJob | Cron Job 創建基于時間調度的 Jobs。 |
HPA全稱Horizontal Pod Autoscaler | 根據資源利用率自動調整service中Pod數量,實現Pod水平自動縮放 |
(三)replicaset控制器
replicaset功能
- ReplicaSet 確保任何時間都有指定數量的 Pod 副本在運行
- 協助Deployments 用作協調 Pod 創建、刪除和更新的機制
replicaset解釋
apiVersion: apps/v1
kind: ReplicaSet
metadata:name: replicaset #指定pod名稱,一定小寫,如果出現大寫報錯
spec:replicas: 2 #指定維護pod數量為2selector: #指定檢測匹配方式matchLabels: #指定匹配方式為匹配標簽app: myapp #指定匹配的標簽為app=myapptemplate: #模板,當副本數量不足時,會根據下面的模板創建pod副本metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp
replicaset 示例
創建測試容器
#生成yml文件
[root@k8s-master ~]# kubectl create deployment replicaset --image myapp:v1 --dry-run=client -o yaml > replicaset.yml[root@k8s-master ~]# vim replicaset.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:name: replicaset #指定pod名稱,一定小寫,如果出現大寫報錯
spec:replicas: 2 #指定維護pod數量為2selector: #指定檢測匹配方式matchLabels: #指定匹配方式為匹配標簽app: myapp #指定匹配的標簽為app=myapptemplate: #模板,當副本數量不足時,會根據下面的模板創建pod副本metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp[root@k8s-master ~]# kubectl apply -f replicaset.yml
replicaset.apps/replicaset created
測試:通過標簽匹配pod,標簽不同,會重新啟動一個標簽相同的容器
[root@k8s-master ~]# kubectl label pod replicaset-l4xnr app=timinglee --overwrite
pod/replicaset-l4xnr labeled
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-gd5fh 1/1 Running 0 2s app=myapp #會開啟新的pod
replicaset-l4xnr 1/1 Running 0 3m19s app=timinglee
replicaset-t2s5p 1/1 Running 0 3m19s app=myapp
測試:控制容器的數量
#刪除其中一個pod,會自動重新生成新的pod,保證數量
[root@k8s-master ~]# kubectl delete pods replicaset-t2s5p
pod "replicaset-t2s5p" deleted[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-l4xnr 1/1 Running 0 5m43s app=myapp
replicaset-nxmr9 1/1 Running 0 15s app=myapp
(四)deployment 控制器
4.1 deployment控制器說明
- Deployment控制器并不直接管理pod,而是通過管理ReplicaSet來間接管理Pod
- Deployment管理ReplicaSet,ReplicaSet管理Pod
- Deployment 為 Pod 和 ReplicaSet 提供了一個申明式的定義方法
- 在Deployment中ReplicaSet相當于一個版本
典型的應用場景:
- 用來創建Pod和ReplicaSet
- 滾動更新和回滾
- 擴容和縮容
- 暫停與恢復
pod控制器—deployment
kubectl create deployment webcluster --imagge myapp:v1 - replicas 4#deployment---為實時和系統進行命令的對比,查看是否符合命令操作
#replicas---為期望,設定期望pod開啟的數量為4個
4.2 deployment控制器示例
#生成yaml文件
[root@k8s-master ~]# kubectl create deployment deployment --image myapp:v1 --dry-run=client -o yaml > deployment.yml[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment
spec:replicas: 4selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp
#建立pod
root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/deployment created#查看pod信息
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
deployment-5d886954d4-2ckqw 1/1 Running 0 23s app=myapp,pod-template-hash=5d886954d4
deployment-5d886954d4-m8gpd 1/1 Running 0 23s app=myapp,pod-template-hash=5d886954d4
deployment-5d886954d4-s7pws 1/1 Running 0 23s app=myapp,pod-template-hash=5d886954d4
deployment-5d886954d4-wqnvv 1/1 Running 0 23s app=myapp,pod-template-hash=5d886954d4
4.2.1 版本迭代
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-5d886954d4-2ckqw 1/1 Running 0 2m40s 10.244.2.14 k8s-node2 <none> <none>
deployment-5d886954d4-m8gpd 1/1 Running 0 2m40s 10.244.1.17 k8s-node1 <none> <none>
deployment-5d886954d4-s7pws 1/1 Running 0 2m40s 10.244.1.16 k8s-node1 <none> <none>
deployment-5d886954d4-wqnvv 1/1 Running 0 2m40s 10.244.2.15 k8s-node2 <none> <none>#pod運行容器版本為v1
[root@k8s-master ~]# curl 10.244.2.14
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>[root@k8s-master ~]# kubectl describe deployments.apps deployment
Name: deployment
Namespace: default
CreationTimestamp: Sun, 01 Sep 2024 23:19:10 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=myapp
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge #默認每次更新25%#更新容器運行版本
[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment
spec:minReadySeconds: 5 #最小就緒時間5秒replicas: 4selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- image: myapp:v2 #更新為版本2name: myapp[root@k8s2 pod]# kubectl apply -f deployment-example.yaml#更新過程
[root@k8s-master ~]# watch - n1 kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE
deployment-5d886954d4-8kb28 1/1 Running 0 48s
deployment-5d886954d4-8s4h8 1/1 Running 0 49s
deployment-5d886954d4-rclkp 1/1 Running 0 50s
deployment-5d886954d4-tt2hz 1/1 Running 0 50s
deployment-7f4786db9c-g796x 0/1 Pending 0 0s#測試更新效果
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-7f4786db9c-967fk 1/1 Running 0 10s 10.244.1.26 k8s-node1 <none> <none>
deployment-7f4786db9c-cvb9k 1/1 Running 0 10s 10.244.2.24 k8s-node2 <none> <none>
deployment-7f4786db9c-kgss4 1/1 Running 0 9s 10.244.1.27 k8s-node1 <none> <none>
deployment-7f4786db9c-qts8c 1/1 Running 0 9s 10.244.2.25 k8s-node2 <none> <none>[root@k8s-master ~]# curl 10.244.1.26
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[!NOTE]
更新的過程是重新建立一個版本的RS,新版本的RS會把pod 重建,然后把老版本的RS回收
4.2.2 版本回滾
[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment
spec:replicas: 4selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- image: myapp:v1 #回滾到之前版本name: myapp[root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/deployment configured#測試回滾效果
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-5d886954d4-dr74h 1/1 Running 0 8s 10.244.2.26 k8s-node2 <none> <none>
deployment-5d886954d4-thpf9 1/1 Running 0 7s 10.244.1.29 k8s-node1 <none> <none>
deployment-5d886954d4-vmwl9 1/1 Running 0 8s 10.244.1.28 k8s-node1 <none> <none>
deployment-5d886954d4-wprpd 1/1 Running 0 6s 10.244.2.27 k8s-node2 <none> <none>[root@k8s-master ~]# curl 10.244.2.26
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
4.2.3 滾動更新策略
[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment
spec:minReadySeconds: 5 #最小就緒時間,指定pod每隔多久更新一次replicas: 4strategy: #指定更新策略rollingUpdate:maxSurge: 1 #比定義pod數量多幾個maxUnavailable: 0 #比定義pod個數少幾個selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp
[root@k8s2 pod]# kubectl apply -f deployment-example.yaml
4.2.4 暫停及恢復
在實際生產環境中我們做的變更可能不止一處,當修改了一處后,如果執行變更就直接觸發了
我們期望的觸發時當我們把所有修改都搞定后一次觸發
暫停,避免觸發不必要的線上更新
[root@k8s2 pod]# kubectl rollout pause deployment deployment-example[root@k8s2 pod]# vim deployment-example.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment-example
spec:minReadySeconds: 5strategy:rollingUpdate:maxSurge: 1maxUnavailable: 0replicas: 6 selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- name: myappimage: nginxresources:limits:cpu: 0.5memory: 200Mirequests:cpu: 0.5memory: 200Mi[root@k8s2 pod]# kubectl apply -f deployment-example.yaml#調整副本數,不受影響
[root@k8s-master ~]# kubectl describe pods deployment-7f4786db9c-8jw22
Name: deployment-7f4786db9c-8jw22
Namespace: default
Priority: 0
Service Account: default
Node: k8s-node1/172.25.254.10
Start Time: Mon, 02 Sep 2024 00:27:20 +0800
Labels: app=myapppod-template-hash=7f4786db9c
Annotations: <none>
Status: Running
IP: 10.244.1.31
IPs:IP: 10.244.1.31
Controlled By: ReplicaSet/deployment-7f4786db9c
Containers:myapp:Container ID: docker://01ad7216e0a8c2674bf17adcc9b071e9bfb951eb294cafa2b8482bb8b4940c1dImage: myapp:v2Image ID: docker-pullable://myapp@sha256:5f4afc8302ade316fc47c99ee1d41f8ba94dbe7e3e7747dd87215a15429b9102Port: <none>Host Port: <none>State: RunningStarted: Mon, 02 Sep 2024 00:27:21 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mfjjp (ro)
Conditions:Type StatusPodReadyToStartContainers TrueInitialized TrueReady TrueContainersReady TruePodScheduled True
Volumes:kube-api-access-mfjjp:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 6m22s default-scheduler Successfully assigned default/deployment-7f4786db9c-8jw22 to k8s-node1Normal Pulled 6m22s kubelet Container image "myapp:v2" already present on machineNormal Created 6m21s kubelet Created container myappNormal Started 6m21s kubelet Started container myapp#但是更新鏡像和修改資源并沒有觸發更新
[root@k8s2 pod]# kubectl rollout history deployment deployment-example
deployment.apps/deployment-example
REVISION CHANGE-CAUSE
3 <none>
4 <none>#恢復后開始觸發更新
[root@k8s2 pod]# kubectl rollout resume deployment deployment-example[root@k8s2 pod]# kubectl rollout history deployment deployment-example
deployment.apps/deployment-example
REVISION CHANGE-CAUSE
3 <none>
4 <none>
5 <none>#回收
[root@k8s2 pod]# kubectl delete -f deployment-example.yaml
(五) daemonset控制器
5.1 daemonset功能
DaemonSet 確保全部(或者某些)節點上運行一個 Pod 的副本。當有節點加入集群時, 也會為他們新增一個 Pod ,當有節點從集群移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它創建的所有 Pod
DaemonSet 的典型用法:
- 在每個節點上運行集群存儲 DaemonSet,例如 glusterd、ceph。
- 在每個節點上運行日志收集 DaemonSet,例如 fluentd、logstash。
- 在每個節點上運行監控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等
- 一個簡單的用法是在所有的節點上都啟動一個 DaemonSet,將被作為每種類型的 daemon 使用
- 一個稍微復雜的用法是單獨對每種 daemon 類型使用多個 DaemonSet,但具有不同的標志, 并且對不同硬件類型具有不同的內存、CPU 要求
5.2 daemonset 示例
[root@k8s2 pod]# cat daemonset-example.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:name: daemonset-example
spec:selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:tolerations: #對于污點節點的容忍- effect: NoScheduleoperator: Existscontainers:- name: nginximage: nginx[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-87h6s 1/1 Running 0 47s 10.244.0.8 k8s-master <none> <none>
daemonset-n4vs4 1/1 Running 0 47s 10.244.2.38 k8s-node2 <none> <none>
daemonset-vhxmq 1/1 Running 0 47s 10.244.1.40 k8s-node1 <none> <none>#回收
[root@k8s2 pod]# kubectl delete -f daemonset-example.yml
(六)job 控制器
6.1 job控制器說明
- 可以進行批量處理的短暫一次運行
[root@k8s2 pod]# vim job.yml
apiVersion: batch/v1
kind: Job
metadata:name: pi
spec:completions: 6 #一共完成任務數為6 parallelism: 2 #每次并行完成2個backoffLimit: 4 #嘗試運行失敗4次后重新運行template:spec:containers:- name: piimage: perl:5.34.0command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] #計算圓周率3.14的后2000位restartPolicy: Never #關閉后不自動重啟[root@k8s2 pod]# kubectl apply -f job.yml#監控
[root@K8smaster ~]# watch -n 1 "kubectl get pods -o wide"
#刪除
[root@K8smaster build]# kubectl delete jobs.batch pi
[!NOTE]
關于重啟策略**
restartPolicy
**設置的說明:
? 如果指定為OnFailure,則job會在pod出現故障時重啟容器
? 而不是創建pod,failed次數不變
? 如果指定為Never,則job會在pod出現故障時創建新的pod
? 并且故障pod不會消失,也不會重啟,failed次數加1
? 如果指定為Always的話,就意味著一直重啟,意味著job任務會重復去執行了
結果查看:可以看到狀態為completed狀態
(七)cronjob控制器
7.1 cronjob說明
- Cron Job 創建基于時間調度的 Jobs
- CronJob控制器以Job控制器資源為其管控對象,并借助它管理pod資源對象
- CronJob可以進行周期性任務作業,控制其運行時間點及重復運行的方式
- CronJob可以在特定的時間點(反復的)去運行job任務
7.2 cronjob示例
[root@k8s2 pod]# vim cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:name: hello
spec:schedule: "* * * * *"jobTemplate:spec:template:spec:containers:- name: helloimage: busyboximagePullPolicy: IfNotPresentcommand:- /bin/sh- -c- date; echo Hello from the Kubernetes clusterrestartPolicy: OnFailure #當失敗后,重新啟動pod,但不記錄失敗次數[root@k8s2 pod]# kubectl apply -f cronjob.yml
五、微服務
微服務相當于主機中的網卡,實現服務發現
編寫配置文件時,需要注意格式,保證配置正常運行
- Service是一組提供相同服務的Pod對外開放的接口
- service默認只支持4層負載均衡能力,沒有7層功能(可以通過Ingress實現)
結構圖:
(一)微服務的類型
微服務類型 | 作用描述 |
---|---|
ClusterIP | 默認值,k8s系統給service自動分配的虛擬IP,只能在集群內部訪問 |
NodePort | 將Service通過指定的Node上的端口暴露給外部,訪問任意一個NodeIP:nodePort都將路由到ClusterIP |
LoadBalancer | 在NodePort的基礎上,借助cloud provider創建一個外部的負載均衡器,并將請求轉發到 NodeIP:NodePort,此模式只能在云服務器上使用 |
ExternalName | 將服務通過 DNS CNAME 記錄方式轉發到指定的域名(通過 spec.externlName 進行設定) |
前三個類型都是,集群外部訪問到集群內部;另一個是,集群內訪問集群外部
(二)IPVS模式
- Service 是由 kube-proxy 組件,加上 iptables 來共同實現的
- kube-proxy 通過 iptables 處理 Service 的過程,需要在宿主機上設置相當多的 iptables 規則,如果宿主機有大量的Pod,不斷刷新iptables規則,會消耗大量的CPU資源
- IPVS模式的service,可以使K8s集群支持更多量級的Pod
3.1 ipvs模式配置方式
- 在所有節點中安裝ipvsadm
[root@k8s-所有節點 pod]dnf install ipvsadm –y
- 修改master節點的代理配置
[root@k8s-master ~]# kubectl -n kube-system edit cm kube-proxymetricsBindAddress: ""mode: "ipvs" #設置kube-proxy使用ipvs模式nftables:
- 配置yml文件
[root@K8smaster build]# vim myappv1.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: myappv1name: myappv1
spec:replicas: 2selector:matchLabels:app: myappv1template:metadata:labels:app: myappv1spec:containers:- image: myapp:v1name: myapp
---
apiVersion: v1
kind: Service
metadata:labels:app: myappv1name: myappv1
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myappv1type: ClusterIP
- 需重啟pod,才能生效
[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'[root@k8s-master ~]# ipvsadm -Ln
注意:
當切換ipvs模式后,kube-proxy會在宿主機上添加一個虛擬網卡:kube-ipvs0,并分配所有service IP
(三)微服務類型詳情
3.1 ClusterIP
- 用于在集群的內部暴露控制器的,在集群內訪問,并對集群內的pod提供健康檢測和自動發現功能
對于微服務的域名解析
#service創建后集群DNS提供解析[root@K8smaster build]# dig myappv1.default.svc.cluster.local @10.96.0.10; <<>> DiG 9.16.23-RH <<>> myappv1.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28306
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: fa143f2b1d9b817f (echoed)
;; QUESTION SECTION:
;myappv1.default.svc.cluster.local. IN A;; ANSWER SECTION:
myappv1.default.svc.cluster.local. 30 IN A 10.103.231.139;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Aug 18 00:03:33 CST 2025
;; MSG SIZE rcvd: 123
3.2 ClusterIP中的特殊模式headless
headless(無頭服務)
對于無頭 Services
并不會分配 Cluster IP,kube-proxy不會處理它們, 而且平臺也不會為它們進行負載均衡和路由,集群訪問通過dns解析直接指向到業務pod上的IP,所有的調度由 dns 單獨完成
[root@K8smaster build]# vim myappv1.yml
---
apiVersion: v1
kind: Service
metadata:labels:app: myappv1name: myappv1
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myappv1type: ClusterIPclusterIP: "None" #添加此代碼
進行域名的解析可以看到
3.3 nodeport
通過ipvs暴漏端口從而使外部主機通過master節點的對外ip,來訪問pod業務
- 其訪問過程為:
---
apiVersion: v1
kind: Service
metadata:labels:app: myappv1name: myappv1
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myappv1type: NodePoort #改為NodePort模式
可以看到會生成一個對外的訪問端口—32583
[root@K8smaster build]# kubectl get service myappv1
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myappv1 NodePort 10.104.59.217 <none> 80:32583/TCP 22s
通過訪問主機的IP+端口就可以訪問到pod上
!注意
nodeport默認端口
nodeport默認端口是30000-32767,超出會報錯
3.3.1 端口的固定優化
---
apiVersion: v1
kind: Service
metadata:labels:app: myappv1name: myappv1
spec:ports:- port: 80protocol: TCPtargetPort: 80nodePort: 36666 #設置固定的對外端口selector:app: myappv1type: NodePoort
如果需要使用這個范圍以外的端口就需要特殊設定
root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml- --service-node-port-range=30000-40000
[!NOTE]
添加“–service-node-port-range=“ 參數,端口范圍可以自定義
修改后api-server會自動重啟,等apiserver正常啟動后才能操作集群
集群重啟自動完成在修改完參數后全程不需要人為干預
3.4 loadbalancer
云平臺會為我們分配vip并實現訪問,如果是裸金屬主機那么需要metallb來實現ip的分配
[root@k8s-master ~]# vim myappv1.yaml---
apiVersion: v1
kind: Service
metadata:labels:app: myappv1name: myappv1
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myappv1type: LoadBalancer[root@k8s2 service]# kubectl apply -f myappv1.yml默認無法分配外部訪問IP
[root@k8s2 service]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d1h
myappv1 LoadBalancer 10.107.23.134 <pending> 80:32537/TCP 4s
LoadBalancer模式適用云平臺,裸金屬環境需要安裝metallb提供支持
3.5 metalLB
相當于網絡中的DHCP,為LoadBalancer分配vip
官網:https://metallb.universe.tf/installation/
部署方式
1.設置ipvs模式
[root@k8s-master ~]# kubectl edit cm -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:strictARP: true[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'2.下載部署文件
[root@k8s2 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml3.修改文件中鏡像地址,與harbor倉庫路徑保持一致
[root@k8s-master ~]# vim metallb-native.yaml
...
image: metallb/controller:v0.14.8
image: metallb/speaker:v0.14.84.上傳鏡像到harbor
[root@k8s-master ~]# docker pull quay.io/metallb/controller:v0.14.8
[root@k8s-master ~]# docker pull quay.io/metallb/speaker:v0.14.8[root@k8s-master ~]# docker tag quay.io/metallb/speaker:v0.14.8 reg.timinglee.org/metallb/speaker:v0.14.8
[root@k8s-master ~]# docker tag quay.io/metallb/controller:v0.14.8 reg.timinglee.org/metallb/controller:v0.14.8[root@k8s-master ~]# docker push reg.timinglee.org/metallb/speaker:v0.14.8
[root@k8s-master ~]# docker push reg.timinglee.org/metallb/controller:v0.14.8部署服務
[root@k8s2 metallb]# kubectl apply -f metallb-native.yaml
[root@k8s-master ~]# kubectl -n metallb-system get pods
NAME READY STATUS RESTARTS AGE
controller-65957f77c8-25nrw 1/1 Running 0 30s
speaker-p94xq 1/1 Running 0 29s
speaker-qmpct 1/1 Running 0 29s
speaker-xh4zh 1/1 Running 0 30s配置分配地址段
[root@k8s-master ~]# vim configmap.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:name: first-pool #地址池名稱namespace: metallb-system
spec:addresses:- 172.25.254.50-172.25.254.99 #修改為自己本地地址段--- #兩個不同的kind中間必須加分割
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:name: examplenamespace: metallb-system
spec:ipAddressPools:- first-pool #使用地址池 [root@k8s-master ~]# kubectl apply -f configmap.yml
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/example created[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h
timinglee-service LoadBalancer 10.109.36.123 172.25.254.50 80:31595/TCP 9m9s#通過分配地址從集群外訪問服務
[root@reg ~]# curl 172.25.254.50
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
4.6 externalname
- 開啟services后,不會被分配IP,而是用dns解析CNAME固定域名來解決ip變化問題
- 一般應用于外部業務和pod溝通或外部業務遷移到pod內時
- 在應用向集群遷移過程中,externalname在過度階段就可以起作用了。
- 集群外的資源遷移到集群時,在遷移的過程中ip可能會變化,但是域名+dns解析能完美解決此問題
示例:
[root@k8s-master ~]# vim timinglee.yaml
---
apiVersion: v1
kind: Service
metadata:labels:app: timinglee-servicename: timinglee-service
spec:selector:app: timingleetype: ExternalNameexternalName: www.timinglee.org[root@k8s-master ~]# kubectl apply -f timinglee.yaml[root@k8s-master ~]# kubectl get services timinglee-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
timinglee-service ExternalName <none> www.timinglee.org <none> 2m58s#測試:
[root@master service]# kubectl run test --image busyboxplus -it
If you don't see a command prompt, try pressing enter./# ping [root@master service]# kubectl run test --image busyboxplus -it
If you don't see a command prompt, try pressing enter./# ping ext-service.default.svc.cluster.local
PING ext-service.default.svc.cluster.local (103.235.46.115): 56 data bytes64 bytes from 103.235.46.115:seq=0 tt1=127 time=331.212 ms
(五)ingress-nginx
5.1 部署ingress
ingress-nginx功能
- 一種全局的、為了代理不同后端 Service 而設置的負載均衡服務,支持7層
- Ingress由兩部分組成:Ingress controller和Ingress服務
- Ingress Controller 會根據你定義的 Ingress 對象,提供對應的代理能力
- 業界常用的各種反向代理項目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已經為Kubernetes 專門維護了對應的 Ingress Controller
5.1.1 下載部署文件
在Harbor中創建項目ingress-nginx
#在Harbor倉庫上傳所需鏡像
docker tag registry.k8s.io/ingress-nginx/controller:v1.13.1 reg.zym.org/ingress-nginx/controller:v1.13.1docker tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.1 reg.zym.org/ingress-nginx/kube-webhook-certgen:v1.6.1docker push reg.zym.org/ingress-nginx/kube-webhook-certgen:v1.6.1
docker push reg.zym.org/ingress-nginx/controller:v1.13.1
5.1.2 安裝ingress
[root@k8s-master ~]# vim deploy.yaml
image: ingress-nginx/controller:v1.13.1
image: ingress-nginx/kube-webhook-certgen:v1.6.1
image: ingress-nginx/kube-webhook-certgen:v1.6.1[root@k8s-master ~]# kubectl -n ingress-nginx get pods
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-ggqm6 0/1 Completed 0 82s
ingress-nginx-admission-patch-q4wp2 0/1 Completed 0 82s
ingress-nginx-controller-7bf698f798-bkxq2 1/1 Running 0 82s[root@K8smaster build]# kubectl -n ingress-nginx get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.104.155.231 172.25.254.50 80:31247/TCP,443:31269/TCP 4h33m
ingress-nginx-controller-admission ClusterIP 10.103.168.235 <none> 443/TCP
提示:
EXTERNAL-IP
為對外開放的ip地址
5.1.3 測試ingress
#生成yaml文件
[root@k8s-master ~]# kubectl create ingress webcluster --rule '*/=timinglee-svc:80' --dry-run=client -o yaml > timinglee-ingress.yml
kubectl create ingress
- create表示創建資源,ingress指定要創建的資源類型是 Ingress
webcluster
- 創建的 Ingress 資源的名稱,它在所屬的命名空間內必須是唯一
--rule '*/=timinglee-svc:80'
-
–rule:參數用于定義 Ingress 的路由規則
*/=timinglee-svc:80
表示: -
*:匹配所有的主機名
-
/:匹配所有的 URL 路徑,即所有的 HTTP 請求路徑都會被這個規則處理
timinglee-svc
- 指定后端要轉發流量的 Service 名稱
--dry-run=client
- 該參數表示以客戶端模擬運行的方式執行命令,不會真正在集群中創建 Ingress 資源,僅在本地對命令進行語法檢查,并按照命令執行后的結果生成相應的數據結構
-o yaml
- -o是–output的縮寫,用于指定輸出格式,yaml表示將命令執行后的結果以 YAML 格式輸出
timinglee-ingress.yml
- 這是將命令輸出的 YAML 內容重定向到名為timinglee-ingress.yml的文件中,后續可以通過編輯該文件,對 Ingress 配置進行調整
[root@k8s-master ~]# vim timinglee-ingress.yml
aapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: test-ingress
spec:ingressClassName: nginxrules:- http:paths:- backend:service:name: timinglee-svcport:number: 80path: /pathType: Prefix #Exact(精確匹配),ImplementationSpecific(特定實現),Prefix(前綴匹配),Regular expression(正則表達式匹配)
#建立ingress控制器
[root@k8s-master ~]# kubectl apply -f timinglee-ingress.yml
ingress.networking.k8s.io/webserver created[root@k8s-master ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress nginx * 172.25.254.10 80 8m30s
5.2 ingress高級用法
5.2.1 基于路徑進行訪問
A. 測試配置yaml編寫
[root@k8s-master app]# kubectl create deployment myapp-v1 --image myapp:v1 --dry-run=client -o yaml > myapp-v1.yaml[root@k8s-master app]# kubectl create deployment myapp-v2 --image myapp:v2 --dry-run=client -o yaml > myapp-v2.yaml[root@k8s-master app]# vim myapp-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: myapp-v1name: myapp-v1
spec:replicas: 1selector:matchLabels:app: myapp-v1strategy: {}template:metadata:labels:app: myapp-v1spec:containers:- image: myapp:v1name: myapp---apiVersion: v1
kind: Service
metadata:labels:app: myapp-v1name: myapp-v1
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myapp-v1[root@k8s-master app]# vim myapp-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: myapp-v2name: myapp-v2
spec:replicas: 1selector:matchLabels:app: myapp-v2template:metadata:labels:app: myapp-v2spec:containers:- image: myapp:v2name: myapp
---
apiVersion: v1
kind: Service
metadata:labels:app: myapp-v2name: myapp-v2
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: myapp-v2
#將端口寫到容器內
[root@k8s-master app]# kubectl expose deployment myapp-v1 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml[root@k8s-master app]# kubectl expose deployment myapp-v2 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml
查看services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d23h
myapp-v1 ClusterIP 10.111.66.48 <none> 80/TCP 11h
myapp-v2 ClusterIP 10.106.191.86 <none> 80/TCP 11h
B. 編寫建立ingress的yaml文件
#vim ingress1.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/rewrite-target: /name: ingress1
spec:ingressClassName: nginxrules:- host: www.timinglee.orghttp:paths:- backend:service:name: myapp-v1port:number: 80path: /v1pathType: Prefix- backend:service:name: myapp-v2port:number: 80path: /v2pathType: Prefix
C. 效果測試:
#測試:
[root@reg ~]# echo 172.25.254.50 www.timinglee.org >> /etc/hosts[root@reg ~]# curl www.timinglee.org/v1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@reg ~]# curl www.timinglee.org/v2
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>#nginx.ingress.kubernetes.io/rewrite-target: / 功能實現
[root@reg ~]# curl www.timinglee.org/v2/aaaa
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
5.2.4 建立auth認證
#建立認證文件
[root@k8s-master app]# dnf install httpd-tools -y
[root@k8s-master app]# htpasswd -cm auth lee
New password:
Re-type new password:
Adding password for user lee
[root@k8s-master app]# cat auth
lee:$apr1$BohBRkkI$hZzRDfpdtNzue98bFgcU10#建立認證類型資源
[root@k8s-master app]# kubectl create secret generic auth-web --from-file auth
root@k8s-master app]# kubectl describe secrets auth-web
Name: auth-web
Namespace: default
Labels: <none>
Annotations: <none>Type: OpaqueData
====
auth: 42 bytes
#建立ingress4基于用戶認證的yaml文件
[root@k8s-master app]# vim ingress4.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/auth-type: basicnginx.ingress.kubernetes.io/auth-secret: auth-webnginx.ingress.kubernetes.io/auth-realm: "Please input username and password"name: ingress4
spec:tls:- hosts:- myapp-tls.timinglee.orgsecretName: web-tls-secretingressClassName: nginxrules:- host: myapp-tls.timinglee.orghttp:paths:- backend:service:name: myapp-v1port:number: 80path: /pathType: Prefix#建立ingress4
[root@k8s-master app]# kubectl apply -f ingress4.yml
ingress.networking.k8s.io/ingress4 created
[root@k8s-master app]# kubectl describe ingress ingress4
Name: ingress4
Labels: <none>
Namespace: default
Address:
Ingress Class: nginx
Default backend: <default>
TLS:web-tls-secret terminates myapp-tls.timinglee.org
Rules:Host Path Backends---- ---- --------myapp-tls.timinglee.org/ myapp-v1:80 (10.244.2.31:80)
Annotations: nginx.ingress.kubernetes.io/auth-realm: Please input username and passwordnginx.ingress.kubernetes.io/auth-secret: auth-webnginx.ingress.kubernetes.io/auth-type: basic
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Sync 14s nginx-ingress-controller Scheduled for sync
結果測試:測試前需要解析主機名
(六)Canary金絲雀發布
6.1 金絲雀發布介紹
金絲雀發布(Canary Release)也稱為灰度發布,是一種軟件發布策略。
主要目的是在將新版本的軟件全面推廣到生產環境之前,先在一小部分用戶或服務器上進行測試和驗證,以降低因新版本引入重大問題而對整個系統造成的影響。
是一種Pod的發布方式。金絲雀發布采取先添加、再刪除的方式,保證Pod的總量不低于期望值。并且在更新部分Pod后,暫停更新,當確認新Pod版本運行正常后再進行其他版本的Pod的更新。
6.2 Canary發布方式
其中header和weiht中的最多
6.2.1 基于header(http包頭)灰度
- 通過Annotaion擴展
- 創建灰度ingress,配置灰度頭部key以及value
- 灰度流量驗證完畢后,切換正式ingress到新版本
- 之前我們在做升級時可以通過控制器做滾動更新,默認25%利用header可以使升級更為平滑,通過key 和vule 測試新的業務體系是否有問題。
配置示例:
#建立版本1的ingress
[root@k8s-master app]# vim ingress7.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:name: myapp-v1-ingress
spec:ingressClassName: nginxrules:- host: myapp.zym.orghttp:paths:- backend:service:name: myapp-v1port:number: 80path: /pathType: Prefix[root@k8s-master app]# kubectl apply -f ingress7.yml
如圖配置查看
#建立基于版本2的ingress
[root@k8s-master app]# vim ingress8.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-by-header: versionnginx.ingress.kubernetes.io/canary-by-header-value: "2"name: myapp-v2-ingress
spec:ingressClassName: nginxrules:- host: myapp.zym.orghttp:paths:- backend:service:name: myapp-v2port:number: 80path: /pathType: Prefix[root@k8s-master app]# kubectl apply -f ingress8.yml
ingress.networking.k8s.io/myapp-v2-ingress created
#測試:
[root@K8smaster build]# curl myapp.zym.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@K8smaster build]# curl -H "version: 2" myapp.zym.org
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
6.2.2 基于權重的灰度發布
- 通過Annotaion拓展
- 創建灰度ingress,配置灰度權重以及總權重
- 灰度流量驗證完畢后,切換正式ingress到新版本
配置示例
#基于權重的灰度發布
[root@k8s-master app]# vim ingress8.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "10" #更改權重值nginx.ingress.kubernetes.io/canary-weight-total: "100"name: myapp-v2-ingress
spec:ingressClassName: nginxrules:- host: myapp.timinglee.orghttp:paths:- backend:service:name: myapp-v2port:number: 80path: /pathType: Prefix[root@k8s-master app]# kubectl apply -f ingress8.yml
ingress.networking.k8s.io/myapp-v2-ingress created#測試:
[root@reg ~]# vim check_ingress.sh
#!/bin/bash
v1=0
v2=0for (( i=0; i<100; i++))
doresponse=`curl -s myapp.timinglee.org |grep -c v1`v1=`expr $v1 + $response`v2=`expr $v2 + 1 - $response`done
echo "v1:$v1, v2:$v2"[root@reg ~]# sh check_ingress.sh
v1:90, v2:10#更改完畢權重后繼續測試可觀察變化
六、K8s儲存管理
(一)configmap
1.1 configmap的功能
用于存儲非敏感的配置數據,以鍵值對的形式存在,使得應用程序可以在不修改鏡像的情況下讀取不同的配置信息,進行pod的配置
- configMap用于保存配置數據,以鍵值對形式存儲
- configMap 資源提供了向 Pod 注入配置數據的方法
- 鏡像和配置文件解耦,以便實現鏡像的可移植性和可復用性
- etcd限制了文件大小不能超過1M
1.2 configmap的使用場景
- 填充環境變量的值
- 設置容器內的命令行參數
- 填充卷的配置文件
1.3 configmap創建方式
1.3.1 字面值的創建
[root@K8smaster ~]# kubectl create cm zym-config --from-literal fname=liubailiushiliu --from-literal name=zym
configmap/zym-config created
[root@K8smaster ~]# kubectl describe cm zym-config
Name: zym-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
fname:
----
liubailiushiliu
name:
----
zymBinaryData
====Events: <none>
1.3.2 通過文件創建
[root@K8smaster ~]# kubectl create cm zym2-config --from-file /etc/resolv.conf
configmap/zym2-config created
[root@K8smaster ~]# kubectl describe cm zym2-config
Name: zym2-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
resolv.conf:
----
# Generated by NetworkManager
search zym.org
nameserver 8.8.8.8BinaryData
====Events: <none>
1.3.3 通過目錄創建
[root@K8smaster ~]# kubectl create cm zym3-config --from-file zymconfig/
configmap/zym3-config created
[root@K8smaster ~]# kubectl describe cm zym3-config
Name: zym3-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
fstab:
----#
# /etc/fstab
# Created by anaconda on Fri Jul 11 02:10:59 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=c37e3bfa-0b77-4e9a-9b23-880e9bd2dfab / xfs defaults 0 0
UUID=c2a71f8f-02fb-407f-94f0-91e81b201c49 /boot xfs defaults 0 0
#UUID=1d85bab1-7292-44e0-8c9f-cc996a24a9a2 none swap defaults 0 0rc.local:
----
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.touch /var/lock/subsys/local
mount /dev/cdrom /rhel9/
mount /dev/cdrom /rhel9/BinaryData
====Events: <none>
1.3.4 通過yaml文件創建
[root@K8smaster ~]# kubectl create cm zym4-config --from-literal db_host=192.168.147.100 --from-literal db_port=3306 --dry-run=client -o yaml > zym-config.yamlapiVersion: v1
data:db_host: 192.168.147.100db_port: "3306"
kind: ConfigMap
metadata:name: zym4-config#生成configmap
[root@K8smaster ~]# kubectl apply -f zym-config.yaml
[root@K8smaster ~]# kubectl describe cm zym4-config
Name: zym4-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
db_host:
----
192.168.147.100
db_port:
----
3306BinaryData
====Events: <none>
1.4 configmap使用方式
- 通過環境變量的方式直接傳遞,掛載到pod中
- 通過pod的命令行運行方式
1.4.1 使用configmap填充環境變量
注意:Kubectl apply只能在正在運行中的pod進行打補丁
#把cm中的內容映射為指定變量
[root@k8s-master ~]# vim testpod1.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:containers:- image: busyboxplus:latestname: testpodcommand:- /bin/sh- -c- envenv:- name: key1valueFrom:configMapKeyRef:name: zym4-configkey: db_host- name: key2valueFrom:configMapKeyRef:name: zym4-configkey: db_portrestartPolicy: Never[root@k8s-master ~]# kubectl apply -f testpod.yml
pod/testpod created
#把cm中的值直接映射為變量
[root@k8s-master ~]# vim testpod2.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:containers:- image: busyboxplus:latestname: testpodcommand:- /bin/sh- -c- envenvFrom:- configMapRef:name: lee4-configrestartPolicy: Never#查看日志
[root@k8s-master ~]# kubectl logs pods/testpod
#在pod命令行中使用變量
[root@k8s-master ~]# vim testpod3.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:containers:- image: busyboxplus:latestname: testpodcommand:- /bin/sh- -c- echo ${db_host} ${db_port} #變量調用需envFrom:- configMapRef:name: lee4-configrestartPolicy: Never#查看日志
[root@k8s-master ~]# kubectl logs pods/testpod
172.25.254.100 3306
(二)secrets配置管理
2.1 功能介紹
在公有和私有的倉庫中,均需要密鑰信息才可以被使用
-
敏感信息放在 secret 中比放在 Pod 的定義或者容器鏡像中來說更加安全和靈活
-
Pod 可以用兩種方式使用 secret:
- 作為 volume 中的文件被掛載到 pod 中的一個或者多個容器里
-
當 kubelet 為 pod 拉取鏡像時使用
2.2 secret創建方法
[root@K8smaster ~]# mkdir -p secrets
[root@K8smaster ~]# echo -n zym > username.txt
[root@K8smaster ~]# echo -n 123456 > password.txt[root@K8smaster ~]# kubectl create secret generic userlist --from-file username.txt --from-file password.txt
查看信息:
#查看密碼編碼
[root@K8smaster ~]# echo -n zym | base64
enlt
[root@K8smaster ~]# echo -n 123456 | base64
MTIzNDU2[root@k8s-master secrets]# kubectl create secret generic userlist --dry-run=client -o yaml > userlist.yml
編寫yaml
apiVersion: v1
kind: Secret
metadata:creationTimestamp: nullname: userlist
type: Opaque
data:username: enlt #用戶名password: MTIzNDU2 #密碼
查看:
[root@K8smaster secrets]# kubectl apply -f userlist.yml
2.3 Secretss使用方法
2.3.4 存儲docker registry的認證信息
建立私有倉庫并上傳鏡像
成功上傳,如上圖所示
[root@Harbor packages]# docker load -i game2048.tar.gz
Loaded image: timinglee/game2048:latest[root@Harbor packages]# docker tag timinglee/game2048:latest reg.zym.org/zym/game2048:latest[root@Harbor packages]# docker push reg.zym.org/zym/game2048
創建Docker認證的secret
[root@K8smaster build]# kubectl create secret docker-registry my-registry-secret --docker-server=reg.zym.org --docker-username=admin --docker-password=123456
編寫yaml文件
apiVersion: v1
kind: Pod
metadata:labels:name: game2048name: game2048
spec:imagePullSecrets: #鏡像拉取密鑰- name: my-registry-secret #密鑰名稱containers:- image: reg.zym.org/zym/game2048:latestname: game2048
運行:
[root@K8smaster build]# kubectl apply -f pod3.yml
pod/game2048 created
[root@K8smaster build]# kubectl get pods
NAME READY STATUS RESTARTS AGE
game2048 1/1 Running 0 12s
(三) volumes卷配置管理
卷的兩點重要性
- 數據的持久化
- 共享存儲
存儲卷的區別
存儲類型 | 生命周期 | 數據持久性 | 適用場景 |
---|---|---|---|
emptyDir | 與 Pod 綁定 | 臨時(Pod 刪除丟失) | 容器間臨時共享數據 |
hostPath | 與節點綁定 | 節點本地持久化 | 單節點測試(不適合生產) |
PersistentVolume | 集群級獨立生命周期 | 跨 Pod / 節點持久化 | 生產環境數據存儲(如數據庫) |
3.1 emptyDir卷
emptyDir
是 Kubernetes 中一種簡單的臨時存儲卷,它的核心特點是生命周期與 Pod 綁定,主要用于 Pod 內部容器之間共享數據,或存儲臨時數據
- 無法進行數據的持久化
emptyDir 的使用場景:
- 緩存空間,例如基于磁盤的歸并排序
- 耗時較長的計算任務提供檢查點,以便任務能方便地從崩潰前狀態恢復執行
- 在 Web 服務器容器服務數據時,保存內容管理器容器獲取的文件
示例配置:
[root@k8s-master volumes]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:name: vol1
spec:containers:- image: busyboxplus:latestname: vm1command:- /bin/sh- -c- sleep 30000000volumeMounts:- mountPath: /cachename: cache-vol- image: nginx:latestname: vm2volumeMounts:- mountPath: /usr/share/nginx/htmlname: cache-volvolumes:- name: cache-volemptyDir:medium: MemorysizeLimit: 100Mi[root@k8s-master volumes]# kubectl apply -f pod1.yml#查看pod中卷的使用情況
[root@k8s-master volumes]# kubectl describe pods vol1#測試效果[root@k8s-master volumes]# kubectl exec -it pods/vol1 -c vm1 -- /bin/sh
/ # cd /cache/
/cache # ls
/cache # curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>
/cache # echo timinglee > index.html
/cache # curl localhost
timinglee
/cache # dd if=/dev/zero of=bigfile bs=1M count=101
dd: writing 'bigfile': No space left on device
101+0 records in
99+1 records out
3.2 hostpath卷
在 Kubernetes 中,hostPath
卷的核心功能是將節點(Node)的本地文件系統路徑掛載到 Pod 的容器中,實現 Pod 與所在節點之間的文件共享
- 可以進行數據持久化保存
示例配置:
apiVersion: v1
kind: Pod
metadata:name: vol1
spec:containers:- image: nginx:1.23name: vm1volumeMounts:- mountPath: /usr/share/nginx/htmlname: cache-volvolumes:- name: cache-volhostPath:path: /datatype: DirectoryOrCreate #當/data目錄不存在時自動建立
測試:
[root@K8smaster build]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
vol1 1/1 Running 0 5m33s 10.244.3.6 k8sslave2.zym.org
在node節點上
[root@k8s-node2 ~]# echo liubailiu > /data/index.html
[root@k8s-master volumes]# curl 10.244.3.6s
liubailiu#當pod被刪除后hostPath不會被清理
[root@k8s-master volumes]# kubectl delete -f pod2.yml
pod "vol1" deleted
[root@k8s-node2 ~]# ls /data/
index.html
3.4 nfs卷
-
NFS 卷允許將一個現有的 NFS 服務器上的目錄掛載到 Kubernetes 中的 Pod 中,意思是:在集群以外創建一個NFS的服務器,pod掛載在NFS卷上,實現數據的持久化
-
如果有多個容器需要訪問相同的數據集,或者需要將容器中的數據持久保存到外部存儲,NFS 卷可以提供一種方便的解決方案
3.4.1部署一臺nfs共享主機
#舉例用Harbor倉庫作為nfs共享主機
[root@Harbor packages]# dnf install nfs-utils -y[root@Harbor ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)[root@Harbor ~]# mkdir -p /nfsdata
[root@Harbor ~]# exportfs -rv
exporting *:/nfsdata[root@Harbor ~]# showmount -e
Export list for Harbor.zym.org:
/nfsdata *
K8s集群上的所有節點均需安裝nfs-utils
[root@k8s-master & node1 & node2 ~]# dnf install nfs-utils -y
3.4.2 部署nfs卷
配置yaml文件–pod3.yml
apiVersion: v1
kind: Pod
metadata:name: vol1
spec:containers:- image: nginx:1.23name: vm1volumeMounts:- mountPath: /usr/share/nginx/htmlname: cache-volvolumes:- name: cache-volnfs:server: 192.168.147.200path: /nfsdata[root@K8smaster build]# kubectl apply -f pod3.yml
pod/vol1 created[root@K8smaster build]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
vol1 1/1 Running 0 20s 10.244.3.8 k8sslave2.zym.org
#訪問該IP
curl 10.244.3.8
測試:
在nfs主機上創建內容文件
[root@Harbor ~]# echo liubailiushiliu > /nfsdata/index.html
集群中訪問查看
3.5 PersistentVolume持久卷
PV 的核心是將存儲資源(如 NFS、本地磁盤、云存儲等)抽象為集群中的一種 “資源”,供 Pod 通過 PersistentVolumeClaim(PVC)申請使用,解決了 Pod 生命周期與數據持久化的矛盾(Pod 刪除后,PV 中的數據仍可保留)
- pv和pod是相互獨立的
- pv是集群中的一種資源,是一種Volume的插件
- pv的提供方式有兩種方式:
- 靜態PV:集群管理員創建多個PV,它們攜帶著真實存儲的詳細信息,它們存在于Kubernetes API中,并可用于存儲使用
- 動態PV:當管理員創建的靜態PV都不匹配用戶的PVC時,集群可能會嘗試專門地供給volume給PVC。這種供給基于StorageClass;當pod要使用資源的時候,會調用一個class自動創建pv存儲分配器,去到nfs主機中讀取數據
PersistentVolumeClaim(持久卷聲明,簡稱PVC)
-
是用戶的一種存儲請求
-
它和Pod類似,Pod消耗Node資源,而PVC消耗PV資源
-
Pod能夠請求特定的資源(如CPU和內存)。PVC能夠請求指定的大小和訪問的模式持久卷配置
-
PVC與PV的綁定是一對一的映射。沒找到匹配的PV,那么PVC會無限期得處于unbound未綁定狀態
volumes
-
容量(capacity):指定存儲大小(如 10Gi)
-
訪問模式(accessModes)
:支持的訪問方式,包括:
ReadWriteOnce(RWO)
:僅允許單個節點讀寫ReadOnlyMany(ROX)
:允許多個節點只讀ReadWriteMany(RWX)
:允許多個節點讀寫(需存儲類型支持)
-
回收策略(persistentVolumeReclaimPolicy)
:PVC 釋放后 PV 的處理方式:
Retain
:保留數據,需手動清理(默認)Delete
:自動刪除 PV 及關聯存儲(適合云存儲)Recycle
:清空數據后可被重新申請(已廢棄,推薦用 Retain)
-
存儲類(storageClassName):關聯到特定存儲類(StorageClass),實現動態 PV 創建
注意:
[!NOTE]
只有NFS和HostPath支持回收利用
AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷支持刪除操作
靜態PV實例
#在nfs主機中建立實驗目錄
[root@reg ~]# mkdir /nfsdata/pv{1..3}
#編寫創建pv的yml文件,pv是集群資源,不在任何namespace中
[root@k8s-master pvc]# vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:name: pv1
spec:capacity:storage: 5GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv1server: 192.168.147.200---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv2
spec:capacity:storage: 15GivolumeMode: FilesystemaccessModes:- ReadWriteManypersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv2server: 192.168.147.200
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv3
spec:capacity:storage: 25GivolumeMode: FilesystemaccessModes:- ReadOnlyManypersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv3server: 192.168.1417.200
[root@K8smaster pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pv1 5Gi RWO Retain Available nfs <unset> 5s
pv2 15Gi RWX Retain Available nfs <unset> 5s
pv3 25Gi ROX Retain Available nfs <unset> 5s
#建立pvc,pvc是pv使用的申請,需要保證和pod在一個namesapce中
[root@k8s-master pvc]# vim pvc.ym
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc1
spec:storageClassName: nfsaccessModes:- ReadWriteOnceresources:requests:storage: 1Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc2
spec:storageClassName: nfsaccessModes:- ReadWriteManyresources:requests:storage: 10Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc3
spec:storageClassName: nfsaccessModes:- ReadOnlyManyresources:requests:storage: 15Gi
如圖所示:為Bound狀態
#在其他namespace中是無法應用
[root@k8s-master pvc]# kubectl -n kube-system get pvc
No resources found in kube-system namespace.
在pod中使用pvc
[root@k8s-master pvc]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:name: timinglee
spec:containers:- image: nginxname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: vol1volumes:- name: vol1persistentVolumeClaim:claimName: pvc1[root@k8s-master pvc]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
timinglee 1/1 Running 0 83s 10.244.2.54 k8s-node2 <none> <none>
[root@k8s-master pvc]# kubectl exec -it pods/timinglee -- /bin/bash
root@timinglee:/# curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>
root@timinglee:/# cd /usr/share/nginx/
root@timinglee:/usr/share/nginx# ls
html
root@timinglee:/usr/share/nginx# cd html/
root@timinglee:/usr/share/nginx/html# ls[root@reg ~]# echo timinglee > /data/pv1/index.html[root@k8s-master pvc]# kubectl exec -it pods/timinglee -- /bin/bash
root@timinglee:/# cd /usr/share/nginx/html/
root@timinglee:/usr/share/nginx/html# ls
index.html
排錯方法:
kubectl -n nfs-client-provisioner get pods
kubectl -n nfs-client-provisioner describe pod <pod名稱> # 替換為上一步獲取的Pod名稱
(四)存儲類storageclass
StorageClass(存儲類) 是用于動態管理持久化存儲的 API 資源,它為管理員提供了一種定義 “存儲類型” 的方式,能夠自動創建滿足特定需求的持久卷(PersistentVolume,PV),從而簡化存儲管理流程
- StorageClass提供了一種描述存儲類(class)的方法,不同的class可能會映射到不同的服務
- 每個 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 這些字段會在StorageClass需要動態分配 PersistentVolume 時會使用到
4.1 StorageClass的屬性
屬性說明:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
**Provisioner(存儲分配器):**用來決定使用哪個卷插件分配 PV,該字段必須指定。可以指定內部分配器,也可以指定外部分配器。外部分配器的代碼地址為: kubernetes-incubator/external-storage,其中包括NFS和Ceph等。
**Reclaim Policy(回收策略):**通過reclaimPolicy字段指定創建的Persistent Volume的回收策略,回收策略包括:Delete 或者 Retain,沒有指定默認為Delete。
4.2 存儲分配器NFS Client Provisioner
源碼地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
-
NFS Client Provisioner是一個automatic provisioner,使用NFS作為存儲,自動創建PV和對應的PVC,本身不提供NFS存儲,需要外部先有一套NFS存儲服務。
-
PV以
${namespace}-${pvcName}-${pvName}
的命名格式提供(在NFS服務器上) -
PV回收的時候以
archieved-${namespace}-${pvcName}-${pvName}
的命名格式(在NFS服務器上)
4.3 部署NFS Client Provisioner
4.3.1 創建sa并授權
[root@k8s-master storageclass]# vim rbac.yml
apiVersion: v1
kind: Namespace
metadata:name: nfs-client-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisionernamespace: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: nfs-client-provisioner-runner
rules:- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list", "watch"] #設置可以“顯示,列出,監控”的動作- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: run-nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-client-provisioner
roleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-client-provisioner
rules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-client-provisioner
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io#查看rbac信息
[root@k8s-master storageclass]# kubectl apply -f rbac.yml
namespace/nfs-client-provisioner created
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@k8s-master storageclass]# kubectl -n nfs-client-provisioner get sa
NAME SECRETS AGE
default 0 14s
nfs-client-provisioner 0 14s
4.4.2 部署應用
[root@k8s-master storageclass]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nfs-client-provisionerlabels:app: nfs-client-provisionernamespace: nfs-client-provisioner
spec:replicas: 1strategy:type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisionercontainers:- name: nfs-client-provisionerimage: sig-storage/nfs-subdir-external-provisioner:v4.0.2volumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner- name: NFS_SERVERvalue: 172.25.254.250- name: NFS_PATHvalue: /nfsdatavolumes:- name: nfs-client-rootnfs:server: 172.25.254.250path: /nfsdata[root@k8s-master storageclass]# kubectl -n nfs-client-provisioner get deployments.apps nfs-client-provisioner
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 86s
4.4.3 創建存儲類
[root@k8s-master storageclass]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:archiveOnDelete: "false"[root@k8s-master storageclass]# kubectl apply -f class.yaml
storageclass.storage.k8s.io/nfs-client created
[root@k8s-master storageclass]# kubectl get storageclasses.storage.k8s.io
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 9s
4.4.4 創建pvc
[root@k8s-master storageclass]# vim pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: test-claim
spec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 1G
[root@k8s-master storageclass]# kubectl apply -f pvc.yml
persistentvolumeclaim/test-claim created[root@k8s-master storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-claim Bound pvc-7782a006-381a-440a-addb-e9d659b8fe0b 1Gi RWX nfs-client <unset> 21m
4.4.5 創建測試pod
[root@k8s-master storageclass]# vim pod.yml
kind: Pod
apiVersion: v1
metadata:name: test-pod
spec:containers:- name: test-podimage: busyboxcommand:- "/bin/sh"args:- "-c"- "touch /mnt/SUCCESS && exit 0 || exit 1"volumeMounts:- name: nfs-pvcmountPath: "/mnt"restartPolicy: "Never"volumes:- name: nfs-pvcpersistentVolumeClaim:claimName: test-claim[root@k8s-master storageclass]# kubectl apply -f pod.yml[root@reg ~]# ls /data/default-test-claim-pvc-b1aef9cc-4be9-4d2a-8c5e-0fe7716247e2/
SUCCESS
4.4.6 設置默認存儲類
-
在未設定默認存儲類時pvc必須指定使用類的名稱
-
在設定存儲類后創建pvc時可以不用指定storageClassName
#一次性指定多個pvc
[root@k8s-master pvc]# vim pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc1
spec:storageClassName: nfs-clientaccessModes:- ReadWriteOnceresources:requests:storage: 1Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc2
spec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 10Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc3
spec:storageClassName: nfs-clientaccessModes:- ReadOnlyManyresources:requests:storage: 15Giroot@k8s-master pvc]# kubectl apply -f pvc.yml
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created
[root@k8s-master pvc]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
pvc1 Bound pvc-25a3c8c5-2797-4240-9270-5c51caa211b8 1Gi RWO nfs-client <unset> 4s
pvc2 Bound pvc-c7f34d1c-c8d3-4e7f-b255-e29297865353 10Gi RWX nfs-client <unset> 4s
pvc3 Bound pvc-5f1086ad-2999-487d-88d2-7104e3e9b221 15Gi ROX nfs-client <unset> 4s
test-claim Bound pvc-b1aef9cc-4be9-4d2a-8c5e-0fe7716247e2 1Gi RWX nfs-client <unset> 9m9s
設定默認存儲類
[root@k8s-master storageclass]# kubectl edit sc nfs-client
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"nfs-client"},"parameters":{"archiveOnDelete":"false"},"provisioner":"k8s-sigs.io/nfs-subdir-external-provisioner"}storageclass.kubernetes.io/is-default-class: "true" #設定默認存儲類creationTimestamp: "2024-09-07T13:49:10Z"name: nfs-clientresourceVersion: "218198"uid: 9eb1e144-3051-4f16-bdec-30c472358028
parameters:archiveOnDelete: "false"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate#測試,未指定storageClassName參數
[root@k8s-master storageclass]# vim pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: test-claim
spec:accessModes:- ReadWriteManyresources:requests:storage: 1Gi[root@k8s-master storageclass]# kubectl apply -f pvc.yml
persistentvolumeclaim/test-claim created
[root@k8s-master storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-claim Bound pvc-b96c6983-5a4f-440d-99ec-45c99637f9b5 1Gi RWX nfs-client <unset> 7s
(五)StatefulSet控制器
用于管理有狀態應用的工作負載控制器,專為需要穩定標識、持久存儲和有序部署 / 擴展 / 更新的應用設計。與管理無狀態應用的 Deployment 不同,StatefulSet 為每個 Pod 提供固定的身份和一致的部署順序,確保有狀態服務(如數據庫、分布式系統、消息隊列等)的可靠運行
StatefulSet 的工作依賴兩個關鍵組件:
- Headless Service:為 Pod 提供穩定的網絡標識(DNS 記錄),不分配集群 IP
- StatefulSet 資源:定義 Pod 模板、擴縮容策略、更新策略等
5.1 構建方法
#建立無頭服務
[root@k8s-master statefulset]# vim headless.yml
apiVersion: v1
kind: Service
metadata:name: nginx-svclabels:app: nginx
spec:ports:- port: 80name: webclusterIP: Noneselector:app: nginx
[root@k8s-master statefulset]# kubectl apply -f headless.yml#建立statefulset
[root@k8s-master statefulset]# vim statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:serviceName: "nginx-svc"replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxvolumeMounts:- name: wwwmountPath: /usr/share/nginx/htmlvolumeClaimTemplates:- metadata:name: wwwspec:storageClassName: nfs-clientaccessModes:- ReadWriteOnceresources:kuberequests:storage: 1Gi
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml
statefulset.apps/web configured
root@k8s-master statefulset]# kubectl get pods
NAME READY STATUS RESTARTS kuh AGE
web-0 1/1 Running 0 3m26s
web-1 1/1 Running 0 3m22s
web-2 1/1 Running 0 3m18s[root@reg nfsdata]# ls /nfsdata/
default-test-claim-pvc-34b3d968-6c2b-42f9-bbc3-d7a7a02dcbac
default-www-web-0-pvc-0390b736-477b-4263-9373-a53d20cc8f9f
default-www-web-1-pvc-a5ff1a7b-fea5-4e77-afd4-cdccedbc278c
default-www-web-2-pvc-83eff88b-4ae1-4a8a-b042-8899677ae854
5.2 測試:
#為每個pod建立index.html文件[root@reg nfsdata]# echo web-0 > default-www-web-0-pvc-0390b736-477b-4263-9373-a53d20cc8f9f/index.html
[root@reg nfsdata]# echo web-1 > default-www-web-1-pvc-a5ff1a7b-fea5-4e77-afd4-cdccedbc278c/index.html
[root@reg nfsdata]# echo web-2 > default-www-web-2-pvc-83eff88b-4ae1-4a8a-b042-8899677ae854/index.html#建立測試pod訪問web-0~2
[root@k8s-master statefulset]# kubectl run -it testpod --image busyboxplus
/ # curl web-0.nginx-svc
web-0
/ # curl web-1.nginx-svc
web-1
/ # curl web-2.nginx-svc
web-2#刪掉重新建立statefulset
[root@k8s-master statefulset]# kubectl delete -f statefulset.yml
statefulset.apps "web" deleted
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml
statefulset.apps/web created#訪問依然不變
[root@k8s-master statefulset]# kubectl attach testpod -c testpod -i -t
If you don't see a command prompt, try pressing enter.
/ # cu
curl cut
/ # curl web-0.nginx-svc
web-0
/ # curl web-1.nginx-svc
web-1
/ # curl web-2.nginx-svc
web-2
測試截圖:
5.3 statefulset的彈縮
首先,想要彈縮的StatefulSet. 需先清楚是否能彈縮該應用
用命令改變副本數
$ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
通過編輯配置改變副本數
$ kubectl edit statefulsets.apps <stateful-set-name>
statefulset有序回收
[root@k8s-master statefulset]# kubectl scale statefulset web --replicas 0
statefulset.apps/web scaled
[root@k8s-master statefulset]# kubectl delete -f statefulset.yml
statefulset.apps "web" deleted
[root@k8s-master statefulset]# kubectl delete pvc --all
persistentvolumeclaim "test-claim" deleted
persistentvolumeclaim "www-web-0" deleted
persistentvolumeclaim "www-web-1" deleted
persistentvolumeclaim "www-web-2" deleted
persistentvolumeclaim "www-web-3" deleted
persistentvolumeclaim "www-web-4" deleted
persistentvolumeclaim "www-web-5" deleted
[root@k8s2 statefulset]# kubectl scale statefulsets web --replicas=0[root@k8s2 statefulset]# kubectl delete -f statefulset.yaml[root@k8s2 mysql]# kubectl delete pvc --all
七、K8s通信與調度
(一)網絡通信
1.1 k8s的通信架構
- k8s通過CNI接口接入其他插件來實現網絡通訊。目前比較流行的插件有flannel,calico等
- CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
插件使用的解決方案如下:
? a. 虛擬網橋,虛擬網卡,多個容器共用一個虛擬網卡進行通信
? b. 多路復用:MacVLAN,多個容器共用一個物理網卡進行通信
? c. 硬件交換:SR-LOV,一個物理網卡可以虛擬出多個接口,這個性能最好
- 容器間通信:
- 同一個pod內的多個容器間的通信,通過lo回環接口即可實現pod之間的通信
- 同一節點的pod之間通過cni網橋轉發數據包。
- 不同節點的pod之間的通信需要網絡插件支持
- pod和service通信: 通過iptables或ipvs實現通信,ipvs取代不了iptables,因為ipvs只能做負載均衡,做不了nat轉換
- pod和外網通信:iptables的MASQUERADE
- Service與集群外部客戶端的通信;(ingress、nodeport、loadbalancer)
1.2 flannel網絡插件
插件組成:
插件 | 功能 |
---|---|
VXLAN | 即Virtual Extensible LAN(虛擬可擴展局域網),是Linux本身支持的一網種網絡虛擬化技術。VXLAN可以完全在內核態實現封裝和解封裝工作,從而通過“隧道”機制,構建出覆蓋網絡(Overlay Network) |
VTEP | VXLAN Tunnel End Point(虛擬隧道端點),在Flannel中 VNI的默認值是1,這也是為什么宿主機的VTEP設備都叫flannel.1的原因 |
Cni0 | 網橋設備,每創建一個pod都會創建一對 veth pair。其中一端是pod中的eth0,另一端是Cni0網橋中的端口(網卡) |
Flannel.1 | TUN設備(虛擬網卡),用來進行 vxlan 報文的處理(封包和解包)。不同node之間的pod數據流量都從overlay設備以隧道的形式發送到對端 |
Flanneld | flannel在每個主機中運行flanneld作為agent,它會為所在主機從集群的網絡地址空間中,獲取一個小的網段subnet,本主機內所有容器的IP地址都將從中分配。同時Flanneld監聽K8s集群數據庫,為flannel.1設備提供封裝數據時必要的mac、ip等網絡數據信息 |
1.2.1 flannel跨主機通信原理
通信原理解析:
- 當容器發送IP包,通過veth pair 發往cni網橋,再路由到本機的flannel.1設備進行處理。
- VTEP設備之間通過二層數據幀進行通信,源VTEP設備收到原始IP包后,在上面加上一個目的MAC地址,封裝成一個內部數據幀,發送給目的VTEP設備。
- 內部數據楨,并不能在宿主機的二層網絡傳輸,Linux內核還需要把它進一步封裝成為宿主機的一個普通的數據幀,承載著內部數據幀通過宿主機的eth0進行傳輸
- Linux會在內部數據幀前面,加上一個VXLAN頭,VXLAN頭里有一個重要的標志叫VNI,它是VTEP識別某個數據楨是不是應該歸自己處理的重要標識
- flannel.1設備只知道另一端flannel.1設備的MAC地址,卻不知道對應的宿主機地址是什么。在linux內核里面,網絡設備進行轉發的依據,來自FDB的轉發數據庫,這個flannel.1網橋對應的FDB信息,是由flanneld進程維護的
- linux內核在IP包前面再加上二層數據幀頭,把目標節點的MAC地址填進去,MAC地址從宿主機的ARP表獲取
- 此時flannel.1設備就可以把這個數據幀從eth0發出去,再經過宿主機網絡來到目標節點的eth0設備。目標主機內核網絡棧會發現這個數據幀有VXLAN Header,并且VNI為1,Linux內核會對它進行拆包,拿到內部數據幀,根據VNI的值,交給本機flannel.1設備處理,flannel.1拆包,根據路由表發往cni網橋,最后到達目標容器
1.2.2 flannel支持的后端模式
網絡模式 | 功能 |
---|---|
vxlan | 報文封裝,默認模式 |
Directrouting | 直接路由,跨網段使用vxlan,同網段使用host-gw模式 |
host-gw | 主機網關,性能好,但只能在二層網絡中,不支持跨網絡 如果有成千上萬的Pod,容易產生廣播風暴,不推薦 |
UDP | 性能差,不推薦 |
更改flannel的默認模式
[root@k8s-master ~]# kubectl -n kube-flannel edit cm kube-flannel-cfg
apiVersion: v1
data:cni-conf.json: |{"name": "cbr0","cniVersion": "0.3.1","plugins": [{"type": "flannel","delegate": {"hairpinMode": true,"isDefaultGateway": true}},{"type": "portmap","capabilities": {"portMappings": true}}]}net-conf.json: |{"Network": "10.244.0.0/16","EnableNFTables": false,"Backend": {"Type": "host-gw" #更改內容}}
#重啟pod
[root@k8s-master ~]# kubectl -n kube-flannel delete pod --all
pod "kube-flannel-ds-bk8wp" deleted
pod "kube-flannel-ds-mmftf" deleted
pod "kube-flannel-ds-tmfdn" deleted[root@k8s-master ~]# ip r
default via 172.25.254.2 dev eth0 proto static metric 100
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 172.25.254.10 dev eth0
10.244.2.0/24 via 172.25.254.20 dev eth0
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.25.254.0/24 dev eth0 proto kernel scope link src 172.25.254.100 metric 100
1.3 calico網絡插件
calico簡介:
- 純三層的
網絡層
轉發,中間沒有任何的NAT和overlay,轉發效率最好 - Calico 僅依賴三層路由可達。Calico 較少的依賴性使它能適配所有 VM、Container、白盒或者混合環境場景
calico網絡架構:
1.3.1 部署calico
刪除flannel插件
[root@k8s-master ~]# kubectl delete -f kube-flannel.yml
刪除所有節點上flannel配置文件,避免沖突
[root@k8s-master & node1-2 ~]# rm -rf /etc/cni/net.d/10-flannel.conflist
創建文件夾,將所需內容放進去
[root@K8smaster calico]# ls
calico.yaml
[root@Harbor network]# ls
calico-3.28.1.tar calico.yaml#在harbor中上傳鏡像到倉庫中
更改calico.yaml文件
[root@k8s-master calico]# vim calico.yaml
4835 image: calico/cni:v3.28.1
4835 image: calico/cni:v3.28.1
4906 image: calico/node:v3.28.1
4932 image: calico/node:v3.28.1
5160 image: calico/kube-controllers:v3.28.1
5249 - image: calico/typha:v3.28.14970 - name: CALICO_IPV4POOL_IPIP
4971 value: "Never"4999 - name: CALICO_IPV4POOL_CIDR
5000 value: "10.244.0.0/16"
5001 - name: CALICO_AUTODETECTION_METHOD
5002 value: "interface=eth0"[root@k8s-master calico]# kubectl apply -f calico.yaml
[root@k8s-master calico]# kubectl -n kube-system get pods
部署完成測試:
[root@K8smaster calico]# kubectl run web --image myapp:v1
pod/web created
[root@K8smaster calico]# kubectl get pods web -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 24s 192.168.179.64 k8sslave1.zym.org <none> <none>
[root@K8smaster calico]# curl 192.168.179.64
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
(二)k8s調度
2.1 調度在Kubernetes中的作用
- 調度是指將未調度的Pod自動分配到集群中的節點的過程
- 調度器通過 kubernetes 的 watch 機制來發現集群中新創建且尚未被調度到 Node 上的 Pod
- 調度器會將發現的每一個未調度的 Pod 調度到一個合適的 Node 上來運行
2.2 調度原理:
- 創建Pod
- 用戶通過Kubernetes API創建Pod對象,并在其中指定Pod的資源需求、容器鏡像等信息。
- 調度器監視Pod
- Kubernetes調度器監視集群中的未調度Pod對象,并為其選擇最佳的節點。
- 選擇節點
- 調度器通過算法選擇最佳的節點,并將Pod綁定到該節點上。調度器選擇節點的依據包括節點的資源使用情況、Pod的資源需求、親和性和反親和性等。
- 綁定Pod到節點
- 調度器將Pod和節點之間的綁定信息保存在etcd數據庫中,以便節點可以獲取Pod的調度信息。
- 節點啟動Pod
- 節點定期檢查etcd數據庫中的Pod調度信息,并啟動相應的Pod。如果節點故障或資源不足,調度器會重新調度Pod,并將其綁定到其他節點上運行。
2.3 調度器種類
- 默認調度器(Default Scheduler):
- 是Kubernetes中的默認調度器,負責對新創建的Pod進行調度,并將Pod調度到合適的節點上。
- 自定義調度器(Custom Scheduler):
- 是一種自定義的調度器實現,可以根據實際需求來定義調度策略和規則,以實現更靈活和多樣化的調度功能。
- 擴展調度器(Extended Scheduler):
- 是一種支持調度器擴展器的調度器實現,可以通過調度器擴展器來添加自定義的調度規則和策略,以實現更靈活和多樣化的調度功能。
- kube-scheduler是kubernetes中的默認調度器,在kubernetes運行后會自動在控制節點運行
2.4 常用的調度方法
2.4.1 nodenam–指定節點
- nodeName 是節點選擇約束的最簡單方法,但一般不推薦
- 如果 nodeName 在 PodSpec 中指定了,它會優先于其他的節點選擇方法
- 使用 nodeName 來選擇節點的一些限制
- 如果指定的節點不存在。
- 如果指定的節點沒有資源來容納 pod,則pod 調度失敗。
- 云環境中的節點名稱并非總是可預測或穩定的
實例:
#建立pod文件
[[root@k8s-master scheduler]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > pod1.yml#設置調度
[root@k8s-master scheduler]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:nodeName: k8s-node2 #需要指定集群中的節點名稱相同containers:- image: myapp:v1name: testpod#建立pod
[root@k8s-master scheduler]# kubectl apply -f pod1.yml
pod/testpod created[root@k8s-master scheduler]# kubectl get pods testpod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 18s 10.244.169.130 k8s-node2 <none> <none>
[! 注意]
找不到節點pod會出現pending狀態,優先級最高,其他調度方式無效
可以使用
kubectl get nodes
,該命令查看集群中節點名稱
2.4.2 Nodeselector—通過標簽控制節點
-
nodeSelector 是節點選擇約束的最簡單推薦形式
-
給選擇的節點添加標簽:
kubectl label nodes k8s-node1 lab=zym
-
可以給多個節點設定相同標簽,當運行pod會指定節點運行
spec:nodeSelector:lab: zym
示例:
#查看節點標簽
[root@k8s-master scheduler]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8smaster.zym.org Ready control-plane 8d v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8smaster.zym.org,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
k8sslave1.zym.org Ready <none> 8d v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8sslave1.zym.org,kubernetes.io/os=linux
k8sslave2.zym.org Ready <none> 8d v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8sslave2.zym.org,kubernetes.io/os=linux#設定節點標簽
[root@k8s-master scheduler]# kubectl label nodes k8s-node1 lab=zym
node/k8s-node1 labeled
[root@k8s-master scheduler]# kubectl get nodes k8s-node1 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-node1 Ready <none> 5d3h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux,lab=zym#調度設置
[root@k8s-master scheduler]# vim pod2.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:nodeSelector:lab: zymcontainers:- image: myapp:v1name: testpod[root@k8s-master scheduler]# kubectl apply -f pod2.yml
pod/testpod created
[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 4s 10.244.36.65 k8s-node1 <none> <none>
2.5 affinity(親和性)
官方文檔 :
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node
2.5.1 親和與反親和
- nodeSelector 提供了一種非常簡單的方法來將 pod 約束到具有特定標簽的節點上。親和/反親和功能極大地擴展了你可以表達約束的類型。
- 使用節點上的 pod 的標簽來約束,而不是使用節點本身的標簽,來允許哪些 pod 可以或者不可以被放置在一起。
2.5.2 nodeAffinity節點親和
- 那個節點服務指定條件就在那個節點運行
requiredDuringSchedulingIgnoredDuringExecution
必須滿足,但不會影響已經調度的podpreferredDuringSchedulingIgnoredDuringExecution
傾向滿足,在無法滿足情況下也會調度pod- IgnoreDuringExecution 表示如果在Pod運行期間Node的標簽發生變化,導致親和性策略不能滿足,則繼續運行當前的Pod。
- nodeaffinity還支持多種規則匹配條件的配置如
匹配規則 | 功能 |
---|---|
ln | label 的值在列表內 |
Notln | label 的值不在列表內 |
Gt | label 的值大于設置的值,不支持Pod親和性 |
Lt | label 的值小于設置的值,不支持pod親和性 |
Exists | 設置的label 存在 |
DoesNotExist | 設置的 label 不存在 |
nodeAffinity示例
#示例1
[root@k8s-master scheduler]# vim pod3.yml
apiVersion: v1
kind: Pod
metadata:name: node-affinity
spec:containers:- name: nginximage: nginxaffinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: diskoperator: In | NotIn #兩個結果相反values:- ssd
2.5.3 Podaffinity(pod的親和)
- 那個節點有符合條件的POD就在那個節點運行
- podAffinity 主要解決POD可以和哪些POD部署在同一個節點中的問題
- podAntiAffinity主要解決POD不能和哪些POD部署在同一個節點中的問題。它們處理的是Kubernetes集群內部POD和POD之間的關系。
- Pod 間親和與反親和在與更高級別的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用時,
- Pod 間親和與反親和需要大量的處理,這可能會顯著減慢大規模集群中的調度
Podaffinity示例
[root@k8s-master scheduler]# vim example4.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxaffinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: "kubernetes.io/hostname"[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-658496fff-d58bk 1/1 Running 0 39s 10.244.169.133 k8s-node2 <none> <none>
nginx-deployment-658496fff-g25nq 1/1 Running 0 39s 10.244.169.134 k8s-node2 <none> <none>
nginx-deployment-658496fff-vnlxz 1/1 Running 0 39s 10.244.169.135 k8s-node2 <none> <none>
2.5.4 Podantiaffinity(pod反親和)
Podantiaffinity示例
[root@k8s-master scheduler]# vim example5.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxaffinity:podAntiAffinity: #反親和requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: "kubernetes.io/hostname"[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-5f5fc7b8b9-hs9kz 1/1 Running 0 6s 10.244.169.136 k8s-node2 <none> <none>
nginx-deployment-5f5fc7b8b9-ktzsh 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-deployment-5f5fc7b8b9-txdt9 1/1 Running 0 6s 10.244.36.67 k8s-node1 <none> <none>
2.6 Taints—污點模式
- 禁止調度到該標記污點的節點上
$ kubectl taint nodes <nodename> key=string:effect #命令執行方法
$ kubectl taint nodes node1 key=value:NoSchedule #創建
$ kubectl describe nodes server1 | grep Taints #查詢
$ kubectl taint nodes node1 key- #刪除
其中 effect
可取值:
effect值 | 解釋 |
---|---|
NoSchedule | POD 不會被調度到標記為 taints 節點,就像貼了個 “禁止入內”,已經在這節點運行的也會繼續運行 |
PreferNoSchedule | NoSchedule 的軟策略版本,盡量不調度到此節點,如果實在沒別的節點可用,也可以放在該節點進行運行 |
NoExecute | 如該節點標為污點模式,不能調度上該節點上,并且節點內正在運行的 POD 沒有對應 Tolerate 設置,會直接被節點去掉 |
2.6.1 設定污點
#創建運行pod
[root@K8smaster calico]# vim example.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: webname: web
spec:replicas: 2selector:matchLabels:app: webtemplate:metadata:labels:app: webspec:containers:- image: nginx:1.23name: nginx
設定污點標簽
[root@K8smaster calico]# kubectl taint node k8sslave1.zym.org name=zym:NoSchedule
此時設定污點標簽后,正在運行的節點還是會在該節點上運行
新添加的節點就不會,在標記污點的節點上運行
[root@K8smaster calico]# kubectl scale deployment web --replicas 6
2.6.2 污點刪除
[root@K8smaster calico]# kubectl taint node k8sslave1.zym.org name-[root@K8smaster calico]# kubectl describe nodes k8sslave1.zym.org k8sslave2.zym.org | grep Tain
Taints: <none>
Taints: <none>
2.6.3 污點容忍
$ kubectl taint nodes <nodename> key=value:effect
$ kubectl taint node k8sslave1.zym.org name=zym:NoSchedule
key 和 value 可以自定義
-
tolerations中定義的key、value、effect,要與node上設置的taint保持一直:
- 如果 operator 是 Equal ,則key與value之間的關系必須相同
- 如果 operator 是 Exists ,value可以省略
- 如果不指定operator屬性,則默認值為Equal
-
還有兩個特殊值:
-
當不指定key,再配合Exists 就能匹配所有的key與value ,可以容忍所有污點
-
當不指定effect ,則匹配所有的effecttolerations中定義的key、value、effect,要與node上設置的taint保持一直
-
如果 operator 是 Equal ,則key與value之間的關系必須相等。如果 operator 是 Exists ,value可以省略如果不指定operator屬性,則默認值為Equal。還有兩個特殊值:當不指定key,再配合Exists 就能匹配所有的key與value ,可以容忍所有污點。當不指定effect ,則匹配所有的effect
-
容忍實例:
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: webname: web
spec:replicas: 2selector:matchLabels:app: webtemplate:metadata:labels:app: webspec:containers:- image: nginx:1.23name: nginxtolerations: #容忍所有污點- operator: Exists
容忍effect為Noschedule的污點
tolerations: #容忍effect為Noschedule的污點
- operator: Existseffect: NoSchedule
容忍指定key的NoSchedule污點
$ kubectl taint node k8s-node2 nodetype=bad:NoScheduletolerations: #容忍指定key和value的NoSchedule污點
- key: nodetypevalue: badeffect: NoSchedule
八、k8s中的認證授權
(一)kubernetes API 訪問控制
Authentication(認證)
-
認證方式現共有8種,可以啟用一種或多種認證方式,只要有一種認證方式通過,就不再進行其它方式的認證。通常啟用X509 Client Certs和Service Accout Tokens兩種認證方式。
-
Kubernetes集群有兩類用戶:由Kubernetes管理的Service Accounts (服務賬戶)和(Users Accounts) 普通賬戶。k8s中賬號的概念不是我們理解的賬號,它并不真的存在,它只是形式上存在。
Authorization(授權)
- 必須經過認證階段,才到授權請求,根據所有授權策略匹配請求資源屬性,決定允許或拒絕請求。授權方式現共有6種,AlwaysDeny、AlwaysAllow、ABAC、RBAC、Webhook、Node。默認集群強制開啟RBAC。
Admission Control(準入控制)
- 用于攔截請求的一種方式,運行在認證、授權之后,是權限認證鏈上的最后一環,對請求API資源對象進行修改和校驗。
1.1 UserAccount與ServiceAccount
-
用戶賬戶是針對人而言的。 服務賬戶是針對運行在 pod 中的進程而言的。
-
用戶賬戶是全局性的。 其名稱在集群各 namespace 中都是全局唯一的,未來的用戶資源不會做 namespace 隔離, 服務賬戶是 namespace 隔離的。
-
集群的用戶賬戶可能會從企業數據庫進行同步,其創建需要特殊權限,并且涉及到復雜的業務流程。 服務賬戶創建的目的是為了更輕量,允許集群用戶為了具體的任務創建服務賬戶 ( 即權限最小化原則 )。
1.1.1 ServiceAccount
-
服務賬戶控制器(Service account controller)
-
服務賬戶管理器管理各命名空間下的服務賬戶
-
每個活躍的命名空間下存在一個名為 “default” 的服務賬戶
-
-
服務賬戶準入控制器(Service account admission controller)
-
相似pod中 ServiceAccount默認設為 default。
-
保證 pod 所關聯的 ServiceAccount 存在,否則拒絕該 pod。
-
如果pod不包含ImagePullSecrets設置那么ServiceAccount中的ImagePullSecrets 被添加到pod中
-
將掛載于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到 pod 下的每個容器中
-
將一個包含用于 API 訪問的 token 的 volume 添加到 pod 中
-
1.1.2 ServiceAccount示例:
建立名字為zym的ServiceAccoun
kubectl create sa zym
建立secrets
kubectl create secret docker-registry docker-login --docker-username admin --docker-password 123456 --docker-server reg.zym.org --docker-email zym@qq.org
secrets注入到sa中
[root@k8s-master ~]# kubectl edit sa timinglee
apiVersion: v1
imagePullSecrets:
- name: docker-login
kind: ServiceAccount
metadata:creationTimestamp: "2025-08-19T07:49:26Z"name: zymnamespace: defaultresourceVersion: "355930"uid: 2601532b-7de8-4af2-a1fd-a9483bd59e5d
建立私有倉庫并且利用pod訪問私有倉庫
[root@k8s-master auth]# vim example1.yml
[root@K8smaster calico]# kubectl run testpod --image reg.zym.org/zym/game2048 --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:creationTimestamp: nulllabels:run: testpodname: testpod
spec:containers:- image: reg.zym.org/zym/game2048name: testpodresources: {}dnsPolicy: ClusterFirstrestartPolicy: Always
status: {}
[root@K8smaster calico]# kubectl run testpod --image reg.zym.org/zym/game2048 --dry-run=client -o yaml > example1.yml[root@k8s-master auth]# kubectl apply -f example1.yml
pod/testpod created
[root@k8s-master auth]# kubectl describe pod testpodWarning Failed 5s kubelet Failed to pull image "reg.timinglee.org/lee/nginx:latest": Error response from daemon: unauthorized: unauthorized to access repository: lee/nginx, action: pull: unauthorized to access repository: lee/nginx, action: pullWarning Failed 5s kubelet Error: ErrImagePullNormal BackOff 3s (x2 over 4s) kubelet Back-off pulling image "reg.timinglee.org/lee/nginx:latest"Warning Failed 3s (x2 over 4s) kubelet Error: ImagePullBackOff
在創建pod時會鏡像下載會受阻,因為docker私有倉庫下載鏡像需要認證
pod綁定sa
[root@k8s-master auth]# vim example1.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:serviceAccountName: zymcontainers:- image: reg.zym.org/zym/game2048:latestname: testpod
現在可以正常拉取鏡像了
[root@k8s-master auth]# kubectl apply -f example1.yml
pod/testpod created
[root@k8s-master auth]# kubectl get pods
NAME READY STATUS RESTARTS AGE
testpod 1/1 Running 0 2s
二 認證(在k8s中建立認證用戶)
2.1 創建UserAccount
建立證書
[root@K8smaster calico]# cd /etc/kubernetes/pki/
[root@K8smaster pki]# openssl genrsa -out zym.key 2048
[root@K8smaster pki]# openssl req -new -key zym.key -out zym.csr -subj "/CN=zym"
[root@K8smaster pki]# openssl x509 -req -in zym.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out zym.crt -days 365
Certificate request self-signature ok
subject=CN = zym
[root@K8smaster pki]# openssl x509 -in zym.crt -text -noout
Certificate:Data:Version: 1 (0x0)Serial Number:66:14:f2:95:f5:ab:f3:e4:da:d1:53:ae:5d:6f:14:bc:c7:7f:72:6aSignature Algorithm: sha256WithRSAEncryptionIssuer: CN = kubernetesValidityNot Before: Aug 19 08:22:34 2025 GMTNot After : Aug 19 08:22:34 2026 GMTSubject: CN = zymSubject Public Key Info:Public Key Algorithm: rsaEncryptionPublic-Key: (2048 bit)Modulus:00:9c:38:50:1e:53:2f:59:f5:7d:9f:06:c6:10:4c:2b:58:a3:aa:84:65:d4:7b:28:9c:17:e0:1c:e2:40:9e:ad:55:51:57:18:f5:53:25:b3:1c:2b:a9:85:fe:55:b1:d6:95:dc:85:97:0b:40:eb:a3:c4:51:2a:bf:ed:29:4f:89:81:81:37:70:04:25:bf:0f:97:ce:f3:23:61:1a:09:44:23:19:f4:bf:8d:d3:45:79:41:05:ed:a5:0e:29:29:59:db:94:56:e2:5a:f9:ad:88:29:da:36:73:78:67:98:12:9d:44:4c:33:f6:b6:da:d9:3d:e1:e9:f1:0a:3f:e9:6b:07:ae:06:dd:b6:12:8b:1f:af:c8:68:8b:c1:b6:41:42:95:9c:57:98:10:39:80:20:1a:63:01:54:72:64:b6:c8:13:bf:fa:e2:4a:b8:1e:4d:7d:3c:ca:ae:63:2c:b7:68:5c:74:c2:dd:07:7c:ae:9a:46:8d:b4:1f:79:a8:82:7a:e5:19:9f:ca:58:fd:1d:a6:40:da:03:d0:86:d9:8b:58:eb:7f:d5:b2:69:f1:b6:c4:d3:1f:bb:69:08:ff:15:81:08:69:57:f0:fb:f6:10:05:41:0b:d1:4c:2e:c4:95:11:da:2f:7f:40:58:a7:0c:17:e9:d9:46:52:d8:5b:dc:23:b1Exponent: 65537 (0x10001)Signature Algorithm: sha256WithRSAEncryptionSignature Value:ad:77:d8:17:fe:8e:f6:dd:79:7a:23:74:8f:62:22:af:9d:0c:39:e1:95:dc:81:da:e8:50:3a:c8:d3:aa:59:ae:30:11:be:d0:8d:3c:5c:d6:5d:44:d4:ef:ca:f4:99:9a:22:54:5b:04:bd:a8:ea:2f:cc:b8:c1:61:96:70:eb:c1:a5:b7:ac:a0:52:86:49:dd:94:b3:35:1f:4e:37:5b:0a:3f:04:36:39:6a:7a:32:49:23:75:7a:08:6e:c3:db:18:fb:11:91:c4:36:7f:bc:e5:b8:0c:2f:00:75:fe:66:69:9b:3b:6f:16:e7:bf:bf:fa:ed:54:13:79:8e:f8:68:8a:fa:87:53:b2:5a:a5:cb:63:93:09:22:64:6c:00:1d:25:e2:8a:d7:1a:4a:5b:f0:4e:51:ce:d3:51:d8:98:b6:92:6e:cb:b5:5b:25:f8:f2:e7:5f:b8:db:b4:89:01:7e:2f:27:d6:77:ff:15:7d:45:15:46:1f:7e:06:3e:3f:2d:e0:c9:31:87:43:20:ca:3d:35:5c:de:6f:75:22:ab:83:8c:9c:35:d3:2d:b2:fd:14:33:ce:10:37:35:1d:36:96:2f:bd:a4:07:3f:ad:82:df:6a:d1:aa:13:af:63:54:85:be:7a:6d:a5:a9:07:7e:d6:99:cb:6a:4e:a4:0f:95:46:a2
建立k8s中的用戶
[root@K8smaster pki]# kubectl config set-credentials zym --client-certificate /etc/kubernetes/pki/zym.crt --client-key /etc/kubernetes/pki/zym.key --embed-certs=true
User "zym" set.
[root@k8s-master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:certificate-authority-data: DATA+OMITTEDserver: https://172.25.254.100:6443name: kubernetes
contexts:
- context:cluster: kubernetesuser: kubernetes-adminname: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-adminuser:client-certificate-data: DATA+OMITTEDclient-key-data: DATA+OMITTED
- name: timingleeuser:client-certificate-data: DATA+OMITTEDclient-key-data: DATA+OMITTED#為用戶創建集群的安全上下文
root@k8s-master pki]# kubectl config set-context timinglee@kubernetes --cluster kubernetes --user timinglee
Context "timinglee@kubernetes" created.#切換用戶,用戶在集群中只有用戶身份沒有授權
[root@k8s-master ~]# kubectl config use-context timinglee@kubernetes
Switched to context "timinglee@kubernetes".
[root@k8s-master ~]# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "timinglee" cannot list resource "pods" in API group "" in the namespace "default"#切換會集群管理
[root@k8s-master ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".#如果需要刪除用戶
[root@k8s-master pki]# kubectl config delete-user timinglee
deleted user timinglee from /etc/kubernetes/admin.conf
2.2 RBAC(Role Based Access Control)
2.2.1 基于角色訪問控制授權:
-
允許管理員通過Kubernetes API動態配置授權策略。RBAC就是用戶通過角色與權限進行關聯。
-
RBAC只有授權,沒有拒絕授權,所以只需要定義允許該用戶做什么即可
-
RBAC的三個基本概念
-
Subject:被作用者,它表示k8s中的三類主體, user, group, serviceAccount
-
Role:角色,它其實是一組規則,定義了一組對 Kubernetes API 對象的操作權限。
-
RoleBinding:定義了“被作用者”和“角色”的綁定關系
-
-
RBAC包括四種類型:Role、ClusterRole、RoleBinding、ClusterRoleBinding
-
Role 和 ClusterRole
-
Role是一系列的權限的集合,Role只能授予單個namespace 中資源的訪問權限。
-
ClusterRole 跟 Role 類似,但是可以在集群中全局使用。
-
Kubernetes 還提供了四個預先定義好的 ClusterRole 來供用戶直接使用
-
cluster-amdin、admin、edit、view
-
2.2.2 role授權實施
#生成role的yaml文件
[root@k8s-master rbac]# kubectl create role myrole --dry-run=client --verb=get --resource pods -o yaml > myrole.yml#更改文件內容
[root@k8s-master rbac]# vim myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:creationTimestamp: nullname: myrole
rules:
- apiGroups:- ""resources:- podsverbs:- get- watch- list- create- update- path- delete#創建role
[root@k8s-master rbac]# kubectl apply -f myrole.yml
[root@k8s-master rbac]# kubectl describe role myrole
Name: myrole
Labels: <none>
Annotations: <none>
PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----pods [] [] [get watch list create update path delete]
#建立角色綁定
[root@k8s-master rbac]# kubectl create rolebinding timinglee --role myrole --namespace default --user timinglee --dry-run=client -o yaml > rolebinding-myrole.yml[root@k8s-master rbac]# vim rolebinding-myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: timingleenamespace: default #角色綁定必須指定namespace
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: myrole
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: timinglee[root@k8s-master rbac]# kubectl apply -f rolebinding-myrole.yml
rolebinding.rbac.authorization.k8s.io/timinglee created
[root@k8s-master rbac]# kubectl get rolebindings.rbac.authorization.k8s.io timinglee
NAME ROLE AGE
timinglee Role/myrole 9s
#切換用戶測試授權
[root@k8s-master rbac]# kubectl config use-context timinglee@kubernetes
Switched to context "timinglee@kubernetes".[root@k8s-master rbac]# kubectl get pods
No resources found in default namespace.
[root@k8s-master rbac]# kubectl get svc #只針對pod進行了授權,所以svc依然不能操作
Error from server (Forbidden): services is forbidden: User "timinglee" cannot list resource "services" in API group "" in the namespace "default"#切換回管理員
[root@k8s-master rbac]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
2.2.3 clusterrole授權實施
#建立集群角色
[root@k8s-master rbac]# kubectl create clusterrole myclusterrole --resource=deployment --verb get --dry-run=client -o yaml > myclusterrole.yml
[root@k8s-master rbac]# vim myclusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: myclusterrole
rules:
- apiGroups:- appsresources:- deploymentsverbs:- get- list- watch- create- update- path- delete
- apiGroups:- ""resources:- podsverbs:- get- list- watch- create- update- path- delete[root@k8s-master rbac]# kubectl describe clusterrole myclusterrole
Name: myclusterrole
Labels: <none>
Annotations: <none>
PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----deployments.apps [] [] [get list watch create update path delete]pods.apps [] [] [get list watch create update path delete]#建立集群角色綁定
[root@k8s-master rbac]# kubectl create clusterrolebinding clusterrolebind-myclusterrole --clusterrole myclusterrole --user timinglee --dry-run=client -o yaml > clusterrolebind-myclusterrole.yml
[root@k8s-master rbac]# vim clusterrolebind-myclusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: clusterrolebind-myclusterrole
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: timinglee[root@k8s-master rbac]# kubectl describe clusterrolebindings.rbac.authorization.k8s.io clusterrolebind-myclusterrole
Name: clusterrolebind-myclusterrole
Labels: <none>
Annotations: <none>
Role:Kind: ClusterRoleName: myclusterrole
Subjects:Kind Name Namespace---- ---- ---------User timinglee#測試:
[root@k8s-master rbac]# kubectl get pods -A
[root@k8s-master rbac]# kubectl get deployments.apps -A
[root@k8s-master rbac]# kubectl get svc -A
Error from server (Forbidden): services is forbidden: User "timinglee" cannot list resource "services" in API group "" at the cluster scope
2.2.4 服務賬戶的自動化
服務賬戶準入控制器(Service account admission controller)
-
如果該 pod 沒有 ServiceAccount 設置,將其 ServiceAccount 設為 default。
-
保證 pod 所關聯的 ServiceAccount 存在,否則拒絕該 pod。
-
如果 pod 不包含 ImagePullSecrets 設置,那么 將 ServiceAccount 中的 ImagePullSecrets 信息添加到 pod 中。
-
將一個包含用于 API 訪問的 token 的 volume 添加到 pod 中。
-
將掛載于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到 pod 下的每個容器中。
服務賬戶控制器(Service account controller)
服務賬戶管理器管理各命名空間下的服務賬戶,并且保證每個活躍的命名空間下存在一個名為 “default” 的服務賬戶