八、Kubernetes 入门实践
本文是《Docker必知必会系列》第八篇,原文发布于个人博客:悟尘纪。
Kubernetes 介绍
Kubernetes (K8s) 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务。是目前最主流的容器化管理平台,获得各大主流云服务厂商支持。
Kubernetes 基于 Google 在大规模运行生产经验技术基础上,结合社区中最好的想法和实践构建的开源平台。
为什么需要 Kubernetes
在生产环境中,您需要管理运行应用程序的容器,并确保不会停机。例如,如果一个容器发生故障,则需要启动另一个容器。如果有个系统工具来处理这些需求,会不会更容易?这就是 Kubernetes!
Kubernetes 为您提供了一个可弹性运行分布式系统的框架。满足您的扩展、故障转移、部署模式等要求。
Kubernetes 为您提供:
-
服务发现和负载均衡
Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,并提供负载均衡来分配网络流量。 -
存储编排
Kubernetes 允许您自动挂载您选择的存储系统,例如本地存储、公共云提供商等。 -
自动部署和回滚
您可以使用 Kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态更改为所需状态。例如,Kubernetes 可以自动化为您的部署创建新容器,删除现有容器并将它们的所有资源用于新容器。 -
自动二进制打包
Kubernetes 允许您指定每个容器所需 CPU 和内存(RAM)。当容器指定了资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。 -
自我修复
Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器,并且在准备好服务之前不将其通告给客户端。 -
密钥与配置管理
Kubernetes 允许您存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。您可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
Kubernetes 不是传统的、包罗万象的 PaaS(平台即服务)系统。Kubernetes 提供了构建开发人员平台的基础,但是在重要的地方保留了用户的选择和灵活性。很多云服务商基于K8s来构建自己的PaaS平台。
部署 Kubernetes
您可以在本地机器、云、本地数据中心上部署 Kubernetes 集群,或选择一个托管的 Kubernetes 集群。还可以跨各种云提供商或裸机环境创建自定义解决方案。
为了学习 Kubernetes,建议使用基于 Docker 的解决方案:Docker 是 Kubernetes 社区支持或生态系统中用来在本地计算机上设置 Kubernetes 集群的一种工具。如果是为了生产环境,您应该认真评估适当的解决方案,具体请参照官方文档。
Docker Desktop 启用 Kubernetes
在 Docker Desktop 的 Preferences
页面,点击 Kubernetes
,选择 Enable Kubernetes
,待左下角的 Kubernetes
状态变为 running
时,Kubernetes 即已启动成功。
在控制台执行 kubectl version
,能够正常输出信息,则说明Kubernetes 已经成功启动。
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", GitTreeState:"clean", BuildDate:"2020-01-15T08:26:26Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", GitTreeState:"clean", BuildDate:"2020-01-15T08:18:29Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}
安装 Dashboard
Dashboard 是官方提供的基于网页的 Kubernetes 用户管理界面。您可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。您可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源(如 Deployment,Job,DaemonSet 等等)。例如,您可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。
默认情况下不会部署 Dashboard。可以通过以下命令部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
在要访问 Dashboard 的机器上执行 kubectl proxy
命令,然后就可以通过 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
地址访问 Dashboard了。
当前,Dashboard 仅支持使用 Bearer 令牌登录。 接下来,我们将创建一个名为 admin-user
的服务账号,并为其创建 ClusterRoleBinding。
将以下内容复制到 dashboard-adminuser.yaml
文件中。
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
然后执行:
kubectl apply -f dashboard-adminuser.yaml
找到可以用来登录的令牌:
$ kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
Name: admin-user-token-8mgwp
Namespace: kubernetes-dashboard
Labels: <none>
Annotations: kubernetes.io/service-account.name: admin-user
kubernetes.io/service-account.uid: c32b99ea-a002-4e00-afdf-58ce40fbe5eb
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 20 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkJPNFJmTFJ1ajBKYm4xMGpvV01vYnRRSDdzRnFmd1ZsbUpPQ0lvdFNJWFkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3......povxntPXVTJomVTN7mJ-6vBm8m-kCUF6nxA14c8s5Kis22XPGyPgiUmXNAagXJPJH3cFVO0exs5JVzdj3gtvRXQ
复制 token
并将其粘贴到登录屏幕上的 Token
字段中。点击登录按钮,就可以以管理员身份登录了。
Kubernetes 入门实践
一旦运行了 Kubernetes 集群,就可以在其上部署容器化应用程序。 为此,您需要创建 Kubernetes Deployment 配置。Deployment 指挥 Kubernetes 如何创建和更新应用程序的实例。创建 Deployment 后,Kubernetes master 将应用程序实例调度到集群中的各个节点上。
创建应用程序实例后,Kubernetes Deployment 控制器会持续监视这些实例。 如果托管实例的节点关闭或被删除,则 Deployment 控制器会将该实例替换为群集中另一个节点上的实例。 这提供了一种自我修复机制来解决机器故障维护问题。
环境检查
通过运行 kubectl version
命令,检查 kubectl 是否已配置为与您的集群通信。运行 kubectl get nodes
命令,查看集群中的节点及pods。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
docker-desktop Ready master 112m v1.16.6-beta.0
$ kubectl get pods
No resources found in default namespace.
在这里,我们看到可用的节点(本例中为1)。 Kubernetes 将根据 Node 可用资源选择将我们的应用程序部署到何处。
基于kubectl部署第一个应用
让我们使用 kubectl create deploy
命令在 Kubernetes 上部署我们的第一个应用程序。
创建一个名为 k8s-nginx 的 deployment(需要提供部署名称和应用程序镜像位置):
$ kubectl create deployment --image nginx k8s-nginx
deployment.apps/k8s-nginx created
查看正在运行的 pods,会看到只有一个 pods 正在运行:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-nginx-5c86f54778-92824 0/1 ContainerCreating 0 11s
查看创建的 deployment:
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
k8s-nginx 0/1 1 0 24s
扩展部署,让 2 个 nginx pods 同时运行:
$ kubectl scale deployment --replicas 2 k8s-nginx
deployment.apps/k8s-nginx scaled
列出 pods ,会看到已经变成 2 个 pods 正在运行:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-nginx-5c86f54778-92824 0/1 Running 0 67s
k8s-nginx-5c86f54778-j7dch 0/1 Running 0 6s
将 pods 暴露到互联网上:
kubectl expose deployment k8s-nginx --port=8086 --type=LoadBalancer
service/k8s-nginx exposed
查看已经创建的服务,获取服务地址:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-nginx LoadBalancer 10.100.197.113 <none> 8086/TCP 74s
要清理这两个自动复制的容器,需要删除 deployment:
$ kubectl delete deployment k8s-nginx
deployment.apps "k8s-nginx" deleted
# 再次列出 pods 会发现容器已经被清理。
$ kubectl get pods
No resources found in default namespace.
基于 Deployments 管理应用
可以通过创建一个Kubernetes Deployment 对象来运行一个应用,在YAML文件中描述Deployment。
首先,创建 deployment 描述文件 k8s-nginx-deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-nginx-deployment # 创建名为 k8s-nginx-deployment 的 Deployment
labels:
app: k8s-nginx
spec:
replicas: 3 # 创建 3 个 Pods
selector: # 定义 Deployment 如何查找要管理的 Pods
matchLabels:
app: k8s-nginx
template:
metadata:
labels: # 将 Pod 标记为 k8s-nginx
app: k8s-nginx
spec:
containers:
- name: k8s-nginx # 指定创建的容器名字为 k8s-nginx
image: nginx # 指定运行 Docker Hub 中 nginx 最新版本镜像
ports: # 暴露端口
- containerPort: 8189
通过 kubectl apply
命令创建 Deployment:
$ kubectl apply -f k8s-nginx-deployment.yaml
deployment.apps/k8s-nginx-deployment created
运行 kubectl get deployments
以检查 Deployment 是否已创建:
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
k8s-nginx-deployment 3/3 3 3 47s
几秒钟后,Deployment 已创建所有三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板)并且可用。
更新 Deployment
让我们更新 nginx Pods,以使用 nginx:1.9.1
镜像 ,而不是最新版本 。
$ kubectl --record deployment.apps/k8s-nginx-deployment set image deployment.v1.apps/k8s-nginx-deployment k8s-nginx=nginx:1.9.1
deployment.apps/k8s-nginx-deployment image updated
deployment.apps/k8s-nginx-deployment image updated
查看状态更新:
$ kubectl rollout status deployment.v1.apps/k8s-nginx-deployment
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "k8s-nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "k8s-nginx-deployment" successfully rolled out
更新成功后,可以通过运行 kubectl get deployments
来查看 Deployment 。
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
k8s-nginx-deployment 3/3 3 3 14m
运行 get pods
现在应仅显示新的 Pods:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-nginx-deployment-785b758787-jsbtl 1/1 Running 0 2m31s
k8s-nginx-deployment-785b758787-xdsl4 1/1 Running 0 4m12s
k8s-nginx-deployment-785b758787-zxd7b 1/1 Running 0 2m28s
下次要更新这些 Pods 时,只需再次更新 Deployment Pod 模板。
Deployment 可确保在更新时仅关闭一定数量的 Pods。默认情况下,它确保至少 75%所需 Pods 运行(25%最大不可用)。Deployment 还确保仅创建一定数量的 Pods 高于期望的 Pods 数。默认情况下,它可确保最多增加 25% 期望 Pods 数(25%最大增量)。
如果仔细查看上述 Deployment ,将看到它首先创建了一个新的 Pod,然后删除了一些旧的 Pods,并创建了新的 Pods。它不会杀死老 Pods,直到有足够的数量新的 Pods 已经出现,并没有创造新的 Pods,直到足够数量的旧 Pods 被杀死。它确保至少 2 个 Pods 可用,并且总共最多 4 个 Pods 可用。
获取 Deployment 的更多信息
$ kubectl describe deployments
kubectl describe deployments
Name: k8s-nginx-deployment
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 16m deployment-controller Scaled up replica set k8s-nginx-deployment-99f6477fd to 3
Normal ScalingReplicaSet 6m39s deployment-controller Scaled up replica set k8s-nginx-deployment-785b758787 to 1
Normal ScalingReplicaSet 4m57s deployment-controller Scaled down replica set k8s-nginx-deployment-99f6477fd to 2
Normal ScalingReplicaSet 4m57s deployment-controller Scaled up replica set k8s-nginx-deployment-785b758787 to 2
Normal ScalingReplicaSet 4m54s deployment-controller Scaled down replica set k8s-nginx-deployment-99f6477fd to 1
Normal ScalingReplicaSet 4m54s deployment-controller Scaled up replica set k8s-nginx-deployment-785b758787 to 3
Normal ScalingReplicaSet 4m49s deployment-controller Scaled down replica set k8s-nginx-deployment-99f6477fd to 0
可以看到,当第一次创建 Deployment 时,它创建了一个 ReplicaSet (nginx-deployment-99f6477fd)并将其直接扩展至 3 个副本。更新 Deployment 时,它创建了一个新的 ReplicaSet (nginx-deployment-785b758787),并将其扩展为 1,然后将旧 ReplicaSet 缩小到 2,以便至少有 2 个 Pod 可用,并且最多创建 4 个 Pod。然后,它继续向上和向下扩展新的和旧的 ReplicaSet ,具有相同的滚动更新策略。最后,将有 3 个可用的副本在新的 ReplicaSet 中,旧 ReplicaSet 将缩小到 0。
有时,可能需要回滚 Deployment ;例如,当 Deployment 不稳定时,例如循环崩溃。默认情况下,所有 Deployment 历史记录都保留在系统中,以便可以随时回滚(可以通过修改修改历史记录限制来更改该限制)。
也可以通过设置自动缩放器,基于现有 Pods 的 CPU 利用率设置要运行 Pods的最小和最大值。
还可以在触发一个或多个更新之前暂停 Deployment ,然后继续它。这允许在暂停和恢复之间应用多个修补程序,而不会触发不必要的 Deployment 。
关于 Deployment 的更多信息,请查阅官方文档:Deployments
参考
- 官方文档:Kubernetes 文档
- 官方文档:Creating sample user