Triển khai OpenTofu trên CI/CD Pipeline: Hướng dẫn thực tế di chuyển từ Terraform

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

So sánh phương pháp: Terraform vs. OpenTofu trong Pipeline tự động hóa

Vào ngày 10 tháng 8 năm 2023, HashiCorp đã chuyển Terraform từ giấy phép mã nguồn mở MPL 2.0 sang Business Source License (BSL 1.1). Sự thay đổi giấy phép này lập tức làm dấy lên nhiều dấu hỏi cho các platform team. Liệu việc xây dựng các internal developer platform có vi phạm các điều khoản của BSL hay không?

Liệu các nhà cung cấp dịch vụ quản lý (MSP) có thể tiếp tục cung cấp giải pháp tự động hóa dựa trên Terraform cho khách hàng? Để giải quyết vấn đề này, các công ty bao gồm Gruntwork, Spacelift và Env0 đã khởi xướng OpenTofu. Hiện được quản lý bởi Linux Foundation, OpenTofu cung cấp một bản fork độc lập với giấy phép mã nguồn mở vĩnh viễn.

Các đội ngũ DevOps khi đánh giá quy trình continuous delivery hiện nay đứng trước hai lựa chọn rõ ràng:

  • Ở lại với Terraform: Bạn giữ nguyên bộ công cụ hiện tại và khả năng tích hợp HashiCorp Cloud. Tuy nhiên, đội ngũ pháp chế và platform của bạn phải rà soát toàn bộ hệ thống tự động hóa thương mại, sản phẩm cạnh tranh và công cụ nội bộ để đảm bảo tuân thủ BSL.
  • Chuyển sang OpenTofu: OpenTofu được fork từ Terraform 1.5.6 và tương thích hoàn toàn với các cấu hình Terraform 1.5.7. Các tệp HCL hiện có, remote state backend và các community provider đều hoạt động bình thường mà không cần sửa đổi theo giấy phép MPL 2.0.

Cả hai file nhị phân (binary) đều chia sẻ vòng lặp thực thi tương tự nhau. Chúng tải về các plugin provider, tính toán chênh lệch (diff) tài nguyên so với state, và áp dụng (apply) các thay đổi đã được phê duyệt. Việc di chuyển CI/CD pipeline chỉ cần ba bước: thay đổi CLI binary, trỏ đến OpenTofu registry và xác minh cơ chế khóa state backend.

Ưu & nhược điểm khi chuyển sang OpenTofu

Trước khi cập nhật runner trên hàng loạt repository, hãy cân nhắc giữa lợi ích vận hành đạt được và rào cản khi chuyển đổi.

Các ưu điểm

  • Sự quản trị độc lập từ Foundation: OpenTofu hoạt động dưới sự bảo trợ của Linux Foundation. Lộ trình phát triển, các RFC và chu kỳ phát hành đều trung lập với nhà cung cấp. Không có bất kỳ công ty đơn lẻ nào có thể đơn phương thay đổi giấy phép trong các bản phát hành tương lai.
  • Tương thích CLI 1:1 trực tiếp: Các lệnh ánh xạ 1:1. Bạn có thể chạy tofu init, tofu plan và tofu apply với chính xác các đối số và flag mà đội ngũ của bạn đang sử dụng với Terraform.
  • Khả năng tương thích State liền mạch: Nếu hạ tầng của bạn đang chạy trên Terraform 1.5.7 trở về trước, OpenTofu có thể đọc trực tiếp State Format v4 hiện tại. Bạn không cần phải chuyển đổi JSON schema phức tạp hay reset lại state.
  • Mã hóa State phía Client: Bắt đầu từ phiên bản 1.7.0, OpenTofu đã giới thiệu tính năng mã hóa state nguyên bản (native). Bạn có thể mã hóa các biến nhạy cảm và secret trực tiếp trên runner bằng AWS KMS, GCP KMS hoặc AES-GCM trước khi ghi vào remote object storage.

Các hạn chế tiềm ẩn

  • Sự phân nhánh tính năng: Khả năng tương thích vẫn rất tốt với cú pháp HCL cốt lõi. Tuy nhiên, các tính năng độc quyền được giới thiệu từ Terraform 1.7 trở đi (chẳng hạn như test mock hay một số provider function cụ thể) sẽ không tự động có mặt trên OpenTofu.
  • Hệ sinh thái đóng gói trên CI: HashiCorp duy trì sẵn các bước thiết lập tích hợp trên một số marketplace đám mây. Việc chuyển sang OpenTofu yêu cầu cập nhật file YAML pipeline của bạn để sử dụng action chính thức opentofu/setup-opentofu hoặc container image tương ứng.

Đối với hầu hết platform team, quá trình chuyển đổi chỉ mất chưa đầy hai giờ cho mỗi repository. Lợi ích mang lại là tức thì: hoàn toàn độc lập khỏi các ràng buộc giấy phép thương mại từ phía thượng nguồn.

Cấu hình khuyến nghị cho OpenTofu CI/CD Pipeline

Việc thực thi IaC trong CI/CD đòi hỏi sự cô lập nghiêm ngặt. Một kiến trúc an toàn phụ thuộc vào bốn nguyên tắc bảo vệ cốt lõi sau:

  1. Xác thực OIDC không dùng khóa (Keyless): Loại bỏ thông tin xác thực đám mây tĩnh khỏi repository secret. Sử dụng OpenID Connect (OIDC) để liên kết xác thực giữa CI runner và nhà cung cấp dịch vụ đám mây. AWS IAM, Google Cloud Workload Identity và Azure Entra ID đều hỗ trợ cấp token ngắn hạn (thường là 1 giờ) trực tiếp cho các pipeline job đã được xác minh.
  2. Lưu trữ State với cơ chế Khóa phân tán (Distributed Locking): Lưu trữ state trên remote storage chuyên dụng, chẳng hạn như Amazon S3 kết hợp DynamoDB hoặc Google Cloud Storage đã bật object locking. Việc khóa kịp thời sẽ ngăn chặn race condition và làm hỏng state khi các pull request chạy song song kích hoạt plan chồng chéo lên nhau.
  3. Tách biệt giai đoạn Plan và Apply: Tự động chạy tofu plan trên các pull request. Xuất bản tóm tắt kết quả plan trực tiếp vào comment của PR để người review có thể kiểm tra thay đổi trước khi merge. Giới hạn nghiêm ngặt chỉ chạy tofu apply cho các commit đã được merge vào nhánh main.
  4. Ghim phiên bản nghiêm ngặt: Cố định rõ ràng cả phiên bản binary OpenTofu (ví dụ: 1.8.2) và phiên bản provider (ví dụ: AWS provider ~> 5.40). Việc ghim phiên bản giúp ngăn chặn các bản build tự động bị lỗi khi registry thượng nguồn phát hành các bản cập nhật lớn (major update).

Hướng dẫn triển khai: Di chuyển từ Terraform sang OpenTofu trong GitHub Actions

Hãy làm theo các bước dưới đây để chuyển đổi một repository Terraform hiện có sang workflow GitHub Actions an toàn với OpenTofu.

Bước 1: Kiểm thử dự án cục bộ với OpenTofu CLI

Đảm bảo mã nguồn hoạt động tốt ở môi trường cục bộ trước khi commit thay đổi lên pipeline. Cài đặt OpenTofu và kiểm tra quá trình khởi tạo:

# Cài đặt OpenTofu trên Ubuntu/Debian bằng script cài đặt chính thức
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method deb
rm -f install-opentofu.sh

# Kiểm tra thư mục dự án của bạn
cd my-infrastructure-repo/
tofu init
tofu plan

Nếu lệnh plan hoàn tất mà không có cảnh báo về schema hay lỗi provider, codebase của bạn đã sẵn sàng để tự động hóa.

Bước 2: Cập nhật cấu hình phiên bản

Mở file versions.tf. Thiết lập ràng buộc phiên bản yêu cầu để hỗ trợ các bản phát hành OpenTofu và duy trì S3 backend được mã hóa:

terraform {
  # Chấp nhận OpenTofu 1.6+ hoặc Terraform 1.5.7
  required_version = ">= 1.5.7"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.40"
    }
  }

  backend "s3" {
    bucket         = "corp-infrastructure-tfstate-prod"
    key            = "networking/vpc-production.tfstate"
    region         = "us-east-1"
    dynamodb_table = "corp-tfstate-locks"
    encrypt        = true
  }
}

Bước 3: Xây dựng GitHub Actions Pipeline

Tạo file .github/workflows/opentofu.yml. Workflow này sẽ xác thực qua AWS OIDC, kiểm tra định dạng code, đăng kết quả plan vào pull request và tự động apply thay đổi khi merge.

name: "Pipeline hạ tầng OpenTofu"

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  tofu:
    name: "OpenTofu Plan & Apply"
    runs-on: ubuntu-latest

    steps:
      - name: Checkout mã nguồn
        uses: actions/checkout@v4

      - name: Cấu hình thông tin xác thực AWS qua OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-opentofu
          aws-region: us-east-1

      - name: Cài đặt OpenTofu
        uses: opentofu/setup-opentofu@v1
        with:
          tofu_version: 1.8.2

      - name: Khởi tạo OpenTofu
        run: tofu init

      - name: Kiểm tra định dạng
        run: tofu fmt -check

      - name: Chạy Speculative Plan
        id: plan
        if: github.event_name == 'pull_request'
        run: |
          tofu plan -no-color -out=plan.tfplan
        continue-on-error: false

      - name: Đăng tóm tắt Plan lên Pull Request
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const body = `#### Kết quả Plan của OpenTofu: \`Thành công\`
            * **Được push bởi:** @${context.actor}
            * **Hành động:** \`${context.eventName}\`
            * **Nhánh đích:** \`${context.payload.pull_request.base.ref}\``;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

      - name: Áp dụng State đã phê duyệt
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: tofu apply -auto-approve

Bước 4: Thực hiện chuyển đổi và kiểm tra tính toàn vẹn của State

Triển khai workflow đã cập nhật lên nhánh staging trước. Kiểm tra log của GitHub Actions runner để xác nhận rằng tofu init đã lấy được khóa DynamoDB thành công và đọc S3 state bucket mà không có lỗi.

Trước khi triển khai chính thức trên môi trường production, hãy hoàn thành hai bước bảo vệ thiết yếu sau:

  • Sao lưu remote state: Chạy aws s3 cp s3://corp-infrastructure-tfstate-prod/ ./backup-state/ --recursive để tạo một bản snapshot chính xác trước lần chạy đầu tiên.
  • Chuẩn hóa môi trường làm việc của lập trình viên: Yêu cầu tất cả thành viên trong nhóm cài đặt tofu ở máy cục bộ. Nếu một lập trình viên chạy phiên bản Terraform độc quyền mới hơn (như Terraform 1.9+) tại máy cá nhân, nó có thể nâng cấp phiên bản schema của state và khiến OpenTofu pipeline của bạn bị khóa, không thể xử lý tiếp.
Share: