126 lines
4.8 KiB
Markdown
126 lines
4.8 KiB
Markdown
|
|
---
|
|||
|
|
tags:
|
|||
|
|
- CI/CD
|
|||
|
|
- Docker
|
|||
|
|
- Nginx
|
|||
|
|
- 部署策略
|
|||
|
|
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)** 模式。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
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 作为静态文件服务器的运作方式
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
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 按从上到下 **串行执行**,且某一步失败后后续步骤自动跳过。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
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 "线性流水线"的设计哲学。
|
|||
|
|
|
|||
|
|
### 部署命令拆解
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
- 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/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这一阶段做了三件事:
|
|||
|
|
|
|||
|
|
1. **清理旧容器** — `docker rm -f` 强制删除可能存在的同名容器,`2>/dev/null || true` 确保不存在时不报错退出
|
|||
|
|
2. **启动新容器** — 基于 `nginx:alpine` 镜像创建轻量级 web 服务器
|
|||
|
|
3. **复制构建产物** — 将 `dist/` 下的内容拷贝到 Nginx 的默认网页目录 `/usr/share/nginx/html/`
|
|||
|
|
|
|||
|
|
### 关键设计决策
|
|||
|
|
|
|||
|
|
| 决策 | 选择 | 理由 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 包管理器 | pnpm | 依赖安装速度快,磁盘占用小 |
|
|||
|
|
| 容器基础镜像 | Alpine | 镜像仅几 MB,适合快速构建 |
|
|||
|
|
| Web 服务器 | Nginx (每次重建) | 无状态、零配置,构建产物即静态文件 |
|
|||
|
|
| 端口映射 | 8080:80 | 避免宿主机占用标准 HTTP 端口 80 |
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
|
|||
|
|
- [[CICD 在 Slidev 中的应用]]
|
|||
|
|
- [[workflow-configuration]]
|
|||
|
|
- [[Docker-in-Container 部署模式详解]]
|