使用容器执行自动化任务
使用容器执行自动化任务
九月份博客版本更新时,升级了 Vuepress 版本导致对 NodeJS 版本要求提高了,为此不得不去升级主机的 NodeJS。曾经提到过把博客的自动编译工作放在容器里执行,文档编译相关的依赖从主机转移到了容器。不同的 Node 版本,使用不同容器即可,不需要在主机中安装多个版本的 NodeJS 或被迫限制在某个固定的版本。
注册并运行 act_runner 容器
这篇 文章里提到过如何在主机环境中注册 act_runner 并使用 Gitea Actions 自动部署博客,现在需要将这些行为搬到 Docker 容器中完成。
官方帮助文档中包含使用容器注册并运行 act_runner 的方式与方法。可以直接使用 docker 命令运行,也可以使用 Docker Compose。
直接使用 docker 运行:
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/data:/data \
-v /var/run/docker.sock:/var/run/docker.sock \
-e CONFIG_FILE=/config.yaml \
-e GITEA_INSTANCE_URL=<instance_url> \
-e GITEA_RUNNER_REGISTRATION_TOKEN=<registration_token> \
-e GITEA_RUNNER_NAME=<runner_name> \
-e GITEA_RUNNER_LABELS=<runner_labels> \
--name my_runner \
-d gitea/act_runner:nightlyDocker Compose :
version: "3.8"
services:
runner:
image: gitea/act_runner:nightly
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: "${INSTANCE_URL}"
GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
GITEA_RUNNER_NAME: "${RUNNER_NAME}"
GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"
volumes:
- ./config.yaml:/config.yaml
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sockdocker compose up不同于在主机中直接运行 act_runner ,使用容器的方式会将注册与运行动作合并为一步。
创建 action-runner-helper 仓库
为了方便后续重复部署,把 Docker Compose 部署方式相关文件放到了 Git 仓库里。将文件版本化之后,方便将来审查与问题追溯。
添加 config.yaml
# For more details on configuration options, refer to:
# https://gitea.com/gitea/act_runner/src/branch/main/internal/pkg/config/config.example.yaml
#
log:
level: info
runner:
file: .runner
capacity: 1
env_file: .env
timeout: 3h
shutdown_timeout: 0s
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
github_mirror: ''
labels:
- "ubuntu-22.04:docker://ubuntu:22.04"
- "node-jod:docker://node:jod-bookworm"
cache:
enabled: true
dir: ""
host: ""
port: 0
external_server: ""
container:
network: ""
privileged: false
options: "--add-host=host.docker.internal:host-gateway"
workdir_parent:
valid_volumes: []
docker_host: ""
force_pull: true
force_rebuild: false
require_docker: false
docker_timeout: 0s
host:
workdir_parent:添加 docker-compose.yml
services:
act_runner:
image: gitea/act_runner:nightly
restart: unless-stopped
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: "${INSTANCE_URL}"
GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
GITEA_RUNNER_NAME: "${RUNNER_NAME}"
GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"
volumes:
- ./config.yaml:/config.yaml
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sock添加 .env
INSTANCE_URL=https://gitea.mtfh.cc
REGISTRATION_TOKEN=<your_registration_token>
RUNNER_NAME=gitea-runner
RUNNER_LABELS=linux-amd64:host启动容器
# 启动容器
# 修改了配置文件或容器参数等等
docker compose up -d
# 结束容器
docker compose down最后,完整代码参考 action-runner-helper。
原本让 AI 帮忙写了个脚本,用来辅助用户录入容器注册时所需的参数信息,不过后来发现多余了。
Docker Compose 会默认从 .env 文件中读取变量值并赋给 YAML 中对应的变量,并不会读取 SHELL 临时变量。既然能直接从 .env 里获取参数,那直接改 .env 文件就好了,再整个脚本就有点多此一举了。
测试工作流
添加环境测试工作流,检查工具版本问题。主要用于检测 Vuepress 编译时所需要的工具依赖,包括 NodeJS、Yarn 和 Git。
name: Check Env
run-name: ${{ gitea.actor }}
on:
workflow_dispatch:
jobs:
check-env:
runs-on: node-jod
steps:
- name: Checkout repository
uses: https://gitea.com/actions/checkout@v4
- name: Check Node.js version
run: node -v
- name: Check Git version
run: git --version
- name: Check Yarn version
run: |
if ! command -v yarn >/dev/null 2>&1; then
echo "Yarn not found, installing..."
npm install -g yarn
fi
yarn -v这时候如果有缺少依赖或版本不匹配问题,可以提前发现。比如说需要激活新版本的 Yarn。
分别执行文档编译工作流与子模块合并工作流
更新工作流
添加手动触发工作流的方式;工作流的执行标签使用 node-jod —— 基于 Debian 的 node-22.04 容器;编译文档前激活新版本的 Yarn。
工作流修改后大致内容如下:
name: Build Docs
run-name: ${{ gitea.actor }}
on:
push:
branches:
- main
workflow_dispatch:
jobs:
Build-Docs-and-Deploy-It:
runs-on: node-jod
steps:
- name: Check out code
uses: https://gitea.com/actions/checkout@v4
with:
fetch-depth: 0
ssh-key: ${{ secrets.DEPLOYKEY }}
ssh-known-hosts: ${{secrets.SSH_KNOWN_HOSTS}}
submodules: true
- name: Setup and build docs # 两次 Build 是为了生成文章分类信息
run: |
corepack enable
yarn install
yarn docs:build
yarn docs:build自动更新子模块方面,相对于之前版本单独初始化子模块,这里在检出仓库时连带子仓库一并初始化了——能借助 actions/checkout@v4 自动设置认证信息。
name: Sync Submodules
run-name: ${{ gitea.actor }}
on:
workflow_dispatch:
jobs:
update-submodules:
runs-on: node-jod
steps:
- name: Checkout repo
uses: https://gitea.com/actions/checkout@v4
with:
ssh-key: ${{ secrets.DEPLOYKEY }}
ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
submodules: recursive
- name: Update submodules
run: | # 拉取子模块主分支后,再合并
git -C src/posts fetch origin main
git -C src/posts checkout main
- name: Commit update
run: |
git config user.name "${{ vars.USER_NAME }}"
git config user.email "${{ vars.USER_EMAIL }}"
git add .
if ! git diff --cached --quiet; then
git commit -m "$(git -C src/posts log -1 --pretty=format:"%s")"
git push origin HEAD
else
echo "No submodule updates"
fi容器内的文档(博客)部署问题
如果不添加文件映射的话,容器内的文件是没法直接拷贝到宿主机的。解决这一问题的方式有很多。可以添加目录映射(逻辑卷);上传文档,再使用上传的文档创建一个 Web 容器,然后让 Nginx 作反向代理;还可以使用 SCP 发送文件到宿主机。
当前博客的部署方式是结合 Nginx 一起考虑的。博客项目包含文章的编辑与发布,博客本身的改版,最后统一输出的是一组静态文件——即项目目录
./src/.vuepress/dist里的内容。至此「软件」的开发部分完成了,下面讨论部署与分发。因为「博客软件」是网页应用的形式呈现的,部署成功也就完成了应用的分发。
Nginx 把网站发布出去的步骤包括但不限于 Nginx 配置、域名配置和防火墙配置等。
使用 SCP 部署文档
其实 Github 有现成的 Actions 插件,不过由于某些因素下载不了或者特别慢。就只能让 AI 帮我生成一段配置了。
name: Build Docs
run-name: ${{ gitea.actor }}
on:
push:
branches:
- main
workflow_dispatch:
jobs:
Build-Docs-and-Deploy-It:
runs-on: node-jod
steps:
# 省略的步骤
- name: Install sshpass (with CN mirror)
run: |
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
apt-get update && apt-get install -y sshpass
- name: Deploy via scp (password)
run: |
ssh-keyscan -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts
sshpass -p "${{ secrets.PASSWORD }}" scp \
-o StrictHostKeyChecking=no \
-r ./src/.vuepress/dist/* \
${{ secrets.USERNAME }}@${{ secrets.HOST }}:/var/www/html由于 SCP 拷贝文件需要远程主机的地址,所以在运行 act_runner 容器时,配置文件里需要有以下配置,来保证执行工作流的容器能够访问宿主机,而不是 act_runner 容器。
container:
options: "--add-host=host.docker.internal:host-gateway"另外在 Gitea 仓库配置中添加上相应的变量,secrets.HOST 变量值使用 host.docker.internal 即可。
