1. 程式人生 > 其它 >k8s — pod基礎與分類

k8s — pod基礎與分類

k8s — pod基礎與分類

一、Pod基礎概念

1、解釋

  • Pod是kubernetes中最小的資源管理元件,Pod也是最小化執行容器化應用的資源物件。一個Pod代表著叢集中執行的一個程序。kubernetes中其他大多陣列件都是圍繞著Pod來進行支撐和擴充套件Pod功能的,例如,用於管理Pod執行的StatefulSet和Deployment等控制器物件,用於暴露Pod應用的Service和工ngress物件,為P od提供儲存的PersistentVolume儲存資源物件等。

2、在Kubrenetes叢集中Pod有如下兩種使用方式

  • —個Pod中執行一個容器。“每個Pod中一個容器"的模式是最常見的用法∶在這種使用方式中,你可以把Pod想象成是單個容器的封裝,kuberentes管理的是Pod 而不是直接管理容器。
  • 在一個pod中同時執行多個容器。一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個service單位,比如一個容器共享檔案,另一個"sidecar"容器來更新這些檔案。Pod將這些容器的儲存資源作為一個實體來管理。

一個pod下的容器必須運行於同一節點上。現代容器技術建議—個容器只執行一個程序。該程序在容器中PID 命令空間中的程序號為1,可直接接收並處理訊號,程序終止時容器生命週期也就結束了。若想在容器內執行多個程序,需要有一個類似Linux作業系統 init 程序的管控類程序,以樹狀結構完成多程序的生命週期管理。 運行於各自容器內的程序無法直接完成網路通訊,這是由於容器間的隔離機制導致,k8s中的Pod資源抽象正是解決此類問題,Pod物件是一組容器的集合,這些容器共享Network、UTS及IPC 命令空間,因此具有相同的域名、主機名和網路介面,並可通過IPC直接通訊。

Pod 資源中針對各容器提供網路命令空間等共享機制的是底層基礎容器 pause,基礎容器(也可稱為父容器)pause就是為了管理Pod容器間的共享操作, 這個父容器需要能夠準確地知道如何去建立共享執行環境的容器,還能管理這些容器的生命週期。 為了實現這個父容器的構想,kubernetes中,這個pause容器來作為一個 Pod中所有容器的父容器。這個pause容器有兩個核心的功能,一是它提供整個Pod 的Linux命名間的基礎。二來啟用PID 名稱空間,它在每個Pod 中都作為PID 為1 程序(init程序),並回收殭屍程序。

3、pause容器使得Pod中的所有容器可以共享兩種資源∶網路和儲存。

(1)網路

  • 每個Pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網路空間,包括IP地址和埠。Pod內部的容器可以使用localhost互相通訊。Pod中的容器與外界通訊時,必須分配共享網路資源(例如使用宿主機的埠對映)。

(2)儲存

  • 可以Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的Volume。Volume也可以用來持久化Pod中的儲存資源,以防容器重啟後文件丟失。

4、總結

  • 每個Pod都有一個特殊的被稱為"基礎容器"的Pause容器。Pause容器對應的映象屬於Kubernetes平臺的一部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的使用者應用容器。

5、kubernetes中的pause容器主要為每個容器提供以下功能∶

  • 在pod中擔任Linux名稱空間(如網路命令空間)共享的基礎
  • 啟用PID名稱空間,開啟init程序。

6、Kubernetes設計這樣的Pod概念和特殊組成結構的用意

  • 原因一∶ 在一組容器作為一個單元的情況下,難以對整體的容器簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了麼?那麼引入與業務無關的Pause容器作為Pod的基礎容器,以它的狀態代表著整個容器組的狀態,這樣就可以解決該問題。
  • 原因二∶ Pod裡的多個應用容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了應用容器之間的通訊問題,也解決了容器之間的檔案共享問題。

二、Pod 容器的分類

1、pod 的分類

(1)自主式Pod

  • 這種Pod本身是不能自我修復的,當Pod被建立後(不論是由你直接建立還是被其他Controller),都會被Kuberentes排程到叢集的Node上。直到Pod的程序終止、被刪掉、因為缺少資源而被驅逐、或者Node故險之前這個Pod都會—一直保持在那個Node 上。Pod不會自愈。如果Pod執行的INode故院,或者是排程器本身故院,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。

(2)控制器管理的Pod

  • Kubernetes使用更高階的稱為Controller的抽象層,來管理Pod例項。Controller可以建立和管理多個Pod,提供副本管理、滾動升級和叢集級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod排程到其他健康的Node上。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。

2、Pod 容器的分類

(1)基礎容器(infrastructure container)

  • 維護整個 pod 網路和儲存空間
  • node節點中操作
  • 啟動一個容器時,k8s 會自動啟動一個基礎容器
cat /opt/kubernetes/cfg/kubelet
......
--pod-infra-container-image=registry.cnhangzhou.aliyuncs.com/google-containers/pause-amd64:3.0
  • 每次建立 Pod 時候就會建立,執行的每一個容器都有一個 pause-amd64 的基礎容器自動會執行,對於使用者是透明的
docker ps -a
registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0   "/pause"

(2)初始化容器(initcontainers)

  • Init容器必須在應用程式容器啟動之前執行完成,而應用程式容器是並行執行的,所以Init容器能夠提供了一種簡單的阻塞或延遲應用容器的啟動的方法。

init 容器與普通的容器非常像,除了以下兩點

  • Init 容器總是執行到成功完成為止
  • 每個 Init 容器都必須在下一個 Init 容器啟動之前成功完成啟動和退出

如果 Pod 的 Init 容器失敗,k8s 會不斷地重啟該 Pod,直到 Init 容器成功為止。然而,如果 Pod 對應的重啟策略(restartPolicy)為 Never,它不會重新啟動。

Init 的容器作用

因為init容器具有與應用容器分離的單獨映象,其啟動相關程式碼具有如下優勢

  • Init 容器可以包含一些安裝過程中應用容器中不存在的實用工具或個性化程式碼。例如,沒有必要僅為了在安裝過程中使用類似 sed、 awk、 python 或 dig 這樣的工具而去FROM 一個映象來生成一個新的映象。
  • Init 容器可以安全地執行這些工具,避免這些工具導致應用映象的安全性降低。
  • 應用映象的建立者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用映象。
  • Init 容器能以不同於Pod內應用容器的檔案系統檢視執行。因此,Init容器可具有訪問 Secrets 的許可權,而應用容器不能夠訪問。
  • 由於 Init 容器必須在應用容器啟動之前執行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,

直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會並行啟動。

(3)應用容器(Maincontainer) // 並行啟動

官網示例:
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

這個例子是定義了一個具有 2 個 Init 容器的簡單 Pod。 第一個等待 myservice 啟動, 第二個等待 mydb 啟動。 一旦這兩個 Init容器都啟動完成,Pod 將啟動 spec 中的應用容器。
kubectl describe pod myapp-pod
kubectl logs myapp-pod -c init-myservice

vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
    
kubectl create -f myservice.yaml
kubectl get svc
kubectl get pods -n kube-system
kubectl get pods

vim mydb.yaml
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377
    
kubectl create -f mydb.yaml
kubectl get pods

特別說明

  • 在Pod啟動過程中,Init容器會按順序在網路和資料卷初始化之後啟動。每個容器必須在下一個容器啟動之前成功退出。
  • 如果由於執行時或失敗退出,將導致容器啟動失敗,它會根據Pod的restartPolicy指定的策略進行重試。然而,如果Pod的restartPolicy設定為Always,Init容器失敗時會使用RestartPolicy策略。
  • 在所有的Init容器沒有成功之前,Pod將不會變成Ready狀態。Init容器的埠將不會在Service中進行聚集。正在初始化中的Pod處於Pending狀態,但應該會將Initializing狀態設定為true。
  • 如果Pod重啟,所有Init容器必須重新執行。
  • 對Init容器spec的修改被限制在容器image欄位,修改其他欄位都不會生效。更改Init容器的image欄位,等價於重啟該Pod。
  • Init容器具有應用容器的所有欄位。除了readinessProbe,因為Init容器無法定義不同於完成(completion)的就緒(readiness)之外的其他狀態。這會在驗證過程中強制執行。
  • 在Pod中的每個app和Init容器的名稱必須唯一;與任何其它容器共享同一個名稱,會在驗證時丟擲錯誤。

三、映象拉取策略

Pod 的核心是執行容器,必須指定容器引擎,比如 Docker,啟動容器時,需要拉取映象,k8s 的映象拉取策略可以由使用者指定:

  • IfNotPresent:在映象已經存在的情況下,kubelet 將不再去拉取映象,僅當本地缺失時才從倉庫中拉取,預設的映象拉取策略
  • Always:每次建立 Pod 都會重新拉取一次映象;
  • Never:Pod 不會主動拉取這個映象,僅使用本地映象。

注意:對於標籤為“:latest”的映象檔案,其預設的映象獲取策略即為“Always”;而對於其他標籤的映象,其預設策略則為“IfNotPresent”。

1、官方示例

https://kubernetes.io/docs/concepts/containers/images

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: private-image-test-1
spec:
  containers:
    - name: uses-private-image
      image: $PRIVATE_IMAGE_NAME
      imagePullPolicy: Always
      command: [ "echo", "SUCCESS" ]
EOF

2、master 01上操作

kubectl edit deployment/nginx-deployment
......
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.15.4
        imagePullPolicy: IfNotPresent                            #映象拉取策略為 IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always                                        #Pod的重啟策略為 Always,預設值
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
......

3、建立測試案例

mkdir /opt/demo
cd /opt/demo

vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-test1
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: Always
      command: [ "echo", "SUCCESS" ]

kubectl create -f pod1.yaml

kubectl get pods -o wide
pod-test1                         0/1     CrashLoopBackOff   4          3m33s
//此時 Pod 的狀態異常,原因是 echo 執行完程序終止,容器生命週期也就結束了

kubectl describe pod pod-test1
......
Events:
  Type     Reason     Age                 From                    Message
  ----     ------     ----                ----                    -------
  Normal   Scheduled  2m10s               default-scheduler       Successfully assigned default/pod-test1 to 192.168.80.11
  Normal   Pulled     46s (x4 over 119s)  kubelet, 192.168.80.11  Successfully pulled image "nginx"
  Normal   Created    46s (x4 over 119s)  kubelet, 192.168.80.11  Created container
  Normal   Started    46s (x4 over 119s)  kubelet, 192.168.80.11  Started container
  Warning  BackOff    19s (x7 over 107s)  kubelet, 192.168.80.11  Back-off restarting failed container
  Normal   Pulling    5s (x5 over 2m8s)   kubelet, 192.168.80.11  pulling image "nginx"
//可以發現 Pod 中的容器在生命週期結束後,由於 Pod 的重啟策略為 Always,容器再次重啟了,並且又重新開始拉取映象

4、修改pod1.yaml檔案

cd /opt/demo
vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-test1
spec:
  containers:
    - name: nginx
      image: nginx:1.14                            #修改 nginx 映象版本
      imagePullPolicy: Always
      #command: [ "echo", "SUCCESS" ]            #刪除

//刪除原有的資源
kubectl delete -f pod1.yaml 

//更新資源
kubectl apply -f pod1.yaml 

//檢視 Pod 狀態
kubectl get pods -o wide
NAME                              READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE
pod-test1                         1/1     Running   0          33s   172.17.36.4   192.168.80.11   <none>

//在任意 node 節點上使用 curl 檢視頭部資訊
curl -I http://172.17.36.4
HTTP/1.1 200 OK
Server: nginx/1.14.2
......

四、部署 harbor 建立私有專案

//在 Docker harbor 節點(192.168.80.30)上操作
systemctl stop firewalld.service
systemctl disable firewalld.service
setenforce 0

yum install -y yum-utils device-mapper-persistent-data lvm2 
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 
yum install -y docker-ce
systemctl start docker.service
systemctl enable docker.service
docker version

//上傳 docker-compose 和 harbor-offline-installer-v1.2.2.tgz 到 /opt 目錄中
cd /opt
chmod +x docker-compose
mv docker-compose /usr/local/bin/

//部署 Harbor 服務
tar zxvf harbor-offline-installer-v1.2.2.tgz -C /usr/local/
vim /usr/local/harbor/harbor.cfg
--5行--修改,設定為Harbor伺服器的IP地址或者域名
hostname = 192.168.80.30

cd /usr/local/harbor/
./install.sh

//在 Harbor 中建立一個新專案1)瀏覽器訪問:http://192.168.80.10 登入 Harbor WEB UI 介面,預設的管理員使用者名稱和密碼是 admin/Harbor123452)輸入使用者名稱和密碼登入介面後可以建立一個新專案。點選“+專案”按鈕
(3)填寫專案名稱為“kgc-project”,點選“確定”按鈕,建立新專案

//在每個 node 節點配置連線私有倉庫(注意每行後面的逗號要新增)
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["https://6ijb8ubo.mirror.aliyuncs.com"],
  "insecure-registries":["192.168.80.30"]
}
EOF

systemctl daemon-reload
systemctl restart docker

//在每個 node 節點登入 harbor 私有倉庫
docker login -u admin -p harbor12345 http://192.168.80.30

//在一個 node 節點下載 Tomcat 映象進行推送
docker pull tomcat:8.0.52
docker images

docker tag tomcat:8.0.52 192.168.80.30/kgc-project/tomcat:v1
docker images
docker push 192.168.80.30/kgc-project/tomcat:v1

//檢視登陸憑據
cat /root/.docker/config.json | base64 -w 0            #base64 -w 0:進行 base64 加密並禁止自動換行
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjE5NS44MCI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy41IChsaW51eCkiCgl9Cn0=

//建立 harbor 登入憑據資源清單
vim harbor-pull-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: harbor-pull-secret
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjE5NS44MCI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy41IChsaW51eCkiCgl9Cn0=            #複製貼上上述檢視的登陸憑據
type: kubernetes.io/dockerconfigjson

//建立 secret 資源
kubectl create -f harbor-pull-secret.yaml

//檢視 secret 資源
kubectl get secret

//建立資源從 harbor 中下載映象
cd /opt/demo
vim tomcat-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-tomcat
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: my-tomcat
    spec:
      imagePullSecrets:                        #新增拉取 secret 資源選項
      - name: harbor-pull-secret            #指定 secret 資源名稱
      containers:
      - name: my-tomcat
        image: 192.168.80.30/kgc-project/tomcat:v1        #指定 harbor 中的映象名
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-tomcat
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 31111
  selector:
    app: my-tomcat

//刪除之前在 node 節點下載的 Tomcat 映象
docker rmi tomcat:8.0.52
docker rmi 192.168.80.30/kgc-project/tomcat:v1
docker images

//建立資源
kubectl create -f tomcat-deployment.yaml

kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
my-tomcat-d55b94fd-29qk2   1/1     Running   0         
my-tomcat-d55b94fd-9j42r   1/1     Running   0         

//檢視 Pod 的描述資訊,可以發現映象時從 harbor 下載的
kubectl describe pod my-tomcat-d55b94fd-29qk2

//重新整理 harbor 頁面,可以看到映象的下載次數增加了