当前位置:首页 » 《随便一记》 » 正文

前端微服务架构下CI/CD构建单镜像落地方案_知无涯

2 人参与  2021年12月21日 14:16  分类 : 《随便一记》  评论

点击全文阅读


前言

之前在团队中分享了qiankun微服务的单镜像的部署方案, 详细解析了单镜像部署的好处,但由于单镜像部署在构建时比较复杂,如果在上线时人工地去构建镜像,将是一个非常复杂,且容易出错的事情。所以本篇文章会介绍一种使用GitLab CI/CD来构建一个微服务单镜像的流水线,并应用于生产, 我称之为 aio 方案 all in one 。五个应用构建到一个docker镜像中。

方案探索

部署文件目录

之前分享的单镜像部署是在根目录创建一个child,将子应用的编译的静态资源都存放其中。 目录大致是这样的

└── daas-web/                 # 根文件夹
    |
    ├── child/                # 存放所有微应用的文件夹
    |   ├── app1/             # 存放微应用 app1 的文件夹
    |   ├── app2/             # 存放微应用 app2 的文件夹
    |   ├── app3/             # 存放微应用 app3 的文件夹
    |   ├── app4/             # 存放微应用 app4 的文件夹    
    ├── index.html            # mainApp的index.html
    ├── css/                  # 主应用mainApp的css文件夹
    ├── js/                   # 主应用mainApp的js文件夹
    ├── Dockerfile            # 镜像构建Dockerfile文件
    ├── default.conf          # nginx配置文件
    

但为了兼容现有的多镜像部署方案,并将改动降到最小。所以直接将子应用的构建目录放到根目录。于是目录就变成了这样

└── daas-web/                 # 根文件夹
    |    
    ├── app1/                 # 存放微应用 app1 的文件夹
    ├── app2/                 # 存放微应用 app2 的文件夹
    ├── app3/                 # 存放微应用 app3 的文件夹
    ├── app4/                 # 存放微应用 app4 的文件夹    
    ├── index.html            # mainApp的index.html
    ├── css/                  # 主应用mainApp的css文件夹
    ├── js/                   # 主应用mainApp的js文件夹
    ├── Dockerfile            # 镜像构建Dockerfile文件
    ├── default.conf          # nginx配置文件
    

这种文件组织结构不用修改原有项目的 publicPath
有关这两种的文件组织方式可以查看一下qiankun的部署文档

GitLab CI/CD方案

基本思路是这样的
在主应用(基座)创建tag来触发流水线
首先进行流水线的初始化工作,清空或创建存放制品的目录
接着触发自身和其他应用的相同tag的流水线,并行执行多条跨项目流水线
然后将每个应用编译出来的制品dist目录都存放到制品目录
最后在制品目录中构建镜像,最后推送到harbor

拆分来讲:
在构建aio镜像时,首先需要在其他子应用创建一个相同的tag,最后在主应用创建一个相同名称的tag。
这里的顺序不能错,因为创建了主应用就会触发流水线,如果其他子应用没有相同的tag则会报错。先创建子应用tag,再创建主应用tag,并且tag名称必须保持一致,最终的镜像版本会从tag中解析出来。

由于目前已经有几个子应用使用了gitlab ci/cd来发布研发和集成环境,之前的流水线触发条件是

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == 'develop'

这种写法已经不满足现有要求,因为在aio方案中主应用的流水线是由tag触发,子应用的流水线是有主应用来触发的。
于是拆分出二个配置模版,模版中会配置job所用的runner,触发条件。
一个(.release_aio_config)用于aio方案,
一个(.develop_config)用于研发集成环境的发布。
在job中可以使用关键词extends 来继承模版,使用此方法在job中也可以覆盖模版的配置。

由于在aio的流水线中,存在制品依赖的关系,在构建docker镜像的job中,需要获取到所有应用的制品,gitlab ci/cd提供了need关键词来是实现制品依赖–跨项目流水线中的制品,在一个job中,可以配置依赖当前流水线中的那些制品,其原理是通过web api来下载制品到当前的工作目录,顺便提下,制品都是上传到gitlab。在尝试了几次后,我发现这是一个付费版本的功能。😄😄。。。。俗话说,上帝给你关了一扇窗,必定会给你打开一扇门。于是我思考片刻,决定从物理层面“暴力突破”付费的限制。该方案就是 基于shell执行器,将各个应用的制品存放在本地。
具体做法是在服务器本地安装gitlab-runner的rpm或deb包,然后注册一个shell执行器的runner。使用该runner编译前端项目,并将各个应用的制品按照规定的目录结构存放到一个固定的“制品汇总目录”。

直接在服务器本地进行构建的,工作目录,文件都存放在本地,所以想把使用容器构建,速度更快。
唯一的缺点是依赖本地的环境(如nodejs,git),迁移麻烦。

最终的流水线概览图是这样的
在这里插入图片描述

由于每个子应用都是一个项目,所以这里的流水线必须要使用跨项目流水线。 这种需求在gitlab ci/cd有多种方式实现,使用api,或者使用 trigge 关键词,这里使用的是 trigge 来触发其他项目的。
有关trigger 关键词的使用可以查看该链接
以下是一个job示例

build_other_job:
  stage: build
  variables:
    UPSTREAM_BUILD_TAG: $CI_COMMIT_TAG
  trigger:
    project: a/b/main-app
    branch: $CI_COMMIT_TAG    
    strategy: depend

该job会触发项目a/b/main-app 的流水线,branch限定了触发的分支,strategy限定了必须等待跨项目流水线完成后,再执行下一阶段,不加strategy限定,默认是创建了跨项目流水线就执行下一阶段,这里使用variables向跨项目流水线传递了一个变量,以备后用。

流水线编写

下面开始流水线的编写

首先定义流水线的阶段,变量与缓存。

目录 /home/gitlab-runner/web 用于存放所有应用编译出的制品

stages:
  - prebuild
  - build
  - build_docker
  - track

variables:
  # 所有制品应该存放的目录
  ALL_ARTIFACTS_PATH: '/home/gitlab-runner/web'

default:
  cache:
    key: $CI_PROJECT_NAME
    paths:
      - node_modules

定义二个模板,一个是aio模板,一个是 触发其他项目流水线的模板,使用模板可以帮我节省很多代码,将公共部分提取出来,统一管理。这里的runner 的tag使用 shell-dass 只在创建了tag时触发。

定义模板

# 默认配置模板
.release_aio_config:
  tags:
    - shell-dass
  only:
    - tags    

.build_other_config:
  stage: build
  variables:
    UPSTREAM_BUILD_TAG: $CI_COMMIT_TAG    
  trigger:
    project: a/b/c
    branch: $CI_COMMIT_TAG    
    strategy: depend
  only:
    - tags

可以在跨项目的流水线中 传递参数 UPSTREAM_BUILD_TAG

预编译作业,与主应用的编译作业

ready_job:
  extends: .release_aio_config
  stage: prebuild
  script:
    # 清空用于存放制品的目录
    - rm -rf $ALL_ARTIFACTS_PATH
    - mkdir -p $ALL_ARTIFACTS_PATH

build_base_job:
  extends: .release_aio_config
  stage: build
  script:
    - yarn 
    - yarn build
    - cp -rf dist/* $ALL_ARTIFACTS_PATH

预编译清空存放制品的目录。 主应用编译完成后直接将dist下的所有文件拷贝到 ALL_ARTIFACTS_PATH 目录。二个作业都继承 .release_aio_config 模板,都是用 shell-dass 这个 runner,并且都是在创建tag时触发

编译子应用的作业

build_model_job:
  extends: .build_other_config  
  trigger:
    project: a/b/c    

build_service_job:
  extends: .build_other_config  
  trigger:
    project: a/b/d  
 
build_management_job:
  extends: .build_other_config  
  trigger:
    project: a/b/e

build_dev_job:
  extends: .build_other_config
  trigger:
    project: a/b/f

编译自定义的作业都继承.build_other_config 模板,只需要覆盖 项目地址即可。

构建docker镜像,推送到harbor,并使用钉钉通知将构建出的镜像推送给钉钉群。

creat_app:
  extends: .release_aio_config
  stage: build_docker
  script:
    - echo 'creat_app'
    - cp -rf Dockerfile-AIO nginx-config.conf $ALL_ARTIFACTS_PATH
    - cd $ALL_ARTIFACTS_PATH
    - ls -l    
    - docker build -f Dockerfile-AIO -t web-aio:$CI_COMMIT_TAG .
    - docker tag web-aio:$CI_COMMIT_TAG $PUSH_IMAGE_PATH:$CI_COMMIT_TAG
    - docker login -u $HARBOR_USERNAME -p $HARBOR_PWD $HARBOR_SERVER
    - docker push $PUSH_IMAGE_PATH:$CI_COMMIT_TAG
    - docker rmi $PUSH_IMAGE_PATH:$CI_COMMIT_TAG
    - echo '构建aio镜像成功 镜像地址 $PUSH_IMAGE_PATH:$VERSION '
  after_script:
    - echo '$PUSH_IMAGE_PATH:$VERSION'
    - 'curl -H ''Content-type: application/json'' -d ''{"msgtype":"text", "text": {"content":"$PUSH_IMAGE_PATH:$VERSION"}}'' $DING_WEBHOOK'    
  when: on_success

到了这一步,所有的子应用构建物都已放到了 ALL_ARTIFACTS_PATH 中,只需要进入该目录构建docker镜像即可。
这些需要注意一下,镜像的 Dockerfile 与 nginx 配置文件可能要使用新建的。构建完成后,改成对应的版本号,推送到harbor中。harbor相关变量 以及镜像相关变量是定义在项目的 CI/CD变量中。

最后再编写一个处理流水线失败的job,,当流水线报错时,及时使用钉钉通知告知用户处理。这里注意
when: on_failure 当做之前的job有报错的,才会执行该job。

track_fail:
  extends: .release_aio_config
  stage: track
  variables:
    CONTENT: '@$GITLAB_USER_NAME构建aio镜像错误$CI_PIPELINE_URL'
    DING_WEBHOOK: 'https://oapi.dingtalk.com/robot/send?access_token=$DING_ACCESS_TOKEN'    
  script:
    - echo $CONTENT    
    - 'curl -H ''Content-type: application/json'' -d ''{"msgtype":"text", "text": {"content":"部署 $CONTENT"}}'' $DING_WEBHOOK'    
  when: on_failure

遇到的问题

安装gitlab-runner后,需要将用户gitlab-runner 加入到docker用户组中。

sudo usermod -aG docker gitlab-runner

git报错

fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly

![image.png](https://img-blog.csdnimg.cn/img_convert/09d8917be92db30b9259d2631e19845d.png#clientId=ub2a73473-83bc-4&from=paste&height=430&id=ue419c90e&margin=[object Object]&name=image.png&originHeight=430&originWidth=1188&originalType=binary&ratio=1&size=38458&status=done&style=none&taskId=uc077435e-31d5-46e3-a884-f551b1a6ab6&width=1188)
升级git版本即可解决。升级到 2.13

限定跨项目流水线

使用strategy: depend 来等待其他项目流水线运行完成。
使用branch 来限定触发子项目的那个分支流水线。

nginx 配置

原有的nginx配置无法使用,需要修改。aio方案的nginx配置为。

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    gzip on;
    gzip_buffers 32 4K;
    gzip_comp_level 6;
    gzip_min_length 100;
    gzip_types application/javascript text/css text/xml;
    gzip_disable "MSIE [1-6]\.";
    gzip_vary on;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }    

    error_page   500 502 503 504 404  /index.html;
    location = /index.html {
        root   /usr/share/nginx/html;
    }

}

特别注意 404 转发到index.html 这条规则。

tag转为版本号的处理

将tag中的 tags/tag_ 删除掉 如tag为 tags/tag_v2.7.x.20210908 ,镜像版本为 v2.7.x.20210908

${tags/tags\/tag_/}

部署完成后的网络拓扑图

在这里插入图片描述

http://topology.le5le.com/preview/?id=6143f2278672cb00018b9ff4&r=1

结语

吾山拔地三千尺,凌空耸翠一万年


点击全文阅读


本文链接:http://zhangshiyu.com/post/31858.html

流水线  镜像  触发  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1