Docker容器化入门
Docker 容器化入门实战:从镜像到部署的最短路径
"在我机器上是好的啊!"——这句话背后,是新员工装环境装一整天、测试环境和生产环境行为不一致、依赖冲突互相打架。容器化的目标只有一个:把应用和它的运行环境打包成一个标准件,在任何装了 Docker 的机器上行为完全一致。
这篇不讲容器底层原理(namespace、cgroup 有机会单独写),专注一条最短实战路径:核心概念 → 常用命令 → 写 Dockerfile → 瘦身 → 编排 → 避坑。
一、三个核心概念:镜像是模板,容器是实例
|
概念 |
一句话解释 |
类比 |
|
镜像(Image) |
只读模板:应用 + 依赖 + 运行环境 |
安装光盘 |
|
容器(Container) |
用镜像跑起来的运行实例 |
光盘装出来的系统 |
|
仓库(Registry) |
存放镜像、可拉取推送 |
应用商店 |
理解三者的关系,后面所有命令都有了坐标:docker pull 从仓库拉镜像,docker run 用镜像起容器,docker build 把你的应用做成镜像,docker push 推回仓库。
和虚拟机比,容器共享宿主机内核,不需要 Guest OS:
|
维度 |
虚拟机 |
容器 |
|
启动速度 |
分钟级 |
秒级 |
|
体积 |
GB 级 |
MB 级 |
|
隔离强度 |
强(独立内核) |
中(共享内核) |
|
资源开销 |
高 |
低 |
隔离强度换轻快——对绝大多数应用交付场景,这笔交易稳赚。
二、十分钟上头:安装与第一批命令
装好 Docker Desktop(Windows/Mac)或 Docker Engine(Linux)后,先跑通三条命令感受一下:
docker run hello-world # 拉镜像并运行官方示例
docker run -d -p 8080:80 --name web nginx # 后台起一个 nginx,宿主 8080 映射容器 80
docker logs -f web # 跟踪容器日志
打开 http://localhost:8080,看到 nginx 欢迎页,你就已经完成了"容器跑 Web 服务"的全流程——没有往宿主机装任何依赖。
高频命令速查:
|
命令 |
作用 |
|
docker ps / docker ps -a |
看运行中 / 全部容器 |
|
docker images |
本地镜像列表 |
|
docker stop <name> / docker rm <name> |
停止 / 删除容器 |
|
docker logs -f --tail 100 <name> |
看日志 |
|
docker exec -it <name> sh |
进容器排查(生产慎用) |
|
docker cp <name>:/path ./local |
容器与宿主机互拷文件 |
|
docker inspect <name> |
看容器全部元数据 |
三、写一个自己的镜像:Dockerfile 逐行讲
假设有一个 Node 应用要打包:
# 构建阶段:装依赖、编译产物
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 运行阶段:只带走运行需要的东西
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main.js"]
逐行拆重点:
· FROM:基础镜像,选 alpine/slim 系而不是完整版,起点就小一个量级
· WORKDIR:容器内工作目录,后续指令都相对它
· 先 COPY package*.json ./ 再 RUN npm ci:故意把依赖清单和源码分开拷——Docker 的分层缓存会记住依赖层,只要 package.json 没变,改代码重新构建时不用重装依赖,构建从分钟级掉到秒级
· COPY --from=builder:多阶段构建,编译工具链全部留在 builder 阶段,最终镜像只装"能跑"的东西
· CMD:容器启动命令,必须是一个前台进程(第一坑,见第六节)
构建与运行:
docker build -t myapp:1.0 .
docker run -d -p 3000:3000 --name myapp myapp:1.0
再配一个 .dockerignore(作用同 .gitignore,先把垃圾挡在构建上下文外):
node_modules
.git
*.log
.env
Dockerfile
.dockerignore
四、镜像瘦身三板斧
镜像大小直接决定拉取速度和部署速度:
1. 多阶段构建:上面已经用了,通常能砍掉一半以上
2. 换小基础镜像:node:20(约 1GB)→ node:20-slim(约 200MB)→ node:20-alpine(约 130MB);注意 alpine 用 musl libc,个别原生依赖需要重新编译
3. `.dockerignore` + 合并 RUN 指令:少把无关文件塞进上下文,少生成层
验证效果:
docker images myapp
docker history myapp:1.0 # 看每一层多大,谁胖一目了然
五、数据、网络与编排
数据别放容器里
容器是"用完即弃"的,写进容器文件系统的数据随容器删除一起消失。持久化用卷:
docker volume create pgdata
docker run -d --name pg -v pgdata:/var/lib/postgresql/data postgres:16
开发时想把代码实时挂进容器,用绑定挂载:-v $(pwd):/app(Windows PowerShell 里是 -v ${PWD}:/app)。
容器之间怎么通信
同一个自定义网络里,容器可以用容器名当域名互访:
docker network create appnet
docker run -d --name redis --network appnet redis:7-alpine
docker run -d --name myapp --network appnet -e REDIS_URL=redis://redis:6379 myapp:1.0
多容器项目:docker compose
应用加缓存加数据库,手敲三条 run 太原始。compose 把整套拓扑写成一个 yaml:
services:
web:
build: .
ports:
- "3000:3000"
environment:
- REDIS_URL=redis://redis:6379
depends_on:
- redis
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
redis-data:
之后整套系统就是两个命令:
docker compose up -d # 一键起全套(自动建网络)
docker compose down # 一键收摊
两个细节:compose 里服务名(web、redis)就是网络里的主机名;depends_on 只保证启动顺序,不保证服务就绪——应用里要做连接重试。
六、新手最容易踩的五个坑
1. 容器起来就退出。 容器的生命周期 = CMD 进程的生命周期。CMD 里跑一个后台启动脚本然后脚本退出,容器立刻停止。原则:CMD 必须前台运行(nginx 用 daemon off;,Node 直接 node server.js)。
2. 日志把磁盘吃满。 默认 json-file 日志驱动不轮转,跑几个月能把盘写爆。生产环境要限制:
docker run --log-opt max-size=10m --log-opt max-file=3 ...
3. 时区是 UTC。 日志时间差八小时。加环境变量并装 tzdata:ENV TZ=Asia/Shanghai(alpine 需额外 apk add tzdata)。
4. 数据写在容器层。 数据库容器升级 = 数据全没。一切需要留下的数据都走 volume。
5. 磁盘被镜像和悬空层塞满。 定期体检和清理:
docker system df # 看占用
docker image prune -f # 清悬空镜像(安全)
docker system prune -a # 清所有未使用镜像(确认没有要留的再跑)
七、什么时候轮到 K8s
Docker 单机 + compose 能覆盖开发环境、小项目和单机部署。当你需要多机调度、自愈重启、滚动发布、弹性扩缩容——再上 Kubernetes。别跳级:没有容器化基础直接上 K8s,等于把复杂度从"环境"搬到"平台",坑一个不少还更贵。
速查卡
|
场景 |
命令 |
|
起容器 |
docker run -d -p 8080:80 --name web nginx |
|
看日志 |
docker logs -f --tail 100 web |
|
进容器 |
docker exec -it web sh |
|
构建镜像 |
docker build -t myapp:1.0 . |
|
瘦身诊断 |
docker history myapp:1.0 |
|
数据持久化 |
-v pgdata:/var/lib/postgresql/data |
|
一键编排 |
docker compose up -d |
|
磁盘体检 |
docker system df |
写在最后
容器化的本质是把"环境"从玄学变成工程:环境被声明在 Dockerfile 里、被版本管理、被一键复现。第一次配好可能要一两天,之后新同事入职是五分钟 docker compose up,而不是一整天装环境。
从给一个老项目写 Dockerfile 开始吧——这是容器化路上性价比最高的第一步。
- 点赞
- 收藏
- 关注作者
评论(0)