深入 Pod

ACatSmiling發表於2024-11-05

Author: ACatSmiling

Since: 2024-11-05

kubectl 命令

建立 Pod

方式一:使用配置檔案建立。

  1. 首先,需要建立一個 Pod 的配置檔案(通常是.yaml.yml格式)。例如,建立一個簡單的 Nginx Pod 配置檔案 nginx-pod.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-pod
    spec:
      containers:
      - name: nginx-container # 單容器 Pod
        image: nginx:latest
    
  2. kubectl create:不存在則新建,存在則報錯。

    $ kubectl create -f nginx-pod.yaml
    
  3. kubectl apply:不存在則新建,存在則更新。

    $ kubectl apply -f nginx-pod.yaml
    
  4. 建立多容器 Pod:

    apiVersion: v1
    kind: Pod
    metadata:
      name: multi-container-pod
      labels:
        app: multi-app-label
    spec:
      containers:
        - name: container-1 # 容器 1
        image: nginx:latest
        ports:
          - containerPort: 80
        - name: container-2 # 容器 2
          image: redis:latest
    
    $ kubectl create -f multi-container-pod.yaml
    # 或者
    $ kubectl apply -f multi-container-pod.yaml
    

方式二:使用命令列引數建立(不推薦用於複雜配置)。

  1. kubectl run:快速建立一個簡單的 Pod。例如,建立一個名為 busybox-pod 的 Pod,執行 busybox 映象:

    $ kubectl run busybox-pod --image=busybox:latest
    

檢視 Pod

  1. kubectl get pods:檢視叢集中所有名稱空間下的所有 Pod 列表。示例:

    [root@k8s-master pods]# kubectl get pods
    NAME          READY   STATUS    RESTARTS   AGE
    nginx-pod     1/1     Running   0          10m
    
    • 輸出結果通常包含以下列:

      • NAME:Pod 的名稱,用於在叢集中唯一標識 Pod。
      • READY:顯示準備就緒的容器數量與總容器數量的比例。
      • STATUS:Pod 的當前狀態,常見的狀態有Pending(等待排程或資源分配)、Running(正在執行)、Succeeded(成功完成任務,通常用於一次性任務的 Pod)、Failed(執行失敗)。
      • RESTARTS:容器重啟的次數。
      • AGE:Pod 自建立以來的時間。
    • <pod-name>:檢視指定 Pod。示例:

      [root@k8s-master pods]# kubectl get pods nginx-pod
      NAME        READY   STATUS    RESTARTS   AGE
      nginx-pod   1/1     Running   0          9h
      
    • -n, --namespace:檢視特定名稱空間中的 Pod。示例:

      [root@k8s-master pods]# kubectl get pods -n kube-system
      NAME                                 READY   STATUS    RESTARTS         AGE
      coredns-6d8c4cb4d-d6rrb              1/1     Running   7 (4d11h ago)    11d
      coredns-6d8c4cb4d-zsx7n              1/1     Running   7 (4d11h ago)    11d
      etcd-k8s-master                      1/1     Running   19 (4d11h ago)   66d
      kube-apiserver-k8s-master            1/1     Running   17 (4d11h ago)   66d
      kube-controller-manager-k8s-master   1/1     Running   22 (4d11h ago)   66d
      kube-proxy-6xntx                     1/1     Running   14 (4d11h ago)   59d
      kube-proxy-m2nbx                     1/1     Running   21 (4d11h ago)   66d
      kube-proxy-vzsp7                     1/1     Running   12 (4d11h ago)   59d
      kube-scheduler-k8s-master            1/1     Running   22 (4d11h ago)   66d
      
    • -l:按照標籤來檢視 Pod。示例:

      [root@k8s-master pods]# kubectl get pods -l app=nginx-pod-app
      NAME        READY   STATUS    RESTARTS   AGE
      nginx-pod   1/1     Running   0          8h
      
    • -o wide:以寬格式檢視,獲取更詳細的資訊,包括 Pod 所在的節點 IP 和節點名稱等。示例:

      [root@k8s-master pods]#  kubectl get pods -o wide
      NAME        READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
      nginx-pod   1/1     Running   0          10m   10.244.2.11   k8s-node2   <none>           <none>
      
    • -o custom-columns:自定義顯示的列。示例:

      # 只顯示 Pod 的名稱和狀態
      [root@k8s-master pods]# kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase
      NAME        STATUS
      nginx-pod   Running
      
    • -o yaml|json:以 YAML 或 JSON 格式呈現 Pod 的完整配置資訊。示例:

      [root@k8s-master pods]# kubectl get pod nginx-pod -o yaml
      apiVersion: v1
      kind: Pod
      metadata:
        creationTimestamp: "2024-11-03T02:56:23Z"
        labels:
          app: nginx-pod-app
        name: nginx-pod
        namespace: default
        resourceVersion: "404257"
        uid: 25c1720e-9653-4516-840a-56694aec429c
      spec:
        containers:
        - command:
          - nginx
          - -g
          - daemon off;
          env:
          - name: JVM_OPTS
            value: -Xms128m -Xmx128m
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          name: nginx-pod
          ports:
          - containerPort: 80
            name: http
            protocol: TCP
          resources:
            limits:
              cpu: 200m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 128Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
          - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
            name: kube-api-access-2qcsr
            readOnly: true
          workingDir: /usr/share/nginx/html
        dnsPolicy: ClusterFirst
        enableServiceLinks: true
        nodeName: k8s-node2
        preemptionPolicy: PreemptLowerPriority
        priority: 0
        restartPolicy: OnFailure
        schedulerName: default-scheduler
        securityContext: {}
        serviceAccount: default
        serviceAccountName: default
        terminationGracePeriodSeconds: 30
        tolerations:
        - effect: NoExecute
          key: node.kubernetes.io/not-ready
          operator: Exists
          tolerationSeconds: 300
        - effect: NoExecute
          key: node.kubernetes.io/unreachable
          operator: Exists
          tolerationSeconds: 300
        volumes:
        - name: kube-api-access-2qcsr
          projected:
            defaultMode: 420
            sources:
            - serviceAccountToken:
                expirationSeconds: 3607
                path: token
            - configMap:
                items:
                - key: ca.crt
                  path: ca.crt
                name: kube-root-ca.crt
            - downwardAPI:
                items:
                - fieldRef:
                    apiVersion: v1
                    fieldPath: metadata.namespace
                  path: namespace
      status:
        conditions:
        - lastProbeTime: null
          lastTransitionTime: "2024-11-03T02:56:23Z"
          status: "True"
          type: Initialized
        - lastProbeTime: null
          lastTransitionTime: "2024-11-03T02:56:24Z"
          status: "True"
          type: Ready
        - lastProbeTime: null
          lastTransitionTime: "2024-11-03T02:56:24Z"
          status: "True"
          type: ContainersReady
        - lastProbeTime: null
          lastTransitionTime: "2024-11-03T02:56:23Z"
          status: "True"
          type: PodScheduled
        containerStatuses:
        - containerID: docker://986ebb51cd36474dcb6f9789e13e3ed6ddb064e4a799fd282389c7eddf013fe4
          image: nginx:latest
          imageID: docker-pullable://nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3
          lastState: {}
          name: nginx-pod
          ready: true
          restartCount: 0
          started: true
          state:
            running:
              startedAt: "2024-11-03T02:56:23Z"
        hostIP: 192.168.1.122
        phase: Running
        podIP: 10.244.2.11
        podIPs:
        - ip: 10.244.2.11
        qosClass: Burstable
        startTime: "2024-11-03T02:56:23Z"
        
      [root@k8s-master pods]# kubectl get pod nginx-pod -o json
      {
          "apiVersion": "v1",
          "kind": "Pod",
          "metadata": {
              "creationTimestamp": "2024-11-03T02:56:23Z",
              "labels": {
                  "app": "nginx-pod-app"
              },
              "name": "nginx-pod",
              "namespace": "default",
              "resourceVersion": "404257",
              "uid": "25c1720e-9653-4516-840a-56694aec429c"
          },
          "spec": {
              "containers": [
                  {
                      "command": [
                          "nginx",
                          "-g",
                          "daemon off;"
                      ],
                      "env": [
                          {
                              "name": "JVM_OPTS",
                              "value": "-Xms128m -Xmx128m"
                          }
                      ],
                      "image": "nginx:latest",
                      "imagePullPolicy": "IfNotPresent",
                      "name": "nginx-pod",
                      "ports": [
                          {
                              "containerPort": 80,
                              "name": "http",
                              "protocol": "TCP"
                          }
                      ],
                      "resources": {
                          "limits": {
                              "cpu": "200m",
                              "memory": "256Mi"
                          },
                          "requests": {
                              "cpu": "100m",
                              "memory": "128Mi"
                          }
                      },
                      "terminationMessagePath": "/dev/termination-log",
                      "terminationMessagePolicy": "File",
                      "volumeMounts": [
                          {
                              "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
                              "name": "kube-api-access-2qcsr",
                              "readOnly": true
                          }
                      ],
                      "workingDir": "/usr/share/nginx/html"
                  }
              ],
              "dnsPolicy": "ClusterFirst",
              "enableServiceLinks": true,
              "nodeName": "k8s-node2",
              "preemptionPolicy": "PreemptLowerPriority",
              "priority": 0,
              "restartPolicy": "OnFailure",
              "schedulerName": "default-scheduler",
              "securityContext": {},
              "serviceAccount": "default",
              "serviceAccountName": "default",
              "terminationGracePeriodSeconds": 30,
              "tolerations": [
                  {
                      "effect": "NoExecute",
                      "key": "node.kubernetes.io/not-ready",
                      "operator": "Exists",
                      "tolerationSeconds": 300
                  },
                  {
                      "effect": "NoExecute",
                      "key": "node.kubernetes.io/unreachable",
                      "operator": "Exists",
                      "tolerationSeconds": 300
                  }
              ],
              "volumes": [
                  {
                      "name": "kube-api-access-2qcsr",
                      "projected": {
                          "defaultMode": 420,
                          "sources": [
                              {
                                  "serviceAccountToken": {
                                      "expirationSeconds": 3607,
                                      "path": "token"
                                  }
                              },
                              {
                                  "configMap": {
                                      "items": [
                                          {
                                              "key": "ca.crt",
                                              "path": "ca.crt"
                                          }
                                      ],
                                      "name": "kube-root-ca.crt"
                                  }
                              },
                              {
                                  "downwardAPI": {
                                      "items": [
                                          {
                                              "fieldRef": {
                                                  "apiVersion": "v1",
                                                  "fieldPath": "metadata.namespace"
                                              },
                                              "path": "namespace"
                                          }
                                      ]
                                  }
                              }
                          ]
                      }
                  }
              ]
          },
          "status": {
              "conditions": [
                  {
                      "lastProbeTime": null,
                      "lastTransitionTime": "2024-11-03T02:56:23Z",
                      "status": "True",
                      "type": "Initialized"
                  },
                  {
                      "lastProbeTime": null,
                      "lastTransitionTime": "2024-11-03T02:56:24Z",
                      "status": "True",
                      "type": "Ready"
                  },
                  {
                      "lastProbeTime": null,
                      "lastTransitionTime": "2024-11-03T02:56:24Z",
                      "status": "True",
                      "type": "ContainersReady"
                  },
                  {
                      "lastProbeTime": null,
                      "lastTransitionTime": "2024-11-03T02:56:23Z",
                      "status": "True",
                      "type": "PodScheduled"
                  }
              ],
              "containerStatuses": [
                  {
                      "containerID": "docker://986ebb51cd36474dcb6f9789e13e3ed6ddb064e4a799fd282389c7eddf013fe4",
                      "image": "nginx:latest",
                      "imageID": "docker-pullable://nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3",
                      "lastState": {},
                      "name": "nginx-pod",
                      "ready": true,
                      "restartCount": 0,
                      "started": true,
                      "state": {
                          "running": {
                              "startedAt": "2024-11-03T02:56:23Z"
                          }
                      }
                  }
              ],
              "hostIP": "192.168.1.122",
              "phase": "Running",
              "podIP": "10.244.2.11",
              "podIPs": [
                  {
                      "ip": "10.244.2.11"
                  }
              ],
              "qosClass": "Burstable",
              "startTime": "2024-11-03T02:56:23Z"
          }
      }
      
  2. kubectl describe pod:檢視單個 Pod 的詳細資訊,包括容器狀態、事件等。示例:

    [root@k8s-master pods]# kubectl describe pod nginx-pod
    Name:         nginx-pod
    Namespace:    default
    Priority:     0
    Node:         k8s-node2/192.168.1.122
    Start Time:   Sun, 03 Nov 2024 10:56:23 +0800
    Labels:       app=nginx-pod-app
    Annotations:  <none>
    Status:       Running
    IP:           10.244.2.11
    IPs:
      IP:  10.244.2.11
    Containers:
      nginx-pod:
        Container ID:  docker://986ebb51cd36474dcb6f9789e13e3ed6ddb064e4a799fd282389c7eddf013fe4
        Image:         nginx:latest
        Image ID:      docker-pullable://nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3
        Port:          80/TCP
        Host Port:     0/TCP
        Command:
          nginx
          -g
          daemon off;
        State:          Running
          Started:      Sun, 03 Nov 2024 10:56:23 +0800
        Ready:          True
        Restart Count:  0
        Limits:
          cpu:     200m
          memory:  256Mi
        Requests:
          cpu:     100m
          memory:  128Mi
        Environment:
          JVM_OPTS:  -Xms128m -Xmx128m
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2qcsr (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      kube-api-access-2qcsr:
        Type:                    Projected (a volume that contains injected data from multiple sources)
        TokenExpirationSeconds:  3607
        ConfigMapName:           kube-root-ca.crt
        ConfigMapOptional:       <nil>
        DownwardAPI:             true
    QoS Class:                   Burstable
    Node-Selectors:              <none>
    Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
    Events:                      <none>
    
    • 輸出內容通常包含以下資訊:
      • Pod 的基本資訊:包括名稱、名稱空間、標籤、註釋等。
      • 容器資訊:包括容器名稱、映象、埠、資源請求和限制等,還會顯示容器的狀態,以及容器啟動和停止的相關資訊。
      • 卷(Volumes)資訊:如果 Pod 掛載了卷,會在這裡顯示卷的型別、來源等資訊。
      • 事件資訊:記錄了 Pod 生命週期內發生的事件,例如排程事件、容器啟動和停止事件等。
  3. kubectl logs:檢視 Pod 中容器的日誌。示例:

    [root@k8s-master pods]# kubectl logs nginx-pod
    2024/11/03 02:56:23 [notice] 1#1: using the "epoll" event method
    2024/11/03 02:56:23 [notice] 1#1: nginx/1.27.1
    2024/11/03 02:56:23 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
    2024/11/03 02:56:23 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64
    2024/11/03 02:56:23 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
    2024/11/03 02:56:23 [notice] 1#1: start worker processes
    2024/11/03 02:56:23 [notice] 1#1: start worker process 6
    2024/11/03 02:56:23 [notice] 1#1: start worker process 7
    
    • <pod-name> -c <container-name>:如果 Pod 中有多個容器,需要指定容器名稱。示例:

      # 檢視 nginx-pod 中 nginx-pod 容器的日誌
      [root@k8s-master pods]# kubectl logs nginx-pod -c nginx-pod
      2024/11/03 02:56:23 [notice] 1#1: using the "epoll" event method
      2024/11/03 02:56:23 [notice] 1#1: nginx/1.27.1
      2024/11/03 02:56:23 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
      2024/11/03 02:56:23 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64
      2024/11/03 02:56:23 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
      2024/11/03 02:56:23 [notice] 1#1: start worker processes
      2024/11/03 02:56:23 [notice] 1#1: start worker process 6
      2024/11/03 02:56:23 [notice] 1#1: start worker process 7
      
    • -f:實時日誌檢視。示例:

      [root@k8s-master pods]# kubectl logs -f nginx-pod
      2024/11/03 02:56:23 [notice] 1#1: using the "epoll" event method
      2024/11/03 02:56:23 [notice] 1#1: nginx/1.27.1
      2024/11/03 02:56:23 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
      2024/11/03 02:56:23 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64
      2024/11/03 02:56:23 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
      2024/11/03 02:56:23 [notice] 1#1: start worker processes
      2024/11/03 02:56:23 [notice] 1#1: start worker process 6
      2024/11/03 02:56:23 [notice] 1#1: start worker process 7
      
      

更新 Pod

  1. kubectl set image:更新容器映象。

    $ kubectl set image pod/<pod-name> <container-name>=<new-image>
    
    • 引數說明:

      • <pod-name>:要更新的 Pod 名稱。
      • <container-name>:Pod 中要更新映象的容器名稱。
      • <new-image>:新的容器映象。
    • 注意事項:

      • 更新過程:當執行此命令後,Kubernetes 會自動觸發容器的重新建立過程,以使用新的映象。這個過程可能會導致短暫的服務中斷,具體取決於應用程式的特性和更新策略。一些應用程式可能能夠平滑地過渡到新映象,而另一些可能需要一些額外的配置來確保資料的完整性和服務的連續性。
      • 滾動更新(Deployment):如果 Pod 是由 Deployment 管理的,那麼更新映象會觸發 Deployment 進行滾動更新。滾動更新會逐步替換舊的 Pod 副本為新的副本,以確保服務的可用性,可以透過設定maxSurgemaxUnavailable等引數來控制滾動更新的速度和方式。
      • 版本相容性:在更新映象時,要確保新映象與現有應用程式的配置和資料格式相容。例如,如果應用程式的資料庫模式在新映象中有變化,可能需要先進行資料庫遷移等操作,否則可能會導致應用程式無法正常執行。
    • 示例:

      # 將名為 my-pod 的 Pod,其中名為 my-container 的容器,由當前使用的 nginx:1.19 映象,更新為 nginx:1.23
      $ kubectl set image pod/my-pod my-container=nginx:1.23
      
  2. 更新資源請求和限制(CPU、記憶體等)

    • 修改配置檔案並應用更新(推薦)

      • 步驟一:修改配置檔案。

        # 更新前配置,CPU 為 0.2,記憶體為 256M
        apiVersion: v1
        kind: Pod
        metadata:
          name: my-pod
        spec:
          containers:
          - name: my - container
            image: nginx:latest
            resources:
              requests:
                cpu: "0.2"
                memory: "256Mi"
        
        # 更新後配置,CPU 為 0.3,記憶體為 512M
        apiVersion: v1
        kind: Pod
        metadata:
          name: my-pod
        spec:
          containers:
          - name: my - container
            image: nginx:latest
            resources:
              requests:
                cpu: "0.3"
                memory: "512Mi"
        
      • 步驟二:應用更新。

        # Kubernetes 會根據新的配置調整 Pod 的資源分配
        $ kubectl apply -f my-pod.yaml
        
    • kubectl edit:臨時修改。示例:

      $ kubectl edit pod my-pod
      
      • kubectk edit 命令,會開啟一個文字編輯器(預設是 vi 或 vim),顯示 Pod 的配置資訊。
      • 在編輯器中修改資源請求和限制的相關內容,儲存並退出後,Kubernetes 會嘗試根據修改後的配置更新 Pod。不過這種方式的修改是直接作用於叢集中的資源,沒有經過配置檔案的版本控制,所以在生產環境中使用時要謹慎,並且最好在修改後將更新後的配置儲存到配置檔案中,以方便後續的管理和維護。

刪除 Pod

  1. kubectl delete pod <pod-name>:刪除單個 Pod。示例:

    $ kubectl delete pod nginx-pod
    
    • --force--grace-period=0:強制刪除 Pod,但這種方式可能會導致資料丟失或未完成的操作被中斷,應該謹慎使用。示例:

      $ kubectl delete pod my-pod --force --grace-period=0
      
      • 正常情況下,當執行刪除命令時,Kubernetes 會先傳送SIGTERM訊號給容器內的主程序,等待一段時間(預設是 30 秒,即grace-period),讓程序進行清理操作(如儲存資料、關閉連線等),然後再傳送SIGKILL訊號強制終止程序。如果使用了強制刪除選項,就會跳過 SIGTERM 等待階段,直接傳送 SIGKILL 訊號。
    • -l:透過標籤選擇器來刪除多個 Pod。示例:

      # 刪除帶有 "app=my-app" 標籤的 Pod
      $ kubectl delete pods -l app=my-app
      
    • --all-n:刪除指定名稱空間下的所有 Pod。示例:

      # 刪除 my-namespace 下的所有 Pod
      $ kubectl delete pods --all -n my-namespace
      

在刪除 Pod 時,要確保清楚自己的操作可能帶來的影響。特別是對於一些有狀態的應用,可能會導致資料丟失或服務中斷。如果這些 Pod 是由更高層次的資源(如 Deployment、StatefulSet 等)管理的,刪除後這些資源可能會自動重新建立 Pod,這也需要考慮對系統整體執行的影響。

Pod 配置檔案

在搭建 Kubernetes 叢集時,建立過一個 Nginx 服務用於測試,現在將其刪除:

[root@k8s-master ~]# kubectl get pods
NAME                     READY   STATUS             RESTARTS   AGE
nginx-85b98978db-bhrd8   0/1     ImagePullBackOff   0          3d12h
[root@k8s-master ~]# kubectl get deployment
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   0/1     1            0           49d
# 刪除 Nginx 對應的 deployment
[root@k8s-master ~]# kubectl delete deployment nginx
deployment.apps "nginx" deleted
[root@k8s-master ~]# kubectl get deployment
No resources found in default namespace.
# pod 是透過 deployment 建立的,刪除 deplpyment,對應的 pod 也就刪除了
[root@k8s-master ~]# kubectl get pods
No resources found in default namespace.

[root@k8s-master ~]# kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        58d
nginx        NodePort    10.98.189.130   <none>        80:31173/TCP   49d
# 刪除 Nginx 對應的 service
[root@k8s-master ~]# kubectl delete services nginx
service "nginx" deleted
[root@k8s-master ~]# kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   58d

定義一個 nginx-pod.yaml 配置檔案:

apiVersion: v1 # api 文件版本
kind: Pod # 資源物件型別,也可以配置為像 Deployment、StatefulSet 這一類的物件
metadata: # Pod 相關的後設資料,用於描述 Pod 的資料
  name: "nginx-pod" # Pod 的名稱
  namespace: default # 定義 Pod 的名稱空間
  labels: # 定義 Pod 的標籤
    app: "nginx-pod-app" # 標籤的 key:value,可以按實際來自定義
spec: # 規約,即期望當前 Pod 應按照下面的描述進行建立
  containers: # 對於 Pod 中的容器描述
  - name: nginx-pod # 容器的名稱
    image: "nginx:latest" # 指定容器的映象
    imagePullPolicy: IfNotPresent # 映象拉取策略,指定如果本地有就用本地的,如果沒有就拉取遠端的
    command: # 指定容器啟動時執行的命令
    - nginx
    - -g
    - 'daemon off;' # 當前 command 配置等同於命令:nginx -g 'daemon off;'
    workingDir: /usr/share/nginx/html # 定義容器啟動後的工作目錄
    resources:
      limits: # 最多可以使用的資源
        cpu: 200m # 限制 cpu 最多使用 0.2 個核心
        memory: 256Mi # 限制記憶體最多使用 256 MB
      requests: # 最少需要使用的資源
        cpu: 100m # 限制 cpu 最少使用 0.1 個核心
        memory: 128Mi # 限制記憶體最多使用 128 MB
    ports:
    - containerPort:  80 # 描述容器內要暴露什麼埠
      name:  http # 埠名稱
      protocol: TCP # 描述該埠是基於哪種協議通訊的
    env: # 環境變數
    - name: JVM_OPTS # 環境變數名稱
      value: '-Xms128m -Xmx128m' # 環境變數的值
  restartPolicy: OnFailure # 重啟策略,只有失敗的情況才會重啟

VS Code 中,可以安裝Kubernetes Templates外掛,用於快速建立配置檔案。

透過 nginx-po.yaml 配置檔案,建立 Pod:

[root@k8s-master pods]# cd /opt/k8s/pods/
[root@k8s-master pods]# kubectl create -f nginx-pod.yaml
pod/nginx-pod created

檢視新建的 nginx-pod 這個 Pod 的資訊:

# 檢視 Pod 的簡略資訊
[root@k8s-master pods]# kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
nginx-pod    1/1     Running   0          3m5s # 此時 STATUS 已經是 Running,剛建立時狀態為 ContainerCreating

# 檢視 Pod 的詳細資訊
[root@k8s-master pods]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
nginx-pod    1/1     Running   0          46m   10.244.2.10   k8s-node2   <none>           <none>

[root@k8s-master pods]# kubectl describe pod nginx-pod
Name:         nginx-pod
Namespace:    default
Priority:     0
Node:         k8s-node2/192.168.1.122
Start Time:   Sun, 27 Oct 2024 09:17:02 +0800
Labels:       app=nginx-pod-app
Annotations:  <none>
Status:       Running
IP:           10.244.2.10
IPs:
  IP:  10.244.2.10
Containers:
  nginx-pod:
    Container ID:  docker://52e0bb9cd83f20ebb50988bcac9878592c049a0b1b746672a80a7786c685ea72
    Image:         nginx:latest
    Image ID:      docker-pullable://nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3
    Port:          80/TCP
    Host Port:     0/TCP
    Command:
      nginx
      -g
      daemon off;
    State:          Running
      Started:      Sun, 27 Oct 2024 09:17:03 +0800
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     200m
      memory:  256Mi
    Requests:
      cpu:     100m
      memory:  128Mi
    Environment:
      JVM_OPTS:  -Xms128m -Xmx128m
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-k7zmc (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-k7zmc:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   Burstable
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: # Pods 的事件
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  17s   default-scheduler  Successfully assigned default/nginx-pod to k8s-node2 # 分配到 k8s-node2 節點
  Normal  Pulled     17s   kubelet            Container image "nginx:latest" already present on machine
  Normal  Created    17s   kubelet            Created container nginx-pod
  Normal  Started    17s   kubelet            Started container nginx-pod
  • 最下面的 Events,描述了 Pod 的建立過程。

探針

探針:容器內應用的監測機制,根據不同的探針,可以判斷容器應用當前的狀態。

探針的型別

StartupProbe

StartupProbe啟動探針,用於檢測容器內應用程式是否已經完成啟動過程。在容器啟動階段,有些應用可能需要較長時間來完成初始化,如載入大量配置檔案、建立資料庫連線等。StartupProbe 允許這個啟動過程完成,避免在啟動階段因為 LivenessProbe 或 ReadinessProbe 檢查失敗而導致容器被錯誤地重啟。只有當 StartupProbe 成功後,LivenessProbe 和 ReadinessProbe 才會開始正常工作。

LivenessProbe

LivenessProbe存活探針,用於檢測容器是否還在正常執行狀態。如果容器在執行過程中出現故障,例如進入死迴圈、記憶體洩漏等導致應用程式無法正常工作的情況,LivenessProbe 能夠檢測到這種異常,並根據配置決定是否重啟容器。這有助於保持應用程式的健康執行,及時從故障狀態中恢復。

ReadinessProbe

ReadinessProbe就緒探針,用於判斷容器是否已經準備好接收請求。與 LivenessProbe 不同,它關注的是容器是否能夠正常處理業務流量,而不是僅僅是否存活。當容器剛啟動或者在執行過程中,由於某些原因(如正在載入配置檔案、預熱快取等)暫時無法接收請求時,ReadinessProbe 可以檢測到這種狀態,並且控制服務發現元件(如 Kubernetes 的 Service)暫時不將流量傳送到還沒準備好的容器。

探測的方式

三種探針,均支援以下三種探測方式:

  1. exec:以執行命令的方式進行監測。
  2. tcpSocket:以建立 TCP 連線的方式進行監測。
  3. httpGet:以傳送 HTTP 請求的方式進行監測。

下面以 livenessProbe 為例,給出這三種探測方式的使用說明。

ExecAction

示例:

livenessProbe:
  exec:
    command: ["ps", "-ef", "|", "grep", "myapp", "|", "grep", "-v", "grep"]
  initialDelaySeconds: 20
  periodSeconds: 8
  failureThreshold: 3

含義:表示在容器啟動 20 秒後開始,每 8 秒執行一次 "ps -ef | grep myapp | grep -v grep" 命令,檢查程序是否存在。如果連續 3 次執行這個命令的結果為程序不存在,就判定容器存活狀態檢查失敗,可能會重啟容器。

TCPSocketAction

示例:

livenessProbe:
  tcpSocket:
    port: 3306
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 2

含義:表示在容器啟動 10 秒後開始,每 5 秒檢查一次容器內 3306 埠是否可以建立 TCP 連線。如果連續 2 次檢查失敗,就判定容器存活狀態檢查失敗,可能會重啟容器。

HTTPGetAction

示例:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 15
  periodSeconds: 10
  failureThreshold: 3

含義:表示在容器啟動 15 秒後開始,每隔 10 秒向容器內 8080 埠的 /healthz 路徑傳送一個 HTTP 請求。如果連續 3 次請求都沒有得到預期的響應(如返回碼不是 200 ~ 299 之間),就認為容器存活狀態檢查失敗,可能會觸發容器重啟。

探針的引數配置

探針的通用引數配置及含義:

  • initialDelaySeconds:初始化時間。
  • timeoutSeconds:超時時間。
  • periodSeconds:監測的間隔時間。
  • sucessThreshold:監測成功多少次,才表示成功。
  • failureThreshold:監測失敗多少次,才表示失敗。

Pod 的生命週期

Pod 是 Kubernetes 中最小的可部署和可管理的計算單元,它有著完整的生命週期,主要包括以下幾個階段:

  1. Pending(掛起)階段
    • 狀態描述:當一個 Pod 被建立後,它首先會進入 Pending 狀態。在這個階段,Pod 正在等待被排程到一個合適的節點上執行。這可能是因為叢集中沒有足夠的資源(如 CPU、記憶體、儲存等)來立即啟動 Pod,或者是因為需要等待一些外部依賴(如儲存卷的準備完成)。
    • 關鍵事件:在這個階段,Kubernetes 排程器會不斷評估叢集中的節點資源情況,尋找能夠滿足 Pod 資源請求的節點。同時,系統會檢查 Pod 所依賴的各種資源是否準備就緒。
  2. Running(執行)階段
    • 狀態描述:一旦 Pod 被排程到一個節點並且其所有的容器都已經成功啟動,Pod 就會進入 Running 狀態。在這個狀態下,Pod 中的容器正在按照配置執行相應的任務。容器內的應用程式可以正常接收請求、處理資料等。
    • 關鍵事件:容器啟動過程中的初始化操作是這個階段的關鍵。例如,對於一個基於 Java 的應用容器,可能會在啟動時執行類載入、資料庫連線初始化等操作。同時,容器會開始監聽配置的埠,準備接收外部請求。
  3. Succeeded(成功完成)階段
    • 狀態描述:當 Pod 中的所有容器都正常退出,並且退出碼為 0(表示成功完成任務)時,Pod 就會進入 Succeeded 狀態。這個階段適用於那些執行一次性任務的 Pod,通常用於執行批處理任務、資料遷移任務等 Pod。
    • 關鍵事件:容器內任務的完成和正常退出是這個階段的關鍵。例如,在資料遷移的例子中,任務完成後的清理操作(如關閉資料庫連線、釋放資源等)完成後,容器才會正常退出。在這個階段,Pod 的資源會被保留,直到被手動刪除或者根據 Kubernetes 的垃圾回收策略自動清除。可以透過檢視容器的日誌來確認任務是否成功完成,以及獲取相關的執行結果。
  4. Failed(失敗)階段
    • 狀態描述:如果 Pod 中的任何一個容器以非零退出碼退出,或者容器無法啟動(例如,由於映象拉取失敗、配置錯誤、資源不足等原因),Pod 就會進入 Failed 狀態。
    • 應對措施:容器啟動失敗或者執行過程中出現錯誤導致異常退出是這個階段的關鍵。在這種情況下,需要檢視容器的日誌和相關的事件資訊來確定失敗的原因,例如透過 kubectl describe pod 命令來檢視 Pod 的詳細資訊,包括容器的啟動事件和錯誤訊息。
  5. Unknown(未知)階段
    • 狀態描述:當 Kubernetes 無法獲取 Pod 的狀態資訊時,Pod 會進入 Unknown 狀態。這可能是由於網路問題、與節點通訊中斷或者 API 伺服器出現故障等原因導致的。
    • 應對措施:需要檢查節點的狀態,嘗試恢復節點與叢集控制平面的通訊,以獲取 Pod 的準確狀態。如果節點已經不可恢復,可以考慮將 Pod 排程到其他節點上重新執行。

圖示:

image-20241104213744908

PostStart 鉤子函式

PostStart是一個容器生命週期鉤子函式,它在容器建立後、主程序啟動前被呼叫。主要用於執行一些需要在容器主程序執行之前完成的初始化任務。例如,初始化網路連線、載入配置檔案或者預熱快取等操作。這些操作對於容器主程序的正常執行可能是必需的,透過 PostStart 可以確保這些前置任務先完成。

配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx:latest
    lifecycle: # 生命週期配置
      postStart: # PostStart 鉤子函式
        exec: # 可以是 exec、tcpSocket 或者 httpGet
          command: ["/bin/sh", "-c", "echo 'PostStart hook executed'"]

執行特性:

  • 非同步執行:PostStart 鉤子函式是非同步執行的,容器主程序不會等待它完成就會啟動。這意味著它可以在後臺獨立執行。但如果 PostStart 執行時間過長或者出錯,可能會影響容器的啟動。例如,如果 PostStart 執行的命令一直無法完成,容器可能會一直處於啟動過程中。(也因為 PostStart 鉤子函式與 Pod 主容器中的 command 的先後順序難以保證,PostStart 鉤子函式一般用的比較少,如果有要求在 Pod 主容器之前執行的操作,可以放在初始化階段執行)
  • 錯誤處理與重啟策略相關:如果 PostStart 執行失敗,Kubernetes 會根據容器的重啟策略來決定是否重啟容器。若重啟策略允許,容器可能會被重新啟動以再次嘗試執行 PostStart 和主程序。

PreStop 鉤子函式

PreStop是另一個容器生命週期鉤子函式,它在容器終止之前被呼叫。主要用於執行一些清理操作,例如優雅地關閉資料庫連線、釋放資源(如檔案鎖、網路連線等)、儲存容器狀態或資料等。這有助於確保容器在停止過程中能夠有序地清理自己的資源,避免資料丟失或資源洩漏。

配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
  image: nginx:latest
  lifecycle: # 生命週期配置
    preStop: # PreStop 鉤子函式
      exec: # 可以是 exec、tcpSocket 或者 httpGet
        command: ["/bin/sh", "-c", "echo 'PreStop hook executed'; sleep 10"]

執行特性:

  • 同步執行:PreStop 鉤子函式是同步執行的,容器主程序會等待 PreStop 完成後才會完全終止。這是為了確保清理操作能夠順利完成。不過,如果 PreStop 執行的命令陷入死迴圈或者長時間無法完成,容器可能會一直處於停止過程中,直到 PreStop 執行完成或者達到 Pod 的終止寬限期(grace-period)。
  • 終止寬限期:Kubernetes 在傳送終止訊號給容器後,會等待一段時間(終止寬限期),預設是 30 秒。在這個期間內,PreStop 鉤子函式會執行。如果 PreStop 執行時間超過終止寬限期,Kubernetes 會傳送SIGKILL訊號強制終止容器主程序。但通常建議合理設定 PreStop 執行的命令,使其在終止寬限期內完成。

鉤子函式應用

將 nginx-pod.yaml 中,新增 PostStart 和 PreStop 的配置:

apiVersion: v1 # api 文件版本
kind: Pod # 資源物件型別,也可以配置為像 Deployment、StatefulSet 這一類的物件
metadata: # Pod 相關的後設資料,用於描述 Pod 的資料
  name: "nginx-pod" # Pod 的名稱
  namespace: default # 定義 Pod 的名稱空間
  labels: # 定義 Pod 的標籤
    app: "nginx-pod-app" # 標籤的 key:value,可以按實際來自定義
spec: # 規約,即期望當前 Pod 應按照下面的描述進行建立
  containers: # 對於 Pod 中的容器描述
  - name: nginx-pod # 容器的名稱
    image: "nginx:latest" # 指定容器的映象
    imagePullPolicy: IfNotPresent # 映象拉取策略,指定如果本地有就用本地的,如果沒有就拉取遠端的
    lifecycle:
      postStart:
        exec:
          command:
          - sh
          - -c
          - "echo '<h1>pre stop</h1>' > /usr/share/nginx/html/prestop.html"
      preStop:
        exec:
          command:
          - sh
          - -c
          - "sleep 50; echo 'sleep finished...' > /usr/share/nginx/html/prestop.html"
    command: # 指定容器啟動時執行的命令
    - nginx
    - -g
    - 'daemon off;' # 當前 command 配置等同於命令:nginx -g 'daemon off;'
    workingDir: /usr/share/nginx/html # 定義容器啟動後的工作目錄
    resources:
      limits: # 最多可以使用的資源
        cpu: 200m # 限制 cpu 最多使用 0.2 個核心
        memory: 256Mi # 限制記憶體最多使用 256 MB
      requests: # 最少需要使用的資源
        cpu: 100m # 限制 cpu 最少使用 0.1 個核心
        memory: 128Mi # 限制記憶體最多使用 128 MB
    ports:
    - containerPort:  80 # 描述容器內要暴露什麼埠
      name:  http # 埠名稱
      protocol: TCP # 描述該埠是基於哪種協議通訊的
    env: # 環境變數
    - name: JVM_OPTS # 環境變數名稱
      value: '-Xms128m -Xmx128m' # 環境變數的值
  restartPolicy: OnFailure # 重啟策略,只有失敗的情況才會重啟

首先,建立 Pod,檢視 PostStart 鉤子函式的執行情況:

[root@k8s-master pods]# kubectl create -f nginx-pod.yaml 
pod/nginx-pod created
[root@k8s-master pods]# kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
nginx-pod   1/1     Running   0          8s    10.244.2.12   k8s-node2   <none>           <none>
# 可以看到,PostStart 鉤子函式的命令已執行
[root@k8s-master pods]# curl 10.244.2.12/prestop.html
<h1>pre stop</h1>

然後,開啟兩個視窗,一個視窗刪除 Pod,另一個視窗監控 Pod 的變化:

# 視窗一,刪除 Pod
[root@k8s-master pods]# time kubectl delete pod nginx-pod
pod "nginx-pod" deleted

real    0m31.454s # 刪除操作實際花費時間 31.454 秒
user    0m0.049s
sys     0m0.013s
[root@k8s-master pods]# kubectl get pods -w
NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          38s
nginx-pod   1/1     Terminating   0          42s
nginx-pod   0/1     Terminating   0          73s # Pod 從開始刪除到刪除完成,時間為 31 秒
nginx-pod   0/1     Terminating   0          73s
nginx-pod   0/1     Terminating   0          73s

因為終止寬限期預設為 30s,雖然 PreStop 鉤子函式設定 sleep 50s,但是 30s 後,容器主程序被強制終止。如果將終止寬限期設定為 40s,重複上面的過程,可以發現,刪除 Pod 操作花費的時間是 40s 左右。

...
spec:
  terminationGracePeriodSeconds: 40 # 設定終止寬限期為 40s,預設的是 30s
  containers:
  ...

原文連結

https://github.com/ACatSmiling/zero-to-zero/blob/main/Operation/kubernetes.md