Terraform AWS Cloud: Manajemen Infrastruktur yang Sehat

Diterbitkan: 2022-03-11

Menulis aplikasi hanyalah bagian dari cerita. Agar bernilai, perlu diterapkan di suatu tempat yang dapat diskalakan, harus dijalankan dengan ketersediaan tinggi, perlu dicadangkan, dan seterusnya.

Semakin banyak pengembang diminta untuk setidaknya memahami proses penerapan ini. Ini bermanifestasi sebagai, misalnya, di DevOps menjadi peran yang sering diminta saat ini, seiring dengan meningkatnya kompleksitas sistem. Kita tidak bisa membiarkan diri kita mengabaikan perubahan tersebut dan perlu menyadari bagaimana merancang aplikasi agar mudah diterapkan.

Ini juga untuk kepentingan klien kami: Mereka mempekerjakan kami sebagai ahli di bidang kami dan mengharapkan kami untuk memberikan seluruh produk, seringkali dari awal hingga akhir. Mereka memiliki persyaratan dan sering tidak menyadari tumpukan solusi bisnis yang mereka jalankan. Pada akhirnya, itu adalah nilai bisnis dari produk yang penting.

Memperkenalkan Terraform

Penerapan dan manajemen infrastruktur bukanlah proses yang sederhana. Di atas banyak keahlian domain yang selalu berubah, kita perlu mempelajari Alat Lain atau alur kerja baru. Jika Anda telah menundanya, artikel ini adalah kesempatan bagi Anda untuk mengenal satu pendekatan manajemen infrastruktur. Saya berharap pada akhirnya Anda akan lebih percaya diri dalam menggunakan Terraform dan mengetahui lebih banyak tentang kemungkinan pendekatan dan tantangannya. Anda harus dapat menggunakan alat ini untuk setidaknya mulai mengelola beberapa bagian dari infrastruktur cloud Anda.

Terraform adalah lapisan abstraksi, ya, dan abstraksi bocor, saya setuju. Tetapi pada akhirnya, kita berada dalam bisnis memecahkan masalah dan mengelola abstraksi. Yang ini bertujuan untuk memberi kita lebih banyak kewarasan dalam tugas kita sehari-hari.

Target

Saya akan menjelaskan apa itu Terraform, bagaimana itu cocok dengan seluruh ekosistem, dan bagaimana perbandingannya dengan alat serupa lainnya. Kemudian saya akan menunjukkan kepada Anda langkah-langkah yang diperlukan untuk mengonfigurasi penyiapan Terraform multi-lingkungan dan siap produksi untuk sebuah tim. Saya akan menjelaskan dasar-dasar penulisan konfigurasi Terraform—cara mengelola kompleksitas dan kode duplikat dengan modul yang dapat dibagikan.

Semua contoh akan difokuskan pada satu penyedia cloud: Amazon Web Services (AWS). Ini hanyalah awan yang paling saya miliki pengalamannya tetapi semua informasi harus berlaku untuk awan lain juga.

Saya akan mengakhiri dengan beberapa catatan yang saya harap saya ketahui ketika saya mulai: beberapa sintaks gotcha, kebiasaan, dan kasus di mana Terraform tidak akan menjadi alat pilihan saya.

Saya tidak akan fokus pada detail seluk beluk sintaksis. Anda dapat dengan cepat mengetahuinya dengan membaca dokumentasi dan panduan fantastis yang disediakan HashiCorp untuk Terraform. Saya ingin fokus pada hal-hal yang mungkin tidak jelas dari awal dan yang saya harap saya ketahui sebelum saya mulai bekerja dengan Terraform. Mudah-mudahan, ini akan mengarahkan Anda ke arah yang benar dan memungkinkan Anda mempertimbangkan Terraform sebagai alat untuk digunakan dalam proyek mendatang.

Manajemen Infrastruktur Itu Sulit

Ada beberapa langkah yang terlibat dalam menyiapkan lingkungan untuk aplikasi di cloud. Kecuali Anda menuliskan semuanya sebagai daftar periksa yang terperinci dan mengikutinya dengan cermat, sepanjang waktu, Anda akan membuat kesalahan; kita adalah manusia, setelah semua. Langkah-langkah itu sulit untuk dibagikan. Anda perlu mendokumentasikan banyak prosedur manual dan dokumen dapat dengan cepat menjadi usang. Sekarang kalikan semua itu dengan jumlah total lingkungan untuk satu aplikasi: dev , test/qa , stage , dan prod . Anda juga perlu memikirkan keamanan untuk masing-masing.

Bukankah Setiap Alat Memiliki UI yang Dapat Saya Gunakan dan Lupakan Kompleksitasnya?

Mereka memang memiliki UI—AWS Management Console adalah contoh utama. Tetapi alat-alat itu melakukan banyak hal di bawah tenda. Satu klik pada UI sebenarnya dapat memicu serangkaian perubahan yang sulit dipahami. Biasanya tidak ada cara untuk membatalkan apa yang Anda lakukan di UI (perintah "Apakah Anda yakin?" yang biasa sering kali tidak cukup). Selain itu, selalu merupakan ide yang baik untuk memiliki sepasang mata kedua untuk memeriksa perubahan, tetapi ketika kami menggunakan UI, kami perlu duduk bersama orang ini atau memeriksa perubahan kami setelah dibuat, yang lebih merupakan audit daripada a tinjauan. Setiap penyedia cloud memiliki UI sendiri yang perlu Anda kuasai. UI dirancang agar mudah digunakan (tidak harus sederhana!) dan karena itu rentan terhadap pendekatan delusi seperti "ini hanya tweak kecil", atau hotfix produksi cepat yang akan Anda lupakan dalam 48 jam. Mengklik manual seperti itu juga sangat sulit untuk diotomatisasi.

Bagaimana dengan Alat CLI?

Mereka akan lebih baik daripada alat UI untuk kasus penggunaan kami. Namun, Anda masih cenderung melakukan perubahan dengan tangan atau menulis skrip bash yang dapat dengan mudah lepas kendali. Selain itu, setiap penyedia memiliki alat CLI mereka sendiri. Dengan alat-alat itu, Anda tidak dapat melihat perubahan Anda sebelum Anda berkomitmen pada mereka. Untungnya ini bukan masalah baru dan ada alat yang membantu dalam hal ini.

Orkestrasi vs. Manajemen Konfigurasi

Saya akan mendefinisikan beberapa kategori alat dan praktik yang digunakan untuk mengelola infrastruktur. Ini adalah orkestrasi dan manajemen konfigurasi. Anda dapat menganggapnya secara kasar sebagai model pemrograman deklaratif dan imperatif (pikirkan Prolog vs. Python). Masing-masing memiliki pro dan kontra, tetapi yang terbaik adalah mengetahui semuanya dan menerapkan alat terbaik untuk pekerjaan tertentu. Juga, orkestrasi biasanya melibatkan tingkat abstraksi yang lebih tinggi daripada manajemen konfigurasi.

Orkestrasi

Orkestrasi lebih menyerupai paradigma pemrograman deklaratif. Saya suka menganggapnya sebagai konduktor orkestra. Karya seorang konduktor diringkas dengan baik oleh Wikipedia (tautan) sebagai "seni mengarahkan kinerja simultan dari beberapa pemain atau penyanyi dengan menggunakan gerakan." Konduktor mengomunikasikan ketukan dan tempo, dinamika, dan isyarat musik tetapi pekerjaan sebenarnya dilakukan oleh musisi individu yang ahli memainkan alat musik mereka. Tanpa koordinasi seperti itu, mereka tidak akan mampu menampilkan karya yang sempurna.

Di sinilah Terraform cocok. Anda menggunakannya untuk melakukan bagian dari infrastruktur TI: Anda memberi tahu apa yang diterapkan, dan Terraform menautkan semuanya bersama-sama dan melakukan semua panggilan API yang diperlukan. Ada alat serupa di ruang ini; salah satu yang paling terkenal adalah AWS Cloud Formation. Ini memiliki dukungan yang lebih baik untuk pemulihan dan rollback jika terjadi kesalahan daripada Terraform, tetapi juga, menurut saya, kurva belajar yang lebih curam. Ini juga bukan cloud-agnostic: Ini hanya berfungsi dengan hanya dengan AWS.

Manajemen konfigurasi

Sisi pelengkap dari praktik ini adalah pendekatan manajemen konfigurasi. Dalam paradigma ini, Anda menentukan langkah-langkah tepat yang harus dilakukan alat untuk sampai pada konfigurasi yang diinginkan dan diberikan. Langkah-langkahnya sendiri mungkin kecil dan mendukung banyak sistem operasi, tetapi Anda harus secara aktif memikirkan urutan pelaksanaannya. Mereka tidak memiliki kesadaran tentang keadaan dan lingkungan saat ini (kecuali Anda memprogramnya dengan itu) dan, dengan demikian, akan secara membabi buta menjalankan langkah apa pun yang Anda berikan kepada mereka. Ini dapat menyebabkan masalah yang dikenal sebagai penyimpangan konfigurasi , di mana sumber daya Anda akan perlahan-lahan tidak sinkron dengan apa yang awalnya dimaksudkan untuk diwakili, terutama jika Anda membuat beberapa perubahan manual pada sumber daya tersebut. Mereka hebat dalam mengelola dan menyediakan layanan pada masing-masing instans. Contoh alat yang unggul dalam alur kerja ini adalah Chef, Puppet, Ansible, dan Salt.

Orkestrasi memberlakukan pendekatan ke infrastruktur Anda di mana Anda memperlakukan sumber daya Anda sebagai ternak, bukan sebagai hewan peliharaan. Alih-alih "memelihara" setiap VPS secara manual, Anda dapat menggantinya dengan salinan persis ketika terjadi kesalahan. Saya tidak bermaksud bahwa Anda tidak peduli dan memulai kembali dengan berharap yang terbaik.

Meme acara IT Crowd TV dengan tagline ikonik mereka: Sudahkah Anda mencoba mematikannya dan menghidupkannya lagi?

Sebagai gantinya, Anda harus menyelidiki dan memperbaiki masalah dalam kode dan kemudian menerapkannya.

Ansible (dan alat CM lainnya) dapat digunakan untuk mengelola infrastruktur AWS, tetapi ini akan melibatkan banyak pekerjaan dan lebih rawan kesalahan, terutama ketika infrastruktur sering berubah dan semakin kompleks.

Satu hal penting untuk diingat adalah bahwa pendekatan manajemen orkestrasi dan konfigurasi tidak saling bertentangan. Mereka kompatibel. Tidak masalah untuk memiliki grup instans EC2 (VPS) dalam grup AutoScaling yang dikelola oleh Terraform tetapi menjalankan AWS Application Image (AMI), yang merupakan snapshot dari disk, yang disiapkan dengan langkah-langkah penting dengan, misalnya, Ansible . Terraform bahkan memiliki konsep "penyedia" yang memungkinkan Anda menjalankan alat penyediaan eksternal setelah mesin melakukan booting.

Dokumentasi Terraform sangat membantu dalam menjelaskan hal ini lebih lanjut dan membantu Anda menempatkan Terraform di seluruh ekosistem.

Apa itu Terraform?

Ini adalah alat sumber terbuka, dibuat oleh HashiCorp yang memungkinkan Anda untuk mengkodifikasi infrastruktur Anda sebagai file konfigurasi deklaratif yang diversi dan dibagikan dan dapat ditinjau.

Nama HashiCorp harus membunyikan lonceng — mereka juga membuat Nomad, Vault, Packer, Vagrant, dan Consul. Jika Anda telah menggunakan salah satu dari alat tersebut, Anda sudah mengetahui kualitas dokumentasi, komunitas yang dinamis, dan kegunaan yang dapat Anda harapkan dari solusi mereka.

Infrastruktur sebagai Kode

Terraform adalah platform-agnostik; Anda dapat menggunakannya untuk mengelola server bare metal atau server cloud seperti AWS, Google Cloud Platform, OpenStack, dan Azure. Dalam istilah Terraform, ini disebut penyedia , Anda bisa mengetahui skalanya dengan membaca daftar lengkap penyedia yang didukung. Beberapa penyedia dapat digunakan secara bersamaan, misalnya ketika penyedia A mengonfigurasi VM untuk Anda, tetapi penyedia B mengonfigurasi dan mendelegasikan catatan DNS.

Apakah itu berarti bahwa seseorang dapat beralih penyedia cloud dengan satu perubahan dalam file konfigurasi? Tidak, saya bahkan tidak berpikir Anda menginginkan itu, setidaknya tidak secara otomatis. Masalahnya adalah bahwa penyedia yang berbeda mungkin memiliki kemampuan yang berbeda, penawaran yang berbeda, aliran, ide, dll. Ini berarti Anda harus menggunakan sumber daya yang berbeda untuk penyedia yang berbeda untuk mengekspresikan konsep yang sama. Namun, ini semua masih dapat dilakukan dalam satu sintaks konfigurasi yang familier dan menjadi bagian dari alur kerja yang kohesif.

Bagian Penting dari Pengaturan Terraform

  1. Biner Terraform itu sendiri, yang harus Anda instal
  2. File kode sumber, yaitu konfigurasi Anda
  3. Status (baik lokal atau jauh) yang mewakili sumber daya yang dikelola Terraform (lebih lanjut nanti)

Menulis Konfigurasi Terraform

Anda menulis kode konfigurasi Terraform dalam file *.tf menggunakan bahasa HCL. Ada opsi untuk menggunakan format JSON ( *.tf.json ), tetapi ditargetkan pada mesin dan pembuatan otomatis daripada manusia. Saya sarankan Anda tetap menggunakan HCL. Saya tidak akan menyelam jauh ke dalam sintaks bahasa HCL; dokumen resmi melakukan pekerjaan yang fantastis untuk menjelaskan cara menulis HCL dan cara menggunakan variabel dan interpolasi. Saya hanya akan menyebutkan minimal yang diperlukan untuk memahami contoh.

Di dalam file Terraform, Anda sebagian besar berurusan dengan sumber daya dan sumber data . Sumber daya mewakili komponen infrastruktur Anda, misalnya, instans AWS EC2, instans RDS, catatan DNS Route53, atau aturan dalam grup keamanan. Mereka memungkinkan Anda untuk menyediakan dan mengubahnya di dalam arsitektur cloud.

Dengan asumsi Anda telah mengatur Terraform, jika Anda mengeluarkan terraform apply , kode di bawah ini akan membuat instance EC2 yang berfungsi penuh (hanya properti tertentu yang ditampilkan):

 resource "aws_instance" "bastion" { ami = "ami-db1688a2" # Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type - ami-db1688a2 instance_type = "t2.nano" key_name = "${var.key_name}" subnet_ vpc_security_group_ids = ["${aws_security_group.bastion.id}"] monitoring = "false" associate_public_ip_address = "true" disable_api_termination = "true" tags = { Name = "${var.project_tag}-bastion-${var.env}" Env = "${var.env}" Application ApplicationRole = "Bastion Host" Project = "${var.project_tag}" } }

Di sisi lain, ada sumber data yang memungkinkan Anda membaca data tentang komponen tertentu tanpa mengubahnya. Anda ingin mendapatkan ID AWS (ARN) dari sertifikat yang diterbitkan ACM? Anda menggunakan sumber data. Perbedaannya adalah bahwa sumber data diawali dengan data_ saat mereferensikannya di file konfigurasi.

 data "aws_acm_certificate" "ssl_cert" { domain = "*.example.com" statuses = ["ISSUED"] }

Referensi di atas merujuk pada sertifikat SSL ACM yang diterbitkan yang dapat digunakan bersama dengan AWS ALB. Sebelum Anda melakukan itu semua, Anda perlu mengatur lingkungan Anda.

Struktur Folder

Lingkungan Terraform (dan statusnya) dipisahkan oleh direktori. Terraform memuat semua file *.tf dalam direktori ke dalam satu namespace, jadi urutannya tidak masalah. Saya merekomendasikan struktur direktori berikut:

 /terraform/ |---> default_variables.tf (1) /stage/ (2) |---> terraform.tfvars (3) |---> default_variables.tf (4) |---> terraform.tf (5) |---> env_variables.tf (6) /prod/ /<env_name>/
  1. default_variables.tf – mendefinisikan semua variabel tingkat atas dan secara opsional nilai defaultnya. Mereka dapat digunakan kembali di setiap lingkungan (direktori bersarang) dengan symlink.
  2. /stage/ – direktori yang menyimpan konfigurasi untuk seluruh lingkungan yang terpisah (di sini bernama stage , tetapi bisa apa saja). Setiap perubahan yang dibuat di dalam folder ini benar-benar independen dari lingkungan lain (env—seperti prod ) yang merupakan sesuatu yang Anda inginkan untuk menghindari mengacaukan env produksi dengan perubahan yang dibuat ke stage !
  3. terraform.tfvars – menentukan nilai variabel. File .tfvars mirip dengan file .env karena memiliki pasangan key=val untuk variabel yang ditentukan. Misalnya, ini menentukan profile AWS , AWS key_name dan AWS key_path yang saya gunakan. Itu bisa diabaikan di Git.
  4. default_variables.tf – ini adalah symlink ke file (2), yang memungkinkan kita untuk berbagi variabel env-independen tanpa mengulangi diri kita sendiri.
  5. terraform.tf – ini adalah konfigurasi utama dari setiap env; ini menampung blok terraform {} yang mengonfigurasi back-end. Saya juga mengonfigurasi penyedia di sini.
  6. env_variables.tf – file ini menyimpan variabel khusus env. Saya menandai semua sumber daya dengan Env=<env_name> di AWS, jadi file ini biasanya hanya mendefinisikan satu variabel: env .

Tentu saja, ini bukan satu-satunya cara untuk menata lingkungan Anda. Ini hanya sesuatu yang bekerja dengan baik untuk saya dengan memungkinkan pemisahan yang jelas dari masalah.

Konfigurasi Back-end

Saya sudah menyebutkan keadaan Terraform. Ini adalah bagian penting dari alur kerja Terraform. Anda mungkin bertanya-tanya apakah status benar-benar diperlukan. Tidak bisakah Terraform menanyakan AWS API sepanjang waktu untuk mendapatkan status infrastruktur yang sebenarnya? Nah, jika Anda memikirkannya, Terraform perlu mempertahankan pemetaan antara apa yang dikelolanya dalam file konfigurasi deklaratif dan apa yang sebenarnya sesuai dengan file tersebut (di lingkungan penyedia cloud). Perhatikan bahwa, saat menulis file konfigurasi Terraform, Anda tidak peduli dengan ID, misalnya, instans EC2 individu atau ARN yang akan dibuat untuk grup keamanan yang Anda publikasikan. Namun, secara internal, Terraform perlu mengetahui bahwa blok sumber daya yang diberikan mewakili sumber daya konkret dengan ID/ARN. Ini diperlukan untuk mendeteksi perubahan. Selain itu, status digunakan untuk melacak ketergantungan antar sumber daya (juga sesuatu yang biasanya tidak perlu Anda pikirkan!). Mereka digunakan untuk membangun grafik yang dapat (biasanya) diparalelkan dan dieksekusi. Seperti biasa, saya sarankan Anda membaca dokumentasi yang sangat baik tentang status Terraform dan tujuannya.

Karena status adalah satu-satunya sumber kebenaran untuk arsitektur Anda, Anda perlu memastikan bahwa Anda dan tim Anda selalu mengerjakan versi terbarunya dan bahwa Anda tidak membuat konflik dengan akses yang tidak disinkronkan ke status. Anda tidak ingin menyelesaikan konflik gabungan pada file negara, percayalah.

Secara default, Terraform menyimpan status dalam file pada disk, yang terletak di direktori kerja saat ini (dari setiap env) sebagai file terraform.tfstate . Tidak apa-apa jika Anda tahu bahwa Anda akan menjadi satu-satunya pengembang yang bekerja atau baru belajar dan bereksperimen dengan Terraform. Secara teknis, Anda dapat membuatnya bekerja dalam tim karena Anda dapat mengkomit status ke repositori VCS. Tapi kemudian, Anda perlu memastikan semua orang selalu bekerja pada versi terbaru dari negara bagian dan tidak ada yang melakukan perubahan pada saat yang sama! Ini umumnya sakit kepala besar dan saya sangat menyarankan untuk tidak melakukannya. Selain itu, jika seseorang bergabung dengan operasi single-dev Anda, Anda masih harus mengonfigurasi tempat alternatif untuk status.

Untungnya, ini adalah masalah dengan solusi bagus yang dibangun ke Terraform: yang disebut Remote State . Agar status jarak jauh berfungsi, Anda perlu mengonfigurasi back-end menggunakan salah satu penyedia back-end yang tersedia. Contoh back-end berikut akan didasarkan pada AWS S3 dan AWS DynamoDB (basis data AWS NoSQL). Anda hanya dapat menggunakan S3 tetapi kemudian Anda kehilangan mekanisme penguncian status dan pemeriksaan konsistensi (tidak disarankan). Jika sebelumnya Anda hanya menggunakan status lokal, mengonfigurasi back-end jarak jauh akan menawarkan opsi untuk memigrasikan status Anda pertama kali, sehingga Anda tidak kehilangan apa pun. Anda dapat membaca lebih lanjut tentang konfigurasi back-end di sini.

Sayangnya, ada masalah ayam dan telur: Bucket S3 dan tabel DynamoDB harus dibuat secara manual. Terraform tidak dapat membuatnya secara otomatis karena belum ada status! Nah, ada beberapa solusi seperti https://github.com/gruntwork-io/terragrunt yang mengotomatiskan itu menggunakan AWS CLI, tetapi saya tidak ingin menyimpang dari topik utama posting blog ini.

Hal penting yang perlu diketahui tentang konfigurasi backend S3 dan DynamoDB adalah:

  1. Aktifkan pembuatan versi pada bucket S3 agar aman dari kesalahan manusia dan Hukum Murphy.
  2. Tabel DynamoDB memiliki batas kecepatan untuk membaca dan menulis (disebut kapasitas). Jika Anda membuat banyak perubahan pada status jarak jauh, pastikan untuk mengaktifkan DynamoDB AutoScaling untuk tabel tersebut atau mengonfigurasi batas R/W yang cukup tinggi. Jika tidak, Terraform akan mendapatkan kesalahan HTTP 400 dari AWS API saat menjalankan banyak panggilan.

Singkatnya, konfigurasi back-end berikut dapat ditempatkan di terraform.tf untuk mengonfigurasi status jarak jauh pada S3 dan DynamoDB.

 terraform { # Sometimes you may want to require a certain version of Terraform required_version = ">= 0.11.7" # Stores remote state, required for distributed teams # Bucket & dynamoDB table have to be created manually if they do not exist # See: https://github.com/hashicorp/terraform/issues/12780 backend "s3" { bucket = "my-company-terraform-state" key = "app-name/stage" region = "eu-west-1" # 5/5 R/W Capacity might not be enough for heavy, burst work (resulting in 400s). Consider enabling Auto Scaling on the table. # See: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ProvisionedThroughput.html dynamodb_table = "terraform-state-lock-table" } }

Ini banyak yang harus diambil sekaligus, tapi ingat, Anda melakukan ini sekali untuk setiap env dan kemudian bisa melupakannya. Jika Anda membutuhkan lebih banyak kontrol atas penguncian negara, ada HashiCorp Terraform Enterprise, tetapi saya tidak akan membahasnya di sini.

Penyedia

Agar back-end ini dapat diakses dan dapat berkomunikasi dengan penyedia cloud kami sama sekali, kami perlu mengonfigurasi apa yang disebut penyedia . Blok berikut dapat ditempatkan di file terraform.tf (untuk setiap env):

 provider "aws" { profile = "${var.profile}" region = "${var.region}" version = "~> 1.23.0" }

Variabel untuk profile dan region disimpan dalam file terraform.tfvars , yang dapat diabaikan. Variabel profile mengacu pada profil bernama yang memegang kredensial keamanan untuk AWS cloud menggunakan file kredensial standar. Perhatikan bahwa saya juga menetapkan beberapa batasan versi. Anda tidak ingin Terraform meningkatkan plugin penyedia Anda tanpa sepengetahuan Anda pada setiap inisialisasi back-end. Terutama mengingat ada versi 2.x dari penyedia AWS yang memerlukan peningkatan yang cermat.

Inisialisasi Back-end

Setiap konfigurasi back-end memerlukan langkah inisialisasi di awal dan setiap kali ada perubahan yang dilakukan. Inisialisasi juga mengonfigurasi modul Terraform (lebih lanjut tentang itu nanti), jadi ketika Anda menambahkannya, Anda juga perlu menjalankan kembali langkah init. Operasi ini aman untuk dijalankan beberapa kali. Perhatikan bahwa, selama inisialisasi back-end, tidak semua variabel dapat dibaca oleh Terraform untuk mengonfigurasi status, juga tidak boleh karena alasan keamanan (misalnya, kunci rahasia). Untuk mengatasinya dan, dalam kasus kami, gunakan profil AWS yang berbeda dari default, Anda dapat menggunakan opsi -backend-config dengan menerima pasangan variabel k=v . Ini disebut konfigurasi parsial.

 terraform init -backend-config=profile=<aws_profile_name>

File Terraform berbagi ruang lingkup yang dibatasi ke direktori tertentu. Ini berarti bahwa sub-folder tidak terhubung langsung ke kode direktori induk. Namun, ini mendefinisikan modul yang memungkinkan penggunaan kembali kode, manajemen kompleksitas, dan berbagi.

Alur Kerja

Alur kerja umum saat bekerja dengan kode Terraform adalah sebagai berikut:

  1. Tulis konfigurasi untuk infrastruktur Anda.
  2. Lihat perubahan aktual apa yang akan dibuatnya ( terraform plan ).
  3. Secara opsional, jalankan perubahan persis seperti yang Anda lihat di langkah 2 ( terraform apply ).
  4. GOTO 1

Rencana Terraform

Perintah plan Terraform akan memberi Anda daftar perubahan yang akan dilakukan pada infrastruktur Anda setelah mengeluarkan perintah apply . Aman untuk mengeluarkan plan beberapa kali, karena dengan sendirinya tidak mengubah apa pun.

Cara Membaca Rencana

Objek di Terraform (sumber daya dan sumber data) mudah diidentifikasi dengan nama yang sepenuhnya memenuhi syarat.

  1. Dalam hal sumber daya, ID mungkin terlihat seperti: <resource_type>.<resource_name> —misalnya, aws_ecs_service.this .
  2. Dalam hal sumber daya di dalam modul, kami memiliki nama modul tambahan: module.<module_name>.<resource_type>.<resource_name> —misalnya, module.my_service_ecs_service_task.aws_ecs_service.this .
  3. Sumber data (di dalam dan di luar modul): (module.<module_name>).data.<resource_type>.<resource_name> —misalnya, module.my_service_ecs_service_task.data.aws_ecs_task_definition.this .

Jenis sumber daya khusus untuk penyedia tertentu dan biasanya menyertakan namanya ( aws_… ). Seluruh daftar sumber daya yang tersedia untuk AWS dapat ditemukan di dokumen.

Ada lima tindakan yang akan ditunjukkan oleh rencana untuk sumber daya yang diberikan:

  1. [+] Tambah – Sumber daya baru akan dibuat.
  2. [-] Hancurkan – Sumber daya akan dihancurkan sepenuhnya.
  3. [~] Modifikasi di tempat – Sumber daya akan dimodifikasi dan satu atau lebih parameter akan diubah. Ini umumnya aman. Terraform akan menunjukkan kepada Anda parameter mana yang akan dimodifikasi dan bagaimana caranya (jika memungkinkan).
  4. [- / +] – Sumber daya akan dihapus dan kemudian dibuat ulang dengan parameter baru. Ini terjadi jika perubahan dibuat pada parameter yang tidak dapat diubah di tempat. Terraform akan menunjukkan kepada Anda perubahan mana yang memaksa rekreasi sumber daya dengan komentar berikut berwarna merah: (forces new resource) . Ini berpotensi berbahaya, karena ada periode di mana sumber daya tidak akan ada sama sekali. Itu juga dapat merusak dependensi lain yang terhubung. Saya akan merekomendasikan untuk mengatasi perubahan seperti itu kecuali Anda tahu apa konsekuensinya atau tidak peduli dengan waktu henti.
  5. [<=] – Sumber data akan dibaca. Ini adalah operasi baca-saja.

Terraform AWS — contoh "rencana"

Di atas adalah contoh rencana. Perubahan yang saya lakukan adalah:

  • Mengubah instance_type dari instance benteng pertama
  • Menambahkan instance benteng kedua
  • Mengubah nama grup keamanan

Perhatikan bahwa perubahan terakhir adalah aturan grup keamanan yang secara otomatis mendeteksi perubahan nama grup induk. Menurut pendapat saya, seluruh rencana sangat mudah dibaca. Beberapa nilai parameter ditampilkan sebagai <computed> —itu tidak berarti mereka akan diubah, melainkan bahwa mereka tidak dapat diambil dan disajikan pada tahap ini (seperti nama SG yang belum dibuat). Ingatlah bahwa hanya sumber daya yang diubah yang akan ditampilkan selama perintah plan . Apa pun yang dihilangkan tidak akan disentuh.

Biasanya, perintah Terraform menerima parameter tambahan. Parameter paling penting untuk perintah rencana adalah opsi -out , yang akan menyimpan rencana Anda di disk. Rencana yang disimpan ini kemudian dapat dieksekusi (persis seperti yang disimpan) dengan perintah apply. Ini sangat penting, karena jika tidak, mungkin ada perubahan, yang dibuat oleh, misalnya, rekan kerja di antara penerbitan plan Anda dan penerbitan apply . Contoh:

  1. Keluarkan plan dan verifikasi bahwa itu terlihat bagus.
  2. Seseorang mengubah keadaan, tanpa sepengetahuan Anda.
  3. Masalah apply dan—oops, itu melakukan sesuatu selain dari yang direncanakan!

Untungnya, alur kerja ini telah ditingkatkan di Terraform v0.11.0. Sejak versi ini, perintah apply secara otomatis memberi Anda rencana yang harus Anda setujui (dengan mengetik yes secara eksplisit). Keuntungannya adalah, jika Anda menerapkan rencana ini, itu akan dieksekusi persis seperti yang disajikan.

Opsi berguna lainnya adalah -destroy , yang akan menunjukkan kepada Anda rencana yang akan mengakibatkan penghancuran semua sumber daya yang dikelola Terraform. Anda juga dapat menargetkan sumber daya tertentu untuk dihancurkan dengan opsi -target .

Terraform Terapkan

Saat kami menerapkan rencana tertentu, Terraform keluar dan mengunci status kami untuk memastikan eksklusivitas. Kemudian melanjutkan untuk mengubah sumber daya dan, pada akhirnya, mendorong status yang diperbarui. Satu hal yang perlu diperhatikan adalah bahwa beberapa sumber daya membutuhkan waktu lebih lama untuk diselesaikan daripada yang lain. Misalnya, pembuatan instans AWS RDS mungkin memerlukan waktu lebih dari 12 menit, dan Terraform akan menunggu sampai selesai. Jelas, Terraform cukup pintar untuk tidak memblokir setiap operasi lain dengan ini. itu membuat grafik terarah dari perubahan yang diminta dan, jika tidak ada saling ketergantungan, menggunakan paralelisme untuk mempercepat eksekusi.

Mengimpor sumber daya

Seringkali, Terraform dan solusi "konfigurasi sebagai kode" lainnya diperkenalkan secara bertahap, ke dalam lingkungan yang sudah ada. Transisinya sangat mudah. Pada dasarnya, apa pun yang tidak didefinisikan di dalam Terraform dibiarkan tidak terkelola dan tidak berubah. Terraform hanya peduli dengan apa yang dikelolanya. Tentu saja, mungkin saja ini akan menimbulkan masalah—misalnya, jika Terraform bergantung pada beberapa titik akhir yang ada di luar konfigurasinya dan kemudian dihancurkan secara manual. Terraform tidak mengetahui hal ini, dan dengan demikian tidak dapat membuat ulang sumber daya ini selama perubahan status, yang akan mengakibatkan kesalahan dari API selama eksekusi rencana. Ini bukan sesuatu yang saya khawatirkan; manfaat memperkenalkan Terraform jauh lebih besar daripada kerugiannya.

Untuk membuat proses pengenalan sedikit lebih mudah, Terraform menyertakan perintah import . Ini digunakan untuk memperkenalkan sumber daya eksternal yang sudah ada ke dalam status Terraform dan memungkinkannya untuk mengelola sumber daya tersebut. Sayangnya, Terraform tidak dapat membuat konfigurasi otomatis untuk modul yang diimpor tersebut, setidaknya pada saat penulisan. Ada rencana untuk fungsi ini, tetapi untuk saat ini, Anda harus terlebih dahulu menulis definisi sumber daya di Terraform dan kemudian mengimpor sumber daya ini untuk memberi tahu Terraform agar mulai mengelolanya. Setelah diimpor ke status (dan selama perencanaan eksekusi), Anda akan melihat semua perbedaan antara apa yang Anda tulis di file .tf dan apa yang sebenarnya ada di cloud. Dengan cara ini, Anda dapat mengubah konfigurasi lebih lanjut. Idealnya, tidak ada perubahan yang muncul, yang berarti bahwa konfigurasi Terraform mencerminkan apa yang sudah ada di cloud 1:1.

Modul

Modul adalah bagian penting dari konfigurasi Terraform, dan saya sarankan Anda merangkulnya dan sering menggunakannya. Mereka memberi Anda cara untuk menggunakan kembali komponen tertentu. Contohnya adalah cluster AWS ECS, yang digunakan untuk menjalankan container Docker. Agar cluster seperti itu berfungsi, Anda memerlukan banyak sumber daya terpisah untuk dikonfigurasi: cluster itu sendiri, konfigurasi peluncuran yang akan mengelola instans EC2 terpisah, repositori kontainer untuk gambar, grup dan kebijakan penskalaan otomatis, dan seterusnya. Anda biasanya perlu memiliki cluster terpisah untuk lingkungan dan/atau aplikasi yang terpisah.

Salah satu cara untuk mengatasinya adalah dengan menyalin dan menempelkan konfigurasi, tetapi ini jelas merupakan solusi yang picik. Anda akan membuat kesalahan saat melakukan pembaruan paling sederhana.

Modul memungkinkan Anda untuk merangkum semua sumber daya yang terpisah di bawah satu blok konfigurasi (disebut modul). Modul mendefinisikan input dan output yang merupakan antarmuka yang digunakan untuk berkomunikasi dengan "dunia luar" (atau kode panggilan). Selain itu, modul dapat bersarang di dalam modul lain, memungkinkan Anda untuk dengan cepat memutar seluruh lingkungan yang terpisah.

Modul Lokal dan Jarak Jauh

Demikian pula untuk menyatakan, Anda dapat memiliki modul lokal atau modul jarak jauh. Modul lokal disimpan di samping konfigurasi Terraform Anda (dalam direktori terpisah, di luar setiap lingkungan tetapi dalam repositori yang sama). Tidak apa-apa jika Anda memiliki arsitektur sederhana dan tidak membagikan modul tersebut.

Ini, bagaimanapun, memiliki keterbatasan. Sulit untuk membuat versi modul-modul itu dan membagikannya. Pembuatan versi penting karena Anda mungkin ingin menggunakan v1.0.0 modul ECS Anda pada produksi tetapi ingin bereksperimen dengan v1.1.0 pada lingkungan staging. Jika modul disimpan di samping kode Anda, setiap perubahan pada kode modul akan tercermin di setiap env (setelah apply dijalankan) yang biasanya tidak diinginkan.

Salah satu pendekatan praktis untuk membuat versi modul adalah dengan meletakkan semuanya dalam repositori terpisah, misalnya, your-company/terraform-modules. Kemudian, saat mereferensikan modul-modul tersebut di dalam konfigurasi Terraform Anda, Anda dapat menggunakan tautan VCS sebagai sumber:

 module "my-module" { source = "[email protected]:your-company/terraform-modules.git//modules/my-module?ref=v1.1.0" ... }

Di sini saya merujuk v1.1.0 dari modul saya (jalur khusus) yang dapat saya uji secara independen dari versi lain dari modul yang sama di lingkungan yang berbeda.

Selain itu, ada masalah kemampuan modul untuk dapat ditemukan dan dibagikan. Anda harus berusaha untuk menulis modul yang terdokumentasi dengan baik dan dapat digunakan kembali. Biasanya, Anda akan memiliki konfigurasi Terraform yang berbeda untuk aplikasi yang berbeda dan mungkin ingin berbagi modul yang sama di antara mereka. Tanpa mengekstraknya ke repo terpisah, ini akan sangat sulit.

Menggunakan modul

Modul dapat dengan mudah direferensikan di lingkungan Terraform dengan mendefinisikan blok modul khusus. Berikut adalah contoh blok tersebut untuk modul ECS hipotetis:

 module "my_service_ecs_cluster" { source = "../modules/ecs_cluster" cluster_name = "my-ecs-service-${var.env}" repository_names = [ "my-ecs-service-${var.env}/api", "my-ecs-service-${var.env}/nginx", "my-ecs-service-${var.env}/docs", ] service_name = "my-ecs-service-${var.env}" ecs_instance_type = "t2.nano" min_size = "1" max_size = "1" use_autoscaling = false alb_target_group_arn = "${module.my_alb.target_group_arn}" subnets = "${local.my_private_subnets}" security_groups = "${aws_security_group.my_ecs.id}" key_name = "${var.key_name}" env_tag = "${var.env}" project_tag = "${var.project_tag}" application_tag = "${var.api_app_tag}" asg_tag = "${var.api_app_tag}-asg" }

Semua opsi yang diteruskan (kecuali dari beberapa opsi global seperti source ) didefinisikan di dalam konfigurasi modul ini sebagai input (variabel).

Registri Modul

Baru-baru ini HashiCorp meluncurkan registri modul Terraform resmi. Ini adalah berita bagus karena Anda sekarang dapat mengambil dari pengetahuan komunitas yang telah mengembangkan modul yang telah teruji pertempuran. Selain itu, beberapa dari mereka memiliki lencana "Modul Terverifikasi HashiCorp", yang berarti mereka diperiksa dan dipelihara secara aktif dan memberi Anda kepercayaan diri ekstra.

Sebelumnya, Anda harus menulis modul Anda sendiri dari awal (dan belajar dari kesalahan Anda) atau menggunakan modul yang diterbitkan di GitHub dan tempat lain, tanpa jaminan apa pun tentang perilakunya (selain membaca kode!)

Berbagi Data Antar Lingkungan

Idealnya, lingkungan harus benar-benar terpisah, bahkan dengan menggunakan akun AWS yang berbeda. Pada kenyataannya, ada kasus ketika satu lingkungan Terraform mungkin menggunakan beberapa informasi di lingkungan lain. This is especially true if you are gradually converting your architecture to use Terraform. One example might be that you have a global env that provides certain resources to other envs.

Let's say env global shares data with stage . For this to work, you can define outputs at the main level of the environment like so:

 output "vpc_id" { value = "${module.network.vpc_id}" }

Then, in the stage environment, you define a datasource that points to the remote state of global :

 data "terraform_remote_state" "global" { backend = "s3" config { bucket = "my-app-terraform-state" key = "terraform/global" region = "${var.region}" dynamodb_table = "terraform-state-lock-table" profile = "${var.profile}" } }

Now, you can use this datasource as any other and access all the values that were defined in global 's outputs:

 vpc_

Words of Caution

Terraform has a lot of pros. I use it daily in production environments and consider it stable enough for such work. Having said that, Terraform is still under active development. Thus, you will stumble on bugs and quirks.

Where to Report Issues and Monitor Changes

First of all, remember: Terraform has a separate core repo and repositories for each provider (eg, AWS). If you encounter issues, make sure to check both the core repo and the separate provider repositories for issues and/or opened pull requests with fixes. GitHub is really the best place to search for bugs and fixes as it is very active and welcoming.

This also means that provider plugins are versioned separately, so make sure you follow their changelogs as well as the core one. Most of the bugs I have encountered were resolved by upgrading the AWS provider which already had a fix.

Can't Cheat Your Way out of Cloud Knowledge

You cannot use Terraform to configure and manage infrastructure if you have no knowledge of how a given provider works. I would say this is a misconception and not a downside, since Terraform has been designed to augment and improve the workflow of configuration management and not to be some magic dust that you randomly sprinkle around and—poof! Environments grow! You still need a solid knowledge of a security model of each cloud, how to write, eg, AWS policies, what resources are available, and how they interact.

Prefer Separate Resources That Are Explicitly linked

There are certain resources—for example, the AWS security group or AWS route table—that allow you to configure the security rules and routes respectively, directly inside their own block. This is tempting, as it looks like less work but in fact will cause you trouble. The problems start when you are changing those rules on subsequent passes. The whole resource will be marked as being changed even if only one route/security rule is being introduced. It also gives implicit ordering to those rules and makes it harder to follow the changes. Thankfully, mixing those both approaches is not allowed now (see the note).

Best-practice example, with explicitly linked resources:

 resource "aws_security_group" "my_sg" { name = "${var.app_tag}-my-sg" ... } resource "aws_security_group_rule" "rule_one" { security_group_ ... } resource "aws_security_group_rule" "rule_two" { security_group_ ... }

Terraform plan Doesn't Always Detect Issues and Conflicts

I already mentioned this in the case where you were managing resources with Terraform that were relying on other, unmanaged infrastructure. But there are more trivial examples—for example, you will get an error if your EC2 instance has Termination Protection enabled, even though plan would show you it's OK to destroy it. You can argue that this is what Termination Protection has been designed for, and I agree, but there are more examples of things you can do in theory/on plan but when executed will deadlock or error out. For example, you cannot remove a network interface if something is using it—you get a deadlock without an option to gracefully recover.

Syntax Quirks

There are also quirks related to how HCLv1 (the syntax language Terraform uses) has been designed. It has a couple of frustrating quirks. There is work underway to provide an improved version of the parser for HCLv2. The best way to read on the current limitations and the plan to overcome them is this fantastic blog series. In the meantime, there are workarounds for most of those issues. They are not pretty and they will fail once v0.12 comes out, but hey, it is what it is.

When State Update Fails

It sometimes happens that Terraform is not able to correctly push an updated state. This is usually due to underlying network issues. The solution is to retry the state update instead of running apply again, which will fork the state .

Another issue might happen when state lock (the synchronization primitive that prevents multiple users to update the same state) fails to be taken down by Terraform. This involves running terraform force-unlock with the lock ID to take it down manually.

Thankfully, in case of such problems, Terraform provides you with a good description and steps you need to make to fix it.

Not Everything Is Fun to Manage Through Terraform

There are certain cases where Terraform is not my tool of choice. For example, configuring AWS CodePipeline and CodeBuild projects (AWS equivalent of CI/CD pipeline) is cumbersome when done through Terraform. You need to define each step through very verbose configuration blocks and things like “Login via GitHub” are a lot more complicated than using the UI. Of course, it's still possible if you prefer to have it codified. Well, I guess it's a good candidate for a well-written module!

Same thing goes for managing AWS API Gateway endpoints. In this case, using a dedicated serverless framework would be a better option.

When configuring AWS resources with Terraform, you will find yourself writing a lot of policies. Policies that would otherwise often be auto-generated for you (when using the UI). For those, I'd recommend the AWS Visual Editor and then copying the resulting policy JSON into Terraform.

Kesimpulan

Using Terraform has been fun and I'll continue doing so. Initial steps can be a bumpy ride, but there are more and more resources that help to ease you in.

I'd definitely recommend taking Terraform for a spin and simply playing with it. Remember, though—be safe and test it out on a non-essential account. If you are eligible for AWS Free Tier, use it as a 12-month free trial. Just be aware it has limitations as to what you can provision. Otherwise, just make sure you spin the cheapest resources, like t3.nano instances.

I highly recommend extensions for Terraform support in various code editors. For Visual Studio Code, there is one with syntax highlighting, formatting, validation and linting support.

It's always valuable to learn new things and evaluate new tools. I found that Terraform helped me immensely in managing my infrastructure. I think working with Terraform will only get easier and more fun, especially once v0.12.0 ships with a major upgrade to the HCL syntax and solve most of the quirks. The traction and community around Terraform are active and vibrant. You can find a lot of great resources on things I didn't manage to cover in a single blogs post, eg, a detailed guide on how to write modules.

Related: Terraform vs. CloudFormation: The Definitive Guide