前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端微服务架构下CI/CD构建单镜像落地方案

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

作者头像
拿我格子衫来
发布2022-01-24 14:58:42
6500
发布2022-01-24 14:58:42
举报
文章被收录于专栏:TopFETopFE

前言

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

方案探索

部署文件目录

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

代码语言:javascript
复制
└── 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配置文件

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

代码语言:javascript
复制
└── 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来发布研发和集成环境,之前的流水线触发条件是

代码语言:javascript
复制
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示例

代码语言:javascript
复制
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 用于存放所有应用编译出的制品

代码语言:javascript
复制
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时触发。 ​

定义模板

代码语言:javascript
复制
# 默认配置模板
.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

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

代码语言:javascript
复制
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时触发 ​

编译子应用的作业

代码语言:javascript
复制
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,并使用钉钉通知将构建出的镜像推送给钉钉群。

代码语言:javascript
复制
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。

代码语言:javascript
复制
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用户组中。

代码语言:javascript
复制
sudo usermod -aG docker gitlab-runner

git报错

代码语言:javascript
复制
fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly

(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配置为。

代码语言:javascript
复制
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

代码语言:javascript
复制
${tags/tags\/tag_/}

部署完成后的网络拓扑图

在这里插入图片描述
在这里插入图片描述

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

结语

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 方案探索
    • 部署文件目录
      • GitLab CI/CD方案
      • 流水线编写
        • 首先定义流水线的阶段,变量与缓存。
          • 定义模板
            • 预编译作业,与主应用的编译作业
              • 编译子应用的作业
              • 遇到的问题
                • 安装gitlab-runner后,需要将用户gitlab-runner 加入到docker用户组中。
                  • git报错
                    • 限定跨项目流水线
                      • nginx 配置
                        • tag转为版本号的处理
                        • 部署完成后的网络拓扑图
                        • 结语
                        相关产品与服务
                        容器镜像服务
                        容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档