K8S 深入学习 (一) --- POD 篇

一、 Pod 概念

在 Kubernetes(K8s)里,Pod 是最小的可部署单元

  • 它不是单纯的一个容器,而是一个 容器组(可能有一个或多个容器)
  • 这些容器共享:
    • 网络(同一个 IP、端口空间)
    • 存储卷(可以共享数据)
  • Pod 的生命周期是短暂的(ephemeral),它是由 控制器(DeploymentStatefulSetDaemonSet 等)创建和管理的,而不是你直接长期维护的。
  • 可以把 Pod 想成一个 小房子:
    • 房子里可能有一个人(单容器)或者几个人(多容器),他们共用一个厨房(存储)和一个 Wi-Fi(网络)。
    • 房子本身(Pod)可以被拆掉重建,但人(容器)也会跟着一起走

说明:
Pod 通常不是直接创建的,而是使用工作负载资源创建的。(Deployment(部署)、 StatefulSet(有状态集)、 DaemonSet(守护进程集) 等 )

二、 Pod 特性

类别 描述
网络共享 Pod 内的所有容器共享一个网络命名空间(同 IP、同端口空间),用 localhost 就能互相通信
存储共享 可以挂载同一个 Volume,让多个容器共享读写数据
生命周期 Pod 会跟着其控制器策略进行启动、重建、终止。支持初始化容器(InitContainer)和探针(健康检查)
调度与伸缩 Pod 会被调度到集群中的某个节点上,支持副本数扩缩容和分布策略(亲和/反亲和)

2.1 网络共享

示例: 创建名为 network-demo 的 pod, 包含两个容器, app(nginx), sidecar(busybox)

  • kubectl apply -f network-demo.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: network-demo
    spec:
    containers:
    - name: app
    image: nginx
    ports:
    - containerPort: 80
    - name: sidecar
    image: busybox
    command: ["sh", "-c", "wget -qO- http://localhost:80"]

结果如下:

root@debian:~/k8s/pod# kubectl get pods
NAME READY STATUS RESTARTS AGE
network-demo 1/2 CrashLoopBackOff 6 (3m50s ago) 10m

上述结果中, READY 的状态 1/2 是正常的, 应为容器sidecar 实际上是 busybox, 在执行完 COMMAND 之后就挂了, Kubernetes 期望容器能持续运行,当容器退出时,它会认为Pod不健康,并将其重启。这就形成了 CrashLoopBackOff 循环

我们查看下容器 sidecar 最后的日志输出

  • kubectl logs network-demo -c sidecar --previous

  • --previous 标志来查看容器上一次崩溃时的日志

    root@debian:~/k8s/pod# kubectl logs network-demo -c sidecar --previous
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed a
    working. Further configuration is required.</p>

    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    root@debian:~/k8s/pod#

让我们进入容器查看下

  • kubectl exec -it network-demo -- /bin/sh

    root@debian:~/k8s/pod# kubectl exec -it network-demo
    error: you must specify at least one command for the container

当 pod 只有一个容器的时候, kubectl 会自动进入该容器, 但是 kubectl exec 不会自动进入 Pod 中唯一存活的容器。当一个 Pod 包含多个容器时,你必须显式地指定要进入的容器名称

  • kubectl exec -it network-demo -c app -- /bin/sh
  • kubectl exec -it pods/network-demo -c app -- /bin/sh

保持 sidecar 存活, 修改 sidecar 执行的命令

  • command: ["/bin/sh", "-c", "wget -qO- http://localhost && sleep infinity"]

重新发布

  • kubectl apply -f network-demo.yaml

报错如下

the Pod "network-demo" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`,`spec.initContainers[*].image`,`spec.activeDeadlineSeconds`,`spec.tolerations` (only additions to existing tolerations),`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)

解释

你正在尝试以一种不被允许的方式更新一个 Pod。Kubernetes Pod 的更新策略非常严格,因为 Pod 是最基础的调度和运行单元,许多关键配置在创建后是不可变的

Pod 更新时下面字段可以被修改:

  • spec.containers[*].image: 容器镜像
  • spec.initContainers[*].image: 初始化容器镜像
  • spec.activeDeadlineSeconds: 活跃截止秒数。
  • spec.tolerations: 容忍度(仅限于添加新的容忍度)
  • spec.terminationGracePeriodSeconds: 终止优雅期限

上述列表之外的任何其他字段,例如:

  • commandargs:容器的启动命令和参数。
  • ports:容器暴露的端口。
  • volumes:挂载的卷。
  • securityContext:安全上下文。
  • restartPolicy:重启策略。

正确做法

  • kubectl delete pod network-demo
  • kubectl apply -f your-pod.yaml