在云原生领域,无论使用哪种编排调度平台,Kubernetes,DockerSwarm,OpenShift等,业务都需要基于镜像进行交付,我们在内部实践“Source-to-image”和链式构建,总而总结出“OneBuild”模式。
其核心思想是:一处构建,多处使用。
问题
一般,我们会使用类似Jenkins CI系统来构建镜像,以满足持续集成,持续开发,持续交付等场景。事实上,如果我们在某一方面能够提升效率或者解决镜像交付实践。
长期来看,将能够带来不少的成本收益,并且对于平台来讲,这种收益是一种可度量收益。假设我们在当前交付(git)分支中,需要fix或者feature已经release分支的,如何进行?如果在已经交付给用户的镜像中存在漏洞,需要批量交付,如何进行?为了解决这些问题,我们的团队必须重新构建镜像,并且找出基本镜像,构建过程有那些依赖关系。然后基于这些成熟的流程和规范进行快速交付。
解决方案
Docker build是大家比较常用的镜像构建方法,并且在构建中只需要声明自己的Dockerfile即可,就可以实现快速构建。但是这并不满足大型企业实践以及快速交付。
所以需要一套规范且能够直接生产的流程,帮助在云原生下进行快速交付。下面我们讲结合行云平台进行“OneBuild”方法的实践。
悬衡而知乎,没规而知圆。因此,我们在团队的流水线建立和改造的过程中,尤其注重标准化。
包括dockerfile的命名和设计,构建代码的设计。由此新项目加入时,我们只需复制,然后做小工作量的改造即可。
行云Build
行云是JDT生产效率的标准化产品,是一个比较成熟的产品。用于支撑内部研发,测试,交付的平台。
Build是行云中一个子系统,用于研发过程中的持续集成,持续测试,持续构建等任务。
团队日常开发语言主要是以golang为主,并且在上线或交付制品中,也以Docker镜像为主。并且由于大多数时间,我们必须在真实的K8S环境中运行。
所以稳定的构建平台,高效,快速的构建,对我们的日常开发和交付都是至关重要,在构建中往往需要构建多版本镜像。所以围绕行云流水线,主要就是发掘功能,适配改造。
Dockerfile标准化
接下来,我们设计的流程,将会使用上一级构建的产品,对下级镜像进行快速装箱。
Dockerfile命名
1
2
3
4
5
|
Dockerfile # 标准版
Dockerfile.kylinv10 # kylinv10 base 版本
Dockerfile.oel22 # openeuler base 版本
|
下面我们继续看dockerfile中的细节。
首先是 Dockerfile
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
ARG ARCH
ARG BUILD_IMAGE
ARG BASE_IMAGE
FROM ${BUILD_IMAGE} as builder
ARG ARCH
ENV GOPATH = / go
COPY go.mod go.mod
COPY go. sum go. sum
COPY main.go main.go
COPY api / api /
COPY controllers / controllers /
COPY pkg / pkg /
COPY vendor / vendor /
# Build
RUN CGO_ENABLED = 0 GO111MODULE = on GOOS = linux GOARCH = ${ARCH} go build - - mod = vendor - a - o manager main.go
ARG ARCH
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV PIP3_SOURCE = https: / / pypi.tuna.tsinghua.edu.cn / simple
ENV DEFAULT_FORKS = 50
ENV DEFAULT_TIMEOUT = 600
ENV DEFAULT_GATHER_TIMEOUT = 600
ENV TZ = Asia / Shanghai
ENV PYTHONWARNINGS = ignore::UserWarning
WORKDIR /
COPY - - from = builder / manager .
COPY inventory / inventory /
COPY roles / roles /
COPY etcd - restore.yml etcd - restore.yml
COPY facts.yml facts.yml
COPY requirements.txt requirements.txt
COPY inventory.tmpl.ini inventory.tmpl.ini
COPY ansible.cfg ansible.cfg
RUN yum - y install kde - l10n - Chinese && \
yum - y reinstall glibc - common && \
localedef - c - f UTF - 8 - i zh_CN zh_CN.UFT - 8 && \
echo 'LANG="zh_CN.UTF-8"' > / etc / locale.conf && \
source / etc / locale.conf && \
yum clean all
ENV LANG = zh_CN.UTF - 8
ENV LC_ALL = zh_CN.UTF - 8
RUN ln - snf / usr / share / zoneinfo / $TZ / etc / localtime && \
echo $TZ > / etc / timezone && \
yum install python3 python3 - devel sshpass openssh - clients - y && \
yum clean all && \
/ usr / bin / python3 - m pip - - no - cache - dir install pip = = 21.3 . 1 - U - i $PIP3_SOURCE && \
/ usr / bin / python3 - m pip - - no - cache - dir install - r requirements.txt - i $PIP3_SOURCE
USER root
ENTRYPOINT [ "/manager" ]
|
上述dockerfile中,分为两个阶段构建,第一个阶段builder构建出需要的二进制。这与正常的dockerfile相同。
唯一不同的是,我们讲构建镜像和base镜像进行了参数化,这也使得当变更构建镜像和base镜像,我们只需要在构建时控制参数即可。
再看dockerfile.kylinv10
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
46
47
48
49
50
51
52
53
54
55
|
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV PIP3_SOURCE = https: / / pypi.tuna.tsinghua.edu.cn / simple
ENV DEFAULT_FORKS = 50
ENV LANG = en_US.UTF - 8
ENV DEFAULT_TIMEOUT = 600
ENV DEFAULT_GATHER_TIMEOUT = 600
ENV TZ = Asia / Shanghai
ENV PYTHONWARNINGS = ignore::UserWarning
WORKDIR /
COPY - - from = jdos - etcd - restore - helper:latest / manager /
COPY inventory / inventory /
COPY roles / roles /
COPY etcd - restore.yml etcd - restore.yml
COPY facts.yml facts.yml
COPY requirements.txt requirements.txt
COPY inventory.tmpl.ini inventory.tmpl.ini
COPY ansible.cfg ansible.cfg
RUN ln - snf / usr / share / zoneinfo / $TZ / etc / localtime && \
echo $TZ > / etc / timezone && \
yum install python3 python3 - devel python3 - pip sshpass openssh - clients - y && \
/ usr / bin / python3 - m pip - - no - cache - dir install pip = = 21.3 . 1 - U - i $PIP3_SOURCE && \
/ usr / bin / python3 - m pip - - no - cache - dir install - r requirements.txt - i $PIP3_SOURCE
USER root
ENTRYPOINT [ "/manager" ]
|
发现了什么?在dockerfile.kylinv10中少了builder这一步,COPY --from=jdos-etcd-restore-helper:latest 是从一个指定的临时镜像中直接做了拷贝。这就直接复用了第一步dockerfile中构建出的产物。效率提升比较明显。
在dockerfile设计中,COPY是可以从一个指定的镜像中,copy指定的文件的。
再看Dockerfile.oel22
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
46
47
48
49
50
51
52
53
54
55
|
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV PIP3_SOURCE = https: / / pypi.tuna.tsinghua.edu.cn / simple
ENV DEFAULT_FORKS = 50
ENV LANG = en_US.UTF - 8
ENV DEFAULT_TIMEOUT = 600
ENV DEFAULT_GATHER_TIMEOUT = 600
ENV TZ = Asia / Shanghai
ENV PYTHONWARNINGS = ignore::UserWarning
WORKDIR /
COPY - - from = jdos - etcd - restore - helper:latest / manager /
COPY inventory / inventory /
COPY roles / roles /
COPY etcd - restore.yml etcd - restore.yml
COPY facts.yml facts.yml
COPY requirements.txt requirements.txt
COPY inventory.tmpl.ini inventory.tmpl.ini
COPY ansible.cfg ansible.cfg
RUN ln - snf / usr / share / zoneinfo / $TZ / etc / localtime && \
echo $TZ > / etc / timezone && \
yum install python3 python3 - devel python3 - pip sshpass openssh - clients - y && \
/ usr / bin / python3 - m pip - - no - cache - dir install pip = = 21.3 . 1 - U - i $PIP3_SOURCE && \
/ usr / bin / python3 - m pip - - no - cache - dir install - r requirements.txt - i $PIP3_SOURCE
USER root
ENTRYPOINT [ "/manager" ]
|
是不是与dockerfile.kylinv10的思路非常相似,事实上,这两个文件已经可以合并了(内部为了向后兼容,没有合并这两个文件)。
脚本标准化
还需要在行云流水线中将shell脚本进行固化,与dockerfile进行配合。
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
# 支持shell语言代码的多行输入
cd /
sudo docker login - u $IMAGE_REPO_USER - p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk - F '/' '{print $1}' )
git_commit = ${output.Download_Code.GIT_LAST_COMMIT_SHA1}
build_date = $(date - u + '%Y-%m-%dT%H:%M:%SZ' )
image_tag = "${env.GenerateNewVersion}-${git_commit:0:6}"
echo "start build image - standard"
new_image_repo = "${IMAGE_REPO}"
sudo docker build - t ${new_image_repo}:${image_tag} - f Dockerfile - - build - arg ARCH = "amd64" .
sudo docker login - u $IMAGE_REPO_USER - p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk - F '/' '{print $1}' )
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - standard"
echo "amd64ImageName=${new_image_repo}:${image_tag}" > . / amd64_output
# 重新命名一个新镜像,供下级dockerfile进行多阶段构建时直接copy
sudo docker tag ${new_image_repo}:${image_tag} jdos - etcd - restore - helper:latest
# 条件性选择构建基于kylinv10OS的镜像
if [[ - f Dockerfile.kylinv10 ]];then
echo "start build image - security - kylin base"
new_image_repo = "${IMAGE_REPO}-kylinv10-amd64"
sudo docker build - t ${new_image_repo}:${image_tag} - f Dockerfile.kylinv10 - - build - arg ARCH = "amd64" .
sudo docker login - u $IMAGE_REPO_USER - p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk - F '/' '{print $1}' )
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - security - kylin base"
echo "amd64KylinImageName=${new_image_repo}:${image_tag}" >> . / amd64_output
fi
# 条件性选择构建基于欧拉OS的镜像
if [[ - f Dockerfile.oel22 ]];then
echo "start build image - security - openeuler22 base"
new_image_repo = "${IMAGE_REPO}-openeuler22-amd64"
sudo docker build - t ${new_image_repo}:${image_tag} - f Dockerfile.oel22 - - build - arg ARCH = "amd64" .
sudo docker login - u $IMAGE_REPO_USER - p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk - F '/' '{print $1}' )
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - security - openeuler22 base"
echo "amd64Oel22ImageName=${new_image_repo}:${image_tag}" >> . / amd64_output
fi
# 清理builder镜像,避免产生none垃圾镜像。
sudo docker rmi jdos - etcd - restore - helper:latest - - force
|
提升
基于以上,构建时间从21min缩短至7min,构建效率提升66%