本教程用两个服务搭建最小开发环境:app 运行 PHP 内置服务器,db 运行 MySQL。重点不是堆砌配置,而是理解容器网络、健康检查和数据卷。
前提:已安装支持
docker compose的 Docker。以下示例只用于本地练习,不是生产部署模板。
一、准备目录与 PHP 页面
compose-demo/
├── Dockerfile
├── compose.yaml
└── public/
└── index.php
<?php
$pdo = new PDO(
'mysql:host=db;dbname=demo;charset=utf8mb4',
'demo',
getenv('DB_PASSWORD'),
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$version = $pdo->query('SELECT VERSION()')->fetchColumn();
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['status' => 'ok', 'mysql' => $version]);
这里数据库主机名是 db,因为 Compose 网络会用服务名做 DNS。容器中的 localhost 只代表当前容器。
二、编写最小 Dockerfile
FROM php:8.4-cli
RUN docker-php-ext-install pdo_mysql
WORKDIR /app
CMD ["php", "-S", "0.0.0.0:8000", "-t", "public"]
三、编写 compose.yaml
services:
app:
build: .
ports:
- "8080:8000"
environment:
DB_PASSWORD: local-demo-password
volumes:
- .:/app
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: demo
MYSQL_USER: demo
MYSQL_PASSWORD: local-demo-password
MYSQL_ROOT_PASSWORD: local-root-password
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-plocal-root-password"]
interval: 5s
timeout: 3s
retries: 20
volumes:
mysql_data:
示例密码仅供本地练习。团队项目应使用未提交的环境文件或 secrets,不要把真实密码写进仓库。
四、启动并逐层验证
docker compose config
docker compose up -d --build
docker compose ps
docker compose logs --tail=100 db
docker compose logs --tail=100 app
curl -i http://127.0.0.1:8080
先用 config 检查合并后的配置。ps 中数据库应为 healthy;curl 应返回 200 和 MySQL 版本。
五、验证数据卷确实持久化
docker compose exec db mysql -udemo -plocal-demo-password demo \
-e "CREATE TABLE notes(id INT PRIMARY KEY, body VARCHAR(100)); INSERT INTO notes VALUES(1,'kept');"
docker compose down
docker compose up -d
docker compose exec db mysql -udemo -plocal-demo-password demo \
-e "SELECT * FROM notes;"
最后应仍能查到 kept。普通 down 不删除命名卷;docker compose down -v 会删除卷和数据,执行前必须确认。
常见问题
- 应用连接被拒绝:等待 db 变为 healthy,并检查应用是否使用服务名
db。 - 修改环境变量不生效:重新创建相关容器,单纯 restart 不会更新容器配置。
- 端口冲突:修改宿主机侧端口,例如
8081:8000。 - 数据库反复重启:查看 db 日志与数据目录权限,不要直接删除卷掩盖根因。