Terraform AWS Cloud: Akıllı Altyapı Yönetimi

Yayınlanan: 2022-03-11

Bir uygulama yazmak hikayenin sadece bir kısmı. Değerli olması için ölçeklenebileceği bir yere dağıtılması gerekir, yüksek kullanılabilirlikle çalışması gerekir, yedeklemelere ihtiyacı vardır vb.

Gittikçe daha fazla geliştiricinin en azından bu dağıtım sürecini kavraması gerekiyor. Bu, örneğin sistem karmaşıklığı arttıkça DevOps'un günümüzde sıklıkla talep edilen bir rol haline gelmesiyle kendini gösterir. Bu değişimleri görmezden gelmemize izin veremeyiz ve uygulamaların kolayca dağıtılabilecek şekilde nasıl tasarlanacağının farkında olmamız gerekir.

Bu aynı zamanda müşterilerimizin de çıkarınadır: Bizi alanlarımızda uzman olarak işe alırlar ve genellikle baştan sona tüm ürünü teslim etmemizi beklerler. Gereksinimleri vardır ve genellikle iş çözümlerinin üzerinde çalıştığı yığından habersizdirler. Sonuç olarak, önemli olan ürünün ticari değeridir.

Terraform ile tanışın

Dağıtım ve altyapı yönetimi basit bir süreç değildir. Sürekli değişen birçok alan uzmanlığının yanı sıra Yet Another Aracı veya yeni bir iş akışını öğrenmemiz gerekiyor. Bunu erteliyorsanız, bu makale, altyapı yönetimine yönelik bir yaklaşımla tanışmanız için bir şanstır. Umarım sonunda Terraform'u kullanma konusunda kendinize daha fazla güvenirsiniz ve olası yaklaşımlar ve zorluklar hakkında daha fazla bilgi sahibi olursunuz. En azından bulut altyapınızın bir bölümünü yönetmeye başlamak için bu aracı kullanabilmelisiniz.

Terraform bir soyutlama katmanıdır, evet ve soyutlamalar sızdırıyor, katılıyorum. Ama sonuçta, sorunları çözme ve soyutlamaları yönetme işindeyiz. Bu, günlük görevlerimizde bize daha fazla akıl sağlamayı amaçlıyor.

Amaç

Terraform'un ne olduğunu, tüm ekosisteme nasıl uyduğunu ve diğer benzer araçlarla nasıl karşılaştırıldığını açıklayacağım. Ardından, bir ekip için çok ortamlı ve üretime hazır Terraform kurulumunu yapılandırmak için gereken adımları göstereceğim. Terraform konfigürasyonu yazmanın temellerini açıklayacağım—karmaşıklık nasıl yönetilir ve paylaşılabilir modüllerle kod kopyalanır.

Örneklerin tümü tek bir bulut sağlayıcısına odaklanacak: Amazon Web Services (AWS). Bu sadece en çok deneyime sahip olduğum bir bulut ama tüm bilgiler diğer bulutlar için de geçerli olmalı.

Keşke başladığımda bilseydim dediğim bazı notlarla bitireceğim: bazı sözdizimleri, tuhaflıklar ve Terraform'un benim seçim aracım olmayacağı durumlar.

Sözdiziminin nitty cesur ayrıntılarına odaklanmayacağım. HashiCorp'un Terraform için sağladığı harika belgeleri ve kılavuzları okuyarak bunu hızla hızlandırabilirsiniz. Başından beri bariz olmayan ve Terraform ile çalışmaya başlamadan önce bilseydim dediğim şeylere odaklanmak istiyorum. Umarım bu sizi doğru yöne yönlendirir ve Terraform'u gelecekteki projelerde kullanmak için bir araç olarak görmenize olanak tanır.

Altyapı Yönetimi Zordur

Bulutta bir uygulama için ortam kurmanın birden çok adımı vardır. Hepsini detaylı kontrol listeleri şeklinde yazmadığınız ve yakından takip etmediğiniz sürece, her zaman hata yapacaksınız; sonuçta insanız. Bu adımları paylaşmak zor. Çok sayıda manuel prosedürü belgelemeniz gerekir ve belgeler hızla güncelliğini yitirebilir. Şimdi tüm bunları tek bir uygulama için toplam ortam sayısıyla çarpın: dev , test/qa , stage ve prod . Ayrıca her biri için güvenlik düşünmeniz gerekir.

Her Aracın Kullanabileceğim ve Karmaşıklığı Unutabileceğim Bir Kullanıcı Arayüzü Yok mu?

Kullanıcı arayüzleri var; AWS Yönetim Konsolu bunun en iyi örneğidir. Ancak bu araçlar kaputun altında çok şey yapıyor. Kullanıcı arayüzüne tek bir tıklama, kavraması zor olan bir dizi değişikliği başlatabilir. Genellikle kullanıcı arayüzünde yaptığınızı geri almanın bir yolu yoktur (olağan "Emin misiniz?" istemleri genellikle yeterli değildir). Ayrıca, değişiklikleri kontrol etmek için ikinci bir çift göze sahip olmak her zaman iyi bir fikirdir, ancak kullanıcı arayüzlerini kullandığımızda bu kişiyle birlikte oturmamız veya değişikliklerimizi yapıldıktan sonra kontrol etmemiz gerekir, bu da bir denetimden çok bir denetimdir. gözden geçirmek. Her bulut sağlayıcısının, ustalaşmanız gereken kendi kullanıcı arayüzü vardır. Kullanıcı arayüzleri, kullanımı kolay olacak şekilde tasarlanmıştır (mutlaka basit değil!) ve bu nedenle, "bu sadece küçük bir ince ayar" veya 48 saat içinde unutacağınız hızlı bir üretim düzeltmesi gibi yanıltıcı yaklaşımlara eğilimlidir. Bu tür manuel tıklamanın otomatikleştirilmesi de çok zordur.

CLI Araçları ne olacak?

Kullanım durumlarımız için UI araçlarından daha iyi olurlar. Ancak yine de elle değişiklik yapmaya veya kolayca kontrolden çıkabilecek bash komut dosyaları yazmaya eğilimlisiniz. Ayrıca her sağlayıcının kendi CLI araçları vardır. Bu araçlarla, değişikliklerinizi taahhüt etmeden önce göremezsiniz. Neyse ki bu yeni bir sorun değil ve buna yardımcı olan araçlar var.

Orkestrasyon ve Konfigürasyon Yönetimi

Altyapıyı yönetmek için kullanılan bazı araç ve uygulama kategorilerini tanımlayacağım. Bunlar orkestrasyon ve konfigürasyon yönetimidir. Bunları kabaca bildirimsel ve zorunlu programlama modelleri olarak düşünebilirsiniz (Prolog'a karşı Python'u düşünün). Her birinin kendi artıları ve eksileri vardır, ancak hepsini bilmek ve belirli bir iş için en iyi aracı uygulamak en iyisidir. Ayrıca, düzenleme genellikle yapılandırma yönetiminden daha yüksek bir soyutlama düzeyi içerir.

Orkestrasyon

Orkestrasyon, daha çok bildirimsel bir programlama paradigmasına benzer. Orkestra şefi olarak düşünmeyi seviyorum. Bir orkestra şefinin işi, Wikipedia (bağlantı) tarafından "birkaç oyuncunun veya şarkıcının eşzamanlı performansını jest kullanarak yönetme sanatı" olarak güzel bir şekilde özetlenir. Şefler, müziğin ritmini ve temposunu, dinamiklerini ve ipucunu iletirler, ancak asıl çalışma, müzik aletlerini çalmada uzman olan müzisyenler tarafından yapılır. Böyle bir koordinasyon olmadan mükemmel bir parçayı icra edemezlerdi.

Terraform'un uyduğu yer burasıdır. Onu bir BT altyapısını yürütmek için kullanırsınız: Ona ne dağıtacağını söylersiniz ve Terraform hepsini birbirine bağlar ve gerekli tüm API çağrılarını gerçekleştirir. Bu alanda benzer araçlar var; en bilinenlerinden biri AWS Cloud Formation'dır. Hata durumunda Terraform'dan daha iyi kurtarma ve geri alma desteğine sahip, ancak bence daha dik bir öğrenme eğrisi var. Ayrıca buluttan bağımsız değildir: Yalnızca AWS ile çalışır.

Konfigürasyon yönetimi

Bu uygulamaların tamamlayıcı yönü ise konfigürasyon yönetimi yaklaşımıdır. Bu paradigmada, bir aracın belirli, istenen bir konfigürasyona ulaşması için atması gereken adımları tam olarak belirtirsiniz. Adımların kendisi küçük olabilir ve birden fazla işletim sistemini destekleyebilir, ancak yürütme sırasını aktif olarak düşünmeniz gerekir. Mevcut durum ve çevre hakkında hiçbir farkındalıkları yoktur (onları bununla programlamadığınız sürece) ve bu nedenle, onlara verdiğiniz adımları körü körüne uygulayacaktır. Bu, yapılandırma kayması olarak bilinen bir soruna yol açabilir; bu sorunda, özellikle kaynaklarınızda bazı manuel değişiklikler yaptıysanız, kaynaklarınızın başlangıçta temsil etmek istedikleriyle yavaş yavaş senkronizasyonu bozulacaktır. Bireysel örneklerde hizmetleri yönetme ve sağlama konusunda mükemmeldirler. Bu iş akışında mükemmel olan araçlara örnek olarak Chef, Puppet, Ansible ve Salt verilebilir.

Orkestrasyon, altyapınıza, kaynaklarınızı evcil hayvan olarak değil de sığır olarak değerlendirdiğiniz bir yaklaşımı zorunlu kılar. Her VPS'yi manuel olarak "yetiştirmek" yerine, bir şeyler ters gittiğinde onları tam bir kopyayla değiştirebilirsiniz. Sadece umursamadığınızı ve en iyisini umarak şeyi yeniden başlattığınızı kastetmiyorum.

İkonik sloganlarıyla IT Crowd TV şovunun meme ucu: Kapatıp tekrar açmayı denediniz mi?

Bunun yerine, koddaki sorunu araştırmalı ve düzeltmeli ve ardından dağıtmalısınız.

Ansible (ve diğer CM araçları) AWS altyapısını yönetmek için kullanılabilir, ancak bu çok fazla çalışmayı gerektirir ve özellikle altyapı sık sık değiştiğinde ve karmaşıklaştığında hataya daha açıktır.

Unutulmaması gereken önemli bir nokta, orkestrasyon ve konfigürasyon yönetimi yaklaşımlarının birbiriyle çelişmediğidir. Uyumlular. Bir AutoScaling grubunda Terraform tarafından yönetilen ancak bir AWS Application Image (AMI) çalıştıran bir grup EC2 (VPS) örneğine sahip olmak kesinlikle sorun değil, örneğin Ansible ile zorunlu adımlarla hazırlanmış diskin anlık görüntüsüdür . Terraform, bir makine başlatıldığında harici, tedarik araçlarını çalıştırmanıza izin veren bir "sağlayıcılar" konseptine bile sahiptir.

Terraform belgeleri, bunu daha fazla açıklamak ve Terraform'u tüm ekosisteme yerleştirmenize yardımcı olmak için harika bir iş çıkarır.

Terraform Nedir?

Bu, HashiCorp tarafından oluşturulmuş, altyapınızı sürümlü, paylaşılan ve gözden geçirilebilen bildirimsel yapılandırma dosyaları olarak kodlamanıza olanak tanıyan açık kaynaklı bir araçtır.

HashiCorp adı bir zil çalmalıdır - ayrıca Nomad, Vault, Packer, Vagrant ve Consul yaparlar. Bunlardan herhangi birini kullandıysanız, dokümantasyonun kalitesini, canlı topluluğu ve çözümlerinden bekleyebileceğiniz kullanışlılığı zaten biliyorsunuzdur.

Kod Olarak Altyapı

Terraform, platformdan bağımsızdır; AWS, Google Cloud Platform, OpenStack ve Azure gibi yalın donanım sunucuları veya bulut sunucularını yönetmek için kullanabilirsiniz. Terraform lingo'da bunlara sağlayıcılar denir , Desteklenen sağlayıcıların tam listesini okuyarak ölçeği anlayabilirsiniz. Aynı anda birden fazla sağlayıcı kullanılabilir; örneğin, sağlayıcı A sizin için VM'leri yapılandırdığında, ancak sağlayıcı B, DNS kayıtlarını yapılandırdığında ve yetkilendirdiğinde.

Bu, bir yapılandırma dosyasında tek bir değişiklikle bulut sağlayıcıları arasında geçiş yapılabileceği anlamına mı geliyor? Hayır, bunu isteyeceğini bile sanmıyorum, en azından otomatik bir şekilde. Sorun, farklı sağlayıcıların farklı yeteneklere, farklı tekliflere, akışlara, fikirlere vb. sahip olabilmesidir. Bu, aynı kavramı ifade etmek için farklı bir sağlayıcı için farklı kaynaklar kullanmanız gerekeceği anlamına gelir. Ancak, bunların hepsi yine de tek, tanıdık bir yapılandırma sözdiziminde yapılabilir ve uyumlu bir iş akışının parçası olabilir.

Terraform Kurulumunun Temel Parçaları

  1. Yüklemeniz gereken Terraform ikili dosyasının kendisi
  2. Kaynak kod dosyaları, yani yapılandırmanız
  3. Terraform'un yönettiği kaynakları temsil eden durum (yerel veya uzak)

Terraform Yapılandırmasını Yazma

Terraform konfigürasyon kodunu *.tf dosyalarına HCL dilini kullanarak yazarsınız. JSON biçimini ( *.tf.json ) kullanma seçeneği vardır, ancak bu, insanlardan ziyade makineleri ve otomatik üretimi hedefler. HCL'ye bağlı kalmanızı tavsiye ederim. HCL dilinin sözdizimine derinlemesine dalmayacağım; resmi belgeler, HCL'nin nasıl yazılacağını ve değişkenlerin ve enterpolasyonların nasıl kullanılacağını açıklamak için harika bir iş çıkarır. Örnekleri anlamak için gereken minimum düzeyden bahsedeceğim.

Terraform dosyalarının içinde, çoğunlukla kaynaklar ve veri kaynaklarıyla ilgileniyorsunuz. Kaynaklar, altyapınızın bileşenlerini temsil eder; örneğin, bir AWS EC2 bulut sunucusu, bir RDS bulut sunucusu, bir Route53 DNS kaydı veya bir güvenlik grubundaki bir kural. Bunları bulut mimarisi içinde sağlamanıza ve değiştirmenize olanak tanır.

Terraform'u kurduğunuzu varsayarsak, bir terraform apply , aşağıdaki kod tamamen işlevsel bir EC2 örneği oluşturur (yalnızca belirli özellikler gösterilir):

 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}" } }

Öte yandan, verilen bileşenlerle ilgili verileri değiştirmeden okumanıza izin veren veri kaynakları vardır. ACM tarafından verilen bir sertifikanın AWS Kimliğini (ARN) mi almak istiyorsunuz? Bir veri kaynağı kullanıyorsunuz. Aradaki fark, yapılandırma dosyalarında bunlara başvururken veri kaynaklarının önüne data_ .

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

Yukarıdakiler, AWS ALB'lerle birlikte kullanılabilen, verilmiş bir ACM SSL sertifikasına atıfta bulunur. Tüm bunları yapmadan önce, ortamınızı ayarlamanız gerekir.

Klasör Yapısı

Terraform ortamları (ve durumları) dizinlerle ayrılır. Terraform, bir dizindeki tüm *.tf dosyalarını tek bir ad alanına yükler, bu nedenle sıra önemli değildir. Aşağıdaki dizin yapısını öneririm:

 /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 – tüm üst düzey değişkenleri ve isteğe bağlı olarak bunların varsayılan değerlerini tanımlayın. Sembolik bağlantılarla her ortamda (iç içe dizin) yeniden kullanılabilirler.
  2. /stage/ – tamamen ayrı bir ortam için yapılandırmayı tutan bir dizin (burada stage olarak adlandırılır, ancak herhangi bir şey olabilir). Bu klasörde yapılan herhangi bir değişiklik, diğer ortamlardan (env-gibi prod ) tamamen bağımsızdır; bu, stage yapılan değişikliklerle üretim ortamını karıştırmamak için istediğiniz bir şeydir!
  3. terraform.tfvars – değişken değerleri tanımlayın. .tfvars dosyaları, tanımlı değişkenler için key=val çiftlerini .env dosyalarına benzer. Örneğin bu, kullandığım AWS profile , AWS key_name ve AWS key_path belirtir. Git'te yoksayılabilir.
  4. default_variables.tf – bu, kendimizi tekrar etmeden env'den bağımsız değişkenleri paylaşmamıza izin veren dosyaya (2) bir sembolik bağlantıdır.
  5. terraform.tf – bu, her ortamın ana konfigürasyonudur; arka ucu yapılandıran terraform {} bloğunu tutar. Sağlayıcıları da burada yapılandırırım.
  6. env_variables.tf – bu dosya env'e özgü değişkenleri tutar. AWS'de tüm kaynakları Env=<env_name> ile etiketliyorum, bu nedenle bu dosya genellikle yalnızca bir değişken tanımlar: env .

Tabii ki, ortamınızı yapılandırmanın tek yolu bu değil. Bu, endişelerin net bir şekilde ayrılmasını sağlayarak benim için iyi çalışan bir şey.

Arka Uç Yapılandırması

Terraform durumundan daha önce bahsetmiştim. Bu, Terraform iş akışının önemli bir parçasıdır. Devletin gerçekten gerekli olup olmadığını merak edebilirsiniz. Terraform, altyapının gerçek durumunu almak için her zaman AWS API'sini sorgulayamaz mı? Pekala, düşünürseniz, Terraform'un bildirimsel yapılandırma dosyalarında yönettikleri ile bu dosyaların gerçekte neye karşılık geldiği (bulut sağlayıcısının ortamında) arasında bir eşleme sürdürmesi gerekir. Terraform yapılandırma dosyalarını yazarken, örneğin bireysel EC2 örneklerinin veya yayınladığınız güvenlik grupları için oluşturulacak ARN'lerin kimliklerini umursamadığınızı unutmayın. Ancak dahili olarak, Terraform'un belirli bir kaynak bloğunun bir ID/ARN ile somut bir kaynağı temsil ettiğini bilmesi gerekir. Bu, değişiklikleri algılamak için gereklidir. Ayrıca, durum kaynaklar arasındaki bağımlılıkları izlemek için kullanılır (ayrıca genellikle düşünmeniz gerekmeyen bir şey!). (Genellikle) paralelleştirilebilen ve yürütülebilen bir grafik oluşturmak için kullanılırlar. Her zaman olduğu gibi, Terraform durumu ve amacı hakkındaki mükemmel belgeleri okumanızı tavsiye ederim.

Durum, mimariniz için tek gerçek kaynak olduğundan, sizin ve ekibinizin her zaman en güncel sürüm üzerinde çalıştığından ve duruma senkronize olmayan erişimle çakışmalar oluşturmadığınızdan emin olmanız gerekir. Durum dosyasındaki birleştirme çakışmalarını çözmek istemezsiniz, inan bana.

Varsayılan olarak, Terraform durumu bir terraform.tfstate dosyası olarak geçerli çalışma dizininde (her env'nin) bulunan diskteki bir dosyada saklar. Bu işteki tek geliştirici olacağınızı biliyorsanız veya sadece Terraform ile öğreniyor ve deney yapıyorsanız, bu sorun değil. Teknik olarak, durumu bir VCS deposuna bağlayabildiğiniz için bir takımda çalışmasını sağlayabilirsiniz. Ancak o zaman, herkesin her zaman devletin en son sürümü üzerinde çalıştığından ve kimsenin aynı anda değişiklik yapmadığından emin olmanız gerekir! Bu genellikle büyük bir baş ağrısıdır ve buna karşı şiddetle tavsiye ederim. Ayrıca, tek geliştirici operasyonunuza biri katılırsa, durum için yine de alternatif bir yer yapılandırmanız gerekir.

Neyse ki, bu Terraform'da yerleşik iyi çözümlerle ilgili bir sorun: sözde Uzak Durum . Uzak durumun çalışması için, mevcut arka uç sağlayıcılarından birini kullanarak arka ucu yapılandırmanız gerekir. Aşağıdaki arka uç örneği, AWS S3 ve AWS DynamoDB'yi (AWS NoSQL veritabanı) temel alacaktır. Yalnızca S3 kullanabilirsiniz, ancak daha sonra durum kilitleme ve tutarlılık denetimi mekanizmasını kaybedersiniz (önerilmez). Daha önce yalnızca yerel durumu kullandıysanız, uzak bir arka uç yapılandırmak size durumunuzu ilk kez taşıma seçeneği sunacak ve böylece hiçbir şey kaybetmezsiniz. Arka uç yapılandırması hakkında daha fazla bilgiyi buradan okuyabilirsiniz.

Maalesef bir tavuk ve yumurta sorunu var: S3 kovası ve DynamoDB tablosunun manuel olarak oluşturulması gerekiyor. Henüz bir durum olmadığı için Terraform bunları otomatik olarak oluşturamaz! AWS CLI kullanarak bunu otomatikleştiren https://github.com/gruntwork-io/terragrunt gibi bazı çözümler var, ancak bu blog gönderisinin ana konusundan ayrılmak istemiyorum.

S3 ve DynamoDB arka uç yapılandırması hakkında bilinmesi gereken önemli şeyler şunlardır:

  1. İnsan hatasından ve Murphy Yasasından korunmak için S3 kovasında sürüm oluşturmayı etkinleştirin.
  2. DynamoDB tablosunun okuma ve yazma (kapasite adı verilen) için bir hız sınırı vardır. Uzak durumda çok fazla değişiklik yaparsanız, o tablo için DynamoDB AutoScaling'i etkinleştirdiğinizden veya yeterince yüksek R/W limitleri yapılandırdığınızdan emin olun. Aksi takdirde Terraform, çok sayıda çağrı yürütürken AWS API'sinden HTTP 400 hataları alacaktır.

Hepsini özetlemek gerekirse, S3 ve DynamoDB'de uzak durumu yapılandırmak için aşağıdaki arka uç yapılandırması terraform.tf yerleştirilebilir.

 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" } }

Bunu bir kerede kabul etmek için çok fazla, ama unutmayın, bunu her ortam için bir kez yaparsınız ve sonra unutabilirsiniz. Durum kilitleme üzerinde daha fazla kontrole ihtiyacınız varsa, HashiCorp Terraform Enterprise var, ancak burada ele almayacağım.

sağlayıcılar

Bu arka ucun erişilebilir olması ve bulut sağlayıcımızla iletişim kurabilmesi için, sözde sağlayıcıyı yapılandırmamız gerekiyor. Aşağıdaki blok terraform.tf dosyasına yerleştirilebilir (her env için):

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

profile ve region için değişkenler, terraform.tfvars dosyasında saklanır ve göz ardı edilebilir. profile değişkeni, standart kimlik bilgileri dosyasını kullanarak AWS bulutu için güvenlik kimlik bilgilerini tutan adlandırılmış bir profili ifade eder. Ayrıca bazı sürüm kısıtlamaları da ayarladığımı unutmayın. Terraform'un, her arka uç başlatma hakkında bilginiz olmadan sağlayıcı eklentilerinizi yükseltmesini istemezsiniz. Özellikle, dikkatli yükseltme gerektiren AWS sağlayıcısının 2.x sürümü olduğu göz önüne alındığında.

Arka Uç Başlatma

Her arka uç yapılandırması, başlangıçta ve her değişiklik yapıldığında bir başlatma adımı gerektirir. Başlatma ayrıca Terraform modüllerini de yapılandırır (daha sonraları hakkında), bu nedenle bunları eklediğinizde, init adımını da yeniden çalıştırmanız gerekir. Bu işlemin birden çok kez çalıştırılması güvenlidir. Arka ucun başlatılması sırasında, tüm değişkenlerin durumu yapılandırmak için Terraform tarafından okunamayacağını ve güvenlik nedenleriyle (örneğin, gizli anahtarlar) olmaması gerektiğini unutmayın. Bunun üstesinden gelmek ve bizim durumumuzda varsayılandan farklı bir AWS profili kullanmak için k=v değişken çiftlerini kabul eden -backend-config seçeneğini kullanabilirsiniz. Buna kısmi konfigürasyon denir.

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

Terraform dosyaları, belirli bir dizine sınırlı bir kapsamı paylaşır. Bu, bir alt klasörün doğrudan üst dizin koduna bağlı olmadığı anlamına gelir. Bununla birlikte, kodun yeniden kullanılmasına, karmaşıklık yönetimine ve paylaşılmasına izin veren bir modül tanımlamaktadır.

İş Akışı

Terraform koduyla çalışırken genel iş akışı aşağıdaki gibidir:

  1. Altyapınız için yapılandırma yazın.
  2. Bakalım ne gibi değişiklikler yapacak ( terraform plan ).
  3. İsteğe bağlı olarak, 2. adımda gördüğünüz değişiklikleri aynen terraform apply ).
  4. 1 GİT

Terraform Planı

Terraform plan komutu, apply komutunu verdikten sonra altyapınızda yapılacak değişikliklerin bir listesini size sunacaktır. Tek başına hiçbir şeyi değiştirmediği için plan birden çok kez yayınlamak güvenlidir.

Bir Plan Nasıl Okunur?

Terraform'daki nesneler (kaynaklar ve veri kaynakları) tam adlarıyla kolayca tanımlanabilir.

  1. Kaynaklar söz konusu olduğunda, kimlik şöyle görünebilir: <resource_type>.<resource_name> —örneğin, aws_ecs_service.this .
  2. Modüllerin içindeki kaynaklar söz konusu olduğunda, ek bir modül adımız vardır: module.<module_name>.<resource_type>.<resource_name> —örneğin, module.my_service_ecs_service_task.aws_ecs_service.this .
  3. Veri kaynakları (bir modülün içinde ve dışında): (module.<module_name>).data.<resource_type>.<resource_name> —örneğin, module.my_service_ecs_service_task.data.aws_ecs_task_definition.this .

Kaynak türü belirli bir sağlayıcıya özeldir ve genellikle adını içerir ( aws_… ). AWS için mevcut kaynakların tam listesi dokümanlarda bulunabilir.

Verilen kaynaklar için bir planın göstereceği beş eylem vardır:

  1. [+] Ekle – Yeni bir kaynak oluşturulacak.
  2. [-] Yok Et – Bir kaynak tamamen yok edilecek.
  3. [~] Yerinde değiştir – Bir kaynak değiştirilecek ve bir veya daha fazla parametre değiştirilecek. Bu genellikle güvenlidir. Terraform, hangi parametrelerin değiştirileceğini ve (mümkünse) nasıl yapılacağını size gösterecektir.
  4. [- / +] – Kaynak kaldırılacak ve ardından yeni parametrelerle yeniden oluşturulacak . Bu, yerinde değiştirilemeyecek bir parametrede değişiklik yapıldığında gerçekleşir. Terraform, aşağıdaki kırmızı yorumla hangi değişikliklerin bir kaynağı yeniden oluşturmaya zorladığını size gösterecektir: (forces new resource) . Bu, kaynağın hiç var olmayacağı bir dönem olduğundan potansiyel olarak tehlikelidir. Ayrıca diğer bağlantılı bağımlılıkları da bozabilir. Sonuçlarının ne olacağını bilmiyorsanız veya bir kesinti süresini umursamıyorsanız, bu tür değişiklikler üzerinde çalışmanızı tavsiye ederim.
  5. [<=] – Bir veri kaynağı okunacak. Bu salt okunur bir işlemdir.

Terraform AWS — örnek bir "plan"

Yukarıda örnek bir plan var. Yaptığım değişiklikler şunlardı:

  • İlk kale örneğinin instance_type değiştirildi
  • İkinci bir kale örneği eklendi
  • Bir güvenlik grubunun adını değiştirdi

Son değişikliğin, üst grubun adındaki bir değişikliği otomatik olarak algılayan bir güvenlik grubu kuralı olduğunu unutmayın. Bence, bütün plan çok okunabilir. Bazı parametre değerleri <computed> olarak gösterilir — bu, değiştirilecekleri anlamına gelmez, daha ziyade bu aşamada alınamayacakları ve sunulamayacakları anlamına gelir (henüz oluşturulmamış SG adı gibi). plan komutu sırasında yalnızca değiştirilen kaynakların gösterileceğini unutmayın. İhmal edilen hiçbir şeye dokunulmaz.

Genellikle, Terraform komutları ek parametreleri kabul eder. plan komutunun en önemli parametresi, planınızı diske kaydedecek olan -out seçeneğidir. Bu kaydedilen plan daha sonra Apply komutuyla (tam olarak kaydedildiği gibi) yürütülebilir. Bu çok önemlidir, çünkü aksi takdirde, örneğin, bir plan yayınlanması ile application'ın yayınlanması arasında meslektaşlarınız tarafından yapılan bir değişiklik apply . Örnek vermek:

  1. plan ve iyi göründüğünü doğrulayın.
  2. Birisi sizin haberiniz olmadan durumu değiştirir.
  3. Sorun apply ve — ayy, planlanandan farklı bir şey yaptı!

Neyse ki, bu iş akışı Terraform v0.11.0'da geliştirildi. Bu sürümden bu yana, apply komutu size otomatik olarak onaylamanız gereken bir plan sunar (açıkça yes yazarak). Avantajı, eğer bu planı uygularsanız, aynen sunulduğu gibi uygulanacaktır.

Bir başka kullanışlı seçenek -destroy , Terraform'un yönettiği tüm kaynakları yok etmekle sonuçlanacak planı size gösterecek. Ayrıca -target seçeneğiyle belirli kaynakları imha için hedefleyebilirsiniz.

Terraform Uygula

Belirli bir planı uyguladığımızda, Terraform dışarı çıkar ve münhasırlığı sağlamak için devletimize kilitler. Ardından kaynakları değiştirmeye devam eder ve sonunda güncellenmiş bir duruma geçer. Unutulmaması gereken bir nokta, bazı kaynakların tamamlanması diğerlerinden daha uzun sürer. Örneğin, bir AWS RDS örneğinin oluşturulması 12 dakikadan fazla sürebilir ve Terraform bunun bitmesini bekleyecektir. Açıkçası, Terraform bununla diğer tüm işlemleri engellemeyecek kadar akıllıdır. istenen değişikliklerin yönlendirilmiş bir grafiğini oluşturur ve karşılıklı bağımlılık yoksa yürütmeyi hızlandırmak için paralellik kullanır.

Kaynakları içe aktarma

Çoğu zaman, Terraform ve diğer "kod olarak yapılandırma" çözümleri, zaten var olan bir ortama kademeli olarak eklenir. Geçiş gerçekten çok kolay. Temel olarak, Terraform içinde tanımlanmayan herhangi bir şey yönetilmez ve değiştirilmez. Terraform sadece yönettikleriyle ilgilenir. Tabii ki, bunun sorunlara yol açması mümkündür - örneğin, Terraform konfigürasyonunun dışında var olan bir uç noktaya güveniyorsa ve daha sonra manuel olarak yok edilirse. Terraform bunu bilmiyor ve bu nedenle durum değişiklikleri sırasında bu kaynağı yeniden oluşturamaz, bu da planın yürütülmesi sırasında API'den hatalara neden olur. Bu endişeleneceğim bir şey değil; Terraform'u tanıtmanın faydaları, eksilerinden çok daha ağır basar.

Terraform, tanıtım sürecini biraz daha kolaylaştırmak için import komutunu içerir. Halihazırda var olan harici kaynakları Terraform durumuna sokmak ve bu kaynakları yönetmesine izin vermek için kullanılır. Ne yazık ki, Terraform, en azından yazma sırasında, bu içe aktarılan modüller için yapılandırmaları otomatik olarak oluşturamaz. Bu işlevsellik için planlar var, ancak şimdilik, önce kaynak tanımını Terraform'a yazmanız ve ardından Terraform'a onu yönetmeye başlamasını söylemek için bu kaynağı içe aktarmanız gerekiyor. Duruma aktarıldığında (ve yürütmenin planlanması sırasında), .tf dosyalarına yazdıklarınız ile bulutta gerçekte var olan arasındaki tüm farkları göreceksiniz. Bu şekilde, yapılandırmayı daha da değiştirebilirsiniz. İdeal olarak, hiçbir değişiklik görünmemelidir; bu, Terraform konfigürasyonunun halihazırda bulutta olanı 1:1 yansıttığı anlamına gelir.

Modüller

Modüller, Terraform konfigürasyonunun önemli bir parçasıdır ve onları benimsemenizi ve sık sık kullanmanızı tavsiye ederim. Size belirli bileşenleri yeniden kullanmanın bir yolunu sunarlar. Bir örnek, Docker kapsayıcılarını çalıştırmak için kullanılan AWS ECS kümesi olabilir. Böyle bir kümenin çalışması için, yapılandırılacak birçok ayrı kaynağa ihtiyacınız vardır: kümenin kendisi, ayrı EC2 örneklerini yönetecek başlatma yapılandırması, görüntüler için kapsayıcı havuzları, otomatik ölçeklendirme grubu ve ilkesi vb. Genellikle ayrı ortamlar ve/veya uygulamalar için ayrı kümeleriniz olması gerekir.

Bunun üstesinden gelmenin bir yolu, konfigürasyonu kopyalayıp yapıştırmak olabilir, ancak bu açıkçası dar görüşlü bir çözüm. En basit güncellemeleri yaparken hata yaparsınız.

Modüller, tüm bu ayrı kaynakları tek bir yapılandırma bloğu (modül olarak adlandırılır) altında toplamanıza olanak tanır. Modüller, "dış dünya" (veya çağrı kodu) ile iletişim kurduğu arayüzler olan girdileri ve çıktıları tanımlar. Ayrıca, modüller diğer modüllerin içine yerleştirilebilir, bu da tüm ayrı ortamları hızlı bir şekilde döndürmenize olanak tanır.

Yerel ve Uzak Modüller

Duruma benzer şekilde, yerel modüllere veya uzak modüllere sahip olabilirsiniz. Yerel modüller, Terraform konfigürasyonunuzla birlikte depolanır (ayrı bir dizinde, her ortamın dışında ama aynı depoda). Basit bir mimariniz varsa ve bu modülleri paylaşmıyorsanız, bu sorun değil.

Ancak bunun sınırlamaları vardır. Bu modülleri sürümlendirmek ve paylaşmak zor. Sürüm oluşturma önemlidir çünkü üretimde ECS modülünüzün v1.0.0 sürümünü kullanmak isteyebilir, ancak bir hazırlama ortamında v1.1.0 ile denemeler yapmak isteyebilirsiniz. Modül, kodunuzla birlikte depolanmışsa, modül kodundaki her değişiklik, genellikle istenmeyen bir durum olan her ortama (bir kez apply çalıştırıldığında) yansıtılır.

Modülleri sürümlendirmeye yönelik kullanışlı bir yaklaşım, hepsini ayrı bir havuza, örneğin, şirketiniz/dünya-modüllerine koymaktır. Ardından, Terraform yapılandırmanızdaki bu modüllere başvururken kaynak olarak bir VCS bağlantısı kullanabilirsiniz:

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

Burada, farklı ortamlarda aynı modülün diğer sürümlerinden bağımsız olarak test edebileceğim modülümün (belirli yol) v1.1.0'ına atıfta bulunuyorum.

Bunun dışında modüllerin keşfedilebilirliği ve paylaşılabilirliği sorunu var. İyi belgelenmiş ve yeniden kullanılabilir modüller yazmaya çalışmalısınız. Genellikle, farklı uygulamalar için farklı Terraform konfigürasyonlarına sahip olacaksınız ve aynı modülü aralarında paylaşmak isteyebilirsiniz. Onları ayrı bir depoya çıkarmadan, bu çok zor olurdu.

Modülleri kullanma

Modüller, özel bir modül bloğu tanımlanarak Terraform ortamlarında kolayca referans alınabilir. Varsayımsal bir ECS modülü için böyle bir blok örneği:

 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" }

Geçilen tüm seçenekler ( source gibi bazı global olanlar hariç), bu modülün konfigürasyonunda girdiler (değişkenler) olarak tanımlanmıştır.

Modül Kayıt Defteri

Son zamanlarda HashiCorp resmi bir Terraform modül kaydı başlattı. Bu harika bir haber çünkü artık savaşta test edilmiş modüller geliştirmiş olan topluluğun bilgisinden yararlanabilirsiniz. Ayrıca, bazılarında "HashiCorp Onaylı Modül" rozeti bulunur; bu, kontrol edildikleri ve aktif olarak bakımlarının yapıldığı anlamına gelir ve size ekstra güven verir.

Daha önce, ya kendi modüllerinizi sıfırdan yazmak (ve hatalarınızdan ders almak) ya da GitHub ve diğer yerlerde yayınlanan modülleri, davranışları konusunda herhangi bir garanti vermeden (kodu okumak dışında!)

Ortamlar Arasında Veri Paylaşımı

İdeal olarak, farklı AWS hesapları kullanılsa bile ortamlar tamamen ayrı olmalıdır. In reality, there are cases when one Terraform environment might use some information in another environment. 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.

Çözüm

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