1.实验介绍
1.1 实验内容
Pod 是 Kubernetes 最重要的核心概念,Kubernetes 中其它的对象都是在管理、暴露 Pod 或是被 Pod 使用。本节实验将会向大家介绍 Pod 这一核心概念。
1.2 实验知识点
- Pod 简介
- 创建 Pod
- 标签
- 标签选择器
- 命名空间(Namespace)
- 删除 Pod
- 副本集(RS)
- 后台支撑服务集(DaemonSet)
- 任务(Job)
1.3 推荐阅读
1.4 课程环境
本课程全部为云主机环境,采用 Kubeadm-dind 方式在云主机环境里部署 Kubernetes 集群,DIND 代表 Docker in Docker,因为这种方式部署的集群里节点都是通过 Docker 容器模拟的,而部署到集群里的应用又以 Docker 容器运行在节点容器里。目前支持 Kubernetes 1.10.x 到 1.15.x 几个版本,我们实验环境中使用的是最新版的 1.15.x。
实验环境中已经下载好对应的脚本,文件地址为 /home/shiyanlou/dind-cluster-v1.15.sh
,使用这个脚本就可以直接启动整个集群。
先来启动集群:(整个启动过程大概需要一两分钟)
$ ./dind-cluster-v1.15.sh up
* Making sure DIND image is up to date
sha256:12574f2350c69da756ae10b85af0e1ff689a2b5fd3728a2f3112c68195c08d8c: Pulling from mirantis/kubeadm-dind-cluster
Digest: sha256:12574f2350c69da756ae10b85af0e1ff689a2b5fd3728a2f3112c68195c08d8c
Status: Image is up to date for mirantis/kubeadm-dind-cluster@sha256:12574f2350c69da756ae10b85af0e1ff689a2b5fd3728a2f3112c68195c08d8c
docker.io/mirantis/kubeadm-dind-cluster:62f5a9277678777b63ae55d144bd2f99feb7c824-v1.15@sha256:12574f2350c69da756ae10b85af0e1ff689a2b5fd3728a2f3112c68195c08d8c
* Restoring containers
* Restoring master container
* Restoring node container: 1
* Restoring node container: 2
* Starting DIND container: kube-master
* Starting DIND container: kube-node-1
* Starting DIND container: kube-node-2
* Node container restored: 1
* Node container restored: 2
* Master container restored
Creating static routes for bridge/PTP plugin
* Setting cluster config
Cluster "dind" set.
Context "dind" modified.
Switched to context "dind".
* Waiting for kube-proxy and the nodes
........................[done]
* Bringing up coredns
deployment.extensions/coredns scaled
....[done]
* Bringing up kubernetes-dashboard
deployment.extensions/kubernetes-dashboard scaled
..[done]
NAME STATUS ROLES AGE VERSION
kube-master Ready master 3d12h v1.15.0
kube-node-1 Ready <none> 3d12h v1.15.0
kube-node-2 Ready <none> 3d12h v1.15.0
* Access dashboard at: http://127.0.0.1:32768/api/v1/namespaces/kube-system/services/kubernetes-dashboard:/proxy
* Access dashboard at: http://127.0.0.1:32768/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy (if version>1.6 and HTTPS enabled)
如果在启动集群的过程中,一直卡在 deployment.extensions/coredns scaled
部分可以尝试使用 Ctrl+C 中断启动脚本,然后重新执行启动命令。如果试过好几次依然失败,可以关掉当前的云主机环境,重新启动环境进行实验。
在这个集群中有一个 master 节点为 kube-master,两个 node 节点分别为 kube-node-1 和 kube-node-2,它们的 IP 地址分别为:
kube-master:10.192.0.2
kube-node-1:10.192.0.3
kube-node-2:10.192.0.4
2.Pod 简介
一个 Pod 是 Kubernetes 最基本的构建单元,也是最小、最简单的构建单元。Pod 也是扩缩容的基本单位,Kubernetes 的扩容和缩容都是直接对 Pod 进行操作的,直接增加 Pod 或是减少 Pod。
一个 Pod 包含一个应用容器(有的时候有多个)、存储资源、唯一的网络 IP、以及其它容器运行所必须的资源。
Pod 在 Kubernetes 集群中主要有两种使用方式:
- 运行一个单独的容器:这是最常用的方式;在这种情况下,可以认为一个 Pod 封装了一个单独的容器,Kubernetes 是对 pod 进行管理,而不是直接对容器进行管理。
- 运行耦合度高的多个容器:Pod 也可能包含多个容器,这些容器之间关联紧密需要共享资源。将多个容器添加到单个 Pod 的主要原因是应用可能由一个主进程和一个或多个辅助进程组成。在实践中,把一个进程放到一个容器中运行是最好的。
在本实验中,我们只讲解单容器 Pod 的情况。
每个 Pod 意味着运行了一个单独的应用实例,如果你想要运行多个应用实例对应的就应该使用多个 Pod。
Nodes 与 Pods
Pod 是运行在 Node 上的。一个 Node 是 Kubernetes 上的工作节点,它可能是虚拟出来的节点或者是物理节点,这取决于集群的部署方式。每个 Node 节点都被 Master 节点所管理,一个 Node 节点可以运行多个 Pod,在集群中,Kubernetes Master 节点通过 Node 节点自动管理 Pods。
每个 Nodes 运行至少需要两个组件:
- Kubelet:负责 Master 和 Node 之间的通信,用于管理节点上的 Pod。
- Docker:负责从仓库拉取容器镜像,运行应用等。
3.操作 Pod
主要介绍如何直接手动操作 Pod,虽然在实际的生产过程中,我们常常使用的是部署(Deployment)来管理 Pod,但是了解这些操作可以帮助我们更好的理解 Pod。
3.1 创建 Pod
Pod 和其他 Kubernetes 资源通过向 Kubernetes REST API 提供 JSON 或 YAML 描述文件来创建,由于 YAML 格式具有更好的可读性,kubectl 在请求 API 时会从配置文件中读取 YAML 格式内容并转换为 JSON 格式后再发送给 API Server。
编写 YAML 描述文件
编写一个 YAML 文件有 4 个重要的组成部分:
- apiVersion: YAML 描述文件所使用的 Kubernetes API 版本
- kind: Kubernetes 对象/资源类型
- metadata: Pod 元数据(名称、命名空间、标签、注解等)
- spec: Pod 规格/内容(容器列表、存储卷等)
在 /home/shiyanlou
目录下新建 nginx-manual.yaml
文件,并向该文件中写入如下内容:
apiVersion: v1
kind: Pod
metadata:
name: nginx-manual
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
name: nginx
ports:
- containerPort: 80
protocol: TCP
上面的这个 YAML 文件定义了我们要创建一个名为 nginx-manual 的 Pod,这个 Pod 中运行了一个基于 nginx:1.9.1 镜像构建的名为 nginx 的容器,默认监听在 80 端口。
大家在编写的时候如果不清楚有哪些可用属性,可以使用 kubectl explain
来查看:
# 查看 pods 有哪些属性
kubectl explain pods
# 查看具体的属性
kubectl explain pod.spec
执行创建
使用如下命令可以创建 Pod:
$ kubectl create -f nginx-manual.yaml
pod/nginx-manual created
在 Pod 列表中查看新创建的 Pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-manual 0/1 ContainerCreating 0 4s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-manual 1/1 Running 0 16s
可以看到这个 Pod 已经创建成功并在运行中。
Pod 在整个生命周期中存在各种状态,常见的状态如下所示:
状态 | 描述 |
---|---|
Pending | API Server 已经创建该 Pod,但在 Pod 内还有一个或多个容器的镜像没有创建,包括正在下载镜像的过程 |
Running | Pod 内所有容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态 |
Succeeded | Pod 内所有容器均成功执行后退出,且不会再重启 |
Failed | Pod 内所有容器均已退出,但至少有一个容器退出为失败状态 |
Unknown | 由于某种原因无法获取该 Pod 的状态,可能由于网络通信不畅导致的 |
另外 Pod 的重启策略(RestartPolicy)有 3 种,分别为:
Always
:默认策略,当容器失效时,kubelet 会自动重启该容器OnFailure
:当容器终止运行且退出码不为 0 时,kubelet 会自动重启该容器Never
:不论容器运行状态如何,kubelet 都不重启该容器
查看运行中的 Pod 完整定义
查看一个 Pod 的 YAML 描述文件:
kubectl get pod nginx-manual -o yaml
# 也可以查看 json 格式的
# kubectl get pod nginx-manual -o json
结果如下所示:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2019-08-04T08:56:24Z
name: nginx-manual
namespace: default
resourceVersion: '1384'
selfLink: /api/v1/namespaces/default/pods/nginx-manual
uid: bcf146de-b695-11e9-b712-ce9ce5f54bfa
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-ttqxg
readOnly: true
dnsPolicy: ClusterFirst
nodeName: kube-node-1
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-ttqxg
secret:
defaultMode: 420
secretName: default-token-ttqxg
status:
conditions:
- lastProbeTime: null
lastTransitionTime: 2019-08-04T08:56:24Z
status: 'True'
type: Initialized
- lastProbeTime: null
lastTransitionTime: 2019-08-04T08:56:34Z
status: 'True'
type: Ready
- lastProbeTime: null
lastTransitionTime: 2019-08-04T08:56:24Z
status: 'True'
type: PodScheduled
containerStatuses:
- containerID: docker://111b01507bed8b5b752529e778ee79895ebe60a5d73244f3ac84362634e85360
image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
imageID: docker-pullable://registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx@sha256:a42a428525996f3a84d466ee628a074cac568e0e8c99b5d6f7398be342337039
lastState: {}
name: nginx
ready: true
restartCount: 0
state:
running:
startedAt: 2019-08-04T08:56:34Z
hostIP: 10.192.0.3
phase: Running
podIP: 10.244.2.3
qosClass: BestEffort
startTime: 2019-08-04T08:56:24Z
这个 Pod 是处于运行状态,最终获取到的信息会比较多,可以看到前面我们定义的 4 个部分都展示了出来,这里额外还显示了一个部分:
- status: 运行中的 Pod 及其内容容器当前的详细状态(Pod 所处的条件、每个容器的状态、内部 IP 等)
注意:status 是运行的 Pod 在查询时刻的资源状态,所以在编写 YAML 文件的时候不需要这个属性。
查看日志
如果 Pod 上只包含一个容器,想要查看该容器的日志,就可以通过如下命令查看日志:
kubectl logs nginx-manual
如果 Pod 上包含多个容器,在查询具体容器的日志时,需要指定参数 -c 容器名
进行查询,比如:
kubectl logs nginx-manual -c nginx
需要注意的是:每天或是每次日志文件达到 10M 大小之后,容器日志会自动轮替,kubectl logs 命令只显示最后一次轮替后的日志。
测试 Pod 端口是否可用
Pod 运行之后想要测试(调试)一下是否可用,怎么办呢?可以使用 kubectl port-forward
命令来执行端口转发,将本地的 8080 端口转发到 nginx-manual 的 80 端口,执行如下命令:
$ kubectl port-forward nginx-manual 8080:80
Forwarding from 127.0.0.1:8080 -> 80
使用 curl 命令向 pod 发送 HTTP 请求,新开一个标签,执行:
$ curl http://localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3.2 标签
当集群中的 Pod 数量越来越多时,想要有效的区分和管理这些 Pod 就成为了一个问题。可以通过标签来组织 Pod 和所有其他 Kubernetes 资源对象。通过标签划分组,这样就可以对属于某个组的所有 Pod 进行操作,而不需要单独为某个 Pod 执行操作。
标签是可以附加在 Kubernetes 资源对象的任意键值对,通过标签选择器可以选择具有该确切标签的资源。标签的 key 是唯一的,一个资源可以拥有多个标签。创建资源时可以将标签附加在资源上,也可以在现有的资源上添加标签或修改标签值。
创建时指定标签
我们尝试创建一个带有两个标签的新 Pod,在 /home/shiyanlou
目录下新建 nginx-manual-with-labels.yaml
文件,并向其中写入如下代码:
apiVersion: v1
kind: Pod
metadata:
name: nginx-manual-v2
labels:
creation_method: manual
rel: beta
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
name: nginx
ports:
- containerPort: 80
protocol: TCP
然后执行如下命令创建 Pod:
$ kubectl create -f nginx-manual-with-labels.yaml
pod/nginx-manual-v2 created
查看 Pod 的标签可以使用 --show-labels
选项:
$ kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-manual 1/1 Running 0 14m <none>
nginx-manual-v2 1/1 Running 0 33s creation_method=manual,rel=beta
如果想要查看某个具体的标签可以使用 -L
选项指定:
$ kubectl get pod -L creation_method,rel
NAME READY STATUS RESTARTS AGE CREATION_METHOD REL
nginx-manual 1/1 Running 0 15m
nginx-manual-v2 1/1 Running 0 1m manual beta
修改标签
标签也可以在现有的 Pod 上进行添加和修改。
先尝试向 nginx-manual 这个 Pod 添加一个标签,执行如下命令:
$ kubectl label pod nginx-manual creation_method=manual
pod/nginx-manual labeled
然后将 nginx-manual-v2 这个 Pod 上的 rel=beta 修改为 rel=stable,需要添加 --overwrite
选项,执行如下命令:
$ kubectl label pod nginx-manual-v2 rel=stable --overwrite
pod/nginx-manual-v2 labeled
现在来查看更新后的标签:
$ kubectl get pod -L creation_method,rel
NAME READY STATUS RESTARTS AGE CREATION_METHOD REL
nginx-manual 1/1 Running 0 18m manual
nginx-manual-v2 1/1 Running 0 3m manual stable
3.3 标签选择器
标签通常与标签选择器结合在一起使用,标签选择器可以选择标记有特定标签的 Pod 子集,并对这些 Pod 执行操作。
标签选择器对于标签的使用一般有如下 3 种方式:
- 包含或是不包含使用特定键的标签
- 包含具有特定键和值的标签
- 包含有特定键,值可以为任意值的标签
想要筛选出所有手动创建的 Pod:
$ kubectl get pod -l creation_method=manual
NAME READY STATUS RESTARTS AGE
nginx-manual 1/1 Running 0 18m
nginx-manual-v2 1/1 Running 0 4m
列出含有 rel 标签的所有 Pod:
$ kubectl get pod -l rel
NAME READY STATUS RESTARTS AGE
nginx-manual-v2 1/1 Running 0 4m
列出不含有 rel 标签的所有 Pod:
$ kubectl get pod -l '!rel'
NAME READY STATUS RESTARTS AGE
nginx-manual 1/1 Running 0 7m
还有一些其它的使用方式:
# 列出含有 creation_method 标签,但是其值不能为 manual 的 Pod
kubectl get pod -l 'creation_method!=manual'
# 列出含有 rel 标签,且其值为 beta 或是 stable 的 Pod
kubectl get pod -l 'rel in (beta,stable)'
# 列出含有 rel 标签,且其值不为 beta 和 stable 的 Pod
kubectl get pod -l 'rel notin (beta,stable)'
# 列出含有标签 creation_method=manual 和 rel=stable 的 Pod
kubectl get pod -l creation_method=manual,rel=stable
约束 Pod 调度
在 Kubernetes 中,Pod 通常都是随机调度到工作节点上的,这也是 Kubernetes 集群中正确的工作方式。但是在某些特定的情况下,我们会指定 Pod 的调度,这种需求不太常见,这里大家仅作为了解即可。
有的时候一个集群中的硬件基础设施会不一样,比如机器学习的环境中,有的使用 CPU 环境,有的是 GPU 环境,这两种环境的硬件不一样,会导致对应的计算速度也不同。如果想要将 Pod 调度到 GPU 的工作节点上,可以对相应的节点打上标签,然后在编写 yaml 文件时使用 nodeSelector 指定对应的节点标签。
首先查看环境中有几个节点:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-master Ready master 8d v1.15.0
kube-node-1 Ready <none> 8d v1.15.0
kube-node-2 Ready <none> 8d v1.15.0
任意选择一个节点打上标签:
$ kubectl label node kube-node-1 gpu=true
node/kube-node-1 labeled
现在查看是否打上标签:
$ kubectl get nodes -l gpu=true
NAME STATUS ROLES AGE VERSION
kube-node-1 Ready <none> 8d v1.15.0
新建一个名为 nginx-gpu 的 Pod,在 /home/shiyanlou
目录下新建 nginx-gpu.yaml
文件,并向其中写入如下代码:
apiVersion: v1
kind: Pod
metadata:
name: nginx-gpu
spec:
nodeSelector:
gpu: 'true'
containers:
- image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
name: nginx
ports:
- containerPort: 80
protocol: TCP
其中的 nodeSelector
字段表示在创建 Pod 时调度器只在包含 gpu=true 的工作节点中选择。
然后执行创建:
$ kubectl create -f nginx-gpu.yaml
pod/nginx-gpu created
3.4 命名空间
由于标签和 Pod 是多对多的关系,使用标签可以将众多的 Pod 进行分组,这些组中的 Pod 有交叉重复的可能;使用命名空间就可以将对象分隔成完全独立且不重叠的组。Kubernetes 的命名空间为对象名称提供了一个作用域。对象名称只需要在一个命名空间内保持唯一,不同的命名空间可以包含同名的对象。
查看集群中所有的命名空间:
$ kubectl get namespaces
NAME STATUS AGE
default Active 8d
kube-node-lease Active 8d
kube-public Active 8d
kube-system Active 8d
我们在前面的操作中没有指定命名空间,那么就一直都是在 default 这个命名空间下进行的 Pod 创建等操作。
可以查看一下其他命名空间中的 Pod:
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-76dc8f6bf5-rdp2j 1/1 Running 0 14m
etcd-kube-master 1/1 Running 6 13m
kube-apiserver-kube-master 1/1 Running 6 14m
kube-controller-manager-kube-master 1/1 Running 6 13m
kube-proxy-6kj44 1/1 Running 0 14m
kube-proxy-n5bbk 1/1 Running 0 14m
kube-proxy-ptd2d 1/1 Running 0 14m
kube-scheduler-kube-master 1/1 Running 6 14m
kubernetes-dashboard-5ff478f859-2mkkh 1/1 Running 0 14m
可以看到 kube-system 命名空间下的 Pod 都是和 Kubernetes 系统相关的。
现在来尝试新建一个命名空间,在 /home/shiyanlou
目录下新建 test1-namespace.yaml
文件并向其中写入如下代码:
apiVersion: v1
kind: Namespace
metadata:
name: test1-namespace
然后执行创建:
$ kubectl create -f test1-namespace.yaml
namespace/test1-namespace created
当然也可以使用命令直接创建新的命名空间:
$ kubectl create namespace test2-namespace
namespace/test2-namespace created
如果想要在新的命名空间中创建 Pod,有两种方式:
- 在 yaml 文件的 metadata 字段中添加
namespace: test1-namespace
属性 - 创建 Pod 时在命令中使用参数
-n
指定命名空间
比如我们使用前面的 nginx-manual.yaml
文件在 test1-namespace 命名空间中新建 Pod:
$ kubectl create -f nginx-manual.yaml -n test1-namespace
pod/nginx-manual created
这样我们就有两个同名的 Pod 分别运行在两个不同的命名空间内。
3.5 删除及更新 Pod
可以使用名称删除 Pod:
$ kubectl delete pod nginx-manual
pod "nginx-manual" deleted
也可以使用标签选择器删除 Pod:
$ kubectl delete pod -l creation_method=manual
pod "nginx-manual-v2" deleted
还可以通过删除整个命名空间的方式来删除 Pod(命名空间不存在的话,其中的 Pod 会自动被删除):
$ kubectl delete ns test1-namespace
namespace "test1-namespace" deleted
如果想要更新 Pod,可以在修改 Pod 的配置文件之后执行 kubectl replace -f xxx.yaml --force
强制更新 Pod 的各种配置属性。
4.副本集(RS)、后台支撑服务集(DaemonSet)、任务(Job)
使用前面的方法创建 Pod,如果该 Pod 所在的工作节点挂掉了,那么这个节点上的 Pod 会丢失,并且不会重新建立。
在实际的生产中,我们希望我们的部署可以自动运行、保持健康、工作节点挂掉之后 Pod 会自动迁移到新的节点,所以几乎不会手动创建 Pod,而是使用副本集 ReplicaSet 或部署 Deployment 来创建并管理 Pod。
4.1 副本集(RS)
副本集 ReplicaSet 是一种 Kubernetes 资源对象,它可以保证 Pod 始终处于运行状态,如果 Pod 因任何原因消失,ReplicaSet 会注意到缺少了 Pod 并创建新的 Pod 进行替代。
ReplicaSet 主要用于创建和管理一个 Pod 的多个副本(replicas),核心标准是确保 Pod 的数量始终与其标签选择器匹配,它会持续监控正在运行的 Pod 列表,并保证带有对应标签的 Pod 数量与期望相符,如果运行的 Pod 太少会根据 Pod 模板创建新的副本;如果运行的 Pod 太多就会删除多余的副本。
因此 ReplicaSet 由 3 个部分组成:
- 标签选择器(label selector): 确定 ReplicaSet 作用域中有哪些 Pod
- 副本个数(replica count): 指定应运行的 Pod 数量
- Pod 模板(pod template): 用于创建新的 Pod 副本
上述的 3 个部分都可以随时修改,只有副本个数的变更会影响到现有的 Pod,更改标签选择器和 Pod 模板对现有的 Pod 没有影响。如果更改标签选择器会使现有的 Pod 脱离 ReplicaSet 的范围,ReplicaSet 会停止关注它们;如果更改模板,只会对新创建的 Pod 应用新的模板,并不会影响现在存在的 Pod。
使用 ReplicaSet 有以下 3 大好处:
- 保证 Pod 持续运行,如果现有 Pod 数量不符合预期将会自动调整 Pod 的数量;
- 当集群节点发生故障时,在故障节点受 ReplicaSet 控制的所有 Pod 会被创建新的替代副本;
- 可以轻松实现 Pod 的水平伸缩。
注意:这里的标签选择器可以匹配如下的标签:
- 具有某个特定标签名和值的 Pod
- 缺少某个标签的 Pod
- 包含特定标签名,不管其值为多少的 Pod
- 匹配多个标签,只要符合其中一个标签就认为是符合标准的
现在我们来创建一个 ReplicaSet,在 /home/shiyanlou
目录下新建 nginx-replicaset.yaml
文件并向其中写入如下代码:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
执行创建:
$ kubectl create -f nginx-replicaset.yaml
replicaset.apps/nginx created
查看创建的 Pods 和 ReplicaSet:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-45h47 1/1 Running 0 48s
nginx-gpu 1/1 Running 0 17m
nginx-pp6xw 1/1 Running 0 48s
nginx-vf2rg 1/1 Running 0 48s
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 1m
查看详细的描述:
$ kubectl describe rs
Name: nginx
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: registry.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/nginx:1.9.1
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-pp6xw
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-45h47
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-vf2rg
除了使用 matchLabels 属性外,还可以使用功能更加强大的 matchExpressions 属性,在这个属性中可以使用表达式,使标签匹配能够更加丰富。现在我们来改写上面的标签表达式:
selector:
matchExpressions:
- key: app
operator: In
values:
- nginx
使用 matchExpressions 属性一般包含 3 个部分:一个 key、一个 operator(运算符)、以及可能还有一个 values 列表(这取决于运算符)。
operator 运算符一般有 4 种:
- In: 标签的值必须与其中一个指定的 values 匹配
- NotIn: 标签的值必须与指定的 values 不匹配
- Exists: Pod 必须包含一个指定名称的标签(值不重要),这时候就不需要指定 values
- DoesNotExist: Pod 不能够包含有指定名称的标签,这时候也不需要指定 values
如果指定了多个表达式或者同时混合使用了 matchLabels 和 matchExpressions 属性,,这些表达式必须都为 true 才能和 Pod 进行匹配。
最后也可以删除定义的 ReplicaSet:
$ kubectl delete rs nginx
replicaset.extensions "nginx" deleted
在删除 nginx ReplicaSet 时也会删除对应匹配的所有 Pod。
4.2 后台支撑服务集(DaemonSet)
ReplicaSet 用于在 Kubernetes 集群上运行部署特定数量的 Pod,如果你希望在集群的每个 Node 上都运行某个 Pod,这个时候就需要使用到 DaemonSet 了,当有节点加入集群时,会为它们新增一个 Pod。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。通常这种情况下这种 Pod 都是执行系统级别与基础结构相关的操作,比如网络路由、存储、日志或是监控等。
DaemonSet 的使用情况分为两种:
- 在每个节点上运行一个 Pod
- 在特定的节点上运行一个 Pod
在每个节点上运行一个 Pod
对于采用 kubeadm-dind 部署方式而言,后面创建 Pod 运行 MySQL 会不成功,会有相关报错如下所示:ERROR: mysqld failed whilmysqld: error while loading shared libraries: libpthread.so.0: cannot stat shared object: Permission denied
,主要原因是在 dind 环境中 MySQL 的权限问题,执行如下命令可以暂时在开发环境中解决这个问题:
sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
在 /home/shiyanlou
目录下新建 mysql-ds.yaml
,并向其中写入如下代码:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: mysql-ds
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
然后执行创建:
$ docker pull mysql:5.7
$ kubectl create -f mysql-ds.yaml
daemonset.apps/mysql-ds created
观察 Pod 是否分布到了每个节点上:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-master Ready master 8d v1.15.0
kube-node-1 Ready <none> 8d v1.15.0
kube-node-2 Ready <none> 8d v1.15.0
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-ds-fmtcr 1/1 Running 0 5m50s 10.244.2.11 kube-node-1 <none> <none>
mysql-ds-mkwn2 1/1 Running 0 5m50s 10.244.3.9 kube-node-2 <none> <none>
nginx-gpu 1/1 Running 0 52m 10.244.2.5 kube-node-1 <none> <none>
在特定的节点上运行一个 Pod
如果想要使用 DaemonSet 只在特定的节点上运行 Pod,只需要在模板中的 nodeSelector 属性中指明即可。
环境中有两个节点,分别名为 kube-node-1 和 kube-node-2,我们先将 kube-node-1 打上标签 disk1=ssd1:
$ kubectl label node kube-node-1 disk1=ssd1
node/kube-node-1 labeled
然后在 /home/shiyanlou
目录下新建 tomcat-ssd.yaml
,并向其中写入如下代码:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: tomcat-ssd
spec:
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
nodeSelector:
disk1: ssd1
containers:
- name: tomcat
image: kubeguide/tomcat-app:v1
执行创建并观察新建的 ds 和 Pod:
$ kubectl create -f tomcat-ssd.yaml
daemonset.apps/tomcat-ssd created
$ kubectl get ds
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
mysql-ds 2 2 2 2 2 <none> 9m
tomcat-ssd 1 1 1 1 1 disk1=ssd1 37s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-ds-fmtcr 1/1 Running 6 10m
mysql-ds-mkwn2 1/1 Running 6 10m
nginx-gpu 1/1 Running 0 58m
tomcat-ssd-sqswr 1/1 Running 0 1m
那么如果 kube-node-1 这个节点上的标签打错了,我们将其修改为 disk1=hdd,使用 DaemonSet 创建的 Pod 还存在吗?让我们试试:
$ kubectl label node kube-node-1 disk1=hdd --overwrite
node/kube-node-1 labeled
然后运行在节点上的 Pod:
$ kubectel get pod
NAME READY STATUS RESTARTS AGE
mysql-ds-fmtcr 1/1 Running 9 27m
mysql-ds-mkwn2 1/1 Running 9 27m
nginx-gpu 1/1 Running 0 1h
可以看到该 Pod 已经终止了。
4.3 任务(Job)
前面介绍的 ReplicaSet 和 DaemonSet 监控管理的 Pod 会持续不断的运行任务,这样的任务是没有完成态的,如果其中的进程退出了 Pod 会重新启动。如果我们想要执行一个可完成的任务,当进程终止后 Pod 不再重新启动,那么就需要使用任务(Job)。
当节点发生故障的时候,该节点上由 Job 管理的 Pod 会按照 ReplicaSet 的 Pod 的方式,重新安排到其它节点;如果进程异常退出,可以将 Job 配置为重新启动容器。
现在我们来模拟一个任务,有一个构建在 busybox 上的容器,该容器会调用 sleep 命令休息两分钟,然后就正常退出。
在 /home/shiyanlou
目录下新建 sleep.yaml
文件并向其中写入如下代码:
apiVersion: batch/v1
kind: Job
metadata:
name: batch-job
spec:
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
其中的 restartPolicy 属性定义了当容器中的进程运行结束时 Kubernetes 会如何做,默认的值为 Always,表示的是重新启动并运行;所以在使用 Job 时我们必须修改为 OnFailure 或是 Never。
执行创建:
$ kubectl create -f sleep.yaml
job.batch/batch-job created
查看 Job 和 Pod:
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
batch-job 0/1 17s 17s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
batch-job-zknt4 1/1 Running 0 1m
mysql-ds-fmtcr 1/1 Running 0 30m
mysql-ds-mkwn2 1/1 Running 0 30m
nginx-gpu 1/1 Running 0 1h
等待两分钟,当任务执行完成后再重看一次:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
batch-job-zknt4 0/1 Completed 0 4m
mysql-ds-fmtcr 1/1 Running 0 33m
mysql-ds-mkwn2 1/1 Running 0 33m
nginx-gpu 1/1 Running 0 1h
$ kubectl get job
NAME COMPLETIONS DURATION AGE
batch-job 1/1 2m8s 7m17s
如果你想要一项任务按顺序依次执行 10 次,可以使用 completions 属性:
spec:
completions: 10
template: ...
如果你想要一项任务总共运行 10 次,每次可以并行执行 3 个 Pod,可以使用 parallelism 属性:
spec:
completions: 10
parallelism: 3
template: ...
5.实验总结
在这个实验中,我们主要围绕 Kubernetes 中的最小核心概念 Pod 进行了详细的讲解,其中包括 Pod 简介、创建 Pod 和删除 Pod,还有使用命名空间(Namespace) 对不同的 Pod 进行隔离。对 Pod 进行操作就涉及到一个很重要的概念:标签和标签选择器,正是它们使我们可以很轻松的选择出所需要的 Pod。
然后还介绍了对 Pod 进行管理的副本集(RS)、后台支撑服务集(DaemonSet)、以及任务(Job),这是 Kubernetes 中非常重要的工作机制,这样才能够实现自动托管 Pod,保证任务可以连续正常的运行。
本文由 liyunfei 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 29,2022