jenkins在k8s中的CICD(第二版)


  早在二年前,公司项目上线使用aws一系列产品时,记录过一篇 《》,这篇文章更多详细的记录了非常详细的安装和使用过程;今日,由于公司使用腾讯云,且使用的也是云k8s,本篇文章更多记录CI/CD的一些升级的做法,简单的插件安装等这里就不做介绍。

  所以最大的变化是,k8s项目集群的配置文件变更为git管理,jenkinsfile做了小小的改动,其余的变化不大。

 

1.文件目录

/k8s/config
└── h5-infra
    ├── environments
    │   ├── dev
    │   │   └── gcc-mh1
    │   │       ├── backend
    │   │       │   ├── jenkins
    │   │       │   │   └── gcc-mh1-backend.groovy
    │   │       │   └── tke
    │   │       │       ├── default.conf
    │   │       │       ├── gcc-mh1-backend-configmap.yaml
    │   │       │       ├── gcc-mh1-backend-deployment.yaml
    │   │       │       ├── gcc-mh1-backend-ingress.yaml
    │   │       │       ├── gcc-mh1-backend-service.yaml
    │   │       │       └── kustomization.yaml
    │   │       └── frontend
    │   │           ├── jenkins
    │   │           │   └── gcc-mh1-frontend.groovy
    │   │           └── tke
    │   │               ├── default.conf
    │   │               ├── gcc-mh1-frontend-deployment.yaml
    │   │               ├── gcc-mh1-frontend-ingress.yaml
    │   │               ├── gcc-mh1-frontend-service.yaml
    │   │               └── kustomization.yaml
    │   └── prod
    │       └── gcc-mh1
    │           ├── backend
    │           │   ├── jenkins
    │           │   │   └── gcc-mh1-backend.groovy
    │           │   └── tke
    │           │       ├── default.conf
    │           │       ├── gcc-mh1-backend-configmap.yaml
    │           │       ├── gcc-mh1-backend-deployment.yaml
    │           │       ├── gcc-mh1-backend-ingress.yaml
    │           │       ├── gcc-mh1-backend-service.yaml
    │           │       └── kustomization.yaml
    │           └── frontend
    │               ├── jenkins
    │               │   └── gcc-mh1-frontend.groovy
    │               └── tke
    │                   ├── default.conf
    │                   ├── gcc-mh1-frontend-deployment.yaml
    │                   ├── gcc-mh1-frontend-ingress.yaml
    │                   ├── gcc-mh1-frontend-service.yaml
    │                   └── kustomization.yaml
    ├── scripts
    │   ├── create_project.sh
    │   ├── create_project_web.sh
    │   └── git_update.sh
    └── template
        ├── h5-web-template-dev
        │   ├── backend
        │   │   ├── jenkins
        │   │   │   └── h5-web-template-backend.groovy
        │   │   └── tke
        │   │       ├── default.conf
        │   │       ├── h5-web-template-backend-configmap.yaml
        │   │       ├── h5-web-template-backend-deployment.yaml
        │   │       ├── h5-web-template-backend-ingress.yaml
        │   │       ├── h5-web-template-backend-service.yaml
        │   │       └── kustomization.yaml
        │   └── frontend
        │       ├── jenkins
        │       │   └── h5-web-template-frontend.groovy
        │       └── tke
        │           ├── default.conf
        │           ├── h5-web-template-frontend-deployment.yaml
        │           ├── h5-web-template-frontend-ingress.yaml
        │           ├── h5-web-template-frontend-service.yaml
        │           └── kustomization.yaml
        ├── h5-web-template-prod
        │   ├── backend
        │   │   ├── jenkins
        │   │   │   └── h5-web-template-backend.groovy
        │   │   └── tke
        │   │       ├── default.conf
        │   │       ├── h5-web-template-backend-configmap.yaml
        │   │       ├── h5-web-template-backend-deployment.yaml
        │   │       ├── h5-web-template-backend-ingress.yaml
        │   │       ├── h5-web-template-backend-service.yaml
        │   │       └── kustomization.yaml
        │   └── frontend
        │       ├── jenkins
        │       │   └── h5-web-template-frontend.groovy
        │       └── tke
        │           ├── default.conf
        │           ├── h5-web-template-frontend-deployment.yaml
        │           ├── h5-web-template-frontend-ingress.yaml
        │           ├── h5-web-template-frontend-service.yaml
        │           └── kustomization.yaml
        ├── h5-web-template-web-dev
        │   └── frontend
        │       ├── jenkins
        │       │   └── h5-web-template-frontend.groovy
        │       └── tke
        │           ├── default.conf
        │           ├── h5-web-template-frontend-deployment.yaml
        │           ├── h5-web-template-frontend-ingress.yaml
        │           ├── h5-web-template-frontend-service.yaml
        │           └── kustomization.yaml
        └── h5-web-template-web-prod
            └── frontend
                ├── jenkins
                │   └── h5-web-template-frontend.groovy
                └── tke
                    ├── default.conf
                    ├── h5-web-template-frontend-deployment.yaml
                    ├── h5-web-template-frontend-ingress.yaml
                    ├── h5-web-template-frontend-service.yaml
                    └── kustomization.yaml 
文件模版目录树

  可以看到,k8s文件目录主要分为environments、scritps、template,其中: 

    • environments里面存放的文件为项目文件的jenkinsfile以及k8s的deploy文件。
    • scripts为k8s的deploy的生成脚本,本篇文章不会讲解。
    • template为生成environments里的项目时的固定模板,里面的字符串都是固定的,为了脚本操作时方便。

  最主要的当然是environments,另外三个文件夹也是辅助他的存在,项目的重要文件全部在里面。

 

2.environments讲解

  这是整个流程中最重要的目录,所以拿出来单独讲解。

    ├── environments
    │   ├── dev
    │   │   └── gcc-mh1
    │   │       ├── backend
    │   │       │   ├── jenkins
    │   │       │   │   └── gcc-mh1-backend.groovy
    │   │       │   └── tke
    │   │       │       ├── default.conf
    │   │       │       ├── gcc-mh1-backend-configmap.yaml
    │   │       │       ├── gcc-mh1-backend-deployment.yaml
    │   │       │       ├── gcc-mh1-backend-ingress.yaml
    │   │       │       ├── gcc-mh1-backend-service.yaml
    │   │       │       └── kustomization.yaml
    │   │       └── frontend
    │   │           ├── jenkins
    │   │           │   └── gcc-mh1-frontend.groovy
    │   │           └── tke
    │   │               ├── default.conf
    │   │               ├── gcc-mh1-frontend-deployment.yaml
    │   │               ├── gcc-mh1-frontend-ingress.yaml
    │   │               ├── gcc-mh1-frontend-service.yaml
    │   │               └── kustomization.yaml
    │   └── prod
    │       └── gcc-mh1
    │           ├── backend
    │           │   ├── jenkins
    │           │   │   └── gcc-mh1-backend.groovy
    │           │   └── tke
    │           │       ├── default.conf
    │           │       ├── gcc-mh1-backend-configmap.yaml
    │           │       ├── gcc-mh1-backend-deployment.yaml
    │           │       ├── gcc-mh1-backend-ingress.yaml
    │           │       ├── gcc-mh1-backend-service.yaml
    │           │       └── kustomization.yaml
    │           └── frontend
    │               ├── jenkins
    │               │   └── gcc-mh1-frontend.groovy
    │               └── tke
    │                   ├── default.conf
    │                   ├── gcc-mh1-frontend-deployment.yaml
    │                   ├── gcc-mh1-frontend-ingress.yaml
    │                   ├── gcc-mh1-frontend-service.yaml
    │                   └── kustomization.yaml
  
environments详细目录文件

可以看出路径为environments/dev/gcc-mh1/backend和frontend,最下面分为jenkins以及tke文件。

  其中jenkins中是jenkinsfile文件,tke则是k8s的相关文件。

  后面通过脚本的更改,将各文件的内容替换掉。整个jenkins都可以围绕整个文件夹为中心。

 

3.持续部署持续交付

  具体细节这里就不做过多讲解,可以参考本人2年前的博客。

  1.创建一个”流水线项目”,首先进入参数化构建过程.

  发布与回滚需要用到参数化构建过程中3个选项参数,一个运行时参数.(参数值最好不要用“-”,否则pipeline读取变量时无法识别)

  分支参数

  Git使用这个的变量来判断拉取哪个分支的代码.

  命名空间

  用这个控制服务部署在k8s的哪个命名空间下

  在之前的项目中,jenkins写在了jenkins的pipeline里,这样不好管理,也比较繁琐,这里,直接将任何项目的jenkinsfile放在了git上

  2.流水线语法

  这里改动不是很大,所以,这里就不详细解释语法用法,最新版本的jenkinsfile甚至取消了回滚功能,但是本篇文章主要讲解项目文件的规范管理方式,如果有需要增加回滚等功能,在上面拓展即可。

  注意:这里frontend以及backend的jenkinsfile也有稍微的改动,但是这里就不做对比了,具体的文件参考本人的项目文件留档。

[root@k8s-lizexiong jenkins]# cat gcc-mh1-frontend.groovy 
// 公共
def REGISTRY= "denadocker.tencentcloudcr.com"
def GIT_ADDRESS = "https://私有git/h5-development/gcc-mh1.git"
def GIT_INFRA_ADDRESS = "http://私有git/devops_web/h5-infra.git"
def PROJECT_NAME ="gcc"
def ACTIVITY_NAME = "mh1"
//def CDN_DIR= "${PROJECT_NAME}/(ACTIVITY_NAME.replaceAll('/','-'))"
def CDN_DIR= "${PROJECT_NAME}"+ "/" + "${ACTIVITY_NAME}".replaceAll('-','/')
def POJECT_TYPE = "frontend"


// 项目
def REGISTRY_NAMESPACE = "h5-web"
def BRANCH_STR= (branch.replaceAll('/','-'))
def IMAGE_NAME= "${REGISTRY}/${REGISTRY_NAMESPACE}/${PROJECT_NAME}-${ACTIVITY_NAME}-${POJECT_TYPE}:${BRANCH_STR}-${BUILD_NUMBER}"
def SERVICE_DIR = "h5"
def INFRA_DIR = "h5-infra"
// 认证
def TCR_AUTH = "973589fa-7ae2-4a08-9002-b139ea04c61c"
def GIT_AUTH = "93766ad8-ffee-42f4-ac01-afa590157c3b"
def K8S_AUTH = "h5web-k8s-test"

//def ENVIRONMENT=""
//def branch=""
node() {
    stage('checkout service code') {
        checkout([$class: 'GitSCM', branches: [[name: "${branch}"]], extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: "${SERVICE_DIR}"],[$class: 'CleanBeforeCheckout']], userRemoteConfigs: [[credentialsId: "${GIT_AUTH}", url: "${GIT_ADDRESS}"]]])
    }
    stage('compile code') {
        withDockerContainer(image: "node:14") {
            sh """
            echo ${CDN_DIR}
            cd ${SERVICE_DIR}/frontend
            npm install && npm run build
            """
        }
    }
    stage('build and push image') {
        withCredentials([usernamePassword(credentialsId: "${TCR_AUTH}", passwordVariable: 'TCR_PASSWORD', usernameVariable: 'TCR_USERNAME')]) {
            sh """
                # login to TCR
                echo "Login to TCR"
                echo ${TCR_PASSWORD} | docker login --password-stdin -u ${TCR_USERNAME} https://${REGISTRY}
                echo "docker build & push"
                cd ${SERVICE_DIR}/frontend
                echo '
                FROM denadocker.tencentcloudcr.com/h5-web/nginx:1.19.10-logformat-v1
                ADD ./dist/*.html  /usr/share/nginx/html/
                EXPOSE 80
                ' > Dockerfile
                echo "docker build & push"
                docker build  -f ./Dockerfile  -t ${IMAGE_NAME} .
                docker push ${IMAGE_NAME} 
            """
        }
    }
    stage('upload resources to the CDN'){
        sh "ossutil64 cp -rf ${SERVICE_DIR}/frontend/dist/static/ oss://cn-op-web/cdn/h5/${CDN_DIR}/static/"
        //sh "ossutil64 cp -rf ${SERVICE_DIR}/frontend/dist/static/ oss://cn-op-web/cdn/h5/${PROJECT_NAME}/${ACTIVITY_NAME}/static/"
    }

    stage('checkout infra code') {
        checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: "${INFRA_DIR}"],[$class: 'CleanBeforeCheckout']], userRemoteConfigs: [[credentialsId: "${GIT_AUTH}", url: "${GIT_INFRA_ADDRESS}"]]])
    }

    stage('deploy'){
        sh """
            echo deploy service
            cd ./${INFRA_DIR}/environments/${ENVIRONMENT}/${PROJECT_NAME}-${ACTIVITY_NAME}/${POJECT_TYPE}/tke
            sed -i 's#\$IMAGE_NAME#${IMAGE_NAME}#' ${PROJECT_NAME}-${ACTIVITY_NAME}-${POJECT_TYPE}-deployment.yaml
            cd -
            kustomize build --load_restrictor none ./${INFRA_DIR}/environments/${ENVIRONMENT}/${PROJECT_NAME}-${ACTIVITY_NAME}/${POJECT_TYPE}/tke >${PROJECT_NAME}-${ACTIVITY_NAME}-${POJECT_TYPE}.yaml
          """
        kubernetesDeploy configs: "${PROJECT_NAME}-${ACTIVITY_NAME}-${POJECT_TYPE}.yaml", kubeconfigId: "${K8S_AUTH}"
    }
}

可以看出2年前版本的jenkinsfile比较明显的改变就是npm编译直接使用docker容器,而不是本地安装,在最后CD的过程钱使用了kustomize来校对管理k8s的配置文件。 

 

4.总结

  整篇文档没有两年前的安装和解释那么详细,但是给人了一种文件规范管理的思路,这样,即使跳板机更改和一些其它情况,配置文件都能规范同步,规范管理。

  如果对安装以及版本流程不太清楚的,可以参考本人两年前的jenkins博客:https://www.cnblogs.com/lizexiong/p/14863602.html