「部署认知」一、前端转全栈必会的 Docker + CI/CD 20% 核心

2301 字
12 分钟
「部署认知」一、前端转全栈必会的 Docker + CI/CD 20% 核心

📌 系列简介:《my-resume AI实战》部署过渡篇,共三篇。 本篇:建立最小部署认知 / 下一篇:真实踩坑复盘 / 第三篇:联调稳定化到 AI 实战 前端转 JS 全栈,正在学部署,理解难免有偏差,欢迎批评指正 ~


写在前面#

两年前掘金写了篇博客 学习TailWindCSS顺便打造个性化在线简历项目 当时也有朋友问怎么没做CICD ~

当时的心路历程,1是麻烦,2是不会… https nginx 把这些折腾上去都够呛,不想学新的了 ……

AI时代,再停留真要被落下了,那么就让AI带着自己一起跑吧。高速路我选择60 = =

好的,又要扯偏了,真正让我卡住的,同样是用 借助AI,把自己的学习历程也发出来

不是 Docker 难,而是三个边界没分清:构建、运行、数据。

这篇想把我理清楚这三个边界的过程写下来——

不是完整的 Docker 教程,是前端转全栈阶段,真正用得上的那 20%。


一、先把概念对齐:最容易混的 6 组#

学 Docker 最痛苦的阶段,是概念还没对齐就开始操作—— 报错了不知道是哪一层的问题,改了半天改错了地方。

我整理了最容易混的 6 组,先对齐再往下走:

容易混淆正确认知
Image vs ContainerImage 是封箱好的运行包;Container 是它跑起来的实例。镜像像类,容器像对象。
Registry / Repository / TagRegistry 是仓库服务(比如 GHCR);Repository 是镜像名空间;Tag 是具体版本指针。
ARG vs ENVARG 只在构建期有效;ENV 会进入运行时容器,服务启动后还在。
EXPOSE vs portsEXPOSE 只是声明,不对外开放;真正映射端口靠 Compose 的 ports 字段。
Volume vs Bind MountVolume 更适合生产持久化;Bind Mount 更适合本地开发联调。
Build vs Run构建阶段解决”产物一致性”;运行阶段解决”实例可用性与配置注入”。

把这 6 组搞清楚,排障时至少知道问题出在哪一层。


二、为什么”上线后就能运行”?#

搞清楚概念之后,我才真正理解了一件事——

上线的不是源码,是可运行工件。

在 Docker 路线里,这个工件是镜像(Image):包含代码、运行环境(Node、依赖、系统库)、启动命令。

服务器只做两件事:拉镜像 + 启容器

这就是”发布成功即可运行”的基础。 也是为什么换了服务器、换了机器,只要能拉到镜像,服务就能跑起来。


三、从代码到用户访问:一条链路#

flowchart LR A[代码提交] --> B[CI校验: test/typecheck/build] B --> C[构建镜像] C --> D[推送GHCR] D --> E[ECS release.sh] E --> F[docker compose pull + up] F --> G[Nginx反向代理] G --> H[用户访问域名]

这条链路的关键是:构建和运行分离。

  • 构建在 CI 完成:有算力、有缓存、可重试,产物一致
  • 运行在 ECS 完成:尽量轻量,只负责拉起服务

我之前习惯”SSH 上服务器直接跑”,后来发现这样有两个问题: 本地环境和服务器环境不一致,出了问题很难复现; 而且没有版本记录,出事了不知道回滚到哪里。

CI 构建镜像解决的就是这两个问题。


四、Dockerfile:真正需要懂的 7 件事#

Dockerfile 定义镜像怎么构建。我用得最多的就这 7 个指令:

FROM node:22-slim # 基础镜像
WORKDIR /app # 工作目录
COPY package*.json ./ # 先复制依赖文件(利用缓存)
RUN npm ci # 安装依赖
COPY . . # 再复制业务代码
ARG BUILD_ENV # 构建时参数(只在 build 阶段)
ENV NODE_ENV=production # 运行时环境变量(保留到容器)
CMD ["node", "dist/main.js"] # 启动命令

缓存层的顺序很重要#

Dockerfile 每条指令都是一层,前面的层变了,后面的缓存全部失效。

我踩过的坑:把 COPY . . 放在 RUN npm ci 前面—— 每次改一行业务代码,依赖就重新安装一遍,构建时间从 30 秒变成 3 分钟。

正确做法:先复制 package.json,装完依赖,再复制业务代码。 依赖没变,那一层缓存就命中,只有业务代码那层重新构建。

多阶段构建:让镜像更小#

# 第一阶段:构建
FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 第二阶段:运行(只复制必要产物)
FROM node:22-slim AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/main.js"]

Builder 阶段的编译缓存、devDependencies,全部不进最终镜像。 对小规格 ECS 来说,镜像越小,拉取越快,发布越稳。 我的服务镜像从 1.2GB 压到了 380MB,就靠这一步。


五、Compose:多服务的”启动说明书”#

my-resume 有三个服务:web(用户端)、admin(后台)、server(API)。 Compose 让这三个服务按规则一起跑。

最关键的字段:

services:
server:
image: ghcr.io/my-org/server:v2.2.0 # 用哪个镜像
ports:
- "3000:3000" # 端口映射
env_file:
- .env.production # 运行时配置
volumes:
- resume_data:/app/data # 持久化存储
depends_on:
- db # 启动顺序依赖
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
retries: 3

有一个我之前理解错的地方:

depends_on 只保证容器启动顺序,不保证服务真的可用。

数据库容器启动了,不代表数据库已经接受连接了。 要配合 healthcheck 和应用层重试,才能真正保证依赖可用。


六、线上稳定性的最小闭环#

跑通部署之后,我意识到还差三件事:知道服务活没活、出问题能看日志、出问题能回滚。

健康检查#

健康检查要检查业务端点,不只是进程存不存在。

进程活着不代表服务可用——我遇到过进程在但数据库连接断了, 外面看着”绿色”,实际上所有请求都在报错。

GET /api/health 里加上数据库连通性检查,才是真正的健康检查。

日志#

出了问题,先看容器日志:

Terminal window
docker compose logs -f server

大多数问题——环境变量缺失、数据库连接失败、端口冲突——日志里都有。 先看日志,再看源码,别一上来就改代码。

回滚#

镜像 tag 要用可追溯的版本号,不要只用 latest

Terminal window
# 推荐
ghcr.io/my-org/server:v2.2.0
ghcr.io/my-org/server:v2.2.0-a3f8c1d
# 不推荐
ghcr.io/my-org/server:latest # 出了问题不知道回滚到哪

回滚就是把 Compose 里的 tag 改回旧版本,重启服务。 不需要重新排查编译环境,不需要重新部署代码——切版本,就完了。


七、CI/CD 在干嘛#

可以把它理解成三段流水线:

1. CI 检查 代码合格(测试、类型检查、构建验证)
2. Build 构建镜像,push 到 GHCR,打上版本 tag
3. CD 部署 ECS 拉指定 tag,docker compose up

比”SSH 上服务器手动构建”稳的原因:

  • 构建环境一致,不会出现”我本地好的”
  • 每个版本有 tag,可追溯
  • 出问题可以快速切回旧 tag

八、常用命令:够用就行#

查看状态#

Terminal window
docker ps # 看运行中的容器
docker images # 看本地镜像
docker compose ps # 看 compose 服务状态
docker compose logs -f # 实时看日志

部署操作#

Terminal window
docker compose pull # 拉最新镜像
docker compose up -d --no-build # 启动(不重新构建)
docker compose down # 停止并删除容器

排障#

Terminal window
docker inspect <container> # 看容器详细配置
docker exec -it <container> sh # 进容器排查
curl -i http://127.0.0.1:<port> # 测试服务是否可达

九、这阶段该学多深?#

我的判断:先学”能跑通 + 能排障”,不要一次学太深。

现在要会的:

  • 写/读 Dockerfile,理解缓存层顺序
  • 读懂 Compose 核心字段
  • 看日志、看健康检查
  • 跑通 CI 构建镜像 + ECS 拉镜像部署
  • 用 tag 做回滚

可以后置的:

  • 内核细节(cgroups / namespace / overlayfs)
  • 大规模集群调度
  • 复杂网络与安全策略

不是这些不重要,是当前阶段投入产出比不高。 把能跑通、能排障做扎实,比看完整本书更有用。


写在最后#

做完这套部署之后,我对”部署”这件事的理解变了——

它不是神秘的运维操作,是工程化的延伸: 把可运行工件,稳定地、可追溯地、可回滚地送到线上。

前端做工程化,讲的是构建产物的一致性和可维护性。 Docker + CI/CD 做的是同一件事,只是把边界从”浏览器能跑”扩展到了”服务器能跑”。

想清楚这一点之后,Docker 就没那么陌生了。


参考文档#


昇哥 · 2026年4月 my-resume 部署上线途中,把想清楚的事写下来


下一篇,我会把这次部署真实踩过的坑写出来—— Node 版本不统一、GHCR token 权限、buildx 网络超时…… 每一个坑背后,都有一个值得记下来的判断。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

「部署认知」一、前端转全栈必会的 Docker + CI/CD 20% 核心
https://blog.fridolph.top/posts/2026-04-13__pre-prj-1/
作者
Fridolph
发布于
2026-04-17
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Fridolph
热爱 Coding、音乐和羽毛球的 90 后全栈工程师
公告
欢迎访问我的小站 ^_^ 我是昇哥,热爱Coding,喜爱音乐、羽毛球和摄影的 90后全栈工程师
分类
标签

文章目录