AWS 서비스

[클라우드] basic. 클라우드 인프라 구성해보기

szoo_ 2024. 9. 19. 10:23

[주의사항]

이 글은 간단한 프론트엔드와 백엔드를 구성하여 인프라 구축을 하는 실습을 진행합니다.

사전 준비 지식으로는 AWS의 VPC, EC2 사용법Docker 이미지와 컨테이너를 생성하는 방법이 필요합니다.

따라서 만약 위 지식을 아예 모른다면 다른 글을 읽고오는 것을 추천 드립니다.

 

Introduce. 클라우드 인프라 시작하기

 

Introduce. 클라우드 인프라 시작하기

클라우드??  뭐부터 시작해야 하나요?클라우드를 시작하면 AWS, Docker.. 등등을 공부하고,만약 팀에서 역할이 개발(프론트엔드, 백엔드, 인공지능) / 클라우드 인프라 관리로 나뉘었다면?"어? 인프

sz-tech.tistory.com


이번 글은 배운 것들을 토대로 AWS 인프라를 구축하고, 도커를 설치하여 애플리케이션을 띄운 뒤 엔드테스트까지 하는 실습을 할 것이다.

진행 순서

1. VPC 생성

2. 보안그룹 생성

3. 인스턴스 생성 + 도커 설치

4. 프론트, 백엔드 애플리케이션 실행

5. E2E(End to End) 테스트

 

으로 진행 될 예정이다.

 

아래는 실습으로 할 요소들의 정보를 한번에 정리했다.

직접 아래의 정보를 보며 실습을 진행해도 되고,

내가 설명하는 과정을 따라하며 하나씩 진행해가도 좋을 것이다.

 

네트워크 정보

  • VPC
    • 가용 영역: 서울 ap-northeast-2 
    • name: blog_vpc
    • IPv4 CIDR: 10.0.0.0/16
  • Subnet(서브넷 - 퍼블릭, 프라이빗 / 2개)
    • AZ: ap-northeast-2a 
    • blog_subnet_public(CIDR - 10.0.1.0/24)
    • blog_subnet_private(CIDR - 10.0.2.0/24)
  • Routing Table(라우팅 테이블 - 퍼블릭, 프라이빗 / 2개)
    • blog_rtb_public 
      연결: blog_subnet_public
    • blog_rtb_private
      연결: blog_subnet_private
  • Internet gateway (인터넷 게이트웨이)
    • blog_igw
      연결: blog_rtb_public
    • blog_rtb_public 
      연결: blog_rtb_private
  • security groups (보안 그룹)
    • blog_sg_public - 포트: 22 / 80 / 3000
    • blog_sg_private - 포트: 22 /  3000

인스턴스 정보

  1. blog_ec2_public
    - AMI: Amazon Linux 2023 (64bit)
    - 인스턴스 유형: t2.micro
    - 키페어 선택(ssh 연결하게끔하는 키)
    - 네트워크(편집 버튼을 누르면 설정 가능)
      - VPC: blog_vpc
      - subnet: blog_subnet_public
      - 퍼블릭 IP 자동 할당: 활성화
      - 방화벽: 기존 보안 그룹 선택 - blog_sg_public
  2. blog_ec2_private
    - AMI: Amazon Linux 2023 (64bit)
    - 인스턴스 유형: t2.micro
    - 키페어 선택(ssh 연결하게끔하는 키)
    - 네트워크(편집 버튼을 누르면 설정 가능)
      - VPC: blog_vpc
      - subnet: blog_subnet_private
      - 퍼블릭 IP 자동 할당: 활성화
      - 방화벽: 기존 보안 그룹 선택 - blog_sg_private

VPC 생성하기

하나씩 생성해보는 것도 좋지만 어느정도 감을 익히고 난 뒤엔 해당 작업이 귀찮게 느껴질 것이다.

그래서 조금 더 편한 방법을 알려주고자한다.

 

1. VPC 생성하기

방법은 생성할 리소스에서 "VPC만"을 선택하는 것이 아닌,
"VPC등" 을 선택하는 것이다.

해당 선택지는 VPC를 생성할 때 VPC에 기본적으로 구성될 항목들을 미리 지정하여 한번에 생성 할 수 있다.

 

 

VPC 설정

  • 생성할 리소스: VPC 등
  • 이름 태그 자동 생성: 자동 생성 체크 해제 > 오른쪽 미리 보기에서 직접 각 요소의 이름 지정해주기
  • IPv4 CIDR 블록: 10.0.0.0/16
  • 가용 영역(AZ) 수: 1개
  • 퍼블릭 서브넷 수: 1개
  • 프라이빗 서브넷 수: 1개
  • NAT 게이트웨이(이것으로 인해 조금의 비용이 부과될 것이다): 1개의 AZ에서
  • VPC 엔드 포인트: 없음

이렇게 구성한 뒤 생성하면 보안그룹을 제외한 나머지는 모두 설정되어 있는 것을 확인 할 수 있다.
(생성할 때 모든 세팅을 하기 때문에 시간이 조금 걸린다.)


보안그룹

보안그룹은 간편하게 설정하고 그런거 없다. 열심히 만들자

 

퍼블릭 보안그룹 - 생성시 VPC 확인!!!

프라이빗 보안 그룹 - 생성시 VPC 확인!!!


EC2 인스턴스 생성하기

간혹 인스턴스마다 도커를 설치하는 것은 자원 낭비라고 생각하는 사람이 있다.

왜냐하면 "결국 돌리는 애플리케이션은 하나인데 직접 환경을 구성하지 않고, 굳이 도커 컨테이너로 띄워야 하나?" 싶은 생각이기도 하다.

하지만 만약 돌려야하는 인스턴스가 10개, 100개일때도 한개씩 붙잡고 환경을 구성하고 변경사항을 하나씩 적용할 것인가?

실제로 도커를 사용하거나 하지 않거나 성능차이는 미미하다.

 

따라서, 사용하는 방법에 정답은 없지만

각 애플리케이션을 관리하는데 있어서 어떤 것이 관리 비용과 자원을 끌어다 쓸지 고민해볼 필요가 있다.

 

나는 왠만하면 도커 사용을 추천한다.

 

 

 

퍼블릭 인스턴스 네트워크 설정

프라이빗 인스턴스 네트워크 설정

 

Tip.꿀팁!

인스턴스를 생성할 때 맨 아래를 보면 고급 세부 정보 설정이 있다.

 

그 중에서도 맨 아래 사용자 데이터라는 항목이 있는데,

이것은 Bootstrap script이라는 것으로

인스턴스를 처음 실행할 때 실행시킬 수 있는 스크립트이다.

 

우리가 해야 할 일은 인스턴스를 생성하고나면 각 인스턴스에 접속하여 도커를 설치하는 작업을 거쳐야 하는데,

만약 이 사용자 데이터 항목에 스크립트(특정 명령어들)를 입력하여,

인스턴스가 처음 생성할 때 같이 필요 요소들을 설치하게끔 지정 할 수 있다. 

아래 코드는 Amazon Linux 2023 OS 기준,

사용자 데이터에 넣으면 도커 설치와 도커 명령어를 sudo 없이 바로 설치 되게끔 한다.

#!/bin/bash
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
usermod -aG docker ec2-user

* 이곳에 들어갈 수 있는 것은 쉘 스크립트 또는 명령어만 가능하다. 

 

 

아래 명령어는 우리가 직접 인스턴스에 접속하지 않아도 명령어가 자동으로 실행되지만,

직접 명령어를 쳤을 때와 똑같이 작동하기 때문에 실제로 설치시간이 어느정도 걸린다. (1분 내외)


 

이제 도커를 설치한 인스턴스까지 생성했으니

한번 도커허브에서 이미지를 가져와보자.

 

이미지는 내가 실습을 위해 생성한 임의의 이미지를 통해 실습을 진행하겠다.

인스턴스에 애플리케이션 컨테이너 띄우기

생성할 애플리케이션(컨테이너) 목록 및 이미지 이름

  • 퍼블릭 이미지 - lyleseungju/blog_dockerhub:frontend
  • 프라이빗 이미지 - lyleseungju/blog_dockerhub:backend
  • nginx 이미지 - 직접 생성하여 사용(blog_nginx:latest)

퍼블릭 인스턴스

1. 프론트 웹 컨테이너 실행

docker run -d -p 3000:3000 lyleseungju/blog_dockerhub:frontend

미리 도커 이미지를 pull 해와도 되지만,

run 명령어를 사용할 때 해당 이미지가 도커 허브에 존재한다면 바로 가져와서 실행되게끔도 가능하다.

 

2. nginx 이미지 생성 및 컨테이너 실행

- 컨테이너로 띄운 프론트 웹에서 백엔드 서버로 요청을 정상적으로 동작시키기 위해 중간에 nginx를 추가하였다.

 

nginx.conf 파일을 그대로 복사하기 전에 파일 내부에 꼭 <프라이빗 IP> 항목에서

프라이빗 인스턴스의 프라이빗 IP 값으로 바꿔 넣어주자

# nginx.conf

user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    server {
        listen 80;  # Nginx가 80번 포트에서 요청을 수신
        server_name localhost;  # 로컬 요청을 처리

        location / {
            # 프록시 서버로 요청 전달 (프라이빗 서버의 IP 및 포트)
            proxy_pass http://<프라이빗 인스턴스의 프라이빗IP>:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

        }
    }
}

 

# Dockerfile

FROM nginx:alpine

COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

 

퍼블릭 인스턴스에서 아래와 같은 파일을 생성하였다면 이미지 빌드를 하고 컨테이너를 실행시켜주자

# nginx 도커 이미지 생성을 위한 파일 구조
/현재 폴더
├── Dockerfile
└── nginx.conf
# nginx 도커 이미지 생성
docker build -t blog_nginx:latest .
# nginx 컨테이너 실행
docker run -d -p 80:80 blog_nginx:latest

 

성공적으로 실행시켰다면 아래와 같은 화면이 나타날 것이다.

 

프라이빗 인스턴스

프라이빗 인스턴스에 접속하려면 기본적으로 퍼블릭 인스턴스에서 키페어와 프라이빗 IP를 통해 ssh 접속을 할 수 있다.

  1. 퍼블릭 인스턴스에 접속하기
  2. 퍼블릭 인스턴스에 .pem(접속키) 복사하기
    2-1. 맥북에서 키가 있는 경로에 cat <키페어명>.pem하여 값 출력
    2-2. '%' 기호를 제외한 모든 문구를 복사
    2-3. 퍼블릭 인스턴스에서 sudo vi <키페어명>.pem
    2-4. 붙여넣기
    2-5. esc 한번 누르고 :wq 엔터
  3. 프라이빗 인스턴스의 프라이빗 IP 복사하기

    4. 퍼블릭 인스턴스에서 프라이빗 인스턴스 접속

sudo ssh -i <키페어명>.pem ec2_user@<프라이빗 IP>

퍼블릭 인스턴스에서 프라이빗 인스턴스에 접속한 모습

    5. 백엔드 애플리케이션 실행하기

docker run -d -p 3000:3000 lyleseungju/blog_dockerhub:backend

 

   6. 프라이빗 인스턴스에서 백엔드 애플리케이션에 요청 날려보기(방금 명령어 친곳에 그대로하면 된다)

curl localhost:3000

 


자, 기본적인 인프라를 구성하고 정상적으로 돌아갈 수 있도록 프론트, 백엔드, 프록시 애플리케이션까지 띄웠다.

이제 각 애플리케이션이 정상적으로 동작하는지 확인하고 각 애플리케이션이 서로 정상적으로 동작하는 지 테스트 해보자

테스트해보기

  • 프론트엔드 테스트
  • 백엔드엔드 테스트
  • 프록시 동작 테스트

프론트엔드 테스트하기

  • 프론트 인스턴스 안에서 요청을 날렸을때 정상적으로 동작하는지 확인
# 퍼블릭 인스턴스 안에서 동작
curl localhost:3000

이 사진처럼 뜬다면 정상이다.

  - 정상적으로 접속이 되지 않는다면 컨테이너에 3000번 포트가 열려있는지 확인해보자

 

 

  • 외부(크롬)에서 퍼블릭 IP 주소로 웹 사이트에 접속해보기
http://<퍼블릭 인스턴스의 퍼블릭 IP>:3000

   - 로딩이 오래걸리거나 접속이 되지 않는다면 해당 인스턴스의 보안그룹에 3000번 포트가 열려있는지 확인해보자

 


백엔드 테스트하기

  • 백엔드 인스턴스 안에서 요청을 날렸을 때 정상적으로 동작하는지 확인
# 프라이빗 인스턴스 안에서 동작
curl localhost:3000

 - 동작하지 않는다면 3000번 포트를 컨테이너에서 열었는지 확인해보자

 


프록시 테스트하기

프록시(NGINX) 애플리케이션도 같은 퍼블릭 인스턴스에서 동작하므로 퍼블릭 인스턴스에서 진행

  • 퍼블릭 인스턴스에서 요청을 날렸을 때 정상적으로 동작하는지 확인
curl localhost:80

 - 동작하지 않는다면 컨테이너의 80번 포트 열려있는지 확인하기

 - 동작하지 않는다면 프라이빗 인스턴스의 3000번 포트 열려있는지 확인하기

 - 다른 문구가 보인다면 nginx 이미지를 빌드할 때 nginx.conf에 프라이빗 아이피를 정상적으로 바꾸었는지 확인하기

 

 

 

  • 외부(맥북 터미널)에서 요청 테스트해보기
curl <pulbic ip>:80

 - 동작하지 않는다면 퍼블릭 인스턴스의 보안그룹에서 80번 포트가 열려있는지 확인


 

자, 이제 각 애플리케이션 테스트도 끝마쳤으니

정상적으로 모두 동작하는지 확인해보기 전에!!

 

잠깐 우리가 구성한 클라우드 인프라 동작에 대해 설명하겠다.

클라우드 인프라 동작 순서

 

 

보통 퍼블릭 인스턴스에서 웹을 띄우고 프라이빗 인스턴스에 있는 백엔드 서버로 요청을 보내면,

"퍼블릭 인스턴스 > 프라이빗 인스턴스 로 요청을 보내는 것이지 않을까?" 라는 생각이 들 것이다.

(나도 그랬다.)

 

근데 실제 동작을 보면

react 웹 서버는 클라이언트로 웹페이지를 서빙하는 역할만 하고,

실제 요청은 외부(크롬)에서 날리는 것이기에 프록시를 통해 백엔드 서버로 요청을 날리게끔 구성했다.

 

 

만약 프록시를 따로 두지 않는다면 웹에서는 백엔드 서버에 바로 요청을 보내야하는데,

 

백엔드 서버는 외부에 노출되지 않는 프라이빗 서브넷에 있기 때문에 막히게 된다.

 

결론: 프론트 동작은 외부에서 동작하고, 외부의 요청을 안받는 백엔드 서버는 리버스 프록시가 필요하다.

 

그래서 웹에서 백엔드 서버로 요청하는 것은 퍼블릭 서버에 있는 프록시서버에 요청을 날리면 된다.


E2E 테스트하기

우리가 직접 띄운 웹에 접속해서 요청 링크를 입력한 후 버튼을 눌렀을 때 정상적으로 동작하는지 확인해볼 것이다.

 

  • 웹에 접속해서 요청 날려보기

입력할 URL 값: http://<퍼블릭 인스턴스의 퍼블릭IP>:80

 

성공한 화면

 

여기까지 모두 따라왔다면, 축하한다.

프론트 - 백엔드로 구성된 클라우드를 직접 구성하고 애플리케이션을 띄워서

작동하는 인프라를 모두 구성해본 것이다.

실습을 끝마쳤다면 구성했던 모든 요소는 삭제해주자 (비용부과 볼때마다 마음아프다.)

 

이후 글에서는 이 인프라를 베이스로 조금씩 추가 서비스를 붙여나가며 진행할 것이지만,

NAT가 비용이 들기에 퍼블릭 서브넷을 통해서만 구성하여 진행할 생각이다.