Docker入门到部署实战:30分钟搞定容器化开发流

为什么你该现在学Docker?

上周帮朋友排查一个“本地能跑,服务器报错”的bug——Node版本不一致、Redis没装、系统依赖缺失…折腾两小时后我直接甩了份Dockerf

ile过去。他跑完说了句:“这东西早该学了。”

如果你也经历过:

  • “在我电脑上明明能跑”的玄学问题
  • 部署新项目要装一堆依赖,环境配置写满三页文档
  • 线上扩容每次都要手动配置新服务器

Docker就是你的解药。它把应用和依赖打包成一个标准化的容器,保证开发、测试、生产环境完全一致。我自己的项目从传统部

署切到Docker后,部署时间从15分钟降到3分钟,出错的概率直接归零。

(插一张Docker与传统虚拟机的架构对比图:左边是VM的Hypervisor+Guest OS,右边是Docker的Docker Engine+共享内核,突出容器更轻量的特点)

核心概念:3个词搞懂Docker

镜像 vs 容器 vs Dockerfile

很多教程喜欢讲一堆术语,我换个说法:

  • 镜像:做饭的菜谱+食材包(包含运行应用的所有东西)
  • 容器:按菜谱做出来的那盘菜(镜像运行后的实例)
  • Dockerfile:写菜谱的步骤说明(如何构建镜像的脚本)

实际使用中,你写Dockerfile描述应用怎么跑,然后docker build生成镜像,最后docker run启动容器。就这么简单。

安装与验证

踩坑提醒:Windows用户别直接装Docker Desktop,Hyper-V容易和虚拟机软件冲突。建议先装WSL2,再装Docker Desktop选WSL2后端。

bash

安装完成后验证

docker --version # 我用的版本是24.0.6
docker info # 看有没有出现Server Version
`

实战第一步:让一个Node应用集装箱化

写Dockerfile

假设你有一个Express应用,目录结构长这样:
`
my-app/
├── package.json
├── app.js
└── Dockerfile
`

新手最容易犯的错是把整个项目丢进去,结果node_modules也打包进去。正确的写法:

`dockerfile

多阶段构建,减小镜像体积

FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 注意用ci不是install,保证锁定版本

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
`

我用的发现alpine版本镜像只有5MB,完整版node镜像超过200MB。生产环境必选alpine。

构建并运行

`bash

构建镜像,-t是打标签

docker build -t my-app:1.0 .

运行容器,-d后台运行,-p映射端口

docker run -d -p 3000:3000 --name app-instance my-app:1.0

查看运行状态

docker ps # 显示所有运行的容器
docker logs -f app-instance # 实时看日志

进入容器内部调试

docker exec -it app-instance sh
`

执行docker ps后应该看到类似输出:
`
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 my-app:1.0 "node app.js" 5 seconds ago Up 4 seconds 0.0.0.0:3000->3000/tcp app-instance
`

(插入一个终端截图:docker build过程中分层构建的输出,突出每一层缓存使用的提示)

实战第二步:容器编排与数据库

单跑一个应用不够,实际项目通常需要数据库、缓存等。我踩过的坑是:手动启动多个容器,端口和网络配置经常搞混。

Docker Compose拯救你

在项目根目录创建docker-compose.yml

`yaml
version: '3.8'

services:
app:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=db
- DB_PORT=27017
depends_on:
db:
condition: service_healthy # 等数据库就绪才启动
volumes:
- .:/app # 开发模式挂载源码,热更新
- /app/node_modules # 排除node_modules覆盖

db:
image: mongo:6
volumes:
- mongodb_data:/data/db # 持久化数据
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh --quiet
interval: 10s

volumes:
mongodb_data:
`

踩过的坑depends_on默认只等容器启动,不等服务就绪。比如MongoDB要几秒才能接受连接,不加healthcheck的话app启动就会报连接拒绝。

一键启动

`bash

启动所有服务

docker compose up -d

查看服务状态

docker compose ps

查看所有日志

docker compose logs -f

停止并清理

docker compose down -v # -v会删掉volume,生产慎用
`

部署实战:从本地到服务器

搭建私有镜像仓库

直接把镜像推到Docker Hub?慢且不安全。我推荐用Harbor搭建私有仓库:

`bash

下载Harbor离线安装包(约2.3GB,建议先下好)

wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz

修改配置

tar xzf harbor-offline-installer-*.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml

修改hostname为你服务器的域名或IP

生产环境务必启用HTTPS

安装(需要docker compose)

./install.sh
`

推送镜像到仓库

`bash

登录仓库

docker login your-registry.com -u admin

给镜像打标签

docker tag my-app:1.0 your-registry.com/library/my-app:1.0

推送

docker push your-registry.com/library/my-app:1.0
`

服务器上拉取并运行

建议先…再…:先写个docker-compose.prod.yml,区分开发和生产配置:

`yaml
version: '3.8'

services:
app:
image: your-registry.com/library/my-app:1.0
ports:
- "80:3000"
restart: always # 自动重启
logging:
driver: "json-file"
options:
max-size: "10m" # 限制日志大小,防磁盘爆满
`

然后在服务器上执行:

`bash

从仓库拉取最新镜像

docker compose -f docker-compose.prod.yml pull

重启服务,如果镜像没变不会重新创建

docker compose -f docker-compose.prod.yml up -d
`

(插入一张Harbor仓库管理界面的截图,显示镜像列表和标签,突出制品存储功能)

生产环境5个避坑指南

  • 别用root运行容器:Dockerfile里加USER node,防止容器逃逸。我见过生产环境被黑就是因为容器里装的root权限。
  • 限制资源使用:docker run加–memory=512m –cpus=0.5,或者compose里配deploy.resources。不加限制的话,一个容器能把整台服务器搞崩。
  • 日志轮转:默认docker日志会无限增长,几周就能吃掉几十GB。配好max-sizemax-file,或者用ELK统一收集。
  • 镜像瘦身:从800MB瘦到80MB不是梦。用多阶段构建、选alpine基础镜像、合并RUN命令减少层数。
  • 健康检查:业务层加/health端点,Dockerfile里加HEALTHCHECK`指令。配合负载均衡自动摘除异常容器。
  • 立刻动手

  • 找个你现有的Node/Python项目,30分钟内写个Dockerfile并跑起来
  • 如果已经用Docker,试试把单容器改成Docker Compose管理多个服务
  • Docker的核心价值不是技术,而是“一次构建,到处运行”的确定性。浪费在环境问题上的时间,省下来写代码不香吗?

    本文由AI辅助创作,仅供参考。

    滚动至顶部