上一篇 下一篇 分享链接 返回 返回顶部

Docker 实战部署指南:从环境配置到 Compose 编排完整示例

发布人:慈云数据-客服中心 发布时间:4小时前 阅读量:4

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 部署流程如下:

  1. 本地开发完成并提交代码。
  2. 编写或更新 Dockerfile。
  3. 编写 .dockerignore
  4. 使用 Docker Compose 定义应用、数据库、缓存、网关等服务。
  5. 在测试环境构建并运行镜像。
  6. 通过日志和接口测试确认功能正常。
  7. 将镜像推送到镜像仓库。
  8. 在生产服务器拉取指定版本镜像。
  9. 使用 Docker Compose 启动服务。
  10. 配置监控、日志、备份和告警。
  11. 发布后观察服务状态。
  12. 如有异常,快速回滚到上一个稳定版本。

十四、完整部署命令示例

假设项目已经包含 Dockerfiledocker-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 与规范的运维流程结合起来,才能真正实现稳定、可靠、可持续的应用部署。

目录结构
全文