美文网首页
.NET DevOps 接入指南 | 使用GitLab流水线模板

.NET DevOps 接入指南 | 使用GitLab流水线模板

作者: 圣杰 | 来源:发表于2022-03-22 10:18 被阅读0次

    引言

    通过前面几节的介绍,想必你已能够基本玩转GitLab流水线。接下来就来介绍下实际项目中一些流水线的高级设置。比如使用流水线模板来统一相同项目类型的流水线流程。

    定义模板

    通过上面流水线的案例,不难发现一个完整的从构建、测试、打包、发布的流水线配置,相对较长。对于一个解决方案中有多个发布项目的场景,如果都在一个.gitlab-ci.yml文件中配置,那整个流水线的可读性将很差。如果能定义模板,那么不仅可以增加的流水线的可读性,而且可以在相同类型的项目中进行复用。GitLab的流水线就提供的有模板功能,允许用户按照规范定义自己的模板。下面就来定义一个可复用的模板,来简化流水线的配置。

    创建模板仓库

    demos组下创建一个新的项目,命名为:ci-cd templates,并创建jobstemplates两个文件夹。其中jobs文件夹用于创建各个job模板,方便复用;templates文件夹用于定义流水线模板。

    定义构建Job模板

    jobs文件夹中添加build.yml文件,文件中定义.build-job如下,其中引用BUILD_IMAGEBUILD_SHELL变量用来指定构建镜像和构建脚本。

    .build-job:
        image: $BUILD_IMAGE
        stage: build
        script:
            - $BUILD_SHELL
            - echo "build passed"
    

    定义测试Job模板

    jobs文件夹中添加test.yml文件,文件中定义.test-job如下,其中引用TEST_IMAGETEST_SHELL变量用来指定构建镜像和测试脚本。

    .test-job:   
      image: $TEST_IMAGE
      stage: test 
      script:    
        - $TEST_SHELL
        - echo "test passed"
    

    定义发布Job模板

    jobs文件夹中添加publish.yml文件,文件中定义.publish-job如下,其中引用PUBLISH_IMAGEPUBLISH_SHELLPUBLISH_PATH变量用来指定构建镜像、发布脚本和发布目录。

    .publish-job:
      image: $PUBLISH_IMAGE
      stage: deploy
      script:
        - $PUBLISH_SHELL
        - echo "publish passed"
      artifacts:
        paths:
          - $PUBLISH_PATH
    

    定义构建镜像Job模板

    jobs文件夹中添加build-image.yml文件,文件中定义.build-image-job如下,其中引用BUILD_IMAGE_SHELLIMAGE_TAG变量用来指定构建镜像脚本和镜像标签。

    .build-image-job:
        image: docker:19.03.13
        variables:
            DOCKER_HOST: tcp://docker:2376
            DOCKER_TLS_CERTDIR: "/certs"
            DOCKER_TLS_VERIFY: 1
            DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
        services:
            - docker:19.03.13-dind
        tags:
            - docker
        stage: deploy
        before_script:
            - until docker info; do sleep 1; done
            - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
            - echo $IMAGE_TAG
        script:
            - eval $BUILD_IMAGE_SHELL
            - echo 'build docker image succeed'
            - docker push $IMAGE_TAG
            - docker image rm $IMAGE_TAG
    
    

    定义Deployment Job模板

    jobs文件夹中添加apply-deploy.yml文件,文件中定义.apply-deployment-job如下,主要用于创建通用Deployment模板,并进行占位符替换。

    .apply-deployment-job:
        stage: deploy
        image: bitnami/kubectl:1.19
        environment:
            name: $ENV
        before_script:
            - kubectl version
            - kubectl create secret docker-registry gitlab-registry-secret 
              --docker-server="$CI_REGISTRY" 
              --docker-username="$CI_DEPLOY_USER" 
              --docker-password="$CI_DEPLOY_PASSWORD" 
              --docker-email="$GITLAB_USER_EMAIL"  
              -o yaml --dry-run=client | kubectl apply -f -
        script: 
            - |
                cat << EOF > app.deployment.yaml 
                apiVersion: apps/v1
                kind: Deployment
                metadata:
                  name: __APP_NAME__-deployment
                  labels:
                    app: __APP_NAME__
                  annotations:
                    app.gitlab.com/app: __APP_NAME__
                    app.gitlab.com/env: __ENV__  
                spec:
                  replicas: 3
                  selector:
                    matchLabels:
                      app: __APP_NAME__
                  template:
                    metadata:
                      labels:
                        app: __APP_NAME__
                    spec:
                      imagePullSecrets:
                      - name: gitlab-registry-secret
                      containers:
                      - name: __APP_NAME__
                        image: __IMAGE_TAG__
                        ports:
                        - containerPort: 80
                EOF
            - sed -i "s#__APP_NAME__#$APP_NAME#g" app.deployment.yaml
            - sed -i "s#__IMAGE_TAG__#$IMAGE_TAG#g" app.deployment.yaml
            - sed -i "s#__ENV__#$ENV#g" app.deployment.yaml
            - cat app.deployment.yaml        
            - kubectl apply -f app.deployment.yaml
            - echo 'create deployment succeed' 
        cache: []
    
    

    定义Service Job模板

    jobs文件夹中添加apply-service.yml文件,文件中定义.apply-service-job如下,主要用于创建通用Service模板,并进行占位符替换。

    .apply-service-job:
        stage: deploy
        environment:
            name: $ENV
        image: bitnami/kubectl:1.19
        before_script: []
        script:
            - |
                cat << EOF > app.service.yaml 
                apiVersion: v1
                kind: Service
                metadata:
                  name: __APP_NAME__-service  
                  labels:
                    app: __APP_NAME__
                spec:
                  selector:
                    app: __APP_NAME__
                  ports:
                    - protocol: TCP
                      port: 80
                      targetPort: 80            
                EOF
            - sed -i "s#__APP_NAME__#$APP_NAME#g" app.service.yaml
            - cat app.service.yaml        
            - kubectl apply -f app.service.yaml
            - echo 'create service succeed' 
        cache: []
    

    定义Ingress Job 模板

    在jobs文件夹中添加apply-ingress.yml文件,文件中定义.apply-ingress-job如下,主要用于创建通用Ingress模板,并进行占位符替换。

    .apply-ingress-job:
        stage: deploy
        environment:
            name: $ENV
        image: bitnami/kubectl:1.19    
        before_script: []
        script:
            - |
                cat << EOF > app.ingress.yaml 
                apiVersion: networking.k8s.io/v1
                kind: Ingress
                metadata:
                  name: __APP_NAME__-ingress
                  labels:
                      app: __APP_NAME__
                  annotations:
                    cert-manager.io/cluster-issuer: letsencrypt-prod
                    acme.cert-manager.io/http01-edit-in-place: "true" 
                    kubernetes.io/ingress.class: gitlab-nginx
                    kubernetes.io/ingress.provider: nginx
                    nginx.ingress.kubernetes.io/rewrite-target: /
                spec:
                  tls:
                    - hosts:
                        - __INGRESS_HOST__
                      secretName: __APP_NAME__-tls
                  rules:
                    - host: __INGRESS_HOST__
                      http:
                        paths:
                          - path: __INGRESS_PATH__                      
                            pathType: Prefix
                            backend:
                              service:
                                name:  __APP_NAME__-service
                                port:
                                  number: 80         
                EOF
            - sed -i "s#__APP_NAME__#$APP_NAME#g" app.ingress.yaml
            - sed -i "s#__INGRESS_HOST__#$INGRESS_HOST#g" app.ingress.yaml
            - sed -i "s#__INGRESS_PATH__#$INGRESS_PATH#g" app.ingress.yaml
            - cat app.ingress.yaml        
            - kubectl apply -f app.ingress.yaml
            - echo 'create ingress succeed' 
        cache: []
    

    定义ASP.NET Core 流水线模板

    templates文件夹下创建aspnetcore-pipeline.yml,通过GitLab定义的includesextends完成流水线的预置,如下所示:

    include:
        - project: 'demos/cicd-templates'
          ref: main
          file: 
            - 'jobs/build.yml'
            - 'jobs/test.yml'
            - 'jobs/publish.yml'
            - 'jobs/build-image.yml'
            - 'jobs/apply-deploy.yml'
            - 'jobs/apply-service.yml'
            - 'jobs/apply-ingress.yml'
            
    variables:
        ENV: development
        INGRESS_PATH: '/'
        DOTNET_SDK_IMAGE: mcr.microsoft.com/dotnet/sdk:5.0    
        NUGET_CACHE_DIR: '.nuget'
        SLN_PATH: './'
        APP_NAME: $CI_PROJECT_PATH_SLUG
        BUILD_PROJET_PATH: $SLN_PATH
        TEST_PROJECT_PATH: $SLN_PATH
        PUBLISH_PROJECT_PATH: $SLN_PATH
        PUBLISH_PATH: publish/
        BUILD_IMAGE: $DOTNET_SDK_IMAGE
        TEST_IMAGE: $DOTNET_SDK_IMAGE
        PUBLISH_IMAGE: $DOTNET_SDK_IMAGE
        BUILD_SHELL: dotnet build $BUILD_PROJECT_PATH --no-restore
        TEST_SHELL: dotnet test $TEST_PROJECT_PATH --no-restore
        PUBLISH_SHELL: dotnet publish --no-restore $PUBLISH_PROJECT_PATH -o $PUBLISH_PATH
        IMAGE_TAG: $CI_REGISTRY_IMAGE/$APP_NAME:$CI_COMMIT_SHORT_SHA
        BUILD_IMAGE_SHELL: "docker build -t ${IMAGE_TAG} $PUBLISH_PATH -f $PUBLISH_PROJECT_PATH/Dockerfile"
        
    cache: &global_cache
        key: $CI_PROJECT_PATH_SLUG
        paths:
            - './*/obj/project.assets.json' 
            - $NUGET_CACHE_DIR
    
    before_script: 
        - dotnet restore ${SLN_PATH} --packages $NUGET_CACHE_DIR
    
    stages:
        - build
        - test
        - deploy
    
    build-job:
        stage: build
        extends: .build-job 
    
    test-job:
        stage: test
        extends: .test-job
        cache:
            <<: *global_cache
            policy: pull
    
    publish-job:
        stage: deploy
        when: manual
        extends: .publish-job
        cache:
            <<: *global_cache
            policy: pull
    
    build-image-job:
        stage: deploy
        extends: .build-image-job
        tags: ["docker"]
        cache: []    
        needs:
            - publish-job
    
    apply-deployment-job:
        stage: deploy
        extends: .apply-deployment-job
        cache: []
        needs:
            - publish-job
            - build-image-job
    
    apply-service-job:
        stage: deploy
        when: manual
        extends: .apply-service-job
        cache: []
    
    apply-ingress-job:
        stage: deploy
        when: manual
        extends: .apply-ingress-job
        cache: []    
    
    

    完成后,该ASP.NET Core 流水线模板创建完毕,整个模块库的代码结构如下图所示:


    image

    使用流水线模板

    回到我们的示例项目AspNetCore.CiCd.Demo,修改.gitlab-ci.yml如下所示:

    include:
        - project: 'demos/cicd-templates'
          ref: main
          file: 'templates/aspnetcore-pipeline.yml' # 直接引用上面定义的ASP.NET Core 流水线模板
    variables:  # 配置流水线预置遍历
        APP_NAME: aspnetcore-cicd-web  # 指定应用名称
        TEST_PROJECT_PATH: './AspNetCore.CiCd.Web.Tests/' # 指定测试项目路径
        PUBLISH_PROJECT_PATH: './AspNetCore.CiCd.Web/' # 指定发布项目路径
        INGRESS_HOST: demo.shengjie.dev # 指定Ingress域名
        INGRESS_PATH: /dotnet # 指定Ingress 路径
    
    提交后,流水线会按预置的流水线模板进行运行,运行效果如下图所示: image

    通过这种方式,可以发现,仅需管理员创建好通用的流水线模板,比如前端模板,后端模板,其他项目仅需简单按需引用即可,大大简化了项目流水线的配置难度。

    限定分支

    以上的流水线有个问题就是,任何的提交都会触发流水线,这样会相对浪费流水线资源。而按照标准Git Flow 流程,对合并到developreleasemain分支的提交进行持续构建、测试即可。而对于发布应该限定在releasemain分支。那如何进行设置呢?简单,可以通过使用rulesonly关键字进行限定。比如修改构建Job和测试Job模板如下,即可限定持续构建和测试自动运行在maindevelopmain分支。

    build-job:
        stage: build
        extends: .build-job 
        only: ["main","develop","/^release.*$/","merge_requests"]    
    test-job:
        stage: test
        extends: .test-job
        cache:
            <<: *global_cache
            policy: pull
        only: ["main","develop","/^release.*$/","merge_requests"]    
    
    通过修改发布Job模板如下,即可限定持续部署仅能运行在`main`和`release`分支。
    
    publish-job:
        stage: deploy
        when: manual
        extends: .publish-job
        cache:
            <<: *global_cache
            policy: pull
        only: 
            - main
            - /^release.*$/
    

    相关文章

      网友评论

          本文标题:.NET DevOps 接入指南 | 使用GitLab流水线模板

          本文链接:https://www.haomeiwen.com/subject/kryzdrtx.html