基于docker镜像部署博客
之前我对docker的使用的认知仅仅停留在docker pull和docker run的阶段,没有试过基于docker镜像的发布流程。举个例子,我部署博客使用了github action进行自动化发版,虽然也使用了docker,但是其实本质和传统的部署流程一般无二(将产物通过ssh传输到docker内nginx在宿主机上挂载的静态资源文件夹中)。当然,这种方式能用,但是并不是很好。因为只有一台nginx,当项目多了的情况下就会出现一些不方便的情况(比如部署到二级目录等)。于是我决定将部署流程改为基于docker镜像的发布流程。
打包前端镜像
在构建前端镜像前,需要编写dockerfile。我们在前端项目的根目录新建一个dockerfile,文件内容大致如下:
FROM node:lts-alpine as builder
WORKDIR /
COPY . /
RUN npm install pnpm@6.32.6 -g && pnpm i && pnpm run docs:build
FROM nginx:alpine
LABEL maintainer="KiraZz1 <1025658492@qq.com>"
COPY --from=builder /docs/.vuepress/dist/ /usr/share/nginx/html/
EXPOSE 80值得一提的是,上面采用了多阶段构建,所以最终产出镜像的体积并不包含node的runtime,大小实际上只比nginx:alpine镜像略大一点。
其运行过程也很简单,把工作区里面的文件拷贝到node镜像里面进行打包,然后把打包的产物挪到下一阶段使用的nginx镜像中的静态资源文件夹中。
不过工作区内还有一些与构建无关的文件夹比如node_modules,如果把这玩意copy到镜像里,速度是很慢的。所以我们还需要新建一个.dockerignore文件(其格式和.gitignore没啥区别),下面是我自己项目中的.dockerignore:
node_modules/
.vscode
# VuePress files
docs/.vuepress/.temp/
docs/.vuepress/.cache/
docs/.vuepress/dist/
# MacOS Desktop Services Store
.DS_Store可以在工作区根目录下执行docker build -t vuepress-blog:latest .来测试构建镜像的结果。
新建镜像仓库
首先是关于镜像仓库的问题,由于本人比较穷,买不起好的机器用于搭建devops的基础设施比如harbor私有镜像仓库。一开始我打算放弃这个方案,然后采用用ssh直接把项目文件传到宿主机上打包镜像并且运行。不过我发现了阿里云里面镜像仓库的个人版似乎是不要钱的,不要钱的自然是好的,嘿嘿。
在阿里云的控制台进入容器镜像服务模块:

创建个人实例并进入下一界面(创建个人实例的时候会让设置密码,后面要用到),点击镜像仓库,然后点击创建镜像仓库按钮:

弹出如下界面:

填完信息后点击下一步:

选择本地仓库点确认即可。在新建的仓库内会有操作指南,告诉你应该怎样去发布镜像和拉取镜像。下面是操作指南的界面:

修改Github Action配置
我们需要修改在项目根目录中的.github/workflows的yml配置,以实现自动化打包镜像、推送镜像、宿主机拉取镜像并运行等步骤。我的yml文件大致如下:
name: github pages
on:
push:
branches:
- master # push 到 main 分支时触发 jobs
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
with:
persist-credentials: false
# checkout到你的hexo代码分支
ref: master
# hexo需要加载内部子模块
submodules: true
- name: Build docker image
run: |
docker build -t xxx:latest .
docker login --username=${{ secrets.DOCKER_USERNAME }} registry.cn-hangzhou.aliyuncs.com --password=${{ secrets.DOCKER_PASSWORD }}
docker tag xxx registry.cn-hangzhou.aliyuncs.com/xxx/xxx:latest
docker push registry.cn-hangzhou.aliyuncs.com/xxx/xxx:latest
# 将静态页面部署至 ECS
- name: Deploy image
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }} # ECS 域名 或 IP 地址
username: ${{ secrets.SSH_USERNAME }} # 登录用户名
password: ${{ secrets.SSH_PASSWORD }} # 登录密码
script: |
docker rm -f xxx
docker image rm registry.cn-hangzhou.aliyuncs.com/xxx/xxx
docker pull registry.cn-hangzhou.aliyuncs.com/xxx/xxx
docker run -d --name xxx -p 8083:80 registry.cn-hangzhou.aliyuncs.com/xxx/xxx:latest分析一下上面的命令构成:
在
Build docker image阶段,我们需要登陆镜像仓库,命令大致如下:docker login --username=${{ secrets.DOCKER_USERNAME }} \ registry.cn-hangzhou.aliyuncs.com \ --password=${{ secrets.DOCKER_PASSWORD }}这里的
DOCKER_USERNAME和DOCKER_PASSWORD是我们登陆镜像仓库的账号和密码(账号可以到镜像仓库的操作指南去看,密码在创建个人版实例的时候会让我们设置),我们需要把这两项设置进仓库的secret变量中:
将镜像打上标签推送到仓库的命令如下:
docker tag xxx registry.cn-hangzhou.aliyuncs.com/命名空间/镜像名:latest docker push registry.cn-hangzhou.aliyuncs.com/命名空间/镜像名:latest注意
registry.cn-hangzhou.aliyuncs.com/命名空间部分的信息要和新建完镜像仓库后操作指南中提供的一致。在宿主机上部署之前,要移除掉同名的容器和镜像:
docker rm -f xxx docker image rm registry.cn-hangzhou.aliyuncs.com/xxx/xxx
全局nginx反向代理
因为我的网站入流量都是走的nginx,而我部署的应用在8083端口,所以需要进行反向代理。配置文件的片段大致如下:
location / {
rewrite ^/(.*?)$ /$1 break;
proxy_pass http://宿主机ip:8083/;
}对应服务器的安全组端口要放开。
提交代码
上面的步骤做完之后,可以把新增的代码(dockerfile、.dockerignore、.github/workflows)提交到github测试下:

访问网站也是能正常访问的。
