本项目代码已开源,具体见:
后端工程: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 配置语法。各家平台提供的配置语法大同小异,关键概念可能也只是换了一个名字,学会了一个,使用其他的平台也不会很难,当然这个过程需要很多耐心,试错,纠正,反复,最后取得成功!
- 开源地址:vue3-ts-blog-frontend
- 专栏导航:Vue3+TS+Node打造个人博客(总览篇)