安装Docker
所有组件使用docker/docker compose搭建,所以先要安装docker。
docker安装过程略过,配置/etc/docker/daemon.json如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"data-root" : "/data/docker" ,
"bip" : "192.168.100.1/24" ,
"default-address-pools" : [
{ "base" : "192.168.0.0/16" , "size" : 24 }
],
"registry-mirrors" : [
"https://docker.1ms.run" ,
"https://docker.xuanyuan.me"
],
"live-restore" : true ,
"log-driver" : "json-file" ,
"log-opts" : { "max-size" : "50m" , "max-file" : "3" }
}
其中data-root一般调整到外挂磁盘;如果服务器的ip段是172段,需要修改bip到192段或者10段。
live-restore可以保证重启docker不重启容器(有时候需要关掉这个行为)。
搭建gitlab
首先需要搭建代码仓库,compose文件如下:
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
services :
gitlab :
image : registry.gitlab.cn/omnibus/gitlab-jh
container_name : gitlab
restart : always
hostname : 'zop-tools.cscec3b-iti.com'
environment :
GITLAB_OMNIBUS_CONFIG : |
external_url 'https://zop-tools.cscec3b-iti.com:7440'
gitlab_rails['trusted_proxies']=['172.18.0.0/16']
gitlab_rails['gitlab_port'] = 7440
gitlab_rails['gravatar_enabled'] = false
nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['redirect_http_to_https'] = false
nginx['proxy_set_headers'] = {
"X-Forwarded-Proto" => "https",
"X-Forwarded-Ssl" => "on",
"X-Forwarded-Port" => "7440"
}
ports :
- '7440:80'
volumes :
- '/data/gitlab/config:/etc/gitlab'
- '/data/gitlab/logs:/var/log/gitlab'
- '/data/gitlab/data:/var/opt/gitlab'
shm_size : '256m'
这里面的nginx是gitlab自带的nginx的配置。如果外围自己又加了个nginx,路径是:nginx(自建) -> nginx(gitlab) ->rails,这里面的转发header和外围nginx要对齐。
外围nginx的参考配置如下:
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
upstream gitlab {
server 172.18.195.26 : 7440 ;
}
server {
server_name zop-tools.cscec3b-iti.com 171.43.173.112 ;
listen 7440 ssl ;
ssl_certificate /etc/nginx/certs/cscec3b-iti.com.pem ;
ssl_certificate_key /etc/nginx/certs/cscec3b-iti.com.key ;
ssl_protocols TLSv1.1 TLSv1.2 ;
ssl_session_cache shared:GITLAB:10m ;
ssl_ciphers HIGH:!aNULL:!MD5 ;
ssl_prefer_server_ciphers on ;
location / {
proxy_pass http://gitlab ;
proxy_set_header Host $host ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $scheme ;
proxy_set_header X-Forwarded-Host $host:$server_port ;
proxy_set_header X-Forwarded-Ssl on ;
proxy_set_header X-Forwarded-Port $server_port ;
proxy_redirect off ;
proxy_connect_timeout 300 ;
proxy_read_timeout 300 ;
proxy_send_timeout 300 ;
client_max_body_size 5m ;
}
# 处理WebSocket连接
location /websocket/ {
proxy_pass http://gitlab ;
proxy_http_version 1 .1 ;
proxy_set_header Upgrade $http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_set_header Host $host ;
}
}
gitlab也支持高可用搭建,步骤就比较繁琐了(主要是通过PostgreSQL支持多节点),这里不记录。
搭建Gitlab runner
使用管理员账号登录gitlab,点击【管理员】按钮,进入【Runner】,点击【创建实例Runner】。
为Runner创建标签,ci文件中通过标签与Runner匹配,可以为某个Runner勾选【运行未打标签的作业】做兜底。
如果是虚拟机/裸金属服务器作为Runner,一台机器上装1个就可以了。
如果是k8s中安装Runner,整个集群里面装1个就行,这两种方式的工作原理不太一样,但都是有一个主进程周期探测有没有部署任务,有的话创建一个容器运行对应的任务。
创建完成后会显示密钥,复制它,后面会用上。
Docker安装Runner
首先创建一个config文件夹,放入runner的配置config.toml,参考如下:
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
concurrent = 8
check_interval = 5
connection_max_age = "15m0s"
shutdown_timeout = 0
[ session_server ]
session_timeout = 1800
[[ runners ]]
name = "ecs"
url = "https://zop-tools.cscec3b-iti.com:7440"
id = 3
token = "" #上面的密钥
token_obtained_at = 2025-09-23T08:08:03Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "docker"
request_concurrency = 4
[ runners . cache ]
MaxUploadedArchiveSize = 0
[ runners . cache . s3 ]
[ runners . cache . gcs ]
[ runners . cache . azure ]
[ runners . feature_flags ]
FF_USE_ADAPTIVE_REQUEST_CONCURRENCY = true
[ runners . docker ]
tls_verify = false
image = "docker:26"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = [ "/var/run/docker.sock:/var/run/docker.sock" , "/cache" ]
extra_hosts = [ "zop-tools.cscec3b-iti.com:172.18.195.25" ]
shm_size = 0
network_mtu = 0
由于CI进程里面一般需要使用docker进行镜像打包,而runner本身也要运行在docker里面。所以需要调用宿主机的docker来创建容器,从而避免docker in docker问题,因此需要再volumes里面做一层映射。当然还有个方案是使用其他工具打包(下面会讲)。
这里[runners.docker]里面的image可以随便写,因为ci文件那边可以覆盖掉。extra_hosts里面主要需要讲harbor镜像仓库的域名映射成内网地址,加快拉取速度。concurrent根据机器cpu核数适当调整。
启动Runner的compose文件参考:
1
2
3
4
5
6
7
8
9
10
11
12
services :
gitlab-runner :
image : gitlab/gitlab-runner:latest
container_name : gitlab-runner
restart : always
extra_hosts :
- "zop-tools.cscec3b-iti.com:172.18.195.25"
volumes :
- /data/gitlab/runner/config:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
environment :
- TZ=Asia/Shanghai
上面的config.toml要放到/data/gitlab/runner/config文件夹下面。
启动容器之后,gitlab那边可以看到runner上线。
K8s安装Runner
k8s使用helm安装:
1
2
helm repo add gitlab https://charts.gitlab.cn
kubectl create ns gitlab-runner
假设将runner安装在gitlab-runner这个ns,服务使用dev和test两个ns进行部署,对应开发和测试环境。需要创建一个ServiceAccout给runner使用,赋予runner调用k8s api的权利。
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
# 1. 在 gitlab-runner namespace 创建 ServiceAccount
apiVersion : v1
kind : ServiceAccount
metadata :
name : gitlab-deployer
namespace : gitlab-runner
---
# 2. 定义一个 ClusterRole,拥有所有资源的所有操作权限
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : dev-test-full-access
rules :
- apiGroups : [ "*" ]
resources : [ "*" ]
verbs : [ "*" ]
---
# 3. 在 dev namespace 绑定
apiVersion : rbac.authorization.k8s.io/v1
kind : RoleBinding
metadata :
name : gitlab-deployer-dev
namespace : dev
subjects :
- kind : ServiceAccount
name : gitlab-deployer
namespace : gitlab-runner
roleRef :
kind : ClusterRole
name : dev-test-full-access
apiGroup : rbac.authorization.k8s.io
---
# 4. 在 gitlab-runner namespace 绑定
apiVersion : rbac.authorization.k8s.io/v1
kind : RoleBinding
metadata :
name : gitlab-deployer-test
namespace : test
subjects :
- kind : ServiceAccount
name : gitlab-deployer
namespace : gitlab-runner
roleRef :
kind : ClusterRole
name : dev-test-full-access
apiGroup : rbac.authorization.k8s.io
---
# 4. 在 test namespace 绑定
apiVersion : rbac.authorization.k8s.io/v1
kind : RoleBinding
metadata :
name : gitlab-deployer-self
namespace : gitlab-runner
subjects :
- kind : ServiceAccount
name : gitlab-deployer
namespace : gitlab-runner
roleRef :
kind : ClusterRole
name : dev-test-full-access
apiGroup : rbac.authorization.k8s.io
使用kubectl apply -f account.yml,在集群中创建权限和绑定。这里给的权限比较大,也可以修改ClusterRole里面的rules只赋予必要的权限。
之后创建values.yml,修改helm安装runner的默认配置:
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
# 使用helm在k8s里面安装gitlab-runner
gitlabUrl : "https://zop-tools.cscec3b-iti.com:7440"
runnerRegistrationToken : "" #从gitlab中获取
runnerName : "k8s-gitlab-runner"
runnerTagList : "k8s,dev,test"
concurrent : 10 #并发度
checkInterval : 5
unregisterRunners : true
rbac :
create : false
serviceAccount : "gitlab-deployer"
clusterWideAccess : false
runners :
config : |
[[runners]]
[runners.kubernetes]
namespace = "gitlab-runner"
service_account = "gitlab-deployer"
ttlSecondsAfterFinished = 300
image = "ubuntu:22.04"
[runners.cache]
type = "s3"
[runners.cache.s3]
[runners.cache.gcs]
这里只需要绑定手动创建的ServiceAccount即可。
使用helm install gitlab-runner gitlab/gitlab-runner -f values.yaml --namespace gitlab-runner,完成runner安装,同样在gitlab里面会看到runner在线。
安装Harbor
harbor官方支持docker-compose安装,直接去github的release里面下载。
解压之后修改harbor.yml,主要需要修改的部分如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http :
port : 7441
external_url : https://zop-tools.cscec3b-iti.com:7441
harbor_admin_password : yourpass
data_volume : /data/harbor/data
trivy :
ignore_unfixed : false
skip_update : true
skip_java_db_update : true
offline_scan : true
security_check : vuln
insecure : false
log :
level : info
local :
rotate_count : 10
rotate_size : 20M
location : /data/harbor/log
注意 :harbor会启动多个容器,其中redis和postgresql的名字可能会和已有的容器冲突,可以使用docker rename修改已有容器的名字。
之后运行./install.sh --with-trivy进行安装。
然后去github下载oras二进制文件,放到PATH下面,运行下面的脚本下载漏洞库:
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
#!/usr/bin/bash
#创建缓存目录
mkdir -p /data/harbor/data/trivy-adapter/trivy/{ db,java-db}
cd /data/harbor/data/trivy-adapter/trivy
# 清空 db 目录下的内容
rm -rf db/*
# 清空 java-db 目录下的内容
rm -rf java-db/*
# 下载离线库文件
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-java-db:1
oras pull ghcr.nju.edu.cn/aquasecurity/trivy-db:2
# 解压 jdb.tar.gz 文件到 java-db 目录
tar -xvf javadb.tar.gz -C java-db
# 解压 db.tar.gz 文件到 db 目录
tar -xvf db.tar.gz -C db
# 删除压缩包文件
rm -f javadb.tar.gz
rm -f db.tar.gz
#chown赋权
chown -Rf 10000:10000 /data/harbor/data/trivy-adapter/trivy
可以在cronjob里面配置每天更新漏洞库。
之后就可以在harbor里面进行镜像管理和漏洞扫描了。
harbor外侧的nginx配置参考:
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
upstream harbor {
server 172.18.195.26 : 7441 ;
}
server {
server_name zop-tools.cscec3b-iti.com 171.43.173.112 ;
listen 7441 ssl ;
ssl_certificate /etc/nginx/certs/cscec3b-iti.com.pem ;
ssl_certificate_key /etc/nginx/certs/cscec3b-iti.com.key ;
ssl_protocols TLSv1.1 TLSv1.2 ;
ssl_session_cache shared:HARBOR:10m ;
ssl_ciphers HIGH:!aNULL:!MD5 ;
ssl_prefer_server_ciphers on ;
location / {
proxy_pass http://harbor ;
proxy_http_version 1 .1 ;
proxy_set_header Host $host:$server_port ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $scheme ;
proxy_redirect off ;
proxy_connect_timeout 300 ;
proxy_read_timeout 300 ;
proxy_send_timeout 300 ;
client_max_body_size 2000m ;
proxy_buffering on ;
proxy_pass_request_headers on ;
}
}
主要是要支持大镜像的拉取和推送。
安装nexus
由于ci运行在容器里无法复用宿主机的缓存,需要nexus做一层局域网缓存加快ci编译速度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
services :
nexus :
image : sonatype/nexus3:latest
container_name : nexus3
restart : always
ports :
- "7442:8081"
volumes :
- /data/nexus/data:/nexus-data
environment :
- NEXUS_CONTEXT=/
- INSTALL4J_ADD_VM_PARAMS=-Xms1g -Xmx4g -XX:MaxDirectMemorySize=4g -Djava.util.prefs.userRoot=/nexus-data/.java/.userPrefs
healthcheck :
test : [ "CMD" , "wget" , "--no-verbose" , "--tries=1" , "--spider" , "http://localhost:8081/service/metrics/health" ]
interval : 30s
timeout : 10s
retries : 10
注意点:
chown -R 200 <本地nexus-data目录>
参数里面jvm的内存分配,这玩意儿里面有es,内存建议不低于4g。
登录nexus,在settings-repositories里面手动创建npm的代理(proxy)和托管(hosted)。maven可以将中央仓库改为阿里源,增加google等常用proxy。
创建pypi代理时注意,remote url不加路径(https://pypi.tuna.tsinghua.edu.cn/ ),但是设置pip代理时,需要加路径(http://zop-tools.cscec3b-iti.com:7442/repository/pypi-tsinghua/simple ),其中pypi-tsinghua是你仓库的名字,后面的simple需要手动加上。
修改~/.m2/settings.xml,将仓库加到配置里,ci的时候也要将这个文件放到对应的位置。
外围nginx反向代理配置参考:
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
server {
server_name zop-tools.cscec3b-iti.com 171.43.173.112 ;
listen 7442 ssl ;
ssl_certificate /etc/nginx/certs/cscec3b-iti.com.pem ;
ssl_certificate_key /etc/nginx/certs/cscec3b-iti.com.key ;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3 ;
ssl_session_cache shared:HARBOR:10m ;
ssl_ciphers HIGH:!aNULL:!MD5 ;
ssl_prefer_server_ciphers on ;
location /v2 {
proxy_set_header Host $host:$server_port ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto "https" ;
proxy_read_timeout 600 ;
client_max_body_size 2000m ;
proxy_pass http://172.18.195.26:7442/repository/zop-image/ $request_uri ;
}
location / {
proxy_pass http://172.18.195.26:7442 ;
proxy_http_version 1 .1 ;
proxy_set_header Host $host:$server_port ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $scheme ;
proxy_redirect off ;
proxy_connect_timeout 300 ;
proxy_read_timeout 300 ;
proxy_send_timeout 300 ;
client_max_body_size 2000m ;
proxy_buffering on ;
proxy_pass_request_headers on ;
}
}
这里/v2是给docker仓库用的,如果不想安装harbor,而是用nexus托管docker镜像,可以创建对应的仓库(这里叫zop-image),然后配置上去。
但是,nexus的docker托管不支持按aritifact清理镜像,也不支持trivis集成,不如harbor成熟。
注意nexus和harbor都要配置清理策略,不然硬盘容易耗尽。
开发者账号需要的权限:
nx-component-upload
nx-repository-view-*-*-*
nx-search-read
安装SonarQube
如果想在ci时统一管控代码质量,可以安装sonar.
Docker Compose文件如下:
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
services :
sonarqube :
image : sonarqube:community
hostname : sonarqube
container_name : sonarqube
read_only : true
extra_hosts :
- "zop-tools.cscec3b-iti.com:172.18.195.25"
depends_on :
db :
condition : service_healthy
environment :
SONAR_JDBC_URL : jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME : sonar
SONAR_JDBC_PASSWORD : sonar
volumes :
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
- sonarqube_temp:/opt/sonarqube/temp
ports :
- "7443:9000"
networks :
- ${NETWORK_TYPE:-ipv4}
db :
image : postgres:17
healthcheck :
test : [ "CMD-SHELL" , "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
interval : 10s
timeout : 5s
retries : 5
hostname : postgresql
container_name : postgresql
environment :
POSTGRES_USER : sonar
POSTGRES_PASSWORD : sonar
POSTGRES_DB : sonar
volumes :
- postgresql:/var/lib/postgresql
networks :
- ${NETWORK_TYPE:-ipv4}
volumes :
sonarqube_data :
sonarqube_temp :
sonarqube_extensions :
sonarqube_logs :
postgresql :
networks :
ipv4 :
driver : bridge
enable_ipv6 : false
dual :
driver : bridge
enable_ipv6 : true
ipam :
config :
- subnet : "192.168.2.0/24"
gateway : "192.168.2.1"
- subnet : "2001:db8:2::/64"
gateway : "2001:db8:2::1"
需要注意的是,sonar不支持挂载volume,只能用docker create的volume,所以一定要在docker配置文件里修改data-root,避免磁盘溢出。
如果服务器可以连接github,可以在市场里面下载中文插件。否则需要手动下载jar包到/data/docker/volumes/sonarqube_sonarqube_extensions/_data/plugins, 这里data-root是/data/docker。
然后重启容器就会变成中文界面。
将sonar关联到gitlab也比较简单,在gitlab用户那边创建访问令牌,授权gitlab read相关api就可以了。
安装bytebase
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
services :
bytebase :
image : bytebase/bytebase:latest # Use the latest image or a specific version
container_name : bytebase
restart : unless-stopped
ports :
- "7444:8080"
volumes :
- ./bytebase-data:/var/opt/bytebase
command :
[
"--data" , "/var/opt/bytebase" ,
"--port" , "8080" ,
"--external-url" , "https://dev.chuyuwater.cn:32004"
]
对应nginx:
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
upstream bytebase {
server 172.21.0.6:7444;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name dev.chuyuwater.cn 172.21.0.6;
listen 32004 ssl;
ssl_certificate /etc/nginx/certs/fullchain.cer;
ssl_certificate_key /etc/nginx/certs/private.key;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_session_cache shared:BYTEBASE:10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location ~ ^/(v1:adminExecute|lsp) {
# Point to the actual Bytebase service, NOT the nginx domain
proxy_pass http://bytebase; # If Bytebase runs on the same host
proxy_http_version 1.1;
# Enables WebSocket which is required for SQL Editor autocomplete
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location / {
# Point to the actual Bytebase service, NOT the nginx domain
proxy_pass http://bytebase; # If Bytebase runs on the same host
}
proxy_read_timeout 3600;
proxy_send_timeout 3600;
}
配置CI/CD
都安装完成之后,在gitlab里面创建一个cicd专用的项目,比如devops/cicd,可以设置为”内部“权限,或者公开权限(如果用了vpn的话),方便其他项目集成。
在项目根目录创建templates文件夹,然后将完善项目描述、ReadMe文件。
在项目根目录下创建.gitlab-ci.yml文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
stages :
- release
create-release :
stage : release
image : registry.gitlab.com/gitlab-org/release-cli:latest
script : echo "Creating release $CI_COMMIT_TAG"
rules :
- if : $CI_COMMIT_TAG
release :
tag_name : $CI_COMMIT_TAG
description : "Release $CI_COMMIT_TAG of components in $CI_PROJECT_PATH"
这样一旦给commit打了tag就会自动发布新版本。
在templates里面添加常用的模板供其他项目集成,比如java后端的编译+部署模板如下:
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
variables :
# 默认镜像制品名(可被项目覆盖)
IMAGE_ARTIFACT_NAME : "$CI_PROJECT_NAME"
# 默认容器名称
CONTAINER_NAME : "app"
stages :
- build
- deploy
default :
before_script :
- |
export IMAGE_TAG="$CI_COMMIT_SHORT_SHA"
if [[ -n "$CI_COMMIT_TAG" ]]; then export IMAGE_TAG="$CI_COMMIT_TAG"; fi
export IMAGE="$HARBOR_HOST/$REPO_NAME/$IMAGE_ARTIFACT_NAME:$IMAGE_TAG"
echo "Built image will be: $IMAGE"
.kaniko_build :
image :
name : zop-tools.cscec3b-iti.com:7441/cicd/kaniko:debug
entrypoint : [ "" ]
script :
- echo "{\"auths\":{\"${HARBOR_HOST}\":{\"auth\":\"$(echo -n ${HARBOR_USER}:${HARBOR_PWD} | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context ${CI_PROJECT_DIR} --dockerfile ${CI_PROJECT_DIR}/Dockerfile --destination ${IMAGE}
# 使用kaniko构建镜像(dev/test)
dev_test_build :
stage : build
extends : .kaniko_build
rules :
- if : '$CI_COMMIT_BRANCH == "dev"'
when : manual
variables :
REPO_NAME : "dev"
- if : '$CI_COMMIT_BRANCH == "test"'
variables :
REPO_NAME : "test"
tags : [ $CI_COMMIT_BRANCH ]
# 使用kaniko构建镜像(生产)
release_build :
stage : build
extends : .kaniko_build
rules :
- if : '$CI_COMMIT_TAG =~ /^v/'
variables :
REPO_NAME : "main"
tags : [ "main" ]
# 部署到 Kubernetes(仅 dev/test 分支)
dev_test_deploy :
stage : deploy
image : zop-tools.cscec3b-iti.com:7441/cicd/kubectl:1.24
script :
- echo "Deploying $IMAGE to namespace $K8S_NAMESPACE"
- kubectl set image deployment/$IMAGE_ARTIFACT_NAME $CONTAINER_NAME=$IMAGE -n $K8S_NAMESPACE
- kubectl rollout status deployment/$IMAGE_ARTIFACT_NAME -n $K8S_NAMESPACE --timeout=300s
rules :
- if : '$CI_COMMIT_BRANCH == "dev"'
when : manual
variables :
K8S_NAMESPACE : "dev"
REPO_NAME : "dev"
- if : '$CI_COMMIT_BRANCH == "test"'
when : manual
variables :
K8S_NAMESPACE : "test"
REPO_NAME : "test"
needs : [ dev_test_build ]
tags : [ $CI_COMMIT_BRANCH ]
这个CI/CD文件使用kaniko进行编译打包 ,并支持dev/test环境持续部署(替换镜像名)。
为了加快CI/CD的速度,这里将image都上传到私库里面了。
对于k8s的runner,需要同时修改k8s宿主机的host和coredns的host,将域名映射成内网ip。
注 :google官方的kaniko已经不再维护,建议使用第三方维护的martizih/kaniko镜像,用debug版本(有bash)。
在对应的项目的.gitlab-ci.yml里,引用对应的模板即可:
1
2
3
4
5
6
7
8
include :
- project : 'devops/cicd'
ref : v0.9.2
file : 'templates/backend.yml'
# 可选:覆盖默认变量
variables :
IMAGE_ARTIFACT_NAME : "hello-world"
这里面的ref对应release的版本,如果还在调试,可以用main引用最新的commit.
项目的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
FROM zop-tools.cscec3b-iti.com:7441/cicd/openjdk:21-builder AS builder
# 设置工作目录
WORKDIR /app
# 复制 Maven 配置文件
COPY pom.xml .
# 下载依赖(利用 Docker 缓存)
RUN mvn dependency:go-offline -B
# 复制源代码
COPY src ./src
# 编译打包
RUN mvn package -DskipTests
# 第二阶段:运行环境
FROM zop-tools.cscec3b-iti.com:7441/cicd/openjdk:21
# 设置工作目录
WORKDIR /app
# 从 builder 阶段复制 jar 包
COPY --from= builder /app/target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 运行应用
ENTRYPOINT [ "java" , "-jar" , "app.jar" ]
注意这是一个多阶段Dockerfile,编译型语言需要在第一阶段构建出目标文件,解释型语言(如Python)一般不需要。
附:Docker镜像定制
docker镜像最小的一般是alpine版本,定制化的话需要替换国内源。如果是go/c++服务,尽量用glibc版本,musl版本有时候会有一些奇奇怪怪的问题。
glibc版本的alpine:
1
2
3
4
5
6
7
8
FROM frolvlad/alpine-glibc:alpine-3.18_glibc-2.34
ENV TZ Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache alpine-conf ttf-dejavu fontconfig \
&& /sbin/setup-timezone -z Asia/Shanghai \
&& apk del alpine-conf && rm -rf /tmp/* /var/cache/apk/*
一般的基于alpine的镜像定制(java21):
1
2
3
4
5
6
7
8
FROM azul/zulu-openjdk-alpine:21
ENV TZ Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache alpine-conf ttf-dejavu fontconfig \
&& /sbin/setup-timezone -z Asia/Shanghai \
&& apk del alpine-conf && rm -rf /tmp/* /var/cache/apk/*
用的时候,直接用apk安装需要的二进制文件即可,例如apk add curl。