2024 KDT 📕/Project

[ AWS Terraform ] NginX 리버스 프록시 설정 관련

L_Chae 2024. 7. 22. 13:25

terraform 코드에서 명시적으로 지정하려고 했는데 에러가 발생했다.

가장 쉬운 방법은 수동으로 터미널 진입해서 작성해주는건데, 일단 2차 프로젝트에서는 이렇게 진행하고, 3차에는 프로비저너 이용해서 쓰는 걸로 하자 ...

# 원본 코드
resource "aws_instance" "A_Public" {
  ami           = "ami-062cf18d655c0b1e8"
  instance_type = "t2.medium"
  subnet_id     = aws_subnet.Public_A1.id
  key_name      = "KDT_Project2_AWS"

  vpc_security_group_ids = [aws_security_group.default.id]

  tags = {
    Name = "A_Public"
  }

  user_data = <<-EOF
              #!/bin/bash

              # 로깅 확인 파일 생성
              LOG_FILE=/var/log/user_data.log
              exec > >(tee -a $LOG_FILE) 2>&1
              
              # 호스트 이름 변경
              hostnamectl set-hostname a-public
              echo "127.0.1.1 a-public" >> /etc/hosts
              echo "호스트 이름 변경 완료!"

              # SSH 포트 변경
              sed -i 's/#Port 22/Port 51228/' /etc/ssh/sshd_config
              systemctl restart sshd
              echo "SSH 포트 변경 성공!"

              # PEM 파일 생성 및 권한 설정
              echo "${var.key_pair_content}" > /home/ubuntu/KDT_Project2_AWS.pem
              chmod 400 /home/ubuntu/KDT_Project2_AWS.pem
              echo "키 페어 파일 생성 및 권한 설정 완료!"

              # Nginx 및 OpenJDK 17 설치
              sudo apt-get update
              sudo apt-get install -y curl gnupg2 ca-certificates lsb-release

              # ubuntu-keyring 패키지 설치
              sudo apt-get install -y ubuntu-keyring

              # nginx.list 파일 생성 : 공식 저장소에서 서명 키 가져오기
              curl -s https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
                  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

              # 다운로드한 키가 올바른지 확인
              gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

              # 저장소 설정 (Stable version)
              echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
              http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
                  | sudo tee /etc/apt/sources.list.d/nginx.list

              # 저장소 업데이트
              sudo apt-get update

              # nginx 설치
              sudo apt-get install -y nginx

              # nginx 버전 확인
              nginx -v

              # nginx 가동 시작
              sudo systemctl start nginx

              # OpenJDK 17 설치
              sudo apt update
              sudo apt install -y openjdk-17-jdk
              echo "Nginx와 JDK 17 설치 완료!"

              # Nginx 리버스 프록시 설정
              A_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.A_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)
              B_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.B_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)
              
              sudo sed -i '/http {/a \\
              upstream inclass-spring-security {\\
                server ${A_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
                server ${B_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
              }\\
              server {\\
                location / {\\
                  proxy_pass http://inclass-spring-security;\\
                  proxy_http_version 1.1;\\
                  proxy_set_header Upgrade $http_upgrade;\\
                  proxy_set_header Connection "upgrade";\\
                  proxy_set_header Host $host;\\
                  proxy_cache_bypass $http_upgrade;\\
                }\\
              }' /etc/nginx/nginx.conf

              sudo systemctl restart nginx
              echo "Nginx 리버스 프록시 설정 완료!"
              EOF
}

resource "aws_eip" "a_public_eip" {
  instance = aws_instance.A_Public.id
  vpc      = true
}

이 코드에서 수정 진행, 2차 플젝은 저기서 nginx 리버스 프록시 설정하는 버전 지우고, 수동으로 설정해줌

 

에러 코드 : 

Error: Invalid reference
│
│   on ec2_instances.tf line 167, in resource "aws_instance" "A_Public":
│  167:                 server ${A_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
│
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
╵
╷
│ Error: Invalid reference
│
│   on ec2_instances.tf line 168, in resource "aws_instance" "A_Public":
│  168:                 server ${B_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
│
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.

GPT의 대답 : 

Terraform에서 인스턴스의 Private IP를 가져오기 위해서는 데이터 소스를 사용해야 합니다. aws_instance 리소스가 생성된 후에 IP 주소를 사용할 수 있기 때문에, user_data에서 바로 사용할 수 없습니다.

해결 방법:

local-exec 프로비저너를 사용하여 인스턴스 생성 후 IP 주소를 가져오고, 필요한 파일을 구성합니다. Terraform에서 변수와 데이터 소스를 사용하여 이를 수행할 수 있습니다.

1. 인스턴스 정의 수정

먼저, aws_instance 리소스 정의에서 user_data를 단순화하고, 이후에 local-exec 프로비저너를 사용하여 Nginx 설정을 구성합니다.

resource "aws_instance" "A_Public" {
  ami           = "ami-062cf18d655c0b1e8"
  instance_type = "t2.medium"
  subnet_id     = aws_subnet.Public_A1.id
  key_name      = "KDT_Project2_AWS"

  vpc_security_group_ids = [aws_security_group.default.id]

  tags = {
    Name = "A_Public"
  }

  user_data = <<-EOF
              #!/bin/bash

              # 로깅 확인 파일 생성
              LOG_FILE=/var/log/user_data.log
              exec > >(tee -a $LOG_FILE) 2>&1
              
              # 호스트 이름 변경
              hostnamectl set-hostname a-public
              echo "127.0.1.1 a-public" >> /etc/hosts
              echo "호스트 이름 변경 완료!"

              # SSH 포트 변경
              sed -i 's/#Port 22/Port 51228/' /etc/ssh/sshd_config
              systemctl restart sshd
              echo "SSH 포트 변경 성공!"

              # PEM 파일 생성 및 권한 설정
              echo "${var.key_pair_content}" > /home/ubuntu/KDT_Project2_AWS.pem
              chmod 400 /home/ubuntu/KDT_Project2_AWS.pem
              echo "키 페어 파일 생성 및 권한 설정 완료!"

              # Nginx 및 OpenJDK 17 설치
              sudo apt-get update
              sudo apt-get install -y curl gnupg2 ca-certificates lsb-release

              # ubuntu-keyring 패키지 설치
              sudo apt-get install -y ubuntu-keyring

              # nginx.list 파일 생성 : 공식 저장소에서 서명 키 가져오기
              curl -s https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
                  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

              # 다운로드한 키가 올바른지 확인
              gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

              # 저장소 설정 (Stable version)
              echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
              http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
                  | sudo tee /etc/apt/sources.list.d/nginx.list

              # 저장소 업데이트
              sudo apt-get update

              # nginx 설치
              sudo apt-get install -y nginx

              # nginx 버전 확인
              nginx -v

              # nginx 가동 시작
              sudo systemctl start nginx

              # OpenJDK 17 설치
              sudo apt update
              sudo apt install -y openjdk-17-jdk
              echo "Nginx와 JDK 17 설치 완료!"
              EOF

  provisioner "local-exec" {
    command = <<-EOF
              A_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.A_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)
              B_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.B_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)

              ssh -i /path/to/your/private/key ubuntu@${self.public_ip} << 'EOC'
              sudo sed -i '/http {/a \\
              upstream inclass-spring-security {\\
                server ${A_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
                server ${B_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
              }\\
              server {\\
                location / {\\
                  proxy_pass http://inclass-spring-security;\\
                  proxy_http_version 1.1;\\
                  proxy_set_header Upgrade $http_upgrade;\\
                  proxy_set_header Connection "upgrade";\\
                  proxy_set_header Host $host;\\
                  proxy_cache_bypass $http_upgrade;\\
                }\\
              }' /etc/nginx/nginx.conf
              sudo systemctl restart nginx
              EOC
              EOF
  }
}

resource "aws_eip" "a_public_eip" {
  instance = aws_instance.A_Public.id
  vpc      = true
}

2. 데이터 소스를 사용하여 인스턴스 정보 가져오기

인스턴스 생성 후에 Private IP 주소를 가져오는 방법을 추가합니다.

data "aws_instance" "A_Private01" {
  instance_id = aws_instance.A_Private01.id
}

data "aws_instance" "B_Private01" {
  instance_id = aws_instance.B_Private01.id
}

이제 local-exec 프로비저너에서 data 블록을 사용하여 인스턴스의 Private IP 주소를 가져올 수 있습니다.

3. 통합된 코드

아래는 통합된 코드입니다.

provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "KDT_Project2" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "Public_A1" {
  vpc_id            = aws_vpc.KDT_Project2.id
  cidr_block        = "10.0.1.0/24"
  map_public_ip_on_launch = true
}

resource "aws_security_group" "default" {
  vpc_id = aws_vpc.KDT_Project2.id

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

  ingress {
    from_port   = 51228
    to_port     = 51228
    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 = "default"
  }
}

resource "aws_instance" "A_Public" {
  ami           = "ami-062cf18d655c0b1e8"
  instance_type = "t2.medium"
  subnet_id     = aws_subnet.Public_A1.id
  key_name      = "KDT_Project2_AWS"

  vpc_security_group_ids = [aws_security_group.default.id]

  tags = {
    Name = "A_Public"
  }

  user_data = <<-EOF
              #!/bin/bash

              # 로깅 확인 파일 생성
              LOG_FILE=/var/log/user_data.log
              exec > >(tee -a $LOG_FILE) 2>&1
              
              # 호스트 이름 변경
              hostnamectl set-hostname a-public
              echo "127.0.1.1 a-public" >> /etc/hosts
              echo "호스트 이름 변경 완료!"

              # SSH 포트 변경
              sed -i 's/#Port 22/Port 51228/' /etc/ssh/sshd_config
              systemctl restart sshd
              echo "SSH 포트 변경 성공!"

              # PEM 파일 생성 및 권한 설정
              echo "${var.key_pair_content}" > /home/ubuntu/KDT_Project2_AWS.pem
              chmod 400 /home/ubuntu/KDT_Project2_AWS.pem
              echo "키 페어 파일 생성 및 권한 설정 완료!"

              # Nginx 및 OpenJDK 17 설치
              sudo apt-get update
              sudo apt-get install -y curl gnupg2 ca-certificates lsb-release

              # ubuntu-keyring 패키지 설치
              sudo apt-get install -y ubuntu-keyring

              # nginx.list 파일 생성 : 공식 저장소에서 서명 키 가져오기
              curl -s https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
                  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

              # 다운로드한 키가 올바른지 확인
              gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

              # 저장소 설정 (Stable version)
              echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
              http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
                  | sudo tee /etc/apt/sources.list.d/nginx.list

              # 저장소 업데이트
              sudo apt-get update

              # nginx 설치
              sudo apt-get install -y nginx

              # nginx 버전 확인
              nginx -v

              # nginx 가동 시작
              sudo systemctl start nginx

              # OpenJDK 17 설치
              sudo apt update
              sudo apt install -y openjdk-17-jdk
              echo "Nginx와 JDK 17 설치 완료!"
              EOF

  provisioner "local-exec" {
    command = <<-EOF
              A_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.A_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)
              B_PRIVATE01_IP=$(aws ec2 describe-instances --instance-ids ${aws_instance.B_Private01.id} --query "Reservations[*].Instances[*].PrivateIpAddress" --output text)

              ssh -i /path/to/your/private/key ubuntu@${self.public_ip} << 'EOC'
              sudo sed -i '/http {/a \\
              upstream inclass-spring-security {\\
                server ${A_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
                server ${B_PRIVATE01_IP}:8080 weight=100 max_fails=3 fail_timeout=3s;\\
              }\\
              server {\\
                location / {\\
                  proxy_pass http://inclass-spring-security;\\
                  proxy_http_version 1.1;\\
                  proxy_set_header Upgrade $http_upgrade;\\
                  proxy_set_header Connection "upgrade";\\
                  proxy_set_header Host $host;\\
                  proxy_cache_bypass $http_upgrade;\\
                }\\
              }' /etc/nginx/nginx.conf
              sudo systemctl restart nginx
              EOC
              EOF
  }
}

resource "aws_eip" "a_public_eip" {
  instance = aws_instance.A_Public.id
  vpc      = true
}

data "aws_instance" "A_Private01" {
  instance_id = aws_instance.A_Private01.id
}

data "aws_instance" "B_Private01" {
  instance_id = aws_instance.B_Private01.id
}

이제 aws_instance 리소스가 생성된 후에 local-exec 프로비저너를 사용하여 인스턴스의 Private IP 주소를 가져오고, 필요한 Nginx 설정을 수행할 수 있습니다.