ArgoCD+Jenkins实现GitOps
ArgoCD+Jenkins实现GitOps
一、安装ArgoCD+Jenkins
-
大哥博客:
-
实现的思路是这样的:
- Jenkins实现CI,拉代码打包成镜像,然后更新代码仓库helm目录的values.yaml文件(这通过envsubst+ values.tpl实现)
- ArgoCD实现CD,创建APP,通过helm方式部署,监听仓库helm目录
二、Jenkins实现CI
- 试验环境:
- 阿里云镜像仓库
- jihu的jitlab
- k8s 1.28.0
- Jenkins
2.1、实验做的demo展示
这是一个go编写的简单代码演示,然后写了一个chart包去部署这个go代码,在helm目录(这个目录在argocd中会使用到)
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
import "fmt"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H {
"msg": "Welcome to the Jenkins CI Demo!",
})
})
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H {
"health": true,
})
})
if err := r.Run(":8080"); err != nil {
logrus.WithError(err).Fatal("Couldn't listen")
}
}
然后这个项目main.go 同级目录有个Jenkinsfile文件,这就是我们可以在Jenkins通过SCM配置git地址,然后指定路径读取到Jenkinsfile,yamlFile "ci/jnlp.yaml" // 指定YAML配置文件路径,这个是ci目录下
- Jenkinsfile
- stage('change ImageTag') 这个步骤,主要是通过envbust 把变量转换成yaml,首先values.yaml 跟values.tpl文件内容是一样的,就是values.tpl是变量,values.yaml是固定值,values.tpl 接收变量,渲染到values.yaml ,然后通过helm 部署的时候还是读取values.yaml的值
// 初始化变量,用于存储提交ID和时间戳
def COMMITID = ""
def TIMESTAMP = ""
pipeline {
agent {
// 使用Kubernetes代理,生成唯一的标签
kubernetes {
label "jnlp-slave-${UUID.randomUUID().toString().substring(0, 8)}"
yamlFile "ci/jnlp.yaml" // 指定YAML配置文件路径,这个是ci目录下
}
}
environment {
// 定义环境变量
DOCKER_REGISTRY = "registry.cn-hangzhou.aliyuncs.com" // Docker注册表地址
REGISTRY_NAMEPSACE = "zhenhuan" // 注册表命名空间
IMAGE = "${DOCKER_REGISTRY}/${REGISTRY_NAMEPSACE}" // 完整的镜像地址
OPS_REPO = "jihulab.com/devopsx/ci-demo.git" // GitOps仓库地址
}
options {
// 构建丢弃策略,保持构建15天,最多保留30个构建
buildDiscarder logRotator(artifactDaysToKeepStr: '15', artifactNumToKeepStr: '', daysToKeepStr: '15', numToKeepStr: '30')
// 启用时间戳
timestamps()
// 设置超时时间为100分钟
timeout(time: 100, unit: 'MINUTES')
}
stages {
stage('commit') {
steps {
script {
// 获取当前Git提交的短ID
COMMITID = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
// 获取当前时间戳
TIMESTAMP = sh(script: "date +%Y%m%d%H%M-%S", returnStdout: true).trim()
// 设置镜像标签,格式为:BUILD_ID-时间戳-提交ID
env.ImageTag = "${BUILD_ID}-${TIMESTAMP}-${COMMITID}"
// 从JOB_NAME中提取应用名称并转换为小写
env.AppName = env.JOB_NAME.split('/').last().toLowerCase()
}
}
}
stage('build image') {
steps {
container('docker') { // 在Docker容器中执行步骤
withCredentials([[$class: 'UsernamePasswordMultiBinding',
credentialsId: 'docker-auth', // 使用Docker认证凭证
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASSWORD']]) {
script {
sh """
echo "开启多架构编译"
// 创建并使用Docker Buildx构建器
docker buildx create --name mybuilder --use --driver docker-container --driver-opt image=registry.cn-hangzhou.aliyuncs.com/zhenhuan/buildkit:buildx-stable-1
echo "登陆仓库"
// 登录到Docker注册表
docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
echo "构建/推送镜像"
// 使用Buildx构建镜像并推送到注册表,支持多架构
docker buildx build --progress=plain --no-cache --platform=linux/amd64,linux/arm64 -f Dockerfile -t ${IMAGE}/${AppName}:${ImageTag} . --push
"""
}
}
}
}
}
stage('change ImageTag') {
steps {
container('tools') { // 在工具容器中执行步骤
script {
sh """
// 使用envsubst替换模板中的环境变量,生成Helm值文件
envsubst < ./values.tpl > helm/values.yaml
cat helm/values.yaml // 输出生成的Helm值文件
// 使用Helm模板渲染
helm template --debug helm/ -f helm/values.yaml
"""
}
}
}
}
stage('push yaml') {
steps {
withCredentials([[$class: 'UsernamePasswordMultiBinding',
credentialsId: 'github-ci', // 使用GitHub CI凭证
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASSWORD']]) {
script {
sh """
// 配置Git用户信息
git config --global user.email "ci"
git config --global user.name "ci@ci.com"
// 切换到主分支
git checkout main
// 添加所有更改
git add .
// 提交更改,提交信息包含应用名称和镜像标签
git commit -m "${AppName}-${ImageTag} " || true
// 推送更改到GitOps仓库
git push https://${GIT_USER}:${GIT_PASSWORD}@${OPS_REPO}
"""
}
}
}
}
}
}
- ci/jnlp.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: jenkins-slave
spec:
volumes:
- name: docker-socket
emptyDir: {}
- name: workspace-volume
emptyDir: {}
serviceAccount: jenkins
#nodeName: k8s-node05
containers:
- name: jnlp
image: registry.cn-hangzhou.aliyuncs.com/zhenhuan/inbound-agent:latest
- name: tools
image: registry.cn-hangzhou.aliyuncs.com/s-ops/tools:latest
command:
- cat
tty: true
- name: docker
image: registry.cn-hangzhou.aliyuncs.com/zhenhuan/docker:latest
env:
- name: DOCKER_CLI_EXPERIMENTAL
value: "enabled"
command:
- sleep
args:
- 99d
readinessProbe:
exec:
command: ["ls", "-S", "/var/run/docker.sock"]
initialDelaySeconds: 10
volumeMounts:
- name: docker-socket
mountPath: /var/run
- name: docker-daemon
image: registry.cn-hangzhou.aliyuncs.com/zhenhuan/docker:19.03.1-dind
securityContext:
privileged: true
volumeMounts:
- name: docker-socket
mountPath: /var/run
- name: workspace-volume
mountPath: /home/jenkins/agent
readOnly: false
- ci/tools 镜像的dockerfile
# 基于 Alpine 最新版本构建tools容器镜像
FROM docker.cloudimages.asia/alpine:latest
# 安装kubectl helm yq envsubst
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.ustc.edu.cn|g' /etc/apk/repositories && \
apk update && apk upgrade && \
apk add --no-cache \
ca-certificates \
tzdata \
helm \
kubectl \
yq \
bash \
vim \
gettext && \
update-ca-certificates && \
rm -rf /var/cache/apk/*
ENV TZ=Asia/Shanghai
- 部署这个go程序的dockerfile
# 指定基础的go编译镜像
FROM registry.cn-hangzhou.aliyuncs.com/zhenhuan/golang:alpine3.17 as build
# 指定go的环境变量
RUN go env -w GOPROXY=https://goproxy.cn,direct # https://mirrors.aliyun.com/goproxy/
# 指定工作空间目录,会自动cd到这个目录
WORKDIR /opt
# 把项目的其他所有文件拷贝到容器中
COPY . .
# 编译成可执行二进制文件
RUN go env -w GO111MODULE=on
RUN go mod tidy
RUN go build -o app main.go
FROM registry.cn-hangzhou.aliyuncs.com/zhenhuan/alpine:latest as serviceDeploy
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && apk update && apk upgrade && apk add ca-certificates && update-ca-certificates && apk add --update tzdata && rm -rf /var/cache/apk/*
ENV TZ=Asia/Shanghai
COPY --from=build /opt/app /
CMD ["/app"]

三、Argocd 实现CD
参考:https://cloud.tencent.com/developer/article/2398649
ArgoCD的APP配置文件
apiVersion: argoproj.io/v1alpha1 # 指定API版本,表明这是Argo CD应用程序的定义
kind: Application # 定义的资源类型为“Application”
metadata: # 资源的元数据
name: cd-demo # 应用程序的名称为 cd-demo
namespace: argocd # 资源所在的命名空间为 argocd
spec: # 资源的具体规格
project: default # 指定该应用程序属于 'default' 项目
source: # 应用程序的源代码定义
path: helm # 指定应用程序的路径,这里使用 Helm Charts
repoURL: https://jihulab.com/devopsx/ci-demo.git # 指向包含应用代码和 Helm Charts 的 Git 仓库的 URL
targetRevision: main # 指定要使用的代码分支,通常为主分支 main
destination: # 目标 Kubernetes 集群和命名空间配置
server: 'https://kubernetes.default.svc' # 指向默认的 Kubernetes API 服务器
namespace: kube-ops # 应用程序部署到的 Kubernetes 命名空间为 kube-ops
syncPolicy: # 同步策略设置
automated: # 启用自动同步
prune: true # 在同步过程中自动删除不再需要的资源
selfHeal: true # 启用自我恢复功能,若检测到偏差会自动纠正
查看部署结果:

# 查看pod 日志(稍微改动了下go代码,无碍)
[root@k8s-master01 devops]# kubectl logs -f -n kube-ops ci-demo-5768d9c6c6-bmtn7
你好吗? 我的朋友!
后续代码有变更,修改代码后,在Jenkins构建镜像,后面Argocd就会帮我们去部署
四、部署Helm到 Argo CD的方式
参考:https://cloud.tencent.com/developer/article/2398649
部署 Helm 仓库中 Charts
要使用 Argo CD 部署 Helm Charts,可以创建一个 Application 资源,并指定 Helm Chart 的路径、存储库 URL 和目标修订版本。例如,要部署一个名为 nginx 的 Helm Chart,可以创建以下 Application 资源:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mysql
namespace: argocd
spec:
project: default
source:
chart: mysql
repoURL: https://charts.onwalk.net
targetRevision: 9.21.2
helm:
releaseName: mysql
destination:
server: "https://kubernetes.default.svc"
namespace: itsm-dev-db
syncPolicy:
automated:
prune: true
selfHeal: true
部署 Git仓库中的 Charts-Helmfile
要部署 Helmfiles,可以在 Application 资源中指定 Helmfile 的路径、存储库 URL 和目标修订版本。例如,要部署一个名为 my-helmfiles 的 Helmfile,可以创建以下 Application 资源:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: itsm
namespace: argocd
spec:
project: default
source:
path: helmfiles/itsm
repoURL: https://github.com/svc-design/gitops.git
targetRevision: main
destination:
server: 'https://kubernetes.default.svc'
namespace: itsm-dev
syncPolicy:
automated:
prune: true
selfHeal: true
部署 Git仓库中的 Charts
要部署来自 Git 仓库的 Helm Charts,可以在 Application 资源中指定 Helm Chart 的路径、存储库 URL 和目标修订版本。例如,要部署一个名为 my-chart 的 Helm Chart,可以创建以下 Application 资源:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: redis
namespace: argocd
spec:
project: default
source:
path: helm/redis
repoURL: https://github.com/svc-design/gitops.git
targetRevision: main
destination:
server: 'https://kubernetes.default.svc'
namespace: itsm-dev
syncPolicy:
automated:
prune: true
selfHeal: true

浙公网安备 33010602011771号