Mencoba OpenTofu, Sebuah Fork yang Muncul dari Ketidakpuasan Hashicorp Terraform


This work by Muhammad Raihan Widagdo is licensed under CC BY-SA 4.0

Photo by Sherman Kwan on Unsplash

OpenTofu adalah alat infrastructure as code (IaC) open-source. Istilah “infrastructure as code” berarti infrastruktur, seperti sumber daya komputasi awan, dikelola menggunakan kode. Ini memungkinkan tim untuk mengotomatiskan penyediaan dan pengelolaan infrastruktur mereka, yang dapat menghemat waktu dan mengurangi kesalahan.

OpenTofu mirip dengan alat IaC populer lainnya yaitu Terraform, tetapi OpenTofu adalah fork dari Terraform. OpenTofu didasarkan pada kode Terraform, tetapi dikembangkan secara independen oleh komunitas OpenTofu dibawah Linux Foundation. OpenTofu dibuat dikarenakan setelah ~9 tahun Terraform menjadi open source di bawah lisensi MPL v2, Terraform dipindahkan ke bawah lisensi BSL v1.1 non-open source, mulai dari versi berikutnya (1.6). Hal ini mengakibatkan limitasi untuk penggunaan Terraform terutama untuk penggunaan komersial.

Artikel ini akan membahas proses instalasi dan mencoba sekilas OpenTofu untuk membangun infrastruktur sederhana berupa Docker Container. Environment yang digunakan adalah Debian 12 dan sudah terpasang Docker Engine.

Saatnya eksperimen

Pertama tentu saja kita perlu melakukan instalasi OpenTofu. Untuk Linux Debian dan turunannya, OpenTofu sudah menyediakan skrip instalasi otomatis. Anda bisa langsung melakukan copy paste skrip di bawah ke terminal.

# Download the installer script:
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
# Alternatively: wget --secure-protocol=TLSv1_2 --https-only https://get.opentofu.org/install-opentofu.sh -O install-opentofu.sh

# Give it execution permissions:
chmod +x install-opentofu.sh

# Please inspect the downloaded script

# Run the installer:
./install-opentofu.sh --install-method deb

# Remove the installer:
rm install-opentofu.sh

Tidak seperti Terraform yang dapat kita panggil dengan terraform, OpenTofu menggunakan command yang lebih pendek dan mudah yaitu tofu. Bila anda membutuhkan kompabilitas dengan Terraform anda masih bisa melakukan alias pada command tofu.

$ tofu version
OpenTofu v1.6.2
on linux_amd64

Buat direktori baru untuk menyimpan konfigurasi OpenTofu.

$ mkdir learn-tofu-docker-container
$ cd learn-tofu-docker-container

Seperti di terraform, buatlah file main.tf sebagai file konfigurasi utama.

$ nano main.tf

Masukkan kode berikut lalu simpan. Kode ini adalah konfigurasi dalam bahasa dalam format HCL (HashiCorp Configuration Language)

terraform {
  required_providers {
    docker = {
      source = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.image_id
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}

Ketika membuat konfigurasi baru, atau mengambil konfigurasi yang ada dari version-control misalnya Git, diperlukan inisialisasi direktori dengan terraform init.

$ tofu init

Initializing the backend...

Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "~> 3.0.1"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2. Signature validation was skipped due to the registry not containing GPG keys for this provider

OpenTofu has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that OpenTofu can guarantee to make the same selections by default when
you run "tofu init" in the future.

OpenTofu has been successfully initialized!

You may now begin working with OpenTofu. Try running "tofu plan" to see
any changes that are required for your infrastructure. All OpenTofu commands
should now work.

If you ever set or change modules or backend configuration for OpenTofu,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Untuk memformat kode ke dalam gaya penulisan yang konsisten dan sesuai dengan standar lakukan perintah berikut.

$ tofu fmt
$ tofu validate
Success! The configuration is valid.

Terapkan kode tadi ke environment dan infrastruktur.

$ tofu apply

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

OpenTofu will perform the following actions:

  # docker_container.nginx will be created
  + resource "docker_container" "nginx" {
      + attach                                      = false
      + bridge                                      = (known after apply)
      + command                                     = (known after apply)
      + container_logs                              = (known after apply)
      + container_read_refresh_timeout_milliseconds = 15000
      + entrypoint                                  = (known after apply)
      + env                                         = (known after apply)
      + exit_code                                   = (known after apply)
      + hostname                                    = (known after apply)
      + id                                          = (known after apply)
      + image                                       = (known after apply)
      + init                                        = (known after apply)
      + ipc_mode                                    = (known after apply)
      + log_driver                                  = (known after apply)
      + logs                                        = false
      + must_run                                    = true
      + name                                        = "tutorial"
      + network_data                                = (known after apply)
      + read_only                                   = false
      + remove_volumes                              = true
      + restart                                     = "no"
      + rm                                          = false
      + runtime                                     = (known after apply)
      + security_opts                               = (known after apply)
      + shm_size                                    = (known after apply)
      + start                                       = true
      + stdin_open                                  = false
      + stop_signal                                 = (known after apply)
      + stop_timeout                                = (known after apply)
      + tty                                         = false
      + wait                                        = false
      + wait_timeout                                = 60

      + ports {
          + external = 8000
          + internal = 80
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # docker_image.nginx will be created
  + resource "docker_image" "nginx" {
      + id           = (known after apply)
      + image_id     = (known after apply)
      + keep_locally = false
      + name         = "nginx:latest"
      + repo_digest  = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  OpenTofu will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

docker_image.nginx: Creating...
docker_image.nginx: Creation complete after 0s [id=sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666anginx:latest]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 1s [id=6bcf40c73fa5872e139520022871a0684ca79051b1d8fbd833930eddb5cd02ae]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Dari eksperimen yang kita lakukan. OpenTofu secara garis besar kompatibel dengan Hashicorp Terraform. OpenTofu juga memberikan alternatif yang lebih baik dibandingkan Terraform yang lebih restriktif untuk penggunaan komersial.

Terakhir “hancurkan” infrastruktur yang telah kita terapkan tadi.

$ tofu destroy
docker_image.nginx: Refreshing state... [id=sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666anginx:latest]
docker_container.nginx: Refreshing state... [id=6bcf40c73fa5872e139520022871a0684ca79051b1d8fbd833930eddb5cd02ae]

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

OpenTofu will perform the following actions:

  # docker_container.nginx will be destroyed
  - resource "docker_container" "nginx" {
      - attach                                      = false -> null
      - command                                     = [
          - "nginx",
          - "-g",
          - "daemon off;",
        ] -> null
      - container_read_refresh_timeout_milliseconds = 15000 -> null
      - cpu_shares                                  = 0 -> null
      - dns                                         = [] -> null
      - dns_opts                                    = [] -> null
      - dns_search                                  = [] -> null
      - entrypoint                                  = [
          - "/docker-entrypoint.sh",
        ] -> null
      - env                                         = [] -> null
      - group_add                                   = [] -> null
      - hostname                                    = "6bcf40c73fa5" -> null
      - id                                          = "6bcf40c73fa5872e139520022871a0684ca79051b1d8fbd833930eddb5cd02ae" -> null
      - image                                       = "sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666a" -> null
      - init                                        = false -> null
      - ipc_mode                                    = "private" -> null
      - log_driver                                  = "json-file" -> null
      - log_opts                                    = {} -> null
      - logs                                        = false -> null
      - max_retry_count                             = 0 -> null
      - memory                                      = 0 -> null
      - memory_swap                                 = 0 -> null
      - must_run                                    = true -> null
      - name                                        = "tutorial" -> null
      - network_data                                = [
          - {
              - gateway                   = "172.17.0.1"
              - global_ipv6_address       = ""
              - global_ipv6_prefix_length = 0
              - ip_address                = "172.17.0.2"
              - ip_prefix_length          = 16
              - ipv6_gateway              = ""
              - mac_address               = "02:42:ac:11:00:02"
              - network_name              = "bridge"
            },
        ] -> null
      - network_mode                                = "default" -> null
      - privileged                                  = false -> null
      - publish_all_ports                           = false -> null
      - read_only                                   = false -> null
      - remove_volumes                              = true -> null
      - restart                                     = "no" -> null
      - rm                                          = false -> null
      - runtime                                     = "runc" -> null
      - security_opts                               = [] -> null
      - shm_size                                    = 64 -> null
      - start                                       = true -> null
      - stdin_open                                  = false -> null
      - stop_signal                                 = "SIGQUIT" -> null
      - stop_timeout                                = 0 -> null
      - storage_opts                                = {} -> null
      - sysctls                                     = {} -> null
      - tmpfs                                       = {} -> null
      - tty                                         = false -> null
      - wait                                        = false -> null
      - wait_timeout                                = 60 -> null

      - ports {
          - external = 8000 -> null
          - internal = 80 -> null
          - ip       = "0.0.0.0" -> null
          - protocol = "tcp" -> null
        }
    }

  # docker_image.nginx will be destroyed
  - resource "docker_image" "nginx" {
      - id           = "sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666anginx:latest" -> null
      - image_id     = "sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666a" -> null
      - keep_locally = false -> null
      - name         = "nginx:latest" -> null
      - repo_digest  = "nginx@sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  OpenTofu will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

docker_container.nginx: Destroying... [id=6bcf40c73fa5872e139520022871a0684ca79051b1d8fbd833930eddb5cd02ae]
docker_container.nginx: Destruction complete after 1s
docker_image.nginx: Destroying... [id=sha256:e4720093a3c1381245b53a5a51b417963b3c4472d3f47fc301930a4f3b17666anginx:latest]

Destroy complete! Resources: 3 destroyed.