brunch

You can make anything
by writing

C.S.Lewis

by Master Seo Aug 19. 2023

15. 테라폼 - Terraform Cloud(TFC)



<1> Terraform Cloud(TFC)

<2> 예제 에러 조치와 배포



<1> Terraform Cloud(TFC)


1

TFC ?

워크플로 구성 환경 제공, Github Action 보다 자유도는 낮지만 VCS연동, 변수 구성, RBAC, 원격 실행 환경 등의 기능 활용


2

TFC 권한 관리 : p273~278, Standard Plan 이상 필요로 skip


3

다음 저장소 포크 : https://github.com/terraform101/terraform-aws-tfc-workflow


4

github 사용 사용 가능한지 확인 하자!!!

https://github.com/topasvga/terraform-aws-tfc-workflow


terraform 블록에 지정된 cloud 백엔드의 organization 의 값을 소유한 이름으로 변경하자.


MyGit=<>

MyGit=topasvga

git clone https://github.com/$MyGit/terraform-aws-tfc-workflow

cd terraform-aws-tfc-workflow


MyTfcOrg=<각자 자신의 TFC 조직명>

MyTfcOrg=topasvga-org

sed -i -e "s/<MY-ORG>/$MyTfcOrg/g" main.tf


git add main.tf

git commit -m "init"

git push


5

#  main.tf 내용 확인

terraform {

  cloud {

    organization = "topasvga-org"

    hostname     = "app.terraform.io" # default




6

terraform init



7

[테라폼 클라우드 에서 작업]


TFC 생성 워크스페이스에 Execution Mode를 Remote로 유지

terraform-aws-tfc-workflow > Setting >   Remote = 실행이 로컬에서 하는것이 아니라, 테라폼 클라우드가 테라폼 plan , 테라폼 apply를 한다!!!


7

terraform plan

// terraform plan #-var=prefix=dev

Running plan in Terraform Cloud. Output will stream here. Pressing Ctrl-C

will stop streaming the logs, but will not stop the plan running remotely.

Preparing the remote plan...

To view this run in a browser, visit:

https://app.terraform.io/app/topasvga-org/terraform-aws-tfc-workflow/runs/run-Em1iqPj9KH3VJZrh



Terraform Cloud(TFC) 에서 확인

테라폼 가입된 다른 팀원들도 같이 볼수 있다!!

Run에서 확인.

에러 보면 프리픽스가 없다?




<2> 예제 에러 조치와 배포


1

생성된 work space에서 Variables로 간다.

TFC 리모트 실행 환경에서의 테라폼 입력 변수와 시스템 환경 변수 관리 : 워크스페이스 → Variables


입력 변수 : TFC에서는 실행 후 인라인으로 넣을 수 없기 때문이며, 기존 terraform.tfvars 를 대체하는 역할을 수행함. 따라서 기존 terraform.tfvars 파일은 동작하지 않는다. (이제 로컬이 아니다)


환경 변수 : 테라폼 실행 환경은 더 이상 로컬 작업 환경이 아닌 원격지의 TFC 환경이다. 프로비저닝하는 클라우드의 API 키 또는 테라폼 실행 설정 등이 구성되어야 하는 경우와 같은 상황에서 사용된다



2

Variables > Add Variables


Terraform variable 선택

 Key(prefix), value(topasvga =사용자 닉네임)


Environment variable 선택

Key(AWS_ACCESS_KEY_ID), value(자신의 값)


Environment variable 선택

Key(AWS_SECRET_ACCESS_KEY), value(자신의 값), Sensitive 선택

3개 입력 완료.




5

테라폼 클라우드에서 실행되는것이지만, 콘솔해서 해본다. 

terraform plan 

// 혹, 우분트 에러 발생되는경우 ?   iam 계정에 권한이 없어서 발생한다. 



6

terraform apply

>> 아직 yes 입력 하지 말자

원격 테라폼 클라우드에서 실행되는 것이다.



7

TFC 워크스페이스에서 Overview 확인 → [See details] 클릭해서 내용을 우선 보자.

실행된거 내용들 나온다.

 [Confirm & Apply] 클릭  



8

AWS 콘솔상에서 VPC와 EC2 생성 되었는지 확인한다.

  default     = "10.0.0.0/16"



9

TFC 워크스페이스나  명령서버에서 Overview 확인

output등 결과가 확인된다.

사이트 접속등 확인한다.


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

Outputs:

catapp_ip = "http://3.38.223.64"

catapp_url = "http://ec2-3-38-223-64.ap-northeast-2.compute.amazonaws.com"



10

삭제 ?

terraform destroy -auto-approve

삭제해도 리모트(TFC 워크스페이스)에서 삭제가 실행된다.







11

테라폼 파일 참고

[root@myeks2-bastion-EC2 terraform-aws-tfc-workflow]# ls

files  LICENSE  main.tf  outputs.tf  README.md  variables.tf


[root@myeks2-bastion-EC2 terraform-aws-tfc-workflow]# more *.tf

::::::::::::::

main.tf

::::::::::::::

terraform {

  cloud {

    organization = "topasvga-org"

    hostname     = "app.terraform.io" # default

    workspaces {

      name = "terraform-aws-tfc-workflow"

    }

  }

  required_providers {

    aws = {

      source  = "hashicorp/aws"

      version = "~> 4.0"

    }

  }

}

provider "aws" {

  region = var.region

  default_tags {

    tags = {

      Project = "Coffee-Mug-Cake"

      Owner   = "jerry & tom"

    }

  }

}

resource "aws_vpc" "hashicat" {

  cidr_block           = var.address_space

  enable_dns_hostnames = true

  tags = {

    name        = "${var.prefix}-vpc-${var.region}"

    environment = "Production"

  }

}

resource "aws_subnet" "hashicat" {

  vpc_id     = aws_vpc.hashicat.id

  cidr_block = var.subnet_prefix

  tags = {

    name = "${var.prefix}-subnet"

  }

}

resource "aws_security_group" "hashicat" {

  name = "${var.prefix}-security-group"

  vpc_id = aws_vpc.hashicat.id

  ingress {

    from_port   = 22

    to_port     = 22

    protocol    = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port   = 80

    to_port     = 80

    protocol    = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port   = 443

    to_port     = 443

    protocol    = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  egress {

    from_port       = 0

    to_port         = 0

    protocol        = "-1"

    cidr_blocks     = ["0.0.0.0/0"]

    prefix_list_ids = []

  }

  tags = {

    Name = "${var.prefix}-security-group"

  }

}

resource "aws_internet_gateway" "hashicat" {

  vpc_id = aws_vpc.hashicat.id

  tags = {

    Name = "${var.prefix}-internet-gateway"

  }

}

resource "aws_route_table" "hashicat" {

  vpc_id = aws_vpc.hashicat.id

  route {

    cidr_block = "0.0.0.0/0"

    gateway_id = aws_internet_gateway.hashicat.id

  }

}

resource "aws_route_table_association" "hashicat" {

  subnet_id      = aws_subnet.hashicat.id

  route_table_id = aws_route_table.hashicat.id

}

data "aws_ami" "ubuntu" {

  most_recent = true

  owners      = ["099720109477"] # Canonical

  filter {

    name   = "name"

    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]

  }

  filter {

    name   = "virtualization-type"

    values = ["hvm"]

  }

}

resource "aws_eip" "hashicat" {

  instance = aws_instance.hashicat.id

  vpc      = true

}

resource "aws_eip_association" "hashicat" {

  instance_id   = aws_instance.hashicat.id

  allocation_id = aws_eip.hashicat.id

}

resource "aws_instance" "hashicat" {

  ami                         = data.aws_ami.ubuntu.id

  instance_type               = var.instance_type

  key_name                    = aws_key_pair.hashicat.key_name

  associate_public_ip_address = true

  subnet_id                   = aws_subnet.hashicat.id

  vpc_security_group_ids      = [aws_security_group.hashicat.id]

  tags = {

    Name = "${var.prefix}-hashicat-instance"

  }

}

# We're using a little trick here so we can run the provisioner without

# destroying the VM. Do not do this in production.

# If you need ongoing management (Day N) of your virtual machines a tool such

# as Chef or Puppet is a better choice. These tools track the state of

# individual files and can keep them in the correct configuration.

# Here we do the following steps:

# Sync everything in files/ to the remote VM.

# Set up some environment variables for our script.

# Add execute permissions to our scripts.

# Run the deploy_app.sh script.

resource "null_resource" "configure-cat-app" {

  depends_on = [aws_eip_association.hashicat]

  // triggers = {

  //   build_number = timestamp()

  // }

  provisioner "file" {

    source      = "files/"

    destination = "/home/ubuntu/"

    connection {

      type        = "ssh"

      user        = "ubuntu"

      private_key = tls_private_key.hashicat.private_key_pem

      host        = aws_eip.hashicat.public_ip

    }

  }

  provisioner "remote-exec" {

    inline = [

      "sudo apt -y update",

      "sleep 15",

      "sudo apt -y update",

      "sudo apt -y install apache2",

      "sudo systemctl start apache2",

      "sudo chown -R ubuntu:ubuntu /var/www/html",

      "chmod +x *.sh",

      "PLACEHOLDER=${var.placeholder} WIDTH=${var.width} HEIGHT=${var.height} PREFIX=${var.prefix} ./deploy_app.sh",

      "sudo apt -y install cowsay",

      "cowsay Mooooooooooo!",

    ]

    connection {

      type        = "ssh"

      user        = "ubuntu"

      private_key = tls_private_key.hashicat.private_key_pem

      host        = aws_eip.hashicat.public_ip

    }

  }

}

resource "tls_private_key" "hashicat" {

  algorithm = "RSA"

}

locals {

  private_key_filename = "${var.prefix}-ssh-key.pem"

}

resource "aws_key_pair" "hashicat" {

  key_name   = local.private_key_filename

  public_key = tls_private_key.hashicat.public_key_openssh

}

::::::::::::::

outputs.tf

::::::::::::::

output "catapp_url" {

  value = "http://${aws_eip.hashicat.public_dns}"

}

output "catapp_ip" {

  value = "http://${aws_eip.hashicat.public_ip}"

}

::::::::::::::

variables.tf

::::::::::::::

variable "prefix" {

  description = "This prefix will be included in the name of most resources."

}

variable "region" {

  description = "The region where the resources are created."

  default     = "ap-northeast-2"

}

variable "address_space" {

  description = "The address space that is used by the virtual network. You can supply more than one address space. Changing this forces a new resource to be c

reated."

  default     = "10.0.0.0/16"

}

variable "subnet_prefix" {

  description = "The address prefix to use for the subnet."

  default     = "10.0.10.0/24"

}

variable "instance_type" {

  description = "Specifies the AWS instance type."

  default     = "t3.micro"

}

variable "height" {

  default     = "400"

  description = "Image height in pixels."

}

variable "width" {

  default     = "600"

  description = "Image width in pixels."

}

variable "placeholder" {

  default     = "placekitten.com"

  description = "Image-as-a-service URL. Some other fun ones to try are fillmurray.com, placecage.com, placebeard.it, loremflickr.com, baconmockup.com, placeim

g.com, placebear.com, placeskull.com, stevensegallery.com, placedog.net"

}


[root@myeks2-bastion-EC2 terraform-aws-tfc-workflow]#  terraform destroy -auto-approve




다음과정

https://brunch.co.kr/@topasvga/3410

다음은 주말 CloudNet 테라폼 스터디 내용 참고하여  정리한 부분입니다.

https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863  


감사합니다.


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari