Terraform : Web-Was-DB

Gyullbb·2021년 6월 4일
0

Cloud

목록 보기
3/3

Terraform - 2

0. 구성도

이번 게시글에서는 이전에 작성한 Terraform 문서에서 다루지 않은 내용만 다뤄볼 것이다.

1. 기존 VPC 삭제 후 VPC 및 보안그룹 생성

일반적으로 VPC 작업을 할 때 기존 VPC를 삭제하는 것을 권장한다고 한다.

AWS 콘솔에서 VPC를 삭제한 후 Terraform을 이용해서 VPC와 보안그룹을 생성한다.

#aws new vpc
resource "aws_vpc" "default"{
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"
  tags = {
    Name = "default"
  }
}

#aws default 보안 그룹
data "aws_security_group" "default"{
  name = "default"
  depends_on = ["aws_vpc.default"]
}

#외부 - 22번 포트 보안 그룹 생성
resource "aws_security_group" "ssh"{
  name = "allow_ssh_from_all"
  description = "Allow SSH port from all"
  vpc_id = aws_vpc.default.id
  depends_on = ["aws_vpc.default"]
  ingress{
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

이 때 주의해야 할 설정들이 있다. VPC를 새로 생성하면 자동으로 default 보안 그룹이 생성된다. 이 default 보안 그룹을 사용하기 위해 단순히 data로 보안 그룹을 불러온다면 VPC가 아직 생성이 되지 않았기 때문에 보안 그룹을 생성할 수 없다는 에러가 뜰 수 있다.

이를 방지 하기 위한 옵션이 depends_on이다. 어떠한 리소스가 생성된 후에 해당 리소스를 생성하라는 종속성을 위한 옵션이다.

default 보안 그룹은 VPC가 생성된 후에 만들어져야 하므로 depends_on = ["aws_vpc.default"]옵션을 추가한다.

2. EC2 생성 시 원하는 ami 찾는 방법

생성해야 하는 ami(Amazone Machine Image) 중 marketplace에는 존재하지만 ami id가 명시되어있지 않은 경우가 있다.

이런 경우..

이럴 때에는 aws cli를 활용해서 ami id를 찾을 수 있다.

# 1. aws cli 설치
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install

# 2. aws cli로 ami id 찾기
aws ec2 describe-images --owners aws-marketplace --filters "Name=name,Values=*15 SP2*" --query "reverse(sort_by(Images, &Name))[:100].ImageId" --output text
ami-039b8ca5919916521   ami-0d7d36a6e5712d9ac

3. EC2에 추가 스토리지 구성

EC2에 추가 스토리지를 구성하는 방식은 EBS를 사용하는 것이다. EBS의 종류에는 SSD, HDD, 마그네틱이 있는데 이번에는 HDD를 사용하고자 한다. (종류를 더 알고싶으면 aws-console에서 확인 가능)

순서는 EBS 생성 > EC2생성 > EC2와 EBS 연결 이다.

#ebs(web1)생성
resource "aws_ebs_volume" "web1"{
  availability_zone = "ap-northeast-2a"
  size = 150
  type = "st1"
  tags = {
    Name = "web1"
  }
}
...
#ec2(web1)생성
resource "aws_instance" "web1"{
  ami = "ami-0e4214f08b51e23cc"
  instance_type = "t3.large"
  subnet_id = aws_subnet.public1.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "web1"
  }
}

#ebs ec2(web1,web2) 연결
resource "aws_volume_attachment" "web1ebs"{
  device_name = "/dev/sdb"
  volume_id = "${aws_ebs_volume.web1.id}"
  instance_id = "${aws_instance.web1.id}"
  depends_on = ["aws_instance.web1"]
}

이 경우도 마찬가지로 종속 관계를 고려해서 생성해야 한다. 종속관계가 있는경우 depends_on속성을 사용한다.

또 주의해야할 점은 aws_volume_attachment"에 있어 instance_id를 작성할 때 "${ }"형식을 따라야 하는 것이다.

이 후 ec2에 접속해서 lsblk명령어를 통해 확인해보면 디스크가 잘 생성이 되어 붙은 것을 볼 수 있다.

4. was 구성

private 서브넷을 생성한 후 was용 ec2를 생성한다. 퍼블릭 서브넷에 NAT 게이트웨이를 구성한 후 private 서브넷을 연결한다.

방식은 이전 게시글과 같으므로 아래에 코드로 첨부하겠다.

5. RDS 보안 그룹 및 설정

WAS에서 RDS에 접근할 수 있어야하고 RDS에서 외부로 빠져나갈 수 있어야하기 때문에 보안 그룹을 설정해주어야 한다.

인바운드로 프라이빗 서브넷 ip와 postgres 포트 5432를 뚫어주고 아웃바운드로 0.0.0.0/0을 설정해준다.

#was - postgres 포트 보안 그룹 생성
resource "aws_security_group" "was-db"{
  name = "allow_postgres_from_was"
  vpc_id = aws_vpc.default.id
  description = "Allow postgres port from was"
  ingress{
    from_port = 5432
    to_port = 5432
    protocol = "tcp"
    cidr_blocks = ["10.0.3.0/24","10.0.4.0/24"]
  }
  egress{
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

이 후 RDS설정을 해준다. RDS에는 설정할 수 있는 것이 굉장히 많은데 Terraform 공식문서에서 살펴보고 필요한 것만 선별하여 설정하면 된다.(나머지는 default로 자동 생성)

여기서도 주의해야 할 사항이 있다.

  1. postgresql의 경우 username으로 admin을 사용할 수 없다.
  2. 보안 그룹을 설정할 때 vpc_security_group_ids = ["${ }"]형식을 사용해야 한다.

6. 접속

접속 순서는 다음과 같다.

public ec2(web) > private ec2(was) > rds(postgresql db)

  1. public ec2 접속

    # sudo ssh -i "ec2_key_pair.pem" centos@ec2-3-36-53-190.ap-northeast-2.compute.amazonaws.com
  2. sftp로 pem key 이동 (local > public ec2)

  3. private was 접속

    # ssh -i "ec2_key_pair.pem" {private was ip}
  4. postgres rds 접속

    # yum install -y postgres-server

    local에서 rds endpoint 확인

    # terraform console
    > aws_db_instance.was-db.endpoint

    나온 endpoint로 rds 접속

    psql --host=terraform-20210604013021074800000002.cv3tugvyuy2b.ap-northeast-2.rds.amazonaws.com --port=5432

7. 전체 코드

- provider.tf
provider "aws" {
  access_key = ""
  secret_key = ""
  region = "ap-northeast-2"
}
- web.tf
#키페어 사용
resource "aws_key_pair" "ec2_key_pair"{
  key_name = "ec2_key_pair"
  public_key = file("~/.ssh/ec2_key_pair.pub")
}

#aws new vpc
resource "aws_vpc" "default"{
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"
  tags = {
    Name = "default"
  }
}

#aws default 보안 그룹
data "aws_security_group" "default"{
  name = "default"
  depends_on = ["aws_vpc.default"]
}

#외부 - 22번 포트 보안 그룹 생성
resource "aws_security_group" "ssh"{
  name = "allow_ssh_from_all"
  description = "Allow SSH port from all"
  vpc_id = aws_vpc.default.id
  depends_on = ["aws_vpc.default"]
  ingress{
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

#web용 public subnet 생성
resource "aws_subnet" "public1"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-2a"
  map_public_ip_on_launch = true
}

resource "aws_subnet" "public2"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "ap-northeast-2c"
  map_public_ip_on_launch = true
}


#외부 접근을 위한 VPC IGW 생성
resource "aws_internet_gateway" "default-gw"{
  vpc_id = aws_vpc.default.id
  tags = {
    Name = "default-gw"
  }
}

#IGW, 외부 연결 라우팅 테이블 생성
resource "aws_route_table" "route-public-igw1"{
  vpc_id = aws_vpc.default.id
  route{
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.default-gw.id
  }
  tags = {
    Name = "terra-public1"
  }
}

#라우팅 테이블과subnet 연결
resource "aws_route_table_association" "route-public1"{
  subnet_id = aws_subnet.public1.id
  route_table_id = aws_route_table.route-public-igw1.id
}

resource "aws_route_table_association" "route-public2"{
  subnet_id = aws_subnet.public2.id
  route_table_id = aws_route_table.route-public-igw1.id
}

#ebs(web1, web2)생성
resource "aws_ebs_volume" "web1"{
  availability_zone = "ap-northeast-2a"
  size = 150
  type = "st1"
  tags = {
    Name = "web1"
  }
}

resource "aws_ebs_volume" "web2"{
  availability_zone = "ap-northeast-2c"
  size = 150
  type = "st1"
  tags = {
    Name = "web2"
  }
}

#ec2(web1, web2)생성
resource "aws_instance" "web1"{
  ami = "ami-0e4214f08b51e23cc"
  instance_type = "t3.large"
  subnet_id = aws_subnet.public1.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "web1"
  }
}

resource "aws_instance" "web2"{
  ami = "ami-0e4214f08b51e23cc"
  instance_type = "t3.large"
  subnet_id = aws_subnet.public2.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "web2"
  }
}

#ebs ec2(web1,web2) 연결
resource "aws_volume_attachment" "web1ebs"{
  device_name = "/dev/sdb" 
  volume_id = "${aws_ebs_volume.web1.id}"
  instance_id = "${aws_instance.web1.id}"
  depends_on = ["aws_instance.web1"]

}

resource "aws_volume_attachment" "web2ebs"{
  device_name = "/dev/sdb"
  volume_id = "${aws_ebs_volume.web2.id}"
  instance_id = "${aws_instance.web2.id}"
  depends_on = ["aws_instance.web2"]

}

#ebs(suse)생성
resource "aws_ebs_volume" "suse"{
  availability_zone = "ap-northeast-2a"
  size = 1000
  type = "st1"
  tags = {
    Name = "suse"
  }
}

#suse linux ec2생성
resource "aws_instance" "suse"{
  ami = "ami-097fc5cd098dd20d5"
  instance_type = "t2.micro"
  subnet_id = aws_subnet.public1.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "suse"
  }
}

#ebs ec2(suse) 연결
resource "aws_volume_attachment" "suseebs"{
  device_name = "/dev/sdb"
  volume_id = "${aws_ebs_volume.suse.id}"
  instance_id = "${aws_instance.suse.id}"
  depends_on = ["aws_instance.suse"]

}
-was.tf
#was용private subnet 생성
resource "aws_subnet" "private1"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.3.0/24"
  availability_zone = "ap-northeast-2a"
}

resource "aws_subnet" "private2"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.4.0/24"
  availability_zone = "ap-northeast-2c"
}

#NAT Gateway에 할당하기위한 탄력적 IP생성[eip]
resource "aws_eip" "nat"{
  vpc = true
}

#public subnet과 연결을 위한 NAT Gateway 생성
resource "aws_nat_gateway" "natgw1"{
  allocation_id = aws_eip.nat.id
  subnet_id = aws_subnet.public1.id
  tags = {
    Name = "natgw1"
  }
}

#NAT Gateway, 외부 연결 라우팅 테이블 생성
resource "aws_route_table" "route-private-nat1"{
  vpc_id = aws_vpc.default.id
  route{
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_nat_gateway.natgw1.id
  }
  tags = {
    Name = "route-private-nat1"
  }
}

#라우팅 테이블과 private subnet 연결
resource "aws_route_table_association" "terra-private1-route"{
  subnet_id = aws_subnet.private1.id
  route_table_id = aws_route_table.route-private-nat1.id
}

resource "aws_route_table_association" "terra-private2-route"{
  subnet_id = aws_subnet.private2.id
  route_table_id = aws_route_table.route-private-nat1.id
}

#ebs(web1, web2)생성
resource "aws_ebs_volume" "was1"{
  availability_zone = "ap-northeast-2a"
  size = 150
  type = "st1"
  tags = {
    Name = "was1"
  }
}

resource "aws_ebs_volume" "was2"{
  availability_zone = "ap-northeast-2c"
  size = 150
  type = "st1"
  tags = {
    Name = "was2"
  }
}

#ec2(was1, was2)생성
resource "aws_instance" "was1"{
  ami = "ami-0e4214f08b51e23cc"
  instance_type = "t3.large"
  subnet_id = aws_subnet.private1.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "was1"
  }
}

resource "aws_instance" "was2"{
  ami = "ami-0e4214f08b51e23cc"
  instance_type = "t3.large"
  subnet_id = aws_subnet.private2.id
  key_name = aws_key_pair.ec2_key_pair.key_name
  vpc_security_group_ids = [
    data.aws_security_group.default.id
  ]
  tags = {
    Name = "was2"
  }
}

#ebs ec2(was1,was2) 연결
resource "aws_volume_attachment" "was1ebs"{
  device_name = "/dev/sdb"
  volume_id = "${aws_ebs_volume.was1.id}"
  instance_id = "${aws_instance.was1.id}"
  depends_on = ["aws_instance.was1"]
}

resource "aws_volume_attachment" "was2ebs"{
  device_name = "/dev/sdb"
  volume_id = "${aws_ebs_volume.was2.id}"
  instance_id = "${aws_instance.was2.id}"
  depends_on = ["aws_instance.was2"]
}
- rds.tf
#rds용 private subnet 생성
resource "aws_subnet" "private3"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.5.0/24"
  availability_zone = "ap-northeast-2a"
}

resource "aws_subnet" "private4"{
  vpc_id = aws_vpc.default.id
  cidr_block = "10.0.6.0/24"
  availability_zone = "ap-northeast-2c"
}

#rds private subnet group 생성
resource "aws_db_subnet_group" "db_subnet_group"{
  name = "db_subnet_group"
  subnet_ids = [aws_subnet.private1.id,aws_subnet.private2.id]
  tags = {
    Name = "db_subnet_group"
  }
}

#was - postgres 포트 보안 그룹 생성
resource "aws_security_group" "was-db"{
  name = "allow_postgres_from_was"
  vpc_id = aws_vpc.default.id
  description = "Allow postgres port from was"
  ingress{
    from_port = 5432
    to_port = 5432
    protocol = "tcp"
    cidr_blocks = ["10.0.3.0/24","10.0.4.0/24"]
  }
  egress{
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

#rds 생성
resource "aws_db_instance" "was1-db1"{
  engine = "postgres"
  engine_version = "13.2"
  instance_class = "db.t3.large"
  allocated_storage = 100
  storage_type = "gp2"
  username = "postgres"
  password = "<DB_PASSWORD>"
  skip_final_snapshot = true
  vpc_security_group_ids = ["${aws_security_group.was-db.id}"]
  db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id
  multi_az = true 
}

resource "aws_db_instance" "was2-db2"{
  engine = "postgres"
  engine_version = "13.2"
  instance_class = "db.t3.large"
  allocated_storage = 100
  storage_type = "gp2"
  username = "postgres"
  password = "<DB_PASSWORD>"
  skip_final_snapshot = true
  vpc_security_group_ids = ["${aws_security_group.was-db.id}"]
  db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id
  multi_az = true
}
profile
🎈도전 속의 여유를 즐기자🎈

0개의 댓글