0Pricing
PHP Academy · 课时

使用 Docker Compose 构建本地技术栈

在本地同时运行 PHP、数据库和缓存

使用 Docker Compose 构建本地技术栈 是 CoddyKit 上的免费 PHP Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 PHP Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 PHP Academy 课程共包含 4 节课。

使用 Compose 构建本地服务栈

真正的 PHP 应用从来不只是 PHP——它们还需要数据库、缓存,有时还需要队列和邮件捕获服务。Docker Compose 会在一个文件中将这些组件声明为服务,并将它们连接到共享网络,使服务可以通过名称相互访问。

本课将构建一个完整的本地服务栈:PHP-FPM + nginx + MySQL + Redis,并配置卷、健康检查和依赖顺序。

服务骨架

Compose 文件会在 services: 下列出各项服务。每项服务都可以从 Dockerfile build,也可以拉取一个 image。Compose 会创建一个默认网络,其中每项服务都可以通过自己的键访问——您的 PHP 应用应通过主机名 db 连接 MySQL,而不是使用 localhost。

services:
  app:
    build:
      context: .
      target: dev          # multi-stage dev target
    volumes:
      - ./:/app            # live code mount
    depends_on:
      db:
        condition: service_healthy
  db:
    image: mysql:8.4
  redis:
    image: redis:7-alpine

让 nginx 位于 FPM 前端

FPM 在 9000 端口上使用 FastCGI 通信,而不是使用 HTTP。nginx 负责终止 HTTP 连接,并将 .php 请求代理到 app:9000。nginx 配置通过 Compose 服务名称引用 PHP 服务。

# docker/nginx/default.conf
server {
  listen 80;
  root /app/public;
  index index.php;

  location / {
    try_files $uri /index.php?$query_string;
  }

  location ~ \.php$ {
    fastcgi_pass app:9000;       # service name from compose
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

连接 Web 服务

nginx 服务会挂载相同的代码(用于解析 SCRIPT_FILENAME)和配置文件,发布 80 端口,并依赖于应用服务。两者共享 /app,因此 FastCGI 两端的路径能够保持一致。

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    volumes:
      - ./:/app:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app

持久化卷

容器文件系统是临时的。命名卷可以在执行 docker compose down 后保留数据库文件。绑定挂载(./:/app)可以在开发期间实时同步主机代码。请对有状态数据使用命名卷,对源代码使用绑定挂载。

services:
  db:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: app
      MYSQL_USER: app
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: rootsecret
    volumes:
      - dbdata:/var/lib/mysql

volumes:
  dbdata:        # survives `down`, removed only by `down -v`

健康检查与依赖关系

单独使用 depends_on 时,只会等待容器启动,不会等待 MySQL 接受连接。请添加 healthcheck,并使用 condition: service_healthy,这样应用会一直等待到数据库真正准备就绪。

services:
  db:
    image: mysql:8.4
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-prootsecret"]
      interval: 5s
      timeout: 3s
      retries: 10
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy   # waits for healthcheck pass

环境变量与 .env

Compose 会自动加载同级的 .env 以进行变量插值,您可以通过 environment 或 env_file 传入应用配置。请不要将密钥放入已提交的 Compose 文件中,而应改为引用变量。

services:
  app:
    build: .
    env_file:
      - .env
    environment:
      DATABASE_URL: "mysql://app:secret@db:3306/app"
      REDIS_URL: "redis://redis:6379"
# .env (gitignored) provides ${...} substitutions
#   MYSQL_PASSWORD=secret

从 PHP 连接服务

在网络内部,主机名就是服务名称。您的 PHP 代码可以直接连接 db 和 redis。这个片段以配置层可能采用的方式解析 DSN,展示 Compose 服务名称如何流入连接字符串。

<?php
$dsn = 'mysql://app:secret@db:3306/app';
$p = parse_url($dsn);

printf("driver: %s\n", $p['scheme']);
printf("host:   %s\n", $p['host']);   // 'db' resolves via compose DNS
printf("port:   %d\n", $p['port']);
printf("db:     %s\n", ltrim($p['path'], '/'));

$pdoDsn = sprintf('mysql:host=%s;port=%d;dbname=%s', $p['host'], $p['port'], ltrim($p['path'], '/'));
echo $pdoDsn . PHP_EOL;
?>

用于本地开发的 Xdebug

只在本地挂载 Xdebug 配置(通过 dev 构建目标)。请将 client_host 指向 host.docker.internal,这样调试器就能连接主机上的 IDE。绝不要将 Xdebug 部署到生产环境,因为它会严重降低性能。

; docker/php/xdebug.ini  (mounted only in dev)
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

运行一次性命令

docker compose run 会为迁移、测试或 Composer 启动一个临时容器;exec 则会在已经运行的服务内部执行命令。请对一次性任务使用 run --rm,以便清理用完即弃的容器。

# Run migrations against the running db
docker compose exec app php bin/console doctrine:migrations:migrate

# One-off: install deps without a long-lived container
docker compose run --rm app composer install

# Tail logs of just the web service
docker compose logs -f web

覆盖文件

Compose 会自动合并 docker-compose.yml 与 docker-compose.override.yml。请将面向生产环境的默认配置保留在基础文件中,并将仅供开发使用的卷、端口和 Xdebug 放入覆盖文件中——这样 CI 使用基础配置,开发人员则可以直接获得额外功能。

# docker-compose.override.yml (auto-merged, dev only)
services:
  app:
    volumes:
      - ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini:ro
    environment:
      APP_ENV: dev
# CI runs: docker compose -f docker-compose.yml up  (no override)

快速检查

在运行迁移之前,为什么单纯的 depends_on: [db] 不够?

回顾

您使用 Compose 组装了一个本地服务栈:nginx 后面的 PHP-FPM(通过 FastCGI 连接到 app:9000)、可通过服务名称访问的 MySQL 和 Redis、用于持久化的命名卷、控制 depends_on 的健康检查、由环境变量驱动的配置、仅供开发使用的覆盖配置中的 Xdebug,以及通过 run/exec 执行的一次性命令。

请记住:服务名称就是 DNS 主机名,覆盖文件可以将开发环境的额外配置排除在 CI 之外,而健康检查比简单的启动顺序更可靠。

常见问题解答

「使用 Docker Compose 构建本地技术栈」课时是免费的吗?

是的 — 「使用 Docker Compose 构建本地技术栈」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 PHP Academy 课程的其余内容,请升级到 CoddyKit PRO。 PHP Academy 课程共包含 4 节课。

「使用 Docker Compose 构建本地技术栈」这节课中我会学到什么?

在本地同时运行 PHP、数据库和缓存 你通过在浏览器中直接运行的动手代码来练习 PHP Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 PHP Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 PHP Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「使用 Docker Compose 构建本地技术栈」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 PHP Academy 课中编写并运行代码吗?

能。每节 PHP Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 将 PHP 应用容器化
  2. 多阶段构建与优化
  3. 使用 Docker Compose 构建本地技术栈
  4. 使用 GitHub Actions 实现 CI/CD
← 返回 PHP Academy