Linux-Ubantu-贴士-建立Docker 沙盒(三)

现在来编写你的第一个 docker-compose.yml 文件,并了解如何高效管理和部署容器。


一、第一个 docker-compose.yml:一个经典的 Web 应用栈

我们将用一个 Nginx + PHP + MySQL 的示例来展示 Compose 的强大。创建一个新目录:

bash 复制代码
mkdir my-webapp && cd my-webapp
touch docker-compose.yml

1.1 基础版:单个 Nginx 服务

先写一个最简版本,熟悉语法。

yaml 复制代码
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
  • version:Compose 文件格式版本(目前主流 3.8)。
  • services:定义容器(这里只有一个叫 web 的服务)。
  • image:使用的镜像。
  • ports:宿主机端口 8080 映射到容器 80 端口。
  • volumes:将当前目录下的 html 文件夹挂载到 nginx 默认站点目录。

运行:

bash 复制代码
mkdir html
echo "<h1>Hello from Docker Compose!</h1>" > html/index.html
docker compose up -d

访问 http://localhost:8080 就能看到页面。

1.2 完整版:Nginx + PHP + MySQL

现在扩展成一个典型的 LEMP 栈。

yaml 复制代码
version: '3.8'

services:
  # Nginx Web 服务器
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
      - db

  # PHP-FPM 处理动态请求
  php:
    image: php:8.2-fpm-alpine
    volumes:
      - ./html:/var/www/html

  # MySQL 数据库
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: myapp
      MYSQL_USER: user
      MYSQL_PASSWORD: pass
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "3306:3306"

volumes:
  db_data:

关键概念

  • depends_on:服务启动顺序(web 会等 phpdb 启动后再启动)。
  • environment:传递环境变量给容器。
  • volumes:命名卷 db_data 用于持久化数据库数据,即使容器删除也不会丢失。
  • nginx.conf:需要准备一个简单的站点配置(放在项目根目录)。

nginx.conf 示例

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    root /var/www/html;

    index index.php index.html;

    location ~ \.php$ {
        fastcgi_pass php:9000;  # 注意这里 php 是服务名
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

启动:docker compose up -d


二、如何高效管理和部署容器

2.1 常用 Compose 命令速查

命令 作用
docker compose up -d 后台启动所有服务(首次会自动拉取镜像)
docker compose down 停止并删除容器、网络,但保留卷
docker compose down -v 同时删除卷(彻底清理)
docker compose logs -f 实时查看所有日志
docker compose ps 查看服务状态
docker compose exec <service> sh 进入某个服务容器内部
docker compose restart 重启所有服务
docker compose build 重新构建自定义镜像(如果有 Dockerfile)

2.2 高效技巧:环境差异化

开发、测试、生产环境往往需要不同配置。推荐使用 多 Compose 文件

bash 复制代码
# 开发环境
docker compose -f docker-compose.yml -f docker-compose.override.yml up

# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
  • docker-compose.override.yml 默认会被自动加载(适合开发时的本地覆盖)。
  • 生产文件可以定义不同的资源限制、不同镜像标签等。

2.3 使用 .env 文件管理敏感信息

在项目根目录创建 .env 文件:

ini 复制代码
MYSQL_ROOT_PASSWORD=verysecret
MYSQL_DATABASE=myapp
MYSQL_USER=user
MYSQL_PASSWORD=pass

然后在 docker-compose.yml 中引用:

yaml 复制代码
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

⚠️ 注意.env 文件不要提交到 Git ,加入 .gitignore

2.4 健康检查与依赖等待

depends_on 只保证容器启动顺序,但不保证服务就绪(比如 MySQL 还没准备好接受连接)。更健壮的方式是使用 健康检查

yaml 复制代码
services:
  db:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  web:
    image: nginx:alpine
    depends_on:
      db:
        condition: service_healthy

这样 web 会等待 db 健康后再启动。

2.5 资源限制与性能调优

防止单个容器耗尽宿主机资源:

yaml 复制代码
services:
  web:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

注意:deploy 仅在 swarm 模式下生效,但在 docker compose up 中也可以使用 --compatibility 标志来模拟限制。

2.6 构建与镜像仓库

如果你有自己的代码需要打包,可以自定义 Dockerfile,然后在 Compose 中直接构建:

yaml 复制代码
services:
  app:
    build: .
    image: myapp:latest   # 可选:指定生成的镜像名

然后 docker compose build 构建。

生产部署时,将镜像推送到私有仓库(如阿里云容器镜像服务、Docker Hub):

bash 复制代码
docker tag myapp:latest registry.example.com/myapp:1.0
docker push registry.example.com/myapp:1.0

然后在服务器上用 Compose 直接拉取镜像运行。


三、一个完整的部署流程示例

假设你要将一个应用部署到云服务器:

  1. 本地开发 :使用 docker compose up 验证。

  2. 构建镜像docker compose build

  3. 打标签并推送

    bash 复制代码
    docker tag myapp:latest myregistry.com/prod/myapp:v1
    docker push myregistry.com/prod/myapp:v1
  4. 登录服务器 ,克隆 docker-compose.yml.env(注意生产环境用不同的环境变量)。

  5. 拉取镜像并启动

    bash 复制代码
    docker compose pull
    docker compose up -d
  6. 滚动更新 :重新构建新版本镜像,推送,然后在服务器上:

    bash 复制代码
    docker compose pull
    docker compose up -d --force-recreate

当你需要将 Docker Compose 应用到真实项目时,CI/CD 集成多环境配置是两个最核心的进阶场景。下面我会分别给出实用的配置示例和最佳实践。


四. 多环境配置:开发、测试、生产一套配置管理

推荐方式:基准文件 + 环境专属覆盖

使用 docker-compose.yml 作为基础配置 ,然后用 docker-compose.override.yml 覆盖开发环境,用 docker-compose.prod.yml 覆盖生产环境。

目录结构示例:

bash 复制代码
project/
├── docker-compose.yml          # 基础配置(所有环境共享)
├── docker-compose.override.yml # 开发环境自动加载(gitignore 建议忽略)
├── docker-compose.prod.yml     # 生产环境覆盖
├── .env                        # 默认环境变量
├── .env.prod                   # 生产环境变量
└── src/ ...

基础配置 docker-compose.yml

yaml 复制代码
version: '3.8'

services:
  app:
    image: myapp:${TAG:-latest}
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    environment:
      - NODE_ENV=${NODE_ENV:-development}
      - DB_URL=postgresql://${DB_USER}:${DB_PASS}@db:5432/${DB_NAME}
    depends_on:
      - db
      - redis
    networks:
      - backend

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASS}
      - POSTGRES_DB=${DB_NAME}
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - backend

  redis:
    image: redis:7-alpine
    networks:
      - backend

volumes:
  db_data:

networks:
  backend:

开发覆盖 docker-compose.override.yml (开发时自动生效)

yaml 复制代码
version: '3.8'

services:
  app:
    build:
      target: development   # 使用 Dockerfile 中的 development stage
    volumes:
      - ./src:/app/src      # 挂载源码实现热重载
    environment:
      - DEBUG=true
    ports:
      - "9229:9229"         # 暴露调试端口

  db:
    ports:
      - "5432:5432"         # 暴露数据库端口便于本地工具连接

  redis:
    ports:
      - "6379:6379"

生产配置 docker-compose.prod.yml

yaml 复制代码
version: '3.8'

services:
  app:
    restart: always
    environment:
      - NODE_ENV=production
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G

  db:
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

环境变量文件 .env (默认,可提交模板)

bash 复制代码
TAG=latest
NODE_ENV=development
DB_USER=postgres
DB_PASS=devpassword
DB_NAME=myapp_dev

.env.prod (生产环境,不提交到 Git)

bash 复制代码
TAG=v1.2.3
NODE_ENV=production
DB_USER=prod_user
DB_PASS=strongpassword
DB_NAME=myapp_prod

使用命令

bash 复制代码
# 开发环境(自动加载 .env 和 docker-compose.override.yml)
docker compose up -d

# 生产环境(指定环境变量文件和配置文件)
docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -d

# 生产环境启动并保证服务异常重启
docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -d --restart always

五. CI/CD 集成(以 GitHub Actions 为例)

场景:在 PR 中运行测试,合并后构建镜像并部署

GitHub Actions 工作流 .github/workflows/ci-cd.yml

yaml 复制代码
name: CI/CD Pipeline

on:
  pull_request:
    branches: [ main, develop ]
  push:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Start test environment
        run: |
          docker compose -f docker-compose.yml up -d db redis
          docker compose -f docker-compose.yml run --rm app npm test
        env:
          NODE_ENV: test
          DB_USER: test
          DB_PASS: test
          DB_NAME: testdb

      - name: Tear down
        if: always()
        run: docker compose down -v

  build-and-push:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}, ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to server via SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.DEPLOY_KEY }}
          script: |
            cd /opt/myapp
            docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml pull
            docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -d --remove-orphans
            docker image prune -f

六. 扩展技巧:配置服务、Secrets 与健康检查

使用 Docker Secrets (Swarm 模式,单机也可用)

yaml 复制代码
services:
  app:
    secrets:
      - db_password
secrets:
  db_password:
    file: ./secrets/db_password.txt

健康检查

yaml 复制代码
services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

依赖等待(使用 wait-for-it 或 depends_on + condition)

yaml 复制代码
services:
  app:
    depends_on:
      db:
        condition: service_healthy
  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s

七. 本地开发最佳实践

  • 使用 .env 存储敏感信息,不提交到版本库,提供 .env.example 模板。
  • 利用 docker-compose.override.yml 覆盖开发专用配置(如挂载源码、开启调试端口)。
  • 开发时使用 docker compose up 并保持前台运行查看日志。
  • 定期清理:docker compose down -v 完全清理测试数据。
相关推荐
茶马古道的搬运工2 小时前
Linux-Ubantu-贴士-apt的地盘
操作系统
带娃的IT创业者1 天前
穿越回 1980:解读微软开源的“最早 DOS 源码”与操作系统的原点
microsoft·微软·开源·操作系统·dos·源码解析·计算机历史
Seven971 天前
select、poll、epoll 到底有什么区别?一文讲透 I/O 多路复用
操作系统
磊 子2 天前
硬中断 软中断
后端·操作系统
mifengxing3 天前
操作系统(五)
linux·运维·服务器·操作系统·王道考研
apcipot_rain3 天前
计科八股20260605——软件生命周期、文档、死锁、地址转换、I/O控制方式、堆、无向图、连通图、最小支配集、逆关系、永真式
数据结构·操作系统·软件工程·计算机组成原理·离散数学
sulikey4 天前
个人Linux操作系统学习笔记7 - 进程理解
linux·笔记·学习·操作系统·进程·pid
星马梦缘6 天前
死锁与进程资源分配问题的解法
算法·操作系统·深度优先·死锁
暂未成功人士!6 天前
ROS 核心知识点和常用的命令行详细总结
linux·操作系统·ros