AWS’de Terraform ile Altyapı Yönetimi -I: EC2 Instance Oluşturma

Müslüm Han ÖZTÜRK
Turk Telekom Bulut Teknolojileri
9 min readMay 13, 2024

Terraform, Infrastructure as Code (IaC) için kullanılan bir araçtır ve bu nedenle genellikle IaaS (Infrastructure as a Service) ortamlarını yönetmek için kullanılır. IaaS, bulut bilişim hizmet modelinin bir türüdür ve kullanıcılara sanal altyapı kaynakları sağlar. Terraform, IaaS sağlayıcılarına (AWS, Azure, Google Cloud gibi) erişim sağlayarak sanal makineler, ağ yapılandırmaları, depolama hizmetleri ve diğer altyapı kaynaklarını oluşturup yönetmek için kullanılabilir. Bu makalede Amazon Web Service üzerindeki bir sunucuya altyapı yönetim aracı olan terraform yüklemeyi ve terraform ile altyapı oluşturmayı öğreneceğiz.

Bölüm 1 - Terraform Kurulum

Amazon hesabınızda Amazon Linux 2023 AMI’yi kullanarak bir EC2 bulut sunucusu başlatın. Daha sonra vscode terminale geçerek ssh bağlantısı yapın.

(AWS üzerinde EC2 bulut sunucusu oluşturmak için; bkz.)

ssh -i .ssh/mhan-key-pair.pem ec2-user@54.89.70.14
sudo dnf update –y
sudo dnf install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo dnf -y install terraform
terraform version

Bölüm 2 - Terraform ile AWS Altyapısı Oluşturma

Terraform ile AWS de altyapı yönetimi işlemleri yapabilmek için config ayarlarının yapılması gerekir. Bunun için “aws configure” komutu kullanılır ve bu komut ile AWS kimlik bilgilerinizi (erişim anahtarı ve gizli anahtar), varsayılan bölgeyi ve çıktı formatını belirlemenizi sağlar. Bu ayarlar, AWS CLI’nin belirli bir oturumda hangi AWS hesabına ve bölgeye erişeceğini belirler.

(Access key oluşturmak için; bkz.)

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$aws configure
AWS Access Key ID [****************None]: AKIA4MTWKX7EX4TBT2ML
AWS Secret Access Key [****************None]: FPE7x4Fcbq/8eGvVXwxazdrRHXjia4zZIcsdZ5/
Default region name [None]: us-east-1
Default output format [None]: yaml

Not: Bu makale yayınlandığında buradaki access key’ler değişmiş olacak :)

Bu ayarlama yapıldıktan sonra IAM servisinde yeni role oluşturularak politika tanımlaması yapılır. Burada AmazonEC2FullAccess IAM politikası seçtik, AWS üzerinde EC2 hizmetine geniş kapsamlı erişim izni sağlar. Terraform ile EC2 örnekleri oluştururken bu yetkilere ihtiyaç duyulabilir, ancak güvenlik için en az ayrıntı prensibine uygun olarak özenle kullanılmalıdır. Production ortamlarında daha kısıtlı yetkilere sahip IAM rolleri tercih edilmelidir.

(IAM Role oluşturmak için; bkz.)

Şimdi terraform dosylarımızı oluşturabiliriz. Öncesinde çalışma yapacağımız dizini ve main.tf dosyamızı oluşturalım.

mkdir terraform-aws && cd terraform-aws && touch main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.49.0"
}
}
}

provider "aws" {
region = "us-east-1"
# access_key = "my-access-key" (aws configure ayarı yapıldıgı icin yoruma alınan satırların girilmesine gerek yoktur.)
# secret_key = "my-secret-key"
## profile = "my-profile"
}

resource "aws_instance" "tf-ec2" {
ami = "ami-07caf09b362be10b8"
instance_type = "t2.micro"
tags = {
"Name" = "ec2-instance"
}
}

Bu Terraform dosyası, AWS sağlayıcısını ve gerekli sürümünü tanımlar ve “us-east-1” bölgesindeki AWS sağlayıcısını belirtir. Ayrıca, aws_instance kaynağı oluşturarak belirtilen AMI (Amazon Machine Image) ve örnekleme türü (t2.micro) ile bir EC2 örneği oluşturur ve bu örneğe “ec2-instance” adında bir etiket ekler.

Terraform dosyasını çalıştırmadan önce, proje bağımlılıklarını yüklemek içinterraform initkomutunu kullanmalısınız. Bu komut, Terraform’un kullanacağı sağlayıcıları (provider) ve modülleri yükler.

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "5.49.0"...
- Installing hashicorp/aws v5.49.0...
- Installed hashicorp/aws v5.49.0 (signed by HashiCorp)

Terraform 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 Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

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

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

İnit komutunu çalıştırdığımızda, projenin kök dizininde .terraform ve .terraform.lock.hcl dosyaları oluşturulur. .terraform dizini, Terraform'un proje bağımlılıklarını (örneğin, kullanılan sağlayıcılar ve modüller) sakladığı bir dizindir. Bu dizin, Terraform'un proje dosyalarını düzenli bir şekilde yönetmesini sağlar ve projenin gereksinim duyduğu kaynakların versiyonlarını ve dosyalarını içerir.

.terraform.lock.hcl dosyası ise proje bağımlılıklarının (örneğin, kullanılan sağlayıcı ve modül versiyonları) belirlendiği kilit bir dosyadır. Bu dosya, Terraform'un çalışma zamanında hangi versiyonların kullanılacağını belirler ve bağımlılıkların tutarlılığını sağlar. Genellikle bu dosya elle düzenlenmemeli ve değiştirilmemelidir, çünkü Terraform'un bağımlılıkları güvenli bir şekilde yönetmesini sağlar.

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$tree -a
.
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── hashicorp
│ └── aws
│ └── 5.49.0
│ └── linux_amd64
│ ├── LICENSE.txt
│ └── terraform-provider-aws_v5.49.0_x5
├── .terraform.lock.hcl
└── main.tf

7 directories, 4 files

terraform plan komutu, Terraform'un yapacağı değişiklikleri görselleştirir ve planı oluşturur. Bu adım, gerçek değişiklikleri uygulamaz, sadece planı gösterir.

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$terraform plan

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

Terraform will perform the following actions:

# aws_instance.tf-ec2 will be created
+ resource "aws_instance" "tf-ec2" {
+ ami = "ami-07caf09b362be10b8"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ spot_instance_request_id = (known after apply)
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "ec2-instance"
}
+ tags_all = {
+ "Name" = "ec2-instance"
}
+ tenancy = (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
}

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

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

terraform plan çıktısı, Terraform'un planlanan işlemleri gösteren bir özet sunar. Bu çıktıda:

  • + create simgesi, Terraform'un yeni bir kaynak oluşturacağını gösterir.
  • aws_instance.tf-ec2 adında bir EC2 örneği oluşturulacak.
  • Oluşturulacak EC2 örneğinin detayları (ami, instance_type, tags vb.) belirtilmiştir.
  • Plan: 1 to add, 0 to change, 0 to destroy. özeti ise Terraform'un yapacağı değişiklikleri özetler:
  • 1 yeni kaynak eklenecek.
  • Değişiklik veya silme yapılacak kaynak bulunmamaktadır.

terraform apply komutunu çalıştırdıktan sonra, Terraform planını gösterir ve değişiklikleri uygulamadan önce onayınızı ister. Değişiklikleri onayladığınızda, Terraform değişiklikleri uygulamaya başlar.

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$terraform apply

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

Terraform will perform the following actions:

# aws_instance.tf-ec2 will be created
+ resource "aws_instance" "tf-ec2" {
+ ami = "ami-07caf09b362be10b8"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ spot_instance_request_id = (known after apply)
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "ec2-instance"
}
+ tags_all = {
+ "Name" = "ec2-instance"
}
+ tenancy = (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
}

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

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

Enter a value: yes

aws_instance.tf-ec2: Creating...
aws_instance.tf-ec2: Still creating... [10s elapsed]
aws_instance.tf-ec2: Still creating... [20s elapsed]
aws_instance.tf-ec2: Still creating... [30s elapsed]
aws_instance.tf-ec2: Creation complete after 32s [id=i-03135b065cd20b956]

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

Bu terraform apply çıktısı, Terraform’un planladığı işlemleri gerçekleştirmesinin ardından oluşturulan kaynak hakkında bilgi verir ve işlemin başarıyla tamamlandığını belirtir. Oluşturulan EC2 örneğiyle ilgili ayrıntılar (id, public_ip gibi) artık bilinmektedir ve bu bilgilere daha sonra proje içinde veya başka işlemlerde erişilebilir.

terraform apply komutu çalıştırıldığında oluşturulan altyapı kaynakları ve bu kaynakların durum bilgileri terraform.tfstate dosyası oluşturularak buraya kaydedilir. Bu dosya, Terraform'un yönettiği altyapı kaynaklarının mevcut durumunu izlemek ve güncellemek için kullanılır. Dosya JSON formatında olup, projenin .terraform dizini altında saklanır ve Terraform tarafından otomatik olarak yönetilir. Dosyanın doğrudan değiştirilmesi tavsiye edilmez; bunun yerine Terraform komutları aracılığıyla durum bilgilerine erişilir ve yönetilir.

Bu adımları takip ederek, Terraform dosyanızı init, plan, ve apply komutlarını kullanarak çalıştırabilir ve belirlediğiniz altyapı kaynaklarını AWS üzerinde oluşturabilir veya güncelleyebilirsiniz. Değişiklikleri geri almak veya altyapıyı silmek isterseniz, terraform destroy komutunu kullanabilirsiniz.

ec2-user@ip-172-31-16-229:~/Terraform/terraform-aws$terraform destroy
aws_instance.tf-ec2: Refreshing state... [id=i-03135b065cd20b956]

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

Terraform will perform the following actions:

# aws_instance.tf-ec2 will be destroyed
- resource "aws_instance" "tf-ec2" {
- ami = "ami-07caf09b362be10b8" -> null
- arn = "arn:aws:ec2:us-east-1:851725434825:instance/i-03135b065cd20b956" -> null
- associate_public_ip_address = true -> null
- availability_zone = "us-east-1c" -> null
- cpu_core_count = 1 -> null
- cpu_threads_per_core = 1 -> null
- disable_api_stop = false -> null
- disable_api_termination = false -> null
- ebs_optimized = false -> null
- get_password_data = false -> null
- hibernation = false -> null
- id = "i-03135b065cd20b956" -> null
- instance_initiated_shutdown_behavior = "stop" -> null
- instance_state = "running" -> null
- instance_type = "t2.micro" -> null
- ipv6_address_count = 0 -> null
- ipv6_addresses = [] -> null
- monitoring = false -> null
- placement_partition_number = 0 -> null
- primary_network_interface_id = "eni-017ce0d25145595a4" -> null
- private_dns = "ip-172-31-23-197.ec2.internal" -> null
- private_ip = "172.31.23.197" -> null
- public_dns = "ec2-107-23-167-189.compute-1.amazonaws.com" -> null
- public_ip = "107.23.167.189" -> null
- secondary_private_ips = [] -> null
- security_groups = [
- "default",
] -> null
- source_dest_check = true -> null
- subnet_id = "subnet-0f76d70f1401b5d07" -> null
- tags = {
- "Name" = "ec2-instance"
} -> null
- tags_all = {
- "Name" = "ec2-instance"
} -> null
- tenancy = "default" -> null
- user_data_replace_on_change = false -> null
- vpc_security_group_ids = [
- "sg-0d3109be0917c44ba",
] -> null
# (8 unchanged attributes hidden)

- capacity_reservation_specification {
- capacity_reservation_preference = "open" -> null
}

- cpu_options {
- core_count = 1 -> null
- threads_per_core = 1 -> null
# (1 unchanged attribute hidden)
}

- credit_specification {
- cpu_credits = "standard" -> null
}

- enclave_options {
- enabled = false -> null
}

- maintenance_options {
- auto_recovery = "default" -> null
}

- metadata_options {
- http_endpoint = "enabled" -> null
- http_protocol_ipv6 = "disabled" -> null
- http_put_response_hop_limit = 2 -> null
- http_tokens = "required" -> null
- instance_metadata_tags = "disabled" -> null
}

- private_dns_name_options {
- enable_resource_name_dns_a_record = false -> null
- enable_resource_name_dns_aaaa_record = false -> null
- hostname_type = "ip-name" -> null
}

- root_block_device {
- delete_on_termination = true -> null
- device_name = "/dev/xvda" -> null
- encrypted = false -> null
- iops = 3000 -> null
- tags = {} -> null
- tags_all = {} -> null
- throughput = 125 -> null
- volume_id = "vol-0f5562c3cae58f9a5" -> null
- volume_size = 8 -> null
- volume_type = "gp3" -> null
# (1 unchanged attribute hidden)
}
}

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

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

Enter a value: yes

aws_instance.tf-ec2: Destroying... [id=i-03135b065cd20b956]
aws_instance.tf-ec2: Still destroying... [id=i-03135b065cd20b956, 10s elapsed]
aws_instance.tf-ec2: Still destroying... [id=i-03135b065cd20b956, 20s elapsed]
aws_instance.tf-ec2: Still destroying... [id=i-03135b065cd20b956, 30s elapsed]
aws_instance.tf-ec2: Still destroying... [id=i-03135b065cd20b956, 40s elapsed]
aws_instance.tf-ec2: Destruction complete after 40s

Destroy complete! Resources: 1 destroyed.

Seriye devam etmek için sabırsızlanıyorum! Terraform ile AWS üzerinde altyapı oluşturmayı öğrenmeye başladıkça daha fazlasını keşfetmeye hazır olun. Sorularınız veya geri bildiriminiz varsa lütfen bana ulaşın. Bir sonraki bölümde görüşmek üzere!

--

--