关键字: k8s, gitlab, kubesphere, kubenetes, springboot, springcloud, .gitlab-ci.yml, minio
服务名 | 版本 | 备注 |
---|---|---|
gitlab | GitLab Community Edition 11.3.5 | 公司自建服务,非k8s体系 |
kubesphere | v3.3.2 | |
kubernetes | v1.23.10 | 使用kubesphere搭建k8s服务 |
minio | RELEASE.2023-09-30T07-02-29Z | 使用helm部署, 作为gitlab ci的外部缓存; 可以不使用minio,使用gilab ci自带缓存也可以 |
registry | - | 使用阿里云镜像库个人版,可以用harbor等私有部署代替 |
此流程图是一个简易的流程示意图, 包含两个stage build和deploy, 每个stage中分别包含一个job,因此会触发初始化两个临时pod容器组
能够使用gitlab ci流程完成springboot项目前后端的持续集成及持续部署
下图是官网对不同类型runner的能力描述,因为我们是k8s环境,因此我选择k8s类型runner
在企业空间页面,选择应用管理-应用仓库,点击添加
将gitlab chart库填入(https://charts.gitlab.io), 点击确定即可保存,
保存成功后即可在项目中新建gitlab应用
选择gitlab-runner应用,版本影响不大, 我的gitlab是11, 选取最新16.4.1安装也没有事
接下来是很重要的应用设置文件,下面的应用配置是我的个人应用配置
image:
registry: registry.gitlab.com
image: gitlab-org/gitlab-runner
useTini: false
imagePullPolicy: IfNotPresent
gitlabUrl: 'https://git.xxx.cn'
image_pull_secrets:
1. 'aliyun-hangzhou-reg'
runnerRegistrationToken: "sdfsdfsdf"
terminationGracePeriodSeconds: 3600
privileged: true
concurrent: 10
checkInterval: 30
sessionServer:
enabled: false
rbac:
create: true
rules:
- resources:
- configmaps
- events
- pods
- pods/attach
- pods/exec
- secrets
- services
verbs:
- get
- list
- watch
- create
- patch
- update
- delete
- apiGroups:
- ''
resources:
- pods/exec
verbs:
- create
- patch
- delete
clusterWideAccess: false
serviceAccountName: lit
podSecurityPolicy:
enabled: false
resourceNames:
- gitlab-runner
metrics:
enabled: false
portName: metrics
port: 9252
serviceMonitor:
enabled: false
service:
enabled: false
type: NodePort
runners:
config: |
[[runners]]
environment = ["REG_USER_NAME=", "REG_PASSWD="]
cache_dir = "/cache"
[runners.cache]
Type = "s3"
Path = "/cache"
Shared = false
[runners.cache.s3]
ServerAddress = "minio-w1hko6-svc:9000"
AccessKey = "minio"
SecretKey = "minio"
BucketName = "runners-cache"
BucketLocation = "cn-hb-wh-1"
Insecure = true
[runners.kubernetes]
namespace = "{{.Release.Namespace}}"
image = "ubuntu:22.04"
[[runners.kubernetes.host_aliases]]
ip = "192.168.10.128"
hostnames = ["lb.kubesphere.local"]
[[runners.kubernetes.volumes.config_map]]
name = "runner-config"
mount_path = "/runner-config"
[[runners.kubernetes.volumes.pvc]]
name = "gitlab-runner-local-pvc"
mount_path = "/root/.m2/repository"
[[runners.kubernetes.volumes.host_path]]
name = "docker-sock"
mount_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
configPath: ''
cache: {}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
runAsNonRoot: true
privileged: false
capabilities:
drop:
- ALL
podSecurityContext:
runAsUser: 100
fsGroup: 65533
resources: {}
affinity: {}
nodeSelector: {}
tolerations: []
hostAliases: []
deploymentAnnotations: {}
deploymentLabels: {}
podAnnotations: {}
podLabels: {}
priorityClassName: ''
secrets: []
configMaps: {}
volumeMounts:
- mountPath: /maven
name: volume-runner
volumes:
- name: volume-runner
persistentVolumeClaim:
claimName: gitlab-runner-local-pvc
总的来说,这个配置文件用于在Kubernetes上部署GitLab Runner,并指定了一些安全性、并发性、挂载卷以及GitLab连接信息等方面的配置。根据需要,可以根据实际情况进行修改和自定义。
runners:
config: |
[[runners]]
environment = ["REG_USER_NAME=", "REG_PASSWD="]
cache_dir = "/cache"
[runners.cache]
Type = "s3"
Path = "/cache"
Shared = false
[runners.cache.s3]
ServerAddress = "minio-w1hko6-svc:9000"
AccessKey = "minio"
SecretKey = "minio"
BucketName = "runners-cache"
BucketLocation = "cn-hb-wh-1"
Insecure = true
[runners.kubernetes]
namespace = "{{.Release.Namespace}}"
image = "ubuntu:22.04"
[[runners.kubernetes.host_aliases]]
ip = "192.168.10.128"
hostnames = ["lb.kubesphere.local"]
[[runners.kubernetes.volumes.config_map]]
name = "runner-config"
mount_path = "/runner-config"
[[runners.kubernetes.volumes.pvc]]
name = "gitlab-runner-local-pvc"
mount_path = "/root/.m2/repository"
[[runners.kubernetes.volumes.host_path]]
name = "docker-sock"
mount_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
[[runners]]: 这是GitLab Runner配置的起始点,表示一个GitLab Runner的配置块。通常,你可以有多个不同的[[runners]]块来配置不同的Runner。
environment: 这里可以指定一些环境变量,它们以形式"键=值"存在,会在每个执行job中均初始化此处环境变量信息
cache_dir: 指定了缓存的目录,缓存是用于存储构建和依赖的数据以加速构建过程的工具。默认缓存目录即为/cache
[runners.cache]: 这个块包含了关于缓存的详细配置 。
minio是部署分布式缓存的选择, 可以使用gitlab自带的缓存配置
与gitlab仓库类似, 将charts.min.io 到应用仓库中
新建应用,版本随意选择,我选择了最新版本
主要需要修改的参数
该脚本是该文章重点内容
如图所示该流程一共五个阶段,目前每个阶段均只有一个job。
- pre阶段:该阶段主要为预备阶段,首先是生成动态环境变量,其次是获取到本次提交的内容是属于那些子模块,获取到CHANGE_MODULES,为后续push及deploy阶段做准备工作
- build阶段: 该阶段为mavn 构建阶段,将maven构建制品放入缓存(注: 制品存储可以直接使用artifact, 我由于外部原因,只能使用cache缓存代替)
- push阶段: 构建docker镜像以及将镜像推送到镜像库
- deploy: 将微服务通过kubectl调度容器组镜像信息
- clear: 由于minio存储空间及其有限,因此最后手动进行了清理
stages:
- pre
- build
- push
- deploy
- clear
# 公共配置
.common: &common
# 触发流程的分支
only:
- dev
# 调试用
- litao-dev
variables:
TZ: Asia/Shanghai
# 测试环境
NAMESPACE: crm2
# 监听待发布服务列表
DEPLOY_MODULES: admin,authorization,bi,examine,gateway
# 预检查,查看待发布服务列表
pre-checking:
<<: *common
image: bitnami/git
stage: pre
before_script:
# 复制获取变化文件列表模型
- cp /runner-config/change_modules.sh .
- chmod +x change_modules.sh
script:
- export CHANGE_MODULES=$(sh change_modules.sh $CI_COMMIT_SHA $DEPLOY_MODULES)
- export BUILD_START_TIME=$(date +%Y%m%d%H%M%S)
# 存储环境变量
- echo "BUILD_START_TIME=$BUILD_START_TIME" >> share.env
- echo "CHANGE_MODULES=$CHANGE_MODULES" >> share.env
artifacts:
paths:
# job间共享环境变量
- share.env
# maven构建
building:
<<: *common
image: maven:3.6.3-jdk-8
stage: build
dependencies:
- pre-checking
cache:
key: build-cache
paths:
# 存储变更打包的制品
- target
#aliyun mvn配置文件准备,提高速度
before_script:
# 读取共享环境变量信息
- source share.env
- if [ -z "$CHANGE_MODULES" ]; then
echo "微服务未发生变动,跳过部署";
exit 0;
fi
# 将自定义阿里云xml复制到镜像中
- echo `ls $MAVEN_HOME/conf`
- cp -f /runner-config/setting.xml $MAVEN_HOME/conf/settings.xml
script:
- echo "=============== 开始编译源码,在target目录生成jar文件 ==============="
- mvn clean compile package -Dmaven.test.skip=true
- echo "=============== 完成源码编译打包 ==============="
# 将需要缓存的文件复制到target文件夹中
- cp /runner-config/copy_artifacts.sh .
- chmod +x copy_artifacts.sh
- echo $CHANGE_MODULES
- sh copy_artifacts.sh target $CHANGE_MODULES
- ls -lh target
artifacts:
paths:
# job间共享环境变量
- share.env
################-----push-----##########################
# push模块公共组件
push-service:
<<: *common
image: docker:latest
stage: push
dependencies:
- building
cache:
key: build-cache
policy: pull
paths:
- target/*tar.gz
before_script:
- cat share.env
- source share.env
# 提前登陆镜像库
- echo "password" | docker login -u "username" --password-stdin registry.cn-hangzhou.aliyuncs.com
# CHANGE_MODULES 变量不为空,执行构建操作
# 生成镜像名称
# 使用 $module 进行 Docker 构建操作
# CHANGE_MODULES 变量为空,跳过构建
script:
- |
if [ -n "$CHANGE_MODULES" ]; then
modules=$(echo "$CHANGE_MODULES" | tr ',' '\n')
for module in $modules; do
image_name="registry.cn-hangzhou.aliyuncs.com/quadimodo/crm-${module}:${CI_PIPELINE_IID}-${BUILD_START_TIME}"
docker build -t "$image_name" --build-arg SERVER_NAME="$module" .
docker push "$image_name"
done
else
echo "CHANGE_MODULES is empty, skipping build."
fi
artifacts:
paths:
# job间共享环境变量
- share.env
################-----push-----##########################
###############------deploy-----########################
# 部署公共模块
deploy-service:
<<: *common
image: bitnami/kubectl:latest
stage: deploy
dependencies:
- push-service
before_script:
- cat /runner-config/config.yml | base64 -d > ./config
# 获取环境变量信息
- source share.env
script:
- |
if [ -n "$CHANGE_MODULES" ]; then
modules=$(echo "$CHANGE_MODULES" | tr ',' '\n')
for module in $modules; do
image_name="registry.cn-hangzhou.aliyuncs.com/quadimodo/crm-${module}:${CI_PIPELINE_IID}-${BUILD_START_TIME}"
K8S_SERVER_NAME="crm-${module}-v1"
kubectl set image deployment ${K8S_SERVER_NAME} *=${image_name} --kubeconfig ./config --namespace $NAMESPACE
done
else
echo "CHANGE_MODULES is empty, skipping deploy."
fi
artifacts:
paths:
# job间共享环境变量
- share.env
###############------deploy-----########################
# 清除缓存信息
clear-cache:
<<: *common
image:
name: minio/mc
entrypoint: [ '' ]
stage: clear
after_script:
# 删除缓存
- mc rm --recursive --force minio/runners-cache/cache/runner
before_script:
# 对缓存进行配置
- export MINIO_HOST=$(cat /runner-config/MINIO_HOST)
- export MINIO_ACCESS_KEY=$(cat /runner-config/MINIO_ACCESS_KEY)
- export MINIO_SECRET_KEY=$(cat /runner-config/MINIO_SECRET_KEY)
- mc alias set minio $MINIO_HOST $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
script:
# 删除所有文件, 避免再次缓存
- rm -rf */target/*tar.gz
逐段解释分析
在3.1.2.1 runner配置中, 添加了将configmap键值对挂载到工作pods指定目录/runner-config 下, 用于保存待执行的shell脚本及部分配置文件以及不方便放在gitlab脚本中的保密文件
#!/bin/bash
# 接受两参数:Git提交的SHA和子模块列表
commit_sha=$1
submodules=$2
# 检查是否提供了足够的参数
if [ -z "$commit_sha" ] || [ -z "$submodules" ]; then
echo "Usage: $0 "
exit 1
fi
# 分割子模块列表为数组
# IFS=',' read -ra submodule_list <<< "$submodules"
submodule_list=$(echo "$submodules" | tr ',' '\n')
# 初始化变更的子模块列表
changed_submodules=""
# 使用Git命令获取指定提交与上一次提交之间的文件更改
changed_files=$(git diff-tree -r --name-only --no-commit-id --pretty=format:"%H %P %an %ad" $commit_sha| grep -v ".*\.\(swp\|bak\)")
# 检查每个文件是否以指定的文件夹前缀开头
for file in $changed_files; do
for submodule in $submodule_list; do
case "$file" in
"$submodule"*)
if [ -z "$changed_submodules" ]; then
changed_submodules="$submodule"
else
changed_submodules="$changed_submodules,$submodule"
fi
break ;;
esac
done
done
# 使用 awk 去除重复的前缀
changed_submodules=$(echo "$changed_submodules" | tr ',' '\n' | awk '!seen[$0]++' | tr '\n' ',' | sed 's/,$//')
# 输出变更的子模块列表
echo "$changed_submodules"
#!/bin/bash
# 检查是否提供了正确数量的参数
if [ $# -lt 2 ]; then
echo "Usage: $0 "
exit 1
fi
# 第一个参数是目标文件夹路径
target_dir="$1"
# 第二个参数是逗号分隔的源文件夹路径字符串,可以包含环境变量
source_dirs="$2"
# 创建目标文件夹,如果它不存在
mkdir -p "$target_dir"
# 使用逗号分隔符分割源文件夹字符串为数组
# IFS=',' read -ra source_dirs_array <<< "$source_dirs"
source_dirs_array=$(echo "$source_dirs" | tr ',' '\n')
# 循环遍历每个源文件夹
for source_dir in $source_dirs_array; do
target_dir_in_source="$source_dir/target"
done
# 检查source_dir/target目录是否存在,如果不存在则创建
if [ ! -d "$target_dir_in_source" ]; then
mkdir -p "$target_dir_in_source"
fi
# 使用find命令查找指定目录下的所有.tar.gz文件并复制到目标文件夹
find "$target_dir_in_source" -type f -name "*.tar.gz" -exec cp {} "$target_dir" \;
echo "复制完成"
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>nexus-aliyunid>
<mirrorOf>centralmirrorOf>
<name>Nexus aliyunname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
mirror>
<mirror>
<id>net-cnid>
<mirrorOf>centralmirrorOf>
<name>Nexus netname>
<url>http://maven.net.cn/content/groups/public/url>
mirror>
mirrors>
<profiles>
<profile>
<repositories>
<repository>
<id>nexusid>
<name>local private nexusname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>nexusid>
<name>local private nexusname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>falseenabled>
snapshots>
pluginRepository>
pluginRepositories>
profile>
profiles>
<activeProfiles>
<activeProfile>nexusactiveProfile>
activeProfiles>
settings>
将以上config的yml文件base64后存储到config.yml中。也可以不经过base64,修改一下shell脚本内容即可,不过转换base64,可能会更安全一点
以上流程均为自己经过N次尝试后能够完成需求及性能比较过得去的方案, 肯定不是最佳解决方案。比如, cache如此麻烦,是artifact大小限制问题, 可以直接修改artifact大小限制而不用cache配置及minio搭建。 又比如可以直接升级gitlab的版本,可以解锁一些高级特性,如 rules, only:changes 。不仅要看官网教程,同时也要对照本地gitlab 的help文档看,这样可以知道本地gitlab版本支持语法的界限,可以避免走很多坑
具体可以点击如下链接查看
gitlab-ci yml关键字列表
在k8srunner中, 每次执行一个job都会启动一个新的指定镜像的容器组,因此job之间的信息共享和其他runner存在差异。
我通过挂载docker.sock的方式相对来说是最不安全也是最low的方式,但是我尝试另外两种方式都失败了。花了很长时间搜索错误还是没有头绪,无奈只能放弃
k8s using docker in builds
大家可以点击以上链接自行尝试另外两种可以执行docker build操作的方式
我将上文中出现的链接都放在此处进行统一展示
k8s using docker in builds
gitlab-ci yml关键字列表