Docker 实战部署指南:从环境配置到 Compose 编排完整示例
Docker 部署完整教程|附配置文件
在现代软件开发与运维体系中,Docker 已经成为应用部署的事实标准之一。它通过容器化技术,将应用程序、运行环境、依赖库、系统工具和配置文件打包到一个相对独立的运行单元中,从而解决了传统部署中常见的“本地能跑,服务器不能跑”“环境不一致”“依赖冲突”“迁移困难”等问题。
无论你是后端开发、前端开发、测试工程师,还是运维人员,掌握 Docker 部署都是非常有价值的一项技能。本文将从 Docker 的基础概念讲起,逐步介绍 Docker 的安装、镜像构建、容器运行、Dockerfile 编写、Docker Compose 编排、常见服务部署示例,以及生产环境中的注意事项。文中也会附带完整配置文件,方便你直接参考和使用。
一、Docker 是什么?
Docker 是一个开源的容器化平台,它允许开发者将应用及其依赖打包成镜像,然后通过镜像快速创建容器并运行应用。
简单来说:
- 镜像:应用的静态模板,类似安装包。
- 容器:镜像运行后的实例,类似正在运行的程序。
- Dockerfile:用于构建镜像的配置文件。
- Docker Compose:用于定义和管理多个容器的编排工具。
- 仓库:用于存储和分发镜像,例如 Docker Hub、阿里云镜像仓库、Harbor 等。
传统部署通常需要在服务器上手动安装运行环境,例如 Java、Node.js、Python、Nginx、MySQL 等。不同服务器之间的系统版本、依赖版本和配置差异,很容易导致部署失败。而 Docker 的核心价值就在于:将运行环境标准化,让应用在任何支持 Docker 的机器上都能以相同方式运行。
二、Docker 部署的优势
使用 Docker 部署应用,主要有以下优势。
1. 环境一致
Docker 镜像中包含应用运行所需的依赖和配置,只要镜像一致,应用运行环境就基本一致。开发环境、测试环境、生产环境可以使用同一套镜像,大幅减少环境差异带来的问题。
2. 部署快速
传统部署可能需要安装依赖、修改配置、启动服务、排查冲突,而 Docker 只需要拉取镜像并运行容器即可。配合 Docker Compose,甚至可以一条命令启动完整项目。
3. 易于扩展
容器是轻量级的,可以快速启动和销毁。在需要扩容时,可以基于同一个镜像启动多个容器实例,再结合负载均衡实现横向扩展。
4. 方便回滚
每次发布都可以生成一个版本镜像。如果新版本出现问题,只需要停止当前容器,并使用旧版本镜像重新启动即可。
5. 隔离性较好
不同应用运行在不同容器中,彼此之间相对隔离。比如一个项目使用 Node.js 16,另一个项目使用 Node.js 20,两者不会互相影响。
三、Docker 安装
下面以常见 Linux 服务器为例,介绍 Docker 的安装方式。
1. Ubuntu 安装 Docker
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
安装完成后,可以执行以下命令查看版本:
docker version
docker compose version
启动 Docker 并设置开机自启:
sudo systemctl start docker
sudo systemctl enable docker
如果希望当前用户无需每次使用 sudo 执行 Docker 命令,可以将用户加入 docker 用户组:
sudo usermod -aG docker $USER
执行后需要重新登录服务器,用户组配置才会生效。
四、Docker 常用命令
在正式部署之前,先熟悉一些常用命令。
1. 镜像相关命令
# 查看本地镜像
docker images
# 拉取镜像
docker pull nginx:latest
# 删除镜像
docker rmi nginx:latest
# 构建镜像
docker build -t my-app:1.0 .
2. 容器相关命令
# 查看正在运行的容器
docker ps
# 查看所有容器
docker ps -a
# 启动容器
docker start container_name
# 停止容器
docker stop container_name
# 删除容器
docker rm container_name
# 查看容器日志
docker logs -f container_name
# 进入容器
docker exec -it container_name sh
3. 网络和数据卷命令
# 查看网络
docker network ls
# 创建网络
docker network create app-network
# 查看数据卷
docker volume ls
# 创建数据卷
docker volume create mysql-data
五、使用 Docker 部署一个 Nginx 服务
先从最简单的 Nginx 部署开始。
docker run -d \
--name nginx-demo \
-p 80:80 \
nginx:latest
参数说明:
-d:后台运行容器。--name nginx-demo:指定容器名称。-p 80:80:将宿主机 80 端口映射到容器 80 端口。nginx:latest:使用 Nginx 最新镜像。
启动后,在浏览器访问服务器 IP,如果能看到 Nginx 默认页面,说明部署成功。
如果需要挂载自定义网页目录:
docker run -d \
--name nginx-web \
-p 80:80 \
-v /data/www:/usr/share/nginx/html \
nginx:latest
这样,服务器 /data/www 目录下的文件会映射到容器中的 Nginx 网站根目录。
六、编写 Dockerfile 部署应用
实际项目通常不会直接使用官方镜像运行,而是需要基于项目代码构建自定义镜像。这时就需要编写 Dockerfile。
下面以一个 Node.js 应用为例,项目结构如下:
my-node-app
├── package.json
├── package-lock.json
├── src
│ └── index.js
└── Dockerfile
示例 Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]
配置说明:
FROM node:20-alpine:使用 Node.js 20 Alpine 作为基础镜像,体积较小。WORKDIR /app:设置容器内工作目录。COPY package*.json ./:先复制依赖配置文件。RUN npm ci --omit=dev:安装生产依赖。COPY . .:复制项目代码。EXPOSE 3000:声明应用监听端口。CMD:定义容器启动命令。
构建镜像:
docker build -t my-node-app:1.0 .
运行容器:
docker run -d \
--name my-node-app \
-p 3000:3000 \
my-node-app:1.0
七、配置 .dockerignore
构建镜像时,Docker 会将构建上下文发送给 Docker Daemon。如果项目中有 node_modules、日志文件、临时文件等无关内容,会导致构建速度变慢,镜像也可能变得臃肿。因此建议配置 .dockerignore。
示例 .dockerignore:
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
.env
logs
dist
coverage
需要注意的是,是否忽略 dist 目录取决于你的构建方式。如果你是在本地构建好前端静态文件,再通过 Docker 打包,那么就不能忽略 dist。如果你是在 Dockerfile 中完成构建,则可以忽略本地 dist。
八、使用 Docker Compose 编排多容器服务
很多真实项目并不是单个容器就能完成的,通常还会依赖数据库、缓存、消息队列、反向代理等服务。例如一个后端项目可能需要:
- 应用服务
- MySQL 数据库
- Redis 缓存
- Nginx 网关
如果手动逐个执行 docker run 命令,会很繁琐。Docker Compose 可以通过一个 docker-compose.yml 文件统一定义多个服务。
九、完整 Docker Compose 示例
下面给出一个常见的后端项目部署示例,包含应用服务、MySQL 和 Redis。
项目结构:
project
├── Dockerfile
├── docker-compose.yml
├── .env
├── app
│ └── ...
└── nginx
└── default.conf
1. .env 配置文件
APP_NAME=my-app
APP_PORT=3000
MYSQL_DATABASE=app_db
MYSQL_USER=app_user
MYSQL_PASSWORD=app_password
MYSQL_ROOT_PASSWORD=root_password
REDIS_PASSWORD=redis_password
生产环境中不要使用示例密码,应替换为高强度随机密码,并妥善保存。
2. docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: ${APP_NAME}
restart: unless-stopped
ports:
- "${APP_PORT}:3000"
environment:
NODE_ENV: production
DB_HOST: mysql
DB_PORT: 3306
DB_NAME: ${MYSQL_DATABASE}
DB_USER: ${MYSQL_USER}
DB_PASSWORD: ${MYSQL_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD}
depends_on:
- mysql
- redis
networks:
- app-network
mysql:
image: mysql:8.0
container_name: ${APP_NAME}-mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
command:
- --default-authentication-plugin=mysql_native_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
networks:
- app-network
redis:
image: redis:7-alpine
container_name: ${APP_NAME}-redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-network
volumes:
mysql-data:
redis-data:
networks:
app-network:
driver: bridge
启动服务:
docker compose up -d
查看服务状态:
docker compose ps
查看日志:
docker compose logs -f
停止服务:
docker compose down
如果希望删除数据卷,需要执行:
docker compose down -v
但请注意,-v 会删除数据库和 Redis 的持久化数据,生产环境谨慎使用。
十、使用 Nginx 反向代理应用
在生产环境中,通常不会直接暴露应用容器端口,而是通过 Nginx 做反向代理、HTTPS 终止、静态资源缓存和负载均衡。
示例 nginx/default.conf:
server {
listen 80;
server_name example.com;
client_max_body_size 20m;
location / {
proxy_pass http://app:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
对应的 Docker Compose 可以增加 Nginx 服务:
nginx:
image: nginx:1.25-alpine
container_name: ${APP_NAME}-nginx
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
networks:
- app-network
添加后重新启动:
docker compose up -d
如果需要配置 HTTPS,可以使用 Certbot、acme.sh,或者配合 Nginx Proxy Manager、Traefik 等工具自动管理证书。
十一、生产环境部署建议
1. 不要把敏感信息写进镜像
数据库密码、密钥、Token 等敏感配置不应该写入 Dockerfile,也不应该提交到代码仓库。建议通过 .env 文件、服务器环境变量、密钥管理服务或 CI/CD 平台变量传入。
2. 镜像版本要固定
不要在生产环境长期使用 latest 标签。因为 latest 会随着上游镜像变化而变化,可能导致不可预期的问题。建议使用明确版本,例如:
image: mysql:8.0.36
image: redis:7.2-alpine
image: nginx:1.25-alpine
3. 数据必须持久化
数据库、Redis、上传文件等需要持久化的数据,必须使用 Docker Volume 或宿主机目录挂载。否则容器删除后,数据可能丢失。
4. 设置重启策略
生产服务建议配置:
restart: unless-stopped
这样服务器重启或容器异常退出后,Docker 会自动尝试恢复服务。
5. 控制容器资源
对于资源敏感的场景,可以限制容器 CPU 和内存,避免单个容器占满服务器资源。
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
需要注意,部分 deploy 配置主要用于 Swarm 模式,在普通 Docker Compose 中支持情况与版本有关。
6. 配置日志策略
容器日志如果不限制,长期运行可能占满磁盘。可以在 Docker Daemon 或 Compose 中配置日志轮转:
logging:
driver: json-file
options:
max-size: "100m"
max-file: "3"
7. 定期备份数据
Docker 让服务部署更简单,但并不等于自动解决备份问题。MySQL、PostgreSQL、MongoDB 等数据库仍然需要定期备份,并定期验证备份是否可恢复。
十二、常见问题排查
1. 容器启动失败
查看日志:
docker logs container_name
如果使用 Compose:
docker compose logs -f service_name
重点检查环境变量、端口占用、依赖服务是否启动、配置文件路径是否正确。
2. 端口无法访问
可以依次检查:
docker ps
确认端口是否正确映射;然后检查服务器防火墙、安全组是否放行端口;最后确认应用是否监听了正确地址。很多应用默认只监听 127.0.0.1,在容器中应监听 0.0.0.0。
3. 容器之间无法连接
在 Docker Compose 中,同一个网络下的服务可以通过服务名访问。例如应用连接 MySQL 时,主机名应该写 mysql,而不是 localhost。因为在容器内部,localhost 指的是容器自身。
4. 数据丢失
如果删除容器后数据丢失,通常是因为没有配置数据卷。数据库必须挂载到 Volume 或宿主机目录,例如:
volumes:
- mysql-data:/var/lib/mysql
5. 镜像构建很慢
常见原因包括构建上下文过大、没有配置 .dockerignore、依赖安装步骤没有利用缓存等。建议先复制依赖文件,再安装依赖,最后复制业务代码,这样可以充分利用 Docker 构建缓存。
十三、推荐的部署流程
一个比较规范的 Docker 部署流程如下:
- 本地开发完成并提交代码。
- 编写或更新 Dockerfile。
- 编写
.dockerignore。 - 使用 Docker Compose 定义应用、数据库、缓存、网关等服务。
- 在测试环境构建并运行镜像。
- 通过日志和接口测试确认功能正常。
- 将镜像推送到镜像仓库。
- 在生产服务器拉取指定版本镜像。
- 使用 Docker Compose 启动服务。
- 配置监控、日志、备份和告警。
- 发布后观察服务状态。
- 如有异常,快速回滚到上一个稳定版本。
十四、完整部署命令示例
假设项目已经包含 Dockerfile、docker-compose.yml 和 .env,可以按以下步骤部署:
# 进入项目目录
cd /data/project/my-app
# 拉取最新代码
git pull
# 构建镜像并启动服务
docker compose up -d --build
# 查看容器状态
docker compose ps
# 查看实时日志
docker compose logs -f
# 重启服务
docker compose restart
# 停止服务
docker compose down
如果是生产环境升级,建议先备份数据,再执行构建和启动命令。对于重要系统,不建议直接在高峰期发布。
十五、总结
Docker 的核心价值在于标准化应用运行环境,并让部署流程变得更加简单、稳定和可复制。通过 Dockerfile,我们可以将应用打包成镜像;通过 Docker Compose,我们可以统一管理应用、数据库、缓存和反向代理等多个服务;通过数据卷、环境变量、日志策略和重启策略,我们可以让容器更适合生产环境运行。
对于初学者来说,建议先从单容器部署 Nginx 或简单后端应用开始,再逐步学习 Dockerfile、Docker Compose、网络、数据卷、镜像仓库和 CI/CD。当你能够熟练编写 Dockerfile 和 docker-compose.yml 后,大多数中小型项目的部署都会变得非常清晰。
最后需要强调的是,Docker 并不是万能的。它解决的是环境一致性、部署效率和服务隔离问题,但数据库备份、安全加固、日志监控、资源规划、故障恢复等生产级问题仍然需要认真设计。只有将 Docker 与规范的运维流程结合起来,才能真正实现稳定、可靠、可持续的应用部署。