Kembali ke seri

Variabel dan Output di OpenTofu

Pelajari cara membuat konfigurasi OpenTofu modular dan dinamis menggunakan variables.tf, outputs.tf, terraform.tfvars, validasi kustom, serta tipe data kompleks.

Daftar Isi

Pada bagian sebelumnya, kita menuliskan seluruh konfigurasi infrastruktur dalam satu file main.tf dengan nilai yang bersifat statis (hardcoded). Pendekatan tersebut memadai untuk latihan awal, namun di lingkungan nyata, konfigurasi harus fleksibel agar dapat digunakan ulang di berbagai environment (development, staging, hingga production).

OpenTofu secara otomatis membaca dan menggabungkan seluruh file berekstensi .tf yang berada di dalam direktori kerja yang sama. Dengan memecah konfigurasi menjadi beberapa file terpisah berdasarkan fungsinya, basis kode Anda menjadi jauh lebih rapi, terstruktur, dan mudah dirawat.


Struktur File Modular

Konvensi standar proyek OpenTofu memisahkan deklarasi input, logika resource, dan nilai kembalian ke dalam struktur berkas berikut:

infra/
├── main.tf           # Logika resource dan provider
├── variables.tf      # Deklarasi variabel input dan validasinya
├── outputs.tf        # Deklarasi nilai output yang diekspos
└── terraform.tfvars  # Nilai variabel konkret untuk environment tertentu (opsional)

1. Deklarasi Input (variables.tf)

File variables.tf berfungsi layaknya parameter fungsi dalam pemrograman. Di sini Anda mendefinisikan variabel apa saja yang dapat diterima oleh konfigurasi, tipe data yang diizinkan, nilai default, hingga aturan validasi kustom.

variable "container_name" {
  description = "Nama container Docker di host"
  type        = string
  default     = "belajar-opentofu-nginx"
}

variable "nginx_image" {
  description = "Docker image beserta tag versi"
  type        = string
  default     = "nginx:alpine"
}

variable "external_port" {
  description = "Port host lokal yang di-forward ke port internal container"
  type        = number
  default     = 8080

  # Validasi kustom untuk memastikan nomor port valid
  validation {
    condition     = var.external_port > 0 && var.external_port <= 65535
    error_message = "Nomor port harus berada di rentang 1 sampai 65535."
  }
}

variable "enable_ssl" {
  description = "Menentukan apakah konfigurasi HTTPS diaktifkan"
  type        = bool
  default     = false
}

Anatomi Blok variable

  • type: Menentukan tipe data variabel (misal: string, number, bool, list, map, atau object). Jika diabaikan, tipenya otomatis dianggap any, tetapi sangat disarankan untuk selalu mendeklarasikan tipe secara eksplisit.
  • default: Nilai acuan jika pengguna tidak menyediakan nilai lain. Variabel tanpa nilai default berstatus required (wajib diisi oleh pengguna saat runtime).
  • description: Dokumentasi singkat mengenai tujuan variabel tersebut.
  • validation: Blok evaluasi aturan logika (condition) yang menghasilkan pesan error (error_message) jika input pengguna melanggar aturan.
  • sensitive: Jika bernilai true, OpenTofu akan menyembunyikan nilai variabel ini dari log terminal pada saat tofu plan dan tofu apply (sangat krusial untuk token API atau kata sandi).

2. Menggunakan Variabel di Kode Utama (main.tf)

Resource di dalam main.tf tidak lagi menggunakan nilai statis, melainkan merujuk ke variabel menggunakan sintaks var.<nama_variabel>:

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

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

# Mengunduh image sesuai variabel var.nginx_image
resource "docker_image" "nginx" {
  name         = var.nginx_image
  keep_locally = false
}

# Membuat container menggunakan variabel input
resource "docker_container" "web" {
  image = docker_image.nginx.image_id
  name  = var.container_name

  ports {
    internal = 80
    external = var.external_port
  }
}

3. Mengekstrak Hasil Eksekusi (outputs.tf)

File outputs.tf mendefinisikan data penting yang ingin diekspos setelah proses tofu apply berhasil dieksekusi. Output ini berguna untuk menampilkan informasi ke terminal pengguna, diintegrasikan ke skrip CI/CD, atau dipanggil oleh modul OpenTofu lainnya.

output "container_id" {
  description = "ID unik Docker container yang dibuat"
  value       = docker_container.web.id
}

output "web_url" {
  description = "URL akses web service melalui peramban"
  value       = "http://localhost:${var.external_port}"
}

output "image_digest" {
  description = "SHA digest dari Docker image yang digunakan"
  value       = docker_image.nginx.repo_digest
}

Setelah eksekusi selesai, Anda dapat melihat seluruh nilai output kapan saja tanpa perlu menjalankan apply ulang dengan perintah:

tofu output

Atau menampilkan nilai output tertentu secara spesifik:

tofu output web_url
# "http://localhost:8080"

4. Menyuplai Nilai Variabel (terraform.tfvars)

Jika Anda ingin mengubah nilai variabel tanpa menyentuh file .tf, Anda dapat membuat file bernama terraform.tfvars.

File terraform.tfvars otomatis dimuat oleh OpenTofu setiap kali perintah tofu plan atau tofu apply dijalankan:

container_name = "web-custom-staging"
external_port  = 9090
nginx_image    = "nginx:1.27-alpine"

Urutan Prioritas Variabel (Variable Precedence)

Bagaimana jika sebuah variabel didefinisikan di beberapa tempat sekaligus? OpenTofu mengevaluasi variabel berdasarkan hierarki urutan prioritas (dari prioritas tertinggi ke terendah):

  1. CLI Flag Langsung (-var atau -var-file):
    tofu apply -var="external_port=8888"
  2. File Otomatis *.auto.tfvars atau *.auto.tfvars.json (diurutkan berdasarkan nama file alfabetis).
  3. File terraform.tfvars atau terraform.tfvars.json.
  4. Environment Variables dengan prefiks TF_VAR_:
    export TF_VAR_external_port=9000
  5. Nilai default yang dideklarasikan di dalam blok variable pada file variables.tf.

Praktik Terbaik: Masukkan file *.tfvars yang memuat kredensial atau rahasia sensitif ke dalam berkas .gitignore. Buat file terraform.tfvars.example sebagai panduan konfigurasi bagi anggota tim lain.


5. Tipe Data Lanjutan di OpenTofu

Selain tipe data primitif (string, number, bool), OpenTofu mendukung tipe data koleksi (collection) dan struktural (structural) untuk skenario infrastruktur yang lebih kompleks.

A. List (Daftar Berurutan)

list menyimpan sekumpulan nilai dengan tipe data yang seragam dalam urutan indeks tertentu:

variable "allowed_ports" {
  description = "Daftar port yang diizinkan untuk diakses"
  type        = list(number)
  default     = [80, 443, 8080]
}

# Contoh pengaksesan elemen list:
# var.allowed_ports[0]  -> 80
# var.allowed_ports[1]  -> 443

B. Map (Pasangan Kunci dan Nilai)

map menyimpan pasangan key-value di mana semua nilainya memiliki tipe data yang sama. Sangat ideal untuk pelabelan (tags) atau pemetaan konfigurasi berdasarkan nama environment:

variable "container_labels" {
  description = "Label metadata untuk container"
  type        = map(string)
  default = {
    environment = "development"
    owner       = "devops-team"
    project     = "updeta-tutorial"
  }
}

# Contoh pengaksesan nilai map:
# var.container_labels["environment"]  -> "development"

C. Object (Struktur Data Kompleks)

object memungkinkan Anda membuat skema kustom dengan properti atribut yang memiliki tipe data berbeda-beda:

variable "server_config" {
  description = "Spesifikasi lengkap server"
  type = object({
    hostname      = string
    memory_mb     = number
    restart_policy = string
    is_production  = bool
  })
  default = {
    hostname       = "nginx-server"
    memory_mb      = 512
    restart_policy = "unless-stopped"
    is_production  = false
  }
}

# Akses atribut:
# var.server_config.hostname   -> "nginx-server"
# var.server_config.memory_mb  -> 512

D. Kombinasi Koleksi: list(object)

Untuk mengelola sekumpulan resource berulang (seperti banyak port binding atau volume mount), gunakan list(object):

variable "port_mappings" {
  description = "Daftar pemetaan port container ke host"
  type = list(object({
    internal = number
    external = number
    protocol = string
  }))
  default = [
    {
      internal = 80
      external = 8080
      protocol = "tcp"
    },
    {
      internal = 443
      external = 8443
      protocol = "tcp"
    }
  ]
}

# Mengakses elemen pertama:
# var.port_mappings[0].internal -> 80
# var.port_mappings[0].external -> 8080

6. Praktik Pengujian

Sekarang mari uji konfigurasi modular yang telah dibuat:

1. Uji Coba Override Nilai via terraform.tfvars

Pastikan file terraform.tfvars sudah dibuat dengan isi port 9090:

tofu plan

Perhatikan output rencana: OpenTofu akan mendeteksi bahwa port yang akan dipetakan adalah 9090 (menggantikan nilai default 8080).

2. Terapkan Konfigurasi

tofu apply -auto-approve

Setelah selesai, periksa output yang tercetak:

Outputs:

container_id = "5a2f8c4e..."
image_digest = "sha256:..."
web_url      = "http://localhost:9090"

Uji web server Anda melalui terminal atau peramban:

curl http://localhost:9090

3. Menguji Validasi Kustom

Coba override variabel dengan nilai port yang tidak valid untuk melihat bagaimana blok validation bekerja:

tofu plan -var="external_port=70000"

OpenTofu akan langsung menolak eksekusi dan mencetak pesan kesalahan yang telah kita definisikan:

Error: Invalid value for variable

  on variables.tf line 13:
  13: variable "external_port" {

Nomor port harus berada di rentang 1 sampai 65535.

Fitur validasi ini sangat ampuh mencegah kesalahan konfigurasi sebelum perintah benar-benar menyentuh infrastruktur nyata.


Rangkuman & Langkah Berikutnya

Dalam artikel ini, Anda telah mempelajari:

  • Cara memecah konfigurasi menjadi file terpisah: variables.tf, main.tf, outputs.tf, dan terraform.tfvars.
  • Cara mendeklarasikan variabel dengan tipe data, deskripsi, nilai default, dan blok validation.
  • Hirarki urutan prioritas variabel OpenTofu (precedence).
  • Penggunaan tipe data tingkat lanjut: list, map, object, dan list(object).
  • Cara mengekstrak hasil eksekusi menggunakan outputs.tf dan perintah tofu output.

Pada bagian selanjutnya, kita akan membahas State Management dan Remote Backend—mempelajari bagaimana tim berkolaborasi menggunakan OpenTofu secara aman tanpa benturan file state menggunakan S3 atau backend kompatibel lainnya.


Referensi