实现GitOps流程:JenkinsCI+ArgoCD
Argo CD 是一个为 Kubernetes 而生的,遵循声明式 GitOps 理念的持续部署工具。Argo CD 可在 Git 存储库更改时自动同步和部署应用程序
Argo CD 遵循 GitOps 模式,使用 Git 仓库作为定义所需应用程序状态的真实来源,Argo CD 支持多种 Kubernetes 清单
Argo CD 可在指定的目标环境中自动部署所需的应用程序状态,应用程序部署可以在 Git 提交时跟踪对分支、标签的更新,或固定到清单的指定版本
- 大佬博客:
| Argo CD Version | Kubernetes versions |
|---|---|
| 2.13 | v1.30,v1.29,v1.28,v1.27 |
| 2.12 | v1.29,v1.28,v1.27,v1.26 |
| 2.11 | v1.29,v1.28,v1.27,v1.26,v1.25 |
试验环境:
- 阿里云镜像仓库:registry.cn-guangzhou.aliyuncs.com/cumybride
- gitlab:http://192.168.7.71:8028/root/cumy.git
- k8s 1.28.0
- Jenkins:http://192.168.0.66:30989
一、安装Jenkins+ArgoCD
Argo CD (opens new window)是针对 Kubernetes 的声明式 GitOps 持续交付工具
Jenkisn部分
[root@k8s-master01 argocd]# vim Jenkins.yaml
apiVersion: v1
kind: Namespace
metadata:
name: argocd
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-local
labels:
app: jenkins
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 5Gi
storageClassName: local-storage
local:
path: /data/k8s/jenkins
persistentVolumeReclaimPolicy: Retain
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node02 # 这里随便找一台跑就可以
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: argocd
spec:
storageClassName: local-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: argocd
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments", "ingresses"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["services"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
- apiGroups: [""]
resources: ["pods/log", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins
namespace: argocd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: argocd
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: argocd
spec:
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
serviceAccount: jenkins
initContainers:
- name: fix-permissions
image: registry.cn-guangzhou.aliyuncs.com/cumybride/busybox:1.35.0
command: ["sh", "-c", "chown -R 1000:1000 /var/jenkins_home"]
securityContext:
privileged: true
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
containers:
- name: jenkins
image: registry.cn-guangzhou.aliyuncs.com/cumybride/jenkins:lts-jdk11
imagePullPolicy: IfNotPresent
env:
- name: JAVA_OPTS
value: -Dhudson.model.DownloadService.noSignatureCheck=true -Duser.timezone=Asia/Shanghai
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: jenkins-pvc
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins
namespace: argocd
spec:
ingressClassName: nginx
rules:
- host: jenkins.tbchip.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
name: web
[root@k8s-master01 argocd]# vim jenkins-nodeport.yaml
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: argocd
labels:
app: jenkins
spec:
selector:
app: jenkins
ports:
- name: web
port: 8080
protocol: TCP
nodePort: 30989
- name: agent
port: 50000
targetPort: agent
type: NodePort
[root@k8s-master01 argocd]# kubectl apply -f jenkins.yaml
[root@k8s-master01 argocd]# kubectl apply -f jenkins-nodeport.yaml
获取密码
[root@k8s-master01 argocd]# kubectl logs -f jenkins-cd9fb8959-ccp95 -n argocd
3ddfc6fd163e48ebaac58bf8911fa9e2
输入管理员密码 —— 先勾选“无”(目的是取消所有勾选) —— 再勾选 “Languages” —— 安装
创建管理员用户—— admin/Zlsd@2025
修改时区——“admin” —— “设置” —— "时区:Shanghai"
安装插件
① 访问地址: 192.168.0.66:30989/manage/pluginManager/available
② 安装插件:
Git
Lock
Pipeline
timestamp
ThinBackup
Kubernetes
Pipeline View
Active Choices
Build Name and Description Setter
配置动态 slave 节点
① 访问地址: http://192.168.0.66:30989/manage/cloud/new
② Cloud name: Kubernetes || Type: Kubernetes —— create 创建动态节点
配置连接 Kubernetes API Server 的地址:
名称: Kubernetes
Kubernetes地址:https://kubernetes.default.svc.cluster.local
Kubernetes命名空间:argocd
”连接测试“(在页面右边): Connected to Kubernetes v1.28.0 —— 出现k8s版本即连接正常
配置Jenkins地址
Jenkins 地址 :http://jenkins.argocd.svc.cluster.local:8080 (这里看情况用https或http)
Jenkins 通道 :jenkins.argocd.svc.cluster.local:50000
Add Pod Labels —— 键:jenkins 值:jenkins
最后Save即可
配置凭据
① 访问地址:http://192.168.0.66:30989/credentials/store/system/domain/_/
② 添加凭据:
-
ID:registry-auth
用户名:zwbnhic
密码:xxxxxx
描述:阿里云ACR容器镜像仓库认证信息
-
ID:gitlab-auth
用户名:root
密码:xxxxxx
描述:gitlab代码仓库认证信息
-
ID:argo-auth
用户名:admin
密码:xxxxxx
描述:argocd认证信息
ArgoCD部分
wget -O argocd.yaml https://raw.githubusercontent.com/argoproj/argo-cd/v2.8.4/manifests/install.yaml
sed -i 's|quay.io/argoproj/argocd:v2.8.4|registry.cn-guangzhou.aliyuncs.com/cumybride/argocd:v2.8.4|g' argocd.yaml
sed -i 's|ghcr.io/dexidp/dex:v2.37.0|registry.cn-guangzhou.aliyuncs.com/cumybride/dex:v2.37.0|g' argocd.yaml
sed -i 's|redis:7.0.11-alpine|registry.cn-guangzhou.aliyuncs.com/cumybride/redis:7.0.11-alpine|g' argocd.yaml
sed -i 's/imagePullPolicy: Always/imagePullPolicy: IfNotPresent/g' argocd.yaml
允许不安全(禁用TLS)
[root@k8s-master01 argocd]# vim argocd.yaml
... ...
19839 containers:
19840 - args:
19841 - /usr/local/bin/argocd-server
19842 - --insecure # 添加到 argocd-server命令
部署NodePort用于访问
[root@k8s-master01 argocd]# vim argocd-nodeport.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: server
app.kubernetes.io/name: argocd-server
app.kubernetes.io/part-of: argocd
name: argocd-server-nodeport
namespace: argocd
spec:
ports:
- name: http
port: 80
protocol: TCP
nodePort: 30980
- name: serviceport # 主要通过这个端口来进行访问
port: 8080
protocol: TCP
nodePort: 30988
- name: https
port: 443
protocol: TCP
nodePort: 30943
selector:
app.kubernetes.io/name: argocd-server
type: NodePort
本地安装CLI工具
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.8.4/argocd-linux-amd64
chmod + /usr/local/bin/argocd
部署
[root@k8s-master01 argocd]# kubectl create ns argocd
[root@k8s-master01 argocd]# kubectl apply -f argocd.yaml -n argocd && kubectl apply -f argocd-nodeport.yaml
访问验证:192.168.0.66:30988
获取密码
[root@k8s-master01 argocd]# kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
Fe-LAta6EA2BWwcQ # admin账号的密码
Argocd配置认证
Argocd —— “Settings” —— “Repositories” —— “CONNECT REPO” —— 选择连接方法:[ VIA HTTPS ]
Type:git
Project:cumy
Repository URL:http://192.168.7.71:8028/root/cumy.git
Username (optional):root
Password (optional):xxxxxx
(这里密码不要使用特殊字符)
命令行登录
argocd login 192.168.0.66:30988
admin
******
实现的思路是这样的:
- Jenkins利用ci/jnlp.yaml拉起Pod来完成Gitops全流程所需运行环境
- Jenkins实现CI,拉代码打包成镜像,然后更新代码仓库helm目录的values.yaml文件(这通过envsubst+ values.tpl实现)
- ArgoCD实现CD,创建APP,通过helm方式部署,监听仓库helm目录
二、Jenkins实现CI
2.1、实验做的demo展示(以下文件均存放/上传于gitlab代码仓库中: http://192.168.7.71:8028/root/cumy.git )
这是一个go编写的简单代码演示,然后写了一个chart包去部署这个go代码,在helm目录(这个目录在argocd中会使用到)
- main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H {
"msg": "Welcome to the Argocd GitOps.Here is new World",
})
})
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")
}
}
- go.mod
module app
go 1.20
require (
github.com/gin-gonic/gin v1.10.1
github.com/sirupsen/logrus v1.9.3
)
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
然后这个项目main.go 同级目录有个Jenkinsfile文件,这就是我们可以在Jenkins通过SCM配置git地址,然后指定路径读取Jenkinsfile,下面都是后续可以用于每个分支的固定文件
- Jenkinsfile
// 初始化变量,用于存储提交ID和时间戳
def COMMITID = ""
def TIMESTAMP = ""
pipeline {
agent {
// 使用Kubernetes代理,生成唯一的标签
kubernetes {
label "jnlp-slave-${UUID.randomUUID().toString().substring(0, 8)}"
yamlFile "ci/jnlp.yaml" // 指定YAML配置文件路径
}
}
environment {
// 定义环境变量
DOCKER_REGISTRY = "registry.cn-guangzhou.aliyuncs.com" // Docker注册表地址
REGISTRY_NAMESPACE = "cumybride" // 注册表命名空间
IMAGE = "${DOCKER_REGISTRY}/${REGISTRY_NAMESPACE}" // 完整的镜像地址
}
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仓库URL
OPS_REPO = scm.getUserRemoteConfigs()[0].getUrl().replaceAll(/^https?:\/\//, "")
// 获取当前分支信息
env.BRANCH = env.GIT_BRANCH?.replace('origin/', '')?.trim()
// 获取当前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: 'registry-auth', // 使用jenkins凭据 registry-auth,用于拉/推镜像
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASSWORD']]) {
script {
sh """
echo "开启多架构编译,创建并使用Docker Buildx构建器,使用host主机网络"
docker buildx create --name mybuilder --use --driver docker-container --driver-opt network=host --driver-opt image=registry.cn-guangzhou.aliyuncs.com/cumybride/buildkit:buildx-stable-1
echo "登陆镜像仓库"
docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
echo "构建/推送镜像,使用Buildx构建镜像并推送到注册表,支持多架构 "
docker buildx build --progress=plain --platform=linux/amd64 -f Dockerfile -t ${IMAGE}/${AppName}:${ImageTag} . --push
"""
}
}
}
}
}
stage('render ImageTag') {
// values.tpl 接收变量,通过envbust把变量tpl转换成值yaml,渲染到values.yaml,再通过helm读取values.yaml的值部署
steps {
container('tools') { // 在工具容器中执行步骤
script {
sh """
echo "使用envsubst将values.tpl模板文件渲染helm可用的文件values.yaml;示例:echo 'Hello, $USER!' | envsubst -→ Hello,root!"
echo "注意,envsubst是纯shell命令,只替换shell环境变量,无法从Jenkins Pipeline Groovy的env自动继承变量,因此这里用export声明给shell"
export APP_NAME=${env.AppName}
export IMAGE_TAG=${env.ImageTag}
export REGISTRY_NAMESPACE=${env.REGISTRY_NAMESPACE}
export COMMITID=${env.COMMITID}
export DOCKER_REGISTRY=${env.DOCKER_REGISTRY}
export REGISTRY_NAMESPACE=${env.REGISTRY_NAMESPACE}
envsubst < ./values.tpl > helm/values.yaml
cat helm/values.yaml
echo "使用Helm模板渲染"
helm template --debug helm/ -f helm/values.yaml
"""
}
}
}
}
stage('push yaml') {
steps {
withCredentials([[$class: 'UsernamePasswordMultiBinding',
credentialsId: 'gitlab-auth', // 使用gitlab-auth凭证
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASSWORD']]) {
script {
sh """
echo "切换到对应分支"
git checkout ${BRANCH}
echo "配置Git用户信息"
git config --global user.email "ci"
git config --global user.name "ci@ci.com"
echo "添加所有更改"
git add .
echo "提交更改,提交信息包含应用名称和镜像标签"
git commit -m "${AppName}-${ImageTag} " || true
echo "推送更改到GitOps仓库,按照实际情况配置https/http"
git push http://${GIT_USER}:${GIT_PASSWORD}@${OPS_REPO}
"""
}
}
}
}
stage('argocd-sync') {
steps {
//含有argocd工具的tools容器
container('tools-argocd'){
withCredentials([
usernamePassword(
credentialsId: 'argo-auth',
usernameVariable: 'ARGO_USER',
passwordVariable: 'ARGO_PASSWORD'
),
usernamePassword(
credentialsId: 'gitlab-auth',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASSWORD'
)
]) {
script {
def loginArgoCmd = "echo y | argocd login --insecure 192.168.0.66:30988 --username ${ARGO_USER} --password ${ARGO_PASSWORD} --grpc-web"
try {
sh loginArgoCmd
echo "✅ 成功登录到 ArgoCD"
} catch (Exception e) {
echo "❌ ArgoCD 登录失败: ${e.message}"
error("❌ ArgoCD 登录失败")
}
def loginGitCmd = "argocd repo add http://${OPS_REPO} --username ${GIT_USER} --password ${GIT_PASSWORD} --insecure-skip-server-verification --grpc-web --upsert"
try {
sh loginGitCmd
echo "✅ 成功登录到 REPO仓库"
} catch (Exception e) {
echo "❌ REPO仓库 登录失败: ${e.message}"
error("❌ REPO仓库 登录失败")
}
try {
// 1. 确保 helm 目录存在
def helmExists = sh(script: "test -d helm && echo exists", returnStatus: true)
if (helmExists != 0) {
error("❌ helm 目录不存在,请检查代码仓库")
}
// 2. 检查应用是否存在
def appExists = sh(
script: "argocd app list --grpc-web | grep -w '${AppName}'",
returnStatus: true
)
// 3. 应用存在则更新,不存在则创建
if (appExists == 0) {
echo "🔄 ArgoCD 应用 ${AppName} 已存在,执行更新..."
sh """
argocd app set ${AppName} \
--repo http://${OPS_REPO} \
--path helm \
--revision ${BRANCH} \
--sync-policy automated \
--self-heal \
--grpc-web
"""
} else {
echo "🆕 创建 ArgoCD 应用: ${AppName}"
sh """
argocd app create ${AppName} \
--repo http://${OPS_REPO} \
--path helm \
--dest-namespace default \
--revision ${BRANCH} \
--dest-server https://kubernetes.default.svc \
--sync-policy automated \
--auto-prune \
--sync-option PruneLast=true \
--sync-option CreateNamespace=true \
--grpc-web
"""
}
echo "🔄 等待应用同步完成 ${AppName}..."
sh "argocd app wait ${AppName} --health --grpc-web"
echo "✅ ArgoCD 操作完成"
} catch (Exception e) {
error "❌ ArgoCD 操作失败: ${e.message}"
}
}
}
}
}
}
}
}
- ci/jnlp.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: jenkins-slave
spec:
volumes:
- name: docker-socket
emptyDir: {}
- name: workspace-volume
emptyDir: {}
serviceAccount: jenkins
dnsPolicy: ClusterFirst
#nodeName: k8s-node07
containers:
- name: jnlp
image: registry.cn-guangzhou.aliyuncs.com/cumybride/inbound-agent:latest #原镜像:jenkins/inbound-agent:latest,换了个tag而已
- name: tools
image: registry.cn-guangzhou.aliyuncs.com/cumybride/tools:latest # 工具包镜像,用于CD
command:
- cat
tty: true
- name: tools-argocd
image: registry.cn-guangzhou.aliyuncs.com/cumybride/tools-argocd:latest # 带argocd命令的tools镜像
command: ["cat"]
tty: true
- name: docker
image: registry.cn-guangzhou.aliyuncs.com/cumybride/docker:latest # 原镜像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-guangzhou.aliyuncs.com/cumybride/docker:19.03.1-dind # 原镜像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 --platform=linux/amd64 registry.cn-guangzhou.aliyuncs.com/cumybride/alpine:latest
# 安装kubectl helm yq envsubst
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|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
- ci/tools-argocd镜像的Dockerfile(包含argocd-cli工具的tools镜像)
FROM registry.cn-guangzhou.aliyuncs.com/cumybride/tools:latest
#RUN curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.7.4/argocd-linux-amd64 && chmod +x /usr/local/bin/argocd
ADD argocd-linux-amd64 /usr/local/bin/argocd
RUN chmod +x /usr/local/bin/argocd
- Dockerfile (运行这个go程序的镜像)
# 指定基础的go编译镜像
FROM registry.cn-guangzhou.aliyuncs.com/cumybride/golang:alpine3.17 as build
# 指定go的环境变量
RUN go env -w GOPROXY= https://goproxy.cn ,direct # https://mirrors.aliyun.com/goproxy/
RUN go env -w \
GOPROXY= https://goproxy.cn,https://mirrors.aliyun.com/goproxy/ ,direct \
GOSUMDB=off \
GO111MODULE=on
# 指定工作空间目录,会自动cd到这个目录
WORKDIR /opt
# 把项目的其他所有文件拷贝到容器中
COPY . .
# 编译成可执行二进制文件
RUN go env -w GO111MODULE=on
RUN go mod tidy
RUN go build -o app main.go
#FROM registry.cn-guangzhou.aliyuncs.com/cumybride/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/*
# 这里如果网络不稳定,apk update偶发报错,可以考虑直接使用预装依赖的镜像;即找网络稳定的机器用上面俩FROM+RUN来build一个 alpine-ca:latest
FROM registry.cn-guangzhou.aliyuncs.com/cumybride/alpine-ca:latest as serviceDeploy
ENV TZ=Asia/Shanghai
COPY --from=build /opt/app /
CMD ["/app"]
2.2 Jenkins环境配置
配置动态 slave 节点
① 访问地址: http://192.168.0.66:30989/manage/cloud/new
② Cloud name: Kubernetes || Type: Kubernetes —— create 创建动态节点
配置连接 Kubernetes API Server 的地址:
名称: Kubernetes
Kubernetes地址:https://kubernetes.default.svc.cluster.local
Kubernetes命名空间:argocd
”连接测试“(在页面右边): Connected to Kubernetes v1.28.0 —— 出现k8s版本即连接正常
配置Jenkins地址
Jenkins 地址 :http://jenkins.argocd.svc.cluster.local:8080 (这里看情况用https或http)
Jenkins 通道 :jenkins.argocd.svc.cluster.local:50000
Add Pod Labels —— 键:jenkins 值:jenkins
最后Save即可
配置凭据
① 访问地址:http://192.168.0.66:30989/credentials/store/system/domain/_/
② 添加凭据:
-
ID:registry-auth
用户名:zwbnhic
密码:xxxxxx
描述:阿里云ACR容器镜像仓库认证信息
-
ID:gitlab-auth
用户名:root
密码:xxxxxx
描述:gitlab代码仓库认证信息
-
ID:argo-auth
用户名:admin
密码:xxxxxx
描述:argocd认证信息
2.3 Jenkins配置pipeline实现CI
Jenkins——"新建item"——”流水线:cumy“ # 这里跟代码仓库的项目名同名
流水线——”Configuration“
定义:Pipeline script from SCM
SCM:Git
Repositories URL:http://192.168.7.71:8028/root/cumy.git
Credentials:root/*** (gitlab代码仓库认证信息),前面创建的 gitlab-auth
Branches to build: gitops/dev-1.0
脚本路径:Jenkinsfile
三、Argocd 实现CD
3.1 实验做的demo展示(以下文件均存放/上传于gitlab代码仓库中: http://192.168.7.71:8028/root/cumy.git )
利用helm命令渲染helm/templates目录下的deployment.yaml,这里的变量全部由values.yaml渲染而成
- helm/templates/deployment.yaml (这里按实际需求写,我这里简单写一个deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app.name }}-deployment
labels:
app: {{ .Values.app.name }}
#namespace: argocd
spec:
replicas: 1
selector:
matchLabels:
app: {{ .Values.app.name }}
template:
metadata:
labels:
app: {{ .Values.app.name }}
spec:
#nodeName: k8s-node07
containers:
- name: {{ .Values.app.name }}
image: "{{ .Values.app.image.repository }}:{{ .Values.app.image.tag }}"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 2
periodSeconds: 5
- helm/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.app.name }}-svc
#namespace: argocd
spec:
type: ClusterIP
selector:
app: {{ .Values.app.name }}
ports:
- port: 80
targetPort: 8080
protocol: TCP
然后这个项目还有用于Helm的values.tpl和helm/Chart.yaml,下面都是后续可以用于每个分支的固定文件
- values.tpl (利用envsubst命令生成/更新代码仓库helm目录下的values.yaml文件,这里的变量全部由tools容器自动替换)
app:
name: ${APP_NAME}
image:
repository: ${DOCKER_REGISTRY}/${REGISTRY_NAMESPACE}/${APP_NAME}
tag: ${IMAGE_TAG}
commitId: ${COMMITID}
- helm/Chart.yaml (用于Helm部署应用)
apiVersion: v2
name: cumy
description: A Helm chart for Jenkins CI Demo App
type: application
version: 0.1.0
appVersion: "1.0"
3.2 Argocd创建APP实现CD
注意:Jenkinfile中已经定义”利用tools-argocd容器完成更新/同步APP的动作实现CD“,这里只是针对WEB端和手动创建的说明
参考:https://cloud.tencent.com/developer/article/2398649
ArgoCD的APP配置文件参考: ”NEW APP“ → “EDIT AS YAML”
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: http://192.168.7.71:8028/root/cumy.git # 指向包含应用代码和 Helm Charts 的 Git 仓库的 URL
targetRevision: gitops/dev-1.0 # 指定要使用的代码分支
destination: # 目标 Kubernetes 集群和命名空间配置
server: 'https://kubernetes.default.svc' # 指向默认的 Kubernetes API 服务器
namespace: argocd # 应用程序部署到的 Kubernetes 命名空间为 argocd
syncPolicy: # 同步策略设置
automated: # 启用自动同步
prune: true # 在同步过程中自动删除不再需要的资源
selfHeal: true # 启用自我恢复功能,若检测到偏差会自动纠正
或者直接在UI上配置Argocd实现CD
Argocd —— “Applications” —— “NEW APP”
【GENERAL】
Application Name:cumy
Project Name:default (如需自定义项目名称,需先创建)
SYNC POLICY(默认):Manual
【SOURCE】
Repository URL(Git):http://192.168.7.71:8028/root/cumy.git
Revision(Branches):gitops/dev-1.0
Path:helm
(这里的路径是 仓库中 Kubernetes 清单文件的子目录路径 , 包含应用的 YAML 文件,如 :Deployment、Service)
【DESTINATION】
Cluster URL:https://kubernetes.default.svc
Namespace:argocd
实际使用
切换分支仅需要在jenkins-Web那边修改分支即可,
新建项目就把对应文件Fork过去就可以了,然后改改部署yaml就可以点构建了
ps:除了部署的yaml:deployment.yaml + service.yaml 和 代码:main.go + go.mod

浙公网安备 33010602011771号