Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Một ứng dụng web thực tế hiếm khi chỉ có một thành phần: thường có máy chủ web và cơ sở dữ liệu. Docker Compose cho phép khai báo cả hai trong một file rồi khởi động bằng một lệnh. Bài này hướng dẫn dựng môi trường PHP và MySQL, rất tiện để phát triển mà không cần cài trực tiếp lên máy.
Nếu chạy từng container bằng docker run, bạn phải nhớ nhiều tùy chọn: mạng, cổng, biến môi trường, volume. Compose gom tất cả vào file compose.yaml (hoặc docker-compose.yml) và quản lý vòng đời của cả nhóm: tạo mạng riêng, khởi động theo thứ tự, ghi log chung. Đồng đội chỉ cần chạy một lệnh là có môi trường giống bạn. Bài này giả định bạn đã cài Docker Desktop hoặc Docker Engine kèm plugin Compose; kiểm tra bằng docker compose version.
php-mysql-demo/
compose.yaml
.env
app/
index.phpservices:
web:
image: php:8.3-apache
ports:
- "8080:80"
volumes:
- ./app:/var/www/html
depends_on:
db:
condition: service_healthy
environment:
DB_HOST: db
DB_NAME: ${MYSQL_DATABASE}
DB_USER: ${MYSQL_USER}
DB_PASS: ${MYSQL_PASSWORD}
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 20
volumes:
db_data:Giải thích: mỗi mục trong services là một container. Dịch vụ web dùng image PHP kèm Apache, ánh xạ cổng 8080 của máy sang cổng 80 trong container, và mount thư mục ./app vào thư mục web để sửa code là thấy kết quả ngay. Dịch vụ db dùng MySQL; dữ liệu lưu trong volume tên db_data nên không mất khi xóa container. Trong cùng một file Compose, các dịch vụ tự nằm chung một mạng và gọi nhau bằng tên dịch vụ, vì vậy PHP kết nối tới MySQL qua máy chủ tên db chứ không phải localhost. Phần healthcheck cùng depends_on điều kiện giúp web chỉ khởi động khi MySQL đã sẵn sàng nhận kết nối.
MYSQL_DATABASE=demo
MYSQL_USER=demo_user
MYSQL_PASSWORD=doi_mat_khau_nay
MYSQL_ROOT_PASSWORD=doi_mat_khau_root_nayCompose tự đọc file .env cùng thư mục để thay thế các biến ${...}. Hãy đổi mật khẩu thành giá trị của bạn và thêm .env vào .gitignore. Có thể commit thêm file mẫu .env.example để đồng đội biết cần những biến nào.
Image php:8.3-apache mặc định chưa có phần mở rộng pdo_mysql. Tạo file Dockerfile cho dịch vụ web:
FROM php:8.3-apache
RUN docker-php-ext-install pdo pdo_mysqlRồi trong compose, thay dòng image: php:8.3-apache của dịch vụ web bằng:
build: .Tạo app/index.php:
<?php
$host = getenv('DB_HOST');
$name = getenv('DB_NAME');
$user = getenv('DB_USER');
$pass = getenv('DB_PASS');
try {
$pdo = new PDO("mysql:host=$host;dbname=$name;charset=utf8mb4", $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$version = $pdo->query('SELECT VERSION()')->fetchColumn();
echo 'Kết nối thành công. Phiên bản MySQL: ' . htmlspecialchars($version);
} catch (PDOException $e) {
http_response_code(500);
echo 'Không kết nối được cơ sở dữ liệu.';
error_log($e->getMessage());
}docker compose up -d --build
docker compose ps
docker compose logs -f web
docker compose exec db mysql -u demo_user -p demo
docker compose downMở http://localhost:8080 để thấy thông báo kết nối thành công. Lần đầu MySQL cần thời gian khởi tạo. Lệnh down dừng và xóa container nhưng giữ lại volume dữ liệu; thêm -v chỉ khi bạn thật sự muốn xóa sạch cả dữ liệu.
"8081:80".db.Với một file compose ngắn, bạn có môi trường PHP và MySQL tái tạo được ở mọi máy. Cùng cách khai báo này, bạn có thể thêm Redis, phpMyAdmin hay hàng đợi tác vụ chỉ bằng cách thêm một khối vào services.
Để học Docker và triển khai ứng dụng thực tế, bạn có thể tham khảo các khóa học tại codebem.com.
Nguyễn Đình Cường
0 comment