Kubernetes(K8s)笔记Day04:控制器(ReplicaSet 与Deployment),滚动更新及回滚,滚动更新策略,Pod 的 DNS 策略

一、控制器概述

什么是控制器

控制器是 Kubernetes 中用于管理 Pod 的中间层,能够监测 Pod 运行状况,当 Pod 发生故障时可以自动恢复 Pod。

控制器的主要功能:

功能 说明
故障恢复 Pod 发生故障时,控制器会尝试重启 Pod 或里面的容器
自动补全 Pod 副本数量低于期望值时,自动创建新的 Pod 副本
自动终止 Pod 副本数量多余期望值时,自动终止多余的 Pod 资源
重新编排 如果一直重启有问题,控制器会基于某种策略进行重新布派或重新编排

控制器的核心目标是:确保每一个 Pod 资源始终处于我们所定义或者我们所期望的目标状态。

二、ReplicaSet 控制器

2.1 概念与原理

ReplicaSet(简称 RS) 是 Kubernetes 中的一种副本控制器,主要作用是控制由其管理的 Pod,使 Pod 副本的数量始终维持在预设的个数

核心功能:

  • 保证一定数量的 Pod 能够在集群中正常运行
  • 持续监听 Pod 的运行状态
  • Pod 发生故障时重启 Pod
  • Pod 数量减少时重新运行新的 Pod 副本

官方推荐: 不要直接使用 ReplicaSet,而是用 Deployment 取而代之。Deployment 是比 ReplkcaSet 更高级的概念,它会管理 ReplicaSet 并提供很多其它有用的特性(如声明式更新、历史版本保留等)。

Deployment 与 ReplicaSet 的关系:

复制代码
Deployment --- 管理 → ReplicaSet --- 管理 → Pod

Deployment 控制器不直接管理 Pod 对象,而是由 Deployment 管理 ReplicaSet,再由 ReplicaSet 负责管理 Pod 对象。

2.2 ReplicaSet 的三个组成部分

组成部分 说明
期望副本数 定义由这个控制器管控的 Pod 副本有几个
标签选择器 选定哪些 Pod 是自己管理的
Pod 资源模板 如果集群中现存的 Pod 数量不够,基于模板新建 Pod

2.3 ReplicaSet 使用案例

编写 ReplicaSet 资源清单
bash 复制代码
[root@hd1 ~]# vim replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet  # 声明资源类型为 ReplicaSet(副本控制器)
metadata:
  name: frontend  # ReplicaSet 控制器的名称(在命名空间内唯一)
  labels:
    app: guestbook
    tier: frontend
spec:
  replicas: 3  # 期望运行的 Pod 副本数量(始终维持 3 个),可动态调整
  selector:   # 标签选择器,用于确定哪些 Pod 归该 ReplicaSet 管理
    matchLabels:
      tier: frontend   # 只管理带有 tier=frontend 标签的 Pod(必须是精准匹配)
  template:      # Pod 模板
    metadata:
      labels:  # 给 Pod 打标签(确认能被 selector 选中)
        tier: frontend
    spec:   #定义容器的规格
      containers:   
      - name: php-redis
        image: docker.io/library/nginx:latest
        imagePullPolicy: IfNotPresent

注意:.spec.selector 中定义的标签选择器必须能够匹配到 spec.template.metadata.labels 里定义的 Pod 标签,否则会报错

应用并查看
bash 复制代码
# 应用 YAML 文件
[root@hd1 ~]# kubectl apply -f replicaset.yaml
replicaset.apps/frontend created

# 查看 ReplicaSet
[root@hd1 ~]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   3         3         3       53m

# 查看 Pod(Pod 名称由"控制器名-随机数"组成)
[root@hd1 ~]# kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
frontend-4hzpp   1/1     Running   0          4s
frontend-8jd4l   1/1     Running   0          4s
frontend-h47cc   1/1     Running   0          4s

#随机删除一个pod
[root@hd1 ~]# kubectl delete pod frontend-h47cc
pod "frontend-h47cc" deleted
#再次查看,发现rs自动补了一个新的pod
[root@hd1 ~]# kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
frontend-4hzpp   1/1     Running   0          29s
frontend-8jd4l   1/1     Running   0          29s
frontend-jm6v6   1/1     Running   0          3s
资源清单详细说明
yaml 复制代码
apiVersion: apps/v1              # ReplicaSet 属于的核心群组
kind: ReplicaSet                 # 创建的资源类型
metadata:
  name: frontend                 # 控制器的名字
  labels:
    app: guestbook
    tier: frontend
spec:                            #控制器规格
  replicas: 3                    # 管理的 Pod 副本数量
  selector:
    matchLabels:
      tier: frontend             # 管理带有 tier=frontend 标签的 Pod
  template:                      # 定义 Pod 的模板
    metadata:
      labels:
        tier: frontend           # Pod 标签(必须与 selector 匹配)
    spec:                        #pod的规格
      containers:
      - name: php-redis
        image: docker.io/library/nginx:latest
        ports:
        - name: http  #端口名字
          containerPort: 80  

两个 spec 字段的区别:

  • 第一个 spec:声明 ReplicaSet 的副本数、标签选择器、Pod 模板
  • 第二个 specspec.template.spec):Pod 里的容器属性等配置

2.4 ReplicaSet 管理 Pod:扩容

ReplicaSet最核心的功能之一就是可以动态扩容和回缩,只需要修改配置文件中的replicas值即可

bash 复制代码
# 修改 YAML 文件中的 replicas 值
[root@hd1 ~]# vim replicaset.yaml

spec:
  replicas: 4    #这里改成4

# 修改完直接重新应用才能生效,不需要事先删除之前的pod
[root@hd1 ~]# kubectl apply -f replicaset.yaml
replicaset.apps/frontend configured

# 查看扩容结果
[root@hd1 ~]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   4         4         4       62m

[root@hd1 ~]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-82p9b   1/1     Running   0          62m
frontend-j6twz   1/1     Running   0          62m
frontend-kzjm7   1/1     Running   0          33s
frontend-lcnq6   1/1     Running   0          62m

也可以直接编辑控制器实现扩容:

k8s内置编辑器:kubectl edit <资源类型> <资源名>

这个命令可以修改线上资源的配置,不依赖本地yaml文件。但日常不建议常用,依旧建议使用yaml文件apply的方式进行验证

bash 复制代码
# 实时修改(请求提交给 API Server)
[root@hd1 ~]# kubectl edit rs frontend
# 修改 spec.replicas 的值

这个编译器的使用方法和vim基本一致,并且扩容之后立即生效,并且是实时生效的

此外,当你不小心删掉了原配置文件,这个命令也可以当作当作"应急查看器",可以快速调出配置进行查看

2.5 ReplicaSet 实现动态缩容

同样的,缩容也只需要修改replicas的值即可

bash 复制代码
# 修改 replicas 值
[root@hd1 ~]# vim replicaset.yaml

spec:
  replicas: 2

[root@hd1 ~]# kubectl apply -f replicaset.yaml
replicaset.apps/frontend configured

[root@hd1 ~]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   2         2         2       70m

[root@hd1 ~]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-j6twz   1/1     Running   0          70m
frontend-lcnq6   1/1     Running   0          70m

2.6 ReplicaSet 实现 Pod 升级(v1 → v2)

kubectl edit <资源类型> <资源名>:快速修改资源配置,立即生效

bash 复制代码
[root@hd1 ~]# kubectl edit rs frontend
# 修改镜像:image: tomcat:8.5-jre8-alpine

[root@hd1 ~]# kubectl get rs -o wide
NAME       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                                     SELECTOR
frontend   2         2         2       7h24m   php-redis    docker.io/library/tomcat:8.5-jre8-alpine   tier=frontend

问题: 虽然镜像已经更新,但原有的 Pod 仍然使用旧镜像,新创建的 Pod 才会使用新镜像。需要将老 Pod 全部删除才能完成升级,非常不便。

bash 复制代码
#查看正在运行的pod的完整状态和配置
[root@hd1 ~]# kubectl get pod frontend-jm6v6 -o yaml | grep image
  - image: docker.io/library/nginx:latest

可以发现,当前运行中的pod镜像依旧是旧的镜像

解决方案: 使用 Deployment 控制器来实现更方便的滚动升级。

ReplicaSet 的局限性:

  • 更新镜像后需要手动删除 Pod 才能生效
  • 不支持滚动更新策略
  • 不支持回滚操作
  • 没有历史版本管理

2.7 删除rs控制的pod

我们需要通过删除控制器来删除控制器创建的pod

bash 复制代码
[root@hd1 ~]# kubectl delete rs fronted

三、Deployment 控制器

3.1 Deployment 概述

Deployment 是建立在 ReplicaSet 之上的控制器,可以管理多个 ReplicaSet。

Deployment 的三级结构:

复制代码
Deployment → 管理 → ReplicaSet → 管理 → Pod

Deployment 的优势:

功能 说明
创建 ReplicaSet 和 Pod 自动创建和管理底层资源
滚动升级 不停止旧服务的状态下升级应用
回滚应用 将应用回滚到之前的版本
平滑扩容和缩容 动态调整副本数量
暂停和继续 支持暂停 Deployment 更新

扩展知识: 声明式定义是指直接修改资源清单 YAML 文件,然后通过 kubectl apply -f 应用更改,这是 Deployment 支持的核心特性。

Deployment 是建构在 RS 之上的,多个 RS 组成一个 Deployment,但只有一个 RS 处于活跃状态。每次更新镜像版本,都会生成一个新的 RS,把旧的 RS 替换掉。多个 RS 同时存在,但只有一个 RS 运行。

3.2 Deployment 资源结构

bash 复制代码
# 查看 Deployment 资源结构
[root@hd1 ~]# kubectl explain deployment
KIND:     Deployment
VERSION:  apps/v1
FIELDS:
   apiVersion  <string>   # 该资源使用的 API 版本
   kind        <string>   # 创建的资源类型
   metadata    <Object>   # 元数据(名称、命名空间)
   spec        <Object>   # 定义容器的规格
   status      <Object>   # 状态(不可修改)

3.3 Deployment.spec 字段详解

bash 复制代码
[root@hd1 ~]# kubectl explain deployment.spec
字段 说明
minReadySeconds Kubernetes 在等待设置的时间后才进行升级。如果没有设置,Kubernetes 会假设容器启动起来后就提供服务了
paused 暂停,更新时创建 Pod 先暂停,不是立即更新
progressDeadlineSeconds 升级卡住时的截止时间。在 deadline 之内如果卡着,Deployment 状态被标记为 False
replicas 副本数
revisionHistoryLimit 保留的历史版本数,默认 10
selector 必须,标签选择器,选择它关联的 Pod
strategy 更新策略
template 必须,定义的 Pod 模板

3.4 Deployment 更新策略

bash 复制代码
[root@hd1 ~]# kubectl explain deploy.spec.strategy
策略类型 说明
Recreate 重建式更新,删除一个更新一个,会导致 短暂的服务中断
RollingUpdate 滚动更新,默认且最常用 的策略,定义滚动更新方式,能保证服务在更新期间 零停机

3.5 滚动更新参数

bash 复制代码
[root@hd1 ~]# kubectl explain deploy.spec.strategy.rollingUpdate
参数 说明
maxSurge 更新过程中最多允许超出指定目标副本数的数量。可以是具体数值或百分比,默认 25%
maxUnavailable 最多允许几个不可用。假设有 5 个副本,最多 1 个不可用,表示最少有 4 个可用

3.6 Deployment 使用案例

创建一个web站点

deployment是一个三级结构,deployment管理replicaset,replicaset管理pod

准备镜像

把myapp-blue-v1.tar.gz和myapp-blue-v2.tar.gz上传到hd2和hd3上

bash 复制代码
# 在 hd2 和 hd3 上加载镜像
[root@hd2 ~]# docker load -i myapp-blue-v1.tar.gz
[root@hd2 ~]# docker load -i myapp-blue-v2.tar.gz
[root@hd3 ~]# docker load -i myapp-blue-v1.tar.gz
[root@hd3 ~]# docker load -i myapp-blue-v2.tar.gz
编写 Deployment YAML

可以发现,Deployment YAML文件除了kind是Deployment,其他的配置基本和rs的配置一模一样

yaml 复制代码
[root@hd1 ~]# vim deploy-demo.yaml
apiVersion: apps/v1
kind: Deployment  
metadata:
  name: myapp-v1     #Deployment 的名称
spec:      # 规格,定义 Deployment 的期望状态
  replicas: 2        # 期望运行的 Pod 副本数量
  selector:          # 标签选择器,用于管理pod
    matchLabels:
      app: myapp
      version: v1
  template:           # Pod 模板
    metadata:
      labels:
        app: myapp
        version: v1
    spec:              # Pod 的规格
      containers:      #容器列表
      - name: myapp
        image: docker.io/janakiramm/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
部署并查看
bash 复制代码
# 创建 Deployment
[root@hd1 ~]# kubectl apply -f deploy-demo.yaml

# 查看 Deployment 状态
[root@hd1 ~]# kubectl get deploy
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
myapp-v1   2/2     2            2           60s

Deployment 状态字段说明:

字段 说明
NAME Deployment 名称
READY 就绪/期望副本数
UP-TO-DATE 已更新到所需状态的副本数
AVAILABLE 可用的应用程序副本数
AGE 运行时间
bash 复制代码
# 查看 ReplicaSet(名称格式:DEPLOYMENT名-rs编号)
[root@hd1 ~]# kubectl get rs
NAME                  DESIRED   CURRENT   READY   AGE
myapp-v1-7f4bb69595   2         2         2       3m58s

# 查看 Pod(名称格式:Deployment名-rs编号-pod编号)
[root@hd1 ~]# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
myapp-v1-7f4bb69595-7rkmw   1/1     Running   0          4m1s
myapp-v1-7f4bb69595-xjnq8   1/1     Running   0          4m1s

3.7 Deployment 扩容

bash 复制代码
# 修改 YAML 中的 replicas 值
[root@hd1 ~]# vim deploy-demo.yaml
spec:
  replicas: 3

[root@hd1 ~]# kubectl apply -f deploy-demo.yaml

[root@hd1 ~]# kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
myapp-v1-67fd9fc9c8-fcprr   1/1     Running   0          15m
myapp-v1-67fd9fc9c8-h9js5   1/1     Running   0          11s
myapp-v1-67fd9fc9c8-hw4f9   1/1     Running   0          17m

同样的,可以直接使用kubectl edit 进行配置:

bash 复制代码
[root@hd1 ~]# kubectl edit deployment myapp-v1 

3.8 Deployment 缩容

bash 复制代码
[root@hd1 ~]# vim deploy-demo.yaml
spec:
  replicas: 2

[root@hd1 ~]# kubectl apply -f deploy-demo.yaml

[root@hd1 ~]# kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
myapp-v1-67fd9fc9c8-fcprr   1/1     Running   0          18m
myapp-v1-67fd9fc9c8-hw4f9   1/1     Running   0          20m

或使用kubectl edit 直接配置

3.9 Deployment 滚动更新(重点)

Deployment控制器是建立在rs之上的一个控制器,可以管理多个rs,每次更新镜像版本,都会生成一个新的rs,把旧的rs替换掉,多个rs同时存在,但是只有一个rs运行

rs v1控制三个pod,删除一个pod,在rs v2上重新建立一个,依次类推,直到全部都是由rs v2控制,如果rs v2有问题,还可以回滚,Deployment是建构在rs之上的,多个rs组成一个Deployment,但是只有一个rs处于活跃状态

步骤1:在第一个终端监控 Pod
bash 复制代码
#-l查看对应标签,-w表示持续监控
[root@hd1 ~]# kubectl get pods -l app=myapp -w
NAME                        READY   STATUS    RESTARTS   AGE
myapp-v1-67fd9fc9c8-fcprr   1/1     Running   0          19m
myapp-v1-67fd9fc9c8-hw4f9   1/1     Running   0          22m
步骤2:在第二个终端修改镜像版本
bash 复制代码
[root@hd1 ~]# vim deploy-demo.yaml

# 修改 image: janakiramm/myapp:v1 → janakiramm/myapp:v2

[root@hd1 ~]# kubectl apply -f deploy-demo.yaml
步骤3:观察终端一滚动更新过程
复制代码
[root@hd1 ~]# kubectl get pods -l app=myapp -w
NAME                        READY   STATUS    RESTARTS   AGE
myapp-v1-7f4bb69595-7rkmw   1/1     Running   0          13m
myapp-v1-7f4bb69595-xjnq8   1/1     Running   0          13m
myapp-v1-bb6b49b78-d6scc    0/1     Pending   0          0s
myapp-v1-bb6b49b78-d6scc    0/1     Pending   0          0s
myapp-v1-bb6b49b78-d6scc    0/1     ContainerCreating   0          0s
myapp-v1-bb6b49b78-d6scc    0/1     ContainerCreating   0          1s
myapp-v1-bb6b49b78-d6scc    1/1     Running             0          2s
myapp-v1-7f4bb69595-xjnq8   1/1     Terminating         0          14m
myapp-v1-bb6b49b78-fzlql    0/1     Pending             0          0s
myapp-v1-bb6b49b78-fzlql    0/1     Pending             0          0s
myapp-v1-bb6b49b78-fzlql    0/1     ContainerCreating   0          0s
myapp-v1-7f4bb69595-xjnq8   1/1     Terminating         0          14m
myapp-v1-bb6b49b78-fzlql    0/1     ContainerCreating   0          0s
myapp-v1-7f4bb69595-xjnq8   0/1     Terminating         0          14m
myapp-v1-7f4bb69595-xjnq8   0/1     Terminating         0          14m
myapp-v1-7f4bb69595-xjnq8   0/1     Terminating         0          14m
myapp-v1-bb6b49b78-fzlql    1/1     Running             0          1s
myapp-v1-7f4bb69595-7rkmw   1/1     Terminating         0          14m
myapp-v1-7f4bb69595-7rkmw   1/1     Terminating         0          14m
myapp-v1-7f4bb69595-7rkmw   0/1     Terminating         0          14m
myapp-v1-7f4bb69595-7rkmw   0/1     Terminating         0          14m
myapp-v1-7f4bb69595-7rkmw   0/1     Terminating         0          14m

可以明显的观测到,再进行滚动更新的时候,先创建新的pod(Pending → ContainerCreating → Running),等到新的pod成功running,旧的pod终止(Terminating)

状态说明:

状态 含义
Pending 正在进行调度
ContainerCreating 正在创建 Pod
Running Pod 正在运行
Terminating 正在终止旧 Pod
步骤4:查看 ReplicaSet 变化
bash 复制代码
[root@hd1 ~]# kubectl get rs
NAME                  DESIRED   CURRENT   READY   AGE
myapp-v1-7f4bb69595   0         0         0       20m     (旧rs,已停止)
myapp-v1-bb6b49b78    2         2         2       6m12s   (新rs,活跃)

可以看到: 升级前的 RS 已被停掉,但并未删除,可以随时回滚。

3.10 Deployment 回滚(重点)

查看历史版本语法:kubectl rollout history deployment <Deployment名称>

查看历史版本
bash 复制代码
#注意,这里的myapp-v1是我们的deployment名
[root@hd1 ~]# kubectl rollout history deployment myapp-v1
deployment.apps/myapp-v1 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
#可以看到两个
回滚到指定版本

版本回滚的语法:kubectl rollout undo deployment <deployment名称>

bash 复制代码
#指定回滚到版本1
[root@hd1 ~]# kubectl rollout undo deployment myapp-v1 --to-revision=1
deployment.apps/myapp-v1 rolled back

# 再次查看历史版本(会看到新的版本号)
[root@hd1 ~]# kubectl rollout history deployment myapp-v1
deployment.apps/myapp-v1
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

注意! 回滚后 REVISION 编号会递增,而不是回到原来的编号。

四、自定义滚动更新策略(重要)

4.1 参数说明

参数 说明
maxSurge 更新过程中最多允许超出指定目标副本数的数量。可以是具体数值或百分比,默认 25%
maxUnavailable 最多允许几个不可用。maxUnavailable 控制的是所有 Pod 的总和(包括新的和旧的)中不可用的数量上限

滚动更新本身就是先创建新的,再杀死老的,所以会有新旧同时存在的时刻,也就是pod数量会有超出上限的瞬间,因此要设置maxSurge

4.2 生产环境推荐配置

maxUnavailable: 0maxSurge: 1

即"一上一下,先上后下"最平滑原则。

4.3 配置方法

方法一:使用 kubectl patch 命令

不推荐,因为使用命令去配置不够直观

bash 复制代码
[root@hd1 ~]# kubectl patch deployment myapp-v1 -p '{"spec":{"strategy":{"rollingUpdate": {"maxSurge":1,"maxUnavailable":0}}}}'

方法二:直接修改 YAML 文件

bash 复制代码
[root@hd1 ~]# vim deploy-demo.yaml
# 在 spec 下添加 strategy 配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name:  myapp-v1
  namespace: default
  labels:
    app:  myapp-v1
spec:
  strategy: 
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: myapp
      version: v1
  replicas: 2
  template:
    metadata:
      labels:
        app:  myapp
        version: v1
    spec:
      containers:
      - name:  myapp
        image:  docker.io/janakiramm/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort:  80
          name:  myapp-v1

方法三:使用kubectl edit 修改配置

因为Kubernetes 声明式 API 的"默认值填充"机制,所以我们使用kubectl edit 进入deployment的配置时,会发现它默认就带有maxSurge和maxUnavailable这两个参数,因为**kubectl edit 修改的是集群中的真实 Deployment 配置,而不是你本地文件的内容。**我们只需要修改参数的值即可。

使用kubectl edit修改配置,保存会立即生效,非常方便

bash 复制代码
[root@hd1 ~]# kubectl edit deployment myapp-v1

注意,在edit修改完之后,建议同步修改本地yaml文件,避免出现配置漂移的问题

查看更新策略:

bash 复制代码
[root@hd1 ~]# kubectl describe deployment myapp-v1
RollingUpdateStrategy:  0 max unavailable, 1 max surge

五、Pod 的 DNS 策略

k8s中内置了一个dns服务插件:coredns。用来对集群内提供dns解析服务

bash 复制代码
[root@hd1 ~]# kubectl get pod -n kube-system
coredns-5bbd96d687-464gw                  1/1     Running   0          6d
coredns-5bbd96d687-wcvmp                  1/1     Running   0          6d

#查看 CoreDNS Service IP,这是集群内部所有 Pod 默认使用的 DNS 服务器地址
[root@hd1 ~]# kubectl get svc -n kube-system kube-dns
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   6d1h

CoreDNS 默认部署了 2 个副本,实现高可用和负载均衡。即使其中一个 CoreDNS Pod 因故障被自动重建,Kubernetes 也会确保始终有 2 个副本在运行

5.1 怎么查看当前 DNS 策略

kubectl get pod <pod-name> -o yaml | grep -A 5 dns:查看 Pod 的完整 YAML,筛选 dns 相关字段

bash 复制代码
[root@hd1 ~]# kubectl get pod myapp-v1-7f4bb69595-qxvh4 -o yaml | grep dns
  dnsPolicy: ClusterFirst  #集群优先的策略,优先实验集群内部的策略

#查看 Deployment 的模板中定义的dns策略
[root@hd1 ~]# kubectl get deployment myapp-deploy -o yaml | grep -A 5 dns

5.2 DNS 策略的四种类型

策略 说明
None 无任何策略,使用自定义的策略。可配合 dnsConfig 自定义 DNS 服务器
Default 使用宿主机的 DNS 配置(/etc/resolv.conf
ClusterFirst 集群 DNS 优先(默认值)。优先使用集群 DNS(CoreDNS),解析失败再走宿主机 DNS(未使用 hostNetwork)
ClusterFirstWithHostNet 集群 DNS 绝对优先,集群dns失败再走宿主机(使用 hostNetwork: true 的 Pod)

hostNetwork: true 会让 Pod 直接使用宿主机的网络命名空间,因此它的 /etc/resolv.conf 也会继承宿主机的 DNS 配置,但会导致这个pod导致无法解析集群内部的 Service 域名。这时就需要使用ClusterFirstWithHostNet 策略来解决这个问题了。而这也是ClusterFirstClusterFirstWithHostNet的主要区别

5.3 DNS 配置示例

注意,dns策略是Pod级别的配置,需要定义在pod的spec.dnsPolicy中

示例1:使用默认集群 DNS

bash 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  namespace: default
  labels:
    app: myapp
spec:
  # DNS 策略:默认使用集群 DNS(CoreDNS)
  dnsPolicy: ClusterFirst

  # 自定义 DNS 配置(补充)
  dnsConfig:
    options:
      - name: ndots
        value: "2"                      # 改为 2,减少公网域名解析延迟
      - name: timeout
        value: "1"                      # 可选:DNS 查询超时时间(秒)
      - name: attempts
        value: "2"                      # 可选:DNS 查询重试次数

  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

示例2:hostNetwork 场景

bash 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: hostnetwork-pod
  namespace: default
  labels:
    app: hostnetwork-app
spec:
  # 关键:使用宿主机网络
  hostNetwork: true

  # 关键:必须配合这个策略,否则无法解析集群内部 Service
  dnsPolicy: ClusterFirstWithHostNet

  dnsConfig:
    options:
      - name: ndots
        value: "2"

  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

示例3:完全自定义DNS

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: custom-dns-pod
  namespace: default
  labels:
    app: custom-dns-app
spec:
  # 关键:必须设为 None,表示完全自定义
  dnsPolicy: "None"

  # 自定义 DNS 配置(必须)
  dnsConfig:
    nameservers:
      - 114.114.114.114                 # 主 DNS(可换成你的内网 DNS)
      - 8.8.8.8                         # 备用 DNS
    searches:                           # 可选:域名搜索列表
      - my-namespace.svc.cluster.local  
      - svc.cluster.local
      - cluster.local
    options:                            # 可选:DNS 解析选项
      - name: ndots
        value: "2"
      - name: timeout
        value: "2"

  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

ndots的value值设得太高(如 5),会导致访问公网域名时产生大量无效的 DNS 查询;设得太低(如 1),又可能导致访问集群内部短域名(如 my-service)时找不到

5.4 Deployment中配置DNS策略(适用于生产环境)

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      # DNS 策略配置在此处(与 Pod 模板平级)
      dnsPolicy: ClusterFirst
      dnsConfig:
        options:
          - name: ndots
            value: "2"
      containers:
      - name: myapp
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

5.5 hostNetwork 与 DNS 策略的关系

hostNetwork: true 时(Pod 使用宿主机网络),Pod 的 DNS 服务器默认与宿主机相同,无法识别 Kubernetes 集群内部的域名。为了让 Pod 识别集群内部域名,需要使用 dnsPolicy: ClusterFirstWithHostNet

示例:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: my-hostnetwork-pod
spec:
  hostNetwork: true                      # 必须设置为宿主机网络模式
  dnsPolicy: ClusterFirstWithHostNet     # 依赖 hostNetwork: true,强制使用集群 DNS

四种策略对比:

DNS 策略 适用场景 说明
ClusterFirst 普通 Pod(默认) 优先使用集群 CoreDNS,然后才是宿主机 DNS
Default 不需要集群 DNS 的 Pod 直接使用宿主机 /etc/resolv.conf
ClusterFirstWithHostNet 使用宿主机网络的 Pod hostNetwork: true 的 Pod 既能解析集群内部服务,又能解析集群内部服务
None 完全自定义 DNS 的 Pod 需要配合 dnsConfig 自定义 DNS 服务器

假如一个pod网络命名空间和宿主机相同(hostNetwork: true),那么意味着pod的dns服务器和宿主机的dns服务器是一样的,这样的话,pod就不能识别k8s集群内部的域名,为了让pod识别,dnsPolicy采用ClusterFirstWithHostNet就可以了(这样就可以既识别内部域名,又可以识别外部域名)

六、核心知识点总结

6.1 控制器层级关系

复制代码
Deployment(高级控制器)
    │
    ├── 管理 ReplicaSet(版本管理)
    │       │
    │       └── 管理 Pod(副本管理)
    │
    └── 提供功能:滚动更新、回滚、历史版本、暂停/继续

6.2 ReplicaSet vs Deployment 对比

对比项 ReplicaSet Deployment
管理 Pod ✅ 直接管理 ✅ 通过 ReplicaSet 管理
滚动升级 ❌ 需要手动删除 Pod ✅ 支持滚动更新
回滚 ❌ 不支持 ✅ 支持回滚到历史版本
历史版本 ❌ 不保留 ✅ 保留历史版本(默认 10 个)
更新策略 ❌ 无 ✅ Recreate / RollingUpdate
推荐使用 ❌ 官方不推荐直接使用 ✅ 官方推荐

6.3 关键命令速查

类别 命令 作用
资源操作 kubectl apply -f <file> 创建或更新资源(声明式,可重复执行)
kubectl edit <资源类型> <资源名> 直接编辑集群中的资源(实时生效,如 deployment myapp-v1
kubectl patch <资源类型> <资源名> -p '...' 给资源打补丁(如修改滚动更新策略)
kubectl delete <资源类型> <资源名> 删除资源(如 rs frontend
查看资源 kubectl get rs 查看所有 ReplicaSet
kubectl get deploy 查看所有 Deployment
kubectl get pods -l <label> 按标签筛选并查看 Pod(如 -l app=myapp
kubectl describe deployment <名称> 查看 Deployment 的详细信息(包括更新策略、事件等)
滚动更新与回滚 kubectl rollout status deployment <名称> 查看滚动更新的当前状态(进度)
kubectl rollout history deployment <名称> 查看 Deployment 的历史版本列表
kubectl rollout undo deployment <名称> 回滚到上一个版本
kubectl rollout undo deployment <名称> --to-revision=N 回滚到指定的历史版本(N 为版本号)
kubectl rollout pause deployment <名称> 暂停当前的滚动更新(用于调试或暂停)
kubectl rollout resume deployment <名称> 恢复被暂停的滚动更新
其他 kubectl get pods -w 持续监控 Pod 状态变化(watch 模式)

说明

  • kubectl edit 修改的是集群中实际运行的资源,修改后立即生效,但建议同步更新本地 YAML 文件,避免配置漂移。
  • kubectl rollout 系列命令专用于 Deployment 等支持滚动更新的控制器,是日常发布和回滚的核心工具。

6.4 Deployment 滚动更新流程

复制代码
1. 修改 Deployment 中的镜像版本
2. 创建新的 ReplicaSet(带新镜像)
3. 逐渐增加新 RS 的副本数
4. 逐渐减少旧 RS 的副本数
5. 直到所有 Pod 由新 RS 管理
6. 旧 RS 保留(用于回滚)

6.5 注意事项

  1. selector 是必须字段:Deployment 和 ReplicaSet 都必须指定标签选择器
  2. 标签选择器必须匹配 Pod 模板标签:否则控制器无法管理 Pod
  3. applycreate 的区别apply 可以执行多次(声明式),create 执行一次再执行会报错
  4. 历史版本保留 :默认保留 10 个历史版本,可通过 revisionHistoryLimit 调整
  5. 滚动更新策略 :建议生产环境使用 maxUnavailable: 0, maxSurge: 1,实现"先上后下"的最平滑更新
相关推荐
code_whiter1 小时前
初阶linux2环境基础开发工具完整教程
linux
薛定e的猫咪1 小时前
零基础选型指南:Make / 扣子 Coze/n8n/Dify 四大自动化平台完整对比
运维·自动化
星恒随风1 小时前
C++ STL 详解:set 与 multiset 的使用、区间查询和算法应用
开发语言·c++·笔记·学习·算法
张忠琳1 小时前
【NVIDIA】k8s-device-plugin v0.19.3 辅助命令模块深度分析之七
云原生·容器·架构·kubernetes·nvidia
数聚天成DeepSData1 小时前
外贸海关进出口数据去哪免费下载?从统计到明细的查找指南
linux·服务器·开发语言·前端·网络·人工智能·自然语言处理
爱码少年1 小时前
此docker compose非彼docker-compose
docker
Huangjin007_1 小时前
【Linux 系统篇(十)】基础开发工具(五) —— 第一个系统程序 - 进度条
linux·运维·服务器
January丶1 小时前
docker-compose部署RabbitMQ(含管理页面)
docker
xx24061 小时前
前端性能优化笔记
前端·笔记·性能优化