카테고리 없음

[2023-05-16 화] AWS CloudFormation, 테라폼

16비트 2023. 5. 16. 18:35

1. 개념 복습, 실습 환경 세팅

IaC(코드형 인프라) 정리

  • 애드혹 스크립트는 사용자 데이터처럼 스크립트를 수동으로 간단한 설치에 사용되는 도구. 배시 스크립트
  • 구성관리도구는 앤서블처럼 서버 자체를 구축하지 못하고 이미 구축된 서버의 웹 데몬, 웹 어플, 웹 앱을 구성하고 관리하는 도구. 퍼핏(Openstack), AWS Opsworks(ec2 구성 관리 도구로 셰프, 퍼핏)
  • 서버 템플릿 도구는 스냅샷으로 이미지를 생성하여 쉽게 서버를 생성하는 도구. docker는 이미지를 build하고 배포를 자동화
  • 오케스트레이션은 docker를 관리할 목적으로 업데이트 및 롤백, 자동 복구, 자동 확장, 로드 밸런싱, 서비스 검색 기능 제공하는 도구. Kubernetes
  • 프로비전 도구는 IaC를 관리함. Terraform

 

실습환경 세팅

전원 켜기

 

aws ec2 associate-route-table --subnet-id $test_pub_2a --route-table-id $test_pub_rtb 명령의 의미

이 명령을 해줘야 퍼블릭 서브넷의 기능을 할 수 있다

 

 

aws ec2 modify-vpc-attribute --vpc-id $test_vpc --enable-dns-hostnames 명령의 의미

이 명령을 통해 무료로 제공되는 DNS 주소(엔드포인트 주소)가 나온다

 

2. CloudFormation VPC 스크립트 만들기

AWS CloudFormation(Azure Resource Manager,GCP Deployment Manager)

- 주요 섹션 설명
1. Resources(생성)

  • AWS 인프라의 실질적인 섹션입니다. EC2 인스턴스, S3 버킷, ELB등과 같은 클라우드 포메이션을 이용해 AWS 웹 콘솔에서 실행하는 것으로 거의 모든 리소스 유형을 생성할 수 있습니다.
  • 리소스에는 기본 반환값이 있습니다. Ref를 이용해 이 반환값을 얻어올 수 있고 템플릿의 다른 위치에 사용할 수 있습니다.
  • 예를 들어 AWS::EC2::VPC 리소스 유형은 기본 반환값을 갖고 있고 이 값은 VPC의 ID 입니다.

2. Parameters(입력) 

  • 명령줄 도구에 입력하는 매개변수와 동일하게 스택(명령어를 일정한 순서로 실행시키는 구조)을 만들거나 업데이트할 때 정의하는 입력값입니다.
  • 파라미터는 템플릿의 변경 없이도 스택을 커스터마이즈할 수 있게 해줍니다. => 코드를 바꾸지 않고 외부에서 변수를 통해 옵션을 변경할 수 있다.
  • AMI ID, VPC ID, Subnet ID등과 같은 매개변수를 사용할 수 있습니다.

3. Output(출력) 

  • 스택이 완료된 후에 결과물을 출력하려고 할때 유용합니다. 예를 들어 ELB의 퍼블릭 URL이나 EC2의 퍼블릭 IP를 출력할 수 있습니다.

4. Mapping(지정)

  • 리전의 특화된 템플릿에서 어떠한 요소를 참조할 때 필요합니다.
  • 예를 들어 템플릿에 EC2 AMI ID에 대한 매핑을 지정하는 것입니다. AMI ID가 리전에 특화된 리소스이기 때문에 유효한 AMI ID를 리전별로 지정하려고 할때 사용합니다.
  • 서울 리전의 AMI ID와 도쿄 리전의 AMI ID가 다른 것을 확인할 수 있다

 

글꼴 : consoleas; 알파벳은 띄어쓰기와 크기가 같다. 한글은 크기 적용은 안됨.

CloudFormation 스크립트 작성

yaml 파일 : CloudFormation 스크립트

# vi test-vpc.yaml
AWSTemplateFormatVersion: 2010-09-09    # 버전 정보. 없어도 된다
Resources:
  VPC:
    Type: AWS::EC2::VPC   # VCP 생성시 정의해줘야하는 타입
    Properties:
      CidrBlock: 192.168.0.0/16
      EnableDnsSupport: true  # default 옵션이 true라서 없어도 된다. 그래도 넣어줌, False면 EC2가 Amazon DNS 정보를 못가져온다
      EnableDnsHostnames: true # VPC에서 시작된 인스턴스가 DNS 호스트 이름을 가져오는지 여부를 나타냅니다. 활성화된 경우 VPC의 인스턴스는 DNS 호스트 이름을 가져옵니다
      InstanceTenancy: default   # VPC로 시작된 인스턴스는 인스턴스 시작 중에 다른 테넌시를 명시적으로 지정하지 않는 한 기본적으로 공유 하드웨어에서 실행됩니
      Tags:
        - Key: Name
          Value: test-vpc
  PUB2A:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2a
      VpcId: !Ref VPC         # 어느 VPC에서 생성할 것인지 선언. '!'는 명령을 간소화하기 위해 씀
      CidrBlock: 192.168.0.0/20
      MapPublicIpOnLaunch: true   # 이 서브넷에서 시작된 인스턴스가 퍼블릭 IPv4 주소를 수신하는지 여부를 나타냅니다. 기본값은 입니다 false.
      Tags:
        - Key: Name
          Value: test-pub-2a
  PUB2B:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2b
      VpcId: !Ref VPC
      CidrBlock: 192.168.16.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2b
  PUB2C:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2c
      VpcId: !Ref VPC
      CidrBlock: 192.168.32.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2c
  PUB2D:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2d
      VpcId: !Ref VPC
      CidrBlock: 192.168.48.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2d
  PVT2A:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2a
      VpcId: !Ref VPC
      CidrBlock: 192.168.64.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2a
  PVT2B:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2b
      VpcId: !Ref VPC
      CidrBlock: 192.168.80.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2b
  PVT2C:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2c
      VpcId: !Ref VPC
      CidrBlock: 192.168.96.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2c
  PVT2D:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2d
      VpcId: !Ref VPC
      CidrBlock: 192.168.112.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2d
  InternetGateway:    # 인터넷 게이트웨이 생성
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: test-igw
  VPCGatewayAttachment:      # VPC와 인터넷 게이트웨이 연결
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PUBRTB:      # 퍼블릭 라우팅 테이블 설정
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: test-pub-rtb
  PVTRTB:     # 프라이빗 라우팅 테이블 생성
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: test-pvt-rtb
  InternetRoute:   # 퍼블릭 라우팅 테이블에 인터넷 게이트웨이 라우팅 설정
    Type: AWS::EC2::Route
    DependsOn: InternetGateway
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
      RouteTableId: !Ref PUBRTB
  PUB2ARTBAssociation:   # 퍼블릭 서브넷과 퍼블릭 라우팅 테이블을 명시적으로 연결
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2A
  PUB2BRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2B
  PUB2CRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2C
  PUB2DRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2D
  PVT2ARTBAssociation:  # 프라이빗 서브넷과 프라이빗 라우팅 테이블을 명시적으로 연결
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2A
  PVT2BRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2B
  PVT2CRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2C
  PVT2DRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2D

 

3.  CloudFormation에 사용할 VPC 스크립트 만들기

붙여넣기 할 수 있는 스크립트

더보기

AWSTemplateFormatVersion: 2010-09-09
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 192.168.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: test-vpc
  PUB2A:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2a
      VpcId: !Ref VPC
      CidrBlock: 192.168.0.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2a
  PUB2B:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2b
      VpcId: !Ref VPC
      CidrBlock: 192.168.16.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2b
  PUB2C:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2c
      VpcId: !Ref VPC
      CidrBlock: 192.168.32.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2c
  PUB2D:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2d
      VpcId: !Ref VPC
      CidrBlock: 192.168.48.0/20
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: test-pub-2d
  PVT2A:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2a
      VpcId: !Ref VPC
      CidrBlock: 192.168.64.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2a
  PVT2B:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2b
      VpcId: !Ref VPC
      CidrBlock: 192.168.80.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2b
  PVT2C:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2c
      VpcId: !Ref VPC
      CidrBlock: 192.168.96.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2c
  PVT2D:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-2d
      VpcId: !Ref VPC
      CidrBlock: 192.168.112.0/20
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: test-pvt-2d
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: test-igw
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PUBRTB:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: test-pub-rtb
  PVTRTB:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: test-pvt-rtb
  InternetRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGateway
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
      RouteTableId: !Ref PUBRTB
  PUB2ARTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2A
  PUB2BRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2B
  PUB2CRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2C
  PUB2DRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PUBRTB
      SubnetId: !Ref PUB2D
  PVT2ARTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2A
  PVT2BRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2B
  PVT2CRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2C
  PVT2DRTBAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PVTRTB
      SubnetId: !Ref PVT2D

 

메모장에 붙여넣기 하고 스크립트 저장

 

CloudFormation에 스크립트로 리소스 생성

스택 생성

※ 참고 - AWS에서 기본으로 제공하는 샘플 템플릿이나 드래그를 통해서 CloudFormation을 생성할 수 있다

 

CloudFormation은 저장공간이 없어서 S3나 템플릿 파일을 업로드시켜야 한다

망도로 한번 보기

 

스택 이름 'test-vpc'

 

잘 생성된 것을 확인할 수 있다.

 

템플릿을 통해서 인스턴스 만들기

 

# aws ec2 describe-vpcs      // VPC ID를 확인

 

# aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0eb1c066ccffd9129" --query 'Subnets[*].{ID:SubnetId,CIDR:CidrBlock}' --output table

curl ipconfig.io     // 에코시스템. 내 IP를 확인할 수 있다

ec2 생성 스크립트 작성

# vi test-ec2.yaml
AWSTemplateFormatVersion: 2010-09-09
Mappings:     # 리전 매핑
  RegionMap:   # 리전에 따른 AMI ID를 넣어준다. 내가 만든 AMI ID도 넣어줄 수 있다
    ap-northeast-2:
      AMIID: ami-035da6a0773842f64
    ap-northeast-1:
      AMIID: ami-08928044842b396f0
Parameters:   # 파라미터에 내가 넣고 싶은 값을 넣어둘 수 있다
  InstanceType:
    Type: String
    Default: t2.micro
    Description: Enter instance size. Default is t2.micro
  VPC:
    Type: String
    Default: vpc-0eb1c066ccffd9129    # 생성한 VPC ID 넣어주기. # aws ec2 describe-vpcs로 확인 가능
    Description: VPC ID.
  Subnet:
    Type: String
    Default: subnet-04e690404e0dc3890  # 생성한 퍼블릭 Subnet 2a ID 넣어주기. # aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0eb1c066ccffd9129" --query 'Subnets[*].{ID:SubnetId,CIDR:CidrBlock}' --output table
    Description: Subnet ID.
  AMI:
    Type: String
    Default: AMIID
    Description: The Linux AMI to use.
  Key:
    Type: String
    Default: test-key
    Description: The key used to access the instance.
Resources:
  InstanceSecurityGroup:  # 보안 그룹 생성
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "test-sg-web"
      GroupDescription: "test-sg-web"
      VpcId: !Ref VPC     # 위에 작성한 Parameter의 VPC ID 값으로 설정
      SecurityGroupIngress:     # 들어오는 트래픽에 대한 Ingress 보안그룹 생성
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 106.253.56.124/32     # 송파 강의실 IP를 넣어줌. curl ipconfig.io 에코시스템 명령으로 ip를 알 수 있다
        - IpProtocol: icmp
          FromPort: '-1'
          ToPort: '-1'
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:    # 나가는 트래픽에 대한 Egress 보안그룹 생성
        - IpProtocol: -1      # 나가는 트래픽에 대해 모두 허용하겠다는 뜻
          CidrIp: 0.0.0.0/0
  EC2Insteance:     # 인스턴스 생성
    Type: AWS::EC2::Instance
    Properties:
      SubnetId: !Ref Subnet
#      ImageId: !Ref AMI
      ImageId: !FindInMap [ RegionMap, !Ref "AWS::Region", !Ref AMI ]   # 값이 여러개(Mapping일 때) 함수 사용. RegionMap에 있는 리전 중에 AWS::Region으로 사용자 리전을 알아내서 AMI를 가져와서 RegionMap과 일치하는 것을 적용 
      InstanceType:   # '!'를 안쓰면 두 줄로 표현해야 한다
        Ref: InstanceType
      KeyName: !Ref Key   # '!'를 쓰면 한 줄로 표현 가능
      SecurityGroupIds:
        - Ref: InstanceSecurityGroup
      BlockDeviceMappings:    # 여러 개를 넣어 줄 수도 있다
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
        - DeviceName: /dev/xvdb
          Ebs:
            VolumeSize: 8
      Tags:    # 태그 정보
        - Key: Name
          Value: test-ec2

      UserData:     # 웹서버로 만드는 유저 데이터 입력
        Fn::Base64: |    # '|'는 enter로 개행해서 명령줄 입력이 가능하게 만듦
          #cloud-boothook
          #!/bin/bash
          yum install -y httpd
          systemctl enable --now httpd
          echo "Hello World!" > /var/www/html/index.html
Outputs:  
  PublicIp:    
    Description: PublicIp Output    
    Value: {"Fn::GetAtt": ["EC2Insteance","PublicIp"]}  # GetAtt으로 정보를 가져온다. EC2 ID와 퍼블릭 IP를 가져와서 Output한다

 

4. 인스턴스 스크립트 생성

붙여넣기 가능한 스크립트

더보기

AWSTemplateFormatVersion: 2010-09-09
Mappings:
  RegionMap:
    ap-northeast-2:
      AMIID: ami-035da6a0773842f64
    ap-northeast-1:
      AMIID: ami-08928044842b396f0
Parameters:
  InstanceType:
    Type: String
    Default: t2.micro
    Description: Enter instance size. Default is t2.micro
  VPC:
    Type: String
    Default: vpc-0eb1c066ccffd9129
    Description: VPC ID.
  Subnet:
    Type: String
    Default: subnet-04e690404e0dc3890
    Description: Subnet ID.
  AMI:
    Type: String
    Default: AMIID
    Description: The Linux AMI to use.
  Key:
    Type: String
    Default: test-key
    Description: The key used to access the instance.
Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "test-sg-web"
      GroupDescription: "test-sg-web"
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 106.253.56.124/32
        - IpProtocol: icmp
          FromPort: '-1'
          ToPort: '-1'
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
  EC2Insteance:
    Type: AWS::EC2::Instance
    Properties:
      SubnetId: !Ref Subnet
#      ImageId: !Ref AMI
      ImageId: !FindInMap [ RegionMap, !Ref "AWS::Region", !Ref AMI ]
      InstanceType:
        Ref: InstanceType
      KeyName: !Ref Key
      SecurityGroupIds:
        - Ref: InstanceSecurityGroup
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
        - DeviceName: /dev/xvdb
          Ebs:
            VolumeSize: 8
      Tags:
        - Key: Name
          Value: test-ec2

      UserData:
        Fn::Base64: |
          #cloud-boothook
          #!/bin/bash
          yum install -y httpd
          systemctl enable --now httpd
          echo "Hello World!" > /var/www/html/index.html
Outputs:  
  PublicIp:    
    Description: PublicIp Output    
    Value: {"Fn::GetAtt": ["EC2Insteance","PublicIp"]}

 

5. CloudFormation으로 인스턴스 만들기

CloudFormation에 스크립트 업로드하여 인스턴스 만들기

작성한 스크립트를 yaml 파일로 저장

 

S3 버킷 만들기

 

yaml파일 업로드

 

CloudFormation 생성

 

객체 URL 복사

Amazon S3 URL에 붙여넣기

 

스택 이름 'test-ec2'

파라미터 값을 스크립트로 정해놨기 때문에 자동으로 채워져있다. 안정해놓으면 수동으로 설정해야함

 

 

잘 생성되었다

 

접속테스트. 

스크립트에 출력을 설정해놨기 때문에 인스턴스의 퍼블릭 IP가 나온다

접속이 잘된다

 

서울 VPC 스크립트를 수정해서 도쿄 리전에 VPC를 생성

리전명을 '-2'에서 '-1'으로 변경    // 리전을 서울에서 도쿄로 바꾼다

서브넷 '2b'가 없기 때문에 다 지워줌

 

'PUB2' 되어있는 것들 'PUB1' 변경

'PVT2' 되어있는 것들 'PUB1' 변경

다른 이름으로 저장 'test-vpc-tokyo.yaml'

 

s3에 test-vpc-tokyo 스크립트 업로드

// 서울에 S3가 있지만 글로벌 서비스라서 괜찮음

 

도쿄 리전에 CloudFormation 스택 만들기

 

스택 이름 'test-vpc-tokyo'

 

도쿄 리전에 스크립트를 수정해서 EC2를 만들기


하지만 키가 없음. 만들어줘야한다

명령어를 바로 붙여넣으면 안된다

기본 리전이 'ap-northeast-2'로 되어있기 때문

도쿄 리전에 키 생성 명령어

# aws ec2 create-key-pair --region ap-northeast-1  --key-name tokyo-key --query 'KeyMaterial' --output text > tokyo-key.pem

도쿄 리전에 키가 생성되었다

스크립트 수정

VPC ID, 서브넷 ID, 키 이름 tokyo-key

 

S3 버킷에 'test-ec2-tokyo' 스크립트 업로드

접속 테스트

6. CloudFormation 정리하기, 테라폼 개요

서울 리전, 도쿄 리전 CloudFormation 지우기

CloudFormation를 지우면 다 지워진다. EC2, VPC 지워준다

 

키 페어는 안지워진다. 수동으로 만들었기 때문

직접 지워준다

 

서울 리전 CloudFormation도 지워준다

 

Terraform 이란?

  • 과거 시스템 관리자는 인프라를 수동으로 구축하고 관리했습니다. 그리고 모든 서버, 데이터베이스, 로드 밸런서, 네트워크를 수작업으로 생성하고 관리했기 때문에 서버 다운, 구성 실수, 배포 오류가 자주 발생하였습니다.
  • 테라폼은 간단한 선언적 언어를 사용하여 인프라를 코드로 정의합니다.
  • 몇 가지 명령을 사용하여 AWS, Azure, GCP 같은 다양한 퍼블릭 클라우드 공급자와 오픈스택, ESXi 같은 프라이빗 클라우드와 가상화 플랫폼에서 해당 인프라를 배포 및 관리하게 합니다.

 

--- Terraform 작동 방식

  • 테라폼은 해시코프사에서 Go언어로 개발한 오픈소스도구입니다. 
  • 운영체제마다 바이너리 파일이 존재하는데 Go 코드는 하나의 바이너리 파일로 컴파일되며 Terraform이라는 명령어로 실행할 수 있습니다.
  • 이 Terraform 명령어를 사용하여 노트북, 데스크탑, 빌드 서버 또는 다른 컴퓨터에서든 인프라를 배포할 수 있으며 이를 위해 추가 인프라(마스터, 에이전트)를 생성할 필요가 없습니다.
  • 즉 Terraform 명령어가 AWS, Azure, GCP, Openstack 등의 Provider를 대신해 API를 호출하여 리소스를 생성합니다.
  • 테라폼은 생성하려는 인프라 정보가 담겨 있는 텍스트로 이루어진 테라폼 구성 파일을 생성하여 API를 호출합니다.
  • 이러한 구성 값들이 '코드형 인프라'를 만드는 바로 그 '코드'입니다.
  • 팀의 누군가가 인프라를 수정하고자 할 때, 서버에 직접 접속하여 작업하거나 수작업으로 수정하는 대신 테라폼을 사용하여 구성 파일을 수정할 있습니다. 


Terraform 주요 명령어

 *.tf 스크립트 작성

  • terraform init
    플러그인을 다운받아야함. terraform 명령어에는 테라폼의 기본 기능이 포함되어 있지만 모든 공급자(AWS, Azure, GCP 등)에 대한 코드가 포함되어 있지 않습니다.
    그렇게 때문에 terraform init 명령어를 실행하여 테라폼에 코드를 스캔하도록 지시하고 어느 공급자인지 확인하고, 필요한 코드를 다운로드하도록 해야 합니다.
    기본적으로 공급자 코드는 테라폼의 .terraform 폴더에 플러그인 형태로 다운로드됩니다.
  • terraform plan
    테라폼이 구성 파일을 사용하여 작업을 수행하기 전에 코드의 온전성을 검사할 수 있습니다.
    plan 명령어는 리눅스에서 쓰이는 diff 명령의 결괏값과 유사합니다(비교해서 차이점을 보여줌).
    + 가 있는 항목은 추가되고, - 가 있는 항목은 삭제된다는 뜻입니다. ~ 가 있는 항목은 수정됩니다. 
  • terraform apply
    테라폼의 구성 파일을 실행하려면 terraform apply 명령어를 실행합니다.
    resource "<PROVIDER>_<TYPE>" "<NAME>" { # PROVIDER는 aws 같은 공급자의 이름이고 TYPE은 instance 같이 해당 공급자에서 생성할 리소스 유형입니다. NAME은 테라폼 코드에서 이 리소스를 참조하기 위해 사용할 수 있는 example과 같은 '식별자'입니다. CONFIG는 특정 리소스에 대한 하나 이상의 인수(argument)로 구성됩니다.
      [CONFIG ...]
    }
    작성 예)
    resource "aws_vpc" "main" {
      cidr_block = var.base_cidr_block
    }

  • <BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
      # Block body
      <IDENTIFIER> = <EXPRESSION> # Argument
    }
    블록은 다른 콘텐츠의 컨테이너이며 일반적으로 리소스와 같은 일종의 개체 구성을 나타냅니다.
    블록에는 블록 유형이 있고 , 0개 이상의 레이블이 있을 수 있으며 , 여러 인수와 중첩된 블록을 포함하는 본문이 있습니다.
    대부분의 Terraform 기능은 구성 파일의 최상위 블록에 의해 제어됩니다.

    - 인수는 이름에 값을 할당합니다. 블록 내에 나타납니다.

    - 식은 문자 그대로 또는 다른 값을 참조하고 결합하여 값을 나타냅니다. 인수의 값으로 나타나거나 다른 표현식 내에 나타납니다.

 

7. 테라폼 실습

테라폼 설치

# yum install -y yum-utils
# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo    // 테라폼은 centos 저장소에 없다. centos가 관리하지 않기 때문에 리포지토리를 추가해야한다
# yum -y install terraform

# terraform -version     // 최신 버전이 잘 설치되었다

 

설치 방법 2)   // 지금은 안씀
// # wget https://releases.hashicorp.com/terraform/1.2.3/terraform_1.2.3_linux_amd64.zip
// # wget https://releases.hashicorp.com/terraform/1.4.6/terraform_1.4.6_linux_amd64.zip
// # unzip terraform_1.2.3_linux_amd64.zip
// # unzip terraform_1.4.6_linux_amd64.zip
// # mv terraform /usr/bin/      // binary 폴더에 넣어 명령어를 자유롭게 사용할 수 있음
// # terraform -version

 

# ls -al    // IAM 유저의 정보가 담겨있다

credentials에는 id와 key 암호가 들어가있다

config에는 리전과 파일 형식이 들어가있다

 

※ 일회용 키 로그인 방법 (세션이 끊기면 데이터가 날아감). 처음에 로그인할 때 변수에 넣어두는 방법.

export AWS_ACCESS_KEY_ID=(your access key id)
export AWS_SECRET_ACCESS_KEY=(your secret access key)

 

 

IaC는 별도의 워크스테이션을 만드는 것이 좋다

# cd ~

# mkdir terraform && cd $_

# mkdir tf-test && cd $_

# vi main.tf       //  자원을 정의하는 main 모듈. EC2를 만들 것이다
provider "aws" {       // 문자열을 넣을 때는 " " 사이에 넣어야 한다
  region = "ap-northeast-2"    // 서울 리전에 테라폼을 만들겠다
}

resource "aws_instance" "example" {    // 자원이 'aws 인스턴스'이고, 논리적 ID가 'example'인 resource 블록.
  ami                    = "ami-035da6a0773842f64"       // 서울 리전의 Amazon Linux 2 AMI (HVM) - Kernel 5.10    instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]    // 아이디를 밑에서 참조해서 가져온다. 여러 가지의 항목을 넣을 때는 리스트 사용

  user_data = <<-EOF    // End Of Files 사용자 데이터를 넣기위한 구문. 웹서버 인스턴스를 만든다
              #!/bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "<h1>example</h1>" > /var/www/html/index.html
              EOF

  tags = {    // 인스턴스 이름
    Name = "tf-web01"
  }
}

resource "aws_security_group" "instance" {    // 타입이 'aws 보안 그룹'이고, 논리적 ID가 'instance'인 resource 블록

  name = var.security_group_name   // 밑에서 선언한 variable 레이블 블록의 default 값 "terraform-example-instance" 을 가져온다.

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    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"]
  }

  tags = {
    Name = "tf-web"       // 인스턴스 태그
  }

}

variable "security_group_name" {    
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

 

붙여넣기 가능한 스크립트

# vi main.tf

더보기

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]

  user_data = <<-EOF

              #cloud-boothook
              #!/bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "<h1>Terraform</h1>" > /var/www/html/index.html
              EOF

  tags = {
    Name = "tf-web01"
  }
}

resource "aws_security_group" "instance" {

  name = var.security_group_name

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    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"]
  }

  tags = {
    Name = "tf-web"
  }

}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

 

# terraform init    // 실행 파일이 생겼다

terraform 명령어에는 테라폼의 기본 기능이 포함되어 있지만 모든 공급자(AWS, Azure, GCP 등)에 대한 코드가 포함되어 있지 않습니다. 그렇게 때문에 terraform init 명령어를 실행하여 테라폼에 코드를 스캔하도록 지시하고 어느 공급자인지 확인하고, 필요한 코드를 다운로드하도록 해야 합니다. 기본적으로 공급자 코드는 테라폼의 .terraform 폴더에 플러그인 형태로 다운로드됩니다.

# ls -al

# terraform plan  // know after apply 는 나중에 추가되면 알게 되는 것. 다 새롭게 추가되는 것이기에 '+' 표시.

테라폼이 구성 파일을 사용하여 작업을 수행하기 전에 코드의 온전성을 검사할 수 있습니다. plan 명령어는 리눅스에서 쓰이는 diff 명령의 결괏값과 유사합니다. + 가 있는 항목은 추가되고, - 가 있는 항목은 삭제된다는 뜻입니다. ~ 가 있는 항목은 수정됩니다. 

# terraform apply    //  yes. 리소스가 만들어진다. 테라폼의 구성 파일을 실행하려면 terraform apply 명령어를 실행합니다.

생성이 완료되면 퍼블릭 IP가 출력된다

 

접속테스트

 

8. 마무리

인스턴스의 태그값 수정해보기

# vi main.tf

# terraform init     // 최신버전이라서 다시 실행파일을 다운로드받지 않는다

 

# terraform plan    // 변경된 부분이 '~'로 표시된다

 

# ls -al    // terraform.tfstate파일에 과거 기록들이 저장되어있다

# terraform apply

 

인스턴스 Name이 변경되었다

 

# terraform destroy    // 생성했던 리소스가 다 날라감