4.8 KiB
tags, create time
| tags | create time | ||||
|---|---|---|---|---|---|
|
2026-05-27 19:30 |
部署策略深入
概述
深入分析 Slidev 项目的部署架构,包括 Docker-out-of-Docker 通信模式、Nginx 静态文件服务机制、以及 Pipeline 步骤间的依赖关系。
[!NOTE] 如需了解 Workflow YAML 逐块配置说明,详见 workflow-configuration。
正文
为什么需要 docker-cli?DooD vs SID
[!QUESTION] 思考:workflow 已经在
node:22-alpine容器里运行了,为什么还要装 Docker 相关工具?这不是"套娃"吗?
关键理解:你的命令在 container A(构建容器) 中执行,但你要操控的是 宿主机的 Docker daemon 来启动 container B(Nginx)。这是经典的 Docker-out-of-Docker (DooD) 模式。
flowchart LR
HOST["宿主机\nDocker Daemon"] <-->|通信| CLI["container A 中的\ndocker-cli 命令"]
CLI --> OP["docker run nginx → 新建 container B"]
style HOST fill:#e8f4fd
style CLI fill:#fff4e8
style OP fill:#e8ffe8
这比另一种方案 SID (Socket-In-Docker) 更安全:SID 直接把 /var/run/docker.sock 挂载进容器,等于给了 root 权限——攻击者一行代码就能逃逸到宿主机。而 DooD 通过独立的 docker-cli 通信,安全边界更清晰。
[!TIP] 想深入了解两种方案的完整对比?详见 Docker-in-Container 部署模式详解。
Nginx 作为静态文件服务器的运作方式
flowchart LR
REQ["浏览器请求 :8080/index.html"] --> NGINX["Nginx 监听端口 80\n(容器内映射到宿主机 8080)"]
NGINX --> FS["读取文件系统<br/>/usr/share/nginx/html/"]
FS --> FILES["HTML / CSS / JS / 图片<br/>(来自 dist/ 的构建产物)"]
FILES --> RESP["返回给浏览器渲染"]
style REQ fill:#e8f4fd
style RESP fill:#e8ffe8
核心机制其实非常简单——Nginx 不做任何处理,只是当个"搬运工":
| 概念 | 说明 |
|---|---|
| 为什么选 Nginx | 业界标准、极致轻量(alpine 版仅 ~4MB)、零配置开箱即用 |
| 为什么每次重建 | 无状态设计:删掉旧容器 = 彻底清除历史,避免残留配置或缓存问题 |
为什么用 docker cp |
cp dist/. nginx:/usr/share/nginx/html/ 把构建产物直接铺进容器的网页根目录 |
| 为什么不重启 Nginx | cp 操作不涉及进程热重载,Nginx 自动读最新文件 |
关键参数 -p 8080:80:容器内 Nginx 监听 80 端口,将其映射到宿主机的 8080。访客访问 http://服务器IP:8080 即可看到 slides。这里没有直接用 80 端口,是为了避免和宿主机上其他可能的 HTTP 服务冲突。
Workflow 步骤顺序:谁保证了执行的先后?
答案很直接:YAML 中 steps 的顺序就是执行顺序。Gitea Actions(与 GitHub Actions 一致)对每个 job 内的 steps 按从上到下 串行执行,且某一步失败后后续步骤自动跳过。
flowchart LR
S1[Install tools] --> S2[Checkout]
S2 --> S3[Install pnpm]
S3 --> S4[pnpm install]
S4 --> S5[Build]
S5 --> S6[Deploy]
S1 -.→|.git (代码可用)| S2
S2 -.→|pnpm CLI| S3
S3 -.→|node_modules/| S4
S4 -.→|dist/ 产物| S5
S5 -.→|dist/ 产物| S6
style S1 fill:#fff4e8
style S2 fill:#fff4e8
style S3 fill:#fff4e8
style S4 fill:#fff4e8
style S5 fill:#fff4e8
style S6 fill:#e8ffe8
每一步的输出自然成为下一步的输入——不需要额外的依赖声明,文件系统天然承载了这一步到那一步的数据传递。这正是 CI/CD pipeline "线性流水线"的设计哲学。
部署命令拆解
- name: Deploy to nginx
run: |
docker rm -f slides-nginx 2>/dev/null || true
docker run -d \
--name slides-nginx \
--restart unless-stopped \
-p 8080:80 \
nginx:alpine
docker cp dist/. slides-nginx:/usr/share/nginx/html/
这一阶段做了三件事:
- 清理旧容器 —
docker rm -f强制删除可能存在的同名容器,2>/dev/null || true确保不存在时不报错退出 - 启动新容器 — 基于
nginx:alpine镜像创建轻量级 web 服务器 - 复制构建产物 — 将
dist/下的内容拷贝到 Nginx 的默认网页目录/usr/share/nginx/html/
关键设计决策
| 决策 | 选择 | 理由 |
|---|---|---|
| 包管理器 | pnpm | 依赖安装速度快,磁盘占用小 |
| 容器基础镜像 | Alpine | 镜像仅几 MB,适合快速构建 |
| Web 服务器 | Nginx (每次重建) | 无状态、零配置,构建产物即静态文件 |
| 端口映射 | 8080:80 | 避免宿主机占用标准 HTTP 端口 80 |
关联笔记
- CICD 在 Slidev 中的应用
- workflow-configuration
- Docker-in-Container 部署模式详解