云原生专栏大纲
image: maven:3.6.3-jdk-8
before_script:
- ls
services:
- name: mysql:latest
alias: mysql-1
build:
image: maven:3.6.3-jdk-8
stage: build
tags:
- k8s
script:
- ls
- sleep 2
- echo "mvn clean "
- sleep 10
deploy:
stage: deploy
tags:
- k8s
script:
- echo "deploy"
environment:
name: production
url: http://www.baidu.com
在 GitLab Runner 中使用 Kubernetes (k8s) 执行器时,以下是其工作流程的一般概述:
通过将 GitLab Runner 与 Kubernetes 执行器结合使用,你可以在 Kubernetes 集群中动态地创建和管理容器化的作业环境,实现高度可扩展的持续集成和持续交付流程。
注册器kubernetes 的gitlab runner,使用参考Kubernetes executor官网。Executors | GitLab
执行器 | 极狐GitLab
helm方式部署优势:
helm方式部署缺点:
若要为每个生成作业创建 PersistentVolumeClaim,请确保查看如何启用 Pod Spec 功能。
Kubernetes 允许创建一个附加到 Pod 生命周期的临时 PersistentVolumeClaim。 如果在 Kubernetes 集群上启用了动态预配,这将起作用,允许 每个请求一个新的卷,该卷也将与 Pod 的生命周期相关联。PVC
启用动态配置后,可以按如下方式修改:
[[runners.kubernetes.pod_spec]]
name = "ephemeral-pvc"
patch = '''
containers:
- name: build
volumeMounts:
- name: builds
mountPath: /builds
- name: helper
volumeMounts:
- name: builds
mountPath: /builds
volumes:
- name: builds
ephemeral:
volumeClaimTemplate:
spec:
storageClassName: >
accessModes: [ ReadWriteOnce ]
resources:
requests:
storage: 1Gi
'''
要存储作业的 builds 目录,请定义自定义卷挂载到 已配置(默认)。 如果您使用 PVC 卷, 基于接入模式, 您可能被限制为在一个节点上运行作业。builds_dir/builds
concurrent = 4
[[runners]]
# usual configuration
executor = "kubernetes"
builds_dir = "/builds"
[runners.kubernetes]
[[runners.kubernetes.volumes.empty_dir]]
name = "repo"
mount_path = "/builds"
medium = "Memory"
默认情况下,Kubernetes CI 作业中的构建目录是临时的。 如果您想在作业中持久化 Git 克隆(以使其正常工作), 您必须为生成文件夹装载持久性卷声明。 由于多个作业可以同时运行,因此您必须 使用一个卷,或为每个电位设置一个卷 同一运行器上的并发作业。后者可能性能更高。
concurrent = 4
[[runners]]
executor = "kubernetes"
builds_dir = "/mnt/builds"
[runners.kubernetes]
[[runners.kubernetes.volumes.pvc]]
# CI_CONCURRENT_ID identifies parallel jobs of the same runner.
# name是pvc名称如"build-pvc-$CI_CONCURRENT_ID"
name = "k8s-running-pod-data"
mount_path = "/mnt/builds"
concurrent = 4
check_interval = 30
[[runners]]
name = "myRunner"
url = "gitlab.example.com"
executor = "kubernetes"
[runners.kubernetes]
helper_image = "gitlab-registry.example.com/helper:latest"
[runners.kubernetes.pod_security_context]
run_as_non_root = true
run_as_user = 59417
run_as_group = 59417
fs_group = 59417
[runners.kubernetes.init_permissions_container_security_context]
run_as_user = 1000
run_as_group = 1000
[runners.kubernetes.build_container_security_context]
run_as_user = 65534
run_as_group = 65534
[runners.kubernetes.build_container_security_context.capabilities]
add = ["NET_ADMIN"]
[runners.kubernetes.helper_container_security_context]
run_as_user = 1000
run_as_group = 1000
[runners.kubernetes.service_container_security_context]
run_as_user = 1000
run_as_group = 1000
选择 | 类型 | 必填 | 描述 |
---|---|---|---|
run_as_group | int | 不 | 用于运行容器进程入口点的 GID。 |
run_as_non_root | 布尔 | 不 | 指示容器必须以非 root 用户身份运行。 |
run_as_user | int | 不 | 用于运行容器进程入口点的 UID。 |
capabilities.add | 字符串列表 | 不 | 运行容器时要添加的功能。 |
capabilities.drop | 字符串列表 | 不 | 运行容器时要删除的功能。 |
selinux_type | 字符串 | 不 | 与容器进程关联的 SELinux 类型标签。 |
使用文件中的参数指定单个或多个拉取策略。 该策略控制如何提取和更新映像,并应用于生成映像、帮助程序映像和任何服务。pull_policyconfig.toml
要确定要使用的策略,请参阅有关拉取策略的 Kubernetes 文档。
对于单个拉取策略:
[runners.kubernetes]
pull_policy = "never"
对于多个拉取策略:
[runners.kubernetes]
# use multiple pull policies
pull_policy = ["always", "if-not-present"]
当您定义多个策略时,将尝试每个策略,直到成功获取映像。 例如,当您使用 时,如果策略由于临时注册表问题而失败,则使用该策略。[ always, if-not-present ]if-not-presentalways
要重试失败的拉取,请执行以下操作:
[runners.kubernetes]
pull_policy = ["always", "always"]
GitLab 的命名约定与 Kubernetes 的命名约定不同。
运行器拉取策略 | Kubernetes 拉取策略 | 描述 |
---|---|---|
空白 | 空白 | 使用 Kubernetes 指定的默认策略。 |
if-not-present | IfNotPresent | 仅当执行作业的节点上尚不存在映像时,才会拉取该映像。您应该注意一些安全注意事项 |
always | Always | 每次执行作业时都会拉取映像。 |
never | Never | 永远不会拉取映像,并且要求节点已经拥有它。 |
使用以下选项配置 Pod 的 DNS 设置。
选项 | 类型 | 必须 | 描述 |
---|---|---|---|
nameservers | string 列表 | 否 | 将用作 Pod 的 DNS 服务器的 IP 地址列表 |
options | KubernetesDNSConfigOption | 否 | 一个可选的对象列表,其中每个对象可能有一个名称参数(必需)和一个值参数(可选) |
searches | string 列表 | 否 | 用于在 Pod 中查找主机名的 DNS 搜索域列表 |
config.toml 文件中的配置示例:
concurrent = 1
check_interval = 30
[[runners]]
name = "myRunner"
url = "https://gitlab.example.com"
token = "__REDACTED__"
executor = "kubernetes"
[runners.kubernetes]
image = "alpine:latest"
[runners.kubernetes.dns_config]
nameservers = [
"1.2.3.4",
]
searches = [
"ns1.svc.cluster-domain.example",
"my.dns.search.suffix",
]
[[runners.kubernetes.dns_config.options]]
name = "ndots"
value = "2"
[[runners.kubernetes.dns_config.options]]
name = "edns0"
KubernetesDNSConfigOption:
选项 | 类型 | 必须 | 描述 |
---|---|---|---|
name | 字符串 | 是 | 配置选项名称。 |
value | *string | 否 | 配置选项值。 |
#以下两个在gitlab页面获取
gitlabUrl: http://192.168.31.3:83 # 使用k8s内部gitlab svc地址
runnerRegistrationToken: "GR1348941EfP6qKATzEULxDtvkvAg" #gitlab-runner注册用到的tocken
concurrent: 10 #最大作业并发数
checkInterval: 30 #新作业检查间隔
tags: "k8s" #runner的标签
#rbac权限打开
rbac:
create: true
resources: ["pods", "pods/exec", "secrets","configmaps"]
verbs: ["get", "list", "watch", "create", "patch", "delete","update"]
runners:
# 下述配置
config: |
在kubesphere应用仓库部署结果如下,部署到了ksnode26节点上:
部署后进入终端发现一些目录无操作权限,这是Docker容器的安全限制导致,可设置容器访问控制
/usr/bin/dumb-init,--,/bin/bash,/configmaps/entrypoint
查看/configmaps:
这个命令是使用了/usr/bin/dumb-init作为初始进程,然后运行/bin/bash作为子进程,并将/configmaps/entrypoint作为参数传递给/bin/bash。
/usr/bin/dumb-init是一个轻量级的进程初始化器,它可以帮助正确处理子进程的信号和进程间通信。它在容器环境中经常被使用,以确保进程的正确启动和终止。
/bin/bash是一个常见的Unix和Linux系统中的命令解释器。它提供了一个交互式的命令行界面,可以运行命令和脚本,并提供了丰富的功能和工具集。
/configmaps/entrypoint是一个文件路径,它可能是一个配置映射(ConfigMap)中的入口点脚本。ConfigMap是Kubernetes中用于存储配置数据的一种资源类型。入口点脚本通常用于在容器启动时执行一些初始化操作或配置加载。
综合起来,这个命令的作用是使用dumb-init作为初始进程,启动一个bash子进程,并将/configmaps/entrypoint作为参数传递给bash。这可能是在容器环境中运行的一个脚本或配置文件的启动方式。具体的功能和目的需要查看/configmaps/entrypoint文件的内容来确定。
CI_SERVER_URL:http://192.168.31.3:83/
RUNNER_EXECUTOR:kubernetes
REGISTER_LOCKED:true
RUNNER_TAG_LIST:k8s
配置文件使用临时挂载,挂载路径/home/gitlab-runner/.gitlab-runner/config.toml,默认配置如下
concurrent = 10
check_interval = 30
log_level = "info"
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "gitlab-k8s-runner-gitlab-runner-6fff86bf78-nbjrn"
url = "http://192.168.31.3:83/"
id = 7
token = "HxBNrMvn89soRxaKiR4v"
token_obtained_at = 2024-01-24T09:31:39Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "kubernetes"
[runners.cache]
MaxUploadedArchiveSize = 0
[runners.kubernetes]
host = ""
bearer_token_overwrite_allowed = false
image = "alpine"
namespace = "base"
namespace_overwrite_allowed = ""
node_selector_overwrite_allowed = ""
pod_labels_overwrite_allowed = ""
service_account_overwrite_allowed = ""
pod_annotations_overwrite_allowed = ""
[runners.kubernetes.pod_security_context]
[runners.kubernetes.init_permissions_container_security_context]
[runners.kubernetes.build_container_security_context]
[runners.kubernetes.helper_container_security_context]
[runners.kubernetes.service_container_security_context]
[runners.kubernetes.volumes]
[runners.kubernetes.dns_config]
/entrypoint文件
#!/bin/sh
# gitlab-runner data directory
DATA_DIR="/etc/gitlab-runner"
CONFIG_FILE=${CONFIG_FILE:-$DATA_DIR/config.toml}
# custom certificate authority path
CA_CERTIFICATES_PATH=${CA_CERTIFICATES_PATH:-$DATA_DIR/certs/ca.crt}
LOCAL_CA_PATH="/usr/local/share/ca-certificates/ca.crt"
update_ca() {
echo "Updating CA certificates..."
cp "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}"
update-ca-certificates --fresh >/dev/null
}
if [ -f "${CA_CERTIFICATES_PATH}" ]; then
# update the ca if the custom ca is different than the current
cmp -s "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}" || update_ca
fi
# launch gitlab-runner passing all arguments
exec gitlab-runner "$@"
这个Shell脚本的作用是更新GitLab Runner的CA证书。
首先,它定义了一些变量:
接下来,脚本定义了一个名为 update_ca 的函数。该函数的作用是更新CA证书。它执行以下操作:
然后,脚本使用条件语句检查${CA_CERTIFICATES_PATH}文件是否存在。如果文件存在,则执行以下操作:
最后,脚本使用 exec 命令运行 gitlab-runner 命令,并将脚本的参数(“$@”)传递给 gitlab-runner 命令。这将启动GitLab Runner并执行相应的操作。
总体而言,这个脚本的目的是确保GitLab Runner的CA证书是最新的,并在启动GitLab Runner之前执行必要的更新操作。
#!/bin/bash
set -eou pipefail
if ! /usr/bin/pgrep -f ".*register-the-runner" > /dev/null && ! /usr/bin/pgrep -f "gitlab.*runner" > /dev/null ; then
exit 1
fi
name=$(awk -F'"' '/^ name = ".*"/ { print $2 }' "${HOME%/root}/.gitlab-runner/config.toml")
url=$(awk -F'"' '/^ url = ".*"/ { print $2 }' "${HOME%/root}/.gitlab-runner/config.toml")
gitlab-runner verify -n "$name" -u "$url" 2>&1 | grep -E "is alive|is valid"
[[runners]]
[runners.kubernetes]
namespace = "base"
image = "alpine"
shutdown_timeout = 0
concurrent = 10
check_interval = 30
log_level = "info"
#!/bin/bash
set -e
export CONFIG_PATH_FOR_INIT="/home/gitlab-runner/.gitlab-runner/"
mkdir -p ${CONFIG_PATH_FOR_INIT}
cp /configmaps/config.toml ${CONFIG_PATH_FOR_INIT}
# Set up environment variables for cache
if [[ -f /secrets/accesskey && -f /secrets/secretkey ]]; then
export CACHE_S3_ACCESS_KEY=$(cat /secrets/accesskey)
export CACHE_S3_SECRET_KEY=$(cat /secrets/secretkey)
fi
if [[ -f /secrets/gcs-applicaton-credentials-file ]]; then
export GOOGLE_APPLICATION_CREDENTIALS="/secrets/gcs-applicaton-credentials-file"
elif [[ -f /secrets/gcs-application-credentials-file ]]; then
export GOOGLE_APPLICATION_CREDENTIALS="/secrets/gcs-application-credentials-file"
else
if [[ -f /secrets/gcs-access-id && -f /secrets/gcs-private-key ]]; then
export CACHE_GCS_ACCESS_ID=$(cat /secrets/gcs-access-id)
# echo -e used to make private key multiline (in google json auth key private key is oneline with \n)
export CACHE_GCS_PRIVATE_KEY=$(echo -e $(cat /secrets/gcs-private-key))
fi
fi
if [[ -f /secrets/azure-account-name && -f /secrets/azure-account-key ]]; then
export CACHE_AZURE_ACCOUNT_NAME=$(cat /secrets/azure-account-name)
export CACHE_AZURE_ACCOUNT_KEY=$(cat /secrets/azure-account-key)
fi
if [[ -f /secrets/runner-registration-token ]]; then
export REGISTRATION_TOKEN=$(cat /secrets/runner-registration-token)
fi
if [[ -f /secrets/runner-token ]]; then
export CI_SERVER_TOKEN=$(cat /secrets/runner-token)
fi
# Register the runner
if ! sh /configmaps/register-the-runner; then
exit 1
fi
# Run pre-entrypoint-script
if ! bash /configmaps/pre-entrypoint-script; then
exit 1
fi
# Start the runner
exec /entrypoint run \
--working-directory=/home/gitlab-runner
这个Shell脚本的作用是配置GitLab Runner的运行环境,并执行GitLab Runner的入口点命令。
首先,set -e 表示在脚本中如果有任何命令执行失败(返回非零退出码),则立即退出脚本。
接下来,脚本导出了一个名为 CONFIG_PATH_FOR_INIT 的环境变量,设置为 /home/gitlab-runner/.gitlab-runner/。然后使用 mkdir -p 命令创建了该路径。
然后,脚本使用 cp 命令将 /configmaps/config.toml 文件复制到 ${CONFIG_PATH_FOR_INIT} 目录中。
接下来,脚本使用条件语句检查一些文件是否存在。如果文件存在,则将其内容读取到相应的环境变量中。具体的环境变量如下:
然后,脚本分别执行 /configmaps/register-the-runner 和 /configmaps/pre-entrypoint-script 脚本。如果其中任何一个脚本执行失败(返回非零退出码),则脚本会退出并返回1。
最后,脚本使用 exec 命令执行 /entrypoint run 命令,并传递 --working-directory=/home/gitlab-runner 参数。这将启动GitLab Runner,并设置工作目录为 /home/gitlab-runner。
总体而言,这个脚本的目的是设置GitLab Runner的配置文件和环境变量,然后执行GitLab Runner的入口点命令以启动Runner。
空
#!/bin/bash
MAX_REGISTER_ATTEMPTS=30
# Reset/unset the not needed flags when an authentication token
RUN_UNTAGGED=""
ACCESS_LEVEL=""
for i in $(seq 1 "${MAX_REGISTER_ATTEMPTS}"); do
echo "Registration attempt ${i} of ${MAX_REGISTER_ATTEMPTS}"
/entrypoint register \
${RUN_UNTAGGED} \
${ACCESS_LEVEL} \
--template-config /configmaps/config.template.toml \
--non-interactive
retval=$?
if [ ${retval} = 0 ]; then
break
elif [ ${i} = ${MAX_REGISTER_ATTEMPTS} ]; then
exit 1
fi
sleep 5
done
exit 0
runner-token文件内容空
runner-registration-token文件内容:GR1348941EfP6qKATzEULxDtvkvAg
上述方式部署存在runner pod重启,config.toml配置被重置情况,原因在于下述启动命令中,/configmaps中的脚本。
/usr/bin/dumb-init,--,/bin/bash,/configmaps/entrypoint
/configmaps挂载为了ConfigMap,默认存在如下问题:
需修改ConfigMap下config.template.toml配置:
[[runners]]
builds_dir = "/builds"
[runners.kubernetes]
namespace = "base"
image = "alpine"
pull_policy = "if-not-present"
[[runners.kubernetes.volumes.pvc]]
name = "k8s-running-pod-data"
mount_path = "/builds"
[[runners.kubernetes.volumes.host_path]]
name = "docker"
mount_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
[[runners.kubernetes.host_aliases]]
ip = "192.168.31.11"
hostnames = ["harbor域名"]
runner注册配置可直接修改config.toml 配置文件,无需重启即可生效
concurrent = 10
check_interval = 30
log_level = "info"
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "k8s-gitlab-runner-gitlab-runner-58d796f689-n6phl"
url = "http://192.168.31.3:83"
id = 63
token = "EzF_D7wPTwAjfvxjnvdS"
token_obtained_at = 2024-01-28T09:56:06Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "kubernetes"
builds_dir = "/builds"
[runners.cache]
MaxUploadedArchiveSize = 0
[runners.kubernetes]
host = ""
bearer_token_overwrite_allowed = false
image = "alpine"
namespace = "base"
namespace_overwrite_allowed = ""
pull_policy = ["if-not-present"]
node_selector_overwrite_allowed = ""
pod_labels_overwrite_allowed = ""
service_account_overwrite_allowed = ""
pod_annotations_overwrite_allowed = ""
[runners.kubernetes.pod_security_context]
[runners.kubernetes.init_permissions_container_security_context]
[runners.kubernetes.build_container_security_context]
[runners.kubernetes.helper_container_security_context]
[runners.kubernetes.service_container_security_context]
[runners.kubernetes.volumes]
[[runners.kubernetes.volumes.host_path]]
name = "docker"
mount_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
[[runners.kubernetes.volumes.pvc]]
name = "k8s-running-pod-data"
mount_path = "/builds"
[[runners.kubernetes.host_aliases]]
ip = "192.168.31.11"
hostnames = ["harbor域名"]
[runners.kubernetes.dns_config]
可参考官网GitLab CI/CD examples | 预定义的 CI/CD 变量参考
variables:
MAVEN_OPTS: >-
-Dmaven.repo.local=/builds/maven #maven下载文件路径
-Dorg.slf4j.simpleLogger.showDateTime=true
-Djava.awt.headless=true
MAVEN_CLI_OPTS: >-
--batch-mode
--errors
--fail-at-end
--show-version
--no-transfer-progress
-DinstallAtEnd=true
-DdeployAtEnd=true
package:
stage: package
image: maven:3.6.3-jdk-8
tags:
- k8s
script:
- pwd
- mvn clean package -Dmaven.test.skip=true
# 将打包后target拷贝到指定目录
- rm -rf /builds/project-target/devops-web
- rm -rf /builds/project-target/devops-service
- cp -rf ./devops-web /builds/project-target/devops-web
- cp -rf ./devops-service /builds/project-target/devops-service
提前在宿主机上拉取镜像
将保存maven下载文件路径挂载出来,将下载好的资源上传
将maven打包后的制品拷贝到挂载路径下
执行作业时,会拉取镜像构建maven环境,在k8s集群所有节点上执行发现maven:3.6.3-jdk-8拉取在ksnode20节点上
docker ps | grep maven
参数 | 描述 |
---|---|
-Dmaven.test.skip=true | 跳过测试阶段 |
-Dmaven.compiler.source | 指定源代码的编译版本 |
-Dmaven.compiler.target | 指定生成的字节码的目标版本 |
-Dmaven.repo.local | 指定本地仓库的路径 |
-Dmaven.settings=path | 指定自定义的 Maven 配置文件路径 |
-Dmaven.wagon.http.ssl.insecure=true | 允许使用不安全的 SSL 连接(仅限于特殊情况) |
-Dmaven.wagon.http.ssl.allowall=true | 接受所有 SSL 证书(仅限于特殊情况) |
-Dmaven.test.failure.ignore=true | 忽略测试失败,继续构建过程 |
-Dmaven.test.error.ignore=true | 忽略测试错误,继续构建过程 |
-Dmaven.test.skip.exec=true | 跳过执行测试,但仍然编译测试代码 |
-Dmaven.test.failure.ignore=true | 忽略测试失败,继续构建过程 |
-Dmaven.test.skip.exec=true | 跳过执行测试,但仍然编译测试代码 |
-Dmaven.test.failure.ignore=true | 忽略测试失败,继续构建过程 |
-Dmaven.test.skip.exec=true | 跳过执行测试,但仍然编译测试代码 |
-Dmaven.test.failure.ignore=true | 忽略测试失败,继续构建过程 |
-Dmaven.test.skip.exec=true | 跳过执行测试,但仍然编译测试代码 |
https://blog.51cto.com/zhangxueliang/5478060
build:
stage: build
image:
name: registry.cn-hongkong.aliyuncs.com/cmi/kaniko-project_executor:debug
entrypoint: [""]
tags:
- k8s
script:
- /kaniko/executor
--skip-tls-verify
--insecure
--context "${CI_PROJECT_DIR}"
--dockerfile "/devops-web/Dockerfile"
--destination "harbor.yxym.com/library/devops-web:kaniko"
except:
- tags
docker-build:
# image: docker:latest
image: docker:cli
services:
- docker:dind
stage: build
script:
- docker login -u admin -p Harbor12345 harbor域名
- cd /builds/project-target
- docker build -t devops-web:dind -f ./devops-web/Dockerfile ./devops-web/
- docker tag devops-web:dind harbor域名/library/devops-web:dind
- docker push harbor域名/library/devops-web:dind
登录gitlab查看流水线:
登录harbor查看镜像是否推送到仓库
deploy:
image: google/cloud-sdk
stage: deploy
environment: staging
script:
- kubectl patch deployment $STAGING_SERVICE_NAME -p '{"spec":{"template":{"spec":{"containers":[{"name":"'"$STAGING_SERVICE_NAME"'","image":"'"$CI_REGISTRY_IMAGE:$CI_BUILD_REF"'"}]}}}}'