为什么需要 GitOps?
在传统的 Kubernetes 配置管理实践中,我们常常面临以下痛点:
| 痛点 | 描述 |
|---|---|
| 配置分散 | 配置文件散落在各个开发人员的本地电脑,缺乏统一管理 |
| 变更无记录 | 谁在什么时候改了什么配置,难以追溯 |
| 回滚困难 | 配置出问题后,不知道上一个正确版本是什么 |
| 多环境管理混乱 | 开发、预发布、生产环境的配置差异难以维护 |
| 手动操作风险 | 直接 kubectl edit 修改配置,容易出错且无法审计 |
本文旨在帮助你搭建一套完整的 GitOps 配置管理流程,实现:
- 配置统一管理:所有配置文件存储在 Git 仓库中,Gitea 作为私有代码托管平台
- 变更可追溯:每次配置变更都有 commit 记录,可查看修改内容和提交人
- 自动化同步:代码推送后,Jenkins 自动触发构建,重启对应服务
- 实时通知:部署结果通过钉钉实时通知到团队
- 问题追溯:支持关联 Jira 任务,在问题下自动添加部署评论
整体流程概览
开发人员 → 本地仓库 → Gitea → Jenkins → Kuboard API → K8s集群 → Nginx Pod
│ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼
修改配置 git push Webhook 执行构建 重启Pod 重启完成 配置生效
│
▼
钉钉通知 + Jira评论(可选)
一、环境概览
1.1 环境信息
| IP | 说明 |
|---|---|
| 172.16.109.100 | master |
| 172.16.109.101 | node1 |
| 172.16.109.102 | node2 |
| 组件 | 版本/地址 | 说明 |
|---|---|---|
| K8s 集群 | v1.34.7 | 1 master+2 node |
| 容器运行时 | containerd v2.2.3 | |
| Gitea | 最新版 | 代码仓库,地址: http://172.16.109.102:3000 |
| ArgoCD | v3.4.3 | GitOps 工具 |
| Nginx | latest | 示例应用,ARM64 镜像 |
1.2 注意事项
- 需提前准备好k8s环境
- 我的虚拟机环境是ARM架构的,所以下面的一些安装包可以自行找包切换至X86的
1.3 最终目标
当开发者推送代码到 Gitea 仓库时,ArgoCD 自动将最新的 ConfigMap 同步到 Kubernetes 集群,实现配置的 GitOps 管理。
二、环境准备
2.1 配置 containerd 代理
由于服务器无法直接访问外网,需要为 containerd 配置 SOCKS5 代理(自己搭建的):
# 创建代理配置目录
sudo mkdir -p /etc/systemd/system/containerd.service.d
# 配置代理
sudo tee /etc/systemd/system/containerd.service.d/http-proxy.conf << 'EOF'
[Service]
Environment="HTTP_PROXY=socks5://192.168.50.142:7891"
Environment="HTTPS_PROXY=socks5://192.168.50.142:7891"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc"
EOF
# 重启 containerd
sudo systemctl daemon-reload
sudo systemctl restart containerd
2.2 拉取所需镜像
后续将服务部署到k8s可以不操作这一步
# 拉取 Nginx ARM64 镜像,测试效果用
sudo ctr -n k8s.io image pull docker.io/library/nginx:latest --platform linux/arm64
# 拉取 ArgoCD 镜像
sudo ctr -n k8s.io image pull docker.io/argoproj/argocd:v3.4.3 --platform linux/arm64
2.3 安装 ArgoCD CLI
# 通过代理下载
curl -L -x http://192.168.50.142:7890 \
-o argocd-linux-arm64 \
https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-arm64
# 安装
chmod +x argocd-linux-arm64
sudo mv argocd-linux-arm64 /usr/local/bin/argocd
# 验证
argocd version --client
三、部署 Nginx 应用
3.1 创建 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: default
data:
nginx.conf: |
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
return 200 "healthy\n";
}
location /version {
return 200 "Version: 2.0.0\n";
}
}
}
index.html: |
<!DOCTYPE html>
<html>
<head><title>Nginx GitOps</title></head>
<body><h1>Managed by ArgoCD</h1></body>
</html>
3.2 创建 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
- name: config
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: config
configMap:
name: nginx-config
3.3 创建 Service
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: NodePort
3.4 部署并验证
# 应用所有资源
kubectl apply -f configmap.yaml -f deployment.yaml -f service.yaml
# 获取访问端口
NODE_PORT=$(kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}')
echo "访问端口: $NODE_PORT"
# 测试
curl http://localhost:$NODE_PORT/version
# 输出: Version: 2.0.0
四、部署 ArgoCD
4.1 创建命名空间
kubectl create namespace argocd
4.2 部署 ArgoCD Server
# 使用阿里云镜像加速部署
curl -sSL https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml | \
sed 's/quay.io/registry.cn-hangzhou.aliyuncs.com/g' | \
kubectl apply -n argocd -f -
4.3 暴露 ArgoCD 服务
# 创建 NodePort 服务
cat << EOF | kubectl apply -n argocd -f -
apiVersion: v1
kind: Service
metadata:
name: argocd-server-nodeport
spec:
type: NodePort
ports:
- name: https
port: 443
targetPort: 8080
nodePort: 30443
selector:
app.kubernetes.io/name: argocd-server
EOF
# 创建 HTTP 服务用于 Webhook
cat << EOF | kubectl apply -n argocd -f -
apiVersion: v1
kind: Service
metadata:
name: argocd-server-http
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 8080
nodePort: 30444
selector:
app.kubernetes.io/name: argocd-server
EOF
4.4 获取初始密码
ARGO_PWD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
echo "ArgoCD Admin Password: $ARGO_PWD"
4.5 登录 ArgoCD
# 登录 CLI
argocd login 172.16.109.100:30443 \
--username admin \
--password $ARGO_PWD \
--insecure
# 修改密码(可选)
argocd account update-password \
--current-password $ARGO_PWD \
--new-password your-new-password
4.6 ArgoCD Web UI
访问 https://172.16.109.100:30443 查看:
- 应用拓扑图
- 同步历史
- 资源清单
- 配置对比

五、安装并配置 Git 仓库
5.1 安装Gitea(node2)
| 项目 | 信息 |
|---|---|
| 部署方式 | 二进制部署 |
| 安装路径 | /usr/local/bin/gitea |
| 配置文件 | /etc/gitea/app.ini |
| 数据目录 | /var/lib/gitea |
| 仓库存储 | /var/lib/gitea/data/gitea-repositories |
| 服务管理 | systemd |
| 访问地址 | http://172.16.109.102:3000 |
5.1.1 下载 Gitea 二进制文件
wget https://dl.gitea.com/gitea/1.22.0/gitea-1.22.0-linux-arm64
sudo mv gitea-1.22.0-linux-arm64 /usr/local/bin/gitea
sudo chmod +x /usr/local/bin/gitea
gitea --version
5.1.2 创建 Gitea 用户和数据目录
# 创建 git 用户
sudo adduser --system --group --home /var/lib/gitea git
# 创建必要目录
sudo mkdir -p /etc/gitea /var/lib/gitea/{data,log,git}
sudo chown -R git:git /var/lib/gitea
sudo chmod 750 /var/lib/gitea
5.1.3 创建配置文件
# 编辑配置文件
sudo tee /etc/gitea/app.ini << 'EOF'
APP_NAME = GitOps 配置仓库
RUN_USER = git
RUN_MODE = prod
[server]
DOMAIN = 172.16.109.102
HTTP_PORT = 3000
ROOT_URL = http://172.16.109.102:3000
HTTP_ADDR = 0.0.0.0
[database]
DB_TYPE = sqlite3
PATH = /var/lib/gitea/data/gitea.db
[repository]
ROOT = /var/lib/gitea/data/gitea-repositories
[log]
MODE = file
LEVEL = Info
ROOT_PATH = /var/lib/gitea/log
[security]
INSTALL_LOCK = true
SECRET_KEY = $(openssl rand -base64 32)
INTERNAL_TOKEN = $(openssl rand -base64 32)
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
EOF
# 设置权限
sudo chown git:git /etc/gitea/app.ini
sudo chmod 644 /etc/gitea/app.ini
5.1.4 创建 systemd 服务
sudo tee /etc/systemd/system/gitea.service << 'EOF'
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target
After=syslog.target
After=network-online.target
Wants=network-online.target
[Service]
User=gitea
Group=gitea
Type=simple
WorkingDirectory=/var/lib/gitea
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
RestartSec=10
LimitNOFILE=524288:524288
Environment=USER=gitea HOME=/var/lib/gitea GITEA_WORK_DIR=/var/lib/gitea
[Install]
WantedBy=multi-user.target
EOF
5.1.5 启动 Gitea
# 重载 systemd
sudo systemctl daemon-reload
# 启动 Gitea
sudo systemctl start gitea
# 设置开机自启
sudo systemctl enable gitea
# 查看状态
sudo systemctl status gitea
5.1.6 访问 Gitea 完成安装
- 浏览器访问
http://172.16.109.102:3000 - 首次访问会进入安装页面,但由于已配置
app.ini,会自动完成
注册管理员用户
- 点击 “注册”
- 填写信息:
| 字段 | 建议值 |
|---|---|
| 用户名 | kk |
| 邮箱 | kk@example.com |
| 密码 | 设置强密码 |
第一个注册的用户自动成为管理员
创建测试用的配置仓库
- 登录 Gitea
- 点击右上角 “+” → “新建仓库”
- 填写:
- 仓库名称:
nginx-config - 可见性:
公开
- 仓库名称:
- 点击 “创建仓库”
5.2 创建并推送配置文件
# 克隆 Gitea 仓库
git clone http://172.16.109.102:3000/kk/nginx-config.git
cd nginx-config
# 创建配置目录
mkdir -p k8s-manifests
# 复制 ConfigMap 配置到 Git
cp ../configmap.yaml k8s-manifests/
# 提交并推送
git config user.name "Admin"
git config user.email "admin@example.com"
git add .
git commit -m "Initial commit: nginx configmap"
git push origin main
5.3 添加 Gitea 仓库到 ArgoCD
argocd repo add http://172.16.109.102:3000/kk/nginx-config.git \
--name gitea-repo \
--insecure-skip-server-verification
# 验证
argocd repo list
六、创建 ArgoCD Application
argocd app create nginx-app \
--repo http://172.16.109.102:3000/kk/nginx-config.git \
--revision main \
--path k8s-manifests \
--dest-server https://kubernetes.default.svc \
--dest-namespace default \
--sync-policy automated \
--auto-prune \
--self-heal
# 手动同步(首次)
argocd app sync nginx-app
# 查看状态
argocd app get nginx-app
预期输出显示:
Sync Status: Synced to main (xxx)
Health Status: Healthy
七、配置 Webhook 实现自动同步
7.1 修改 Gitea 配置(临时跳过 TLS 验证)
解决webhook报错:tls: failed to verify certificate: x509: cannot validate certificate for xxx
# 编辑 Gitea 配置文件
vi /etc/gitea/app.ini
# 添加以下内容
[webhook]
SKIP_TLS_VERIFY = true
# 重启 Gitea
systemctl restart gitea
7.2 在 Gitea 添加 Webhook
- 访问
http://172.16.109.102:3000/kk/nginx-config/settings/hooks - 点击 “添加 Webhook” → “Gitea”
- 配置参数:
| 参数 | 值 |
|---|---|
| 目标 URL | http://172.16.109.100:30444/api/webhook |
| HTTP 方法 | POST |
| 内容类型 | application/json |
| 触发条件 | 勾选 “推送代码” |
| 是否启用 | 是 |
- 点击 “添加 Webhook”
7.3 测试 Webhook
# 手动测试
curl -X POST http://172.16.109.100:30444/api/webhook \
-H "Content-Type: application/json" \
-d '{
"ref": "refs/heads/main",
"repository": {
"clone_url": "http://172.16.109.102:3000/kk/nginx-config.git"
}
}'
八、验证 GitOps 全流程
8.1 修改配置并推送
cd /tmp/nginx-config
# 修改版本号
sed -i 's/Version: 2.0.0/Version: 3.0.0/g' k8s-manifests/configmap.yaml
# 提交推送
git add .
git commit -m "Update version to 3.0.0"
git push origin main
8.2 观察自动同步
# 查看 ArgoCD 同步状态
argocd app get nginx-app --watch
# 等待 5-10 秒,同步状态应变为 Synced
8.3 让 Nginx 加载新配置
# Reload Nginx(ConfigMap 更新后需要重载)
kubectl exec deployment/nginx -- nginx -s reload
# 验证版本已更新
NODE_PORT=$(kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}')
curl -s http://localhost:$NODE_PORT/version
# 输出: Version: 3.0.0
8.4 部署Jenkins
8.4.1 创建 Jenkins 部署文件
# 创建 Jenkins 命名空间
kubectl create namespace jenkins
# 创建 Jenkins Deployment 和 Service
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: jenkins/jenkins:lts
ports:
- containerPort: 8080
- containerPort: 50000
env:
- name: JAVA_OPTS
value: "-Djenkins.install.runSetupWizard=false"
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
volumes:
- name: jenkins-home
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: jenkins
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 32000
- port: 50000
targetPort: 50000
nodePort: 32001
selector:
app: jenkins
EOF
8.4.2 拉取 Jenkins 镜像
# 测试通过代理拉取 Jenkins ARM64 镜像
sudo HTTP_PROXY=socks5://192.168.50.142:7891 \
HTTPS_PROXY=socks5://192.168.50.142:7891 \
ctr -n k8s.io image pull docker.io/jenkins/jenkins:lts --platform linux/arm64
8.4.3 获取 Jenkins 初始密码
# 等待 Jenkins 启动
kubectl wait --for=condition=ready pod -l app=jenkins -n jenkins --timeout=300s
# 获取初始密码
kubectl exec -n jenkins deployment/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
8.4.4 配置 Jenkins
- 访问 Jenkins:
http://172.16.109.100:32000 - 输入初始密码登录
- 安装推荐插件(或选择"选择插件来安装",勾选 Pipeline 和 Git 相关插件)
- 创建管理员用户
- 添加Gitea凭据

- 新建 Pipeline 任务:
nginx-config-pipeline - 配置 Pipeline:
- Definition:
Pipeline script from SCM - SCM:
Git - Repository URL:
http://172.16.109.102:3000/kk/nginx-config.git - Credentials: 添加 Gitea 凭据
- 分支:
*/main - Script Path:
Jenkinsfile


- Definition:
- 新建钉钉机器人
8.4.5 创建 Jenkinsfile
cd /tmp/nginx-config
cat > Jenkinsfile << 'EOF'
pipeline {
agent any
environment {
KUBOARD_URL = "http://172.16.109.100:30080/kuboard-api/cluster/myk8s/kind/CICDApi/admin/resource/restartWorkload"
KUBOARD_USERNAME = "admin"
KUBOARD_ACCESS_KEY = "b7zbxmzi8ypi.6ahnzr8c2s8nzkzfw5f7samcsmbx85fn"
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=5a582ca804deed4bc5cea8baa17e2df8e4f77459f22ab6b4f895ad5d802906ee"
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
COMMIT_MSG = sh(script: "git log -1 --pretty=%B", returnStdout: true).trim()
COMMIT_AUTHOR = sh(script: "git log -1 --pretty=%an", returnStdout: true).trim()
DEPLOY_TIME = sh(script: "date '+%Y-%m-%d %H:%M:%S'", returnStdout: true).trim()
echo "重启 Nginx - ${COMMIT_MSG} by ${COMMIT_AUTHOR}"
}
}
}
stage('Restart') {
steps {
script {
sh """
curl -X PUT \
-H "Content-Type: application/json" \
-H "Cookie: KuboardUsername=${KUBOARD_USERNAME}; KuboardAccessKey=${KUBOARD_ACCESS_KEY}" \
-d '{"kind":"deployments","namespace":"default","name":"nginx"}' \
"${KUBOARD_URL}" 2>/dev/null
"""
echo "等待 Pod 重启..."
sh "sleep 15"
}
}
}
stage('Verify') {
steps {
script {
def maxRetries = 10
def health = ""
for (int i = 1; i <= maxRetries; i++) {
health = sh(script: "curl -s -o /dev/null -w '%{http_code}' http://172.16.109.100:31856/health --connect-timeout 3 2>/dev/null || echo '000'", returnStdout: true).trim()
if (health == "200") {
break
}
sh "sleep 5"
}
if (health != "200") {
error("Nginx 重启失败")
}
}
}
}
}
post {
success {
sh """
curl -X POST '${DINGTALK_WEBHOOK}' \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"✅ Nginx 重启成功\\n提交: ${COMMIT_MSG}\\n作者: ${COMMIT_AUTHOR}\\n时间: ${DEPLOY_TIME}"}}' 2>/dev/null || true
"""
}
failure {
sh """
curl -X POST '${DINGTALK_WEBHOOK}' \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"❌ Nginx 重启失败\\n提交: ${COMMIT_MSG}\\n作者: ${COMMIT_AUTHOR}\\n时间: ${DEPLOY_TIME}"}}' 2>/dev/null || true
"""
}
}
}
EOF
git add Jenkinsfile
git commit -m "Add Jenkins pipeline"
git push origin main
8.5 完整流程测试
8.5.1 完整架构图
完整 GitOps 流程
开发人员
│
│ 1. git clone & 修改配置
▼
┌─────────┐ 2. git push ┌─────────┐
│ 本地仓库 │ ─────────────────→ │ Gitea │
└─────────┘ └────┬────┘
│
│ 3. Webhook 触发
▼
┌─────────┐
│ Jenkins │
└────┬────┘
│
│ 4. 调用 API 重启 Pod
▼
┌─────────┐
│ Kuboard │
│ API │
└────┬────┘
│
│ 5. 重启 Deployment
▼
┌─────────┐
│ K8s │
│ Cluster │
└────┬────┘
│
│ 6. Pod 重启完成
▼
┌─────────┐
│ Nginx │
│ Pod │
└────┬────┘
│
│ 7. 发送通知
▼
┌─────────┐
│ 钉钉 │
│ 通知 │
└─────────┘
8.5.2 流程测试
-
修改配置:在 Gitea Web UI 或本地编辑
k8s-manifests/configmap.yaml,可以修改index.html的展示内容

-
提交推送:
git add . && git commit -m "描述" && git push origin main -
自动同步:ArgoCD 检测到变更后自动同步(约 30 秒)到k8s

-
构建服务:Jenkins构建一次

-
构建信息:钉钉收到构建信息
8.5.2 观察各环节状态
| 环节 | 验证方式 | 预期结果 |
|---|---|---|
| Git 推送 | git log --oneline -1 | 显示最新提交 |
| Gitea Webhook | Gitea 仓库 → Webhook → 最近交付 | HTTP 200 |
| Jenkins 构建 | Jenkins 页面 → 构建 | 出现新构建 |
| Kuboard API | 查看 Jenkins 日志 | 返回重启成功 |
| Pod 重启 | kubectl get pods -l app=nginx -w | Pod 重新创建 |
| 配置验证 | curl http://节点IP:31856/version | Version: xxx |
curl http://节点IP:31856/index.html | 看到更改的内容 | |
| 钉钉通知 | 钉钉群 | 收到成功通知 |
九、常见问题及解决方案
9.1 镜像拉取失败
问题:exec format error 或 no such host
解决:
- 确认使用
--platform linux/arm64拉取镜像 - 配置 containerd 代理
- 使用国内镜像源
9.2 ArgoCD 不自动同步
问题:推送后 ArgoCD 没有同步
解决:
- 检查 Webhook 配置是否正确
- 确认 Gitea 配置文件设置了
SKIP_TLS_VERIFY = true - 使用手动同步:
argocd app sync nginx-app --revision main
9.3 Gitea Webhook 报 TLS 错误
问题:x509: certificate signed by unknown authority
解决:
- 配置 Gitea 跳过 TLS 验证
- 或使用 HTTP Webhook(端口 30444)
9.4 ConfigMap 更新后 Nginx 未生效
问题:ConfigMap 已更新,但 Nginx 返回旧版本
解决:
- ConfigMap 更新后 Pod 内文件会自动更新,但 Nginx 需要重载
- 执行:
kubectl exec deployment/nginx -- nginx -s reload
十、相关命令速查
# ArgoCD 应用管理
argocd app list # 列出所有应用
argocd app get nginx-app # 查看应用状态
argocd app sync nginx-app # 手动同步
argocd app history nginx-app # 查看同步历史
argocd app rollback nginx-app # 回滚到上一版本
# Kubernetes 资源操作
kubectl get configmap nginx-config -o yaml # 查看 ConfigMap
kubectl exec deployment/nginx -- nginx -s reload # 重载 Nginx
kubectl rollout restart deployment nginx # 重启 Pod
# Git 操作
git add . && git commit -m "msg" && git push origin main # 推送配置

466

被折叠的 条评论
为什么被折叠?



