欢迎光临
我们一直在努力

K8s 控制器全解:Deployment/DaemonSet/Job/CronJob+Service 服务发现实战宝典

Kubernetes Controllers

ReplicationController

学习参考:ReplicationController

ReplicationController,简称 RC,核心能力与 ReplicaSet 基本一致。ReplicaSet是 RC 的迭代升级版本,原生支持更丰富的基于集合的标签选择算符。

本文档不再对ReplicationController做详细展开。

Deployment

学习参考:Deployment

Deployment 介绍

Deployment,简称 deploy,为Pod与ReplicaSet提供声明式应用更新能力。

ReplicaSet 仅负责保障集群中稳定运行指定数量的 Pod 实例;Deployment 则用于托管多组 ReplicaSet,并封装 Pod 滚动更新、版本回滚、扩缩容等上层运维能力。因此官方推荐直接使用 Deployment 管理 ReplicaSet,仅在需要自定义特殊更新流程时才直接操作 ReplicaSet,日常运维几乎无需单独维护 ReplicaSet 资源。

Deployment 用例

以下为 Deployment 的典型业务使用场景:

  • 创建 Deployment 以将 ReplicaSet 上线。可校验 ReplicaSet 的发布状态,确认实例是否正常就绪。
  • 修改 Deployment 内部 PodTemplateSpec 字段,声明 Pod 的新状态。系统会自动生成全新 ReplicaSet,Deployment 按照可控的速率将业务流量从旧 ReplicaSet 平滑迁移至新 ReplicaSet;每一次模板变更都会生成一条独立的 Deployment 版本记录。
  • 当 Deployment 当前运行状态异常、业务故障时,回滚到较早的 Deployment 版本。每一次版本回滚操作同样会新增一条版本修订记录。
  • 调整 Deployment 副本数量实现扩容或缩容,承载更高或降低业务负载。
  • 暂停 Deployment 的上线流程,批量完成 PodTemplateSpec 的多项配置修改后,再恢复发布流程一次性生成新版本。
  • 读取 Deployment 运行状态,判断滚动发布流程是否出现阻塞、异常停滞。
  • 自动清理历史版本中不再使用的 ReplicaSet,释放集群资源。

Deployment 管理

创建
命令行方式

root@master30 ~ 09:32:14# kubectl create deployment web –image=hub.laoma.cloud/library/nginx:1.27 –replicas=2
deployment.apps/web created
# 查看deployment创建的资源
root@master30 ~ 09:53:57# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/web-7c7f768db9-g5lsk 1/1 Running 0 41s
pod/web-7c7f768db9-lq5z4 1/1 Running 0 41s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 2/2 2 2 41s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-7c7f768db9 2 2 2 41s
3s
# 查看deployment详细信息
root@master30 ~ 09:53:59# kubectl describe deployments.apps web
Name: web
Namespace: configure
CreationTimestamp: Mon, 10 Aug 2026 09:53:18 +0800
Labels: app=web
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=web
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: hub.laoma.cloud/library/nginx:1.27
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Conditions:
Type Status Reason
—- —— ——
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-7c7f768db9 (2/2 replicas created)
Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal ScalingReplicaSet 53s deployment-controller Scaled up replica set web-7c7f768db9 to 2
# ReplicaSet与Deployment关系
root@master30 ~ 09:54:11# kubectl describe replicasets.apps web-7c7f768db9 | grep Controlled
Controlled By: Deployment/web
# 指明ReplicaSet是由Deployment/web创建的。
# pod与ReplicaSet关系
root@master30 ~ 09:55:38# kubectl describe pod web-7c7f768db9-g5lsk | grep Controlled
Controlled By: ReplicaSet/web-7c7f768db9
# 指明pod是由ReplicaSet/web-b78cbd74b创建的。

yaml 文件方式

# 获取deployment的yaml文件
root@master30 ~ 09:56:18# kubectl create deployment web –image=hub.laoma.cloud/library/nginx:1.27 –replicas=2 –dry-run=client -o yaml > deployment-web.yaml
root@master30 ~ 09:57:37# cat deployment-web.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
– image: hub.laoma.cloud/library/nginx:1.27
name: nginx
resources: {}
status: {}

格式说明:

① apiVersion,代表当前资源配置对应的 API 版本。

② kind,标识待创建的资源类型,本示例中为 Deployment。

③ metadata,存储资源元数据,其中 name 为必填字段。

④ spec,定义 Deployment 核心运行规格。

⑤ spec.replicas,指定业务 Pod 副本数量,默认值为 1。

⑥ spec.template,Pod 模板定义,是 Deployment 配置文件的核心模块。

⑦ spec.template.metadata,配置 Pod 自身元数据,至少需要定义一组标签,标签键与值可自定义。

⑧ spec.template.spec,描述 Pod 运行规格,内部定义容器各项参数,其中容器 name 与 image 为必填项。

root@master30 ~ 09:57:55# kubectl apply -f deployment-web.yaml
deployment.apps/web configured

创建方式进行比较

  • 命令行创建方式:

    • 操作简单直观,执行速度快,上手门槛低。
    • 适合临时测试、快速验证实验场景。
  • YAML 配置文件创建方式:

    • 通过配置文件清晰描述应用最终期望状态,声明式管理更贴合云原生理念。

    • 配置文件可作为部署模板,支持多环境重复复用。

    • 可纳入代码仓库版本管理,实现部署流程代码化。

    • 适用于正式生产环境、跨多集群、大规模批量部署场景。

    • 需要掌握 YAML 语法与 K8s 资源字段,存在一定学习成本。

      **kubectl apply ** 命令兼具资源创建与在线更新能力,日常运维使用十分便捷。

编辑

# 方法1:命令行直接修改
root@master30 ~ 09:58:04# kubectl edit deployments.apps
deployment.apps/web edited
# 方法2:编辑本地配置文件,再通过apply命令更新集群资源
# 方法3:专用命令快速修改,例如调整Deployment副本数量
kubectl scale deployment web –replicas=4

删除

直接删除 Deployment 资源时,系统会同步删除其托管的所有子资源(ReplicaSet、Pod)。

root@master30 ~ 09:58:23# kubectl delete deployments.apps web
deployment.apps "web" deleted

添加**–cascade=orphan**参数删除 Deployment,仅移除 Deployment 控制器,保留其管理的 ReplicaSet 与 Pod 资源。

root@master30 ~ 09:58:40# kubectl apply -f deployment-web.yaml
deployment.apps/web created
root@master30 ~ 09:58:52# kubectl delete deployments.apps web –cascade=orphan
deployment.apps "web" deleted
# 确认残留资源
root@master30 ~ 09:59:18# kubectl get all -l app=web
NAME READY STATUS RESTARTS AGE
pod/web-7c7f768db9-56slk 1/1 Running 0 43s
pod/web-7c7f768db9-v6xlq 1/1 Running 0 43s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-7c7f768db9 2 2 2 43s
# 批量清理标签匹配的所有残留资源
root@master30 ~ 09:59:35# kubectl delete all -l app=web
pod "web-7c7f768db9-56slk" deleted
pod "web-7c7f768db9-v6xlq" deleted
replicaset.apps "web-7c7f768db9" deleted
root@master30 ~ 09:59:56# kubectl get all -l app=web
No resources found in configure namespace.

水平伸缩

# 创建 deployment
root@master30 ~ 10:03:21# kubectl create deployment web –image=hub.laoma.cloud/library/nginx:1.27 –replicas=2
deployment.apps/web created
root@master30 ~ 10:04:29# kubectl scale deployment web –replicas=3
deployment.apps/web scaled
# 方式二
kubectl edit deployments.apps web
# 方式三:修改本地YAML文件后重新应用
root@master30 ~ 10:05:04# vim web.yaml
root@master30 ~ 10:05:41# kubectl get deployments.apps web -o yaml > web.yaml
root@master30 ~ 10:06:01# kubectl get pod
NAME READY STATUS RESTARTS AGE
web 1/1 Running 1 (62m ago) 2d18h
web-7c7f768db9-c86wq 1/1 Running 0 66s
web-7c7f768db9-rf5fz 1/1 Running 0 2m26s
web-7c7f768db9-sbqhb 1/1 Running 0 2m26s

健壮性测试

模拟关闭工作节点,验证 Pod 自动重建自愈能力。

root@master30 ~ 10:40:08# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-7c7f768db9-9ltgf 1/1 Running 0 14m 10.224.133.81 worker31.liu.cloud <none> <none>
web-7c7f768db9-c86wq 1/1 Running 0 35m 10.224.133.80 worker31.liu.cloud <none> <none>
web-7c7f768db9-sbqhb 1/1 Running 0 36m 10.224.133.79 worker31.liu.cloud <none> <none>
# 关闭 worker32
root@worker32 ~ 10:19:50# init 0
# 等待约5分钟,Kubernetes判定worker32节点不可用,将该节点上全部Pod标记为Unknown状态,并在其他健康节点重建Pod,维持预设副本总数为3
# 后续worker32节点恢复上线后,原Unknown状态Pod会被清除,已调度至其他节点正常运行的Pod不会自动回迁worker32。

K8s 判定节点宕机分为完整的3 个阶段:

  • 节点上的 kubelet 组件默认每 10 秒向 kube-apiserver 上报一次节点心跳状态。

  • Master 节点的controller-manager

    每5 秒轮询检查各节点心跳记录;若连续40 秒未收到某节点心跳,则标记该节点状态为NotReady。

    对应控制参数:node-monitor-period=5s、node-monitor-grace-period=40s。该组参数归属kube-controller-manager组件,该组件以静态 Pod 形式部署在 Master 节点,配置文件路径:/etc/kubernetes/manifests/kube-controller-manager.yaml

    修改方式:编辑该静态 Pod 配置文件,找到 command 配置段,新增或调整–pod-eviction-timeout参数,保存后静态 Pod 会自动重启生效。

  • 节点持续保持 NotReady 状态满 5 分钟后,集群开始驱逐该节点上所有 Pod,并调度至其他健康节点重建。

    对应参数:pod-eviction-timeout=300s。

    该参数同样隶属于 kube-controller-manager 组件,修改步骤同上。

  • 更新镜像

    # 将deployment内部容器镜像替换为 hub.laoma.cloud/library/nginx:1.28
    # 先查看容器名称
    root@master30 ~ 10:40:21# kubectl get deployments.apps -o wide
    NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
    web 3/3 3 3 37m nginx hub.laoma.cloud/library/nginx:1.27 app=web
    # 更新镜像为hub.laoma.cloud/library/nginx:1.28
    root@master30 ~ 10:41:29# kubectl set image deployment/web nginx=hub.laoma.cloud/library/nginx:1.28 –record
    # 方式二:直接编辑Deployment资源修改镜像版本
    kubectl edit deployments.apps web
    # 更新操作会生成全新ReplicaSet,用于创建新版本Pod
    root@master30 ~ 10:42:32# kubectl get rs
    NAME DESIRED CURRENT READY AGE
    web-74c65fbcdd 3 3 3 18s
    web-7c7f768db9 0 0 0 39m
    # 校验镜像版本是否更新成功
    root@master30 ~ 10:40:21# kubectl get deployments.apps -o wide
    NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
    web 3/3 3 3 37m nginx hub.laoma.cloud/library/nginx:1.27 app=web

    版本控制

    通过 kubectl rollout 系列命令管理 Deployment 多版本发布记录。

    root@master30 ~ 10:43:40# kubectl rollout -h
    Manage the rollout of one or many resources.

    Valid resource types include:
    * deployments
    * daemonsets
    * statefulsets
    Examples:
    # Rollback to the previous deployment
    kubectl rollout undo deployment/abc

    # Check the rollout status of a daemonset
    kubectl rollout status daemonset/foo

    # Restart a deployment
    kubectl rollout restart deployment/abc

    # Restart deployments with the 'app=nginx' label
    kubectl rollout restart deployment –selector=app=nginx
    Available Commands:
    history View rollout history
    pause Mark the provided resource as paused
    restart Restart a resource
    resume Resume a paused resource
    status Show the status of the rollout
    undo Undo a previous rollout
    Usage:
    kubectl rollout SUBCOMMAND [options]
    Use "kubectl rollout <command> –help" for more information about a given command.
    Use "kubectl options" for a list of global command-line options (applies to all commands).

    实操示例:

    # 再次更新镜像至 hub.laoma.cloud/library/nginx:1.28
    root@master30 ~ 10:43:49# kubectl set image deployment/web nginx=hub.laoma.cloud/library/nginx:1.28 –record
    Flag –record has been deprecated, –record will be removed in the future
    # 查看完整发布版本历史
    root@master30 ~ 10:44:57# kubectl rollout history deployment web
    deployment.apps/web
    REVISION CHANGE-CAUSE
    1 <none>
    2 kubectl set image deployment/web nginx=hub.laoma.cloud/library/nginx:1.28 –record=true
    # 回滚至第1个历史版本
    root@master30 ~ 10:46:04# kubectl rollout undo deployment web –to-revision=1
    deployment.apps/web rolled back
    root@master30 ~ 10:46:33# kubectl rollout history deployment web
    deployment.apps/web
    REVISION CHANGE-CAUSE
    2 kubectl set image deployment/web nginx=hub.laoma.cloud/library/nginx:1.28 –record=true
    3 kubectl set image deployment/web nginx=hub.laoma.cloud/library/nginx:1.29 –record=true
    4 <none>

    滚动更新

    Kubernetes 提供 maxSurge 与 maxUnavailable 两个核心参数,精细化控制滚动更新过程中 Pod 的新建、销毁速率。

    • maxSurge:控制滚动更新期间,集群总副本数超出预设 DESIRED 副本数量的最大上限。参数支持整数或百分比配置,百分比计算结果向上取整,默认值 25%。

      举例:业务预设副本数 DESIRED 为 10,最大总副本数 = 向上取整 (10 + 10 × 25%) =13,对应查询中 CURRENT 字段最大值为 13。

    • maxUnavailable:控制滚动更新期间,集群内不可用业务副本占 DESIRED 总数的最大比例。支持整数或百分比配置,百分比计算结果向下取整,默认值 25%。

      举例:业务预设副本数 DESIRED 为 10,集群最小可用副本数 = 10 – 向下取整 (10 × 25%)= 8,对应查询中 AVAILABLE 字段最低值为 8。

      参数总结:

    • maxSurge 数值越大,滚动更新初期可同时创建的新版本 Pod 数量越多。

    • maxUnavailable

      数值越大,滚动更新初期可同时销毁的旧版本 Pod 越多,更新过程中业务不可用实例数量会同步上升。

      理想场景下,完整滚动更新流程逻辑如下:

  • 批量创建 3 个新版本 Pod,此时集群运行中 Pod 总数达到上限 13。

  • 销毁 2 个旧版本 Pod,同步新建 2 个新版本 Pod;集群可用 Pod 维持 8 个。若此前新建的 3 个新 Pod 未完成就绪变为 Running,则集群内存在 5 个处于 ContainerCreating 状态的新 Pod,总副本数依旧保持上限 13。

  • 待新建 Pod 全部就绪切换至 Running 状态(示例中 5 个新 Pod 同时就绪)。

  • 集群运行 Pod 总数达到 13,此时可一次性销毁 5 个旧 Pod,同步创建 5 个新 Pod,保证集群可用副本数不低于 8。

  • 上述新建、销毁循环持续执行,直至所有旧版本 Pod 全部替换为新版本,滚动更新流程完成。

    实操监控:

    更新 Deployment 镜像,执行以下脚本持续监控 Pod 状态变化:

  • root@master30 ~ 10:46:52# vim monitor_pod_numbers

    #!/bin/bash
    while true
    do
    echo '===================' >> output.log
    kubectl get pods –no-headers |awk '{print $3}' |sort | uniq -c |sed -r 's/^ +//'>> output.log
    sleep 0.5
    done

    输出日志样例:

    ===================
    10 Running
    ===================
    5 ContainerCreating
    8 Running
    2 Terminating
    ===================
    5 ContainerCreating
    8 Running
    2 Terminating
    ===================
    5 ContainerCreating
    8 Running
    ===================
    5 ContainerCreating
    8 Running
    ===================
    3 ContainerCreating
    1 Pending
    9 Running
    4 Terminating
    ===================
    5 ContainerCreating
    8 Running
    5 Terminating
    ===================
    5 ContainerCreating
    8 Running
    5 Terminating
    ===================
    5 ContainerCreating
    8 Running
    3 Terminating
    ===================
    10 Running
    4 Terminating
    ===================
    10 Running
    2 Terminating
    ===================
    10 Running
    ===================
    10 Running
    ===================

    DaemonSet

    学习参考:DaemonSet

    DaemonSet 介绍

    DaemonSet,简写 DS,核心作用是保证集群全部或匹配筛选条件的节点上各运行一个 Pod 副本。当集群新增节点时,控制器会自动在新节点创建对应 Pod;节点从集群移除时,节点上的 DS Pod 会同步回收删除。

    DaemonSet 用例

    DaemonSet 主流业务落地场景:

    • 在集群每个节点部署存储守护进程,例如 glusterd、ceph 相关组件。
    • 在集群每个节点部署日志采集组件,例如 fluentd、logstash。
    • 在集群每个节点部署监控采集组件,例如 Prometheus Node Exporter、collectd。

    DaemonSet 用法

    简单使用场景:为每一类节点后台守护进程单独创建一套 DaemonSet,全节点统一部署。

    复杂使用场景:同一类采集 / 守护程序部署多套独立 DaemonSet;每套配置差异化启动参数,针对不同硬件节点配置独立 CPU、内存资源配额。

    DaemonSet 使用

    DaemonSet 创建

    root@master30 ~ 11:12:03# vim daemonset.yaml

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
    name: busybox
    spec:
    selector:
    matchLabels:
    app: busybox
    template:
    metadata:
    labels:
    app: busybox
    spec:
    containers:
    – name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command:
    sleep
    "36000"

    root@master30 ~ 11:28:03# kubectl apply -f daemonset.yaml

    DaemonSet 查看

    root@master30 ~ 11:28:17# kubectl get pod -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    busybox-5c8xs 1/1 Running 0 12s 10.224.218.158 worker32.liu.cloud <none> <none>
    busybox-r4f2n 1/1 Running 0 12s 10.224.133.97 worker31.liu.cloud <none> <none>
    root@master30 ~ 11:28:29# kubectl get ds
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    busybox 2 2 2 2 2 <none> 25s

    DaemonSet 调度

    # Master控制节点默认存在污点,禁止常规Pod调度
    root@master30 ~ 11:28:42# kubectl describe node master30.liu.cloud |grep Taints
    Taints: node-role.kubernetes.io/control-plane:NoSchedule
    # 移除Master节点调度限制污点,允许Pod调度至Master
    root@master30 ~ 11:29:09# kubectl taint node master30.liu.cloud node-role.kubernetes.io/control-plane-
    node/master30.liu.cloud untainted
    root@master30 ~ 11:29:53# kubectl get ds
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    busybox 3 3 3 3 3 <none> 106s
    # 重新添加Master节点禁止调度污点
    root@master30 ~ 11:30:03# kubectl taint node master30.liu.cloud node-role.kubernetes.io/control-plane:NoSchedule
    node/master30.liu.cloud tainted
    root@master30 ~ 11:30:29# kubectl get ds
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    busybox 2 2 2 2 2 <none> 2m19s
    # 集群统计Pod数量变为2个,但已调度至Master节点的busybox Pod不会自动删除,也不再计入DS统计指标。

    DaemonSet 健壮性

    # 强制删除任意一个DS管理的Pod
    root@master30 ~ 11:31:35# kubectl delete pod busybox-5c8xs –force
    Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
    pod "busybox-5c8xs" force deleted
    # 控制器会立刻新建Pod补齐节点实例
    root@master30 ~ 11:31:43# kubectl get pod -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    busybox-h5cqh 1/1 Running 0 12s 10.224.218.159 worker32.liu.cloud <none> <none>
    busybox-r4f2n 1/1 Running 0 3m38s 10.224.133.97 worker31.liu.cloud <none> <none>
    busybox-wg6h6 1/1 Running 0 2m2s 10.224.43.138 master30.liu.cloud <none> <none>

    DaemonSet 删除

    直接删除 DaemonSet 资源时,系统会同步删除其创建的全部节点 Pod;添加**–cascade=orphan**参数删除仅移除 DS 控制器,保留节点上所有 Pod 实例。

    root@master30 ~ 11:31:55# kubectl delete daemonsets.apps busybox
    daemonset.apps "busybox" deleted

    K8s 集群中 DS

    Kubernetes 集群内部系统组件普遍依托 DaemonSet 控制器部署,典型代表为 kube-proxy、calico-node。

    root@master30 ~ 11:33:14# kubectl get daemonsets.apps –namespace kube-system
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    calico-node 3 3 3 3 3 kubernetes.io/os=linux 4d20h
    kube-proxy 3 3 3 3 3 kubernetes.io/os=linux 4d21h

    calico-node 核心配置片段解析:

    kind: DaemonSet
    apiVersion: apps/v1
    metadata:
    name: calico-node
    namespace: kube-system
    labels:
    k8s-app: calico-node
    spec:
    selector:
    matchLabels:
    k8s-app: calico-node
    updateStrategy:
    type: RollingUpdate
    rollingUpdate:
    maxUnavailable: 1
    template:
    metadata:
    labels:
    k8s-app: calico-node
    annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ''
    spec:
    nodeSelector:
    kubernetes.io/os: linux
    hostNetwork: true
    containers:
    – name: calico-node
    image: hub.laoma.cloud/calico/node:v3.28.0

    完整原生配置文件内容更为复杂,本示例仅保留核心字段用于 DaemonSet 学习演示。

    生产级示例

    采集节点日志 – Fluent Bit

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
    name: fluent-bit-ds
    namespace: kube-system
    spec:
    selector:
    matchLabels:
    app: fluent-bit
    template:
    metadata:
    labels:
    app: fluent-bit
    spec:
    containers:
    – name: fluent-bit
    image: cr.fluentbit.io/fluent/fluent-bit:latest
    volumeMounts:
    – name: varlog
    mountPath: /var/log
    – name: varlibdockercontainers
    mountPath: /var/lib/docker/containers
    readOnly: true
    volumes:
    – name: varlog
    hostPath:
    path: /var/log
    – name: varlibdockercontainers
    hostPath:
    path: /var/lib/docker/containers

    采集节点监控指标 – Node Exporter

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
    name: node-exporter-ds
    namespace: monitoring
    spec:
    selector:
    matchLabels:
    app: node-exporter
    template:
    metadata:
    labels:
    app: node-exporter
    spec:
    containers:
    – name: node-exporter
    image: prom/node-exporter:latest
    ports:
    – containerPort: 9100
    volumeMounts:
    – name: proc
    mountPath: /host/proc
    readOnly: true
    – name: sys
    mountPath: /host/sys
    readOnly: true
    volumes:
    – name: proc
    hostPath:
    path: /proc
    – name: sys
    hostPath:
    path: /sys

    Job

    学习参考:Job

    Job 介绍

    • Job 控制器用于调度一次性批处理任务。
    • 若 Pod 内业务执行失败异常退出,控制器会自动创建全新 Pod 重试任务,直至容器正常退出(退出码为 0),Job 流程才算执行完成。
    • 若运行 Job Pod 的节点发生宕机故障,该 Pod 会被重新调度至其他健康节点执行。
    • 直接删除 Job 资源会级联清除其创建的所有 Pod 实例。
    • 暂停 Job 执行会立刻终止所有运行中的活跃 Pod,恢复后重新调度执行。

    Job 用例

    典型落地场景:

    • 数据库定时清理、数据批量清洗。
    • Kubernetes 集群资源备份、数据导出。

    Job 使用

    Job 基本管理

    root@master30 ~ 14:24:23# kubectl create job -h
    Create a job with the specified name.
    Examples:
    # Create a job
    kubectl create job my-job –image=busybox

    # Create a job with command
    kubectl create job my-job –image=busybox — date
    ......
    Usage:
    kubectl create job NAME –image=image [–from=cronjob/name][COMMAND]
    [args...] [options]

    示例 1:

    root@master30 ~ 14:26:29# kubectl create job myjob –image=hub.laoma.cloud/library/busybox — echo hello k8s job!
    job.batch/myjob created
    root@master30 ~ 14:26:46# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-pdrwv 0/1 Completed 0 11m
    NAME COMPLETIONS DURATION AGE
    job.batch/myjob 1/1 20s 11m
    root@master30 ~ 14:28:08# kubectl logs myjob-pdrwv
    hello k8s job!
    # 删除 Job 资源会同步清理关联所有Pod
    # 添加–cascade=orphan参数可保留已完成Pod
    root@master30 ~ 14:28:39# kubectl delete jobs.batch myjob
    job.batch "myjob" deleted

    通过 YAML 配置文件创建 Job:

    root@master30 ~ 14:28:58# vim job.yaml

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echo", "hello k8s job! "]
    restartPolicy: Never

    root@master30 ~ 14:29:25# kubectl apply -f job.yaml
    job.batch/myjob created

    示例 2: 计算圆周率并输出 200 位小数。

    root@master30 ~ 14:29:34# vim job-pi.yaml

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: pi
    spec:
    template:
    spec:
    containers:
    – name: pi
    image: hub.laoma.cloud/library/perl
    imagePullPolicy: IfNotPresent
    command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(200)"]
    restartPolicy: Never
    backoffLimit: 4

    root@master30 ~ 14:30:03# kubectl apply -f job-pi.yaml
    job.batch/pi created
    # 等待任务执行完成
    root@master30 ~ 14:30:14# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/pi-9qtzw 0/1 Completed 0 79s
    NAME COMPLETIONS DURATION AGE
    job.batch/pi Running 0/1 6s 6s
    root@master30 ~ 14:40:23# kubectl logs pi-9qtzw
    3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820

    restartPolicy

    Job 内部 Pod 重启策略仅支持两种配置:

    • Never:任务执行失败退出后,不会重启当前异常 Pod;控制器持续新建独立 Pod 重试,因此集群会产生多个失败 Pod 实例。

    • OnFailure:任务执行失败退出后,复用当前 Pod 容器反复重启重试,集群始终仅保留单个 Pod,重启次数会持续累加。

      验证实验:修改 job.yaml,将合法命令echo替换为不存在的echoxxx模拟执行失败。

    root@master30 ~ 14:40:38# vim job.yaml

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echoxxx", "hello k8s job! "]
    restartPolicy: Never

    重新应用配置观察效果:

    root@master30 ~ 14:41:03# kubectl apply -f job.yaml
    root@master30:~# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-rfvq4 0/1 StartError 0 8s
    pod/myjob-gczbz 0/1 StartError 0 2s
    pod/myjob-n4bpv 0/1 StartError 0 22s
    NAME COMPLETIONS DURATION AGE
    job.batch/myjob 0/1 33s 33s
    # 可观察到集群生成多个状态异常的Pod
    # 查看单个Pod详细事件日志
    root@master30 ~ 14:42:25# kubectl describe pod myjob-rfvq4
    ......
    Events:
    Type Reason Age From Message
    —- —— —- —- ——-
    Normal Scheduled 31s default-scheduler Successfully assigned configure/myjob-rfvq4 to worker31.liu.cloud
    Normal Pulled 31s kubelet Container image "hub.laoma.cloud/library/busybox" already present on machine
    Normal Created 31s kubelet Created container hello
    Warning Failed 31s kubelet Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "echoxxx": executable file not found in $PATH: unknown

    日志提示系统环境变量 PATH 中未找到指定可执行程序,与实验预期一致。

    现象说明: 集群中出现大量失败 Pod 的原因?

    原理解释: 首个 Pod 启动后执行命令异常退出;配置为restartPolicy: Never时,kubelet 不会重启当前 Pod,但 Job 默认要求完成 1 次成功执行,当前 COMPLETIONS 计数为 0 不满足完成条件,控制器会持续创建全新 Pod 重试。本示例中命令永久不存在,任务永远无法成功完成,集群会无限新建失败 Pod。如需终止该循环,需手动删除 Job 资源。

    清理测试 Job 资源

    root@master30 ~ 14:56:13# kubectl delete jobs.batch myjob
    job.batch "myjob" deleted

    若将 restartPolicy 调整为 OnFailure 会产生什么变化?

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echoxxxx", "hello k8s job! "]
    restartPolicy: OnFailure

    重新部署验证:

    root@master30 ~ 14:57:37# kubectl apply -f job.yaml
    job.batch/myjob created
    root@master30 ~ 14:57:54# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-xbwxh 0/1 CrashLoopBackOff 1 68s
    NAME COMPLETIONS DURATION AGE
    job.batch/myjob 0/1 68s 68s
    # Pod执行失败后仅在当前容器内反复重启。
    # 集群Pod数量始终保持1个,RESTARTS字段数值持续上涨。

    backoffLimit

    用于限制任务执行失败后的最大重试次数。

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    backoffLimit: 2
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echoxx", "hello k8s job! "]
    restartPolicy: Never

    测试效果:最多自动新建 2 次重试 Pod,达到上限后停止重试。

    root@master30 ~ 14:57:59# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-87gs2 0/1 StartError 0 8s
    pod/myjob-xp6fr 0/1 StartError 0 19s
    pod/myjob-abcde 0/1 StartError 0 83s
    NAME COMPLETIONS DURATION AGE
    job.batch/myjob 0/1 83s 83s

    completions

    通过 completions 字段指定 Job 需要成功完成多少次 Pod 执行,才算整体任务结束。

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    completions: 2
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echo", "hello k8s job! "]
    restartPolicy: Never

    上述配置含义:累计完成 2 个正常退出的 Pod 实例,Job 标记为完成状态。

    root@master30 ~ 14:58:53# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-hkghv 0/1 Completed 0 23s
    pod/myjob-mps9v 0/1 Completed 0 26s
    NAME COMPLETIONS DURATION AGE
    job.batch/myjob 2/2 12s 12s

    未手动配置 completions 时,默认取值为 1。

    parallelism

    如需同时运行多个 Pod 并行处理任务、缩短整体执行耗时,可通过 parallelism 设置并发 Pod 数量。

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: myjob
    spec:
    completions: 6
    parallelism: 2
    template:
    metadata:
    name: myjob
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["echo", "hello k8s job! "]
    restartPolicy: Never

    root@master30 ~ 15:00:13# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/myjob-9mtqx 0/1 Completed 0 4s
    pod/myjob-f4vrv 0/1 Completed 0 2s
    pod/myjob-hd6mb 0/1 Completed 0 1s
    pod/myjob-rvw4s 0/1 Completed 0 4s
    pod/myjob-rxg7c 0/1 Completed 0 8s
    pod/myjob-wr6xp 0/1 Completed 0 8s
    NAME STATUS COMPLETIONS DURATION AGE
    job.batch/myjob Running 5/6 8s 8s

    运行逻辑:同一时刻最多并发 2 个 Pod 执行,直至累计完成 6 次成功任务。

    未手动配置 parallelism 时,默认取值为 1。

    上述示例仅用于演示并发特性,业务实用价值较低;真实业务中批量数据处理、分布式任务分发场景广泛使用该配置,多个 Pod 从统一任务池读取数据并行处理,副本数量越多整体处理速度越快。

    activeDeadlineSeconds

    Job 总运行时长达到该字段设定秒数后,系统会强制终止所有正在运行的 Pod,Job 状态更新为type: Failed,失败原因为DeadlineExceeded。该时长约束作用于 Job 完整生命周期,与内部创建 Pod 数量无关。

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: pi-with-timeout
    spec:
    backoffLimit: 5
    activeDeadlineSeconds: 10
    template:
    spec:
    containers:
    – name: pi
    image: hub.laoma.cloud/library/perl
    command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
    restartPolicy: Never

    优先级规则: .spec.activeDeadlineSeconds 超时限制优先级高于 .spec.backoffLimit 最大重试次数。若 Job 持续重试失败 Pod,但整体运行时长已触达 activeDeadlineSeconds 阈值,系统会直接停止新建 Pod,即便未达到 backoffLimit 设定的重试上限。

    ttlSecondsAfterFinished

    配置 .spec.ttlSecondsAfterFinished 字段,可启用 TTL 控制器自动清理已结束(成功 / 失败)的 Job 资源。

    TTL 控制器清理 Job 时会级联删除所有关联依赖资源,包括下属 Pod 与 Job 自身。资源删除流程会遵循 Finalizers 生命周期保障机制。

    配置示例:

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: pi-with-ttl
    spec:
    ttlSecondsAfterFinished: 100
    template:
    spec:
    containers:
    – name: pi
    image: hub.laoma.cloud/library/perl
    command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
    restartPolicy: Never

    本示例中 Job 执行完成 100 秒后,会被 TTL 控制器自动回收清理。

    若字段值设为0,Job 执行结束后立即触发自动删除;若未配置该字段,TTL 控制器不会自动清理该 Job。

    该 TTL 自动清理功能当前属于 Alpha 阶段特性,集群使用前需开启TTLAfterFinished特性门控,详细说明参考官方文档TTL 控制器。

    CronJob

    学习参考:CronJob

    CronJob 介绍

    Linux 系统内置 cron 工具用于周期性定时任务,Kubernetes 中 CronJob 实现同类能力,用于按固定周期调度 Job 执行,典型场景包含定时数据备份、周期性报表生成等。

    CronJob 自动创建 Job 与下属 Pod 时,.metadata.name会作为 Pod 主机名前缀;CronJob 名称必须符合合法DNS 子域规范。为避免 Pod 主机名异常,建议严格遵循更严苛的DNS 标签命名规则。

    CronJob 控制器会在原始名称后自动追加 11 位随机字符生成 Job 名称,受限于 Job 名称总长度上限 63 字符,CronJob 自身名称长度不能超过 52 字符。

    CronJob 使用

    root@master30 ~ 15:07:44# kubectl create cronjob -h
    Create a cronjob with the specified name.
    crea
    Aliases:
    cronjob, cj
    Examples:
    # Create a cronjob
    kubectl create cronjob my-job –image=busybox –schedule="*/1 * * * *"

    # Create a cronjob with command
    kubectl create cronjob my-job –image=busybox –schedule="*/1 * * * *"date
    ......
    Usage:
    kubectl create cronjob NAME –image=image –schedule='0/5 * * * ?'
    [COMMAND] [args...] [flags] [options]

    实操示例:

    root@master30 ~ 15:09:09# kubectl create cronjob mycronjob –image=hub.laoma.cloud/library/busybox –schedule='*/2 * * * *' — echo hello k8s job!
    cronjob.batch/mycronjob created

    等效 YAML 配置文件:

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
    name: mycronjob
    spec:
    schedule: "*/2 * * * *"
    jobTemplate:
    spec:
    template:
    spec:
    containers:
    – name: hello
    image: hub.laoma.cloud/library/busybox
    command: ["echo", "hello k8s job! "]
    restartPolicy: Never

    等待数个调度周期后,集群会生成多条历史 Job 记录,默认最多保留 3 条完成 Job。

    root@master30 ~ 15:25:56# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/mycronjob-28301160-gvm2v 0/1 Completed 0 5m18s
    pod/mycronjob-28301162-25jll 0/1 Completed 0 3m18s
    pod/mycronjob-28301164-h7mf7 0/1 Completed 0 78s
    NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
    cronjob.batch/mycronjob */2 * * * * False 0 78s 36m
    NAME COMPLETIONS DURATION AGE
    job.batch/mycronjob-28301160 1/1 18s 5m18s
    job.batch/mycronjob-28301162 1/1 19s 3m18s
    job.batch/mycronjob-28301164 1/1 19s 78s

    CronJob 参数

    Cron 时间表

    .spec.schedule 为必填字段,语法完全兼容标准 Linux Cron 表达式。

    # ┌───────────── 分钟 (0 – 59)
    # │ ┌───────────── 小时 (0 – 23)
    # │ │ ┌───────────── 每月日期 (1 – 31)
    # │ │ │ ┌───────────── 月份 (1 – 12)
    # │ │ │ │ ┌───────────── 每周日期 (0 – 6)(0代表周日;部分系统兼容7代表周日)
    # │ │ │ │ │ 也可使用英文简写 sun,mon,tue,wed,thu,fri,sat
    # │ │ │ │ │
    # │ │ │ │ │
    # * * * * *

    表达式示例 0 0 13 * 5:每月 13 日零点、每周五零点执行任务。

    任务模板

    .spec.jobTemplate 用于定义 CronJob 生成 Job 的模板,为必填项。内部语法与独立 Job 资源完全一致,仅无需填写 apiVersion 与 kind 顶层字段。可在模板内自定义标签、注解等通用元数据,Job 完整配置规范参考编写 Job 规约。

    任务延迟开始的最后期限

    .spec.startingDeadlineSeconds 可选配置,用于设定错过调度时间后,任务允许延迟启动的最大秒数。

    • 超过该截止时间仍未启动的任务会直接跳过,下一次定时调度不受影响。例如每日执行两次备份,允许最大延迟 8 小时,超出时限的备份无业务意义,直接放弃本次执行,等待下一轮定时。
    • 错过截止时间的调度记录会标记为失败任务;未配置该字段时,任务无延迟时间限制。
    • 逻辑判定:到达定时点后,控制器计算当前时间与预期调度时间的差值,若差值超过该阈值则跳过本次 Job 创建。示例配置 200,代表定时触发后最多延迟 200 秒启动,超时直接放弃。
    并发性规则

    .spec.concurrencyPolicy 可选配置,定义同一 CronJob 新旧任务执行重叠时的处理策略,仅支持以下三种取值:

    • Allow(默认策略):允许多个任务并发同时运行。

    • Forbid:禁止并发执行;定时触发时若上一轮任务仍未完成,直接跳过本次调度。

    • Replace:定时触发时若存在运行中的旧任务,终止旧任务并创建全新任务替换执行。

      注意:并发规则仅约束

      同一个 CronJob

      生成的任务;集群内不同 CronJob 创建的任务天然允许并发运行。

    任务历史限制

    .spec.successfulJobsHistoryLimit 与 .spec.failedJobsHistoryLimit 为可选配置,分别控制集群保留的成功、失败历史 Job 数量。系统默认保留 3 条成功 Job、1 条失败 Job;字段值设为0代表执行完成后不保留任何历史 Job。

    如需更多自动清理 Job 的方案,参考官方文档自动清理完成的 Job。

    综合案例

    案例 1:定期清理主机目录内容

    需求:每分钟执行一次脚本,清空 worker31 节点本地/var/data目录文件。

    实现思路:

  • 清理命令:rm -fr /var/data/*
  • 固定调度至 worker31 节点运行:配置 nodeName: worker31
  • 将宿主机/var/data目录挂载至 Pod 内:使用 hostPath 存储卷
  • 周期性调度执行:采用 CronJob 控制器
  • apiVersion: batch/v1
    kind: CronJob
    metadata:
    name: clean
    spec:
    jobTemplate:
    metadata:
    name: clean
    spec:
    template:
    metadata:
    spec:
    nodeName: worker31.laoma.cloud
    containers:
    – command:
    sh
    -c
    sleep 3 && rm -fr /var/data/*
    image: hub.laoma.cloud/library/busybox
    name: clean
    volumeMounts:
    – mountPath: /var/data
    name: data
    volumes:
    – name: data
    hostPath:
    path: /var/data
    restartPolicy: OnFailure
    schedule: '* * * * *'

    案例 2:通过 cronjob 来操作 k8s 集群

    实现思路:

  • 选用内置 kubectl 工具的镜像 bitnami/kubectl。

  • 将集群管理员 kubeconfig 凭据通过配置映射挂载至 Pod,供 kubectl 鉴权访问集群。

    操作流程:

  • # 创建ConfigMap存储kubeconfig文件
    root@master30 ~ 15:30:04# kubectl create cm kubeconfig –from-file=config=/root/.kube/config
    configmap/kubeconfig created
    # 在CronJob模板中通过存储卷挂载该ConfigMap

    apiVersion: batch/v1
    kind: CronJob
    metadata:
    name: clean
    spec:
    schedule: '* * * * *'
    jobTemplate:
    metadata:
    name: clean
    spec:
    template:
    spec:
    restartPolicy: Never
    containers:
    – image: hub.laoma.cloud/kubernetes/kubectl:1.30.2
    imagePullPolicy: IfNotPresent
    name: kubectl
    args:
    – delete
    – pods
    -l
    app=hello
    -n
    – controllers
    volumeMounts:
    – name: kubeconfig
    mountPath: "/.kube"
    volumes:
    – name: kubeconfig
    configMap:
    name: kubeconfig

    hub.laoma.cloud/kubernetes/kubectl:v1.36.0 镜像基于 bitnami/kubectl 二次封装。

    bitnami/kubectl 镜像官方使用文档参考:bitnami/kubectl。

    环境清理

    root@master30 ~ 15:34:07# kubectl delete ns controllers

    Kubernetes Service

    学习参考:Service

    环境准备

    root@master30 ~ 15:39:06# kubectl create ns services
    namespace/services created
    root@master30 ~ 16:19:50# kubectl config set-context –current –namespace services
    Context "kubernetes-admin@kubernetes" modified.

    先看两个例子

    示例 1:

    root@master30 ~ 16:19:56# kubectl run web –image=hub.laoma.cloud/library/httpd –image-pull-policy=IfNotPresent -o yaml –dry-run=client > pod-web.yml
    root@master30 ~ 16:20:39# kubectl apply -f pod-web.yml
    pod/web created
    root@master30 ~ 16:20:51# kubectl get pod -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    web 1/1 Running 0 15s 10.224.218.145 worker32.liu.cloud <none> <none>
    root@master30 ~ 16:21:06# curl http://10.224.218.145
    # 删除pod
    root@master30 ~ 16:21:30# kubectl delete pod web –force
    Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
    # 重新创建可对外访问的Pod,修改配置文件如下
    root@master30 ~ 16:21:48# vim pod-web.yml

    apiVersion: v1
    kind: Pod
    metadata:
    creationTimestamp: null
    labels:
    run: web
    name: web
    spec:
    containers:
    – image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    name: web
    # 添加ports参数
    ports:
    – containerPort: 80
    hostPort: 8080

    resources: {}
    dnsPolicy: ClusterFirst
    restartPolicy: Always
    status: {}

    root@master30 ~ 16:22:23# kubectl apply -f pod-web.yml
    pod/web created
    root@master30 ~ 16:22:42# kubectl get pod -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    web 1/1 Running 0 17s 10.224.218.147 worker32.liu.cloud <none> <none>
    root@master30 ~ 16:22:59# curl http://worker32.liu.cloud:8080
    <html><body><h1>It works!</h1></body></html>
    # 结论:仅能通过Pod所在节点主机IP访问Pod,集群外部客户端必须提前知晓Pod运行在哪个节点。
    # 若通过控制器批量创建同类Pod,同一节点上会出现端口冲突问题
    # 清理 Pod 资源
    root@master30 ~ 16:25:37# kubectl delete pod web –force
    Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
    pod "web" force deleted

    示例 2:

    root@master30 ~ 16:26:45# kubectl create deployment web –image=hub.laoma.cloud/library/httpd –replicas=4 –dry-run=client -o yaml > deploy-web.yml
    root@master30 ~ 16:26:55# vim deploy-web.yml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    creationTimestamp: null
    labels:
    app: web
    name: web
    spec:
    replicas: 4
    selector:
    matchLabels:
    app: web
    strategy: {}
    template:
    metadata:
    creationTimestamp: null
    labels:
    app: web
    spec:
    containers:
    – image: hub.laoma.cloud/library/httpd
    name: httpd

    #添加imagePullPolicy
    imagePullPolicy: IfNotPresent

    #添加ports
    ports:
    – containerPort: 80
    hostPort: 8080

    resources: {}
    status: {}

    root@master30 ~ 16:27:18# kubectl apply -f deploy-web.yml
    deployment.apps/web created
    root@master30 ~ 16:27:32# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web-6f85d979d4-2v9fz 1/1 Running 0 15s
    web-6f85d979d4-7fkcq 0/1 Pending 0 15s
    web-6f85d979d4-p7zkm 1/1 Running 0 15s
    web-6f85d979d4-rh5xn 0/1 Pending 0 15s
    # 两个Pod处于挂起状态,根源是节点无空闲8080宿主机端口可用
    root@master30 ~ 16:27:47# kubectl describe pod web-6f85d979d4-7fkcq
    ......
    Events:
    Type Reason Age From Message
    —- —— —- —- ——-
    Warning FailedScheduling 49s default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't have free ports for the requested pod ports.
    Warning FailedScheduling 49s default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't have free ports for the requested pod ports.
    # 清理测试环境
    root@master30 ~ 16:28:21# kubectl delete deployments.apps web
    deployment.apps "web" deleted

    问题总结:

  • 集群外部客户端必须预先获知 Pod 所在节点主机地址,才能正常访问 Pod。
  • 若使用控制器批量调度 Pod,无法在单节点上部署多个同类 Pod,会触发宿主机端口冲突。
  • Service 介绍

    若通过 Deployment 托管应用,Deployment 会按需动态创建、销毁 Pod。任意时刻,我们都无法确定当前运行的 Pod 数量、健康状态;也无法便捷判断 Pod 是否可用。Kubernetes Pod 属于临时性资源,集群会持续调整 Pod 实例以匹配期望副本数,因此不能将单个 Pod 视作稳定可靠的访问目标。

    每个 Pod 都会分配独立 IP(由集群网络插件保障)。针对同一个 Deployment 下的应用,当前在线的 Pod 实例集合会随时发生变化。

    由此引出核心痛点:

    若一组后端 Pod 为集群内前端 Pod 提供服务,前端应用该如何持续发现、追踪后端 Pod 的 IP 地址,实现流量负载分发?

    解决方案:Service

    • 在 Kubernetes 中,Service 可将一组 Pod 上运行的网络应用封装为标准化网络服务。Service 拥有固定不变的独立 IP 与访问端口,同时内置负载均衡能力。客户端仅需访问 Service 地址,Kubernetes 会自动维护 Service 与后端 Pod 的映射关系。即便后端 Pod 扩容、缩容、重建,也不会对前端客户端造成任何影响,Service 访问入口始终保持稳定。
    • Kubernetes Service 的核心设计目标:无需改造现有业务代码,即可完成服务发现。无论是原生云应用,还是容器化迁移的传统老旧程序,都能借助 Service 实现一组 Pod 的统一网络暴露,供客户端稳定交互。

    Service 基本管理

    环境准备:创建 Deployment

    # 创建 Deployment
    root@master30 ~ 16:33:51# kubectl create deployment web –image=hub.laoma.cloud/library/httpd:2.4.58 –replicas=3
    deployment.apps/web created
    # 查看Pod并展示标签信息
    root@master30 ~ 16:34:19# kubectl get pods –show-labels
    NAME READY STATUS RESTARTS AGE LABELS
    web-d455dd6b-9c676 1/1 Running 0 6s app=web,pod-template-hash=d455dd6b
    web-d455dd6b-c2mww 1/1 Running 0 6s app=web,pod-template-hash=d455dd6b
    web-d455dd6b-jnzpr 1/1 Running 0 6s app=web,pod-template-hash=d455dd6b

    创建 Service

    root@master30 ~ 16:34:25# kubectl create service clusterip web –tcp=8080:80
    service/web created
    root@master30 ~ 16:34:39# kubectl get svc
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    web ClusterIP 10.107.184.140 <none> 8080/TCP 9s
    ## 参数–tcp=8080:80含义:访问Service集群IP的8080端口,流量将转发至后端Pod的80端口
    ## Service 默认自带标签:app=<服务名称>
    # 查看Service完整详情
    root@master30 ~ 16:34:48# kubectl describe service web
    Name: web
    Namespace: services
    Labels: app=web
    Annotations: <none>
    Selector: app=web
    Type: ClusterIP
    IP Family Policy: SingleStack
    IP Families: IPv4
    IP: 10.107.184.140
    IPs: 10.107.184.140
    Port: 8080-80 8080/TCP
    TargetPort: 80/TCP
    Endpoints: 10.224.133.113:80,10.224.133.114:80,10.224.218.159:80
    Session Affinity: None
    Events: <none>
    root@master30 ~ 16:34:52# kubectl describe service web |grep -e Endpoints -e IP:
    IP: 10.107.184.140
    Endpoints: 10.224.133.117:80,10.224.218.165:80

    # 访问验证:请求Service集群IP的8080端口
    root@master30 ~ 16:35:17# curl 10.107.184.140:8080
    <html><body><h1>It works!</h1></body></html>

    验证 Service 核心能力

    修改各 Pod 首页内容,验证负载均衡分发效果。

    # 获取所有Pod名称
    root@master30 ~ 16:35:21# kubectl get pods -o name | awk -F/ '{print $2}'
    web-d455dd6b-9c676
    web-d455dd6b-c2mww
    web-d455dd6b-jnzpr
    # 批量修改每个Pod内的首页文件
    root@master30 ~ 16:35:32# \\
    for pod in $(kubectl get pods -o name | awk -F/ '{print $2}')
    do
    kubectl exec -it $podbash -c "echo $pod > htdocs/index.html"
    done
    # 批量访问并统计流量分发次数
    root@master30 ~ 16:35:55# for i in {1..60};do curl -s 10.107.184.140:8080;done|sort |uniq -c
    18 web-d455dd6b-9c676
    16 web-d455dd6b-c2mww
    26 web-d455dd6b-jnzpr

    新建带有匹配标签的独立 Pod,Service 会自动将流量转发至该实例

    root@master30 ~ 16:36:32# kubectl run web –image=hub.laoma.cloud/library/httpd –labels=app=web
    pod/web created
    root@master30 ~ 16:36:53# for i in {1..60};do curl -s 10.107.184.140:8080;done|sort |uniq -c
    18 <html><body><h1>It works!</h1></body></html>
    14 web-d455dd6b-9c676
    15 web-d455dd6b-c2mww
    13 web-d455dd6b-jnzpr

    滚动重启 Deployment 后,Service 仍可自动感知后端 Pod 变更,正常转发流量

    root@master30 ~ 16:36:56# kubectl rollout restart deployment web
    root@master30 ~ 16:36:59# for i in {1..60};do curl -s 10.103.19.150:8080;done|sort |uniq -c

    Deployment 与 Service 可使用两套独立标签匹配规则,仅需保证 Service 选择器能匹配 Pod 标签即可。

    # 清空现有资源,重新创建Deployment与Service
    root@master30 ~ 16:37:09# kubectl delete deployments.apps web –force
    Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
    deployment.apps "web" force deleted
    root@master30 ~ 16:37:27# kubectl delete service web
    service "web" deleted
    root@master30 ~ 16:37:45# vim deploy-web.yml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    creationTimestamp: null
    labels:
    app: web
    name: web
    spec:
    replicas: 2
    selector:
    matchLabels:
    app1: web1
    strategy: {}
    template:
    metadata:
    creationTimestamp: null
    labels:
    app1: web1
    app2: web2
    spec:
    containers:
    – image: hub.laoma.cloud/library/httpd
    name: httpd
    imagePullPolicy: IfNotPresent
    resources: {}
    status: {}

    root@master30 ~ 16:38:08# kubectl apply -f deploy-web.yml
    deployment.apps/web created
    # 通过expose命令创建Service,自定义标签选择器
    root@master30 ~ 16:38:18# kubectl expose deployment web –port=8080 –target-port=80 –selector=app2=web2
    service/web exposed
    # 参数说明:
    # –port=8080:定义Service对外监听端口
    # –target-port=80:定义后端Pod内应用监听端口
    # –selector=app2=web2:定义Service筛选后端Pod的标签规则
    root@master30 ~ 16:38:28# kubectl describe svc web |grep -e IP: -e Endpoints
    IP: 10.105.141.215
    Endpoints: 10.224.133.117:80,10.224.218.165:80
    root@master30 ~ 16:38:37# curl 10.105.141.215:8080
    <html><body><h1>It works!</h1></body></html>

    无法通过 ping 命令连通 Service IP,但可以正常 ping 通 Pod IP;Service 仅针对指定业务端口配置 iptables 转发规则,不开放 ICMP 协议。

    通过 YAML 文件创建 Service

    root@master30 ~ 16:38:55# kubectl delete svc web
    service "web" deleted
    # 导出Service资源标准YAML模板
    root@master30 ~ 16:39:14# kubectl create service clusterip web –tcp=8080:80 -o yaml –dry-run=client > svc-web.yml
    root@master30 ~ 16:39:21# cat svc-web.yml

    apiVersion: v1
    kind: Service
    metadata:
    creationTimestamp: null
    labels:
    app: web
    name: web
    spec:
    ports:
    – name: 8080-80
    port: 8080
    protocol: TCP
    targetPort: 80
    selector:
    app: web
    type: ClusterIP
    status:
    loadBalancer: {}

    Service 发现

    服务发现指集群内部应用定位并访问目标 Service 的方式。

    下面介绍三种主流的集群内服务发现方案:

  • 直接通过 Service 集群 IP 访问
  • 通过 Pod 内置环境变量访问
  • 通过 DNS 域名解析访问
  • 通过 IP 访问 Service

    实验准备:mysql + wordpress 业务组合

    部署 mysql 资源

    root@master30 ~ 16:48:01# kubectl run mysql –image=hub.laoma.cloud/library/mysql \\
    –image-pull-policy=IfNotPresent \\
    –env=MYSQL_ROOT_PASSWORD=redhat \\
    –env=MYSQL_USER=tom \\
    –env=MYSQL_PASSWORD=redhat \\
    –env=MYSQL_DATABASE=blog \\
    –dry-run=client -o yaml > pod-mysql.yaml
    root@master30 ~ 16:51:08# kubectl apply -f pod-mysql.yaml
    pod/mysql created
    root@master30 ~ 16:51:30# kubectl expose pod mysql –port=3306 –target-port=3306
    service/mysql exposed
    root@master30 ~ 17:14:30# kubectl get service
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    mysql ClusterIP 10.96.50.110 <none> 3306/TCP 9s
    root@master30 ~ 17:14:39# apt install -y mysql-client
    root@master30 ~ 17:15:07# mysql -u tom -predhat -h 0.96.50.110 –ssl-mode=DISABLED -e 'show databases;'
    mysql: [Warning] Using a password on the command line interface can be insecure.
    +——————–+
    | Database |
    +——————–+
    | information_schema |
    | blog |
    +——————–+

    部署 WordPress 资源

    root@master30 ~ 17:18:00# kubectl run wordpress \\
    –image=hub.laoma.cloud/library/wordpress \\
    –image-pull-policy=IfNotPresent \\
    –env=WORDPRESS_DB_USER=tom \\
    –env=WORDPRESS_DB_PASSWORD=redhat \\
    –env=WORDPRESS_DB_NAME=blog \\
    –env=WORDPRESS_DB_HOST=10.96.50.110
    # 为方便外部测试,创建NodePort类型Service暴露WordPress
    root@master30 ~ 17:18:37# kubectl expose pod wordpress –port=80 –target-port=80 –type NodePort
    service/wordpress exposed
    root@master30 ~ 17:18:59# kubectl get service
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    mysql ClusterIP 10.96.50.110 <none> 3306/TCP 4m39s
    wordpress NodePort 10.110.158.41 <none> 80:31029/TCP 20s
    # 外部访问地址
    http://10.1.8.30:31029

    通过环境变量访问 Service

    查看 Pod 内自动注入的服务环境变量

    root@master30 ~ 17:21:01# kubectl run test –rm -it –image=hub.laoma.cloud/library/busybox –image-pull-policy=IfNotPresent sh
    If you don't see a command prompt, try pressing enter.
    / # env|grep MYSQL
    MYSQL_PORT_3306_TCP_ADDR=10.96.50.110
    MYSQL_PORT_3306_TCP_PORT=3306
    MYSQL_SERVICE_HOST=10.96.50.110
    MYSQL_PORT_3306_TCP_PROTO=tcp
    MYSQL_PORT=tcp://10.96.50.110:3306
    MYSQL_SERVICE_PORT=3306
    MYSQL_PORT_3306_TCP=tcp://10.96.50.110:3306
    / # exit
    Session ended, resume using '
    kubectl attach test -c test -i -t' command when the pod is running
    pod "test" deleted

    说明:

  • 可通过环境变量 MYSQL_SERVICE_HOST 获取 mysql 服务地址。

  • 环境变量仅在 Service 创建完成后,新建 Pod 才会自动注入。

  • Service 具备命名空间隔离特性,Pod 仅能读取同一命名空间内 Service 的环境变量。

    重新部署 WordPress,使用环境变量关联数据库

  • # 删除原有WordPress Pod,重新创建
    root@master30 ~ 17:21:06# kubectl delete pod wordpress –force
    root@master30 ~ 17:21:10# kubectl run wordpress \\
    –image=hub.laoma.cloud/library/wordpress \\
    –image-pull-policy=IfNotPresent \\
    –env=WORDPRESS_DB_USER=tom \\
    –env=WORDPRESS_DB_PASSWORD=redhat \\
    –env=WORDPRESS_DB_NAME=blog \\
    –env=WORDPRESS_DB_HOST='$(MYSQL_SERVICE_HOST)'
    # 验证Pod内数据库相关环境变量
    root@master30 ~ 17:21:17# kubectl exec -it wordpress — sh -c 'env|grep MYSQL'
    MYSQL_PORT_3306_TCP_ADDR=10.96.50.110
    MYSQL_PORT_3306_TCP_PORT=3306
    MYSQL_SERVICE_HOST=10.96.50.110
    MYSQL_PORT_3306_TCP_PROTO=tcp
    MYSQL_PORT=tcp://10.96.50.110:3306
    MYSQL_SERVICE_PORT=3306
    MYSQL_PORT_3306_TCP=tcp://10.96.50.110:3306
    # 外部访问地址
    http://10.1.8.30:31029

    通过 DNS 名称访问 Service

    Kubernetes 提供更便捷的 DNS 域名服务发现能力,使用 kubeadm 搭建集群时会默认部署 coredns 组件。

    root@master30 ~ 17:22:44# kubectl get deployments.apps –namespace=kube-system
    NAME READY UP-TO-DATE AVAILABLE AGE
    calico-kube-controllers 1/1 1 1 5d2h
    coredns 2/2 2 2 5d3h

    coredns 是集群内置 DNS 服务,每当新建 Service,coredns 会自动添加对应 DNS 解析记录。集群内 Pod 可通过 <服务名>.<命名空间> 格式访问目标 Service。

    root@master30 ~ 17:23:01:~# kubectl run busybox –rm -it –image=hub.laoma.cloud/library/busybox /bin/sh
    If you don't see a command prompt, try pressing enter.
    / # cat /etc/resolv.conf
    nameserver 10.96.50.110
    search service.svc.cluster.local svc.cluster.local cluster.local laoma.cloud
    options ndots:5
    / # wget wordpress.service:80
    Connecting to wordpress.service:80 (10.110.158.41:80)
    Connecting to wordpress.service:80 (10.110.158.41:80)
    saving to '
    index.html'
    index.html 100% |***************************************| 11607 0:00:00 ETA
    '
    index.html' saved

    当前 Pod 与 wordpress 服务处于同一命名空间,可省略命名空间后缀,直接使用服务名访问 Service。

    / # rm index.html
    / # wget wordpress:80
    Connecting to wordpress:80 (10.110.158.41:80)
    Connecting to wordpress:80 (10.110.158.41:80)
    saving to 'index.html'
    index.html 100% |***************************************| 11571 0:00:00 ETA
    'index.html' saved

    10.96.0.10 即为集群 DNS 服务地址,可通过如下命令查看:

    root@master30 ~ 17:24:27# kubectl get service –namespace kube-system
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 5d3h

    沿用上述 WordPress 业务示例,使用 DNS 域名配置数据库连接:

    # 删除原有WordPress Pod,重新创建
    root@master30 ~ 17:24:30# kubectl delete pod wordpress –force
    Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
    pod "wordpress" force deleted
    root@master30 ~ 17:25:09# kubectl run wordpress \\
    –image=hub.laoma.cloud/library/wordpress \\
    –image-pull-policy=IfNotPresent \\
    –env=WORDPRESS_DB_USER=tom \\
    –env=WORDPRESS_DB_PASSWORD=redhat \\
    –env=WORDPRESS_DB_NAME=blog \\
    –env=WORDPRESS_DB_HOST=mysql
    pod/wordpress created
    # 外部访问地址
    http://10.1.8.30:31029
    # 清理全部测试资源
    root@master30 ~ 17:25:23# kubectl delete svc mysql wordpress
    service "mysql" deleted
    service "wordpress" deleted
    root@master30 ~ 17:26:12# kubectl delete pod mysql wordpress
    pod "mysql" deleted
    pod "wordpress" deleted

    赞(0)
    未经允许不得转载:171主机测评 » K8s 控制器全解:Deployment/DaemonSet/Job/CronJob+Service 服务发现实战宝典
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址