Kubernetes 短途旅行(下)

999 阅读8分钟

Kubernetes 短途旅行(上)

本文会通过一个中文情绪分析的应用(以下简称 SA)把 K8s 的一些基础概念穿插讲一讲,接着我们会进行一次 UI 的更新以便体验一下 K8s 的滚动更新,最后我们还会进行一次回滚,把 UI 的更新给撤销掉并回滚到上一个版本。

那么接下来就按照这个剧本开始吧。

中文情绪分析的应用 SA

仓库地址:github.com/jwma/sentim…

SA 分为三个部分:

  • sa-frontend,使用 Vue.js 开发的前端应用并部署在 Nginx,提供让用户交互的界面;
  • sa-webapp,使用 Go 语言开发的 API 服务,直接面向前端应用;
  • sa-logic,使用 Python 开发的情绪分析服务,面向 API 服务,对前端应用不可见。

部署到 K8s

如果我们要将 SA 部署到 K8s 集群,我们需要先准备一些必需品:

  1. K8s 集群;
  2. 容器镜像;
  3. Deployment 和 Service 配置文件;
  4. 创建 Deployment 和 Service 资源。

1. K8s 集群

参考上一篇文章,你会找到适合你自己的途径。这里我会使用 Minikube 为我启动一个本地的单节点集群。

2. 容器镜像

容器化的细节本文就不展开了,可以参考项目源码内各部分的 Dockerfile,下面讲讲构建镜像的相关内容。

一般来说,我们会把我们的容器镜像推送到一个镜像仓库如 DockerHub,但由于我们的集群就是在本地,所以我们可以重用 Minikube 内置的 Docker,这样我们就不需要浪费时间去推送镜像和拉取镜像了,便于我们在本地体验。

这样使用时需要注意,在为镜像打 tag 时,需要使用 :latest 以外的名字,因为当你使用了 :latest 意味着镜像拉取策略也会被修改为 Always,在镜像不存在于默认的 Docker 镜像仓库(一般为 DockerHub)时,会引发 ErrImagePull 错误。

我们可以这样使用 Minikube 内置的 Docker:

eval $(minikube docker-env)

此时命令行的 Docker 就是 Minikube 的 Docker 了,接着我们就可以构建镜像了:

# 切换到源码目录
cd /path/to/sentiment-analyzer

# 构建 sa-logic 镜像
docker build -t sa-logic:v1.0.0 sa-logic

# 成功的话会看到如下输出
# Successfully tagged sa-logic:v1.0.0

# 构建 sa-webapp 镜像
docker build -t sa-webapp:v1.0.0 sa-webapp

# 成功的话会看到如下输出
# Successfully tagged sa-webapp:v1.0.0

# 暂时无法构建 sa-frontend
# 因为其依赖了 sa-webapp 暴露的通信地址
# 需要等我们创建了 sa-webapp service 之后再构建

3. Deployment 和 Service 配置文件

这一部分内容比较无聊,着急的可以先跳过。

查看源码的 infrastructure 目录,其中包含了 Deployment 和 Service 配置文件。

以 sa-webapp 的 Deployment 举例:

  • #1 apiVersion 指定了该资源对象所对应的 API 版本,K8s 支持多个 API 版本,K8s 团队选择在 API 级别进行版本化,而不是在资源或字段级别进行版本化,以确保 API 提供清晰,一致的系统资源和行为视图,并控制对已废止的 API 和/或实验性 API 的访问;
  • #2 kind 指定了该资源的类型为 Deployment;
  • #3 metadata K8s 的资源对象都拥有通用的元数据,这里指定了名称和添加了一个键为 app 值为 sa-webapp 的标签,后续需要用来匹配对应的 Service;
  • #7 spec 描述你期望的 Deployment 的状态;
  • #8 spec.replicas 指定期望的 Pod 数量,默认值是 1;
  • #9 spec.selector 指定了 Deployment 管理 Pod 的范围,通过标签进行匹配;
  • #12 spec.template 指定 PodTemplate,描述了 Pod 的细节,这里为 Pod 添加了一个键为 app 值为 sa-webapp 的标签,也指明了 Pod 的名字及其实用的镜像,为了让容器能正常运行,还设置了容器所需 的环境变量,最后还暴露了容器的端口。

以 sa-webapp 的 Service 举例:

  • #2 kind 指定了该资源的类型为 Service;
  • #8 spec.selector 通过标签选择器匹配 sa-webapp Deployment;
  • #10 spec.type 指定 Service 类型为 LoadBalancer,也就说来自外部的流量会通过这个 Service 的负载均衡器然后打到匹配的 Pod 上;
  • #11 spec.ports 指定端口的映射关系,把负载均衡器的 80 端口映射到 Pod 的 8080 端口。

什么是 Deployment 和 Service?

在本文的例子中,除了认识 Deployment 和 Service 外,你还需要认识 Pod 和 RS(Replica Set),因为他们的互相结合才使得我们能够把 SA 给运作起来。

实质上,它们都是 K8s 的 API 对象,只是他们负责的工作内容不一样而已。

Pod

Pod 是 K8s 应用的基础执行单元,它是你创建或部署的最小最简单的 K8s 单元。一个 Pod 通常包含的是一个应用容器(有时候会是多个容器)。结合上文,我们在 Deployment 声明了 PodTemplate,也就是说我们的 Pod 会按照我们的声明运行我们想要运行的容器。

RS

RS 保证 Pod 的高可用。结合上文,我们在 Deployment 声明了 replicas,我们期望运行两个 Pod,而实际运行中的 Pod 的数量就是通过 RS 进行保障的。

Deployment

Deployment 可以创建/更新一个服务,也可以滚动更新服务。我们通过配置文件,可以告诉 K8s 集群我们期望应用的运行状态,结合 Pod 我们能把应用运行起来,结合 RS 我们能保障 Pod 的可用性。一次对 Deployment 的操作,就是通过操作相关的 API 对象来更新应用的运行状态以达到我们的期望。

Service

通过上面的几个 API 对象,我们已经保证应用能够正常运作,但没有解决如何访问这些服务的问题,Service 就是用来解决这个问题的。

4. 创建 Deployment 和 Service 资源

在 K8s 上创建 API 对象的资源很简单,我们可以使用统一的方式进行创建:

# 切换到源码目录
cd /path/to/sentiment-analyzer

# 创建 sa-logic 的 Deployment、Service
kubectl apply -f infrastructure/deployment/sa-logic.yaml

# 查看 sa-logic 对应的 Pod 是否正常运作
kubectl get pods -l app=sa-logic

# 创建 sa-logic 的 Service
kubectl apply -f infrastructure/service/sa-logic.yaml

# 查看 sa-logic 对应的 Service
kubectl get service -l app=sa-logic

# 创建 sa-webapp 的 Deployment、Service
kubectl apply -f infrastructure/deployment/sa-webapp.yaml
kubectl apply -f infrastructure/service/sa-webapp.yaml

到这里,我们就把 sa-logic 和 sa-webapp 部署到 K8s 集群了,sa-webapp 是一个对外可见的服务,所以我们在部署 sa-frontend 之前,可以使用 postman 或者 curl 来访问以下 sa-webapp 看看。

由于我们使用的是 Minikube,所以为了获取 sa-webapp 服务的通信地址,我们需要:

minikube service sa-webapp-service --url

我们会得到一个 URL,如:http://192.168.99.105:31861,接下来我们用 cURL 工具测试下 sa-webapp 的接口:

# 发送请求
curl --request POST \
  --url http://192.168.99.105:31861/analyse \
  --header 'Content-Type: application/json' \
  --data '{"sentence": "非常棒"}'

# 响应结果
{"sentence":"非常棒","level":9}

我们成功的得到了结果。现在我们已经得到了正确的 sa-webapp 的通信地址了,所以我们可以开始构建 sa-frontend 镜像然后部署了:

# 切换到源码目录
cd /path/to/sentiment-analyzer

docker build -t sa-frontend:v1.0.0 --build-arg VUE_APP_API_HOST=http://192.168.99.105:31861 sa-frontend

kubectl apply -f infrastructure/deployment/sa-frontend.yaml
kubectl apply -f infrastructure/service/sa-frontend.yaml

然后我们就可以获取 sa-frontend 的访问 URL 了:

# 这次不加 --url,会自动在浏览器打开
minikube service sa-frontend-service

你也可以像我这样玩一下:

sa-frontend

滚动更新

在 K8s 上要实现滚动更新是一件非常简单的事情。 我们接下来会更新 sa-frontend,因为我觉得每次提交完一个句子后,Emoji 出现的太突兀,缺乏了一些动感,所以我接下来会使用 animate.css 为 Emoji 加一个动画,让画面看起来更有动感一些。

来看看整个流程吧:

  1. 修改代码;
  2. 构建一个新的 sa-frontend 镜像;
  3. 更新 sa-frontend Deployment 配置文件;
  4. 向 K8s 提交 Deployment;
  5. 查看结果。

1. 修改代码

这里不是重点,就跳过了。

2. 构建一个新的 sa-frontend 镜像

我们更新了代码,所以我们也会跟着构建一个新的镜像,镜像版本号取 v1.1.0。

# 切换到源码目录
cd /path/to/sentiment-analyzer

docker build -t sa-frontend:v1.1.0 --build-arg VUE_APP_API_HOST=http://192.168.99.105:31861 sa-frontend/

3. 更新 sa-frontend Deployment

# ...省略
# 镜像修改为刚刚构建好的 v1.1.0
image: sa-frontend:v1.1.0
# ...省略

4. 向 K8s 提交 Deployment

跟第一次部署 sa-frontend 一样,我们向 K8s 集群提交了我们的 Deployment 配置文件。

kubectl apply -f infrastructure/deployment/sa-frontend.yaml

5. 查看结果

我感觉这样就好多了呢。

在这里,你可以不去思考 K8s 的滚动更新是怎么做的,但我认为往后你应该要去了解这件事情,这对你理解 K8s 的各个 API 对象很有帮助。

回滚

如果你是一个比较安静的孩纸,不喜欢这么动感,你可以回滚到上一个版本:

kubectl rollout undo deployment sa-frontend-deployment

除了回滚到上一个版本,你还能回滚到指定的版本,这里就不展开了,我相信如果要用到的时候你肯定会去翻文档的。

短途旅行的终点

我们到达了这次短途旅行的终点,就像真正的旅行一样,这个终点往往会是原点,我们不断的旅行,我们见识到了不同的风景,认识到了不同的朋友,体验了不同的风情,虽然我们又回到了原点,但我们不断积累阅历,让我们面对下一个挑战更具勇气,让我们走得更远看得更广。

希望这两篇文章,能带你走马观花看看 K8s,如果能在你的脑中留下 K8s 好像真的不错哦,我想我就满足了。