前言
上一篇文章介绍了公司基于docker的CICD架构,具体内容参考文章
GitLab+Jenkins集群+docker CICD集成
本文将分享 GitLab+Jenkins+K8S+Docker CICD方案实践
k8s简介
k8s是一个完备的分布式系统支持平台,k8s具有完备的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级能力和在线扩容能力、可扩展的资源自我调度机制,以及粒度度的资源配额管理能力。同时k8s提供了完善的管理工具。这些工具包含开发,部署测试,运维监控在内的各个环节,因此,k8s是一个全新的基于容器技术的分布式架构解决方案,并且是一个一站式完备的分布式系统开发和支撑平台。
CICD架构设计
上篇文章的CICD架构其实存在一些问题 GitLab+Jenkins集群+docker CICD集成
- 所有资源无法集中管理,无法根据实际运行资源进行划分
- 无法实现动态扩容,缩容
- 对回滚不友好
引入K8S后这些问题能够得到有效解决。引入K8S后只需稍微改造下发布jenkinsfile即可实现集成。CICD流程如下
- 开发人员提交代码
- 开发人申请merge request
- repo owner 合并代码
- 开发人员trigger build
- checkout 代码
- mvn 编译
- 构建docker 镜像
- 推送镜像到docker hub
- 将K8S 资源文件发送到K8S主节点
- 在主节点运行K8S命令启动pod
Deployment资源清单
deployment作为K8S资源组件支持资源限制及滚动更新因此项目中采用此种方式发布pod
由于是微服务项目因此只需要提供deployment.yaml模版,在jenkins build时进行动态替换实际为服名称,命名空间等信息
apiVersion: apps/v1
kind: Deployment
metadata:
name: #appName
namespace: #env
spec:
replicas: 1
revisionHistoryLimit: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
selector:
matchLabels:
app: #appName
template:
metadata:
labels:
app: #appName
spec:
imagePullSecrets:
- name: #secret
containers:
- name: #appName
image: #img
ports:
- name:
containerPort: #port
protocol: TCP
env:
- name: "NACOS_SERVER"
value: #nacos
svc资源清单
由于使用k8s管理所有应用部署因此网络连通至关重要,k8s中service组件可配置不同网络模式。
由于项目中前端未改造成容器部署,因此需要在K8S集群提供外部访问K8S node 节点网络。在service.yaml文件中使用nodeport进行端口暴露实现外部访问
apiVersion: v1
kind: Service
metadata:
name: #appName
namespace: #env
spec:
selector:
app: #appName
type: NodePort # service类型
ports:
- port: #port
nodePort: #port
targetPort: #port
jenkinsfile改造
由于引入deployment与service两个资源文件因此在jenkinsfile中需要将两个资源文件模版进行替换后部署
node {
stage('prepare') {
checkout([$class: 'GitSCM', branches: [[name: 'origin/****']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '***********', url: 'http://******']]])
}
stage('build') {
sh "mvn clean install -pl ${project_name} -am -amd -Dmaven.test.skip=true -P ${build_env}"
pom_path = sh (script: 'echo ${project_name}/pom.xml', returnStdout: true).trim()
pom = readMavenPom file: pom_path
app_name = "${pom.artifactId}"
source_file= "${pom.artifactId}/target/*.jar"
jar_file="${pom.artifactId}.jar"
commit_id = sh (script: 'git rev-parse --short HEAD', returnStdout: true).trim()
echo "commit id: $commit_id"
docker_img_name = "${dockerHub}:****/${app_name}"
echo "docker-img-name: ${docker_img_name}"
sh "docker build --build-arg APP_NAME=${app_name} --build-arg SOURCE_FILE=${source_file} --build-arg JAR_FILE=${jar_file} -t ${docker_img_name}:${commit_id} ."
sh "docker login -u **** -p **** ${dockerHub}:****"
sh "docker push ${docker_img_name}:${commit_id}"
echo "delete images"
sh "docker rmi `docker images | grep '${app_name}' | awk '{print \$3}'`"
sh "sed -e 's/#appName/${app_name}/' -e 's/#env/${build_env}/' -e 's/#image/${image_name}/' -e 's/#port/${port}/' -e 's/#NACOS_SERVER/${nacosServer}/' k8s-template.yaml > ${app_name}-${build_env}.yaml"
sh "sed -e 's/#appName/${app_name}/' -e 's/#port/${port}/' -e 's/#env/${build_env}/' service-template.yaml > ${app_name}-${build_env}-svc.yaml"
yaml=app_name+'-'+build_env+'.yaml'
svcYaml=app_name+'-'+build_env+'-svc.yaml'
}
stage('deploy'){
def remote = [:]
remote.name = ip
remote.host = ip
remote.user = ****
remote.password = ****
remote.allowAnyHosts = true
sshPut remote: remote, from: yaml, into: '/**'
sshPut remote: remote, from: svcYaml, into: '/**'
sshCommand remote: remote, command: "kubectl apply -f /**/${app_name}-${build_env}-svc.yaml"
sshCommand remote: remote, command: "kubectl apply -f /**/${app_name}-${build_env}.yaml"
}
}
项目改造
工程项目中增加两个模版文件,具体内容根据实际情况自定义
- k8s-template.yaml
- service-template.yaml
至此所有CICD改造均已完成。
总结
本文使用K8S部署方式比较简单,随着对k8s的了解逐渐深入将会持续对cicd进行升级。同时也会分享更多K8S 原理相关文章