跳转至

GitHub Actions 在自托管 Runner 部署 Docker Nginx

目标

这个博客是纯 MkDocs 静态站点,部署架构调整为 Docker 运行 Nginx 容器,由 Nginx 直接托管构建后的 site/ 静态文件。

GitHub Actions Runner 部署在同一台生产服务器上,所以不需要推送镜像到远程仓库,也不需要 SSH 到另一台服务器。workflow 会直接在 runner 服务器本地构建镜像并重启容器。

当前链路是:

git push origin main
  -> GitHub Actions 触发
  -> 自托管 runner 拉取代码
  -> docker compose up -d --build
  -> Dockerfile 多阶段构建
  -> mkdocs build --clean
  -> 将 site/ 复制进 Nginx 镜像
  -> 在本机重启 Nginx 容器

访问请求会直接进入 Nginx 容器,不再依赖腾讯云 COS 静态网站托管。

仓库关键文件

  • .github/workflows/deploy-docker-nginx.yml
  • Dockerfile
  • nginx/default.conf
  • docker-compose.yml
  • requirements.txt
  • mkdocs.yml
  • scripts/preview.sh
  • scripts/preview.ps1

其中 workflow 负责在自托管 runner 上直接执行 compose 部署。Dockerfile 负责在镜像内构建静态站点,nginx/default.conf 负责静态文件服务与缓存策略。

本地构建镜像

docker build -t frank-blog:latest .

本地运行容器

docker run -d --name frank-blog --restart unless-stopped -p 8080:80 frank-blog:latest

访问:

http://127.0.0.1:8080

也可以使用 compose:

docker compose up -d --build

服务器部署

服务器同时承担 GitHub Actions self-hosted runner 和 Docker 容器运行环境。runner 用户需要能执行 Docker 命令。

docker ps
docker compose version

如果 runner 使用 frank 用户运行,推荐把 frank 加入 docker 组:

sudo usermod -aG docker frank

然后重启 GitHub Actions runner 服务,或者退出并重新登录 frank 用户,让新的组权限生效:

id frank
sudo systemctl restart actions.runner.*  # 如果 runner 是 systemd 服务

临时方案是给 Docker 命令配置免密 sudo。workflow 已经支持自动尝试 sudo -n docker,但长期更建议使用 docker 组权限。

Runner Systemd 服务

仓库提供了一个 systemd unit 模板:

deploy/actions-runner.service

按当前服务器路径 /opt/actions-runner 和运行用户 frank 安装:

sudo cp deploy/actions-runner.service /etc/systemd/system/actions-runner.service
sudo systemctl daemon-reload
sudo systemctl enable actions-runner
sudo systemctl start actions-runner

如果之前用 nohup ./run.sh 启动过 runner,先停止旧进程:

ps -ef | grep -E 'actions-runner|Runner.Listener|run.sh' | grep -v grep
sudo kill <pid>

查看状态和日志:

sudo systemctl status actions-runner
sudo journalctl -u actions-runner -f

确认 frank 的 Docker 权限生效:

sudo -iu frank
id
docker ps

部署命令由 workflow 执行:

DEPLOY_CONTAINER_PORTS=80:80 docker compose up -d --build --remove-orphans

如果服务器上还有一层宿主机 Nginx、SLB 或 CDN,可以把端口映射为本机内网端口:

DEPLOY_CONTAINER_PORTS=127.0.0.1:8080:80 docker compose up -d --build --remove-orphans

然后由外层入口转发到 127.0.0.1:8080

GitHub Variables

进入仓库:

Settings -> Secrets and variables -> Actions -> Variables

可选添加:

  • DEPLOY_CONTAINER_PORTS:容器端口映射,默认 80:80
  • PIP_INDEX_URL:Docker 构建阶段使用的 Python 包镜像源,默认 https://mirrors.cloud.tencent.com/pypi/simple
  • PIP_TRUSTED_HOST:pip 镜像源 trusted host,默认 mirrors.cloud.tencent.com

GitHub Actions

push 到 main 后,GitHub Actions 会自动执行:

  1. checkout 仓库
  2. 检查 runner 上的 Docker 与 compose
  3. 执行 docker compose up -d --build --remove-orphans
  4. 访问 127.0.0.1 验证容器本地可用

本地预览

开发写文档时仍然可以直接使用 MkDocs 预览。

Linux/macOS:

bash scripts/preview.sh

Windows:

powershell -ExecutionPolicy Bypass -File scripts/preview.ps1

预览地址:

http://127.0.0.1:8000

注意事项

  • docs/private/ 只是内容目录名,构建后仍然是公开静态页面。
  • 不要把真正敏感的内部资料放进仓库或导航里。
  • 如果前面接 CDN,发版后可能需要刷新 CDN 缓存。
  • 生产 HTTPS 可以放在外层负载均衡、CDN 或宿主机 Nginx 上终止,容器内保持 HTTP 即可。
  • 如果服务器上已经有别的服务占用 80 端口,可以把 GitHub Variables 里的 DEPLOY_CONTAINER_PORTS 设置为 127.0.0.1:8080:80,再由外层 Nginx 转发。
  • 如果 Action 提示无法访问 /var/run/docker.sock,说明 runner 用户没有 Docker 权限,需要把 runner 用户加入 docker 组并重启 runner。
  • 如果 Action 在 pip install 阶段出现 PyPI 下载超时,优先确认 workflow 的 PIP_INDEX_URL 是否指向国内镜像源。当前默认使用腾讯云 PyPI 镜像,也可以在 GitHub Variables 中改成其他可访问的源。