本篇是關於k8s的Pod,主要包括Pod和容器的使用、Pod的控制和調度管理、應用配置管理等內容。node
Pod是k8s的核心概念一直,就名字同樣,是k8s中一個邏輯概念。Pod是docekr容器的集合,每一個Pod中至少有一個Pause容器和業務容器。和docker容器關注單個可用的資源不一樣,Pod更多在應用層的角度,將多個docker容器組合來實現做爲一個應用,它是k8s中最小的資源單位。linux
結合docker自己容器的特性,Pod中全部容器都是共享資源,如磁盤、網絡、CPU、內存等,同時,一個Pod共用一個網絡。nginx
如下的yaml格式的Pod定義文件:redis
apiVersion: v1 kind: Pod metadata: name: string namespace: string labels: - name: string annotations: - name: string spec: containers: - name: string image: string imagePullPolicy: [Always | Never | IfNotPresent] command: [string] args: [string] workingDir: string volumeMounts: string - name: string mountPath: string readOnly: boolean ports: - name: string containerPort: int hostPort: int protocol: string env: - name: string value: string resources: limits: cpu: string memory: string requests: cpu: string memory: string livenessProbe: exec: command: [string] httpGet: path: string port: number scheme: string httpHeaders: - name: string value: string tcpSocket: port: number initialDelaySeconds: 0 timeoutSeconds: 0 periodSeconds: 0 successThreshold: 0 failureThreshold: 0 securityContext: privileged: false restartPolicy: [Always | Never | OnFailure] nodeSelector: object imagePullSecrets: - name: string hostNetwork: false volumes: - name: string emptyDir: {} hostPath: path: string secret: secretName: string items: - key: string value: string configMap: name: string items: - key: string - path: string
Pod定義文件模板中各屬性的說明以下:
算法
注:k8s的Pod啓動命令不能是後臺執行的,否則k8s會不斷建立新的Pod而陷入無限循環中。若是docker鏡像的命令沒法改造爲前臺執行,可使用開源工具Supervisor。或是 && tail -f xx 這樣的組合命令。docker
靜態Pod是由Kubelet進行管理的的僅存在於特定Node上的Pod。它們不能經過API Server進行管理,也沒法和ReplicationController、Deployment或者DaemonSet進行關聯,kubelet也不乏對它們進行健康檢查。靜態Pod老是由kubelet建立,也由kubelet來銷燬。同時也只運行在該kubelet所在的Node上。json
建立靜態Pod由兩種方式:配置文件和HTTP。api
1.配置文件方式bash
靜態文件存放的位置在kubelet的配置文件中定義,由參數staticPodPath指定,若是k8s集羣由kubeadm搭建,那默認存儲在目錄/etc/kubernetes/manifests
下。咱們定義配置文件static-nginx.yaml
:網絡
apiVersion: v1 kind: Pod metadata: name: static-nginx labels: name: static-nginx spec: containers: - name: static-nginx image: nginx ports: - name: nginx containerPort: 80
不須要使用命令建立,等他一會,kubelet會自動建立Pod
[root@k8s-master ~]# kubectl get pods static-nginx-k8s-master 1/1 Running 0 12m
注:若是一段時間仍是沒有生成Pod,能夠查看日誌文件 /var/log/messages
刪除Pod不是使用命令kubelet delete ...
,而是直接刪除/etc/kubernetes/manifests/static-nginx.yaml
,kubelet自動會刪除Pod。
2.HTTP方式
kubelet會定時根據參數--manifest-url
來下載鏡像並生成靜態Pod。
注:比較巧妙地方的是kubeadm安裝地管理節點 kube-apiserver、kube-sheduler、kube-controller-manager 組件都是靜態的Pod。
以前說過,同一個Pod中的容器能共享Volume,那怎麼將Volume共享給Pod呢。
關鍵在於配置文件中的spec.containers[].volumeMounts
和spec.volumes[]
參數,例如Pod中容器之間共享一個emptyDir的目錄,名爲logs,配置文件就能夠這樣:
apiVersion: v1 kind: Pod metadata: name: volume-pod spec: containers: - name: nginx image: nginx volumeMounts: - name: logs mountPath: /usr/local/nginx/logs - name: busybox image: busybox volumeMounts: - name: logs mountPath: /logs volumes: - name: logs emptyDir: {}
這樣一來,容器nginx和busybox就共享一個目錄,且各自掛載的路徑也不一樣。重點是用volumes
定義要共享的volume,再在containers上使用volumeMounts
參數來使用。
k8s 在 1.2版本時提供了一種統一的集羣配置管理方案,就是ConfigMap,利用不一樣配置和不一樣容器分離開的方式,讓複雜容器管理簡單化。
ConfigMap供容器使用的典型用法以下:
1.yaml文件方式
# cm.appvars.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-appvars data: apploglevel: info appdatadir: /var/data
指定命令建立:
kubectl create -f cm-appvars.yaml
查看命令就用:
kubectl get configMap -o json
或者key:value也可使用配置文件的別名和文件的內容。
data: key-serverxml: | <?xml ?> ...... ...... <?xml ... ?> key-properties: "key=... .... "
注意格式問題。
2.kubelet命令行建立 直接經過kubectl create configmap
也能夠建立ConfigMap,可使用參數--from-file
或--from-literal
指定內容。
經過--from-file
參數從文件中建立,能夠指定key的名稱,能夠在一個命令中建立包含多個key的ConfigMap,語法爲:
kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
經過--from-file
參數從目錄中進行建立,該目錄的每一個配置文件名都被設置爲key,文件的內容被設置爲value,語法爲:
kubectl create configmap NAME --from-file=config-files-dir
經過--file-literal
從文本中進行建立、直接將指定的key#=value#建立爲ConfigMap的內容,語法爲:
kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
ConfigMap的使用也有幾種方式。
1.環境變量
apiVersion: v1 kind: Pod metadata: name: cm-test-pod spec: containers: - name: cm-test image: buysbox env: - name: APPLOGLEVEL # 定義環境變量名稱 valueFrom: # key "apploglevel" 對應的值 configMapKeyRef: name: cm-appvars # 環境變量的值取自 cm-appvars 中 key: apploglevel # key 爲 "apploglevel" - name: APPDATADIR valueFrom: configMapKeyRef: name: cm-appvars key: appdatadir restartPolicy: Never
要點是環境變量中使用valueFrom
參數指定configMapKeyRef
2.volumeMount的方式
... spec: containers: - name: cm-test-app image: busybox volumeMounts: - name: serverxml # 引用volume名 mountPath: /configfiles # 掛載到容器內的目錄 volumes: - name: serverxml configMap: name: cm-appconfigfiles # 使用 ConfigMap "cm-appconfigfiles" items: - key: key-serverxml # key=key-serverxml path: server.xml # value將server.xml文件名進行掛載
若是在引用 ConfigMap 時不指定 items,則使用 volumeMount 方式在容器內的目錄中爲每一個 item 生成一個文件名爲 key 的文件。
使用 ConfigMap 的限制條件以下:
Pod的狀態
狀態值 | 描述 |
---|---|
Peding | API Server 已經建立該Pod,但Pod內還有一個或多個容器的鏡像沒有建立,包括正在下載鏡像的過程 |
Running | Pod內全部容器均已建立,且至少有一個容器處於運行狀態、正在啓動狀態或正在重啓狀態 |
Succeeded | Pod內全部容器均成功執行退出,且不會再重啓 |
Failed | Pod內全部容器均已退出,但至少有一個容器退出爲失敗狀態 |
Unknown | 因爲某種緣由沒法獲取該Pod的狀態,可能因爲容器通訊不順暢致使 |
Pod的RestartPolicy重啓策略:
每種控制器對Pod的重啓策略不一樣:
Pod的健康狀態檢查能夠經過兩類探針來檢查:LivenessProbe 和 ReadinessProbe。
kubelet按期執行LivenessProbe探針來診斷容器的健康情況。LivenessProbe有三種實現方式。
ExecAction:在容器內部執行一個命令,若是該命令的返回碼爲0,則代表容器健康。
... spec: containers: - name: liveness ... livenessProbe: exec: command: - cat - /tmp/health initialDelaySeconds: 15 # 探針初始化檢測時間間隔,單位爲秒 timeoutSeconds: 1 # 返回超時時間,單位爲秒。若是超時kubelet會重啓容器
TCPSocketAction:經過容器的IP地址和端口號執行TCP檢查,若是可以創建TCP鏈接。則代表容器健康。
... spec: containers: - name: liveness ... livenessProbe: tcpSocket: port: 80 initialDelaySeconds: 15 # 探針初始化檢測時間間隔,單位爲秒 timeoutSeconds: 1 # 返回超時時間,單位爲秒
HTTPGetAction:經過容器的IP地址、端口號及路徑調用HTTP Get方法,若是響應的狀態碼大於等於200且小於等於400,則認爲容器狀態健康。
... spec: containers: - name: liveness ... livenessProbe: httpGet: path: /_status/healthz port: 80 initialDelaySeconds: 15 # 探針初始化檢測時間間隔,單位爲秒 timeoutSeconds: 1 # 返回超時時間,單位爲秒
在k8s中,Pod在大部分場景在都只是容器的載體而已,一般須要經過RC、Deployment、DaemonSet、Job等對象來完成Pod的調度與自動控制功能。
RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集羣內始終保持用戶指定的副本數量。
Pod的調度策略除了有系統內置的Node調度算法,還能夠在Pod的定義中使用NodeSelector或者NodeAffinity來指定知足條件的Node進行調度。
1.NodeSelector:定向調度
k8s上的服務Scheduler服務負責實現Pod的調度,整個調度經過執行一系列複雜的算法,最終爲每一個Pod計算出一個最佳的目標節點,這一過程是自動完成的。NodeSelector 調度就是經過給Node打上Label,使用Pod的NodeSelector屬性來匹配的。
首先經過kubectl label命令給目標Node打上一些標籤:
kubectl label node <node-name> <label-key>=<label-value>
而後,在Pod的定義中加上nodeSelector的設置
... template: ... spec: ... nodeSelector: label-key: label-value
注:若是有多個節點都定義了相同的label,scheduler就會根據調度算法從這組Node進行Pod調度,可是若是Pod上定義了nodeSelector參數,可是Node上沒法找到對應的Node,則Pod沒法被調度成功。
2.NodeAffinity:親和性調度
NodeAffinity意爲親和性的策略調度,是一種更加靈活的調度策略。增長了In、NotIn、Exists、DoesNotExists、Gt、Lt等操做符來選擇Node。同時還添加一些信息來設置親和性調度策略:
NodeAffinity 對應地還有 PodAffinity 和 PodAntiAffinity。
下面來個實例,指定Pod運行到kubernetes.io/e2e-az-name值爲e2e-az1 或e2e-az2的節點上面
apiVersion: v1 kind: Pod metadata: name: with-node-affinity annotations: scheduler.alpha.kubernetes.io/affinity: > { "nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { "nodeSelectorTerms": [ { "matchExpressions": [ { "key": "kubernetes.io/e2e-az-name", "operator": "In", "values": ["e2e-az1", "e2e-az2"] } ] } ] } } } another-annotation-key: another-annotation-value spec: containers: - name: with-node-affinity image: gcr.io/google_containers/pause:2.0
DaemonSet是k8s1.2版本新增地一種資源對象,用於在集羣中每一個Node上僅運行一份Pod的副本實例。它具備如下的應用實例:
DaemonSet 的 Pod 調度策略與 RC 相似,除了使用系統內置的算法在每臺Node上進行調度,也能夠在Pod的定義中使用NodeSelector或NodeAffinity來指定知足條件的Node範圍進行調度。
k8s在1.2版本之後,開始支持批處理類型的應用,咱們能夠經過k8s Job資源對象來定義並啓動一個批處理任務。批處理任務一般並行或串行啓動多個計算進程去處理一批工做項(work item)。
apiVersion: batch/v1 kind: Job metadata: name: myjob spec: template: metadata: name: myjob spec: containers: - name: hello image: busybox command: ["echo", "hello world"] restartPolicy: Never
查看批處理任務:
[root@k8s-master ~]# kubectl get jobs NAME COMPLETIONS DURATION AGE myjob 1/1 21s 4m44s
同時也能夠指定批處理的並行個數和重複次數
... spec: completions: 6 # 重複次數 parallelism: 3 # 並行個數 ...
同時k8s還支持定時任務,相似linux的Crontab。利用 CronJob 資源對象表示:
apiVersion: batch/v2alpha1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox command: ["echo","hello k8s job!"] restartPolicy: Never
可是建立CronJob會報錯:
[root@k8s-master ~]# kubectl apply -f job/cronJob.yaml error: unable to recognize "job/cronJob.yaml": no matches for kind "CronJob" in version "batch/v2alpha1"
修改kube-apiserver配置文件,/etc/kubernetes/manifests/kube-apiserver.yaml
... spec: containers: - command: - kube-apiserver - --advertise-address=192.168.10.20 - --runtime-config=batch/v2alpha1=true # 添加版本 ...
重啓kubelet
systemctl restart kubelet
從新建立CronJob
kubectl apply -f job/cronJob.yaml
k8s RC的Scale機制能讓咱們在運行中修改Pod的數量。經過命令:
[root@k8s-master ~]# kubectl get rc NAME DESIRED CURRENT READY AGE redis-master 1 1 1 4d11h redis-slave 2 2 2 4d11h [root@k8s-master ~]# kubectl scale rc redis-slave --replicas=3 replicationcontroller/redis-slave scaled
關鍵在於指定參數--replicas
的值,若是該值大於當前rc對應的Pod的值,就添加Pod;反之,則殺死。
除了使用命令kubectl scale以外,k8s還支持 HPA(Horizontal Pod Autoscaler)用於實現基於CPU使用率進行自動Pod擴容縮容的功能。HPA針對RC或Department對象,且Pod必須定義resource.request.cpu。HPA控制器基於Master的kube-controller-manager
服務啓動參數--horizontal-pod-autoscaler-sync-period
定義的探測週期(默認值爲15s),週期性地監測目標Pod地資源性能指標,並與HPA資源對象中地擴縮容條件進行對比,在知足條件時對Pod副本數量進行調整。
須要自動調整的RC或Deployment配置以下:
apiVersion: v1 kind: Service metadata: name: svc-hpa namespace: default spec: selector: app: myapp type: NodePort ##注意這裏是NodePort,下面壓力測試要用到。 ports: - name: http port: 80 nodePort: 31111 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: default spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: name: myapp-demo namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 resources: requests: cpu: 50m memory: 50Mi limits: cpu: 50m memory: 50Mi
HPA配置以下:
apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa-v2 namespace: default spec: minReplicas: 1 ##至少1個副本 maxReplicas: 8 ##最多8個副本 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp metrics: - type: Resource resource: name: cpu targetAverageUtilization: 50 ##注意此時是根據使用率,也能夠根據使用量:targetAverageValue - type: Resource resource: name: memory targetAverageUtilization: 50 ##注意此時是根據使用率,也能夠根據使用量:targetAverageValue
其中關鍵的參數:
k8s支持對如下資源的升級和回滾:
以Deployment爲例:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
使用升級命令:
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
或者使用kubectl edit
命令修改nginx版本爲1.9.1。
一旦鏡像名(或Pod的定義)發生修改,則將觸發系統完成Deployment全部運行Pod的滾動升級操做,使用命令查看:
kubectl rollout status deployment/nginx-deployment
首先可使用命令來查看可回滾的版本:
kubectl rollout history deployment/nginx-deployment
而後使用命令進行回滾:
kubectl rollout undo deployment/nginx-deployment
或者使用指定回滾版本:
kubectl rollout undo deployment/nginx-deployment --to-revision=3
若是Deployment的恢復比較複雜或者在回滾過程當中臨時須要修改,就能夠先暫停回滾,當修改完成後再恢復。
暫停回滾使用命令
kubectl rollout pause deployment/nginx-deployment
暫停回滾後咱們能夠對deployment進行任意次的修改,如更新容器的資源限制:
kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
修改完成後再恢復回滾:
kubectl rollout resume deployment/nginx-deployment