写点什么

读懂 k8s 容器编排控制器 Deployment

用户头像
Garfield
关注
发布于: 2020 年 09 月 01 日
读懂k8s 容器编排控制器 Deployment

我有这样一个需求: 同一套代码,包含不同的数据处理业务逻辑线,这两条逻辑线要跑两个独立的进程,分别加载两个不同的配置文件。

但这两个进程又有某种“亲密关系”:

  • 共享一个Docker Image;

  • 共享同一个 Volume(存储卷);

  • 共享同一个 Network;

且我不想管理两个 Deployment 控制器。

那么我该如何去写这个 Deployment 控制器来编排我的应用。

我是这样写的:

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: demo-app
name: demo-app-deployment
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
volumes:
- name: demo-app
persistentVolumeClaim:
claimName: demo-pvc
imagePullSecrets:
- name: demohub
containers:
- name: demo-app-user
image: hub.demo.cn/demo/demo-app:dev
command:
- sh
- -c
- ./bin/server -c configs/dev/user.json
env:
- name: LOG_LEVEL
value: "TRACE"
imagePullPolicy: "Always"
volumeMounts:
- mountPath: "/var/log/demo-app"
name: demo-app
resources:
limits:
cpu: "1"
memory: "1G"
requests:
cpu: "500m"
memory: "512M"
- name: demo-app-event
image: hub.demo.cn/demo/demo-app:dev
command:
- sh
- -c
- ./bin/server -c configs/dev/event.json
env:
- name: LOG_LEVEL
value: "TRACE"
imagePullPolicy: "Always"
volumeMounts:
- mountPath: "/var/log/demo-app"
name: demo-app
resources:
limits:
cpu: "1"
memory: "1G"
requests:
cpu: "500m"
memory: "512M"


那么,如何理解这个 Deployment 呢? 先对这个 yaml 做一个简单的拆解:





图中把控制器拆成两部分,上半部分为控制器定义,下半部分是被控制对象的模板(template),这个模板在 k8s 就叫做 PodTemplate(Pod 模板)。

Deployment 控制器定义

  • apiVersion

创建该对象所使用的 Kubernetes API 的版本;



  • kind

想要创建的对象的类别;



  • metadata

唯一性标识对象的数据;



上面的例子中 metadata 包含了标识该控制器的标签(labels),对象名称(name),对象所属的 k8s 命名空间(namespace)。



  • replicas

他确保了 app=demo-app 标签的 Pod 数量等于 spec.replicas 指定的个数,即 1 个。

如果在这个集群的 namespace 中,携带 app=demo-app 标签的 Pod 的个数大于 1 的时候,就会有旧的 Pod 被删除;反之,就会有新的 Pod 被创建。



这使得 水平扩展或收缩 非常容易实现,Deployment 控制器只要修改它所控制的 ReplicaSet 的 Pod 副本个数就可以了, 效果如下:





在这个效果中,可以看到四个状态:

  • DESIRED(期望)

用户期望的 Pod 副本个数(spec.replicas 的值);



  • CURRENT(当前)

当前处于 Running 状态的 Pod 的个数;



  • UP-TO-DATE(就绪)

当前处于最新版本的 Pod 的个数。



  • AVAILABLE(已创建)

当前已经可用的 Pod 的个数,即:既是 Running 状态,又是最新版本,且已经处于健康检查正确(Ready)状态的 Pod 的个数。



利用 ReplicaSet 实现水平扩展、动态伸缩、滚动升级这里不再深入了。

被控制对象的 PodTemplate(Pod 模板)

先简单理解下 Pod,它是一个逻辑概念,可理解为是由容器组抽象而来的,类似 Linux 的进程组概念。

Pod 中的所有容器,共享的是同一个 Network,并且可以声明共享同一个 Volume。

我这里也写了 Pod 下的两个容器了共享存储卷(volumes) demo-app。



  • imagePullSecrets

imagePullSecrets 表示拉取运行 Containers 的 Docker image Docker 仓库密码对象(Secret)。

它是 k8s 支持的 Projected Volume,把 Pod 想要访问的加密数据存放到 Etcd 中。与 Secret 类似的是 ConfigMap,只不过ConfigMap 保存的是不需要加密的、应用所需的配置信息。 我写的 yaml 直接把配置 json 拷贝到容器了,没有使用 ConfigMap。



  • containers





我在的模板中 Pod 包含了两个业务逻辑的工作容器:

demo-app-user、demo-app-event。

这两个工作容器启动时加载不同的配置,但是他们共享存储,日志文件均bind mount 挂载到 volumes demo-app。



我的两个工作容器没有依赖关系,但假如我想让两个容器启动有先后顺序呢?

sidecar

  • initContainers

接着上面的问题,办法总是有的:

在 Pod 中,还有一类容器 initContainers。

所有 Init Container 定义的容器,都会比 spec.containers 定义的用户容器先启动。

并且,Init Container 容器会按顺序逐一启动,直到它们都启动并退出了,用户容器(spec.containers )才会启动。

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: demo-app
name: demo-app-deployment
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
volumes:
- name: demo-app
persistentVolumeClaim:
claimName: demo-pvc
imagePullSecrets:
- name: demohub
initContainers:
- name: demo-app-user
image: hub.demo.cn/demo/demo-app:dev
command:
- sh
- -c
- ./bin/server -c configs/dev/user.json
env:
- name: LOG_LEVEL
value: "TRACE"
imagePullPolicy: "Always"
volumeMounts:
- mountPath: "/var/log/demo-app"
name: demo-app
resources:
limits:
cpu: "1"
memory: "1G"
requests:
cpu: "500m"
memory: "512M"
containers:
- name: demo-app-event
image: hub.demo.cn/demo/demo-app:dev
command:
- sh
- -c
- ./bin/server -c configs/dev/event.json
env:
- name: LOG_LEVEL
value: "TRACE"
imagePullPolicy: "Always"
volumeMounts:
- mountPath: "/var/log/demo-app"
name: demo-app
resources:
limits:
cpu: "1"
memory: "1G"
requests:
cpu: "500m"
memory: "512M"


这种玩法通常叫做:sidecar。



让我们可以在一个 Pod 中,启动一个辅助容器,来完成一些独立于主进程(主容器)之外的工作。

比如容器的日志收集,我在 Pod 里同时运行一个 sidecar 容器,它声明挂载同一个 Volume 到 /var/log/demo-app 目录上,不断从自己的 /var/log/demo-app 目录里读取日志文件,转发到 Elasticsearch 中存储起来。

这样就实现了日志收集并落地存储的工作。



以上。



欢迎讨论!

----------------------

公众号:life-is-x

知乎:OneZero



发布于: 2020 年 09 月 01 日阅读数: 52
用户头像

Garfield

关注

Golang Service Mesh 2018.05.15 加入

还未添加个人简介

评论

发布
暂无评论
读懂k8s 容器编排控制器 Deployment