Compose 中的 services、networks、volumes

Compose 中的 services、networks、volumes

三大核心配置的关系

在 Docker Compose 中,servicesnetworksvolumes 是三个最顶层的配置区块。它们的关系可以类比为真实数据中心的规划:

配置 类比 作用
services 服务器 运行什么应用
networks 交换机/网线 服务器之间怎么连接
volumes 硬盘 数据存哪里

三者独立声明、组合使用,实现了关注点分离。

services:定义应用组件

services 是整个 Compose 配置的核心,每个 service 对应一个或多个容器实例。

service 的常见配置

services:
  # 一个 Web API 服务
  api:
    build: ./api
    ports:
      - "8080:8080"
    environment:
      DB_HOST: db
    networks:
      - frontend
      - backend
    volumes:
      - app-data:/app/data
    depends_on:
      - db

  # 数据库服务
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
    volumes:
      - pg-data:/var/lib/postgresql/data
    networks:
      - backend

服务的多实例

services:
  web:
    image: nginx
    # 传统方式(Compose V2)
    deploy:
      replicas: 3
    ports:
      - "80:80"

networks:定义网络拓扑

自动创建网络

当你在 services 中引用网络时,Compose 会自动创建它们:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true   # 后端网络不可对外访问
  monitoring:
    external: true   # 引用已存在的网络
    name: monitor-net

网络类型

# Bridge 网络(默认)
networks:
  my-bridge:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: my-bridge

# Overlay 网络(Swarm 模式)
networks:
  my-overlay:
    driver: overlay
    attachable: true

# Macvlan 网络
networks:
  my-macvlan:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: 192.168.1.0/24
          gateway: 192.168.1.1

IPAM 配置

networks:
  custom-net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1

固定 IP 地址

services:
  db:
    image: postgres
    networks:
      backend:
        ipv4_address: 172.20.0.10

networks:
  backend:
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:定义数据存储

声明命名卷

volumes:
  pg-data:              # 最简单的声明
  redis-data:
    driver: local       # 指定驱动类型
  nfs-storage:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/exports/data"
  external-volume:
    external: true     # 引用外部已存在的卷
    name: prod-db-data # 覆盖外部卷名称

外部卷引用

volumes:
  # 引用已存在的 Docker Volume
  existing-data:
    external: true

  # 指定不同的外部名称
  production-db:
    external: true
    name: prod-postgres-data  # 实际的 Volume 名叫这个

三者如何协同工作

完整示例

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - static-assets:/usr/share/nginx/html:ro
      - nginx-logs:/var/log/nginx
    networks:
      - public
      - internal
    depends_on:
      - api

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    volumes:
      - api-data:/app/data
      - static-assets:/app/static
    environment:
      DB_HOST: db
    networks:
      - internal
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    environment:
      POSTGRES_DB: myapp
    networks:
      - internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s

networks:
  public:
    driver: bridge
  internal:
    driver: bridge
    internal: true

volumes:
  static-assets:
  api-data:
  db-data:
  nginx-logs:

在这个示例中:

  1. nginx 通过 public 网络对外提供服务,通过 internal 网络访问 api
  2. apiinternal 网络中工作,通过 depends_on 确保 db 先启动
  3. db 完全在 internal 网络中,外部无法直接访问
  4. static-assets 卷被 nginx 和 api 同时挂载
  5. db-data 卷持久化 PostgreSQL 数据

网络拓扑图示

         Internet
             |
       [public 网络]
             |
         (nginx)
             |
       [internal 网络]
        /    |    \
      (api) (api) (api)
        |    |
      (redis)(postgres)

最佳实践

  1. 网络安全隔离:前端服务放 public 网络,内部服务放 internal
  2. 卷数据共享:多个服务需要共享文件时使用同一个命名卷
  3. 显式声明:不要依赖默认网络和匿名卷
  4. 外部资源引用external: true 用于共享已经存在的网络或卷
  5. IP 管理:需要固定 IP 时在 IPAM 中配置

面试要点

Q:services 中引用了未在顶级 volumes/networks 中声明的卷/网络会怎样?

A:Compose 会自动创建它们。但显式声明更清晰,也允许配置额外参数(如驱动选项、IPAM)。

Q:internal: true 的网络有什么作用?

A:阻止外部容器访问该网络,提高安全性。数据库等服务应该放在 internal 网络中。

Q:external: true 和默认声明的区别?

A:external: true 表示引用一个已经存在的网络/卷,Compose 不会尝试创建它。如果不存在会报错。常用于共享基础设施。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容