k3s + Gitea Action 实现 CI/CD 流程
# k3s + Gitea Action 实现 CI/CD 流程
# 环境介绍
本文在 Win11 下通过 Docker 部署 k3s 集群 + runner ,使用内网 Gitea 作为代码仓库,最终通过 Gitea Actions 实现 CI/CD 流程。
其他环境如 Mac OS, linux 大同小异,可以参考思路。
# k3s 集群部署
# 安装 k3s
k3s 本身支持 Linux、CentOS、Ubuntu 等环境,可以直接通过指南或者脚本意见安装,详见 k3s - 安装要求 (opens new window)。
笔者的运行环境是 Win11,因此需要借助 k3d 进行安装。
注: 在用 k3d 之前,笔者也尝试过 Win11 + Wsl2 + Ubuntu,在实际使用中,遇到了非常令人头痛的网络问题。 后续不得已放弃,兴趣的朋友可以挑战下...
# k3d
k3d 是一个借助 docker 运行 k3s 集群的社区工具。这个方案不仅 Win 可以用,Mac OS 也可以。
因为笔者用的是 Win11,终端这里采用的是 Powershell(pwsh),所以下面的 shell 命令和流程均为 pwsh 相关的。
如果想看其他的操作指南,跳转这里 k3d.io - v5.8.3 (opens new window) (可能非最新版本噢)。
安装 scoop 包管理工具
# 允许脚本执行,按 Y 确认
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# 安装 scoop
irm get.scoop.sh | iex
# 查看版本
scoop --version
2
3
4
5
6
7
8
9
安装 k3d
# 安装 k3d
scoop install k3d
# 查看版本
k3d --version
# 安装 helm (可选)
scoop install helm
# 查看版本
helm version
2
3
4
5
6
7
8
9
10
11
12
创建集群
# 创建集群 mycluster 可以替换成自己的集群名称
k3d cluster create mycluster
# 查看集群状态
k3d cluster list
# 查看集群节点
kubectl get nodes
2
3
4
5
6
7
8
# 安装仪表盘(kubernetes dashboard)
部署 UI
这里借助的 helm,其他方式可以参考官方文档
# 添加 kubernetes-dashboard 仓库
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
# 使用 kubernetes-dashboard Chart 部署名为 `kubernetes-dashboard` 的 Helm Release
helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard
2
3
4
访问 UI
暴露端口后,仍需要创建用户、生成 token 才可用使用,看下面的步骤
端口转发
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-proxy 8443:443
1proxy
kubectl proxy
1
配置 RBAC
注 admin-user 将在仪表盘中拥有管理权限。
dashboard.admin-user.yml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
2
3
4
5
dashboard.admin-user-role.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
2
3
4
5
6
7
8
9
10
11
12
# 创建 admin-user
kubectl create -f dashboard.admin-user.yml -f dashboard.admin-user-role.yml
# 创建 token
kubectl -n kubernetes-dashboard create token admin-user
2
3
4
5
配置 RBAC (合并版本)
dashboard-admin.yml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建 ServiceAccount 和 ClusterRoleBinding
kubectl apply -f dashboard-admin.yml
# 创建 token
kubectl -n kubernetes-dashboard create token admin-user
2
3
4
5
# 遇到的问题
查看 pod 日志网络出错
复现方式:
- 通过仪表盘 pod -> 查看日志。 提示: xxxx net/http: TLS handshake timeout
- 通过
kubectl logs <pod-name>
超时
解决方法: 问题是 wsl + ubuntu 部署 k3s 时出现的。后续换用了 k3d,问题解决。
# 参考链接
- k3s.io (opens new window)
- k3s - rancher (opens new window)
- k3d - github (opens new window)
- scoop (opens new window)
- Kubernetes 仪表盘 - rancher (opens new window)
- 部署和访问 Kubernetes 仪表板(Dashboard) - k8s (opens new window)
- kubernetes/dashboard - Github (opens new window)
# Gitea Runner 部署
# 安装 runner
参考 k8s did 部署模式进行部署。 Kubernetes Docker in Docker Deployment with act_runner (opens new window)
通过 kubectl 部署
- 获取 Runner Registration Token
Gitea 右上角头像 -> 设置 -> 侧边栏 Actions -> Runners -> 创建 Runner -> 复制 Registration Token
更多内容看指南: 获取注册令牌 - Gitea Docs (opens new window)
- 将 token 创建为 secret
kubectl 命令方式:
kubectl create secret generic runner-secret \
--from-literal=token=<< registration token >>
2
yaml 部署方式:
runner-secret.yaml
---
apiVersion: v1
data:
token: << base64 encoded registration token >>
kind: Secret
metadata:
name: runner-secret
type: Opaque
2
3
4
5
6
7
8
kubectl apply -f runner-secret.yaml
注:kubectl 传入的 token 是原始值,yaml 需要写入 base64 编码后的值
- 部署 runner
dind-docker.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: act-runner-vol
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: local-path # template 里是 standard 咱们用的 k3s 因此需要换成 local-path
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: act-runner
name: act-runner
spec:
replicas: 1
selector:
matchLabels:
app: act-runner
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: act-runner
spec:
# hostNetwork: true # 视情况选择
restartPolicy: Always
volumes:
- name: docker-certs
emptyDir: {}
- name: runner-data
persistentVolumeClaim:
claimName: act-runner-vol
# - name: runner-config # 如果需要给 Runner 指定 config 可以使用,详见下方的 configMap
# configMap:
# name: gitea-runner-config
containers:
- name: runner
image: gitea/act_runner:nightly
command:
[
"sh",
"-c",
"while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- run.sh",
]
env:
- name: DOCKER_HOST
value: tcp://localhost:2376
- name: DOCKER_CERT_PATH
value: /certs/client
- name: DOCKER_TLS_VERIFY
value: "1"
- name: GITEA_INSTANCE_URL
value: http://gitea-http.gitea.svc.cluster.local:3000 # 需要替换成自己的Gitea 地址,如果部署在集群里,不需要额外变更
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: runner-secret
key: token
# - name: CONFIG_FILE # runner config
# value: /config/config.yaml
volumeMounts:
- name: docker-certs
mountPath: /certs
- name: runner-data
mountPath: /data
- name: runner-config
mountPath: /config/config.yaml
subPath: config.yaml
- name: daemon
image: docker:23.0.6-dind
env:
- name: DOCKER_TLS_CERTDIR
value: /certs
securityContext:
privileged: true
volumeMounts:
- name: docker-certs
mountPath: /certs
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
kubectl apply -f dind-docker.yaml
- (可选) Runner Config
gitea-runner-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-runner-config
data:
config.yaml: |
log:
level: info
runner:
file: .runner
capacity: 1
envs:
A_TEST_ENV_NAME_1: a_test_env_value_1
A_TEST_ENV_NAME_2: a_test_env_value_2
env_file: .env
timeout: 3h
shutdown_timeout: 0s
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
github_mirror: ''
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
- "ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04"
cache:
enabled: true
dir: ""
host: ""
port: 0
external_server: ""
container:
network: "host" # 指定网络
privileged: true # 特权模式
options: -v /var/run/docker.sock:/var/run/docker.sock # 挂载 docker 守护进程
workdir_parent:
valid_volumes:
- /var/run/docker.sock # 白名单
docker_host: ""
force_pull: true
force_rebuild: false
require_docker: true
docker_timeout: 300s
host:
workdir_parent:
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
kubectl apply -f gitea-runner-config.yaml
通过 helm chart 安装
参考 helm-actions (opens new window)
# 遇到的问题
Registration token 作为 secret 传入时,需要 base64 编码
did 挂载的
act-runner-vol
持久卷在 k8s 和 k3s 中表现不一致- k8s 中挂载类型是
storageClassName: standard
- k3s 中挂载类型是
storageClassName: local-path
- k8s 中挂载类型是
# 参考链接
# CI/CD 流程
# 设置密钥
根据需求设置全局密钥,还是仓库级别密钥
# CI 流程
.gitea\workflows\build-and-push.yaml
name: Build and Push Docker Image
on:
push:
branches:
- master # 指定分支
workflow_dispatch:
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
# 切出分支拉取最新代码
- name: Checkout code
uses: actions/checkout@v4
# 安装docker buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker
# 设置docker镜像仓库
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# 构建镜像
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/demo:latest
# 显示推送的镜像详情
- name: Show pushed image details
run: |
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/demo:latest"
echo "🎉 Image pushed: $IMAGE"
echo "🔗 Docker Hub: https://hub.docker.com/r/${{ secrets.DOCKERHUB_USERNAME }}/demo"
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
# CD 流程
.gitea\workflows\deploy.yaml
name: Deploy to K3s
on:
push:
branches:
- master
workflow_dispatch: # 手动触发也行
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup kubectl
uses: azure/setup-kubectl@v4
with:
version: "latest" # 或指定具体版本,比如 "v1.29.0"
- name: Configure Kubeconfig
# 假设您的 KUBE_CONFIG 秘密是 Base64 编码的 kubeconfig 文件内容
run: |
# 1. 创建 ~/.kube 目录
mkdir -p $HOME/.kube
# 2. 将 Base64 编码的 KUBE_CONFIG 秘密解码并写入默认配置文件
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
# 3. 确保 kubectl 知道配置文件的位置 (可选, 但安全)
echo "KUBECONFIG=$HOME/.kube/config" >> $GITHUB_ENV
- name: Deploy with kubectl
run: |
kubectl apply -f xxxx.yaml
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
# 遇到的问题
actions/checkout@v4
拉去私有仓库代码卡住 网络问题,通过设置dind-docker.yaml
里 runnerhostNetwork: true
解决。 原理是:让 runner 直接使用宿主机的网络,避免使用容器的网络。(笔者的 Gitea 部署在内网)did 容器里使用 kubectl 地址不对的问题 需要指定 k3s 集群配置进去。