helloworld / hell world / 테라폼 예시 / 예제 / 간단 예시
Terraform 사용법
prerequisite
- AWS CLI 가 설치돼야 한다.
- AWS secret key 도 설정돼야 한다.
- terraform
기본적으로 .tf
file 을 수정하고,
terraform apply
를 하면 infra 에 반영된다.
terraform apply
을 하면, 일단 변경사항이 어떤 것들인지
보여주고, 적용할 것인지를 묻는다. 그 때 yes 를 하면 실제 적용이
이뤄진다.
- 다음처럼
main.tf
를 하나 만들고, terraform init
을 한다.- 다음 내용들이 만들어진다.
.terraform.lock.hcl
: lock file, provider version 들이 적혀있다..terraform/
: download 해서 install 한 provider 가 들어가 있다.(.exe
file)
- 다음 내용들이 만들어진다.
terraform fmt
: formatting 을 해준다. format 에 변경이 있는 file 이름만 stdout 으로 보인다.terraform validate
: 문법확인terraform apply
: code를 보고, 실제 infra 를 생성해준다.terraform.tfstatae
file- 그러면 이 때 생기는 instance 정보를 다시 가져와서
terraform.tfstatae
file에 넣어준다. - terraform 은 현재 instance 의 정보를 이 state
file(
terraform.tfstatae
) 로 판단하기 때문에 aws web console 로 변경하면 이 state file 이 out-of-sync 가 된다. - 그리고 보안도 중요하다. 그래서 이
파일(
terraform.tfstatae
)에 대한 접근은 제한적인 사람만 access 할 수 있게 해야 한다. terraform show
를 하면 이 파일의 내용을 보여준다.
- 그러면 이 때 생기는 instance 정보를 다시 가져와서
terraform state list
: 이것을 하면 terraform state file 에 있는 resource 의 list 를 보여준다.terraform destroy
: 만들어 놓은 infra 를 삭제한다. dependency 가 있으면, 그에 맞는 순서대로 terraform 이 삭제해 준다.terraform output
:.tf
에서 output 으로 정의한 것들을 보여주게 된다.
# main.tf
# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "myserverid1" {
ami = "ami-055437ee4dcf92427"
instance_type = "t2.micro"
tags = {
Name = "my-instance-name-namh"
}
}
# 이 부분을 따로 variable.tf 등으로 만들어도 상관없다. 동작은 같다.
variable "instance_name" {
description = "Value of the Name tag for the EC2 instance"
type = string
default = "my-instance-name-namh"
}
# 이 부분을 따로 output.tf 등으로 만들어도 상관없다. 동작은 같다.
output "instance_id" {
description = "ID of the EC2 instance"
value = aws_instance.namh-test.id
}
d:\a\terrform\test>terraform fmt
hello.tf
d:\a\terrform\test>terraform validate
Success! The configuration is valid.
terraform 에서 infra 변경
만약 위 main.tf
에서 ami
부분을 변경하면,
terraform 은 현재 떠 있는 instance 에서 ami 를 변경할 수 없기 때문에
기존의 것을 삭제 하고 새로운 ami 로 instance 를 만들게 된다.
resource "aws_instance" "myserverid1" {
ami = "ami-0676d41f079015f32"
instance_type = "t2.micro"
d:\a\terrform\test>terraform apply
aws_instance.namh-test: Refreshing state... [id=i-05b38172e99a351bd]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.namh-test must be replaced
-/+ resource "aws_instance" "namh-test" {
~ ami = "ami-055437ee4dcf92427" -> "ami-0676d41f079015f32" # forces replacement
~ arn = "arn:aws:ec2:ap-northeast-2:786531771744:instance/i-05b38172e99a351bd" -> (known after apply)
~ associate_public_ip_address = true -> (known after apply)
~ availability_zone = "ap-northeast-2a" -> (known after apply)
~ cpu_core_count = 1 -> (known after apply)
~ cpu_threads_per_core = 1 -> (known after apply)
~ disable_api_stop = false -> (known after apply)
~ disable_api_termination = false -> (known after apply)
~ ebs_optimized = false -> (known after apply)
- hibernation = false -> null
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
~ id = "i-05b38172e99a351bd" -> (known after apply)
~ instance_initiated_shutdown_behavior = "stop" -> (known after apply)
~ instance_state = "running" -> (known after apply)
~ ipv6_address_count = 0 -> (known after apply)
~ ipv6_addresses = [] -> (known after apply)
+ key_name = (known after apply)
~ monitoring = false -> (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
~ placement_partition_number = 0 -> (known after apply)
~ primary_network_interface_id = "eni-0024d58ca1afb689e" -> (known after apply)
~ private_dns = "ip-172-31-6-77.ap-northeast-2.compute.internal" -> (known after apply)
~ private_ip = "172.31.6.77" -> (known after apply)
~ public_dns = "ec2-52-78-198-216.ap-northeast-2.compute.amazonaws.com" -> (known after apply)
~ public_ip = "52.78.198.216" -> (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [
- "default",
] -> (known after apply)
~ subnet_id = "subnet-d1f1b0b8" -> (known after apply)
~ tags = {
~ "Name" = "ExampleAppServerInstance" -> "namh-test"
}
~ tags_all = {
~ "Name" = "ExampleAppServerInstance" -> "namh-test"
}
~ tenancy = "default" -> (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
~ vpc_security_group_ids = [
- "sg-14baa97d",
] -> (known after apply)
# (4 unchanged attributes hidden)
~ capacity_reservation_specification {
~ capacity_reservation_preference = "open" -> (known after apply)
+ capacity_reservation_target {
+ capacity_reservation_id = (known after apply)
+ capacity_reservation_resource_group_arn = (known after apply)
}
}
- credit_specification {
- cpu_credits = "unlimited" -> null
}
+ ebs_block_device {
+ delete_on_termination = (known after apply)
+ device_name = (known after apply)
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ snapshot_id = (known after apply)
+ tags = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = (known after apply)
+ volume_type = (known after apply)
}
~ enclave_options {
~ enabled = false -> (known after apply)
}
+ ephemeral_block_device {
+ device_name = (known after apply)
+ no_device = (known after apply)
+ virtual_name = (known after apply)
}
~ maintenance_options {
~ auto_recovery = "default" -> (known after apply)
}
~ metadata_options {
~ http_endpoint = "enabled" -> (known after apply)
~ http_put_response_hop_limit = 1 -> (known after apply)
~ http_tokens = "optional" -> (known after apply)
~ instance_metadata_tags = "disabled" -> (known after apply)
}
+ network_interface {
+ delete_on_termination = (known after apply)
+ device_index = (known after apply)
+ network_card_index = (known after apply)
+ network_interface_id = (known after apply)
}
~ private_dns_name_options {
~ enable_resource_name_dns_a_record = false -> (known after apply)
~ enable_resource_name_dns_aaaa_record = false -> (known after apply)
~ hostname_type = "ip-name" -> (known after apply)
}
~ root_block_device {
~ delete_on_termination = true -> (known after apply)
~ device_name = "/dev/xvda" -> (known after apply)
~ encrypted = false -> (known after apply)
~ iops = 100 -> (known after apply)
+ kms_key_id = (known after apply)
~ tags = {} -> (known after apply)
~ throughput = 0 -> (known after apply)
~ volume_id = "vol-0e01fc659049ed2d4" -> (known after apply)
~ volume_size = 8 -> (known after apply)
~ volume_type = "gp2" -> (known after apply)
}
}
Plan: 1 to add, 0 to change, 1 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.namh-test: Destroying... [id=i-05b38172e99a351bd]
aws_instance.namh-test: Still destroying... [id=i-05b38172e99a351bd, 10s elapsed]
aws_instance.namh-test: Still destroying... [id=i-05b38172e99a351bd, 20s elapsed]
aws_instance.namh-test: Destruction complete after 30s
aws_instance.namh-test: Creating...
aws_instance.namh-test: Still creating... [10s elapsed]
aws_instance.namh-test: Still creating... [20s elapsed]
aws_instance.namh-test: Still creating... [30s elapsed]
aws_instance.namh-test: Creation complete after 31s [id=i-0ff6c6e6655dec3bc]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
terraform destroy
d:\a\terrform\test>terraform destroy
aws_instance.namh-test: Refreshing state... [id=i-0ff6c6e6655dec3bc]
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.namh-test will be destroyed
- resource "aws_instance" "namh-test" {
- ami = "ami-0676d41f079015f32" -> null
- arn = "arn:aws:ec2:ap-northeast-2:786531771744:instance/i-0ff6c6e6655dec3bc" -> null
- associate_public_ip_address = true -> null
- availability_zone = "ap-northeast-2a" -> 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-0ff6c6e6655dec3bc" -> 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-0ebdd0e3153dba51d" -> null
- private_dns = "ip-172-31-5-167.ap-northeast-2.compute.internal" -> null
- private_ip = "172.31.5.167" -> null
- public_dns = "ec2-3-35-50-89.ap-northeast-2.compute.amazonaws.com" -> null
- public_ip = "3.35.50.89" -> null
- secondary_private_ips = [] -> null
- security_groups = [
- "default",
] -> null
- source_dest_check = true -> null
- subnet_id = "subnet-d1f1b0b8" -> null
- tags = {
- "Name" = "namh-test"
} -> null
- tags_all = {
- "Name" = "namh-test"
} -> null
- tenancy = "default" -> null
- user_data_replace_on_change = false -> null
- vpc_security_group_ids = [
- "sg-14baa97d",
] -> null
- capacity_reservation_specification {
- capacity_reservation_preference = "open" -> null
}
- credit_specification {
- cpu_credits = "unlimited" -> null
}
- enclave_options {
- enabled = false -> null
}
- maintenance_options {
- auto_recovery = "default" -> null
}
- metadata_options {
- http_endpoint = "enabled" -> 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
- throughput = 125 -> null
- volume_id = "vol-0198723c2720811de" -> null
- volume_size = 8 -> null
- volume_type = "gp3" -> null
}
}
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.namh-test: Destroying... [id=i-0ff6c6e6655dec3bc]
aws_instance.namh-test: Still destroying... [id=i-0ff6c6e6655dec3bc, 10s elapsed]
aws_instance.namh-test: Still destroying... [id=i-0ff6c6e6655dec3bc, 20s elapsed]
aws_instance.namh-test: Destruction complete after 30s
Destroy complete! Resources: 1 destroyed.
terraform output
d:\a\prog\terrform\test>terraform output
╷
│ Warning: No outputs found
│
│ The state file either has no outputs defined, or all the defined outputs are empty. Please define an output in your
│ configuration with the `output` keyword and run `terraform refresh` for it to become available. If you are using
│ interpolation, please verify the interpolated value is not empty. You can use the `terraform console` command to
│ assist.
╵
d:\a\prog\terrform\test>terraform apply
aws_instance.namh-test: Refreshing state... [id=i-0f9248e0f31df356f]
Changes to Outputs:
+ instance_id = "i-0f9248e0f31df356f"
You can apply this plan to save these new output values to the Terraform state, without changing any real
infrastructure.
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
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
instance_id = "i-0f9248e0f31df356f"
d:\a\prog\terrform\test>terraform output
instance_id = "i-0f9248e0f31df356f"
기본 rds 생성하는 예제
rds 생성하는 terraform이다. 이것은 기존에 존재하는 security group 등을 사용했다.
# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = var.region
}
data "aws_availability_zones" "available" {}
resource "aws_db_parameter_group" "myproj" {
name = "myproj"
family = "mariadb10.6"
# parameter {
# name = "log_connections"
# value = "1"
# }
}
resource "aws_db_instance" "myproj-1" {
identifier = "myproj-1"
instance_class = "db.t3.micro"
allocated_storage = 5
engine = "MariaDB"
engine_version = "10.6.12"
username = "myusername"
password = var.db_password
# my-group-prod
# https://ap-northeast-2.console.aws.amazon.com/rds/home?region=ap-northeast-2#db-subnet-group:id=my-group-prod
db_subnet_group_name = "my-group-prod"
vpc_security_group_ids = [
"sg-0a0a0a0a0a0a0a0aa", # my security group 1
"sg-0b0b0b0b0b0b0b0b" # my security group 2
]
# https://ap-northeast-2.console.aws.amazon.com/rds/home?region=ap-northeast-2#parameter-groups-detail:ids=mariadb-10-6-v220825;type=DbParameterGroup;editing=false
parameter_group_name = "mariadb-10-6-v220825"
publicly_accessible = true
skip_final_snapshot = true
}
# ----------------------------------------
# variable
# ----------------------------------------
variable "region" {
default = "ap-northeast-2"
description = "AWS region"
}
variable "db_password" {
description = "RDS root user password"
sensitive = true
}
# ----------------------------------------
# output
# ----------------------------------------
output "rds_hostname" {
description = "RDS instance hostname"
value = aws_db_instance.myproj-1.address
sensitive = true
}
output "rds_port" {
description = "RDS instance port"
value = aws_db_instance.myproj-1.port
sensitive = true
}
output "rds_username" {
description = "RDS instance root username"
value = aws_db_instance.myproj-1.username
sensitive = true
}
state 가 다른 방법으로 변경되었을 때 다시 state 를 맞추는 법
terraform plan -refresh-only
terraform 으로 만든후, web console로 변경하면, state 의 sync가 달라지게 된다. 그 때 다시 state 를 sync 하는 방법이다.
terraform plan -refresh-only
를 해서 변경되는 state 가
마음에 들면, terraform apply -refresh-only
를 하면 state
file 내용이 변경된다. 이 때 infrastructure 를 적은 .tf 파일 내용은
변경되지 않는다.
terraform plan -refresh-only
terraform apply -refresh-only
terraform state mv
- Terraform: How To Rename (Instead Of Deleting) A Resource - DEV Community
- Command: state mv | Terraform | HashiCorp Developer
예시:
resource stage_b 를 stage_c 로 이름 변경하는 경우
resource "aws_instance" "stage_b" {
...
}
resource "aws_instance" "stage_c" {
...
}
terraform state mv aws_instance.stage_b aws_instance.stage_c
moved
stage_b
를 stage_c
로 변경한 경우 아래 처럼
써주고, terraform apply
를 해주면 된다. apply 를 하고나선
moved
는 삭제되어도 된다.
resource "aws_instance" "stage_c" {
...
}
moved {
from = aws_instance.stage_b
to = aws_instance.stage_c
}
만약 .tfstate 파일이 없을때.
만약 infra 가 존재하고 있고, .tfstate
가 없다면, 어떻게
해야 하는가?
이 때는 terraformer 를 사용하도록 하자. 개인적인
경험으로는, terraform import
를 이용하는 것이 낫다.
terraform import
먼저 terraform 에 import 할 내용을 일부 적는다. 그리고 import 를 하면 된다.
아래는 ec2 예시다. ec2 에서는 id 를 사용하고, 다른 곳에서는 id 외의 것을 사용할 수도 있다.
팁: 일단 그냥 시도해봐도 된다. 존재하지 않으면, 존재하지 않는다는 error 가 뜬다. AWS console 의 description 부분을 보면 된다. 그리고 terraformer 을 이용해도 id를 얻을 수 있다.
팁2: terraform console
을 이용하면, import 한 값들을
확인할 수 있다.
resource "aws_instance" "example" {
# ...instance configuration...
}
terraform import aws_instance.example i-abcd1234
terraform 과 infra 의 연결을 끊으려면(detach)
cloud 에 있는 service 는 그대로 두고, terraform 의 resource 를 지우는 방법.
terraform state 에서 지우면 된다.
terraform state list
terraform state rm <name>
terraform.tfstate 를 s3 에 저장하는 법
# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
backend "s3" {
bucket = "mys3bucket-name"
key = "global/ex/myapp/terraform.tfstate"
region = "ap-northeast-2"
}
}
instance 를 생성후 bash script 실행하는 법
Learning how to execute a Bash script from Terraform | by Brad Simonin | Medium, 2020-02-27
cloud init
Provision Infrastructure with Cloud-Init | Terraform | HashiCorp Developer : 모든 cloud provider 가 cloud init 을 제공한다고 한다. 이것을 이용해서 초기 script 를 실행하라고 한다.
Install Docker via Cloud Init on Ubuntu VM · GitHub, cloud-init yml file example
- ubuntu 에서 docker 설치 하는 cloud-init script
User-data scripts is not running on my custom AMI, but working in standard Amazon linux - Stack Overflow : custom AMI 인 경우 user_data 가 동작안할 수 있다.
aws에서는 이미 만들어진 instance 에서 추가로 user_data 를 넣는 경우에도 동작하지 않는다. 처음 instance를 만들때만 동작하는 듯 하다.
/var/log/cloud-init-output.log
resource "aws_instance" "linux_instance" {
...
provisioner "file" {
source = "./mysetup.sh" # local 에서의 bash script 위치
destination = "/tmp/mysetup.sh" # aws 에서의 위치
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/mysetup.sh", # 권한 변경
"sudo /tmp/mysetup.sh", # 실행
]
}
# Login to the ec2-user with the aws key.
connection {
type = "ssh"
user = "ec2-user"
password = ""
private_key = file(var.keyPath)
host = self.public_ip
}
}
댓글 없음:
댓글 쓰기