KubeSphere对接ArgoCD
ArgoCD简介
Argo CD是用于Kubernetes的声明性GitOps持续交付工具,应用程序定义,配置和环境应为声明性的,并应受版本控制,应用程序部署和生命周期管理应该是自动化、可审核且易于理解。
Argo CD遵循GitOps模式,该模式使用Git仓库作为定义所需应用程序状态的真实来源。
Argo CD可在指定的目标环境中自动部署所需的应用程序状态,应用程序部署可以在Git提交时跟踪对分支,标签的更新,或固定到清单的特定版本。
官网:https://argoproj.github.io/
ArgoCD架构图:
Argo CD被实现为kubernetes控制器,该控制器持续监视正在运行的应用程序,并将当前的活动状态与所需的目标状态(在Git存储库中指定)进行比较。当已部署应用程序的运行状态偏离目标状态时将被argoCD视为OutOfSync。
Argo CD报告并可视化差异,同时提供了自动或手动将实时状态同步回所需目标状态的功能。在Git存储库中对所需目标状态所做的任何修改都可以自动应用并同步到指定的目标环境中。
ArgoCD支持的Kubernetes 配置清单包括helm charts、kustomize或纯YAML/json文件等。
本篇文章涉及内容:
- 使用kubesphere devops实现CI部分, CD部分由argoCD完成;
- ArgoCD持续监测git仓库某个目录下yaml文件变动,自动将yaml文件部署到k8s集群;
- ArgoCD持续监测harbor镜像仓库某个镜像tag变动,自动将最新镜像部署到k8s集群。
基本原理图:
准备git代码仓库
准备2个git仓库,一个源码仓库,一个yaml文件仓库,源码和yaml文件分离。
源码仓库可参考以下链接,离线环境原因,这里选择第二个示例spring-demo:
https://github.com/kubesphere/devops-java-sample
https://github.com/willzhang/spring-demo
yaml文件仓库可参考以下链接,这里命名为argocd-gitops:
https://github.com/argoproj/argocd-example-apps
yaml仓库下创建javademo目录,并创建2个简单的yaml文件:
[root@jenkins git]# tree argocd-gitops/
argocd-gitops/
├── javademo
│ ├── javademo-deployment.yaml
│ └── javademo-svc.yaml
javademo-deployment.yaml示例,当前镜像tag可随意指定,执行CI时会实时替换该参数:
apiVersion: apps/v1
kind: Deployment
metadata:
name: javademo
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: javademo
template:
metadata:
labels:
app: javademo
spec:
containers:
- image: 10.39.140.196:8081/apps/javademo:replace
name: javademo
ports:
- containerPort: 8080
javademo-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: javademo
spec:
type: NodePort
ports:
- port: 8012
targetPort: 8080
selector:
app: javademo
部署ArgoCD
argocd有多种部署方式,可以直接部署yaml文件
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
这里使用helm方式部署,可直接指定argocd server service类型nodePort:
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd \
--namespace=argocd --create-namespace \
--set server.service.type=NodePort \
argo/argo-cd
查看运行的pod
[root@master ~]# kubectl -n argocd get pods
NAME READY STATUS RESTARTS AGE
argocd-application-controller-5db8c6f8f9-qnmtr 1/1 Running 0 8h
argocd-dex-server-84b5cbfbc9-fc7rf 1/1 Running 0 8h
argocd-redis-7c7c79dcd9-hjhgr 1/1 Running 0 8h
argocd-repo-server-5fb9cbb945-9xmc7 1/1 Running 0 8h
argocd-server-8d8cb6488-pjwt4 1/1 Running 0 8h
如果使用kubesphere部署argocd,首先需要配置argocd helm仓库,进入企业空间,选择应用模板上传离线helm chart包,或在应用仓库配置公网helm repo地址。
完成后进入项目,点击部署新应用,选择argocd helm chart进行部署即可:
安装ArgoCD CLI
要与ArgoCD API Server进行交互,我们需要安装CLI命令:
wget https://github.com/argoproj/argo-cd/releases/download/v1.7.10/argocd-linux-amd64
cp argocd-linux-amd64 /usr/local/bin/argocd
chmod +x /usr/local/bin/argocd
argocd version
如果上面argocd使用yaml方式部署,修改serivce类型为nodeport,以便访问Argo CD API Server
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'
查看argocd server service,记录nodeport信息:
[root@master ~ ]# kubectl -n argocd get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-dex-server ClusterIP 10.99.232.27 <none> 5556/TCP,5557/TCP,5558/TCP 5d
argocd-metrics ClusterIP 10.107.37.4 <none> 8082/TCP 5d
argocd-redis ClusterIP 10.106.160.6 <none> 6379/TCP 5d
argocd-repo-server ClusterIP 10.100.101.100 <none> 8081/TCP,8084/TCP 5d
argocd-server NodePort 10.106.141.243 <none> 80:31195/TCP,443:32079/TCP 5d
argocd-server-metrics ClusterIP 10.109.81.234 <none> 8083/TCP 5d
argocd默认登录用户为admin,初始密码为argocd-server pod名称,获取pod名称
podName=`kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2`
使用argocd CLI登录,以nodeIP和nodePort作为argocd server登录地址:
argocd login 10.39.140.248:31195 --username admin --password $podName
修改默认密码
argocd account update-password \
--current-password $podName \
--new-password argocd@123
浏览器登录argocd UI
https://10.39.140.248:31195
部署ArgoCD应用
登陆Argocd UI后,选择NEW APP创建application,选择EDIT AS AYML
粘贴以下内容,SAVE后点击左上CREATE,当然也可以直接使用kubectl apply命令执行以下内容,效果相同。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: javademo
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
path: javademo
repoURL: http://10.39.140.196:10080/gogs/argocd-gitops.git
targetRevision: HEAD
destination:
namespace: apps
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- Validate=false
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
参数说明:
- metadata字段:指定了应用名称,命名空间必须指定argocd,添加finalizers字段可在删除应用时级联删除相关k8s资源;
- source字段:指定了yaml文件所在git仓库URL,及要监测的yaml文件存放目录,该目录下文件有任何变更argocd都会自动将其更新部署到k8s集群;
- destination字段:指定监测的yaml文件要部署到哪个k8s集群及哪个命名空间下;
- syncPolicy字段:指定自动同步策略和频率,不配置时需要手动触发同步。
另外如果使用私有git仓库,需要创建凭证,这里的凭证是argocd访问yaml文件git仓库的凭证:
等效的argocd cli命令:
argocd repo add http://10.39.140.196:10080/gogs/argocd-gitops --username gogs --password xxxxxx
创建后argocd会自动将git仓库javademo目录下的yaml文件部署到k8s集群,此时应用无法正常启动,因为yaml文件中的镜像tag还不存在,拉取镜像会失败:
也可以使用argocd CLI查看部署的应用
[root@master ~]# argocd app get javademo
Name: javademo
Project: default
Server: https://kubernetes.default.svc
Namespace: apps
URL: https://10.39.140.248:31195/applications/javademo
Repo: http://10.39.140.196:10080/gogs/argocd-gitops.git
Target: HEAD
Path: javademo
SyncWindow: Sync Allowed
Sync Policy: Automated (Prune)
Sync Status: Synced to HEAD (1b96380)
Health Status: Progressing
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service apps javademo Synced Healthy service/javademo unchanged
apps Deployment apps javademo Synced Progressing deployment.apps/javademo unchanged
在kubesphere UI查看pod状态,一直在重试拉取镜像:
使用kubectl命令查看,状态为ImagePullBackOff :
[root@master ~]# kubectl -n apps get pods
NAME READY STATUS RESTARTS AGE
javademo-64d46bff8-6dgjn 0/1 ImagePullBackOff 0 13m
[root@master ~]# kubectl -n apps get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
javademo ClusterIP 10.111.56.180 <none> 8012/TCP 33m
kubesphere创建流水线
创建CI流水线,使用kubesphere devops完成源码编译、镜像构建并推送到harbor仓库,最后以git commit方式更新yaml仓库中image字段。
由于此时argoCD持续监测yaml仓库配置文件变动,当CI部分执行git push时便会触发argoCD更新yaml文件到k8s集群。
在kubesphere devops工程下创建一条空流水线,命名为javademo,进入流水线,选择编辑Jenkinsfile,复制以下内容:
pipeline {
environment {
GIT_URL='http://10.39.140.196:10080/gogs/spring-demo.git'
GIT_CREDENTIAL_ID = 'git-id'
GIT_BRANCH = 'master'
REGISTRY = '10.39.140.196:8081/apps/javademo'
REGISTRY_CREDENTIAL_ID = 'harbor-id'
}
agent {
node {
label 'maven'
}
}
stages {
stage('SCM Checkout') {
steps {
git branch: "${GIT_BRANCH}", credentialsId: "${GIT_CREDENTIAL_ID}", url: "${GIT_URL}"
}
}
stage('source build') {
steps {
container('maven') {
sh 'mvn clean package'
}
}
}
stage('docker build & push') {
steps {
script {
env.COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
env.TIMESTRAP = sh(returnStdout: true, script: 'date +%Y%m%d%H%M%S').trim()
env.DOCKER_TAG = "dev_${TIMESTRAP}_${COMMIT_ID}_${BUILD_NUMBER}"
}
container('maven') {
withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$REGISTRY_CREDENTIAL_ID" ,)]) {
sh 'docker build -t $REGISTRY:$DOCKER_TAG .'
sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker push $REGISTRY:$DOCKER_TAG'
}
}
}
}
stage('update docker tag') {
environment {
BUILD_USER = 'admin'
BUILD_USER_EMAIL = 'admin@argocd.com'
YAML_REPO_URL='http://${username}:${password}@10.39.140.196:10080/gogs/argocd-gitops.git'
}
steps {
withCredentials([usernamePassword(passwordVariable : 'password' ,usernameVariable : 'username' ,credentialsId : "$GIT_CREDENTIAL_ID" ,)]) {
sh """ git config --global user.name "$BUILD_USER" git config --global user.email "$BUILD_USER_EMAIL" git clone ${YAML_REPO_URL} && cd argocd-gitops sed -i "s#$REGISTRY.*#${REGISTRY}:${DOCKER_TAG}#g" javademo/javademo-deployment.yaml git add -A && git commit -m "update tag: ${DOCKER_TAG}" && git push ${YAML_REPO_URL} """
}
}
}
}
}
注意修改相关参数,流水线中引用了2个凭证:
- GIT_CREDENTIAL_ID为内网gogs git仓库账号密码
- REGISTRY_CREDENTIAL_ID为harbor仓库账号密码
运行流水线前需要在devops工程下提前创建好相关凭证,后续需要在jenkinsfile中引用。
最终流水线如下,点击运行,等待流水线执行完成,查看状态为成功:
查看流水线构建日志,可以看到执行了以下过程,其中最后update docker tag步骤,执行了2个关键操作,sed命令替换镜像tag,然后执行git push更新yaml仓库。
查看推送到harbor仓库的镜像:
ArgoCD监测到yaml文件变更后更新至k8s集群:
ArgoCD UI查看使用的镜像:
登录kubesphere UI查看应用状态为运行中:
在git仓库直接修改yaml文件配置,同样能够触发argocd同步,例如将service类型改为nodePort:
等待argoCD自动同步配置更新到k8s集群,浏览器以nodeport方式访问java web应用:
部署Argo CD Image Updater
上面演示了基于git仓库变更作为应用部署的事实来源,下面演示另一种方式,以镜像tag变更作为应用部署的事实来源。argocd提供了Argo CD Image Updater
小工具,用于实现该操作。
argo cd image updater是一种自动更新由Argo CD管理的Kubernetes工作负载容器镜像的工具。
该工具目前还在开发中,并且有以下特性和局限性:
- 只能更新由Argo CD管理并由Helm或Kustomize工具生成的应用程序的镜像;
- 对广泛使用的容器仓库的默认支持:dockerhub、harbor私有镜像仓库等;
- 能够使用匹配器功能过滤镜像仓库返回的标签列表;
- 镜像拉取secrets必须存在于Argo CD Image Updater在其中运行(或可以访问)的同一Kubernetes群集中。当前不可能从其他集群中获取这些secrets。
- 在当前版本中,Argo CD Image Updater不会将任何更改写回到Git存储库。
官方文档:
https://argocd-image-updater.readthedocs.io/en/stable/
Argo CD Image Updater部署略显繁琐,部署操作如下:
1、在argo cd中创建本地用户
创建Argo CD镜像更新程序需要访问Argo CD API Server的凭据,使用一个image-updater具有适当API权限的帐户,将以下用户定义添加到argocd-cm:
# kubectl -n argocd edit cm argocd-cm
data:
accounts.image-updater: apiKey
为用户创建访问令牌,将令牌的值复制到某个地方,稍后将需要它。
argocd account generate-token --account image-updater --id image-updater
为image-updater
用户配置适当的RBAC权限,Argo CD Image Updater需要应用程序的update
和get
权限。
# kubectl -n argocd edit cm argocd-rbac-cm
data:
policy.default: role:readonly
policy.csv: | p, role:image-updater, applications, get, */*, allow p, role:image-updater, applications, update, */*, allow g, image-updater, role:image-updater
3、 安装Argo CD Image Updater
yaml文件下载:https://github.com/argoproj-labs/argocd-image-updater/tree/master/manifests
kubectl create ns argocd-image-updater
kubectl apply -n argocd-image-updater -f manifests/install.yaml
4、 配置镜像仓库
即使您不打算使用私有镜像仓库,您也需要至少配置一个empty registries.conf
:
# kubectl -n argocd-image-updater edit cm argocd-image-updater-config
data:
registries.conf: ""
没有此条目argocd-image-updater
pod将无法启动。
如果使用私有镜像仓库可参考以下配置,以harbor镜像仓库为例:
data:
argocd.insecure: "true"
log.level: debug
registries.conf: | registries: - name: harbor api_url: http://10.39.140.196:8081 prefix: 10.39.140.196:8081 ping: yes insecure: yes
当从清单安装到Kubernetes集群时,Argo CD Image Updater将从名为ARGOCD_TOKEN
的环境变量中读取访问Argo CD API所需的令牌,该环境变量是从名为argocd.token
的secret字段中设置的argocd-image-updater-secret
。
argocd.token
的值应设置为您上面生成的访问令牌的base64编码值。作为一种捷径,您可以使用kubectl
生成密钥,并将其应用于现有资源:
YOUR_TOKEN=xxx
kubectl create secret generic argocd-image-updater-secret \
--from-literal argocd.token=$YOUR_TOKEN --dry-run -o yaml |
kubectl -n argocd-image-updater apply -f -
更改后,必须重新启动 argocd-image-updater
Pod,即运行
kubectl -n argocd-image-updater rollout restart deployment argocd-image-updater
新建yaml仓库Kustomize文件
由于image updater仅支持helm或Kustomize类型yaml,这里新建一个基于Kustomize的yaml目录,修改yaml中的参数不要与之前的冲突即可:
[root@jenkins git]# tree argocd-gitops/kustomize-javademo/
argocd-gitops/kustomize-javademo/
├── javademo-deployment.yaml
├── javademo-svc.yaml
└── kustomization.yaml
javademo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: javademo-tag
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: javademo-tag
template:
metadata:
labels:
app: javademo-tag
spec:
containers:
- image: 10.39.140.196:8081/apps/javademo:replace
name: javademo-tag
ports:
- containerPort: 8080
javademo-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: javademo-tag
spec:
ports:
- port: 8012
targetPort: 8080
selector:
app: javademo-tag
kustomization.yaml
amePrefix: kustomize-
resources:
- javademo-deployment.yaml
- javademo-svc.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
登录argocd UI新建一个argocd应用,和之前相比增加了annotations参数,指定要监测的镜像地址,更新策略为latest,另外修改了source path
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: javademo=10.39.140.196:8081/apps/javademo
argocd-image-updater.argoproj.io/javademo.update-strategy: latest
name: javademo-tag
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: apps
server: https://kubernetes.default.svc
project: default
source:
path: kustomize-javademo
repoURL: http://10.39.140.196:10080/gogs/argocd-gitops.git
targetRevision: HEAD
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- Validate=false
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
登录kubesphere UI重新创建一条ci流水线,删除update docker tag 步骤即可,已经不需要基于git push来触发应用部署了:
pipeline {
environment {
GIT_URL='http://10.39.140.196:10080/gogs/spring-demo.git'
GIT_CREDENTIAL_ID = 'git-id'
GIT_BRANCH = 'master'
REGISTRY = '10.39.140.196:8081/apps/javademo'
REGISTRY_CREDENTIAL_ID = 'harbor-id'
}
agent {
node {
label 'maven'
}
}
stages {
stage('SCM Checkout') {
steps {
git branch: "${GIT_BRANCH}", credentialsId: "${GIT_CREDENTIAL_ID}", url: "${GIT_URL}"
}
}
stage('source build') {
steps {
container('maven') {
sh 'mvn clean package'
}
}
}
stage('docker build & push') {
steps {
script {
env.COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
env.TIMESTRAP = sh(returnStdout: true, script: 'date +%Y%m%d%H%M%S').trim()
env.DOCKER_TAG = "dev_${TIMESTRAP}_${COMMIT_ID}_${BUILD_NUMBER}"
}
container('maven') {
withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$REGISTRY_CREDENTIAL_ID" ,)]) {
sh 'docker build -t $REGISTRY:$DOCKER_TAG .'
sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker push $REGISTRY:$DOCKER_TAG'
}
}
}
}
}
}
查看流水线日志,镜像成功推送到harbor仓库:
harbor仓库镜像tag更新,argocd image updater自动将最新tag更新到k8s集群。
查看镜像tag
以后每次harbor仓库生成最新镜像,ArgoCD都会自动将其更新到k8s集群。
目录 返回
首页