--- id: devops.docker.compose-network-volume title: Compose、网络和数据卷:多服务编排、健康检查、环境变量 type: lesson domain: devops stack: [docker] tags: [Compose, 网络, 数据卷, 健康检查, 环境变量] level: basic prerequisites: [devops.docker.image-dockerfile] est_hours: 2 related: [devops.docker.scenario.compose-dev-env, devops.docker.interview] week: [3, 6, 13] order: 2 --- # Compose、网络和数据卷:多服务编排、健康检查、环境变量 ## 解释说明 - **Compose**:用一个 `compose.yaml` 描述多个服务(应用、数据库、缓存),`docker compose up -d` 一起启动。适合本地开发、测试环境和小规模单机部署;多机、大规模用 Kubernetes。 - **网络**:Compose 默认为项目创建一个网络,服务之间**用服务名当主机名**访问(`db:5432`),不需要知道 IP。容器内的 `localhost` 指的是容器自己,不是宿主机。 - **端口映射**:`ports: "8080:8080"` 是“宿主机端口:容器端口”,只有需要从宿主机访问的服务才映射。数据库不映射端口更安全(只在内部网络可见)。 - **数据卷**:容器删除后可写层的数据就没了。数据库数据要放在**命名卷**(Docker 管理)或**绑定挂载**(宿主机目录,开发时挂源码目录方便热更新)。 - **健康检查和启动顺序**:`depends_on` 默认只保证“先启动”,不保证“已就绪”。给数据库配 `healthcheck`,应用用 `condition: service_healthy` 等待。应用本身也要有连接重试。 - **环境变量**:`environment` 直接写,或 `env_file: .env`;`.env` 文件不要提交到 Git。Compose 文件里 `${VAR}` 会从 shell 或项目目录的 `.env` 读取。 **常用命令**:`docker compose up -d --build`、`docker compose ps`、`docker compose logs -f api`、`docker compose exec db psql -U app`、`docker compose down`(加 `-v` 会删除数据卷,小心)。 ## 案例 开发 RAG 服务时需要 PostgreSQL(含 pgvector)+ Redis + 应用。用 Compose:新同事 clone 仓库后 `docker compose up -d` 就能跑;数据库数据存在命名卷里,重启不丢;`db` 不映射端口,需要调试时临时 `docker compose exec db psql`。 ## 代码示例 完整文件见 [examples/go-api-compose/compose.yaml](examples/go-api-compose/compose.yaml): ```yaml services: api: build: . ports: - "8080:8080" environment: DATABASE_URL: postgres://app:app@db:5432/app?sslmode=disable # 用服务名 db 访问 REDIS_URL: redis://redis:6379/0 depends_on: db: condition: service_healthy redis: condition: service_started restart: unless-stopped db: image: postgres:17 environment: POSTGRES_USER: app POSTGRES_PASSWORD: app POSTGRES_DB: app volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d app"] interval: 5s timeout: 3s retries: 10 redis: image: redis:7-alpine volumes: pgdata: ``` ## 易错点 - **应用里连 `localhost:5432`**:在容器里 localhost 是应用容器自己,要用服务名 `db`。 - **以为 `depends_on` 会等数据库就绪**:只等容器启动。要配健康检查,应用也要能重试连接。 - **`docker compose down -v`**:会删掉命名卷,数据库数据全没。 - **把数据库端口映射到公网服务器的 `0.0.0.0`**:数据库直接暴露在公网。不映射,或者只绑定 `127.0.0.1:5432:5432`。 - **在 compose 文件里写真实密码并提交**:用 `.env`(加入 `.gitignore`)或部署平台的密钥管理。 - **镜像版本升级时数据目录变化**:例如 PostgreSQL 新大版本的数据目录约定可能变化,升级前看官方镜像说明并备份。 ## 面试常问 见 [Docker 面试题](interview.md):容器之间怎么通信、数据怎么持久化、depends_on 的局限。