CI/CD系列 | 一文掌握Kubernetes操作

1,254 阅读11分钟

本系列将会从宏观角度,讲述CI/CD相关知识。系列文章不求把每一项都讲仔细,而是让大家能对CI/CD整体流程有大致的概念。无论你是前端,后端,或是运维团队,只要是CI/CD链路上的一份子,相信这系列文章对你都会有帮助。 阅读更多专栏文章

前言

上篇文章我们掌握了 Kubernetes 的基本概念,如果你还没有了解过 K8S ,可以先点击阅读上一篇文章《CI/CD系列 | 初探Kubernetes》

而今天,我们将从一个开发者的角度出发,快速地了解如何使用 K8S 进行服务部署,扩展,以及迭代。我们的目标是了解 K8S 的操作逻辑,以及掌握在必要时候,可以手动排查服务的能力。

文本将涉及 CI/CD 环节: 持续部署(Continuous Deployment)

准备工作

开始之前,希望大家可以区分好几个工具:

  • kubeadm: 一个启动,部署 K8S 集群的工具
  • kubelet: 一个负责管理集群中 pods 和 container 的组件
  • kubectl: 一个用户交互工具,可以连接操作集群

现在,大家还需要有一个可以运行的 K8S 环境。如果你所在的团队,可以提供测试使用的 K8S 环境。那么你只需要安装 kubectl 连接到远程的集群即可。

但如果你没有可用的 K8S 环境,或者不想影响到团队线上的环境,可以跟着我往下进行安装步骤。

安装说明

在前面的文章中我们讲到,在 K8S 中 Cluster(集群) 是由 Nodes 组成的。而 Nodes 是一个个的硬件实例(服务器,虚拟机等)。这就意味着,我们在安装 K8S 时,我们需要安装两个内容:

  1. 可以运行集群的工具
  2. 可以在 Nodes 上操作部署内容的工具—— kubectl

实际上,很多的运行集群工具都集成了 kubectl 。所以在本文我们只需要安装好集群工具就行了。而目前 K8S 的集群工具有很多,其中被官网提到的有:

  • kind:基于Docker实现,让我们在本地运行 K8S 的工具
  • minikube: 与 kind 类似,是一个轻型 K8S 集成工具
  • kubeadm: 一个更专业,与操作系统结合度更高的 K8S 集成工具

什么时候选择该 kubeadm?

由于 kubeadm 是直接安装在操作系统的,它对硬件的调度会更好,定制化程度更高。如果你是搭建生产使用的 K8S 环境,或者你是一名专业的运维工程师,都应该了解 kubeadm 的安装和使用方法。

kubeadm 的官方文档地址:kubernetes.io/docs/setup/…

kind的安装使用

但如果你跟我一样是一名开发者,只需了解 K8S 的基本使用。那么,kind 这种轻量工具会是更便捷的选择。kind 的安装方法很简单,而且兼容个个平台。你只需按照官方文档的指引安装即可。

kind 的官方文档:kind.sigs.k8s.io/docs/user/q…

需要注意的是,kind 是基于 Docker 运行的,在安装 kind 之前,你应该要先安装好 Docker。想要了解更多 Docker 相关的知识,可以阅读本系列的另一篇文章《CI/CD系统 | 一文掌握Docker镜像的构建》

集群管理

安装完 kind 之后,我们可以先确认一下,kind 和 kubectl 工具是不是以及可以正常使用了。

kind version

kubectl version

可以看到,两个工具都可以使用了。而此时由于还没有创建集群,kubectl version 的输出只显示了 Client 的信息。

创建集群

接下来,我们开始创建集群。kind 创建集群的方法如下:

# 命令模板
kind create cluster 【可选参数】
# 如果想给集群命名可以加 --name
kind create cluster --name my-cluster
# 如果想用配置文件来生成集群可以加 --config
kind create cluster --name my-cluster --config ./kind-3nodes.yaml

现在我们执行 kind create cluster --name my-cluster 创建一个集群,第一次执行会比较耗时。

成功创建之后,我们可以再次执行 kubectl version,这次会看到除了 Client 以外,还有 Server 的信息。

执行以下命令,可以查看集群信息:

kubectl cluster-info

访问上图输出地址(我这里是https://127.0.0.1:37947/),可以看到响应内容,说明集群以及启动成功了。

删除集群

如果你在了解完本文的操作之后,希望删除创建的测试集群,可以参考下列命令:

# 删除集群
kind delete cluster
# 如果创建的集群有名字,需要用 --name 指定删除
kind delete cluster --name wslk8s
# 如果忘了自己有多少个集群或者集群的名字,可以列出当前集群
kind get clusters

部署应用

成功启动集群之后,我们就可以开始部署我们的应用了。说明一下,在实际情况中,我们部署的应用是根据业务决定的。但为了便于讲解文本的操作。文本将使用与 K8S 官方同款的示范应用: kubernetes-bootcamp

kubernetes-bootcamp

kubernetes-bootcamp 是 K8S 官方用于教学的一个简单应用,镜像里只有一个简单的 NodeJs 服务,内容如下:

// server.js

var http = require('http');
var requests=0;
var podname= process.env.HOSTNAME;
var startTime;
var host;
var handleRequest = function(request, response) {
  response.setHeader('Content-Type', 'text/plain');
  response.writeHead(200);
  response.write("Hello Kubernetes bootcamp! | Running on: ");
  response.write(host);
  response.end(" | v=1\n");
  console.log("Running On:" ,host, "| Total Requests:", ++requests,"| App Uptime:", (new Date() - startTime)/1000 , "seconds", "| Log Time:",new Date());
}
var www = http.createServer(handleRequest);
www.listen(8080,function () {
    startTime = new Date();;
    host = process.env.HOSTNAME;
    console.log ("Kubernetes Bootcamp App Started At:",startTime, "| Running On: " ,host, "\n" );
});

可以看到,应用启动后会在8080端口启动一个服务,接收到任何请求后都会响应一串文字,文字中可以反映出当前容器下的环境变量 HOSTNAME 。


部署应用

部署的命令很简单:

# 命令模板
kubectl create deployment 【deployment的名字】--image=【镜像地址】
# 用 kubernetes-bootcamp:v1 部署,并把 deployment 命名为 kubernetes-bootcamp
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1

执行后看到成功提示

实际上在执行部署命令之后,K8S 做了以下的事情:

  • 在集群中寻找可用 Node 实例(我们这里只有一个)
  • 调度应用运行在 Node 上
  • 配置集群,使其可以在有需要时,可以重新调度新的 Node

此时我们可以执行命令,查看集群下 deployment 的状态

kubectl get deployments

通过 proxy 访问应用

我们都知道 Pods 中是一个独立的网络环境,如果想要访问到实际运行的应用,需要先把网络暴露出来。手动暴露网络,可以用命令:

# 执行后终端会进入持续运行状态,需要用 ctrl + c 退出
kubectl proxy
访问pod
http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/

执行之后,会输出proxy暴露deployment的端口。此时我们可以通过该端口,结合 K8S 的API实现访问效果。

如访问http://localhost:8001/api/v1/namespaces/default/pods/【pod名字】/ 得到对应pod 的信息。

访问http://localhost:8001/api/v1/namespaces/default/pods/【pod名字】/proxy/ 可以访问到pod内部服务。这里我们成功得到了kubernetes-bootcamp服务的响应。

与 Pods 交互

在部署完应用之后,我们就启动了一个 Pod。执行 kubectl get pods 可以看到:

与 Docker 一样,K8S 提供了一些列可以与容器交互的命令

# 列出当前运行中的 Pods 列表
kubectl get pods
# 输出当前 Pods 的详细信息
kubectl describe pods
# 查看具体某个 pod 的运行日志
kubectl logs 【对应pod的名字】
# 在具体某个 pod 中执行命令(与docekr exec类似)
kubectl exec 【对应pod的名字】 【需要执行的命名】
# 进入容器内部(与docekr exec类似)
kubectl exec -ti 【对应pod的名字】 -- bash
# 如果进入了容器后,想要退出
exit

对外暴露应用

kubectl proxy 是访问容器服务最简单的方式之一,但在实际情况中,我们往往不会这么做,因为proxy暴露的是整个集群的 Api 服务,用户可以通过 Http 请求看到我们集群的内部信息。

真正适合在生成环境下暴露应用的方式,是建立 Services。

建立Services

在 K8S 中,services 就是专门处理网络的,我们可以执行命令查看当前的 services 信息。

kubectl get services

我们可以看到当前有一个默认网络,大部分的集群工具都会默认创建一个 service 。这里看到的就是 kind 默认创建的。

接下来我们需要暴露我们的服务,由于我们的 kubernetes-bootcamp 的服务运行在8080端口,因此我们需要把8080 暴露出去。执行命令

# 命令模板
kubectl expose deployment/【deployment名字】 【可选配置】
# 这里用了 --type 指定暴露类型,和--port 指定需要暴露的端口
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

执行成功后,可以用 kubectl get services 看到新 services 的情况。

此时我们可以执行命令,查看 services 的详细信息

# 命令模板
kubectl describe services/【service的名字】
# 这里用上图 kubectl get services 输出的service名字 services/kubernetes-bootcamp
kubectl describe services/kubernetes-bootcamp

执行后可以看到大量信息,其中找到NodePort,就是当前 Node 的对外端口了(本文案例中Node端口是32088)。

此时访问Service的端口即可访问 pod 中的服务

删除服务

如果需要删除服务也很简单:

# 命令模板
kubectl delete services 【service的名字】
# 删除服务
kubectl delete services kubernetes-bootcamp
# 删除服务不会影响 pod 应用的内容,服务在集群内部仍然可以访问
kubectl exec -ti $POD_NAME -- curl localhost:8080

使用标签管理

是实际部署中,我们往往需要部署大量的应用。如果通过名字操作,会耗费大量的时间。K8S允许我们给每个 Pod 或者 Service 打标签,标记之后我们就可以通过标签统一管理我们的资源。

# 标记某个 pod 标签为版本 v1
kubectl label pods 【pod的名字】 version=v1
# 列出所有版本为 v1 的pod
kubectl get pods -l version=v1
# 通过 app 标签列出services列表
kubectl get services -l app=kubernetes-bootcamp
# 删除 app 标签为kubernetes-bootcamp的services
kubectl delete service -l app=kubernetes-bootcamp

我们也可以通过 describe 命令查看标签信息:

扩展应用

随着业务的发展,应用会越来越复杂,为了提供应用的可用性。我们往往需要部署多个节点,避免单一节点异常导致服务不可访问,同时也是为了分担网络请求的压力。

扩展应用节点

先来了解一下我们目前 deployments 的信息,执行 kubectl get deployments

我们可以看到的信息有:

  • NAME: 集群中 deployment 的名字
  • READY: 当前/期望的 pod 副本数量比
  • UP-TO-DATE: 已更新以达到所需状态的副本数
  • AVAILABLE:还有多少副本可供用户使用
  • AGE: 应用程序已经运行了多久

这里提到一个词 副本(ReplicaSet) ,是指 K8S 中用于扩展 pod 的复制副本,可以通过命令查看。

kubectl get rs

副本的名字格式固定为【deployment 的名字】-【随机字符】,这里输出的内容中有两项比较重要:

  • DESIRED:应用期望的副本数量,这是在创建 deployment 的时候声明的
  • CURRENT:当前运行的副本数量

现在我们可以正式开始扩展我们的应用了,扩展应用的本质是增加副本的节点,命令如下:

# 命令模板
kubectl scale deployments/【deployment名字】 --replicas=【调节的副本数量】
# 把 kubernetes-bootcamp 的副本数升为4个
kubectl scale deployments/kubernetes-bootcamp --replicas=4

此时我们再看看现在的集群状态:

负载均衡

K8S 默认已经实现了服务请求的负载均衡。在扩展了应用之后,我们每次请求服务,K8S会均匀地把请求转到不同的副本上。

降低应用扩展

同样,如果我们想减少应用的副本量,只需把副本数量调小即可。

# 把副本数调低至2
kubectl scale deployments/kubernetes-bootcamp --replicas=2

更新应用

最后我们再来看看如果更新一个已经部署了的应用。在K8S中,所有应用都是容器,而容器又来自镜像。因此更新应用的本质,就是更新镜像。

通过执行 kubectl describe pods 可以看到现在的 pod 用的镜像。

我们可以通过命令修改镜像

# 命令模板
kubectl set image deployments/【deployment名字】 【容器名字】=【要修改的新镜像地址】
# 我们把 kubernetes-bootcamp 的镜像改为v2的版本
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2

执行之后,再查看 pods 的状态,会看到我们的 pod 数量翻了一倍。

此时 K8S 会把旧的 pod 停止(Terminating),拉取新的 pod ,并保持新旧数量一致。等一段时间后再查看,就会看到 pod 数量恢复,说明更新完成了。

此时访问服务,可以看到应用服务的输出已经变了,说明我们已经在用另一个镜像。

在更新过程中,你可以执行命令查看进行中的更新状态:

# 命令模板
kubectl rollout status deployments/【deployment名字】
# 查看 kubernetes-bootcamp 的更新状态
kubectl rollout status deployments/kubernetes-bootcamp

执行后终端会持续输出更新状态,直到更新完成后终端就会退出。

回退

可以更新,自然需要回退。尤其是生产环境下,假如由于更新导致服务异常、无法访问等情况,迅速地回退到上一个版本是十分重要的策略。

K8S中也提供了快速回退的功能,下面我们演示一个例子:拉取一个版本为10的 kubernetes-bootcamp 镜像。这个版本是不存在的,这样我们的更新就会出错,然后我们看看如何用 K8S 回退到上一个版本。

# 更新 kubernetes-bootcamp 为v10
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10

查看 pods 状态,发现已经有 pod 镜像拉取失败了。

执行 kubectl describe pods ,查看 Events 中信息,可以看到具体拉取镜像出错的提示。

此时我们可以通过命令回退版本

#命令模板
kubectl rollout undo deployments/【deployment名字】
#回退 kubernetes-bootcamp
kubectl rollout undo deployments/kubernetes-bootcamp

执行后就可以看到 pods 的状态恢复了。

总结

今天我们通过一个简单的案例,学习了 K8S 的基本操作。包括安装、集群的管理、应用部署、网络暴露、以及部署后应用的扩展与更新等。K8S 是一个强大的容器编排工具,如果你是一个运维工程师,那么它将是你必须掌握的技能。

而对应普通的开发者来说,掌握基本操作还是十分重要的。未必每个人在工作都有机会接触到这部分的内容,但是一旦发生了紧急情况,或者 CI/CD 链异常时,掌握基本操作可以让我们有调试与测试的思路,尽快解决问题。

最后,还要强调一下,本文的出发点是讲述最简单的基本操作,如果你有兴趣深入学习更多,可以自行进一步阅读。

进一步阅读

Kubernetes 官方文档:kubernetes.io/docs/home/

Kubeadm安装文档:kubernetes.io/docs/setup/…

kind工具官方文档:github.com/kubernetes-…

部署配置文件说明:kubernetes.io/docs/concep…

如果你觉得本文对你有一点帮助,麻烦给我点个赞吧~~ 谢谢