0%

Kubernetes使用InitContainers和Volume预填充数据

Kubernetes中的InitContainer资源是一个有趣且非常有用的资源。在许多情况下,我们会看到它曾用于在Pod部署时,创建容器之前在卷中预填充数据,因此在业务容器启动时,卷数据已被初始化。

就我而言,我有一个带有单个静态页面的简单Web前端,它使用标准的nginx基础镜像:

1
2
3
4
FROM nginx

COPY index.html /usr/share/nginx/html/index.html
COPY smartos.ipxe /usr/share/nginx/html/smartos.ipxe

该镜像的构建和下载速度非常快,这非常棒,但是部分原因是它是无状态的。例如,smartos.ipxe文件中需要一些数据,这些数据在启动应用程序时需要可用,否则这些引用将无法按预期工作(抽象为404 HTTP响应):

1
2
3
4
5
6
#!ipxe
dhcp
set base-url http://sdc-ipxe.east.gourmet.yoga
kernel ${base-url}/smartos/smartos/platform/i86pc/kernel/amd64/unix -B smartos=true,console=ttyb,ttyb-mode="115200,8,n,1,-"
module ${base-url}/smartos/smartos/platform/i86pc/amd64/boot_archive type=rootfs name=ramdisk
boot

但是,这些文件不是应用程序的一部分,因为它们经常更新。因此,每次推出新版本时,我们都希望该卷中包含最新版本,并且由于我们不需要维护镜像中的这些文件,否则在我们的Registry中存储起来会非常大且昂贵,我们可以在Pod中的容器上挂载一个Volume来提供它们。

因此,基本上,我们需要一种方法来预填充要装入到/usr/share/nginx/html/smartos的卷。

使用InitContainer资源,我们可以指定要运行的命令,并且像Pod中的任何其他容器一样,我们可以分配要挂载的卷,因此让我们从这样的Kubernetes清单开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: apps/v1
kind: Deployment
metadata:
name: sdc-ipxe-deployment
labels:
app: sdc-ipxe
spec:
replicas: 2
selector:
matchLabels:
app: sdc-ipxe
template:
metadata:
labels:
app: sdc-ipxe
spec:
initContainers:
- name: config-data
image: ubuntu:xenial
command: ["/bin/sh","-c"]
args: ["apt update; apt install -y wget tar; wget https://us-east.manta.joyent.com/Joyent_Dev/public/SmartOS/platform-latest.tgz; tar xvf platform-latest.tgz -C /data; mkdir /data/smartos; mv /data/platform* /data/smartos/platform"]
volumeMounts:
- mountPath: /data
name: sdc-data
volumes:
- name: sdc-data
hostPath:
path: /mnt/kube-data/sdc-ipxe/
type: DirectoryOrCreate

因此,在这一点上,我们正在准备卷sdc数据,将其挂载到initContainer的/data目录上并运行:

1
apt update; apt install -y wget tar; wget https://us-east.manta.joyent.com/Joyent_Dev/public/SmartOS/platform-latest.tgz; tar xvf platform-latest.tgz -C /data; mkdir /data/smartos; mv /data/platform* /data/smartos/platform

上述命令下载数据并将其提取到卷中。现在,我们向yaml中添加一个container,然后再次附加该Volume,将可以使用预填充的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
metadata:
name: sdc-ipxe-deployment
labels:
app: sdc-ipxe
...
containers:
- name: sdc-ipxe
image: coolregistryusa.bix/jmarhee/sdc-ipxe:latest
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/smartos
name: sdc-data
...

在业务容器中配置相同名称的卷,则业务容器就可以通过/usr/share/nginx/html/smartos目录获取sdc数据。

如果我们的应用程序依赖于具有可变需求的配置,则这种模式是有用的。可能是我们需要获得令牌,或者地址是动态的,并且需要通过磁盘上的文件而不是环境(比如负载平衡器,Web服务器或具有配置文件的数据库客户端,不容易通过它处理)传递文件(因为它们更改的频率不同)(Secret或ConfigMap),这种方法提供了一个易于编程的界面,用于预先填充或完成传递给容器的数据的模板化。