04 // 正文
Docker容器化部署实践
把应用连同它依赖的环境一起装进一个标准箱子,走到哪都能原样跑起来——这就是容器的浪漫。Docker 用它特有的轻量隔离,把"在我机器上明明能跑"这句笑话变成了历史。本文从核心概念出发,带你完成安装、跑通第一个容器、用 Dockerfile 构建镜像,最后用 Compose 编排一套多服务应用。
先搞清 Docker 的几个概念
Docker 的体系不复杂,核心就五个词:
- 镜像(Image):应用的打包格式,包含运行所需的一切,只读
- 容器(Container):镜像运行起来的实例,可写、可启停
- 仓库(Registry):存储和分发镜像的地方,如 Docker Hub
- Dockerfile:描述"如何构建镜像"的脚本文件
- Docker Compose:用 YAML 一键编排多个容器
💡 小知识
镜像和容器的关系就像"安装包"和"安装完的程序":一个镜像可以启动任意多个互不干扰的容器。
安装并验证 Docker
以 Ubuntu 为例,走一遍官方仓库的安装流程:
# 更新索引并安装依赖
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl
# 添加 Docker 官方 GPG 密钥与仓库
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
# 安装 Docker 引擎
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
# 启动并验证
sudo systemctl enable --now docker
sudo docker --version
为了免去每次敲 sudo,可以把当前用户加进 docker 组(重新登录后生效):sudo usermod -aG docker $USER。
⚠️ 提醒:把用户加入 docker 组等于把 root 权限交给该用户(容器可以挂载主机目录)。仅限可信的运维账户使用,别在生产机器上给普通用户加。
实战一:跑起第一个容器
装完先拿 Nginx 开刀,感受一下"秒级上线":
# 拉取镜像并后台运行,映射 80 端口
docker run -d --name my-nginx -p 80:80 nginx
# 查看运行中的容器
docker ps
# 访问测试
curl http://localhost
# 停止 / 删除容器
docker stop my-nginx
docker rm my-nginx
实战二:用 Dockerfile 构建自己的镜像
现成镜像不够用时,就要自己"造箱子"。以一个 Node.js 应用为例:
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# 构建并运行
docker build -t my-node-app .
docker run -d --name node-app -p 3000:3000 my-node-app
几个字段的作用:FROM 指定基础镜像(-alpine 后缀的小而快),WORKDIR 设定工作目录,COPY 把文件拷进镜像,RUN 在构建时执行命令,CMD 定义容器启动时跑的命令。
📌 注意:每层指令都会产生镜像层,层越多镜像越大。尽量把易变的代码放在
COPY 后面、把不变依赖放在前面,这样改代码不会让依赖层全部重新构建。
实战三:用 Compose 编排多服务
单容器解决不了"前后端 + 数据库"的组合,这时候上 Compose。一个典型的开发环境长这样:
# docker-compose.yml
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
# 一键启动 / 查看 / 停止
docker compose up -d
docker compose ps
docker compose down
depends_on 声明启动顺序,volumes 把数据持久化到容器之外——容器可以随时换,数据必须留下来。
常见问题排查
容器"起不来"时,按下面顺序找病根:
docker ps -a看容器状态是 Exited 还是 Runningdocker logs 容器名看启动日志里的报错docker exec -it 容器名 /bin/sh进容器里手动验证环境docker inspect 容器名检查端口映射、挂载与网络配置docker stats看资源占用,排查 OOM 之类的问题
⚠️ 高发坑位:"容器挂了但没日志"大概率是进程前台退出或启动命令写错;"端口冲突"先
ss -lntp 查占用;"数据丢了"多半是忘了挂卷。都是经验,遇一次就记住了。最佳实践建议
- 多阶段构建:编译和运行分开,镜像体积能瘦一大圈
- 数据不落容器:数据库、上传目录一律用卷挂到宿主机
- 加资源限制:
--memory、--cpus防止单个容器拖垮宿主机 - 用 .dockerignore:把 node_modules、日志等排除在构建上下文外
- 别用 latest 裸奔:生产环境固定镜像 tag,升级可回滚
- 定期清理:
docker system prune -a收拾悬空镜像和停止的容器
容器化的本质是把应用和环境解耦,实现"一次构建,到处运行"。掌握 Docker 不只是多会一个工具,更是理解"打包、分发、隔离"这套云原生思维的入口。
把单容器跑熟之后,可以试着给容器接上资源限制和健康检查,再进一步学习 Kubernetes 的 Pod、Deployment 概念——你会发现 Docker 只是云原生旅程的第一站,但也是最扎实的一站。