【云原生系列3】Docker Compose单机多容器编排工具

Docker Compose

docker单容器命令,一次管一个容器 / 镜像 / 网络

docker compose是上层多容器编排工具底层调用docker API,用一份 yaml 一次性管理一组容器【项目】(web/mysql/redis 等),适合开发、测试、内网部署;生产大规模集群用 K8s。

bash 复制代码
# compose(一次性启动整套服务,自动创建网络、卷)
docker compose up -d
# 原生docker,需要手动一条条写,还要提前创建网络
docker network create app-net
docker run -d --name mysql --network app-net -v mysql-data:/var/lib/mysql mysql:8.0
docker run -d --name myapp--network app-net myapp:1.0

核心概念

  1. Project(项目):当前目录就是一个项目,compose 会自动创建独立网络,项目名默认是目录名,隔离不同项目容器。
  2. Service(服务) :一个服务对应一组同类型容器(可以 scale 扩副本),服务名就是容器之间通信的域名 (非常关键!例如 mysql 服务名,app 容器直接mysql:3306访问,不需要内网 IP)
  3. Container(容器):服务运行实例
  4. Network :项目默认创建一个 bridge 网桥,同项目所有服务自动接入,容器之间用服务名 DNS 互相解析
  5. Volume(数据卷) :持久化数据,分为绑定挂载(宿主机目录)命名卷(docker 管理)

depends_on 只控制启动顺序,不会等待数据库就绪(mysql 启动需要几秒,容器起来不等于服务就绪,业务代码要做重试)

语法详解

docker-compose.yml :YAML 缩进严格,必须空格,不能 tab,遵循 Compose Specification

bash 复制代码
# docker-compose.yml
services:
  # 后端服务
  myapp:
    image: myapp:1.0
    # build: . # 本地Dockerfile构建镜像,二选一image/build
    container_name: myapp-app  # 可选,指定容器名;指定后不能scale扩副本
    ports:
      - "8080:8080" # 宿主机端口:容器端口,tcp默认
      # - "192.168.1.100:8080:8080" 绑定内网网卡,不对外暴露
    environment: # 环境变量
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/myapp?useUnicode=true
      SPRING_REDIS_HOST: redis
    env_file: ./.env # 从外部文件加载变量,密码放这里,不要写yml硬编码
    volumes:
      - ./logs:/app/logs  # 绑定挂载:宿主机目录:容器目录
      - app-data:/app/data
    depends_on:
      - mysql
      - redis
    restart: unless-stopped # 重启策略
    networks:
      - app-net      # 业务内网,连接mysql/redis,一个容器加入多个网络
      - monitor-net  # 监控网络,连接prometheus

  mysql:
    image: mysql:8.0
    container_name: myapp-mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "Root@123456"
      MYSQL_DATABASE: myapp
    volumes:
      - mysql-data:/var/lib/mysql #命名卷
      - ./mysql/conf:/etc/mysql/conf.d
    restart: unless-stopped
    networks:
      - app-net

  redis:
    image: redis:6.2-alpine
    container_name: myapp-redis
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    restart: unless-stopped
    networks:
      - app-net

# 声明命名卷,docker管理
volumes:
  mysql-data:
  redis-data:
  app-data:

# 自定义网络(不写的话compose自动生成默认网络)
networks:
  app-net:
    driver: bridge
    #ipam = IP Address Management,IP 地址管理
    ipam:  
      config:
        - subnet: 172.20.0.0/16  #子网段
          gateway: 172.20.0.1    #网关   
  monitor-net:

核心字段:

字段 含义
image 指定镜像名 + tag,up检查本地无就从Docker Hub / 私有镜像仓库拉取
build 本地 Dockerfile 构建镜像,build: . 代表当前目录 ,执行 docker build 构建镜像;和image二选一
ports 端口映射 宿主机:容器;字符串引号必须加防止解析错误
environment 环境变量,给容器内的程序注入环境变量 ,等价于 docker run -e
env_file 引入.env文件,敏感密码推荐放这里
volumes 持久化容器数据,挂载目录,ro= 只读,rw读写
depends_on 服务启动依赖,控制顺序,不等待应用就绪
restart 重启策略:no:不重启(默认)always:总是重启on-failure:异常退出才重启unless-stopped:除非手动停止,否则自动重启(生产首选)
container_name 自定义容器名,唯一,不能 scale
command 覆盖容器默认启动命令
hostname 设置容器 hostname
networks 加入自定义网络
network_mode: host host 网络模式,直接复用宿主机网卡,不做端口映射

build 完整写法

build: . 等价于 build: { context: ., dockerfile: Dockerfile }

bash 复制代码
build:
      context: ./src       # 构建上下文目录
      dockerfile: Dockerfile-prod # 指定Dockerfile文件名
      args:                # 构建参数(Dockerfile ARG)
        VERSION: "1.0"
复制代码
# 构建镜像 + 启动
docker compose up -d --build

environment

可以引用外部.env文件中的变量,密码不要硬写在 compose.yml

SpringBoot 会自动读取系统环境变量,优先级高于 application.yml。

复制代码
# application.yml
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db

compose environment 覆盖它:

bash 复制代码
env_file: ./.env
environment:
  SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/myapp
  MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}

.env 文件(放在 docker-compose.yml 同级)

复制代码
DB_PASSWORD=Root@2026

查看环境变量,只在容器启动时注入 修改 environment 后,必须重新 up才生效

bash 复制代码
# 进入容器看环境变量 
docker compose exec app env 
# 或者直接inspect 
docker inspect 容器名 | grep Environment

volumes

命名卷 named volume 绑定挂载 bind mount
写法 mysql-data:/var/lib/mysql ./hostdir:/container/path
存储位置 Docker 托管 /var/lib/docker/volumes 宿主机自定义目录
权限 docker 自动处理,数据库友好 需要自己管理目录权限、selinux
down -v 会被删除 不会被 docker 删除(宿主机文件还在)
适用场景 Mysql、Redis 持久化数据 日志、配置文件、本地开发代码热加载

volumes 有两个位置,作用完全不一样:

  1. service 内部的 volumes:给当前这个服务容器配置挂载(最常用)
  2. yml 最顶层的 volumes声明命名卷,只是定义,不会自动挂载!

常用权限:

  1. :ro # read-only 只读,容器内不能修改(配置文件推荐)
  2. :rw # 读写,默认
  3. :z # selinux共享标签(CentOS7常用,解决permission denied)
  4. :Z # selinux私有标签

绑定挂载 bind mount(宿主机目录 ↔ 容器目录),配置文件、日志

  • 宿主机真实目录,两边文件实时双向同步
  • 宿主机修改文件,容器立刻生效(适合修改配置)
  • 权限坑:CentOS7 SELinux,容易出现权限拒绝,可以加:z标签
bash 复制代码
services:
  app:
    image: myapp:1.0
    volumes:
      # 相对路径,compose.yml同级目录 ./logs
      - ./logs:/app/logs
      # 绝对路径
      - /data/myapp/config:/app/config
      # 只读 ro read-only
      - /data/conf:/app/conf:ro

命名卷 named volume(Docker 管理的卷,推荐数据库)

  • 不用写宿主机路径,docker 自动管理,存在 /var/lib/docker/volumes/
  • 自动处理文件权限,mysql 这类数据库首选
  • docker compose down 默认不会删除命名卷docker compose down -v 才会删除(慎用,删库!)
  • 多容器可以共享同一个命名卷

匿名卷(不推荐,尽量不用)只写容器路径,没有宿主机前缀,docker 随机命名,很难管理,down 的时候容易被清理。volumes: - /var/lib/mysql

tmpfs 内存挂载(临时数据):数据放在内存,容器销毁 / 服务器重启数据消失,适合临时缓存。

bash 复制代码
volumes:
  - type: tmpfs
    target: /tmp/cache

networks

网桥 = 虚拟交换机 。交换机把多台设备插在上面,设备之间可以互相通信。Linux 网桥:操作系统内核里的虚拟交换机,纯软件,没有硬件。

Compose 默认自动创建一个默认 bridge 网络,当前项目下所有服务全部接入这个默认网络,不同 Compose 项目网络天然隔离

配置位置:

  1. services服务下的 networks:指定这个容器要加入哪些网络
  2. yml 顶层 networks自定义网络声明,定义网络驱动、子网、网关等

网络模式(4 种常用 driver/network_mode)

  • bridge(默认,最常用)compose 自定义网桥,容器独立 IP,同网络内服务名 DNS 解析互通,可以做端口映射 ports:,不同网络容器默认隔离
  • host 网络模式(network_mode: host):host 不能写在顶层 networks,写在 service 内部,直接复用宿主机网卡,容器没有独立 IP,不需要 ports 端口映射,宿主机端口直接占用,网络性能最好,无 NAT 损耗
  • none 无网络(network_mode: none)容器完全隔离,没有网卡。一般只做离线计算
  • service:服务名 共享容器网络(sidecar 场景)多个容器共用同一个网络栈,共享 IP。

一个容器可以加入多个网络

external 外部网络(跨 compose 项目互通)网络不是当前 compose 创建,是已经预先建好的 docker 网络

前置操作:先手动创建网络,docker network create emqx-net,然后服务加入网络

bash 复制代码
# 项目B(myapp)的compose.yml
services:
  myapp:
    image: myapp:1.0
    networks:
      - emqx-net

networks:
  emqx-net:
    external: true
    name: emqx-net # 指定已存在的docker网络名称

常用命令

bash 复制代码
# 查看所有docker网络
docker network ls

# 查看网络详情(查看接入容器、网段)
docker network inspect app-net

# 手动创建bridge网络
docker network create --subnet=172.20.0.0/16 app-net

# 删除未使用网络
docker network prune

常用命令

必须在 `docker-compose.yml` 文件所在目录执行

启动

bash 复制代码
# 前台启动(看实时输出,调试用,Ctrl+C停止)
docker compose up

# 后台守护进程启动(生产最常用)
docker compose up -d

# 构建镜像 + 后台启动(改了Dockerfile/代码时使用)
docker compose up -d --build

# 指定自定义yml文件启动(多环境:dev/prod)
docker compose -f docker-compose-prod.yml up -d

# 扩容副本(不能写container_name)
docker compose up -d --scale myapp=2

查看状态

bash 复制代码
# 查看当前项目所有容器状态
docker compose ps

# 只看运行中的容器
docker compose ps --services

# 校验yml语法,打印解析后的完整配置(排错神器)
docker compose config

# 查看项目内所有镜像
docker compose images

日志查看

bash 复制代码
# 实时跟踪全部服务日志
docker compose logs -f

# 只看myapp这个服务的实时日志
docker compose logs -f myapp

# 只看最近200行日志
docker compose logs --tail=200 -f myapp

启停、重启

复制代码
# 停止容器(保留容器、网络、卷)
docker compose stop

# 启动已经停止的服务
docker compose start

# 重启所有服务
docker compose restart

# 只重启单个服务(例如重启mysql)
docker compose restart mysql

删除资源(重点!慎用)

bash 复制代码
# 停止,并删除【容器、默认网络】,保留数据卷volumes(日常推荐)
docker compose down

# down + 删除命名卷!!数据库数据全部清空,生产谨慎
docker compose down -v

# down的时候一并删除镜像
docker compose down --rmi all

# 1. 修改yml配置后,重新部署
docker compose down
docker compose up -d

# 2. 修改代码/Dockerfile重新打包部署
docker compose up -d --build

# 3. 查看日志排查问题
docker compose logs -f myapp

进入容器、执行命令

bash 复制代码
# 进入myapp容器交互式shell
docker compose exec myappbash

# 容器内一次性执行命令(不进入shell)
docker compose exec myappenv

# mysql直接执行sql
docker compose exec mysql mysql -uroot -p

镜像构建

bash 复制代码
# 只构建镜像,不启动容器(build字段才生效)
docker compose build

# 构建并拉取基础镜像
docker compose build --pull

清理

bash 复制代码
# 删除当前项目不再使用的镜像
docker compose prune
相关推荐
2601_962218471 小时前
万象生鲜系统订单全生命周期追踪实现生鲜企业订单业务数字化可视
大数据·运维·微服务·云原生·架构
fengyehongWorld1 小时前
Linux 配置Syncthing的中继服务器
linux·运维·服务器
微信ipad协议开发2 小时前
用 WTAPI搭私域营销自动化
运维·自动化
en.en..2 小时前
深入解析 fork:一次调用,两次返回的核心原理
linux·运维·服务器
java_logo2 小时前
Docker 部署 ArchivesSpace:轻松搭建档案信息管理平台
运维·docker·容器·档案管理·轩辕镜像·archivesspace·特藏
kuroomi6 小时前
Docker 与容器基础
linux·运维·docker
梦梦代码精11 小时前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
_itgo12 小时前
意图识别落地方案
运维·docker·容器
mengge.cloud12 小时前
0909华为云计算类综合服务小白实验教程
linux·运维·服务器·网络·华为云·云计算