在 CI/CD 中怎么使用 Docker 部署前端项目?

本项目代码已开源,具体见:

前端工程:vue3-ts-blog-frontend

后端工程:express-blog-backend

数据库初始化脚本:关注公众号程序员白彬,回复关键字"博客数据库脚本",即可获取。

前言

在上一篇文章《前端不懂 Docker ?先用它换掉常规的 Vue 项目部署方式》中,我们学会了怎么使用 docker 制作镜像、推送镜像到 aliyun 私有镜像仓库,也学会了怎么在服务器上拉取最新的镜像进行容器部署。不过,这些都是过程式的命令,我们需要把这些过程提炼出来做成脚本,最终在 CI/CD 工具中直接使用,以实现全自动化的部署。具体怎么做呢?我们来看看!

现有 actions 分析

vue3-ts-blog-frontend 这个前端项目使用的是 github actions 实现自动化部署的,打开ci_cd.yml文件可以查看具体实现。

在引入 Docker 之前,我们的部署流程是这样的,一共分两个 job,第一个 job 是 build,第二个 job 是 deploy。总体来说做的事情是将打包好的 dist 传输到服务器上。

  • build 阶段会安装依赖和打包,也就是我们熟悉的 yarn 和 yarn build。
yaml 复制代码
- name: Install Dependency
  run: |
    yarn config set registry https://registry.npmmirror.com
    yarn

- name: Build
  run: yarn build
  • 接着上传打包好的 dist 资源,这要用到 actions/upload-artifact。
yaml 复制代码
- name: Archive production artifacts
  uses: actions/upload-artifact@v2
  with:
    #产物名称
    name: artifact
    #产物路径
    path: dist
  • 然后来到 deploy 阶段,首先要把刚才上传的文件下载下来,会用到 actions/download-artifact。(其实不拆分 job 也就不需要处理 artifact 了,不过也是为了学习下 artifact 的使用)
yaml 复制代码
- name: Download production artifacts
  uses: actions/download-artifact@v2
    with:
      name: artifact
      path: dist
  • 最后是与服务器建立 ssh 连接,将 dist 资源全部传输到 /usr/share/nginx/html 的项目目录下。
yaml 复制代码
- name: SSH Auth && Deploy To the Server
  run: |
    eval $(ssh-agent -s)
    echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    echo "PubkeyAcceptedKeyTypes +ssh-rsa" > ~/.ssh/config
    ssh-keyscan $SSH_HOST >> ~/.ssh/known_hosts
    chmod 644 ~/.ssh/known_hosts
    scp -r dist/* $SSH_USERNAME@$SSH_HOST:$DEPLOY_DIR

由于是 CI 模式,登录服务器的过程不能有人机交互,必须是全自动化的,这就需要用到免密 ssh 连接,也就会使用到密钥对,如果对这一块不清楚的,可以先看看我之前写的一篇文章《自动化部署的一小步,前端搬砖的一大步》。

具体传输文件就是用到了 scp 命令。

以上过程会涉及到一些私密信息,比如服务器 ip、用户名、私钥等,这些私密信息都可以用 github 的 secrets 维护。

改造思路

既然我们选择了使用 Docker 来部署前端,那 CI 脚本中主要就是对 Docker 的一些操作,可能就不会在 CI 脚本上看到 yarn 安装依赖和打包这种信息了,因为这些信息都被隐藏到 Dockerfile 里了。

所以在 CI 脚本中,大概要做的事情是:

  • 使用 docker build 打镜像。
  • 推送镜像到私有镜像仓库。
  • 登录服务器。
  • 拉取镜像。
  • 重启容器。

理清思路后,实现起来就会简单很多,我们顺着思路一步一步做就可以了。

打镜像

首先是使用 docker build 打镜像,并给出具体的 tag。

bash 复制代码
docker build -t ${{secrets.DOCKER_REGISTRY}}/${{secrets.DOCKER_NAMESPACE}}/${{secrets.DOCKER_REPOSITORY}}:${{github.ref_name}} .      

由于我们要把镜像推送到私有镜像仓库,所以镜像 tag 命名带上了 registry 的地址、命名空间、仓库名,版本号是以 git tag 为准,这些都以变量插值的形式体现在命令中。

推送镜像

我们的镜像是存储在 aliyun 私有镜像仓库中的,在 push 镜像之前,我们需要先登录。

ini 复制代码
docker login --username=${{secrets.DOCKER_USERNAME}} --password=${{secrets.DOCKER_PASSWORD}} ${{secrets.DOCKER_REGISTRY}}

接着使用 docker push 推送镜像。

bash 复制代码
docker push ${{secrets.DOCKER_REGISTRY}}/${{secrets.DOCKER_NAMESPACE}}/${{secrets.DOCKER_REPOSITORY}}:${{github.ref_name}}

登录服务器

打镜像和推送镜像在 runner 中执行即可,但是拉取镜像部署这一步必须要在自己的服务器上执行,所以我们要先登录自己的服务器。

bash 复制代码
mkdir -p ~/.ssh

echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa

chmod 600 ~/.ssh/id_rsa

cat >>~/.ssh/config <<END
Host remote
HostName ${{secrets.SSH_HOST}}
Port 22
User ${{secrets.SSH_USERNAME}}
IdentityFile ~/.ssh/id_rsa
StrictHostKeyChecking no
END

ssh remote

登录服务器之后,我们需要执行登录 aliyun registry、拉取镜像、重启容器等操作。我们可以把这些步骤整合到一个脚本 remote.sh 中,然后一并传输给 ssh 命令执行。

ruby 复制代码
cat >>~/remote.sh <<END
docker ps
docker login --username=${{secrets.DOCKER_USERNAME}} --password=${{secrets.DOCKER_PASSWORD}} ${{secrets.DOCKER_REGISTRY}}
docker pull ${{secrets.DOCKER_REGISTRY}}/${{secrets.DOCKER_NAMESPACE}}/${{secrets.DOCKER_REPOSITORY}}:${{github.ref_name}}
docker stop ${{secrets.DOCKER_CONTAINER_NAME}}
docker rm ${{secrets.DOCKER_CONTAINER_NAME}}
docker run -dp ${{secrets.HOST_PORT}}:${{secrets.CONTAINER_PORT}} --name ${{secrets.DOCKER_CONTAINER_NAME}} ${{secrets.DOCKER_REGISTRY}}/${{secrets.DOCKER_NAMESPACE}}/${{secrets.DOCKER_REPOSITORY}}:${{github.ref_name}}
END

ssh remote < ~/remote.sh

完整的配置文件可以前往底部源码查看。

小结

使用 CI/CD 进行自动化部署与我们在本地执行一条条命令去部署在本质上没有多少区别,关键是把我们整理的命令合理地嵌入到 CI/CD 流程中,这需要我们比较熟悉 CI/CD 平台约定的 yaml 配置语法。各家平台提供的配置语法大同小异,关键概念可能也只是换了一个名字,学会了一个,使用其他的平台也不会很难,当然这个过程需要很多耐心,试错,纠正,反复,最后取得成功!

相关推荐
熊的猫7 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn14 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
追梦不止~26 分钟前
Docker常用命令+详解
运维·docker·容器
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust2 小时前
css:基础
前端·css
帅帅哥的兜兜2 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园2 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称2 小时前
购物车-多元素组合动画css
前端·css