基于 Kubernetes 的云原生 DevOps 第 4 章 Kubernetes 对象
🏷️ Kubernetes 《基于 Kubernetes 的云原生 DevOps》
I can't understand why people are frightened of new ideas. I'm frightened of the old ones.
-- John Cage
4.1 部署
部署的工作是监视与其关联的容器,并确保指定数量的容器始终处于运行状态。如果数量太少,则启动更多容器。如果数量太多,则终止一些容器。
与部署资源配合使用的是一种名为控制器的 Kubernetes 组件。控制器会监视它们负责的资源,确保资源存在并正常工作。
实际上,部署并不会直接管理副本,它会自动创建一个名为 副本集(ReplicaSet) 的关联对象来处理。
创建部署文件(myhello.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: myhello
labels:
app: myhello
spec:
replicas: 1
selector:
matchLabels:
app: myhello
template:
metadata:
labels:
app: myhello
spec:
containers:
- name: demo
image: jiajiablog/myhello
ports:
- containerPort: 8888
---
apiVersion: v1
kind: Service
metadata:
name: myhello
labels:
app: myhello
spec:
ports:
- port: 8888
protocol: TCP
targetPort: 8888
selector:
app: myhello
type: ClusterIP
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
应用部署:
kubectl apply -f .\myhello.yaml
查询部署(当前命名空间):
kubectl get deployments
查看特定部署的更多详细信息:
kubectl describe deployments/myhello
4.2 Pod
Pod 是 Kubernetes 对象,代表一组(一个或多个)容器(Pod 也有一群鲸鱼的意思,非常符合 Kubernetes 隐含的依稀航海风)。
为什么部署不直接管理各个容器呢?原因在于,有时我们需要将一组容器调度到一起,在同一个节点上运行,并在本地通信或共享存储。
Pod 规范拥有一个 Containers 列表。
使用 kubectl run
命令并不会直接创建 Pod。它创建了一个部署,然后部署启动了 Pod。
JiaJia
这里和我实际运行的结果不一致。本地使用的是 minikube,通过 kubectl run
命令启动容器时,仅创建了 Pod,没有自动创建部署。
PS C:\k8s> kubectl run myhello --image=jiajiablog/myhello --port=9999 --labels app=myhello
pod/myhello created
2
根据消息就能看到只创建了 pod/myhello ,没有创建部署。
不知道是因为使用的是 minikube 还是 kubectl run
命令有改动导致的。
想要创建部署,可以参考前一小节中的部署示例。
先创建部署用的 Yaml 文件,然后通过 kubectl apply
命令应用部署。
4.3 副本集
副本集(ReplicaSet) 负责直接管理 Pod。副本集负责一组相同的 Pod(即副本, replica)。
部署则管理副本集,并控制副本更新时的行为。在更新部署时,创建一个新的副本集来管理新的 Pod,更新完成后,再终止旧的副本集及其 Pod。
4.4 维持所需状态
Kubernetes 控制器会不断根据集群的实际状态检查每个资源指定的所需状态,并进行必要的调整以保证二者的同步。这个过程叫做协调循环。
获取 Pod 信息:
kubectl get pods --selector app=myhello
停止 Pod:
kubectl delete pods --selector app=myhello
关闭并清理资源:
kubectl delete all --selector app=myhello
4.5 Kubernetes 调度器
当部署通过管理的副本集判断出需要一个新副本时,它就会在 Kubernetes 数据库中创建 Pod 资源。同时,这个 Pod 会被添加到队列中,而这个队列相当于调度器的收件箱。
调度器的工作是监视未调度的 Pod 队列,从中获取下一个 Pod,并找到一个节点来运行。它会根据一系列不同的条件来选择合适的节点。
在 Pod 被调度到某个节点后,该节点上运行的 kubelet 就会启动它的容器。
4.6 YAML 格式的资源清单
所有的 Kubernetes 资源(比如部署或 Pod)都有内部数据库中的记录表示。协调循环会监视数据库中记录的变动,并采取适当的措施。实际上,kubectl run
命令只是在数据库中添加一个与部署相对应的新纪录,其余的工作都是由 Kubernetes 完成的。
你可以直接创建和编辑资源清单(manifest,即资源所需状态的规范)。你可以将清单文件保存在版本控制系统中,修改清单文件,然后告诉 Kubernetes 读取更新后的数据,这样就不需要通过命令修改规范了。
Kubernetes 清单文件的常用格式是 YAML,尽管 JSON 格式也可以接受。
这是一个清单文件的示例(myhello.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: myhello
labels:
app: myhello
spec:
replicas: 1
selector:
matchLabels:
app: myhello
template:
metadata:
labels:
app: myhello
spec:
containers:
- name: demo
image: jiajiablog/myhello
ports:
- containerPort: 8888
---
apiVersion: v1
kind: Service
metadata:
name: myhello
labels:
app: myhello
spec:
ports:
- port: 8888
protocol: TCP
targetPort: 8888
selector:
app: myhello
type: ClusterIP
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
虽然乍一看貌似非常复杂,但其实大部分都是样板代码。
使用 kubectl apply
应用部署。
kubectl apply -f .\myhello.yaml
服务资源可以提供一个不变的 IP 地址或 DNS 名称,并自动路由到与之匹配的 Pod 上。9.6 节还会介绍 Ingress 资源,该资源允许使用更高级的路由,并且还可以使用 TLS 证书。
你可以将服务当成 Web 代理或负载均衡器,复杂将请求转发到一组后端的 Pod 上。但是,服务并非只能用于 Web 端口,它可以将流量从任意端口转发到其它端口。
上面 myhello.yaml 的第二部分就是一个服务资源的 YAML 清单:
apiVersion: v1
kind: Service
metadata:
name: myhello
labels:
app: myhello
spec:
ports:
- port: 8888
protocol: TCP
targetPort: 8888
selector:
app: myhello
type: ClusterIP
2
3
4
5
6
7
8
9
10
11
12
13
14
该清单将 8888 端口转发到 Pod 的 8888 端口。
selector 部分告诉服务如何将请求路由到特定的 Pod 上。请求会被转发到所有与指定的标签集匹配的 Pod 上,这里的标签是 app: myhello 。
如果匹配到多个 Pod,则服务会将请每个请求发送到一个随机选择的 Pod 上。
从这个角度看,Kubernetes 的服务有点像传统的负载均衡器,实际上,服务和 Ingress 都可以自动创建云负载均衡器。
目前只需记住,部署负责管理应用程序的一组 Pod,而服务提供请求这些 Pod 的入口。
连接本地计算机的 9999 端口到 service/myhello :
kubectl port-forward service/myhello 9999:8888
此时就可以访问 http://localhost:9999/ 了。
测试完后,删除 myhello.yaml 文件中配置的服务资源:
kubectl delete -f .\myhello.yaml
kubectl 工具是 Kubernetes 界的“瑞士军刀”:它可以配置、创建、修改和销毁资源,还可以查询集群以获取有关现有资源及其状态的信息。
查看集群节点信息:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane,master 3d4h v1.22.3
2
查看集群所有信息:
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/myhello-7558759cdf-4wjk5 1/1 Running 0 109s
pod/myhello-7558759cdf-mt5sx 1/1 Running 0 24m
pod/myhello-7558759cdf-xql9v 1/1 Running 0 109s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d4h
service/myhello ClusterIP 10.99.255.0 <none> 8888/TCP 24m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/myhello 3/3 3 3 24m
NAME DESIRED CURRENT READY AGE
replicaset.apps/myhello-7558759cdf 3 3 3 24m
2
3
4
5
6
7
8
9
10
11
12
13
14
查看某个 Pod 的综合信息:
kubectl describe pod/myhello-7558759cdf-4wjk5
Name: myhello-7558759cdf-4wjk5
Namespace: default
Priority: 0
Node: minikube/192.168.49.2
Start Time: Thu, 09 Dec 2021 16:18:25 +0800
Labels: app=myhello
pod-template-hash=7558759cdf
Annotations: <none>
Status: Running
IP: 172.17.0.6
IPs:
IP: 172.17.0.6
Controlled By: ReplicaSet/myhello-7558759cdf
Containers:
demo:
Container ID: docker://705035ea038f07581ae5c94af4febb79120772220fcad0f1d2200719d002b34b
Image: jiajiablog/myhello
Image ID: docker-pullable://jiajiablog/myhello@sha256:dd18397fc935cd335733de5b52f0fcffb0e15713fea5327915a7800035b151b9
Port: 8888/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 09 Dec 2021 16:18:37 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-58mfs (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-58mfs:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m43s default-scheduler Successfully assigned default/myhello-7558759cdf-4wjk5 to minikube
Normal Pulling 4m42s kubelet Pulling image "jiajiablog/myhello"
Normal Pulled 4m31s kubelet Successfully pulled image "jiajiablog/myhello" in 10.4313314s
Normal Created 4m31s kubelet Created container demo
Normal Started 4m31s kubelet Started container demo
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
4.7 Helm:Kubernetes 包管理器
Kubernetes 有一款流行的包管理器叫做 Helm。
你可以使用 helm 命令行工具来按照和配置应用程序,而且还可以创建名为 Helm Chart 的软件包,通过该软件包指定运行应用程序所需的资源、依赖项以及可配置的设置。
安装 Helm
官方文档:安装 Helm:我这里是 Windows 系统,先安装 Chocolatey 的客户端,再通过 Chocolatey 安装 Helm。
使用 cmd 安装(管理员权限运行) Chocolatey :
使用 PowerShell 安装(管理员权限运行) Chocolatey :
安装 kubernetes-helm :
最终还是要从官方网站的地址下载文件,一直失败,遂放弃。
分享下已下载的 3.7.2 版本的 Windows 版的 zip 文件:https://kdocs.cn/l/sl00U5gMGdLH
自行验证文件哈希 Helm 3.7.2:
PS C:\k8s> certutil -hashfile ./helm-v3.7.2-windows-amd64.zip sha256
SHA256 的 ./helm-v3.7.2-windows-amd64.zip 哈希:
299165f0af46bece9a61b41305cca8e8d5ec5319a4b694589cd71e6b75aca77e
CertUtil: -hashfile 命令成功完成。
2
3
4
下载解压后把 helm.exe 的文件目录加入 Path 环境变量。
查看版本:
PS C:\k8s> helm version
version.BuildInfo{Version:"v3.7.2", GitCommit:"663a896f4a815053445eec4153677ddc24a0a361", GitTreeState:"clean", GoVersion:"go1.16.10"}
2
示例仓库中的 hello-helm3 目录下有作者提供的 Chart 示例(12.1 节会介绍这些文件的用途):
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> ls .\k8s\demo\
目录: C:\projects\github\cloudnativedevops\demo\hello-helm3\k8s\demo
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/11/18 17:39 templates
-a---- 2021/11/18 17:39 91 Chart.yaml
-a---- 2021/11/18 17:39 25 production-values.yaml
-a---- 2021/11/18 17:39 22 staging-values.yaml
-a---- 2021/11/18 17:39 121 values.yaml
2
3
4
5
6
7
8
9
10
11
12
13
删除所有 demo 资源:
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> kubectl delete all --selector app=demo
No resources found
2
部署服务:
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm install demo .\k8s\demo\
NAME: demo
LAST DEPLOYED: Fri Dec 10 14:10:15 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
2
3
4
5
6
7
在 minikube dashboard 上搜索 demo 可以看到除了之前创建过的资源之外,还多了一个名为 sh.helm.release.v1.demo.v1 的 Secret。
更新服务(无论是否有改动,REVISION 都会加 1):
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm upgrade demo .\k8s\demo\
Release "demo" has been upgraded. Happy Helming!
NAME: demo
LAST DEPLOYED: Fri Dec 10 14:16:30 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
2
3
4
5
6
7
8
Helm 三大术语:
- Chart:一个 Helm 包,其中包含在 K8s 中运行应用程序所需的所有资源定义。
- Repository:收集和共享 Chart 的地方。
- Release:在 K8s 集群中运行的 Chart 的一个实例。
通常一个 Chart 可以多次安装到一个集群中。Chart 的每个单独的实例都是一个不同的 Release 。
每个 Release 有一个唯一的名字,可以在 helm install
中通过 -name 标志指定。
查看正在运行的 Release :
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
demo default 5 2021-12-10 14:19:44.7023829 +0800 CST deployed demo-1.0.1
2
3
查看指定 Release 的状态:
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm status demo
NAME: demo
LAST DEPLOYED: Fri Dec 10 14:19:44 2021
NAMESPACE: default
STATUS: deployed
REVISION: 5
TEST SUITE: None
2
3
4
5
6
7
可以通过 GitHub 查看公共 Helm Chart 的完整列表:https://github.com/helm/charts/tree/master/stable。
还可以运行 helm search repo
命令,不带任何参数,来获取所有可以使用的 Chart 列表。
JiaJia: 本地运行失败了,看消息估计是少了配置的步骤。
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm search repo
Error: no repositories configured
2
可以使用 helm search redis
搜索 Redis 的 Chart :
JiaJia: 运行仍然报错了,貌似还是配置问题。
PS C:\k8s> helm search redis
Search provides the ability to search for Helm charts in the various places
they can be stored including the Artifact Hub and repositories you have added.
Use search subcommands to search different locations for charts.
2
3
4
5
4.8 小结
- Pod 是 Kubernetes 的基本工作单元,代表一个或一组调度到一起可相互通信的容器。
- 部署是 Kubernetes 的高级资源,可通过声明式的方式管理 Pod,并在必要时部署、调度、更新和重新启动 Pod。
- Kubernetes 的服务相当于负载均衡器或代理,它通过一个众所周知的持久 IP 地址或 DNS 名,将流量路由到与其匹配的 Pod 上。
- Kubernetes 的调度器会监视尚未在任何节点上运行的 Pod,为其找到合适的节点,并指示该节点上的 kubelet 运行 Pod。
- 部署等资源由 Kubernetes 内部数据库的记录表示。在外部,这些资源可由 YAML 格式的外部文件(即清单)表示。清单是所需资源状态的声明。
- kubectl 是与 Kubernetes 进行交互的主要工具,你可以利用应用清单、查询资源、更改资源、删除资源或执行其它各项任务。
- Helm 是 Kubernetes 的包管理器。它简化了 Kubernetes 应用程序的配置和部署,你可以使用一组值(比如应用程序的名称或监听端口)和一组模板来生成 Kubernetes YAML 文件,从而避免手动维护原始 YAML 文件的工作。