一、工作负载
Kubernetes 提供了几个内置的 API 来声明式管理工作负载及其组件。
最终,你的应用以容器的形式在 Pods 中运行; 但是,直接管理单个 Pod 的工作量将会非常繁琐。例如,如果一个 Pod 失败了,你可能希望运行一个新的 Pod 来替换它。Kubernetes 可以为你完成这些操作。
你可以使用 Kubernetes API 创建工作负载对象, 这些对象所表达的是比 Pod 更高级别的抽象概念,Kubernetes 控制平面根据你定义的工作负载对象规约自动管理 Pod 对象。
用于管理工作负载的内置 API 包括:
Deployment (也间接包括 ReplicaSet) 是在集群上运行应用的最常见方式。Deployment 适合在集群上管理无状态应用工作负载, 其中 Deployment 中的任何 Pod 都是可互换的,可以在需要时进行替换。 (Deployment 替代原来的 ReplicationController API)。
StatefulSet 允许你管理一个或多个运行相同应用代码、但具有不同身份标识的 Pod。 StatefulSet 与 Deployment 不同。Deployment 中的 Pod 预期是可互换的。 StatefulSet 最常见的用途是能够建立其 Pod 与其持久化存储之间的关联。 例如,你可以运行一个将每个 Pod 关联到 PersistentVolume 的 StatefulSet。如果该 StatefulSet 中的一个 Pod 失败了,Kubernetes 将创建一个新的 Pod, 并连接到相同的 PersistentVolume。
DaemonSet 定义了在特定节点上提供本地设施的 Pod, 例如允许该节点上的容器访问存储系统的驱动。当必须在合适的节点上运行某种驱动或其他节点级别的服务时, 你可以使用 DaemonSet。DaemonSet 中的每个 Pod 执行类似于经典 Unix / POSIX 服务器上的系统守护进程的角色。DaemonSet 可能对集群的操作至关重要, 例如作为插件让该节点访问集群网络, 也可能帮助你管理节点,或者提供增强正在运行的容器平台所需的、不太重要的设施。 你可以在集群的每个节点上运行 DaemonSets(及其 Pod),或者仅在某个子集上运行 (例如,只在安装了 GPU 的节点上安装 GPU 加速驱动)。
你可以使用 Job 和/或 CronJob 定义一次性任务和定时任务。 Job 表示一次性任务,而每个 CronJob 可以根据排期表重复执行。
组件 | 特点 | 应用 |
---|---|---|
Deployment | 无状态应用部署 | 微服务,提供多副本功能 |
StatefulSet | 有状态应用部署 | Redis,提供稳定的存储、网络等功能 |
DaemonSet | 守护型应用部署 | 日志收集组件,每个机器上都运行一份(有且仅有) |
Job、CronJob | 定时任务部署 | 垃圾清理组件,可在指定的时间运行 |
二、Kubernetes 对象
1、什么是Kubernetes 对象
Kubernetes 里面操作的资源实体,就是 Kubernetes 的对象,可以使用 yaml 来声明,然后让 Kubernetes 根据 yaml 的声明创建出这个对象。
操作 Kubernetes 对象,无论是创建、修改还是删除,都需要使用 Kubernetes 的 API 。如:当使用 kubectl 命令行的时候,CLI 会执行必要的 Kubernetes API 调用。
Kubernetes 对象指的是 Kubernetes 系统的持久化实体,所有的这些 Kubernetes 对象,就代表了当前集群中的实际情况。常规的应用中,我们将应用程序产生的数据存放在数据库中;同理,Kubernetes 将其数据以 Kubernetes 对象的形式通过 api-server 存储在 etcd 中。具体来说,这些数据(Kubernetes 对象)描述了:
- 集群中运行了那些容器化应用程序,以及在哪个节点上运行。
- 集群中应用程序可用的资源,如:网络、存储等。
- 应用程序相关的策略定义,如:重启策略、升级策略和容错策略等。
- 其他 Kubernetes 管理应用程序时所需要的信息。
每一个 Kubernetes 对象都包含了两个重要字段:
spec
:需要由我们来提供,描述了我们对该对象所期望的目标状态
。
status
:只能由 Kubernetes 系统来修改,描述了该对象在 Kubernetes 系统中的实际状态。
Kubernetes 通过对应的
控制器(如:Deployment 等)
,不断的使得实际状态趋向于我们期望的目标状态。
【问】:Kubernetes 是如何保证最终一致的?
etcd 保存的创建资源期望的状态以及最终这个资源的状态,这两种状态需要最终一致,即:spec 和 status 要最终一致。
当输入 kubectl create deployment my-nginx --image=nginx
命令的时候,api-server 保存到 etcd ,controller-manager 会解析数据,知道集群中需要 my-nginx ,保存到 etcd 中。
kubelet 在底层不停的死循环使得 spec 状态和 status 最终一致,如果 spec.replicas != status.replicas
,就启动 Pod。
while(true){
if(status.replicas != spec.replicas){
kubelet.startPod();
}
}
2、描述 Kubernetes 对象
当我们在 Kubernetes 集群中创建一个对象的时候,我们必须提供:
- 该对象的
spec
字段,通过该字段描述我们期望的目标状态
。
- 该对象的
- 该对象的一些基本信息,如:名字等。
可以使用 kubectl 命令行创建对象,也可以使用 yaml 格式的文件进行创建

在上述的 yaml 文件中,如下的字段是必须填写的:
apiVersion
:用来创建对象时所需要的 Kubernetes API 的版本,可以通过 kubectl api-resources 查询。
kind
:创建对象的类型,可以通过 kubectl api-resources 查询。
metadata
:用来唯一确定该对象的元数据,包括 name 、namespace 等,如果 namespace 为空,则默认值为 default 。
spec
:翻译为规格
,表示我们对该对象的期望状态。
status 不需要编写,那是 Kubernetes 实际运行过程中将变化的记录保存在此字段中。
3、如何创建对象的 yaml
(1)已存在对象
如果 Kubernetes 集群中已经存在了要创建的对象,那么可以使用 kubectl get
直接输出 yaml ,然后去除 status 即可:
kubectl get pod xxx -o yaml > demo.yaml
(2)不存在对象
如果 Kubernetes 集群中不存在了要创建的对象,那么可以使用类似 kubectl run xxx --dry-run=client
输出 yaml :
# --dry-run=client 表示客户端干跑
kubectl run nginx-pod --image=nginx --dry-run=client -o yaml > demo.yaml
4、标签
(1)概述
标签(Label)是附件在 Kubernetes 对象上的一组键值对,其意图是按照对用户有意义的方式来标识 Kubernetes 对象,同时,又不对 Kubernetes 的核心逻辑产生影响。标签可以用来组织和选择一组 Kubernetes 对象。我们可以在创建 Kubernetes 对象的时候为其添加标签,也可以在创建以后为其添加标签。每个 Kubernetes 对象可以有多个标签,同一个对象的标签的 key 必须是唯一的,如:
metadata:
labels:
key1: value1
key2: value2
使用标签(Label)可以高效的查询和监听 Kubernetes 对象,在 Kubernetes 界面工具(如:Kubernetes DashBoard)和 kubectl 中,标签使用的非常普遍。而那些非标识性的信息应该记录在 注解(Annotation)
中。
(2)为什么要使用标签
使用标签,用户可以按照自己期望的形式组织 Kubernetes 对象之间的结构,而无需对 Kubernetes 有任何修改。
应用程序的部署或者批处理程序的部署通常是多维度的(如:多个高可用分区、多个程序版本、多个微服务分层)。管理这些对象的时候,很多时候要针对某一个维护的条件做整体操作,如:将某个版本的程序整体删除。这种情况下,如果用户能够事先规划好标签的使用,再通过标签进行选择,就非常的便捷。
标签的例子有:
release: stable
、release: canary
。environment: dev
、environment: qa
、environment: production
。tier: frontend
、tier: backend
、tier: cache
。partition: customerA
、partition: customerB
。track: daily
、track: weekly
。
上面只是一些使用比较普遍的标签,我们也可以根据自己的情况建立合适的标签。
(3)标签的语法
标签是一组键值对(key/value),标签的 key 有两个部分:可选的前缀和标签名,通过
/
分隔。标签前缀:
- 标签前缀部分是可选的。
- 如果指定,必须是一个 DNS 的子域名,如:k8s.eip.work 。
- 不能多余 253 个字符。
- 使用
/
和标签名分隔。
- 使用
标签名:
- 标签名部分是必须的。
- 不能多余 63 个字符。
- 必须由字母、数字开始和结尾。
- 可以包含字母、数字、减号(
-
)、下划线(_
)、小数点(.
)。
- 可以包含字母、数字、减号(
如果省略标签前缀,则标签的 key 就被认为是专属于用户的。Kubernetes 的系统组件(如:kube-scheduler、kube-controller-manager、kube-apiserver、kubectl 或其他第三方组件)向可以的 Kubernetes 对象添加标签的时候,必须指定一个前缀。kubernetes.io/
和 k8s.io/
这两个前缀是 Kubernetes 核心组件预留的。
标签的 value :
- 不能多于 63 个字符。
- 可以为空字符串。
- 如果不为空,则必须由字母、数字开始和结尾。
- 如果不为空,可以包含字母、数字、减号(
-
)、下划线(_
)、小数点(.
)。
- 如果不为空,可以包含字母、数字、减号(
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels: # 标签
app: nginx
environment: prod
spec:
containers:
- name: nginx
image: nginx
(5)标签选择器
通常来讲,会有多个 Kubernetes 对象包含相同的标签。通过使用标签选择器(label selector),用户/客户端可以选择一组对象。标签选择器是 Kubernetes 中最主要的分类和筛选手段。
Kubernetes 的 api-server 支持两种形式的标签选择器,equality-based 基于等式的
和 set-based 基于集合的
。标签选择器可以包含多个条件,并使用逗号进行分隔,此时只要满足所有条件的 Kubernetes对象才会被选中。
基于等式的标签选择器,可以使用三种操作符 =
、==
、!=
。前两个操作符含义是一样的,都代表相等;后一个操作符代表不相等。
# 选择了标签名为 `environment` 且 标签值为 `production` 的Kubernetes对象
kubectl get pods -l environment=production,tier=frontend
# 选择了标签名为 `tier` 且标签值不等于 `frontend` 的对象,以及不包含标签 `tier` 的对象
kubectl get pods -l tier != frontend
# 选择所有包含 `partition` 标签的对象
kubectl get pods -l partition
# 选择所有不包含 `partition` 标签的对象
kubectl get pods -l !partition
基于集合标签选择器,可以根据标签名的一组值进行筛选。支持的操作符有三种:in
、notin
、exists
。
# 选择所有的包含 `environment` 标签且值为 `production` 或 `qa` 的对象
kubectl get pods -l environment in (production, qa)
# 选择所有的 `tier` 标签不为 `frontend` 和 `backend`的对象,或不含 `tier` 标签的对象
kubectl get pods -l tier notin (frontend, backend)
# 选择包含 `partition` 标签(不检查标签值)且 `environment` 不是 `qa` 的对象
kubectl get pods -l partition,environment notin (qa)
示例:Job、Deployment、ReplicaSet 和 DaemonSet 同时支持基于等式的选择方式和基于集合的选择方式。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
selector:
matchLabels: # matchLabels 是一个 {key,value} 组成的 map。map 中的一个 {key,value} 条目相当于 matchExpressions 中的一个元素,其 key 为 map 的 key,operator 为 In, values 数组则只包含 value 一个元素。matchExpression 等价于基于集合的选择方式,支持的 operator 有 In、NotIn、Exists 和 DoesNotExist。当 operator 为 In 或 NotIn 时,values 数组不能为空。所有的选择条件都以 AND 的形式合并计算,即所有的条件都满足才可以算是匹配
app: nginx
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
(6)标签操作
添加标签
kubectl label pod nginx-pod hello=world
更新标签
kubectl label pod nginx-pod hello=java --overwrite
删除标签
kubectl label pod nginx-pod hello-
三、NameSpace
1、概述
命名空间用来进行资源划分,默认只隔离资源,不隔离网络
所有创建的资源在不指定命名空间的情况下,都会创建到 default 命名空间中
删除命名空间会把部署在他下面所有的资源连带删除
命名空间命名规则:
① 不能带小数点(
.
)。② 不能带下划线(
_
)。③ 使用数字、小写字母或减号(
-
)组成的字符串。

命令行操作
# 获取所有命名空间
kubectl get ns
# 删除命名空间
kubectl delete ns 命名空间
# 创建命名空间
kubectl create ns 命名空间
yaml操作
创建名为 hello 的名称空间
apiVersion: v1
kind: Namespace
metadata:
name: hello
应用 yaml 文件,创建名称空间
kubectl apply -f hello.yaml
删除通过该 yaml 创建的所有资源(通过 yaml 创建的资源,要通过同一个 yaml 删除,这样删的干净)
kubectl delete -f hello.yaml
2、默认存在的名称空间
在 Kubernetes 中名称空间是用来对象资源进行隔离的。
默认情况下,Kubernetes 会初始化四个名称空间:
default:所有没有指定 namespace 的对象都会被分配到此名称空间中。
kube-node-lease:Kubernetes 集群节点之间的心跳维护,V 1.13 开始引入。
kube-system:Kubernetes 系统创建的对象放在此名称空间中。
kube-public:此名称空间是 Kubernetes 集群安装时自动创建的,并且所有的用户都可以访问(包括未认证的用户),主要是为集群预留的,如:在某些情况中,某些 Kubernetes 对象应用应该能被所有集群用户访问到。
3、名称空间如何划分
① 基于环境隔离,如:dev(开发)、test(测试)、prod(生产)等。
② 基于产品线隔离,如:前端、后端、中间件、大数据、Android、iOS、小程序等。
③ 基于团队隔离,如:企业发展事业部、技术工程事业部、云平台事业部等。
4、注意事项
大多数的 Kubernetes 资源(如:Pod、Service、副本控制器等)都位于某些名称空间中,但是名称空间本身并不在名称空间中,而且底层资源(如:node 和持久化卷)不属于任何命名空间。
查看在名称空间中的资源:
kubectl api-resources --namespaced=true
查看不在名称空间中的资源:
kubectl api-resources --namespaced=false
四、Pod
1、pod结构
运行中的一组容器,Pod是kubernetes中应用的最小单位

注意:集群中的任意一个机器以及任意的应用都能通过Pod分配的ip来访问这个Pod,同一个 Pod 内不同容器共享网络 ip,共享空间存储
- 同一个 Pod 内的不同容器之间,可通过 127.0.0.1 访问
- 同一个 Pod 内的不同容器,占用同一端口会报错

每个Pod中都包含一个或者多个容器,这些容器可以分为两类:
① 用户程序所在的容器,数量可多可少。
② Pause容器,这是每个Pod都会有的一个根容器,它的作用有两个:
- 可以以它为依据,评估整个Pod的健康状况。
- 可以在根容器上设置IP地址,其它容器都共享此IP(Pod的IP),以实现Pod内部的网络通信(这里是Pod内部的通讯,Pod之间的通讯采用虚拟二层网络技术来实现,我们当前环境使用的是Flannel)。
1、命令行操作
创建 Pod
kubectl run Pod名称 --image=指定镜像
kubectl run mynginx --image=nginx
基本不会用kubectl run的方式启动,因为这样和docker run启动没有区别了,不能发挥kubenates的优点
其他命令
# 查看default名称空间的Pod
kubectl get pod
# 描述
kubectl describe pod Pod名字
# 删除
kubectl delete pod Pod名字
# 查看Pod的运行日志
kubectl logs Pod名字
2、配置文件操作
apiVersion: v1
kind: Pod
metadata:
labels:
run: myapp
# pod名
name: myapp
# 指定命名空间
namespace: default
spec:
containers:
# 所需容器的镜像以及容器名
- image: nginx
name: nginx
- image: tomcat:8.5.68
name: tomcat
3、资源清单
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如 Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #Pod所属的命名空间,默认为"default"
labels: #自定义标签列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
nodeName: #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5个部分:
apiVersion <string>
:版本,有kubernetes内部定义,版本号必须用kubectl api-versions查询。kind <string>
:类型,有kubernetes内部定义,类型必须用kubectl api-resources查询。metadata <Object>
:元数据,主要是资源标识和说明,常用的有name、namespace、labels等。spec <Object>
:描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述。status <Object>
:状态信息,里面的内容不需要定义,由kubernetes自动生成。
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
containers <[]Object>
:容器列表,用于定义容器的详细信息。nodeName <String>
:根据nodeName的值将Pod调度到指定的Node节点上。nodeSelector <map[]>
:根据NodeSelector中定义的信息选择该Pod调度到包含这些Label的Node上。hostNetwork <boolean>
:是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络。volumes <[]Object>
:存储卷,用于定义Pod上面挂载的存储信息。restartPolicy <string>
:重启策略,表示Pod在遇到故障的时候的处理策略。
4、pod配置
(1)概述
本小节主要来研究pod.spec.containers属性,这也是Pod配置中最为关键的一项配置。
# 查看pod.spec.containers的可选配置项
kubectl explain pod.spec.containers
结果
# 返回的重要属性
KIND: Pod
VERSION: v1
RESOURCE: containers <[]Object> # 数组,代表可以有多个容器FIELDS:
name # 容器名称
image # 容器需要的镜像地址
imagePullPolicy # 镜像拉取策略
command <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
args <[]string> # 容器的启动命令需要的参数列表
env <[]Object> # 容器环境变量的配置
ports <[]Object> # 容器需要暴露的端口号列表
resources
(2)基本配置
创建pod-base.yaml文件,内容如下
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
- name: busybox # 容器名称
image: busybox:1.30 # 容器需要的镜像地址
上面定义了一个比较简单的Pod的配置,里面有两个容器:
- nginx:用的是1.17.1版本的nginx镜像创建
- busybox:用的是1.30版本的busybox镜像创建(busybox是一个小巧的linux命令集合)。
(3)镜像拉取策略
创建 pod-imagepullpolicy.yaml
文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-imagepullpolicy
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
imagePullPolicy: Always # 用于设置镜像的拉取策略
- name: busybox # 容器名称
image: busybox:1.30 # 容器需要的镜像地址
imagePullPolicy
:用于设置镜像拉取的策略,kubernetes支持配置三种拉取策略:Always
:总是从远程仓库拉取镜像(一直远程下载)。
IfNotPresent
:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像(本地有就用本地,本地没有就使用远程下载)。
Never
:只使用本地镜像,从不去远程仓库拉取,本地没有就报错(一直使用本地,没有就报错)。
默认值说明:
如果镜像tag为具体的版本号,默认策略是IfNotPresent。
如果镜像tag为latest(最终版本),默认策略是Always。
(4)启动命令
在前面的案例中,一直有一个问题没有解决,就是busybox容器一直没有成功运行,那么到底是什么原因导致这个容器的故障的呢?
原来busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。解决方法就是让其一直在运行,这就用到了command的配置。
创建pod-command.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-command
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
imagePullPolicy: IfNotPresent # 设置镜像拉取策略
- name: busybox # 容器名称
image: busybox:1.30 # 容器需要的镜像地址
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]
command:用于在Pod中的容器初始化完毕之后执行一个命令。
这里稍微解释下 command
中的命令的意思:
"/bin/sh","-c"
:使用sh执行命令。touch /tmp/hello.txt
:创建一个/tmp/hello.txt的文件。while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done
:每隔3秒,向文件写入当前时间
启动后即可进入Pod中的busybox容器,查看文件内容
# 在容器中执行命令
# kubectl exec -it pod的名称 -n 命名空间 -c 容器名称 /bin/sh
kubectl exec -it pod-command -n dev -c busybox /bin/sh
特别说明:通过上面发现command已经可以完成启动命令和传递参数的功能,为什么还要提供一个args选项,用于传递参数?其实和Docker有点关系,kubernetes中的command和args两个参数其实是为了实现覆盖Dockerfile中的ENTRYPOINT的功能:
如果command和args均没有写,那么用Dockerfile的配置。
如果command写了,但是args没有写,那么Dockerfile默认的配置会被忽略,执行注入的command。
如果command没有写,但是args写了,那么Dockerfile中配置的ENTRYPOINT命令会被执行,使用当前args的参数。
如果command和args都写了,那么Dockerfile中的配置会被忽略,执行command并追加上args参数。
(5)环境变量(不推荐)
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
imagePullPolicy: IfNotPresent # 设置镜像拉取策略
- name: busybox # 容器名称
image: busybox:1.30 # 容器需要的镜像地址
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]
env:
- name: "username"
value: "admin"
- name: "password"
value: "123456"
env:环境变量,用于在Pod中的容器设置环境变量。
此种方式不推荐,推荐将这些配置单独存储在配置文件中,后面介绍。
(6)端口设置
apiVersion: v1
kind: Pod
metadata:
name: pod-ports
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
imagePullPolicy: IfNotPresent # 设置镜像拉取策略
ports:
- name: nginx-port # 端口名称,如果执行,必须保证name在Pod中是唯一的
containerPort: 80 # 容器要监听的端口 (0~65536)
protocol: TCP # 端口协议
ports 子选项:
- name ,端口名称,如果指定,必须保证name在pod中是唯一的
- containerPort ,容器要监听的端口(0<x<65536)
- hostPort ,容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
- hostIP ,要将外部端口绑定到的主机IP(一般省略)
- protocol ,端口协议。必须是UDP、TCP或SCTP。默认为“TCP”
访问Pod中的容器中的程序使用的是PodIp:containerPort。
(7)资源配额
容器中的程序要运行,肯定会占用一定的资源,比如CPU和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量的资源,导致其他的容器无法运行。针对这种情况,kubernetes提供了对内存和CPU的资源进行配额的机制,这种机制主要通过resources选项实现,它有两个子选项:
- limits:用于限制运行的容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启。
- requests:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动。
可以通过上面的两个选项设置资源的上下限。
创建pod-resoures.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-resoures
namespace: dev
labels:
user: xudaxian
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
imagePullPolicy: IfNotPresent # 设置镜像拉取策略
ports: # 端口设置
- name: nginx-port # 端口名称,如果执行,必须保证name在Pod中是唯一的
containerPort: 80 # 容器要监听的端口 (0~65536)
protocol: TCP # 端口协议
resources: # 资源配额
limits: # 限制资源的上限
cpu: "2" # CPU限制,单位是core数
memory: "10Gi" # 内存限制
requests: # 限制资源的下限
cpu: "1" # CPU限制,单位是core数
memory: "10Mi" # 内存限制
cpu:core数,可以为整数或小数。
memory:内存大小,可以使用Gi、Mi、G、M等形式。
5、生命周期
我们一般将Pod对象从创建到终止的这段时间范围称为Pod的生命周期,它主要包含下面的过程:
Pod创建过程。
运行初始化容器(init container)过程。
运行主容器(main container):
- 容器启动后钩子(post start)、容器终止前钩子(pre stop)。
- 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)。
Pod终止过程。

在整个生命周期中,Pod会出现5种状态(相位),分别如下:
挂起(Pending):API Server已经创建了Pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中。
运行中(Running):Pod已经被调度到某节点,并且所有容器都已经被kubelet创建完成。
成功(Succeeded):Pod中的所有容器都已经成功终止并且不会被重启。
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态。
未知(Unknown):API Server无法正常获取到Pod对象的状态信息,通常由于网络通信失败所导致。
(1)创建过程
① 用户通过kubectl或其他的api客户端提交需要创建的Pod信息给API Server。
② API Server开始生成Pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端。
③ API Server开始反映etcd中的Pod对象的变化,其它组件使用watch机制来跟踪检查API Server上的变动。
④ Scheduler发现有新的Pod对象要创建,开始为Pod分配主机并将结果信息更新至API Server。
⑤ Node节点上的kubelet发现有Pod调度过来,尝试调度Docker启动容器,并将结果回送至API Server。
⑥ API Server将接收到的Pod状态信息存入到etcd中。
(2)终止过程
① 用户向API Server发送删除Pod对象的命令。
② API Server中的Pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),Pod被视为dead。
③ 将Pod标记为terminating状态。
④ kubelete在监控到Pod对象转为terminating状态的同时启动Pod关闭过程。
⑤ 端点控制器监控到Pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除。
⑥ 如果当前Pod对象定义了preStop钩子处理器,则在其标记为terminating后会以同步的方式启动执行。
⑦ Pod对象中的容器进程收到停止信号。
⑧ 宽限期结束后,如果Pod中还存在运行的进程,那么Pod对象会收到立即终止的信号。
⑨ kubectl请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,此时Pod对于用户已经不可用了。
(3)初始化容器过程
初始化容器是在Pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
- ① 初始化容器必须运行完成直至结束,如果某个初始化容器运行失败,那么kubernetes需要重启它直至成功完成。
- ② 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行。
初始化容器有很多的应用场景,下面列出的是最常见的几个:
- 提供主容器镜像中不具备的工具程序或自定义代码。
- 初始化容器要先于应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足。
接下来做一个案例,模拟下面这个需求:
假设要以主容器来运行Nginx,但是要求在运行Nginx之前要能够连接上MySQL和Redis所在的服务器。
为了简化测试,事先规定好MySQL和Redis所在的IP地址分别为192.168.18.103和192.168.18.104(注意,这两个IP都不能ping通,因为环境中没有这两个IP)。
创建pod-initcontainer.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-initcontainer
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
resources:
limits:
cpu: "2"
memory: "10Gi"
requests:
cpu: "1"
memory: "10Mi"
initContainers: # 初始化容器配置
- name: test-mysql
image: busybox:1.30
command: ["sh","-c","until ping 192.168.18.103 -c 1;do echo waiting for mysql ...;sleep 2;done;"]
securityContext:
privileged: true # 使用特权模式运行容器
- name: test-redis
image: busybox:1.30
command: ["sh","-c","until ping 192.168.18.104 -c 1;do echo waiting for redis ...;sleep 2;done;"]
创建 pod
kubectl create -f pod-initcontainer.yaml
查看pod状态(会发现pod卡在第一个容器初始化过程,后面的容器不会运行)
kubectl describe pod pod-initcontainer -n dev
动态查看Pod:
kubectl get pod pod-initcontainer -n dev -w
接下来,新开一个shell,为当前服务器(192.168.18.100)新增两个IP,观察Pod的变化:
ifconfig ens33:1 192.168.18.103 netmask 255.255.255.0 up
ifconfig ens33:2 192.168.18.104 netmask 255.255.255.0 up
(4)钩子函数
钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器启动之后和停止之前提供了两个钩子函数:
- post start:容器创建之后执行,如果失败会重启容器。
- pre stop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作。
钩子处理器支持使用下面的三种方式定义动作:
- ① exec命令:在容器内执行一次命令。
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command:
- cat
- /tmp/healthy
- ② tcpSocket:在当前容器尝试访问指定的socket。
lifecycle:
postStart:
tcpSocket:
port: 8080
- ③ httpGet:在当前容器中向某url发起HTTP请求。
lifecycle:
postStart:
httpGet:
path: / #URI地址
port: 80 #端口号
host: 192.168.109.100 #主机地址
scheme: HTTP #支持的协议,http或者https
- 接下来,以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-hook-exec
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
resources:
limits:
cpu: "2"
memory: "10Gi"
requests:
cpu: "1"
memory: "10Mi"
lifecycle: # 生命周期配置
postStart: # 容器创建之后执行,如果失败会重启容器
exec: # 在容器启动的时候,执行一条命令,修改掉Nginx的首页内容
command: ["/bin/sh","-c","echo postStart ... > /usr/share/nginx/html/index.html"]
preStop: # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
exec: # 在容器停止之前停止Nginx的服务
command: ["/usr/sbin/nginx","-s","quit"]
(5)容器探测
容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例“摘除”,不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
liveness probes
:存活性探测,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器。用来决定是否重启容器。readiness probes
:就绪性探测,用于检测应用实例是否可以接受请求,如果不能,k8s不会转发流量。用来决定是否将请求转发给容器。
k8s在1.16版本之后新增了startupProbe探针,用于判断容器内应用程序是否已经启动。如果配置了startupProbe探针,就会先禁止其他的探针,直到startupProbe探针成功为止,一旦成功将不再进行探测。
上面两种探针目前均支持三种探测方式:
① exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常。
② tcpSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常。
③ httpGet:调用容器内web应用的URL,如果返回的状态码在200和399之前,则认为程序正常,否则不正常。
exec方式
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-exec
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
livenessProbe: # 存活性探针
exec:
command: ["/bin/cat","/tmp/hello.txt"] # 执行一个查看文件的命令,没有这个文件,则执行失败,重启容器
tcpSocket方式
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-tcpsocket
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
livenessProbe: # 存活性探针
tcpSocket:
port: 8080 # 尝试访问8080端口,失败,因为Pod内部只有一个Nginx容器,而且只是监听了80端口
httpGet方式
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-httpget
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
livenessProbe: # 存活性探针
httpGet: # 其实就是访问http://127.0.0.1:80/hello
port: 80 # 端口号
scheme: HTTP # 支持的协议,HTTP或HTTPS
path: /hello # URI地址
host: 127.0.0.1 # 主机地址
容器探测的补充
上面已经使用了livenessProbe演示了三种探测方式,但是查看livenessProbe的子属性,会发现除了这三种方式,还有一些其他的配置。
查看其他配置
kubectl explain pod.spec.containers.livenessProbe
FIELDS:
exec
tcpSocket
httpGet
initialDelaySeconds # 容器启动后等待多少秒执行第一次探测
timeoutSeconds # 探测超时时间。默认1秒,最小1秒
periodSeconds # 执行探测的频率。默认是10秒,最小1秒
failureThreshold # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold # 连续探测成功多少次才被认定为成功。默认是1
(6)重启策略
在容器探测中,一旦容器探测出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是由Pod的重启策略决定的,Pod的重启策略有3种,分别如下:
Always:容器失效时,自动重启该容器,默认值。
OnFailure:容器终止运行且退出码不为0时重启。
Never:不论状态如何,都不重启该容器。
重启策略适用于Pod对象中的所有容器,首次需要重启的容器,将在其需要的时候立即进行重启,随后再次重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s,300s是最大的延迟时长。
apiVersion: v1
kind: Pod
metadata:
name: pod-restart-policy
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
livenessProbe: # 存活性探测
httpGet:
port: 80
path: /hello
host: 127.0.0.1
scheme: HTTP
restartPolicy: Never # 重启策略
五、ReplicaSet(RS)
1、Pod控制器的介绍
- 在kubernetes中,按照Pod的创建方式可以将其分为两类:
- 自主式Pod:kubernetes直接创建出来的Pod,这种Pod删除后就没有了,也不会重建。
- 控制器创建Pod:通过Pod控制器创建的Pod,这种Pod删除之后还会自动重建。
- Pod控制器:Pod控制器是管理Pod的中间层,使用了Pod控制器之后,我们只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它就会创建出满足条件的Pod并确保每一个Pod处于用户期望的状态,如果Pod在运行中出现故障,控制器会基于指定的策略重启或重建Pod。
- 在kubernetes中,有很多Pod控制器,每种都有自己的适合的场景,常见的有下面这些
- ReplicationController:比较原始的Pod控制器,已经被废弃,由ReplicaSet替代。
- ReplicaSet:保证指定数量的Pod运行,并支持Pod数量变更,镜像版本变更。
- Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、版本回退。
- Horizontal Pod Autoscaler:可以根据集群负载自动调整Pod的数量,实现削峰填谷。
- DaemonSet:在集群中的指定Node上都运行一个副本,一般用于守护进程类的任务。
- Job:它创建出来的Pod只要完成任务就立即退出,用于执行一次性任务。
- CronJob:它创建的Pod会周期性的执行,用于执行周期性的任务。
- StatefulSet:管理有状态的应用。
2、ReplicaSet概述
ReplicaSet的主要作用是保证一定数量的Pod能够正常运行,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对Pod数量的扩缩容

资源清单
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: rs
spec: # 详情描述
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器管理哪些po
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
在这里,需要新了解的配置项就是spec下面几个选项:
- replicas:指定副本数量,其实就是当然rs创建出来的Pod的数量,默认为1.
- selector:选择器,它的作用是建立Pod控制器和Pod之间的关联关系,采用了Label Selector机制(在Pod模块上定义Label,在控制器上定义选择器,就可以表明当前控制器能管理哪些Pod了)。
- template:模板,就是当前控制器创建Pod所使用的模板,里面其实就是前面学过的Pod的定义。
3、创建ReplicaSet
- 创建pc-replicaset.yaml文件,内容如下:
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
name: pc-replicaset # rs名称
namespace: dev # 命名类型
spec: # 详细描述
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器可以管理哪些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
ports:
- containerPort: 80 # 容器所监听的端口
- 创建rs:
kubectl create -f pc-replicaset.yaml
- 查看rs:
kubectl get rs pc-replicaset -n dev -o wide

- 查看当前控制器创建出来的Pod(控制器创建出来的Pod的名称是在控制器名称后面拼接了-xxx随机码):
kubectl get pod -n dev
4、扩缩容
(1)方法一
编辑rs的副本数量,修改 spec:replicas:6
即可。
kubectl edit rs pc-replicaset -n dev

(2)方法二
使用scale命令实现扩缩容,后面加上 --replicas=n
直接指定目标数量即可。
kubectl scale rs pc-replicaset --replicas=2 -n dev
5、删除ReplicaSet
使用kubectl delete rs 命令会删除ReplicaSet和其管理的Pod。
kubectl delete rs pc-replicaset -n dev
在 kubernetes
删除 ReplicaSet
前,会将 ReplicaSet
的 replicas
调整为0,等到所有的Pod被删除后,再执行 ReplicaSet
对象的删除
如果希望仅仅删除ReplicaSet对象(保留Pod),只需要在使用kubectl delete rs命令的时候添加 --cascade=false
选项(不推荐):
kubectl delete rs pc-replicaset -n dev --cascade=false
使用yaml直接删除(推荐):
kubectl delete -f pc-replicaset.yaml
六、Deployment(Deploy)
为了更好地解决服务编排的问题,k8s在V1.2版本开始,引入了deployment控制器,值得一提的是,这种控制器并不直接管理pod,
而是通过管理replicaset来间接管理pod,即:deployment管理replicaset,replicaset管理pod。所以deployment比replicaset的功能更强大。

主要作用:
定义一组Pod期望数量,Controller会维持Pod数量与期望数量一致
配置Pod的发布方式,controller会按照给定的策略更新Pod,保证更新过程中不可用Pod维持在限定数量范围内
如果发布有问题支持回滚
deployment的主要功能有下面几个:
- 支持ReplicaSet的所有功能。
- 自愈&故障转移
- 扩、缩容
- 支持发布的停止、继续。
- 支持版本滚动更新和版本回退。
0、资源清单
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: deploy
spec: # 详情描述
replicas: 3 # 副本数量
revisionHistoryLimit: 3 # 保留历史版本,默认为10
paused: false # 暂停部署,默认是false
progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数 maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
1、多副本创建
(1)创建多副本
在当前集群内创建 3 各指定的 Pod,Deployment 会尽可能将 Pod 数量维持在指定的数量3
kubectl create deployment my-dep --image=nginx --replicas=3
--replicas
:指定启动 Pod 的数量,默认不写为1
(2)配置文件操作
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: pc-deployment # deployment的名称
namespace: dev # 命名类型
spec: # 详细描述
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器可以管理哪些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
ports:
- containerPort: 80 # 容器所监听的端口
(3)删除deploy
通过 kubectl delete
命令
# --cascade=false 删除 deploy 的同时保留 Pod
kubectl delete deployment deploy的名称 [-n 命名空间] [--cascade=false]
kubectl delete deployment nginx-deployment
通过 yaml 文件
kubectl delete -f k8s-deploy.yaml
2、自愈&故障转移
当 deployment 管理的 Pod 因异常原因导致无法使用时,deployment 会在其他的节点重新启动一个相同的 Pod ,保证系统的稳定性
- 停机
- 删除Pod
- 容器崩溃
- 。。。
3、扩/缩容
deployment 管理的 Pod 可进行动态的扩容/缩容,即当流量较大时,会在多起几个服务,当流量小了之后,会将一些服务下线
kubectl edit deployment my-dep -n dev
- 编辑rs的副本数量,修改
spec:replicas:6
即可
- 使用scale命令实现扩缩容,后面加上
--replicas=n
直接指定目标数量即可。
kubectl scale deployment my-dep --replicas=5 -n dev
4、镜像更新
Deployment支持两种镜像更新的策略:重建更新
和滚动更新(默认)
,可以通过strategy
选项进行配置。
strategy: 指定新的Pod替代旧的Pod的策略,支持两个属性
type: 指定策略类型,支持两种策略
Recreate: 在创建出新的Pod之前会先杀掉所有已经存在的Pod
RollingUpdate: 滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的Pod
rollingUpdate: 当type为RollingUpdate的时候生效,用于为rollingUpdate设置参数,支持两个属性:
maxUnavailable: 用来指定在升级过程中不可用的Pod的最大数量,默认为25%。
maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
(1)重建更新
编辑pc-deployment.yaml文件,在spec节点下添加更新策略
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: pc-deployment # deployment的名称
namespace: dev # 命名类型
spec: # 详细描述
replicas: 3 # 副本数量
strategy: # 镜像更新策略
type: Recreate # Recreate:在创建出新的Pod之前会先杀掉所有已经存在的Pod
selector: # 选择器,通过它指定该控制器可以管理哪些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
ports:
- containerPort: 80 # 容器所监听的端口
kubectl apply -f pc-deployment.yaml
镜像升级
kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
查看升级过程
kubectl get pod -n dev -w
(2)滚动更新
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: pc-deployment # deployment的名称
namespace: dev # 命名类型
spec: # 详细描述
replicas: 3 # 副本数量
strategy: # 镜像更新策略
type: RollingUpdate # RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的Pod
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
selector: # 选择器,通过它指定该控制器可以管理哪些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
ports:
- containerPort: 80 # 容器所监听的端口
kubectl apply -f pc-deployment.yaml
镜像升级
kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev
命令格式
kubectl set image <资源类型> <资源名称> <容器名称>=<新镜像名称>
滚动更新的过程

- 镜像更新中rs的变化:
# 查看rs,发现原来的rs依旧存在,只是Pod的数量变为0,而后又产生了一个rs,Pod的数量变为3
# 其实这就是deployment能够进行版本回退的奥妙所在
kubectl get rs -n dev
5、版本回退
# 版本升级相关功能
kubetl rollout 参数 deploy xx
参数支持下面的选择:
- status 显示当前升级的状态
- history 显示升级历史记录
- pause 暂停版本升级过程
- resume 继续已经暂停的版本升级过程
- restart 重启版本升级过程
- undo 回滚到上一级版本 (可以使用–to-revision回滚到指定的版本)
查看当前升级版本的状态:
kubectl rollout status deploy pc-deployment -n dev
查看升级历史记录
kubectl rollout history deployment pc-deployment -n dev
版本回退
# 可以使用-to-revision=1回退到1版本,如果省略这个选项,就是回退到上个版本,即2版本
kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
deployment之所以能够实现版本的回退,就是通过记录下历史的ReplicaSet来实现的,一旦想回滚到那个版本,只需要将当前版本的Pod数量降为0,然后将回退版本的Pod提升为目标数量即可。
6、金丝雀发布(灰度发布)
滚动更新也是有缺点的:滚动更新短时间就直接结束了,不能直接控制新老版本的存活时间;而金丝雀发布却可以实现这样的功能。

金丝雀的发布流程如下:
① 将 service 的标签设置为 app=nginx ,这就意味着集群中的所有标签是 app=nginx 的 Pod 都会加入负载均衡网络。
② 使用 Deployment v=v1 app=nginx 去筛选标签是 app=nginx 以及 v=v1 的 所有 Pod。
③ 同理,使用 Deployment v=v2 app=nginx 去筛选标签是 app=nginx 以及 v=v2 的所有 Pod 。
④ 逐渐加大 Deployment v=v2 app=nginx 控制的 Pod 的数量,根据轮询负载均衡网络的特点,必定会使得此 Deployment 控制的 Pod 的流量增大。
⑤ 当测试完成后,删除 Deployment v=v1 app=nginx 即可。
(1)准备v1版本
vi k8s-v1-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy-v1
labels:
app: nginx-deploy-v1
spec:
replicas: 3
selector:
matchLabels:
app: nginx
v: v1
template:
metadata:
name: nginx
labels:
app: nginx
v: v1
spec:
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always
运行
kubectl apply -f k8s-v1-deploy.yaml
(2)准备v2版本
vi k8s-v2-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy-v2
labels:
app: nginx-deploy-v2
spec:
replicas: 4
selector:
matchLabels:
app: nginx
v: v2
template:
metadata:
name: nginx
labels:
app: nginx
v: v2
spec:
initContainers:
- name: alpine
image: alpine
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","echo 2222 > /app/index.html;"]
volumeMounts:
- mountPath: /app
name: app
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: app
mountPath: /usr/share/nginx/html
volumes:
- name: app
emptyDir: {}
restartPolicy: Always
运行
kubectl apply -f k8s-v2-deploy.yaml
(3)创建Service
vi k8s-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: canary-svc
spec:
selector:
app: nginx
type: NodePort
ports:
- port: 80 # svc 的访问端口
name: canary-nginx
targetPort: 80 # Pod 的访问端口
protocol: TCP
nodePort: 31009 # 在机器上开端口,浏览器访问
运行
kubectl apply -f k8s-svc.yaml
七、StatefulSet(有状态)
1、概述
无状态应用:
- 认为Pod都是一样的。
- 没有顺序要求。
- 不用考虑在哪个Node节点上运行。
- 随意进行伸缩和扩展。
有状态应用:
- 有顺序的要求。
- 认为每个Pod都是不一样的。
- 需要考虑在哪个Node节点上运行。
- 需要按照顺序进行伸缩和扩展。
- 让每个Pod都是独立的,保持Pod启动顺序和唯一性。
StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器。
StatefulSet部署需要HeadLinessService(无头服务)。
为什么需要HeadLinessService(无头服务)?
在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在StatefulSet中要求必须是有序 ,每一个Pod不能被随意取代,Pod重建后pod名称还是一样的。
而Pod IP是变化的,所以是以Pod名称来识别。Pod名称是Pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。
StatefulSet常用来部署RabbitMQ集群、Zookeeper集群、MySQL集群、Eureka集群等。
Deployment和StatefulSet的区别
- Deployment和StatefulSet的区别:Deployment没有唯一标识而StatefulSet有唯一标识。
- StatefulSet的唯一标识是根据主机名+一定规则生成的。
- StatefulSet的唯一标识是
主机名.无头Service名称.命名空间.svc.cluster.local
。
2、创建StatefulSet
apiVersion: v1
kind: Service
metadata:
name: service-headliness
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
type: ClusterIP
ports:
- port: 80 # Service的端口
targetPort: 80 # Pod的端口
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: pc-statefulset
namespace: dev
spec:
replicas: 3
serviceName: service-headliness
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
创建
kubectl create -f pc-stateful.yaml
3、查看StatefulSet
kubectl get statefulset pc-statefulset -n dev -o wide
4、删除StatefulSet
kubectl delete -f pc-stateful.yaml
5、金丝雀发布
StatefulSet支持两种更新策略:OnDelete和RollingUpdate(默认),其中OnDelete表示删除之后才更新,RollingUpdate表示滚动更新。
apiVersion: v1
kind: Service
metadata:
name: service-headliness
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
type: ClusterIP
ports:
- port: 80 # Service的端口
targetPort: 80 # Pod的端口
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: pc-statefulset
namespace: dev
spec:
replicas: 3
serviceName: service-headliness
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
八、DaemonSet(DS)
1、概述
DaemonSet类型的控制器可以保证集群中的每一台(或指定)节点上都运行一个副本,一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
- 每向集群中添加一个节点的时候,指定的Pod副本也将添加到该节点上。
- 当节点从集群中移除的时候,Pod也会被垃圾回收。
DaemonSet的资源清单
apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels: #标签
controller: daemonset
spec: # 详情描述
revisionHistoryLimit: 3 # 保留历史版本
updateStrategy: # 更新策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxUnavailable: 1 # 最大不可用状态的Pod的最大值,可用为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理那些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- nginx-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
2、创建 DS
apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型
metadata: # 元数据
name: pc-damonset # 名称
namespace: dev #命名空间
spec: # 详情描述
selector: # 选择器,通过它指定该控制器管理那些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
创建
kubectl create -f pc-daemonset.yaml
3、查看 DS
kubectl get ds -n dev -o wide
4、删除 DS
kubectl delete ds pc-damonset -n dev
九、Job
1、概述
Job主要用于负责批量处理短暂的一次性任务。
Job的特点:
当Job创建的Pod执行成功结束时,Job将记录成功结束的Pod数量。
当成功结束的Pod达到指定的数量时,Job将完成执行。
Job可以保证指定数量的Pod执行完成。
资源清单
apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels: # 标签
controller: job
spec: # 详情描述
completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1
parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1
activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止
backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6
manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false
selector: # 选择器,通过它指定该控制器管理那些Pod
matchLabels: # Labels匹配规则
app: counter-pod
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- counter-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done"]
关于模板中的重启策略的说明:
如果设置为OnFailure,则Job会在Pod出现故障的时候重启容器,而不是创建Pod,failed次数不变。
如果设置为Never,则Job会在Pod出现故障的时候创建新的Pod,并且故障Pod不会消失,也不会重启,failed次数+1。
如果指定为Always的话,就意味着一直重启,意味着Pod任务会重复执行,这和Job的定义冲突,所以不能设置为Always。
2、创建 Job
apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据
name: pc-job # 名称
namespace: dev #命名空间
spec: # 详情描述
manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false
selector: # 选择器,通过它指定该控制器管理那些Pod
matchLabels: # Labels匹配规则
app: counter-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3;done" ]
kubectl create -f pc-job.yaml
3、查看 Job
kubectl get job -n dev -w
4、删除 Job
kubectl delete -f pc-job.yaml
十、CronJob
1、概述
CronJob
控制器以 Job
控制器为其管控对象,并借助它管理Pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似Linux操作系统的周期性任务作业计划的方式控制器运行时间点及重复运行的方式,换言之,CronJob可以在特定的时间点反复去执行Job任务。

资源清单
apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels:
controller: cronjob
spec: # 详情描述
schedule: # cron格式的作业调度运行时间点,用于控制任务任务时间执行
concurrencyPolicy: # 并发执行策略
failedJobsHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
successfulJobsHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义
metadata: {}
spec:
completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1
parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1
activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止
backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done" ]
schedule:cron表达式,用于指定任务的执行时间。
*/1 * * * *:表示分钟 小时 日 月份 星期。
分钟的值从0到59。
小时的值从0到23。
日的值从1到31。
月的值从1到12。
星期的值从0到6,0表示星期日。
多个时间可以用逗号隔开,范围可以用连字符给出:* 可以作为通配符,/表示每…
concurrencyPolicy:并发执行策略
Allow:运行Job并发运行(默认)。
Forbid:禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行。
Replace:替换,取消当前正在运行的作业并使用新作业替换它。
2、创建 CronJob
apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
name: pc-cronjob # 名称
namespace: dev #命名空间
spec: # 详情描述
schedule: "*/1 * * * * " # cron格式的作业调度运行时间点,用于控制任务任务时间执行
jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义
metadata: {}
spec:
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 2;done" ]
kubectl create -f pc-cronjob.yaml
3、查看 CronJob
kubectl get cronjob -n dev -w
4、删除 CronJob
kubectl delete -f pc-cronjob.yaml
十一、Horizontal Pod Autoscaler(HPA)
1、概述
我们已经可以通过手动执行kubectl scale
命令实现Pod的扩缩容,但是这显然不符合kubernetes的定位目标–自动化和智能化。kubernetes期望可以通过监测Pod的使用情况,实现Pod数量的自动调整,于是就产生了HPA这种控制器。
HPA可以获取每个Pod的利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA和之前的Deployment一样,也属于一种kubernetes资源对象,它通过追踪分析目标Pod的负载变化情况,来确定是否需要针对性的调整目标Pod的副本数。

2、安装metrics-server(v0.3.6)
metrics-server可以用来收集集群中的资源使用情况。
获取metrics-server,需要注意使用的版本(网路不行,请点这里v0.3.6.tar.gz):
wget https://github.com/kubernetes-sigs/metrics-server/archive/v0.3.6.tar.gz
- 解压v0.3.6.tar.gz文件:
tar -zxvf v0.3.6.tar.gz
- 进入metrics-server-0.3.6/deploy/1.8+/目录:
cd metrics-server-0.3.6/deploy/1.8+/
- 修改metrics-server-deployment.yaml文件(按图中添加下面选项):
hostNetwork: true
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
args:
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP

- 安装metrics-server:
kubectl apply -f ./
查看资源使用情况:
kubectl top node
kubectl top pod -n kube-system
3、安装metrics-server(v0.4.1)
- 获取metrics-server:
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml
- 修改components.yaml(修改之后的components.yaml文件components.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
# 修改部分
- --kubelet-insecure-tls
# 修改部分
image: registry.cn-shanghai.aliyuncs.com/xuweiwei-kubernetes/metrics-server:v0.4.1

- 安装metrics-server:
kubectl apply -f components.yaml
4、准备Deployment和Service
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: nginx # deployment的名称
namespace: dev # 命名类型
spec: # 详细描述
selector: # 选择器,通过它指定该控制器可以管理哪些Pod
matchLabels: # Labels匹配规则
app: nginx-pod
template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx # 容器名称
image: nginx:1.17.1 # 容器需要的镜像地址
ports:
- containerPort: 80 # 容器所监听的端口
resources: # 资源限制
requests:
cpu: "100m" # 100m表示100millicpu,即0.1个CPU
创建 deploy
kubectl create -f nginx.yaml
创建 service
kubectl expose deployment nginx --name=nginx --type=NodePort --port=80 --target-port=80 -n dev
5、部署HPA
- 创建pc-hpa.yaml文件,内容如下:
apiVersion: autoscaling/v1 # 版本号
kind: HorizontalPodAutoscaler # 类型
metadata: # 元数据
name: pc-hpa # deployment的名称
namespace: dev # 命名类型
spec:
minReplicas: 1 # 最小Pod数量
maxReplicas: 10 # 最大Pod数量
targetCPUUtilizationPercentage: 3 # CPU使用率指标
scaleTargetRef: # 指定要控制的Nginx的信息
apiVersion: apps/v1
kind: Deployment
name: nginx
- 创建hpa:
kubectl create -f pc-hpa.yaml
- 查看 hpa
kubectl get hpa -n dev
6、测试
使用压测工具如Jmeter对service的地进行压测,然后通过控制台查看hpa和pod的变化。
- hpa的变化:
kubectl get hpa -n dev -w

- Deployment的变化:
kubectl get deployment -n dev -w

- Pod的变化:
kubectl get pod -n dev -w
