-
카카오클라우드 - 클라우드 개발자 교육 8주차 후기bootcamp 2025. 12. 31. 09:41
저번시간 구성한 AWS 인프라에 react, fastapi를 배포했다.
질문 1.
Q. 나는 2A의 브라우저 '화면'에서 요청했는데 왜 카테고리 조회 요청이 실제로 2B 서버에서 처리되나요?
A. 처음 popori.store를 브라우저에 입력해 요청하면 해당 패킷은 2A NGINX에서 index.html을 클라이언트에 전달하고,
패킷은 성공적으로 처리됩니다. 두번째 패킷(카테고리 조회)이 새로 생성되어 이 패킷은 동일하게 IG->NAT->ALB->SubNet으로 가는데
이때 로드벨런서가 트래픽을 성공적으로 처리할수 있는 인스턴스로 안내해줍니다. 따라서 동일하게 조회 요청을 10번 했을시 2A 서브넷에서도 응답을 요청할때가 있고, 2B에서 응답을 요청할때가 있습니다.
여기서 햇갈리는 개념은 2A는 2A끼리 통신한다면서요?라는 질문이 있었다.
앞서 설명한 개념에서 말했듯이 '화면'을 2A에서 응답받고 해당 패킷은 성공적으로 종료 되었으며, 이후 N번째 패킷들은 서로 독립적인 요청이기에 다시 처음부터 IG->NAT->ALB->SubNet의 경로로 처리됩니다.
2A는 2A끼리 라는 개념은 하나의 서브넷에서, 2A NGINX, 2A BACKEND서버끼리를 의미합니다.
따라서 2A NGINX가 패킷을 처리하면 2A BACKEND서버 해당 패킷을 처리하지, 2B BACKEND서버에서 처리하지 않습니다.
AWS 3-tier Architecture. AZ 격리 구조.






파일전송
scp -i /Users/yoonhyungjoo/Downloads/02T-powermvp.pem \
-J ubuntu@ip \
./dist.tar.gz \
ubuntu@ip:/home/ubuntu/
SSH 에이전트 키파일 등록 후 파일전송
* ssh-add /Users/yoonhyungjoo/Downloads/02T-powermvp.pem
* ssh -A ubuntu@ip
* scp
* -J ubuntu@ip \
* ./dist.tar.gz \
* ubuntu@1ip:/home/ubuntu/
* ssh -A -J ubuntu@1ip ubuntu@1ip
mysql 접속
mysql \
-h RDS DNS \
-P 3306 \
-u admin \
-p
파이썬 프로젝트 가상환경 설정
git clone https://github.com/yhj0904/testfast.git
tar -zcvf testfast.tar.gz testfast
scp testfast.tar.gz ubuntu@IP:/home/ubuntu/
tar -zxvf testfast.tar.gz
cd testfast
sudo apt update
sudo apt install -y python3-venv python3-pip
python3 -m venv venv
source venv/bin/activate
가상환경 실행
파이썬 유비콘으로 실행
Bastion에서 CURL로 api 테스트
react 프로젝트 client.js baseURL 수정후 재배포.
popori.store 테스트후 완료
pip install -r requirements.txt
nginx 문법체크
sudo nginx -t
nginx 설정파일 위치
/etc/nginx/conf.d/default.conf
환경변수
export DB_HOST="RDS DNS"
export DB_PORT=""
export DB_USER=""
export DB_PASSWORD=""
export DB_NAME="shopdb"
자동배포
서버종류
자동배포 범위
Deploy
webhook
CICD 아키텍쳐
webhook push
→ Build build
→ Test
→ Deploy.
AZ 격리니 블루-그린 배포
파이프라인?
우리가 수동배포한 플로우 확인배포순서
- 플랫폼 세팅
- 리엑트
- npm install node_modules 폴더 생성
- npm run build 빌드 후 dist폴더 생성
- ssh-add /Users/yoonhyungjoo/Downloads/02T-powermvp.pem ssh 키파일 등록
- * ssh -A -J ubuntu@ip ubuntu@ipnginx 인스턴스 ssh 터널링
- tar -zcvf dist.tar.gz dist tar.gz로 압축
- scp -J ubuntu@ip \
./dist.tar.gz \
ubuntu@ip:/home/ubuntu/ - dist 폴더 nginx 인스턴스에 전송
- tar -zxvf dist.tar.gz 압축해제
- mv dist/ /usr/share/nginx/html
- cd /etc/nginx/conf.d/ nginx 설정파일 위치.
- sudo nano default.conf nginx 설정파일 수정.
- sudo nginx -t
- sudo systemctl restart nginx nginx 재부팅
- sudo systemctl reload nginx nginx 새로고침
- 파이썬.
- git push
- ssh -A -J ubuntu@ip ubuntu@ip 파이썬 인스턴스 ssh 터널링
- sudo apt-get update
- sudo apt-get install git
- git clone [깃 주소]
- cd testfast
- sudo nano .env
- .env 생성
- python3 -m venv venv 파이썬 가상환경 설치
- source venv/bin/activate 가상환경 접속
- pip install -r requirements.txt 모듈 설치
- uvicorn app.main:app --host 0.0.0.0 --port 8000
배포 순서는 간략하게 이렇게 작성했다.
#자동배포 ./github/workflows/deploy.yml name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] workflow_dispatch: env: PYTHON_VERSION: '3.11' jobs: test: name: Test Application runs-on: ubuntu-latest services: mysql: image: mysql:8.0 env: MYSQL_ROOT_PASSWORD: testpassword MYSQL_DATABASE: testdb MYSQL_USER: testuser MYSQL_PASSWORD: testpass ports: - 3306:3306 options: >- --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache pip packages uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install pytest pytest-cov httpx - name: Run tests env: DB_HOST: localhost DB_PORT: 3306 DB_NAME: testdb DB_USER: testuser DB_PASSWORD: testpass run: | pytest tests/ -v --cov=app --cov-report=xml --cov-report=html continue-on-error: true # 테스트가 없는 경우를 고려 - name: Upload coverage reports uses: codecov/codecov-action@v3 with: file: ./coverage.xml fail_ci_if_error: falseTrublesooting
1. scp 인증 오류
4. ssh 점프로 bastion -> nginx(접속 안됌!) 이유 불명.
5. ssh agent에 키파일 등록 후 scp시도. 정상 작동.
—------명령어—-----
6. ssh-add /Users/yoonhyungjoo/Downloads/02T-powermvp.pem
7. scp -o ForwardAgent=yes \
8. -J ubuntu@18.216.66.86 \
9. ./dist.tar.gz \
10. ubuntu@10.250.11.240:/home/ubuntu/
11. ssh -A -J ubuntu@18.216.66.86 ubuntu@10.250.11.240
용어
Bastion 서버는 왜 필요한가?
Bastion 서버(Bastion Host)는 AWS 같은 클라우드 환경에서 프라이빗 서브넷에 있는 서버에 안전하게 접속하기 위해 존재하는 단 하나의 관문이다.
Bastion이 없으면?
모든 EC2에 퍼블릭 IP 부여
모든 서버에 SSH(22) 포트 오픈
IP 관리 어려움침입 지점이 서버 수만큼 증가
보안 사고 확률이 기하급수적으로 증가한다.Bastion이 있으면?
퍼블릭 IP는 Bastion 하나만
SSH 인바운드는 Bastion만 허용
내부 서버는 완전한 프라이빗 유지
접속 경로가 단일화됨CIDR란?
(Classless Inter-Domain Routing)
클래스 없는 도메인간 라우팅 기법
도메인간의 라우팅에 사용되는 인터넷 주소를 원래 IP주소 클래스 체계를 쓰는 것보다 더욱 능동적의로 할수 잇도록 할당하여 지정하는 방식
서브네팅, 슈퍼네팅 이러한 IP나누고 합치는 기법을 모두 CIDR
cidr은 네트워크 정보를 여러개로 나누어진 Sub-Network들을 모두 나타낼 수 있는 하나의 Network로 통합해서 보여주는 방법이다
NAT(Network Address Translation) Gateway란?
프라이빗 서브넷에 있는 인스턴스가 인터넷으로 나가기만 할 수 있도록 해주는 AWS 관리형 서비스
아웃바운드 전용
퍼블릭 서브넷에 위치
Elastic IP를 가짐
외부 → 내부 인바운드 접속 불가
상태 저장(Stateful)프라이빗 서브넷의 EC2는 퍼블릭 IP가 없다. 그래서 아래와 같은 작업을 직접 할 수 없다.
OS 보안 패치, 외부 API 호출, Docker 이미지 Pull, 외부 인증 서버(JWT, OAuth) 통신
이 문제를 해결하기 위해 대신 인터넷에 나가주는 대리인이 NAT Gateway다.라우팅 테이블(Route Table)이란?
라우팅 테이블은이 목적지 IP로 가는 트래픽은 어디로 보내라 라는 규칙 집합이다.

서브넷(Subnet)은 반드시 어떤 라우팅 테이블 하나를 사용해야 한다.
그래서 그림에서 RT_PUBLIC -> Public Subnet, RT_APP -> Private App Subnet, RT_DB -> Private DB Subnet처럼 Association이 표시돼 있다.
라우팅 테이블은 구조적으로 Destination → Target 매칭된다.
Main Route Table는 별도로 존재하는 이유는 VPC는 기본 RT가 필요하니까 AWS가 자동으로 Main RT를 만든다. 그리고 어떤 서브넷이든, 명시적으로 다른 RT와 연결하지 않으면 Main RT가 자동 적용된다
GPG키 란?
리눅스 GPG 키(GPG Key)는 패키지를 설치·업데이트할 때 이 소프트웨어가 진짜인지, 중간에 변조되지 않았는지를 검증하기 위한 기준이다.
GPG(GNU Privacy Guard)는 공개키 암호 기반(Public Key Cryptography)의 서명·암호화 도구다.
패키지 배포자는 개인키(Private Key)로 패키지에 서명하고, 사용자는 공개키(Public Key)로 그 서명을 검증한다.
리눅스 GPG 키는 이 패키지가 누가 만들었고, 중간에 바뀌지 않았는지를 확인하는 공개키다.
외부 리소스. ex) op.gg desktop, mysql 커스텀 버전?, ~~~ 등 외부 리소스를 레포지토리에 담고,
이 리소스를 설치할때 검증하는 키파일이다.
CLB(Classic Load Balancer), ALB(Application Load Balancer) 특징
AWS에서 CLB와 ALB는 모두 트래픽을 여러 서버로 분산시키는 로드밸런서지만, 동작 계층, 기능 범위, 가 다르다. CLB는 레거시, ALB는 현재 표준이다.
CLB(Classic Load Balancer)란?
CLB는 AWS 초창기에 등장한 구형(레거시) 로드밸런서다.
Layer 4(TCP)와 제한적인 Layer 7(HTTP)을 혼합 지원함CLB의 특징
L4 + 제한적 L7
EC2 기반 환경에 최적화
단순한 헬스체크
URL, Host 기반 라우팅 불가AWS에서 신규 생성 비권장
TCP까지 제어함
그냥 들어오는 트래픽을 서버들에게 나눠주는 역할.
ALB는 Layer 7(HTTP/HTTPS) 로드밸런서다.
HTTP 요청의 내용 자체를 이해하고, 그에 따라 트래픽을 지능적으로 분기할 수 있다.ALB의 핵심 특징
L7 전용
URL Path / Host 기반 라우팅
하나의 ALB로 여러 서비스 운영 가능
ECS / EKS / 마이크로서비스 친화적WebSocket, HTTP/2 지원
helth check 가능
요청을 이해하고, 상황에 맞게 분기하는 로드밸런서
DNS 레코드 종류는?
A(Adrees) : ip, 혹은 DNS를 명시해 DNS가 주소를 가르키게한다.
SOA(Start of Authority) :
SOA는 해당 도메인 존(Zone)의 ‘시작 선언문’이자 최고 책임자 정보다.
존 파일에는 반드시 하나의 SOA 레코드가 존재한다.SOA가 담고 있는 정보
이 도메인의 주 DNS 서버
관리자 이메일
존 버전(Serial)
캐시 갱신 정책(TTL 관련)NS(Name Server) : Domain이 작동하는 서버 단위. domain을 호스팅해주는 서버 주소.
CNAME(Canonical Name) : 도메인을 다른 도메인의 별명(alias)으로 연결하는 레코드다.
CNAME은 IP를 직접 가리키지 않는다
항상 다른 도메인 이름을 가리킴
CNAME이 있으면 다른 레코드(A, MX 등)와 공존 불가
MX(Mail Exchange) : 이 도메인의 이메일을 어디 서버가 받을지를 지정한다.
DNS 조회 흐름
1. 클라이언트가 www.example.com 요청
2. 루트 DNS → .com TLD 안내
3. .com DNS → NS 레코드로 example.com 담당 서버 안내
4. 담당 DNS 서버 → SOA 확인 (권한 있음)
5. www.example.com → CNAME 또는 A 레코드 조회
6. 최종 IP 반환
SOA/NS는 관리 구조
A/CNAME/MX/TXT는 실제 서비스 정보
Health Check란?
서버, 애플리케이션, 컨테이너, 혹은 특정 인스턴스가 정상적으로 동작 중인지 주기적으로 확인하는 메커니즘
실제 요청을 처리할 수 있는 상태인지 판단 하는 역할
——————————————————————————
본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 3기(B-log) 리뷰로 작성 되었습니다.'bootcamp' 카테고리의 다른 글
카카오클라우드 - 클라우드 개발자 교육 11주차 후기 (2) 2026.01.30 카카오클라우드 - 클라우드 개발자 교육 10주차 후기 (0) 2026.01.20 카카오클라우드 - 클라우드 개발자 교육 7주차 후기 (0) 2025.12.31 카카오클라우드 - 클라우드 개발자 교육 6주차 후기 (0) 2025.12.19 카카오클라우드 - 클라우드 개발자 교육 5주차 후기 (0) 2025.12.12