Menu Close

gitlab+GitLab Runner 构建CICD发布至K8S 平台

安装gitlab社区版

[root@localhost ~]#yum list |grep gitlab

[root@localhost ~]#yum install -y gitlab-ce

[root@localhost ~]# wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-15.9.8-ce.0.el7.x86_64.rpm

安装GitLab Runner

添加 GitLab 的官方仓库

下载并安装 GitLab Runner repository

curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash

列出所有可用版本

因为我的gitlab版本是15.9.8 ,因此gitlab-runner打版本最好相同,不然有可能产生兼容性问题

yum –showduplicates list gitlab-runner

[root@10 ~]# yum install -y gitlab-runner-15.10.1-1

安装后需要将 Runner 注册到你的 GitLab 项目或实例。

  1. 获取注册 Token

项目级 Runner(推荐用于单个项目):

进入 GitLab 项目 → Settings → CI / CD → Runners

复制 “Project registration token”

群组级或实例级 Runner:

在群组或管理员设置中获取对应 Token

[root@10 ~]# gitlab-runner register

手动注册:

直接使用注册命令:

gitlab-runner register -n \

–url http://10.0.20.190:9999 \

–registration-token vffxdeAc4MEb3ArAokpL \

–executor docker \

–description “gitlab-runner120” \

–docker-image “docker:stable” \

–docker-privileged \

–docker-volumes “/var/run/docker.sock:/var/run/docker.sock” \

–docker-volumes “/cache” \

–docker-shm-size “536870912”

注意注册时:

确保 GitLab Runner 已经正确配置以支持 Docker-in-Docker。特别是,检查 Runner 的 config.toml 文件中的 [runners.docker] 部分是否包含如下设置:

特别注意 privileged = true 和 volumes = [“/var/run/docker.sock:/var/run/docker.sock”] 这两项,它们对于允许 Runner 使用 Docker-in-Docker 是必需的。否则构建时使用 docker会报错

services: docker:dind 启动了 dind 容器,但它需要 privileged = true

当前 Runner 使用的是 alpine:latest 镜像,不包含 docker CLI

Runner 没有挂载 /var/run/docker.sock,也无法通过 dind 正常通信

已经注册成功

查看cat /etc/gitlab-runner/config.toml

启动并设置开机自启

systemctl start gitlab-runner

systemctl enable gitlab-runner

systemctl status gitlab-runner

在gitlab仓库中创建一个项目 gitlab_runner_test

在项目的根目录下创建一个 .gitlab-ci.yml文件用于测试注册成功的Runner自动执行触发任务

这里注意三点:

1;在编辑 .gitlab-ci.yml后使用 GitLab CI Lint 工具 验证 .gitlab-ci.yml 是否正确。

2;由于在注册 runner 时用于构建的执行器选择的是 docker 因此本机需要安装docker 以及docker 仓库中的地址 /etc/docker/daemon.json 需要更改为阿里云的或其它国内地址,以免runner在构建时处于“等待中状态”

.gitlab-ci.yml

workflow:

rules:

– if: $CI_COMMIT_BRANCH # 推送到分支时运行

– when: never # 其他情况(如 MR)不运行

job-hello-runner:

script:

– echo “Hello from GitLab Runner!”

– echo “Runner is WORKING!”

tags:

– gitlab-runner120 # ⚠️ 必须和你注册 Runner 时设置的 tag 一致!

Runner 成功执行作业任务

docker安装gitlab-runner

拉取指定版本的 GitLab Runner 镜像

[root@localhost ~]# docker pull gitlab/gitlab-runner:v15.10.1

运行容器

docker run -d \

–name gitlab-runner \

–restart always \

-v /srv/gitlab-runner/config:/etc/gitlab-runner \

-v /var/run/docker.sock:/var/run/docker.sock \

gitlab/gitlab-runner:v15.10.1

/var/run/docker.sock 是为了让 Runner 能调用宿主机的 Docker 守护进程(用于 docker executor)

/srv/gitlab-runner/config 是配置和证书持久化目录

进入容器并注册 Runner

docker exec -it gitlab-runner gitlab-runner register

直接使用注册命令:

docker exec -it gitlab-runner gitlab-runner register -n \

–url http://10.0.20.190:9999 \

–registration-token vffxdeAc4MEb3ArAokpL \

–executor docker \

–description “gitlab-runner120” \

–docker-image “docker:stable” \

–docker-privileged \

–docker-volumes “/var/run/docker.sock:/var/run/docker.sock” \

–docker-volumes “/cache” \

–docker-shm-size 536870912

Gitlab-runner 已经注册成功

至此两台gitlab-runner已经安装完成

创建一个node.js测试项目,实现自动构建部署至k8s集群

GitLab 项目名称:Node.js

项目目录结构建议如下:

Node.js/

├── src/

│ └── index.js

├── package.json

├── Dockerfile

├── .gitlab-ci.yml

└── k8s/

└── deployment.yaml

二、Node.js 示例代码

src/index.js

const express = require(‘express’);

const app = express();

const PORT = process.env.PORT || 3000;

app.get(‘/’, (req, res) => {

res.send(‘Hello from Node.js App – Version 1.0’);

});

app.listen(PORT, ‘0.0.0.0’, () => {

console.log(Server running on port ${PORT});

});

package.json

{

“name”: “nodejs-app”,

“version”: “1.0.0”,

“main”: “src/index.js”,

“scripts”: {

“start”: “node src/index.js”

},

“dependencies”: {

“express”: “^4.18.0”

}

}

三、Dockerfile

# 使用 Node.js 官方基础镜像

FROM node:18-alpine

# 设置工作目录

WORKDIR /app

# 复制 package.json 并安装依赖

COPY package*.json ./

RUN npm install –production

# 复制源码

COPY . .

# 暴露端口

EXPOSE 3000

# 启动命令

CMD [“npm”, “start”]

四、GitLab CI/CD 变量配置(在 GitLab 项目中设置)

进入 GitLab 项目 → Settings → CI / CD → Variables

添加以下 环境变量(Masked 可选):

gitlab上添加的变量

如何获取 KUBE_TOKEN 和 KUBE_CA_PEM?

在你的本地 Kubernetes 集群上执行:

步骤:创建永久 Token(基于 Secret)

  1. 创建 ServiceAccount

kubectl create serviceaccount git-runner -n default

  1. 手动创建 Secret(绑定到 SA,不设置过期时间)

创建文件 sa-token-secret.yaml:

apiVersion: v1

kind: Secret

metadata:

name: git-runner-token

namespace: default

annotations:

kubernetes.io/service-account.name: git-runner

type: kubernetes.io/service-account-token

注意:不要设置 expirationSeconds 字段,就不会自动过期

应用:

kubectl apply -f sa-token-secret.yaml

这个 Secret 将由 kube-controller-manager 自动填充 Token 内容。

  1. 等待 Token 被填充

kubectl get secret git-runner-token -n default -o jsonpath='{.data.token}’ | base64 –decode

如果输出为空,说明 Token 还未生成,等待几秒再试。

  1. 绑定权限(例如 cluster-admin)

kubectl create clusterrolebinding git-runner-admin \

–clusterrole=cluster-admin \

–serviceaccount=default:my-permanent-user

📦 获取你需要的信息

✅ 获取 Bearer Token

TOKEN=$(kubectl get secret git-runner-token -n default -o jsonpath='{.data.token}’ | base64 –decode)

echo $TOKEN

✅ 获取 Kubernetes CA 证书(Base64 编码)

CA_CERT=$(kubectl config view –raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}’)

echo $CA_CERT

✅ 验证 Token 是否“永久”

使用以下命令查看 Secret 的 Token 是否包含过期时间:

kubectl get secret git-runner-token -n default -o yaml

五、.gitlab-ci.yml

stages:

– build-push # 负责构建和推送 Docker 镜像

– deploy # 负责将应用部署到 Kubernetes 集群

# 执行顺序是从上到下的,即先执行 build-push 阶段的任务,再执行 deploy 阶段

variables: # 全局变量定义,定义了一些可在整个流水线中使用的环境变量

IMAGE_NAME: “${ALIYUN_REGISTRY}/${ALIYUN_NAMESPACE}/${ALIYUN_REPO}” TAG: “${CI_COMMIT_SHORT_SHA}”

build-image: # 构建与推送镜像任务

stage: build-push

image: docker:latest

services:

– docker:dind

before_script: # 在执行主脚本前运行

– ‘echo “Logging in to Alibaba Cloud Container Registry…”‘

– ‘docker login -u “${ALIYUN_USERNAME}” -p “${ALIYUN_PASSWORD}” “${ALIYUN_REGISTRY}”‘ script: # 脚本实际执行的操作 – ‘docker build -t “${IMAGE_NAME}:${TAG}” .’ – ‘echo “Image built: ${IMAGE_NAME}:${TAG}”‘ – ‘docker push “${IMAGE_NAME}:${TAG}”‘ – ‘echo “Image pushed: ${IMAGE_NAME}:${TAG}”‘

# tags: # 用于指定该任务应在哪个 GitLab Runner 上运行。

# – gitlab-runner120

only: # 表示这个任务仅在 main 分支触发时运行

– main

deploy-to-k8s:

stage: deploy # 属于 deploy 阶段,会在 build-push 成功后执行

image: alpine/k8s:1.25.0 # 使用一个轻量级镜像,其中预装了 kubectl 工具

script:

# 创建 kube 目录

– mkdir -p ~/.kube

# 解码 CA 证书

– echo “${KUBE_CA_PEM}” | base64 -d > ~/.kube/ca.crt # 写入 kubeconfig 文件(使用 | 正确处理多行) – | cat > ~/.kube/config <<EOF apiVersion: v1 clusters: – cluster: certificate-authority: /root/.kube/ca.crt # insecure-skip-tls-verify: true 跳过 TLS 验证 server: ${KUBE_SERVER}

name: local-k8s

contexts:

– context:

cluster: local-k8s

user: gitlab-runner

name: default

current-context: default

users:

– name: gitlab-runner

user:

token: “${KUBE_TOKEN}”

EOF

# 替换镜像并部署

– sed -i “s|IMAGE_PLACEHOLDER|${IMAGE_NAME}:${TAG}|g” k8s/deployment.yaml

– kubectl apply -f k8s/deployment.yaml

– kubectl rollout status deployment/nodejs-deployment –timeout=60s

– git checkout k8s/deployment.yaml

# tags:

# – gitlab-runner120

only:

– main

⚠️ 注意:

使用 alpine/k8s:1.25.0 镜像包含 kubectl,轻量且适合 CI。

如果版本不兼容,可换为 bitnami/kubectl。

脚本中 – build-push # 负责构建和推送 Docker 镜像的选项在gitlab-runner没有打上标签的情况下,最好作为一部执行完成,以免分开执行时出现构建在gitlab-runner-1上执行,而推送的步骤是在gitlab-runner-2上执行而找不到构建的镜像无法推送而构建失败报错的状况。

.gitlab-ci.yml这段 CI/CD 配置实现了:

自动化构建 Docker 镜像并推送到阿里云。

自动化部署到 Kubernetes 集群。

使用标准安全实践(Token、CA 认证)连接集群。

每次提交独立版本(基于 Git SHA)。

支持部署后状态检查,提升可靠性。

六、k8s/deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: nodejs-deployment

labels:

app: nodejs

spec:

replicas: 2

selector:

matchLabels:

app: nodejs

template:

metadata:

labels:

app: nodejs

spec:

containers:

– name: nodejs

image: IMAGE_PLACEHOLDER # 将在 CI 中被替换为实际镜像地址

ports:

– containerPort: 3000

resources:

requests:

memory: “128Mi”

cpu: “100m”

limits:

memory: “256Mi”

cpu: “200m”

imagePullSecrets:

– name: aliyun-secret # Kubernetes 从阿里云镜像仓库拉取容器镜像引用的secret

apiVersion: v1

kind: Service

metadata:

name: nodejs-service

spec:

type: NodePort

selector:

app: nodejs

ports:

– protocol: TCP

port: 80

targetPort: 3000

nodePort: 30018

⚠️ 注意:在 Deployment 中通过 imagePullSecrets 引用这个 Secret,里面保存了登录镜像仓库的用户名、密码或令牌

在k8s中创建一个 Secret 用于访问阿里云容器镜像服务(ACR)

运行命令创建 Secret:

Bash

kubectl create secret docker-registry aliyun-secret \

–docker-server=registry.cn-beijing.aliyuncs.com \

–docker-username=your-username \

–docker-password=your-password-or-token \

–docker-email=your-email@example.com \

–namespace=default

注意:docker-registry 类型的 Secret 专门用于镜像拉取认证。

💡 说明:

image: IMAGE_PLACEHOLDER 将在 CI 中被替换为实际镜像地址。

Service 使用 NodePort,暴露端口 30018,可通过 http://<any-node-ip>:30018 访问应用。

七、完整流程总结

八、验证部署

推送至阿里云的镜像

Gitlab上构建成功的状态

k8s上自动部署的nodejs服务

# 查看 Pod

kubectl get pods -l app=nodejs

# 查看服务

kubectl get svc nodejs-service

# 浏览器访问

http://10.0.20.121:30018

# 应显示:Hello from Node.js App – Version 1.0

无觅评论,优化体验,加强品牌价值