为什么要容器化

同一套代码在开发机跑得好好的,上线后环境不一样就出问题,这是后端最熟悉的痛。容器把应用连同运行环境一起打包成标准制品,镜像到哪都能跑,部署从折腾环境变成简单替换镜像。Docker 是容器化的事实标准,配合编排工具还能实现弹性伸缩与滚动发布。

本文核心知识点
  • 镜像应用加环境的只读模板。
  • 容器镜像运行起来的实例。
  • 卷把数据持久化到容器外。
  • Compose用声明文件编排多服务。
容器化部署配图:蓝色渐变背景下方一排整齐集装箱方块,顶部中央调度手柄方块,右侧一个集装箱被吊起,扁平科技插画
镜像像集装箱一样标准化、可堆叠、可搬移,正是容器化的意象。

Dockerfile 与镜像构建

Dockerfile 是构建镜像的说明书:FROM 指定基础镜像,COPY 拷贝代码,RUN 执行安装命令,EXPOSE 声明端口,CMD 定义启动命令。每一行指令都会产生一个镜像层,写得越精简,构建越快、镜像越小。

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

把依赖安装放在代码拷贝之前,能充分利用层缓存:只要 package.json 没变,依赖层就不会重建,开发时改代码秒级出镜像。

镜像分层与仓库

镜像由一层层只读层叠加而成,推送到镜像仓库时只传输新增层,拉取时也能并发拉层,这是镜像比整机快的原因。基础镜像尽量选官方精简版,例如 alpine,体积小、攻击面小;不要图省事装一堆用不到的包。

docker build -t registry.example.com/app:v1.2.3 .
docker push registry.example.com/app:v1.2.3

版本号建议带上 git 短提交或流水线序号,保证可追溯;latest 标签只用于开发,生产部署永远指向明确版本,回滚才有依据。

容器运行与资源限制

容器不是无限制地吃资源,生产上必须显式限制 CPU 与内存,防止单个容器把整台机器拖垮。内存超限容器会被 OOM 杀掉,所以限制值要留足余量,并与 JVM 等运行时参数匹配。

docker run -d --name app \
  --memory 512m --cpus 1 \
  -p 8080:3000 app:v1.2.3

容器内应用要感知资源限制:Java 用容器感知参数,Node 设置合理的堆上限,日志要打到标准输出并由容器收集,不要往容器内写大文件。