自动化构建 Golang 项目
这里演示一下对于 Golang 的自动化构建,本次示例的代码地址: https://gitee.com/dukuan/go-project.git。 先将该项目导入到 Gitlab 中。
定义 Jenkinsfile
本次示例的 Jenkinsfile 和之前的也无太大区别,需要的更改的位置是构建容器的镜像、缓存目录、Git 地址和项目名称:
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222pipeline {
agent {
kubernetes {
cloud 'kubernetes-test'
slaveConnectTimeout 1200
workspaceVolume hostPathWorkspaceVolume(hostPath: "/opt/workspace", readOnly: false)
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
image: \'registry.cn-beijing.aliyuncs.com/citools/jnlp:alpine\'
name: jnlp
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/etc/localtime"
name: "localtime"
readOnly: false
- command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "registry.cn-beijing.aliyuncs.com/citools/golang:1.15"
imagePullPolicy: "IfNotPresent"
name: "build"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "localtime"
# 缓存目录为 /go/pkg/, 执行 go build 时下载的依赖包会缓存在该目录
- mountPath: "/go/pkg/"
name: cachedir
- command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "registry.cn-beijing.aliyuncs.com/citools/kubectl:self-1.17"
imagePullPolicy: "IfNotPresent"
name: "kubectl"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "localtime"
readOnly: false
- command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "registry.cn-beijing.aliyuncs.com/citools/docker:19.03.9-git"
imagePullPolicy: "IfNotPresent"
name: "docker"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "localtime"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "dockersock"
readOnly: false
restartPolicy: "Never"
nodeSelector:
build: "true"
securityContext: {}
volumes:
- hostPath:
path: "/var/run/docker.sock"
name: "dockersock"
- hostPath:
path: "/usr/share/zoneinfo/Asia/Shanghai"
name: "localtime"
# 缓存保存的位置
- name: "cachedir"
hostPath:
path: "/opt/gopkg"
'''
}
}
stages {
stage('Pulling Code') {
parallel {
stage('Pulling Code by Jenkins') {
when {
expression {
env.gitlabBranch == null
}
}
steps {
git(
url: 'git@gitlab.59izt.com:kubernetes/go-project.git', # 修改项目仓库地址
changelog: true,
poll: true,
branch: "${BRANCH}",
credentialsId: 'gitlab-key'
)
script {
COMMIT_ID = sh(
returnStdout: true,
script: "git log -n 1 --pretty=format:'%h'"
).trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
stage('Pulling Code by trigger') {
when {
expression {
env.gitlabBranch != null
}
}
steps {
git(
url: 'git@gitlab.59izt.com:kubernetes/go-project.git', # 修改项目仓库地址
branch: env.gitlabBranch,
changelog: true,
poll: true,
credentialsId: 'gitlab-key'
)
script {
COMMIT_ID = sh(
returnStdout: true,
script: "git log -n 1 --pretty=format:'%h'"
).trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
}
}
# 构建命令
stage('Building') {
steps {
container(name: 'build') {
sh '''
export GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go build
'''
}
}
}
stage('Docker build for creating image') {
environment {
HARBOR_USER = credentials('HARBOR_ACCOUNT')
}
steps {
container(name: 'docker') {
sh """
echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${TAG}
docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .
docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}
"""
}
}
}
stage('Deploying to K8s') {
environment {
MY_KUBECONFIG = credentials('kubernetes-test')
}
steps {
container(name: 'kubectl') {
sh """
/usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG \
set image deploy -l \
app=${IMAGE_NAME} \
${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} \
-n $NAMESPACE
"""
}
}
}
}
environment {
COMMIT_ID = ''
HARBOR_ADDRESS = 'harbor.china-snow.net'
REGISTRY_DIR = 'kubernetes'
IMAGE_NAME = 'go-project' # 修改镜像名称
NAMESPACE = 'kubernetes'
TAG = ''
}
parameters {
gitParameter(
branch: '',
branchFilter: 'origin/(.*)',
defaultValue: '',
description: 'Branch for build and deploy',
name: 'BRANCH',
quickFilterEnabled: false,
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_BRANCH'
)
}
}以上文件内容相比 Java 项目的 Jenkinsfile 文件,只是修改了以下几个地方:
- 构建容器(build)改为具有 Golang 环境的镜像,版本需要和公司项目一致
1
image: "registry.cn-beijing.aliyuncs.com/citools/golang:1.15"
- Golang 的缓存目录为 /go/pkg/,执行
go build
时下载的依赖包会缓存在该目录
1
2
3- mountPath: "/go/pkg/"
name: "cachedir"
readOnly: false- 修改
Pulling Code
Stage 中 git 的 URL 地址; - 修改
Building
Stage 中的构建命令,具体的命令可以询问开发
1
2
3export GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go build- 修改 environment 配置中的镜像名称为项目名称
定义 Dockerfile
和之前不一样的地方是,Golang 编译后生成的是一个二进制文件,可以直接执行,所以底层镜像设置为 alpine 或者其它的小镜像即可:
1
2
3
4
5
6
7
8
9
10FROM registry.cn-beijing.aliyuncs.com/dotbalo/alpine-glibc:alpine-3.9
# 如果定义了单独的配置文件,可能需要拷贝到镜像中
COPY conf/ ./conf
# 包名称按照实际情况进行修改
COPY ./go-project ./
# 启动该应用
ENTRYPOINT [ "./go-project"]
定义 kubernetes 资源
创建 go-demo.yaml 文件,内容如下
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
110
111
112
113
114apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: go-project
name: go-project
namespace: kubernetes
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: go-project
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: go-project
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: go-project
operator: In
values:
- go-project
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: go-project
ports:
- containerPort: 8080
name: web
protocol: TCP
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: C.UTF-8
resources:
limits:
cpu: "4"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
lifecycle: {}
readinessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8080
timeoutSeconds: 2
livenessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8080
timeoutSeconds: 2
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: harborkey
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
labels:
app: go-project
name: go-project
namespace: kubernetes
spec:
ports:
- name: web
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: go-project
sessionAffinity: None
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: go-project
namespace: kubernetes
spec:
rules:
- host: go-project.test.com
http:
paths:
- backend:
service:
name: go-project
port:
number: 8080
path: /
pathType: ImplementationSpecific创建资源
1
2
3
4# kubectl create -f go-demo.yaml
deployment.apps/go-project created
service/go-project created
ingress.networking.k8s.io/go-project created
创建 Jenkins Job
- 创建 Jenkins Job 和上述小节也并无区别,在此不再重复演示。创建完成后,可以自行构建
- 查看 Harbor 仓库是否已经存在镜像
- 在 kubernetes 集群查看服务是否更新,查看镜像TAG是否是最新的镜像