brunch
매거진 테라폼 AWS

15. 테라폼 - Terraform Cloud(TFC)

by Master Seo



<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개 입력 완료.


60 plan.png



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"


70 ok.png


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

Terraform.png

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

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


감사합니다.


keyword
매거진의 이전글14. 테라폼 -프로비저닝 파이프라인-깃헙 액션