In the previous article on how to use GitLab CI for CI/CD in a Kubernetes cluster, we basically used the Docker On Docker
model for building images, because the Kubernetes cluster uses a container runtime like Docker, so we could mount the host docker.sock
file from the host to the container to build the image, but recently we changed the container runtime to Containerd after using Kubernetes version 1.22.X, so there is no Docker service available on the node, this time we need to change the mode of building the image, of course, there are many ways to build the image, we Here we still choose to use Docker to build our Docker image, that is, use the Docker IN Docker
mode.
Each time we build an image, GitLab Runner will start a Pod with three containers, one of which is the Docker DIND container running the Docker daemon, and the built container will connect to the Docker daemon running on the same Pod. namespace, the Docker CLI that builds the image can connect directly to the Docker daemon via localhost to build. However, one of the biggest problems with this approach is that each build starts a brand new Docker daemon, resulting in no cached Docker layer layer, which can significantly increase our build time.
Instead of running a sidecar container with Docker DIND service for each Pod, let’s run a standalone Docker DIND container with all the Docker CLIs of the build container connected to this one Docker daemon, where we persist the Docker layer layer, which also serves as a cache.
First, we create a PVC to store the persistent data of Docker, and for performance reasons, we use a Local PV here.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-volume
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: docker-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-volume
local:
path: /mnt/k8s/docker # 数据存储的目录
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1 # 运行在node1节点
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app: docker-dind
name: docker-dind-data
namespace: kube-ops
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-volume
resources:
requests:
storage: 5Gi
|
Then deploy a Docker DIND service using Deployment.
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
31
32
33
34
35
36
37
38
39
40
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-dind
namespace: kube-ops
labels:
app: docker-dind
spec:
selector:
matchLabels:
app: docker-dind
template:
metadata:
labels:
app: docker-dind
spec:
containers:
- image: docker:dind
name: docker-dind
args:
- --registry-mirror=https://ot2k4d59.mirror.aliyuncs.com/ # 指定一个镜像加速器地址
env:
- name: DOCKER_DRIVER
value: overlay2
- name: DOCKER_HOST
value: tcp://0.0.0.0:2375
- name: DOCKER_TLS_CERTDIR # 禁用 TLS
value: ""
volumeMounts:
- name: docker-dind-data-vol # 持久化docker根目录
mountPath: /var/lib/docker/
ports:
- name: daemon-port
containerPort: 2375
securityContext:
privileged: true # 需要设置成特权模式
volumes:
- name: docker-dind-data-vol
persistentVolumeClaim:
claimName: docker-dind-data
|
Then create a Service to facilitate the connection of the built Docker CLI to it.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
apiVersion: v1
kind: Service
metadata:
name: docker-dind
namespace: kube-ops
labels:
app: docker-dind
spec:
ports:
- port: 2375
targetPort: 2375
selector:
app: docker-dind
|
After deploying the Docker DIND service, we can use this daemon to build images in Gitlab CI, as follows.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
tages:
- image
build_image:
stage: image
image: docker:latest
variables:
DOCKER_HOST: tcp://docker-dind:2375 # 通过 service dns 形式连接 docker dind 服务
script:
- docker info
- docker build -t xxxx .
- docker push xxxx
only:
- tags
|
Since we cache the Docker layer, the build speed will be significantly faster at this time. Finally, as a lot of images are built, we can write a Cronjob to clear the cache regularly.
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
|
apiVersion: batch/v1
kind: CronJob
metadata:
name: docker-dind-clear-cache
namespace: kube-ops
spec:
schedule: 0 0 * * 0 # 每周清理一次
jobTemplate:
metadata:
labels:
app: docker-dind
name: docker-dind-clear-cache
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: clear-cache
image: docker:latest
command:
- docker
- system
- prune
- -af
env:
- name: DOCKER_HOST
value: tcp://docker-dind:2375
|