Series Docker & Database cho Laravel #1: Xây dựng "Trái tim" Dữ liệu Bất tử và Tự động hóa
1. Nỗi đau bay màu dữ liệu và Hiểm họa "Mũi tên mù"
Lỗi chí mạng của một lập trình viên khi mới học Docker là sử dụng tag latest cho Database Image và bỏ quên khái niệm Data Persistence (Lưu trữ bền vững).
Khi bạn kéo image mysql:latest, tháng này bạn có thể đang dùng bản 8.0, nhưng tháng sau Docker cập nhật lên bản 8.1 hoặc 9.0. Khi Server khởi động lại, Docker tự động kéo bản mới nhất về, gây ra xung đột phiên bản và làm hỏng toàn bộ cấu trúc file dữ liệu cũ.
Chuẩn Senior:
- Luôn luôn đóng đinh (pin) phiên bản chính xác (ví dụ: mysql:8.0.35).
- Bắt buộc ánh xạ (Mount) Volume dữ liệu ra ổ cứng vật lý của Server.
2. Thiết kế bản vẽ Docker Compose chuẩn mực
Hãy tạo (hoặc cập nhật) file docker-compose.yml tại thư mục gốc của dự án. Chúng ta sẽ lấy MySQL làm hệ quản trị cơ sở dữ liệu tiêu chuẩn cho Laravel.
version: '3.8'
services:
db:
image: mysql:8.0.35
container_name: afc_mysql
restart: unless-stopped
environment:
# Định nghĩa các biến môi trường thiết yếu
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-SecretMetro@2026}"
MYSQL_DATABASE: "${DB_DATABASE:-afc_metro_db}"
MYSQL_USER: "${DB_USERNAME:-afc_app_user}"
MYSQL_PASSWORD: "${DB_PASSWORD:-SecretMetro@2026}"
# Ép Database chạy đúng múi giờ
TZ: "Asia/Ho_Chi_Minh"
ports:
# Chỉ mở cổng ra ngoài ở môi trường Dev, Production nên đóng kín (chỉ app nội bộ được gọi)
- "3306:3306"
volumes:
# 1. Bảo vệ dữ liệu sống còn
- mysql_data:/var/lib/mysql
# 2. Tự động hóa khởi tạo (Init Scripts)
- ./docker/mysql/init:/docker-entrypoint-initdb.d
# 3. Ghi đè cấu hình tối ưu
- ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
networks:
- afc_network
volumes:
mysql_data:
driver: local
networks:
afc_network:
driver: bridge
3. Giải phẫu các chốt chặn Kiến trúc
Bản cấu hình trên chứa đựng những thiết lập phòng ngự cực kỳ khắt khe:
- Tách quyền (Least Privilege): Không bao giờ để ứng dụng Laravel kết nối thẳng vào Database bằng quyền root. Bằng cách định nghĩa MYSQL_USER và MYSQL_PASSWORD, Docker sẽ tự động tạo ra một user con tên là afc_app_user, chỉ có quyền cao nhất trên đúng Database afc_metro_db. Nếu Laravel bị hack, Hacker cũng không thể xóa (DROP) các Database khác nằm cùng trên Server.
- Đồng bộ Múi giờ (TZ): Các giao dịch vé (Transaction) phụ thuộc sống còn vào Timestamp. Trạm thiết bị quẹt vé ở Việt Nam, nhưng nếu Container MySQL chạy múi giờ UTC mặc định, toàn bộ log sẽ bị lệch 7 tiếng. Biến TZ: "Asia/Ho_Chi_Minh" ép Container chạy đúng nhịp thời gian thực.
- Volume mysql_data: Toàn bộ dữ liệu vật lý nằm trong /var/lib/mysql của Container được móc an toàn ra ngoài. Dù bạn có gõ lệnh docker rm -f afc_mysql để đập bỏ Container, dữ liệu giao dịch vẫn nằm an toàn trên Server.
4. Tự động hóa Khởi tạo (Zero-Touch Setup)
Khi triển khai hệ thống mới cho một nhà ga, bạn không thể SSH vào Server, truy cập MySQL CLI, rồi lóc cóc gõ lệnh CREATE DATABASE và phân quyền thủ công.
Docker cung cấp một cơ chế tuyệt vời: Thư mục /docker-entrypoint-initdb.d.
Khi Container MySQL được khởi chạy lần đầu tiên (chưa có dữ liệu), nó sẽ tự động quét thư mục này và chạy toàn bộ các file .sql hoặc .sh bên trong.
Bạn chỉ cần tạo một file thư mục ./docker/mysql/init/ trong source code, thêm file 01_setup_test_db.sql vào đó:
-- Tạo thêm Database riêng cho việc chạy Unit Test
CREATE DATABASE IF NOT EXISTS `afc_metro_testing`;
-- Cấp quyền cho user ứng dụng truy cập Database Test
GRANT ALL PRIVILEGES ON `afc_metro_testing`.* TO 'afc_app_user'@'%';
FLUSH PRIVILEGES;
Giờ đây, chỉ với một lệnh docker-compose up -d, cả cơ sở dữ liệu chính và cơ sở dữ liệu dành riêng cho việc kiểm thử tự động (Testing) đều được đúc sẵn và phân quyền chuẩn xác, sẵn sàng đón nhận luồng dữ liệu từ Laravel.
Bằng việc cố định phiên bản, tách quyền user, đồng bộ thời gian và tự động hóa các script khởi tạo, bạn đã xây dựng thành công một Container Database vững như bàn thạch. Hệ thống giờ đây không chỉ an toàn về mặt dữ liệu mà còn cực kỳ nhàn nhã cho khâu triển khai CI/CD.
All Rights Reserved