Hướng dẫn sử dụng Flyway quản lý Schema Migration và Version Control cho MySQL trong CI/CD

MySQL tutorial - IT technology blog
MySQL tutorial - IT technology blog

Bối cảnh & Tại sao cần

Đồng hồ điểm đúng 2 giờ sáng. Điện thoại réo liên tục vì PagerDuty báo lỗi 500 hàng loạt trên cụm backend. Sau đợt release đêm, API checkout sập hoàn toàn. Mở log server, nguyên nhân đập ngay vào mắt: Unknown column 'discount_rate' in 'field list'.

Hóa ra Kubernetes vừa kéo image mới chứa code tính chiết khấu. Tuy nhiên, bảng orders dưới MySQL vẫn ở schema cũ vì dev quên chạy script SQL thủ công trước khi merge pull request.

Sửa lỗi kiểu chắp vá lúc nửa đêm cực kỳ nguy hiểm. Paste script qua SSH vào database production dung lượng hàng trăm GB dễ dẫn đến khóa bảng (table lock) hoặc mất dữ liệu. Khi hệ thống mở rộng nhiều môi trường (Dev, Staging, Prod), tình trạng lệch schema (schema drift) giữa code và database là thủ phạm hàng đầu gây downtime.

Flyway giải quyết tận gốc rủi ro này. Công cụ biến toàn bộ thay đổi schema thành các file script có số phiên bản rõ ràng, tự động kiểm tra mã hash checksum và thực thi migration ngay trong pipeline CI/CD.

# Lỗi kinh điển khi code và database lệch version lúc 2h sáng
ERROR 1054 (42S22): Unknown column 'discount_rate' in 'orders'

Cài đặt

Flyway bản Community Edition hoàn toàn miễn phí. Công cụ hỗ trợ chạy qua CLI độc lập, Docker container hoặc tích hợp vào Maven/Gradle. Trong pipeline CI/CD hiện đại như GitHub Actions hay GitLab CI, dùng Docker image hoặc binary CLI là lựa chọn gọn nhẹ nhất.

Cài đặt Flyway CLI trên máy chủ Linux

Tải trực tiếp bản release chính thức từ repository Maven:

# Tải và giải nén Flyway CLI
cd /tmp
wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/10.10.0/flyway-commandline-10.10.0-linux-x64.tar.gz | tar -xvz

# Chuyển vào thư mục hệ thống
sudo mv flyway-10.10.0 /opt/flyway
sudo ln -s /opt/flyway/flyway /usr/local/bin/flyway

# Kiểm tra phiên bản cài đặt
flyway -v

Khởi tạo cấu trúc thư mục dự án

Tổ chức workspace chứa file cấu hình và các file migration SQL:

mkdir -p ~/mysql-flyway-migration/{sql,config}
cd ~/mysql-flyway-migration

Cấu hình chi tiết

Flyway quét file migration dựa vào quy tắc đặt tên với tiền tố và hai dấu gạch dưới (__):

  • V<Version>__<description>.sql: Versioned migration (ví dụ: V1.0__create_users_table.sql, V1.1__add_discount_to_orders.sql). Mỗi file chỉ chạy một lần duy nhất theo thứ tự version tăng dần.
  • U<Version>__<description>.sql: Undo migration dùng để rollback (chỉ hỗ trợ trên bản Teams/Enterprise).
  • R__<description>.sql: Repeatable migration. File này chạy lại mỗi khi nội dung thay đổi, cực kỳ thích hợp cho Views, Stored Procedures hoặc Functions.

Tạo file cấu hình Flyway

Tạo file config/flyway.conf để khai báo kết nối MySQL:

# config/flyway.conf
flyway.url=jdbc:mysql://127.0.0.1:3306/ecommerce_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
flyway.user=flyway_user
flyway.password=SuperSecretPassword123!
flyway.locations=filesystem:sql
flyway.table=flyway_schema_history
flyway.baselineOnMigrate=true
flyway.baselineVersion=0.0
flyway.validateOnMigrate=true
flyway.cleanDisabled=true

Lưu ý an toàn: Luôn bật flyway.cleanDisabled=true trên production. Cờ này chặn đứng lệnh flyway clean vô tình xóa sạch mọi table và dữ liệu.

Tạo các script migration mẫu

Đầu tiên, tạo cấu trúc bảng khởi tạo trong file sql/V1.0__init_schema.sql:

-- sql/V1.0__init_schema.sql
CREATE TABLE IF NOT EXISTS users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    full_name VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS orders (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    total_amount DECIMAL(12, 2) NOT NULL DEFAULT 0.00,
    status VARCHAR(50) NOT NULL DEFAULT 'PENDING',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Tiếp theo, tạo file bổ sung cột chiết khấu sql/V1.1__add_discount_to_orders.sql:

-- sql/V1.1__add_discount_to_orders.sql
ALTER TABLE orders 
ADD COLUMN discount_rate DECIMAL(5, 2) NOT NULL DEFAULT 0.00 AFTER total_amount,
ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

Tích hợp Flyway vào Pipeline CI/CD (GitHub Actions)

Thay vì chạy tay, cấu hình workflow .github/workflows/db-migration.yml để tự động migrate schema trước khi app rollout:

name: Database Migration Pipeline

on:
  push:
    branches:
      - main
    paths:
      - 'sql/**'

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Run Flyway Migration
        uses: docker://flyway/flyway:10.10.0
        with:
          args: >-
            -url=jdbc:mysql://${{ secrets.DB_HOST }}:3306/${{ secrets.DB_NAME }}?useSSL=false&allowPublicKeyRetrieval=true
            -user=${{ secrets.DB_USER }}
            -password=${{ secrets.DB_PASSWORD }}
            -locations=filesystem:sql
            -connectRetries=10
            migrate

Kiểm tra & Vận hành

Trước khi chạy thật, bạn nên kiểm tra danh sách script đang chờ bằng lệnh CLI.

Kiểm tra trạng thái migration qua CLI

# Xem chi tiết lịch sử và các version chưa apply
flyway -configFiles=config/flyway.conf info

# Tiến hành migration
flyway -configFiles=config/flyway.conf migrate

Sau khi lệnh migrate hoàn tất, Flyway tự tạo bảng flyway_schema_history trong MySQL. Bảng này lưu vết toàn bộ: checksum SHA-256 của script, thời gian thực thi tính bằng mili-giây, và cờ trạng thái success.

Truy vấn trực tiếp bảng metadata trong MySQL

-- Kiểm tra bảng lưu vết schema
SELECT installed_rank, version, description, type, script, checksum, installed_on, execution_time, success 
FROM flyway_schema_history 
ORDER BY installed_rank DESC;

Xử lý lỗi Checksum Mismatch

Tình huống thường gặp: một dev lỡ tay chỉnh sửa file V1.0__init_schema.sql cũ sau khi file này đã apply lên Staging hoặc Production. Khi chạy lại, Flyway phát hiện hash file hiện tại khác với checksum trong DB và lập tức dừng tiến trình:

ERROR: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1.0
- Applied to database : 1948294012
- Resolved locally    : -492810481

Nguyên tắc vàng: Không bao giờ sửa file migration đã release. Hãy luôn tạo một version mới (ví dụ V1.2__fix_orders_index.sql). Nếu chỉ đổi khoảng trắng hoặc comment và cần cập nhật lại hash mà không chạy lại SQL, hãy dùng lệnh repair:

# Đồng bộ lại checksum trong DB khớp với file trên đĩa
flyway -configFiles=config/flyway.conf repair

Tích hợp Flyway vào pipeline CI/CD giúp đội ngũ kiểm soát 100% lịch sử schema. Không còn cảnh dev quên chạy SQL tay, và không còn những cuộc gọi khẩn cấp lúc nửa đêm vì lỗi thiếu cột.

Share: