Pod pod 探针 k8s基础-Pod入门与实战 十八岁 2024-12-22 2025-11-02
1.创建pod 使用 kubectl run 命令创建一个pod:
1 2 3 4 5 6 7 8 # 基本命令格式 kubectl run <pod-name> --image=<image-name> [options] # 示例: kubectl run nginx-pod --image=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 # nginx-pod 是创建pod的名字,所在命名空间唯一 # --image=nginx:1.24.0默认从dockerhub拉取镜像,现在已经无法拉取 # --image=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0指定地址拉取
利用命令快速导出一个yaml:
1 kubectl run nginx-pod --image=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine --dry-run=client -oyaml >nginx-pod.yaml
通过yaml文件定义pod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 cat nginx-pod.yaml apiVersion: v1 kind: Pod metadata: labels: run: nginx-pod name: nginx-pod spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx ports: - containerPort: 80 protocol: TCP name: http - containerPort: 443 protocol: TCP name: https
通过yaml创建pod:
1 kubectl create -f pod.yaml
查看创建的pod:
1 2 3 [root@k8s-master01 10-pod]# kubectl get po NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 63s
2.一个pod多个容器 通过yaml文件定义一个pod中多个容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 cat pod.yaml apiVersion: v1 kind: Pod metadata: labels: run: nginx-redis name: nginx-redis-pod spec: containers: - name: nginx image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 ports: - containerPort: 80 protocol: TCP name: http - containerPort: 443 protocol: TCP name: https - name: redis image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/redis:5.0.14 ports: - containerPort: 6379 protocol: TCP name: redis
创建上述pod:
1 kubectl create -f pod.yaml
查看创建的pod:
1 2 3 4 [root@k8s-master01 10-pod]# kubectl get po NAME READY STATUS RESTARTS AGE nginx-redis-pod 2/2 Running 0 25s # READY 字段中的 2/2 表示: 2/2 = 就绪容器数/总容器数,表示该pod中一共有两个容器,就绪容器数量也是2
查看pod中容器的日志:
如果pod中只有一个容器,直接使用kubectl logs -f [pod的名字]
如果pod中有多个容器,那么就要使用-c指定查看的容器:kubectl logs -f pods/nginx-redis-pod -c nginx kubectl logs -f pods/nginx-redis-pod -c redis;-c参数中的nginx和redis是pod配置中pod.spec.containers.name中定义的容器名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [root@k8s-master01 10-pod]# kubectl logs -f pods/nginx-redis-pod -c nginx /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2025/10/23 12:50:00 [notice] 1#1: using the "epoll" event method 2025/10/23 12:50:00 [notice] 1#1: nginx/1.24.0 2025/10/23 12:50:00 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 2025/10/23 12:50:00 [notice] 1#1: OS: Linux 5.14.0-503.15.1.el9_5.x86_64 2025/10/23 12:50:00 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1073741816:1073741816 2025/10/23 12:50:00 [notice] 1#1: start worker processes 2025/10/23 12:50:00 [notice] 1#1: start worker process 30 2025/10/23 12:50:00 [notice] 1#1: start worker process 31 ^C [root@k8s-master01 10-pod]# kubectl logs -f pods/nginx-redis-pod -c redis 1:C 23 Oct 2025 12:50:12.303 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 1:C 23 Oct 2025 12:50:12.303 # Redis version=5.0.14, bits=64, commit=00000000, modified=0, pid=1, just started 1:C 23 Oct 2025 12:50:12.303 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf 1:M 23 Oct 2025 12:50:12.305 * Running mode=standalone, port=6379. 1:M 23 Oct 2025 12:50:12.305 # Server initialized 1:M 23 Oct 2025 12:50:12.305 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. 1:M 23 Oct 2025 12:50:12.307 * Ready to accept connections
小技巧:(使用kubectl explain pod 可以查看pod都可以使用哪些参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 [root@k8s-master01 10-pod]# kubectl explain pod KIND: Pod VERSION: v1 DESCRIPTION: Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts. FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds metadata <ObjectMeta> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata spec <PodSpec> Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status status <PodStatus> Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status # 一层一层的往下查看都有哪些参数可以配置,例如: kubectl explain pod.spec.containers
查看pod状态,默认查看的是default命名空间下的pod,如果要查看其他命名空间下的pod加-n参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@k8s-master01 10-pod]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-68fb4dc4d4-6cnj9 1/1 Running 1 (9h ago) 31h nginx-68fb4dc4d4-9c67f 1/1 Running 8 (9h ago) 67d nginx-68fb4dc4d4-n8wwl 1/1 Running 1 (9h ago) 31h nginx-deployment-7b778c4d44-5nmfm 1/1 Running 13 (9h ago) 90d nginx-deployment-7b778c4d44-sk42r 1/1 Running 13 (9h ago) 90d nginx-redis-pod 2/2 Running 0 25m rabbitmq-6f8f9b4d4f-c2q5l 1/1 Running 8 (9h ago) 67d redis-679fcfb58-wtd89 1/1 Running 1 (9h ago) 31h redis-cli-57cc5fd584-6ndnb 1/1 Running 29 (9h ago) 177d redis-master-0 1/1 Running 33 (9h ago) 184d test-nginx-7c589fc9f6-pn8nc 1/1 Running 21 (9h ago) 130d test-nginx-7c589fc9f6-wbv9k 1/1 Running 21 (9h ago) 130d
查看kube-system命名空间下的pod需要通过-n参数来指定命名空间:
1 2 3 4 5 6 7 8 9 10 11 12 [root@k8s-master01 10-pod]# kubectl get po -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-7d67d4b9c7-78t8t 1/1 Running 56 312d calico-node-7wmww 1/1 Running 56 (9h ago) 312d calico-node-88nrk 1/1 Running 54 (9h ago) 312d calico-node-cmkbl 1/1 Running 54 (99m ago) 312d calico-node-ft6c4 1/1 Running 54 (9h ago) 312d calico-node-lxjwd 1/1 Running 55 (9h ago) 312d calico-node-zn86s 1/1 Running 54 (9h ago) 312d coredns-6fbc9bdf46-dlrxh 1/1 Running 8 (9h ago) 67d coredns-6fbc9bdf46-g59vh 1/1 Running 1 (9h ago) 31h metrics-server-6c79fcf899-9vll2 1/1 Running 1 (9h ago) 31h
获取pod的更多信息使用-o wide参数:
1 2 3 4 5 kubectl get pod -owide # get表示获取某个资源 # pod表示获取的资源是pod # -o(或--output)用于指定命令的输出格式 # wide 这是-o参数的一个可选值,表示以宽格式输出。
删除pod:
通过yaml文件删除:kubectl delete -f pod.yaml
通过pod名字删除:kubectl delete pod nginx-redis-pod , nginx-redis-pod是指定要删除pod的名字。
3.pod自定义容器的启动命令和参数 在 Kubernetes 中,command 和 args 是用来覆盖容器镜像中的默认命令和参数的。它们都可以在 spec.containers 字段下定义,分别用于设置容器启动时执行的命令和传递给该命令的参数。
command :覆盖容器镜像的 ENTRYPOINT
args :覆盖容器镜像的 CMD
与 Dockerfile 的对应关系:
Dockerfile
Kubernetes
说明
ENTRYPOINT
command
主命令
CMD
args
命令参数
1 2 3 4 5 6 command: 覆盖容器镜像中的默认命令。它可以是一个单独的命令(如 /bin/bash)或一个完整的命令路径(如 /usr/bin/env) 如果未指定,容器将使用镜像中的默认入口点(ENTRYPOINT)。如果指定了 command,它会覆盖默认的 ENTRYPOINT。 args: 传递给 command 的参数。 如果未指定,容器将使用镜像中的默认参数(CMD)。如果指定了 args,它会覆盖默认的 CMD。
1 2 3 4 5 6 7 8 9 10 11 12 [root@k8s-master01 pra]# cat pod.yaml apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run command: ["sleep","10"] #覆盖容器ENTRYPOINT启动命令,可选参数
4.为容器分配cpu和内存 在 Kubernetes(简称 K8s)中,Pod 是最小的可部署单元,通常包含一个或多个容器。资源分配是指为 Pod 中的容器指定 CPU、内存等资源的请求(requests)和限制(limits)。这有助于 Kubernetes 调度器合理分配节点资源,避免资源争用,并确保应用稳定运行。如果一个pod中有多个容器,那么需要针对每个容器进行分配的。
4.1为什么需要分配资源?
调度优化 :Kubernetes 根据容器的资源请求(requests)决定将 Pod 调度到哪个节点。如果节点资源不足,Pod 可能无法启动。
资源隔离 :通过限制(limits),防止单个容器消耗过多资源,导致其他容器或节点崩溃。
QoS(服务质量) :根据 requests 和 limits 的配置,Pod 被分为 Guaranteed、Burstable 或 BestEffort 三类 QoS 级别,影响优先级和驱逐策略。
Guaranteed:requests = limits,所有资源均设置。
Burstable:requests < limits 或部分设置。
BestEffort:无 requests 和 limits。
如果不分配资源,容器可能被视为 BestEffort,在资源紧张时容易被驱逐。
4.2.资源类型 Kubernetes 支持的主要资源:
CPU :单位为“核”(cores),如 1 表示 1 个 CPU 核,0.5 表示半核。也可以用毫核(millicores),如 500m = 0.5 核。
内存 :单位为字节,如 Mi(兆字节)、Gi(吉字节),例如 512Mi 或 1Gi。
其他 :如 GPU(nvidia.com/gpu)、临时存储(ephemeral-storage)等,但最常见的是 CPU 和内存。
4.3为容器分配资源 资源配置在 Pod 的 YAML 文件中,位于容器的 spec.containers[].resources 字段下。分为:
requests :容器启动时保证的最小资源。如果节点无法满足,Pod 不会调度。
limits :容器可使用的最大资源上限。如果超过,CPU 会节流,内存可能导致 OOM(Out of Memory)杀死容器。
示例 YAML 配置(一个简单的 Nginx Pod):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:latest resources: requests: memory: "128Mi" cpu: "500m" limits: memory: "256Mi" cpu: "1"
注意:在为容器分配cpu和内存时,requests中配置的memory和cpu的值不能大于节点的总容量,limits中配置的memory和cpu可以超过节点的总容量。同时配置的requests不能大于limits 。
4.4pod调度不成功 使用 free -m 查看节点内存使用情况,明明节点上的内存和cpu资源是够的,但是在创建pod时却无法调度到该节点,describe查看pod信息提示资源不够,出现这种情况的原因是pod是否能成功调度并不是由free -m 所显示的内存来决定的。详细解释如下:
为了让一个配置了 requests 的 Pod 成功调度到耨个节点,必须关注节点的剩余可用资源 。
Kubernetes 调度器会执行一个非常简单的计算:
1 [节点的可分配资源 (Allocatable)]` - `[节点上已分配的请求 (Allocated resources - Requests)]` >= `[新 Pod 的请求 (Pod's requests)]
查看节点的资源使用情况:kubectl describe nodes k8s-node02
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 [root@k8s-master01 10-pod]# kubectl describe nodes k8s-node02 Name: k8s-node02 Roles: <none> Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/os=linux ingress=true kubernetes.io/arch=amd64 kubernetes.io/hostname=k8s-node02 kubernetes.io/os=linux node.kubernetes.io/node= Annotations: node.alpha.kubernetes.io/ttl: 0 projectcalico.org/IPv4Address: 192.168.0.85/24 projectcalico.org/IPv4IPIPTunnelAddr: 172.16.58.192 volumes.kubernetes.io/controller-managed-attach-detach: true CreationTimestamp: Sat, 14 Dec 2024 21:15:58 +0800 Taints: <none> Unschedulable: false Lease: HolderIdentity: k8s-node02 AcquireTime: <unset> RenewTime: Fri, 24 Oct 2025 14:21:17 +0800 Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- NetworkUnavailable False Fri, 24 Oct 2025 11:17:59 +0800 Fri, 24 Oct 2025 11:17:59 +0800 CalicoIsUp Calico is running on this node MemoryPressure False Fri, 24 Oct 2025 14:21:25 +0800 Wed, 22 Oct 2025 14:21:33 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Fri, 24 Oct 2025 14:21:25 +0800 Wed, 22 Oct 2025 14:21:33 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure PIDPressure False Fri, 24 Oct 2025 14:21:25 +0800 Wed, 22 Oct 2025 14:21:33 +0800 KubeletHasSufficientPID kubelet has sufficient PID available Ready True Fri, 24 Oct 2025 14:21:25 +0800 Wed, 22 Oct 2025 14:21:33 +0800 KubeletReady kubelet is posting ready status Addresses: InternalIP: 192.168.0.85 Hostname: k8s-node02 Capacity: #表示节点的总资源 cpu: 2 ephemeral-storage: 101308Mi hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7835728Ki pods: 110 Allocatable: #表示节点可分配的资源,这是这个节点真正能用来分配给 Pod 的资源总量。它不等于 Capacity (总容量),因为 Capacity 中有一部分资源被 Kubernetes 系统组件(如 kubelet)和操作系统本身预留了。 cpu: 2 ephemeral-storage: 95606223509 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7733328Ki pods: 110 System Info: Machine ID: fe7f9ee8ad6f4e929dbbdfa31836b572 System UUID: 15204d56-ebfb-e466-0fa8-a448673bb632 Boot ID: cbd57ca5-5485-4d7d-9282-0a0c80fc84d8 Kernel Version: 5.14.0-503.15.1.el9_5.x86_64 OS Image: Rocky Linux 9.5 (Blue Onyx) Operating System: linux Architecture: amd64 Container Runtime Version: containerd://1.7.24 Kubelet Version: v1.31.4 Kube-Proxy Version: v1.31.4 PodCIDR: 172.16.3.0/24 PodCIDRs: 172.16.3.0/24 Non-terminated Pods: (4 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age --------- ---- ------------ ---------- --------------- ------------- --- default nginx-pod 1 (50%) 0 (0%) 1Gi (13%) 0 (0%) 39s ingress-nginx ingress-nginx-controller-hst99 100m (5%) 0 (0%) 90Mi (1%) 0 (0%) 142d kube-system calico-node-ft6c4 250m (12%) 0 (0%) 0 (0%) 0 (0%) 313d monitoring node-exporter-z8xsm 112m (5%) 270m (13%) 200Mi (2%) 220Mi (2%) 32d Allocated resources: #已经分配的配置,这是k8s-node02节点上所有Pod的 Requests 总和。调度器就是看这个值来计算剩余资源的。 (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 1462m (73%) 270m (13%) memory 1314Mi (17%) 220Mi (2%) ephemeral-storage 0 (0%) 0 (0%) hugepages-1Gi 0 (0%) 0 (0%) hugepages-2Mi 0 (0%) 0 (0%) Events: <none>
来算一下 k8s-node02 节点当前还剩下 多少资源可供分配:
剩余 CPU:
可分配 (Allocatable): 2 (即 2000m)
已请求 (Requests): 1462m
剩余 CPU = 2000m - 1462m = 538m
剩余内存:
可分配 (Allocatable): 7733328Ki (约 7552Mi)
已请求 (Requests): 1314Mi
剩余内存 ≈ 7552Mi - 1314Mi = 6238Mi
结论:
新 Pod,其所有容器的 requests 资源总和 必须 小于或等于 538m CPU 和 6238Mi 内存 ,才有可能 被调度到 k8s-node02 节点上。
最后一点: 还应该看一下 Taints (污点)。这个节点是 <none> (没有污点),所以它对所有 Pod 开放。如果这里有污点,你的 Pod 还
必须有相应的 Tolerations (容忍) 才能被调度上来。
5.为pod配置环境变量 在 Kubernetes Pod 中为容器配置环境变量是非常核心的一个操作。主要有五种方式,下面会结合实际案例逐一讲解:
**直接定义 (Key-Value)**:最简单的方式,直接在 Pod 定义中写入。
**引用 ConfigMap (单个 Key)**:从 ConfigMap 中提取一个特定的 Key 作为环境变量。
**引用 Secret (单个 Key)**:从 Secret 中提取一个特定的 Key(如密码)。
**批量引用 (envFrom)**:把整个 ConfigMap 或 Secret 导入为环境变量。
**引用 Pod 自身信息 (Downward API)**:把 Pod 的 IP、名称等元数据注入为环境变量。
5.1直接定义环境变量 (env) 这是最基础的方式,直接在 Pod 的 spec.containers[].env 字段中指定键值对。适用于静态配置,不涉及敏感数据或动态注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@k8s-master01 10 -pod ] apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx-env name: nginx-env spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-env env: - name: APP_MODE value: "prod" resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
创建pod并验证容器中环境变量:
1 2 3 4 5 6 7 8 9 10 # 创建pod kubectl create -f env-pod.yaml # 验证环境变量,两种验证方式:一种是进入到pod中,另一种不进入pod,无论哪种验证方式APP_MODE输出的值都是yaml中定义的prod值 [root@k8s-master01 10-pod]# kubectl exec -ti nginx-env -- bash root@nginx-env:/# echo $APP_MODE prod [root@k8s-master01 10-pod]# kubectl exec nginx-env -- printenv APP_MODE prod
5.2引用 Pod 自身字段(fieldRef) 有时候,应用程序需要知道它自己运行时的信息,比如它自己的 IP 地址、它所在的命名空间或它自己的名字。
使用场景 :
服务注册 :应用启动时需要告诉注册中心(如 Nacos、Consul)自己的 IP 地址。
监控 :应用需要将自己的 Pod 名称作为标签附加到监控数据上。
集群感知 :应用需要知道自己在哪个 Namespace。
案例 :将 Pod 的名称、IP 和命名空间注入为环境变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [root@k8s-master01 10 -pod ] apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx-env name: nginx-env spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-env env: - name: APP_MODE value: "prod" - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
创建pod并验证容器中环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 创建pod kubectl create -f env-pod.yaml # 验证环境变量,两种验证方式:一种是进入到pod中,另一种不进入pod [root@k8s-master01 10-pod]# kubectl exec -ti nginx-env -- bash root@nginx-env:/# echo $POD_NAME $POD_NAMESPACE $POD_IP nginx-env default 172.16.58.241 [root@k8s-master01 10-pod]# kubectl exec nginx-env -- printenv POD_NAME POD_NAMESPACE POD_IP nginx-env default 172.16.58.241 # 查看pod的IP [root@k8s-master01 10-pod]# kubectl get po -owide|grep nginx-env nginx-env 1/1 Running 0 2m23s 172.16.58.241 k8s-node02 <none> <none>
常用的内置字段:
1 2 3 4 5 6 7 8 9 10 11 metadata.name metadata.namespace metadata.uid metadata.labels['key'] metadata.annotations['key'] spec.nodeName spec.serviceAccountName status.hostIP status.hostIPs status.podIP status.podIPs
常用的内置字段中metadata.labels['key'] 和 metadata.annotations['key'] 用法相同,这里只演示metadata.labels[xxx]的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 labels: app: web-ui version: v1 env: prod run: nginx-pod cat nginx-pod.yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: app: web-ui version: v1 env: prod run: nginx-pod name: nginx-pod spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine name: nginx-pod env: - name: ENV valueFrom: fieldRef: fieldPath: metadata.labels['env'] dnsPolicy: ClusterFirst restartPolicy: Always status: {}
创建pod并验证容器中环境变量:
1 2 3 4 5 6 # 创建pod kubectl create -f nginx-pod.yaml # 验证容器中环境变量,ENV是否等于prod [root@k8s-master01 10-pod]# kubectl exec nginx-pod -- printenv|grep ENV ENV=prod
5.3从 ConfigMap 加载环境变量 用于加载外部配置项(例如数据库地址、服务 URL 等)。 ConfigMap 可以集中管理配置,多个 Pod 可复用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: ConfigMap metadata: name: app-config data: APP_MODE: "prod" APP_PORT: "8080" API_URL: "https://api.example.com" DB_HOST: "mysql-prod.default.svc.cluster.local" DB_NAME: "mydatabase" kubectl apply -f app-config.yaml
方式一:从ConfigMap 逐个引用键值:
从 app-config 这个 ConfigMap 中,只取出 DB_HOST 的值,并将其注入到容器中。
使用场景 :你只需要 ConfigMap 中的某几个特定配置项,或者你需要重命名 环境变量(例如 ConfigMap 中的 Key 叫 DB_HOST,但容器内需要叫 DATABASE_HOSTNAME)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: v1 kind: Pod metadata: name: env-cm-demo spec: containers: - name: my-app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 env: - name: DATABASE_HOSTNAME valueFrom: configMapKeyRef: name: app-config key: DB_HOST
创建pod并验证容器中环境变量:
1 2 3 4 5 6 # 创建pod [root@k8s-master01 10-pod]# kubectl create -f cm-env.yaml # 验证容器中的环境变量DATABASE_HOSTNAME是否等于mysql-prod.default.svc.cluster.local [root@k8s-master01 10-pod]# kubectl exec env-cm-demo -- printenv DATABASE_HOSTNAME mysql-prod.default.svc.cluster.local #可以看到环境变量设置成功
方式二:批量导入ConfigMap所有键值
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Pod metadata: name: env-cm-demo spec: containers: - name: my-app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 envFrom: - configMapRef: name: app-config
创建pod并验证容器中环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 # 创建pod [root@k8s-master01 10-pod]# kubectl create -f cm-env.yaml # 验证容器中的环境变量, 这样 ConfigMap 中的所有 key 都会自动变成环境变量 [root@k8s-master01 10-pod]# kubectl exec -ti env-cm-demo -- bash root@env-cm-demo:/# env|grep -E '^(APP_MODE|APP_PORT|API_URL|DB_HOST|DB_NAME)=' API_URL=https://api.example.com #可以看到环境变量就是ConfigMap中定义的key和value DB_HOST=mysql-prod.default.svc.cluster.local APP_MODE=prod DB_NAME=mydatabase APP_PORT=8080
5.4从 Secret 加载环境变量(用于敏感信息) 从Secret 加载环境变量和5.3中从ConfigMap加载环境变量几乎一样,只是把 configMapKeyRef 换成了 secretKeyRef。
使用场景 :必须 用于注入密码、API 密钥、Token 等敏感信息。
定义一个 Secret (mysql-secret) 这个 Secret 存储了数据库的用户和密码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque stringData: DB_USER: "root" DB_PASSWORD: "S!p3rS3cretPa$$w0rd" kubectl apply -f mysql-secret.yaml
有图pod从Secret 加载环境变量和5.3中从ConfigMap加载环境变量几乎一样,只是把 configMapKeyRef 换成了 secretKeyRef,所以这里就不验证了,配置示例如下:
方式一:从 Secret 逐个引用键值示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: v1 kind: Pod metadata: name: env-cm-demo spec: containers: - name: my-app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 env: - name: DATABASE_USER valueFrom: secretKeyRef: name: mysql-secret key: DB_USER
方式二:批量导入 Secret 所有键值示例:
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Pod metadata: name: env-cm-demo spec: containers: - name: my-app image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 envFrom: - secretRef: name: mysql-secret
5.5pod中混合使用多种方式 配置示例参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Pod metadata: name: env-demo spec: containers: - name: nginx image: nginx:latest envFrom: - configMapRef: name: app-config - secretRef: name: mysql-secret env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: CUSTOM_MESSAGE value: "Hello from mixed env"
6.Pod镜像拉取策略 通过 spec.containers[].imagePullPolicy 参数可以指定镜像的拉取策略,目前支持的策略如下:
操作方式
说明
Always
总是拉取,当镜像 tag 为 latest 时,且 imagePullPolicy 未配置,默认为 Always
IfNotPresent
镜像不存在时拉取镜像,如果 tag 为非 latest,且 imagePullPolicy 未配置,默认为 IfNotPresent
Never
不管是否存在都不会拉取
指定镜像的拉取策略为Always
1 2 3 4 5 6 7 8 9 10 11 12 vim pod.yaml apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run imagePullPolicy: Always
验证当tag不是latest是,不配置imagePullPolicy,默认是IfNotPresent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@k8s-master01 pra ] apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx spec: containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run [root@k8s-master01 pra ] pod/nginx created 查看pod的yaml文件的imagePullPolicy是否为Always [root@k8s-master01 pra ] imagePullPolicy: IfNotPresent
案例:为什么节点有镜像还是提示镜像下载失败?
现象: 为什么节点上明明有镜像,还是会去下载镜像,并且还下载失败了。
情况一: 当 Kubernetes 使用 Docker 作为 Runtime 时,如果集群节点无法从外网拉取镜像,即使在 master01 节点上通过 docker load 导入了镜像,Pod 在调度到其他节点上时仍会尝试从网上下载镜像。 因此,镜像必须在 所有可调度 Pod 的节点上 都进行导入(docker load),才能保证 Pod 创建时不再报错或尝试下载镜像。
情况二: 当 Kubernetes 使用 Containerd 作为 Runtime 时,如果节点无法从外网拉取镜像,不能使用 docker load 导入镜像,而应使用 **nerdctl load**。 因为 Docker 与 Containerd 的镜像存储目录和管理机制不互通 ,两者导入的镜像互相不可见。
情况三: 即使使用 nerdctl load 并在每个节点都导入了镜像,仍可能出现找不到镜像的情况。原因是 Containerd 存在命名空间隔离机制 ,导入镜像时需要 指定正确的命名空间(如 --namespace k8s.io) ,否则 Kubernetes 无法识别该镜像。
例如:在 Kubernetes 使用 Containerd 作为 Runtime 的环境中,即使在 Kubernetes 里创建的 Pod 属于自定义命名空间(例如 prod),Containerd 实际使用的命名空间仍然是固定的:k8s.io。
也就是说:无论你的 Pod 在 Kubernetes 的哪个命名空间(default、prod、dev 等), Containerd 都会在 k8s.io 命名空间下查找镜像。
因此,如果你要手动导入镜像,正确的做法是:
1 nerdctl --namespace k8s.io load -i your-image.tar
Kubernetes 在所有命名空间(如 prod、dev、default)中创建的 Pod,其底层 Containerd 镜像都统一存放在 k8s.io 命名空间中。因此,手动导入镜像时应始终使用 --namespace k8s.io。
情况四: 在 Kubernetes 使用 Containerd 作为 Runtime 的环境中,即使使用 nerdctl --namespace k8s.io load 将镜像导入到所有节点,仍可能出现 Pod 创建时提示下载镜像或找不到镜像的情况。原因在 Pod 的 YAML 配置中,imagePullPolicy 被设置为 Always。当 imagePullPolicy: Always 时,Kubernetes 会 强制从镜像仓库重新拉取镜像 ,而不会使用本地已存在的镜像。 解决方法 :将镜像策略改为 IfNotPresent 或 Never。
7.Pod重启策略 在 Kubernetes 中,Pod 的重启策略(Restart Policy)定义了当容器崩溃或退出时,Kubernetes 如何处理该 Pod 中的容器。Pod 的重启策略可以帮助确保容器在运行期间的高可用性和稳定性。
可以使用 spec.restartPolicy 指定容器的重启策略
操作方式
说明
Always
默认策略。无论容器退出的原因是什么,都会重启容器。对于大多数控制器(如 Deployment、ReplicaSet),默认使用 Always。
OnFailure
仅当容器以非零状态码退出时才 重启。
Never
当容器无论以任何状态退出时,都不会重启。
指定pod的重启策略为Always
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx-run spec: restartPolicy: Always containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run ports: - containerPort: 80 - image: redis:6.0.0 name: redis
指定pod的重启策略为OnFailure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx-run spec: restartPolicy: OnFailure containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run ports: - containerPort: 80 - image: redis:6.0.0 name: redis
指定pod的重启策略为Never
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx-run spec: restartPolicy: Never containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.24.0 name: nginx-run ports: - containerPort: 80 - image: redis:6.0.0 name: redis
8.Pod生命周期 8.1pod启动过程 pod启动过程技术总结 (含探针):
Pending (待处理)
API Server 收到请求后将pod信息写入etcd 。
kube-scheduler (调度器) 寻找合适的 Node。
Scheduler 将 nodeName 写入 etcd,完成“绑定”。
ContainerCreating (容器创建中)
目标 Node 上的 kubelet 监测到 Pod。
kubelet 开始准备:拉取镜像 (Pulling)、配置网络 (CNI)、挂载卷 (Volumes)等。
Init (初始化)
kubelet 检查 initContainers。
按顺序 启动并运行 Init 容器。
所有 Init 容器必须成功退出 (exit code 0)。探针(Probes)不适用于 Init 容器 。
Running (运行中)
所有 Init 容器成功后,kubelet 并行启动 所有主容器 (containers),如果有多个容器会同时启动。
容器进程启动后,Pod 状态变为 Running。
kubelet 开始执行三种探针(如果已配置):
Startup Probe (启动探针) :
首先 被执行。
在它成功之前,Liveness 和 Readiness 探针都不会 启动。
如果它失败达到 failureThreshold 次,kubelet 会重启容器 。
一旦成功,它就功成身退,不再运行。
Liveness Probe (存活探针) :
在 Startup Probe 成功后(或在 initialDelaySeconds 后,如果无 Startup 探针)开始执行。
在容器的整个生命周期内定期运行。
如果失败达到 failureThreshold 次,kubelet 会重启容器 。
Readiness Probe (就绪探针) :
与 Liveness 探针并行 启动(也是在 Startup Probe 成功后或 initialDelaySeconds 后)。
在容器的整个生命周期内定期运行。
如果失败,kubelet 会将 Pod 的 Ready 状态设为 False。它不会重启容器 。
Ready (就绪)
当 Startup Probe(如果存在)和 Readiness Probe 都首次成功时,kubelet 将 Pod 的 Ready 状态设置为 True。
Service 对应的 Endpoint 会包含此 Pod 的 IP。
K8s 开始向该 Pod 转发流量。
关键点梳理:
Startup Probe (启动探针): 只在启动时运行一次 。它是“启动期”的保护者,防止启动慢的应用被误杀。它会“暂停”另两个探针。
Liveness Probe (存活探针): 贯穿整个生命周期 。检查“是否僵死”。失败 = 重启容器 。
Readiness Probe (就绪探针): 贯穿整个生命周期 。检查“是否能接客”。失败 = 停止流量 (不重启)。
8.2pod退出过程 退出过程技术总结
用户删除 Pod :kubectl delete pod ...
API Server 更新状态 :Pod 对象在 etcd 中被标记为 Terminating 状态,并记录 deletionTimestamp。
Endpoint 移除 :EndpointController 监听到 Pod 状态变化,将其从 Service 的 Endpoint 列表中移除。新的网络流量停止 。
Kubelet 响应 :节点上的 kubelet 监听到 Pod 变为 Terminating。
preStop 钩子执行 :kubelet 首先 执行 Pod 中定义的 preStop 钩子。
SIGTERM 信号 :preStop 钩子执行完毕后,kubelet 向容器内的主进程 (PID 1) 发送 SIGTERM 信号,要求其优雅关闭。
**等待优雅关闭 (Grace Period)**:
kubelet 开始等待,最长时间为 Pod 定义的 terminationGracePeriodSeconds(默认为 30 秒)。
如果容器在此期间内自行退出 (理想情况),kubelet 立即进入步骤 9。
SIGKILL 信号 :
如果优雅关闭期限已到 ,但容器进程仍在运行。
kubelet 会(通过 CRI)向容器发送 SIGKILL 信号 ,强制杀死进程。
资源清理 :容器进程退出后,kubelet 清理该 Pod 占用的所有资源(如网络、存储卷等)。
API Server 删除对象 :kubelet 通知 API Server Pod 已被成功删除。API Server 最终从 etcd 中移除该 Pod 对象。
关键点梳理:
第一步是断流 :K8s 首先确保新流量 不再进入即将死亡的 Pod,这是通过将其从 Service 的 Endpoint 移除来实现的。
preStop 优先 :preStop 钩子在 SIGTERM 信号之前执行,用于执行“必须完成”的收尾工作。
**SIGTERM vs SIGKILL**:
SIGTERM:是“通知 ”,允许应用优雅关闭(比如保存数据)。
SIGKILL:是“强杀 ”,应用无法捕获,强制终止,可能导致数据丢失。
terminationGracePeriodSeconds:这是从 preStop 开始到 SIGKILL 发生的 总时限 。如果你的 preStop 任务要执行 10 秒,那么你的应用就只剩下 20 秒(假设总时限30秒)来响应 SIGTERM 并退出。
9.Pod的三种探针 在 Kubernetes 中,探针(Probes)用于检测 Pod 中容器的健康状态和可用性。探针有三种类型:存活探针(Liveness Probe)、就绪探针(Readiness Probe)和启动探针(Startup Probe)。这些探针可以帮助 Kubernetes 自动恢复不健康的容器,并在应用启动或准备就绪时将流量引导到健康的实例。
健康检查是针对容器进行的,所以配置在spec.containers中的
三种探针类型:
Liveness Probe(存活探针) :检测容器是否处于健康状态。如果存活探针失败,Kubernetes 会重启该容器。
Readiness Probe(就绪探针) :检测容器是否准备好接受流量。如果就绪探针失败,Kubernetes 会将该容器从服务的负载均衡器中移除。
Startup Probe(启动探针) :检测容器是否已经成功启动。如果配置了启动探针,存活探针会被禁用,直到启动探针成功为止。适用于启动时间较长的应用。
种类
说明
startupProbe(只启动一次,适用于启动较慢的程序)
Kubernetes1.16 新加的探测方式,用于判断容器内的应用程序是否已经启动。如果配置了 startupProbe,就会先禁用其他两种探测,直到它成功为止。 如果探测失败,Kubelet会杀死容器,之后根据重启策略进行处理,如果探测成功,或没有配置 startupProbe,则状态为成功,之后就不再探测。
livenessProbe(循环探测)
用于探测容器是否在运行,如果探测失败,kubelet 会“杀死”容器并根据重启策略进行相应的处理。如果未指定该探针,将默认为 Success。(该策略会触发pod重启)
readinessProbe(循环探测)
一般用于探测容器内的程序是否健康,即判断容器是否为就绪(Ready)状态 。如果是,则可以处理请求,反之Endpoints Controller将从所有的 Service 的 Endpoints中删除此容器所在 Pod 的 IP 地址。如果未指定,将默认为 Success;失败 = 停止流量 (不会重启pod )
不配置健康检查的影响: 如果pod没有配置任何健康检查,同时程序启动的又非常慢,此时pod会很快设置为就绪(Ready)状态,当pod状态为Ready时表示可以正常接收流量了,但是由于程序启动慢,实际上程序还没有启动完成是没法处理分发过来的流量,这样用户体验很不友好,生产环境中不应出现这种情况,下面是案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 cat slow-pod.yaml apiVersion: v1 kind: Pod metadata: name: slow-pod labels: app: slow spec: containers: - name: slow-container image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/slow:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8080 name: http [root@k8s-master01 10 -pod ] pod/slow-pod created [root@k8s-master01 10 -pod ] NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES slow-pod 1 /1 Running 0 22s 172.16 .58 .247 k8s-node02 <none> <none> [root@k8s-master01 10 -pod ] Starting... Start initializing basic data... [root@k8s-master01 ~ ] curl: (7) Failed to connect to 172.16.195.51 port 8080: Connection refused
结论:当一个程序启动很慢,又没有健康检查,容器创建完状态会立马变为Running状态,此时就会为该容器分配流量,但是由于程序实际没有成功启动,所以无法处理流量,就会拒绝服务
9.1探针的四种检测方式 每种探针只能配置一种检测方式,根据情况在exec、tcpSocket、httpGet、grpc中四选一进行配置,暂时不支持配置多种探测方式。
探测方式
说明
exec
在容器内执行一个指定的命令,如果命令执行成功,则返回值是 0,就认为容器健康(返回值是否为0 根据echo $?判断)
tcpSocket(程序可能存在假死状态)
通过 TCP 连接检查容器指定的端口,如果端口开放,则认为容器健康(适用数据库、Redis、gRPC 等)
httpGet(最可靠,但是需要开发提供一个接口)
适用Web 应用、REST 接口,对指定的 URL 进行 Get 请求,如果状态码在 200~400 之间,则认为容器健康,(该方式需要开发在程序提供一个接口)
grpc
GRPC协议的健康检查,如果响应的状态是”SERVING”,则认为容器健康。(K8s v1.24+)
9.2liveness Probe(存活探针)和readinessProbe(就绪探针) 创建一个有健康检查的pod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 cat slow-pod.yaml apiVersion: v1 kind: Pod metadata: name: slow-pod labels: app: slow spec: containers: - name: slow-container image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/slow:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8080 name: http readinessProbe: httpGet: path: /index.html port: 80 scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 2 failureThreshold: 2 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 2
创建并查看pod状态:
1 2 3 4 [root@k8s-master01 10-pod]# kubectl create -f slow-pod.yaml [root@k8s-master01 10-pod]# kubectl get po NAME READY STATUS RESTARTS AGE slow-pod 0/1 Running 6 (99s ago) 4m19s
通过 describe po 查看pod的事件:
1 2 3 4 5 6 7 8 9 10 11 [root@k8s-master01 10-pod]# kubectl describe po slow-pod Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m7s default-scheduler Successfully assigned default/slow-pod to k8s-node01 Normal Killing 87s (x2 over 107s) kubelet Container slow-container failed liveness probe, will be restarted Normal Pulled 86s (x3 over 2m6s) kubelet Container image "registry.cn-beijing.aliyuncs.com/k8s-liujunwei/slow:latest" already present on machine Normal Created 86s (x3 over 2m6s) kubelet Created container slow-container Normal Started 86s (x3 over 2m6s) kubelet Started container slow-container Warning Unhealthy 67s (x8 over 112s) kubelet Readiness probe failed: Get "http://172.16.85.220:80/index.html": dial tcp 172.16.85.220:80: connect: connection refused Warning Unhealthy 67s (x6 over 112s) kubelet Liveness probe failed: dial tcp 172.16.85.220:8080: connect: connection refused
pod状态看到:pod的STATUS(状态)字段是Running,但是READY字段是0/1,RESTARTS字段为6;
describe pod看到事件中提示Liveness probe 失败了,原因是程序中的端口是8080,没有/index.html路径,readinessProbe中配置错误;Readiness probe失败原因是由于程序启动很慢,探测时间参数配置不合理导致探测不成功,pod一致重启。
总结:livenessProbe当探测失败后会根据容器的重启策略对容器进行重启,readinessProbe当探测失败时不会对容器进行重启,只是该pod服务不可用,service不会将流量分发给该pod。如果程序启动很慢要使用startupProbe探针进行探测
生产案例:
程序里定义了一个健康检查接口(例如 /healthz), 但为了防止外部随便访问这个接口(比如黑客探测、扫描器、监控误触发等), 程序要求所有访问 /healthz 的请求必须带上一个特定的 HTTP 请求头 (header)。
Kubernetes 的探针配置中通过 httpHeaders: 字段带上这个 header, 这样只有探针能访问成功,而其他人由于不知道我们的请求头,所以就会被拒绝。这就是典型的 “受保护的健康检查” 模式。
应用程序(Spring Boot)端配置示例:
1 2 3 4 5 6 7 8 9 10 11 @GetMapping("/healthz") public ResponseEntity<String> health (@RequestHeader(value = "X-Auth", required = false) String token) { if (!"SecretToken123" .equals(token)) { return ResponseEntity.status(403 ).body("Forbidden" ); } return ResponseEntity.ok("OK" ); } #说明: #程序只接受带有请求头 X-Auth: SecretToken123 的访问; #其他请求一律返回 403 。
pod的健康检查就要配置请求头,示例如下:
1 2 3 4 5 6 7 8 9 readinessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: X-Auth value: SecretToken123 initialDelaySeconds: 5 periodSeconds: 10
这样:
kubelet 在探测时会自动带上正确的 header;
探针可以访问成功;
其他任何人(比如访问 http://<PodIP>:8080/healthz)没有带头部,访问会被拒绝。
9.3startupProbe(启动探针) 通过startupProbe 探针解决程序启动的影响(程序启动慢要从程序上解决)
下面的配置是:当一个程序启动很慢,通过startupProbe进行探测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 cat slow-pod.yaml apiVersion: v1 kind: Pod metadata: name: slow-pod labels: app: slow spec: restartPolicy: Always containers: - name: slow-container image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/slow:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8080 name: http startupProbe: tcpSocket: port: 8080 initialDelaySeconds: 20 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 20 readinessProbe: httpGet: path: /ping port: 8080 scheme: HTTP initialDelaySeconds: 3 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 2 failureThreshold: 2 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 3 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 2
创建该pod:
1 [root@k8s-master01 10-pod]# kubectl create -f slow-pod.yaml
查看pod状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 状态正常,可以处理流量 [root@k8s-master01 10-pod]# kubectl get pod NAME READY STATUS RESTARTS AGE slow-pod 1/1 Running 0 2m10s # 通过 describe po 查看pod的事件,readinessProbe和livenessProbe探测成功信息不会显示在Events,Events只显示异常信息 [root@k8s-master01 10-pod]# kubectl describe po slow-pod Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 12m default-scheduler Successfully assigned default/slow-pod to k8s-node02 Normal Pulled 12m kubelet Container image "registry.cn-beijing.aliyuncs.com/k8s-liujunwei/slow:latest" already present on machine Normal Created 12m kubelet Created container slow-container Normal Started 12m kubelet Started container slow-container Warning Unhealthy 11m (x4 over 12m) kubelet Startup probe failed: dial tcp 172.16.58.255:8080: connect: connection refused
补充知识点:进入容器内部
1 2 3 4 5 6 7 8 9 # 如果想进入容器的 shell 以便进行交互式操作,可以使用以下命令: kubectl exec -it <pod-name> -c <container-name> -- /bin/sh # -it:表示以交互模式运行,-i 表示交互模式,-t 表示分配一个伪终端。 # <pod-name>:指定 Pod 的名称。 # -c <container-name>:指定容器的名称(如果 Pod 中有多个容器)。 # -- /bin/sh:指定要执行的命令。在大多数容器中,/bin/sh 是可用的 shell,如果容器使用的是其他 shell(如 bash),你可以相应地替换它。 # 案例:如果你有一个名为 slow-pod 的 Pod,容器名称为 slow-container,并且想进入 bash 环境(如果容器中安装了 bash),可以使用: [root@k8s-master01 pra]# kubectl exec -ti slow-pod -c slow-container -- /bin/sh
总结:当使用的kubernetes版本>1.16,程序启动时间超过30,要配置startupProbe,而不是用livenessProbe(存活探针)和readinessProbe配置等待时间。
10.容器生命周期-postStart和preStop 在 Kubernetes 中,preStop 和 postStart 是容器生命周期钩子,用于在容器启动和终止时执行特定的操作。这些钩子可以帮助你在容器生命周期的关键时刻执行一些重要的任务,从而确保应用程序的平滑运行和关闭。
preStop和postStart都支持exec、httpGet、tcpSocket三种配置方式。需要注意的是这三种配置方式需要容器中有相关的命令。
创建postStart和preStop的pod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 apiVersion: v1 kind: Pod metadata: labels: run: nginx-run name: nginx spec: restartPolicy: Always containers: - image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine name: nginx-run ports: - containerPort: 80 lifecycle: postStart: exec: command: - sh - -c - mkdir /data/postStart -p preStop: exec: command: - sh - -c - sleep 20 startupProbe: tcpSocket: port: 80 initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 2 readinessProbe: httpGet: path: /index.html port: 80 scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 2 livenessProbe: httpGet: path: /index.html port: 80 scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 successThreshold: 1 failureThreshold: 2
创建pod:
1 [root@k8s-master01 pra]# kubectl create -f pod.yaml
进入容器内部检查/data/postStart是否被创建:
1 2 3 4 5 6 7 8 [root@k8s-master01 pra]# kubectl exec -ti nginx -c nginx-run -- /bin/sh / # ls -l /data/ total 0 drwxr-xr-x 2 root root 6 Jul 13 07:04 postStart # nginx是pod的名字 # -c 指定要进入容器的名字,这里要进入的容器是nginx-run # /data/postStart目录已经存在
删除pod:
1 2 3 4 [root@k8s-master01 pra]# kubectl delete -f pod.yaml pod "nginx" deleted # 删除该pod的时候前根据preStop的策略执行,比如案例中的sleep 20表示在删除该pod前等待20秒在进行删除操作
10.1preStop 钩子
10.2postStart 钩子
作用 :在容器启动后立即执行,通常用于初始化操作。
触发时机 :容器启动后,postStart 钩子会与主进程并行执行。
典型场景 :
向注册中心注册服务实例。
加载配置文件或初始化数据库连接。
检查依赖服务是否可用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 apiVersion: v1 kind: Pod metadata: name: java-service spec: containers: - name: java-app image: my-java-app:latest env: - name: SERVICE_NAME value: "user-service" #user-service 是“服务级别”的名字,由程序逻辑决定,不是k8s资源的名字 - name: SERVICE_PORT value: "8080" #8080程序运行的端口 - name: REGISTRY_URL # value: "http://registry:8500" #是注册中心的地址 lifecycle: postStart: exec: command: - /bin/sh - -c - | # 1. 等待主进程启动 until curl -f http://localhost:8080/actuator/health; do echo "Waiting for app to be ready..." sleep 1 done # 注册到服务中心 curl -X POST ${REGISTRY_URL}/register \ -d "service=${SERVICE_NAME}&port=${SERVICE_PORT}" || true
完整案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 apiVersion: apps/v1 kind: Deployment metadata: name: user-service labels: app: user-service spec: replicas: 2 selector: matchLabels: app: user-service template: metadata: labels: app: user-service spec: terminationGracePeriodSeconds: 40 containers: - name: user-service image: user-service:latest env: - name: SERVICE_NAME value: "user-service" - name: SERVICE_PORT value: "8080" - name: REGISTRY_URL value: "http://registry:8500" lifecycle: postStart: exec: command: - "/bin/sh" - "-c" - | # 等待应用真正就绪 until curl -f http://localhost:8080/actuator/health; do echo "Waiting for app to be ready..." sleep 1 done # 注册到服务中心 curl -X POST ${REGISTRY_URL}/register \ -d "service=${SERVICE_NAME}&port=${SERVICE_PORT}" || true preStop: exec: command: - "/bin/sh" - "-c" - | echo "[$(date)] Starting graceful shutdown..." curl -X DELETE ${REGISTRY_URL}/deregister?service=${SERVICE_NAME} || true sleep 5 curl -X POST http://localhost:8080/actuator/shutdown || true sleep 2 echo "[$(date)] Graceful shutdown completed" livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10
11.宽限期terminationGracePeriodSeconds 使用宽限期真正实现服务优雅平滑退出。
terminationGracePeriodSeconds 是 Kubernetes 优雅停机机制(Graceful Shutdown) 的核心参数之一, 在生产环境中控制着 Pod 在被删除或重启时的“优雅退出时间窗口” ,指 Pod 从接收到终止信号到被强制杀死之间的宽限期 (单位:秒)
在 Pod 的规范(spec)中:
1 2 spec: terminationGracePeriodSeconds: 30
含义:
当 Pod 被删除、升级、缩容或节点重启时,Kubernetes 会给容器一个“宽限期”(grace period), 在这段时间里允许应用优雅地完成收尾工作 (比如关闭连接、保存状态、注销注册中心等)。
简单理解:它是“Pod 死之前的缓冲时间 ”。
执行流程(时序图):
假设 terminationGracePeriodSeconds: 30:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 kubectl delete pod myapp-pod ↓ 1️⃣ Kubelet 发送 SIGTERM 给容器内主进程(PID 1) ↓ 2️⃣ 如果配置了 preStop: → 执行 preStop 脚本或 HTTP 请求 ↓ 3️⃣ 应用收到 SIGTERM,开始优雅关闭(停止接收新请求、完成未完成任务、注销注册中心) ↓ 4️⃣ 等待最多 30 秒 ↓ 5️⃣ 如果应用没退出: → Kubelet 发送 SIGKILL(强制杀死容器) ↓ 6️⃣ Pod 状态变为 Terminated
在什么场景使用?
如果程序的退出清理工作比较耗时,超过了默认时间(如 30 秒),就可以通过调高这个参数(如 50 秒),来给程序充足的时间完成退出,避免被强制“杀死”。
11.gRPC探测(1.24版本就默认开启) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@k8s-master01 pra]# cat grpc-pod.yaml apiVersion: v1 kind: Pod metadata: name: etcd-with-grpc spec: containers: - name: etcd image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/etcd:3.5.14 command: [ "/opt/bitnami/etcd/bin/etcd", "--data-dir", "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"] ports: - containerPort: 2379 livenessProbe: grpc: #配置grpc健康检查 port: 2379 initialDelaySeconds: 10 #10秒后开始执行健康检查 volumeMounts: - name: etcd-data mountPath: /var/lib/etcd # 将 emptyDir 挂载到容器内的 /var/lib/etcd 目录 volumes: - name: etcd-data emptyDir: {} # 使用 emptyDir 类型的卷,生命周期与 Pod 相同
pod启动成功后查看日志会看到请求健康检查的日志:
1 2 3 4 5 [root@k8s-master01 pra]# kubectl logs -f etcd-with-grpc # 以下是日志输出 {"level":"debug","ts":"2024-07-13T09:13:34.414727Z","caller":"v3rpc/interceptor.go:182","msg":"request stats","start time":"2024-07-13T09:13:34.414699Z","time spent":"12.948µs","remote":"192.168.0.203:55386","response type":"/grpc.health.v1.Health/Check","request count":-1,"request size":-1,"response count":-1,"response size":-1,"request content":""} {"level":"info","ts":"2024-07-13T09:13:34.415292Z","caller":"zapgrpc/zapgrpc.go:174","msg":"[transport] [server-transport 0xc000956000] Closing: EOF"} {"level":"info","ts":"2024-07-13T09:13:34.415466Z","caller":"zapgrpc/zapgrpc.go:174","msg":"[transport] [server-transport 0xc000956000] loopyWriter exiting with error: connection error: desc = \"transport is closing\""}