Skip to content

基于 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):

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

应用部署:

powershell
kubectl apply -f .\myhello.yaml

查询部署(当前命名空间):

powershell
kubectl get deployments

查看特定部署的更多详细信息:

powershell
kubectl describe deployments/myhello

4.2 Pod

Pod 是 Kubernetes 对象,代表一组(一个或多个)容器(Pod 也有一群鲸鱼的意思,非常符合 Kubernetes 隐含的依稀航海风)。

为什么部署不直接管理各个容器呢?原因在于,有时我们需要将一组容器调度到一起,在同一个节点上运行,并在本地通信或共享存储。

Pod 规范拥有一个 Containers 列表。

使用 kubectl run 命令并不会直接创建 Pod。它创建了一个部署,然后部署启动了 Pod。

JiaJia

这里和我实际运行的结果不一致。本地使用的是 minikube,通过 kubectl run 命令启动容器时,仅创建了 Pod,没有自动创建部署。

powershell
PS C:\k8s> kubectl run myhello --image=jiajiablog/myhello --port=9999 --labels app=myhello
pod/myhello created

根据消息就能看到只创建了 pod/myhello ,没有创建部署。
不知道是因为使用的是 minikube 还是 kubectl run 命令有改动导致的。
想要创建部署,可以参考前一小节中的部署示例。
先创建部署用的 Yaml 文件,然后通过 kubectl apply 命令应用部署。

4.3 副本集

副本集(ReplicaSet 负责直接管理 Pod。副本集负责一组相同的 Pod(即副本, replica)。

部署则管理副本集,并控制副本更新时的行为。在更新部署时,创建一个新的副本集来管理新的 Pod,更新完成后,再终止旧的副本集及其 Pod。

4.4 维持所需状态

Kubernetes 控制器会不断根据集群的实际状态检查每个资源指定的所需状态,并进行必要的调整以保证二者的同步。这个过程叫做协调循环

获取 Pod 信息:

powershell
kubectl get pods --selector app=myhello

停止 Pod:

powershell
kubectl delete pods --selector app=myhello

关闭并清理资源:

powershell
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):

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

虽然乍一看貌似非常复杂,但其实大部分都是样板代码。

使用 kubectl apply 应用部署。

powershell
kubectl apply -f .\myhello.yaml

服务资源可以提供一个不变的 IP 地址或 DNS 名称,并自动路由到与之匹配的 Pod 上。9.6 节还会介绍 Ingress 资源,该资源允许使用更高级的路由,并且还可以使用 TLS 证书。

你可以将服务当成 Web 代理或负载均衡器,复杂将请求转发到一组后端的 Pod 上。但是,服务并非只能用于 Web 端口,它可以将流量从任意端口转发到其它端口。

上面 myhello.yaml 的第二部分就是一个服务资源的 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

该清单将 8888 端口转发到 Pod 的 8888 端口。
selector 部分告诉服务如何将请求路由到特定的 Pod 上。请求会被转发到所有与指定的标签集匹配的 Pod 上,这里的标签是 app: myhello
如果匹配到多个 Pod,则服务会将请每个请求发送到一个随机选择的 Pod 上。

从这个角度看,Kubernetes 的服务有点像传统的负载均衡器,实际上,服务和 Ingress 都可以自动创建云负载均衡器。

目前只需记住,部署负责管理应用程序的一组 Pod,而服务提供请求这些 Pod 的入口。

连接本地计算机的 9999 端口到 service/myhello

powershell
kubectl port-forward service/myhello 9999:8888

此时就可以访问 http://localhost:9999/ 了。

测试完后,删除 myhello.yaml 文件中配置的服务资源:

powershell
kubectl delete -f .\myhello.yaml

kubectl 工具是 Kubernetes 界的“瑞士军刀”:它可以配置、创建、修改和销毁资源,还可以查询集群以获取有关现有资源及其状态的信息。

查看集群节点信息:

powershell
kubectl get nodes
powershell
NAME       STATUS   ROLES                  AGE    VERSION
minikube   Ready    control-plane,master   3d4h   v1.22.3

查看集群所有信息:

powershell
kubectl get all
powershell
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

查看某个 Pod 的综合信息:

powershell
kubectl describe pod/myhello-7558759cdf-4wjk5
powershell
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

4.7 Helm:Kubernetes 包管理器

Kubernetes 有一款流行的包管理器叫做 Helm

你可以使用 helm 命令行工具来按照和配置应用程序,而且还可以创建名为 Helm Chart 的软件包,通过该软件包指定运行应用程序所需的资源、依赖项以及可配置的设置。

安装 Helm

官方文档:安装 Helm我这里是 Windows 系统,先安装 Chocolatey 的客户端,再通过 Chocolatey 安装 Helm

使用 cmd 安装(管理员权限运行) Chocolatey

```bash @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "[System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" ```

使用 PowerShell 安装(管理员权限运行) Chocolatey

```powershell Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) ```

安装 kubernetes-helm

```powershell choco install kubernetes-helm -y ```

最终还是要从官方网站的地址下载文件,一直失败,遂放弃。

分享下已下载的 3.7.2 版本的 Windows 版的 zip 文件:https://kdocs.cn/l/sl00U5gMGdLH

自行验证文件哈希 Helm 3.7.2

powershell
PS C:\k8s> certutil -hashfile ./helm-v3.7.2-windows-amd64.zip sha256
SHA256 的 ./helm-v3.7.2-windows-amd64.zip 哈希:
299165f0af46bece9a61b41305cca8e8d5ec5319a4b694589cd71e6b75aca77e
CertUtil: -hashfile 命令成功完成。

下载解压后把 helm.exe 的文件目录加入 Path 环境变量。

查看版本:

powershell
PS C:\k8s> helm version
version.BuildInfo{Version:"v3.7.2", GitCommit:"663a896f4a815053445eec4153677ddc24a0a361", GitTreeState:"clean", GoVersion:"go1.16.10"}

示例仓库中的 hello-helm3 目录下有作者提供的 Chart 示例(12.1 节会介绍这些文件的用途):

powershell
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

删除所有 demo 资源:

powershell
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> kubectl delete all --selector app=demo
No resources found

部署服务:

powershell
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

minikube dashboard 上搜索 demo 可以看到除了之前创建过的资源之外,还多了一个名为 sh.helm.release.v1.demo.v1Secret

更新服务(无论是否有改动,REVISION 都会加 1):

powershell
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

Helm 三大术语:

  • Chart:一个 Helm 包,其中包含在 K8s 中运行应用程序所需的所有资源定义。
  • Repository:收集和共享 Chart 的地方。
  • Release:在 K8s 集群中运行的 Chart 的一个实例。

通常一个 Chart 可以多次安装到一个集群中。Chart 的每个单独的实例都是一个不同的 Release

每个 Release 有一个唯一的名字,可以在 helm install 中通过 -name 标志指定。

查看正在运行的 Release

powershell
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

查看指定 Release 的状态:

powershell
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

可以通过 GitHub 查看公共 Helm Chart 的完整列表:https://github.com/helm/charts/tree/master/stable。

还可以运行 helm search repo 命令,不带任何参数,来获取所有可以使用的 Chart 列表。

JiaJia: 本地运行失败了,看消息估计是少了配置的步骤。

powershell
PS C:\projects\github\cloudnativedevops\demo\hello-helm3> helm search repo
Error: no repositories configured

可以使用 helm search redis 搜索 RedisChart

JiaJia: 运行仍然报错了,貌似还是配置问题。

powershell
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.

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 文件的工作。