개발이군고구마

[멱살잡고 DevOps] 5. AWS EC2 설정 본문

Cloud Deploy

[멱살잡고 DevOps] 5. AWS EC2 설정

김구황 2025. 7. 21. 21:49
728x90
[Backend Dockerfile] 
1. backend Dockerfile 작성 🎆 
[AWS Front 설정] 
2. S3 버킷 & CloudFront 정적 웹 호스팅 활성화 
[AWS EC2 설정] <- 현단계 
3. EC2 인스턴스 프로비저닝
4. EC2 환경 구성 🎆
[CI/CD] 
5. GitHub Actions CI/CD 구축 🎇
[테스트와 확장]
6.DNS 설정 및 최초 배포 테스트
7. 배포환경 분리 (dev/prod)

 

 

1. 인스턴스 시작하기 

1) AmazonSSMManagedInstanceCore 정책 첨부

ㄴSSM Agent가 AWS Systems Manager와 안전하게 소통할 수 있도록 권한을 부여

 

 

2) 보안 그룹 설정 

ㄴ타입 프로토콜 포트 범위 소스 설명

SSH TCP 22 내 공인 IP (예: 203.0.113.25/32) SSH 접속 허용 (비교적 안전)
HTTPS (CloudFront) TCP 443 pl-xxxxxxxx (CloudFront Origin PRL) CloudFront에서만 /api/* 요청 처리

 

✴CloudFront 엣지 위치 IP 범위를 나타내는 프리픽스 리스트

✴ SSH 대신 SSM Session Manager만 사용하려면 SSH 규칙을 제거해도 무방함 

 

✅ CloudFront → Origin 통신 프로토콜
  • Viewer→CloudFront: Viewer Protocol Policy 설정에 따라 HTTP 또는 HTTPS (보통 Redirect HTTP to HTTPS)
  • CloudFront→Origin(EC2): Origin Protocol Policy에 따라
    • 현재구성 : Viewer Protocol=Redirect HTTP to HTTPS, Origin Protocol=HTTPS Only 로 가정 시, 모든 요청은 포트 443(HTTPS) 으로 EC2의 Nginx에 전달

 

 

 

 

2. MongoDB EC2 IP추가와 Cloudfront behavior 경로 추가 

1) MongoDB Atlas IP 화이트리스트에 EC2 IP 추가

 

 

2) CloudFront Behavior에 /api/* 경로 추가

ㄴ  API 호출은 실시간 처리해야 하므로 캐싱을 비활성화하고, HTTPS만 허용하여 보안 유지

 

EC2와 S3의 캐싱정책 비교

 

💥 Cloudfront 동작 설정 중 origin EC2 목록에 없음 
  • CloudFront 콘솔은 관리형 오리진만 나열해 주고, EC2 같은 “커스텀 오리진” 은 직접 입력
  • Origin domain 직접 입력  또는 Elastic IP 사용
🌐 Cloudfront 원본 등록

 

Cloudfront에 원본으로 등록해주어야 함

💦 EC2 DNS 로 등록을 했으나, 서버가 죽고나서도 문제 없도록 탄력 ip를 연동해주는 것을 권장 

 

 

 

3. Docker & Docker Compose EC2 설치

ㄴ EC2 에 Docker 와 Docker Compose가 있어야 

 

대안비교 - SSH 직접 로그인 뒤 명령 실행 → 보안 그룹 SSH 허용·키 관리 부담 증가
SSM Run Command → SSH 없이 AWS 콘솔 GUI에서 바로 원격 명령 실행, AWS IAM 권한만으로 안전

 

AWS System Manager 에서 

EC2를 타켓으로 한 후 AWS-RunShellScript  로 스크립트 명령어를 작성하여 설치 

Amazon Linux 2023

sudo dnf update -y
sudo dnf install -y docker

sudo systemctl start docker
sudo systemctl enable docker

# 현재 사용자를 'docker' 그룹에 추가
# 이렇게 하면 매번 sudo를 붙이지 않아도 docker 명령을 쓸 수 있음
sudo usermod -aG docker ec2-user

# 6. 변경된 그룹 권한을 적용하기 위해 세션을 종료하고 다시 연결
# 브라우저 탭을 닫고, 7-1 단계에 따라 다시 SSM으로 접속
exit 

# 7. 최신 버전의 Docker Compose를 GitHub에서 직접 다운로드
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 8. 다운로드한 파일에 실행 권한을 부여
sudo chmod +x /usr/local/bin/docker-compose

docker --version
docker-compose --version

 

 

4. Docker Compose 및  Nginx 파일 수정 

ㄴ Docker compose는 현재 프리티어 환경에서 실무 패턴가 가깝기 때문에 채택

ㄴ github -> EC2 배포 

⛳ 대안비교 - AWS ECS/EKS
여러 개의  EC2 에 각기 다른 컨테이너를 pull할 수 있으나 현재 사이즈에선 불필요하다 판단하여 사용하지 않는다. 

 

 

1) Docker Compose 파일 작성 및 배치 (기존에 썼던 파일을 수정) 

  • backend 서비스의 ports 설정 제거
    • Node.js 백엔드 컨테이너의 5000번 포트를 EC2 서버의 5000번 포트에 직접 노출 -> 보안적으로 매우 위험
    • 모든 API 요청은 반드시 Nginx 리버스 프록시를 통해서만 백엔드로 전달되어야 함
    • backend와 nginx는 app-net이라는 내부 네트워크로 이미 연결되어 있으므로, Nginx는 외부 노출 없이도 backend:5000으로 접근할 수 있음
  • backend 서비스에 image 속성 추가
    • GitHub Actions가 코드를 빌드하여 {도커헙아이디}/{이미지 이름}:latest 라는 이미지(Image)를 만들어 Docker Hub에 올리면, EC2 서버에서는 build를 다시 하는 것이 아니라 완성된 이미지를 pull 받아서 사용
    • 역할(빌드는 CI서버, 실행은 EC2서버)을 명확히 분리하는 것이 효율적이고 일관된 배포를 보장
  • logging 드라이버 설정 추가
    • 컨테이너의 로그를 EC2 인스턴스가 아닌 CloudWatch에 중앙 집중적으로 기록 -> 여러 서버, 여러 컨테이너의 로그를 한 곳에서 보고 검색
    • EC2 생성시 만들었던 IAM 역할에 정책을 추가해주어야 함 

 

 

2) Nginx 구성 파일 마운트

  • server_tokens off; 추가
    • Nginx는 에러 페이지나 HTTP 응답 헤더에 nginx/1.25.5 와 같은 버전 정보를 노출
    • 지시어는 버전 정보를 숨겨서 불필요한 정보 노출을 막는 간단하지만 효과적인 보안 설정
  • client_max_body_size 10M; 추가
    • 악의적인 사용자가 매우 큰 용량의 요청(예: 대용량 파일 업로드)을 보내 서버의 리소스를 고갈시키는 서비스 거부(DoS) 공격을 방지

 

3) .env 파일에 gitignore에 업로드 

ㄴ 수동으로 .env 파일을 생성하고 내용을 입력

echo ".env" >> .gitignore

 

 

 

5. 배포 파일 준비 및 애플리케이션 실행

"Build, release, run" 이라는 12-Factor App 방법론의 핵심 원칙

ㄴ 코드를 빌드하고(Build), 실행 가능한 산출물(Docker 이미지)로 묶고(Release), 실제 환경에서 실행(Run)하는 단계 명확히 분리

SSH Client를 사용하지 않고 SSM 을 사용해본다. SSM은 AWS IAM 권한을 통해 안전하게 접속을 제어 할 수 있기 때문!

 

# ec2-user 계정으로 전환
sudo su - ec2-user

# ec2-user의 홈 디렉토리로 이동
cd /home/ec2-user
git clone https://github.com/<YOUR_GITHUB_USERNAME>/<YOUR_BACKEND_REPO>.git

# 생성된 프로젝트 디렉토리로 이동
cd <YOUR_BACKEND_REPO>

# env 파일 생성 후 직접 입력 (mongoDB 정보) 

# docker-compose.yml 파일에 정의된 모든 컨테이너를 백그라운드에서 실행
# -d 옵션은 'detached mode'를 의미하며, 터미널 세션이 끊겨도 컨테이너가 계속 실행
docker-compose up -d

# 확인
docker-compose ps
docker-compose logs -f node-app

컨테이너 생성 완료

 

 

현재까지 진행상황

 


💥 unknown log opt 'awslogs-stream-prefix' for awslogs log driver

 

docker compose 에 작성한 awslogs-stream-prefix 옵션은 비교적 최신 Docker 버전에 추가된 편의 기능

EC2의 Docker 버전이 이 옵션을 지원하지 않아 오류가 발생

 

🌐 현재 설치된 Docker 버전과 호환되는 옵션으로 docker-compose.yml 파일을 수정

# [수정] 'awslogs-stream-prefix'를 'awslogs-stream'으로 변경하고, 스트림 이름을 직접 지정
awslogs-stream: "node-app-stream"
awslogs-create-group: "true"