부트 캠프의 최종 프로젝트를 완성했다.
링크는 다음을 참조하면 된다.
Readme 에 서비스 링크와 설명이 상세하게 적혀있다.

프로젝트의 기본적인 내용은 다음과 같다.
'''
Lazy Traveler는 고객의 위치, 시간, 관심 태그를 기반으로 일정을 손쉽게 만들어 드립니다.
Django Rest Framework(DRF)를 사용하여 API를 구축하고, AI 모델과 연결하여 사용자 질의에 실시간으로 응답합니다.

'''
https://github.com/ohsen12/Lazy-Traveler

 

GitHub - ohsen12/Lazy-Traveler

Contribute to ohsen12/Lazy-Traveler development by creating an account on GitHub.

github.com

 

오늘 드디어 5개월 간의 부트 캠프를 마무리하게 된다.
하지만 이게 끝이 아니다! 며칠 뒤부터는 정보처리기사를 공부하느라 바빠질 듯하다.

앞으로 또 어떤 기술들을 배우고 어떤 일을 하게 될 지 걱정도 되지만 기대되는 마음이 더 크다! 
처음 python 을 접하고 공부했을 때의 마음을 잊지 않고 한걸음 한걸음 성장할 수 있기를 ㅎㅎ 💪🏻

Amazon EC2AWS(Amazon Web Services)의 클라우드 기반 가상 서버 서비스로, 사용자가 필요에 따라 컴퓨팅 리소스를 생성하고 운영할 수 있도록 지원한다.
EC2를 활용하면 Docker, Python, Django, Nginx 등 원하는 스택을 자유롭게 구성하여 맞춤형 서버 환경을 구축할 수 있으며, AWS의 다양한 서비스(RDS, Route 53, S3 등)와의 연동이 용이하다.


✅ 프로젝트에서 EC2를 선택한 이유

1️⃣ 유연한 서버 환경 구축

  • EC2에서는 원하는 OS(예: Ubuntu, Amazon Linux, Windows 등)를 선택하여 맞춤형 배포 환경을 구성할 수 있음.
  • Docker를 활용하여 컨테이너 기반의 배포 및 서비스 관리를 용이하게 할 수 있음.
  • Python, Django, Gunicorn, Nginx 등을 직접 설정하여 백엔드 API 서버를 최적화할 수 있음.
  • AWS 프리 티어(Free Tier)를 활용하면 일정 기간 동안 무료로 사용할 수 있어 초기 비용 부담이 적음.

2️⃣ 보안 및 트래픽 관리 용이

  • AWS Load Balancer(ELB)를 활용하여 다수의 서버 간 트래픽을 분산할 수 있음.
  • AWS Certificate Manager(ACM)를 통해 SSL 인증서를 무료로 적용하여 HTTPS 보안을 강화할 수 있음.
  • 보안 그룹(Security Group) 및 IAM 역할(Role)을 활용하여 접근 제어와 보안 정책을 세밀하게 설정 가능.
  • VPC(Virtual Private Cloud)를 사용하면 네트워크를 분리하여 보다 안전한 환경을 구성할 수 있음.

3️⃣ 데이터베이스 및 네트워크 연동 강화

  • Amazon RDS(Relational Database Service)를 활용하면 EC2와 분리된 데이터베이스 관리가 가능하여, 자동 백업 및 장애 복구를 지원받을 수 있음.
  • Amazon Route 53을 사용하면 도메인 관리 및 트래픽 라우팅을 최적화할 수 있음.
  • EC2와 S3(스토리지 서비스) 연동을 통해 파일 업로드 및 정적 자원 관리를 효과적으로 수행 가능.

4️⃣ 확장성과 유지보수 편의성

  • EC2의 오토스케일링(Auto Scaling) 기능을 활용하면 트래픽 증가 시 자동으로 인스턴스를 추가하여 부하를 분산할 수 있음.
  • 기존 온프레미스(자체 서버)와 비교했을 때, 초기 구축 비용이 절감되며, 필요한 만큼만 인스턴스를 운영할 수 있어 유지보수 비용도 절감 가능.

✅ Amazon EC2 vs 온프레미스 서버 비교

  Amazon EC2 (클라우드) 온프레미스 (자체 서버 구축)
초기 비용 초기 비용 없음 (사용한 만큼 과금) 서버 구매 비용 발생
확장성 Auto Scaling으로 손쉬운 확장 하드웨어 추가 필요
유지보수 AWS에서 하드웨어 관리 직접 서버 유지보수 필요
보안 AWS의 보안 기능 활용 가능 별도 보안 솔루션 필요
백업 및 복구 자동 백업 및 복구 가능 수동 설정 필요

Amazon EC2는 유연한 서버 환경, 보안, 확장성, 데이터베이스 연동 등 다양한 이점을 제공하여, Django 기반 API 서버를 배포하고 운영하는 데 최적화된 솔루션이다.
또한 온프레미스 서버 대비 초기 비용이 절감되며, 트래픽 증가 시 자동 확장할 수 있어 프로덕션 환경에서도 안정적으로 운영 가능하다.

Nginx리버스 프록시 서버이자 웹 서버로서, 부하 분산, SSL 인증서 관리, 그리고 HTTP/HTTPS 전환 등의 기능을 수행하며, 웹 애플리케이션의 성능과 보안을 최적화한다.



Django API와 프론트엔드 통합 최적화

  • Django API는 Gunicorn 에서 실행되며, Nginx는 리버스 프록시 역할을 수행하여 클라이언트와 Django API 간의 통신을 중계한다.

보안 및 성능 최적화

  • SSL/TLS 설정을 통해 HTTPS 보안 연결을 간단히 구현할 수 있다.

  • 캐싱 기능을 통해 요청 처리 시간을 단축시켜 성능을 더욱 최적화할 수 있다.

부하 분산 및 확장성

  • 로드 밸런싱 기능을 통해 여러 서버에 트래픽을 분산시켜 서버의 부하를 조절할 수 있으며, 대규모 서비스에서도 안정적인 운영이 가능하다.

  • 리버스 프록시와 부하 분산을 활용하여 애플리케이션 확장성을 확보할 수 있다.

  • Apache(다른 웹 서버)는 동기식 처리로 인해 대규모 트래픽 처리에서 성능이 떨어지지만, Nginx는 비동기 이벤트 기반으로 동작하여 적은 리소스로 더 많은 트래픽을 처리할 수 있다.

✅ 리버스 프록시(reverse proxy)는 사용자의 요청을 대신 받아서 서버로 전달하고, 서버의 응답을 다시 사용자에게 전달하는 중간 서버

👉 사용자 → 리버스 프록시 → 서버
👉 서버 → 리버스 프록시 → 사용자

즉, 사용자가 직접 서버에 접속하는 게 아니라, 리버스 프록시가 대신 서버와 통신하는 것!


리버스 프록시를 사용하는 이유

보안 강화

  • 서버의 실제 IP 주소를 숨길 수 있어서 DDoS 공격 같은 걸 막는 데 도움 됨.
  • SSL 인증서 관리도 리버스 프록시에서 처리 가능함.

로드 밸런싱

  • 여러 서버가 있을 때, 요청을 골고루 나눠줘서 서버가 과부하되지 않도록 도와줌.

캐싱(속도 개선)

  • 자주 요청되는 데이터를 미리 저장해 두고 빠르게 응답할 수 있음.

압축 및 최적화

  • 트래픽을 줄이기 위해 이미지나 파일을 압축해서 사용자에게 더 빠르게 전달할 수 있음.

🔹 예제 (Nginx 리버스 프록시 설정)

예를 들어, Nginx를 리버스 프록시로 설정하면, 사용자가 example.com에 접속했을 때 내부 서버(127.0.0.1:8000)로 요청을 보낼 수 있음.

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

 

이렇게 하면 example.com으로 들어오는 요청을 127.0.0.1:8000(예: Django 서버)으로 넘겨줄 수 있다.

  • 프록시 서버: 사용자가 직접 서버에 요청하는 대신 중간에서 요청을 대신 보내줌.
  • 리버스 프록시: 서버를 보호하고 성능을 최적화하기 위해 동작하는 프록시 서버.
  • 대표적인 리버스 프록시: Nginx, Apache, HAProxy, Cloudflare 등.
 

LangGraph는 AI 프로젝트 개발을 더 간편하게 해주는 자연어 처리 라이브러리로, 다양한 외부 데이터 소스와 연결하여 모델의 기능을 확장할 수 있다.
특히, 복잡한 대화 흐름을 그래프 기반으로 구조화하여 더욱 유연하게 제어할 수 있다.



✅ 선택 이유

구조화된 대화 흐름

  • 그래프 구조를 활용하여 복잡한 대화 로직을 체계적으로 관리 가능.
  • 선형적인 체인 방식이 아닌, 유연한 분기 처리가 가능해 다양한 시나리오 대응이 용이함.

모듈화된 개발 방식

  • 기능별로 독립적인 노드 설계를 적용하여 유지보수와 테스트가 용이함.
  • 필요한 단계만 실행하는 조건부 흐름 제어가 가능하여 응답 속도가 향상됨.

확장성과 유지보수성 향상

  • 새로운 기능 추가 시 기존 구조를 변경하지 않고 노드만 추가/수정하면 됨.

기존에 사용하던 LangChain과의 비교

  • 기능이 풍부하지만 선형적인 체인 구조로 인해 복잡한 흐름 제어에 한계가 있음.

  • 상태 관리가 직관적이지 않아 세션별 맞춤형 응답을 유지하기 어려움.

  • 체인이 길어질수록 모듈 간 의존성이 증가하여 유지보수가 어려워짐.

 

우리 프로젝트는 기존 LangChain 이 굉장히 구조적으로 구성되어 있었다.

사용자의 질의에 따라 fuction/place/schedule 로 나눠지는 구조였다.

 

⬇️

 

체인이 복잡하게 얽혀있지 않고, 각각의 구조가 잡혀있어서 LangGraph로 변경하기에 적절한 구조라고 생각했고,
LangGraph를 적용했을 때 더 구조화되고 성능의 효율을 높이리라는 기대가 있었다.
기존 LangChain에서는 체인을 따라 순차적으로 실행되지만, LangGraph를 사용하면 여러 노드를 병렬적으로 실행할 수 있다.

 

LangGraph를 적용했을 때의 차이점

  1. 순차 실행(LangChain의 기본 체인 방식)
    • 하나의 작업이 끝나야 다음 작업이 실행됨.
    • 병렬 처리가 안 되므로 속도가 느릴 수 있음.
  2. 병렬 실행(LangGraph)
    • 여러 노드를 동시에 실행할 수 있음.
    • 예를 들어, 문서를 분석하는 과정에서 요약, 키워드 추출, 감성 분석 등의 작업을 동시에 수행할 수 있음.
    • 성능이 향상되고 처리 속도가 빨라짐.

'TIL(Today I Learned)' 카테고리의 다른 글

TIL 161일 차 (Amazon EC2 (Elastic Compute Cloud))  (0) 2025.03.30
TIL 160일 차 (Nginx)  (0) 2025.03.29
TIL 158일 차 (CI/CD)  (0) 2025.03.27
TIL 157일 차 (웹소켓)  (0) 2025.03.26
TIL 156일 차 (Docker: image)  (0) 2025.03.25

CI/CD(Continuous Integration & Continuous Deployment)는 코드 변경 사항을 자동으로 빌드, 테스트, 배포하는 소프트웨어 개발 프로세스다.

 

프론트엔드 배포용 도구인 Vercel에서 CI/CD를 지원한다는 의미는?
➡️ 코드를 GitHub에 push하면 자동으로 배포되는 기능을 제공한다는 것이다.


 CI (Continuous Integration, 지속적 통합) : 코드를 자주 병합하고 자동으로 테스트하는 과정

 

🛠 CI 과정

  1. 개발자가 GitHub에 코드(push)
  2. Vercel이 자동으로 빌드 & 테스트 수행
  3. 빌드가 성공하면 프로젝트가 자동 배포 준비 완료!

 CI를 사용하는 이유

  • 코드 변경 사항을 실시간으로 테스트 & 검증
  • 팀원 간 충돌 방지 (코드 병합이 쉬워짐)
  • 버그를 초기에 발견 가능

 CD (Continuous Deployment, 지속적 배포) : CI 과정이 끝난 후, 검증된 코드를 자동으로 배포하는 과정

 

🛠 CD 과정

  1. CI 단계가 끝나고 빌드가 성공하면?
  2. Vercel이 자동으로 배포(Deploy) 진행
  3. 새로운 코드가 즉시 웹사이트에 반영됨!

 CD를 사용하는 이유

  • 수동 배포가 필요 없음 (push만 하면 자동 배포!)
  • 배포 속도 증가 (실시간 업데이트 가능)
  • 사용자에게 빠르게 기능 제공 가능

CI/CD를 적용한 Vercel 배포 흐름

1. 개발자가 GitHub에 push  
   ⬇  
2. Vercel이 자동으로 빌드 & 테스트 (CI)  
   ⬇  
3. 빌드 성공 시 자동으로 배포 (CD)  
   ⬇  
4. 새로운 웹사이트가 즉시 반영 🚀

 

📌 즉, GitHub에 코드만 올리면 자동으로 배포된다! 새로 백엔드 서버를 올릴 필요가 없다.

 

만약 CI/CD가 없다면? (수동 배포의 문제점)

  • 개발자가 직접 빌드 → 테스트 → 배포해야 함
  • 버그가 많아질 가능성 증가
  • 업데이트 속도가 느려짐

👉 CI/CD를 적용하면?

  • 자동화되어 개발 생산성이 향상됨빠르고 안정적인 배포 가능

1. 웹소켓(WebSocket) 자세히 알아보기

✅ 기존 HTTP 방식 vs. 웹소켓 방식

 

기존 HTTP 요청-응답 방식:

  • 클라이언트(브라우저)가 요청을 보내야 서버가 응답을 보냄.
  • 서버가 먼저 클라이언트에게 말 걸 수 없음.
  • 실시간으로 데이터를 받아야 하면, 주기적으로 요청을 보내야 함(Polling) → 비효율적!

웹소켓 방식:

  • 클라이언트와 서버가 한 번 연결되면 유지됨.
  • 서버도 원할 때 클라이언트에게 데이터를 보낼 수 있음.
  • 클라이언트도 서버에 항상 요청을 보내지 않아도 됨.

✅ 웹소켓이 필요한 이유

 

웹소켓이 유용한 대표적인 경우들:

  • 실시간 채팅 메시지를 바로바로 주고받아야 함.
  • 알림 시스템 → 친구 요청, 댓글 알림 등 즉시 전달.
  • 주식, 환율 차트 → 가격 변동을 실시간으로 보여줌.
  • 온라인 게임플레이어들의 상태가 실시간으로 동기화돼야 함.

📌 즉, "서버가 클라이언트에게 즉시 데이터를 보내야 하는 경우" 웹소켓이 필요함!


2. 웹소켓에서 Redis가 필요한 이유

✅ 웹소켓 연결 방식

 

웹소켓은 연결될 때 각 서버의 메모리에 연결 정보를 저장해.

예를 들어, 서버가 하나라면:

  1. 사용자가 웹소켓에 연결됨 (ws://server.com)
  2. 해당 서버가 사용자의 웹소켓 연결을 메모리에 저장.
  3. 다른 사용자가 메시지를 보내면, 서버가 바로 해당 연결을 찾아 메시지를 전달.

➡️ 문제 없음.

 

✅ 서버가 여러 개일 때 문제 발생!

만약 웹소켓 서버가 여러 개면?

  • A 사용자가 서버 1에 연결됨.
  • B 사용자가 서버 2에 연결됨.
  • A가 B에게 메시지를 보내면?
    • 서버 1은 B가 어디 있는지 모름!

이렇게 서버가 여러 개면, 웹소켓 연결 정보가 분산되어 서로 알 수가 없게 됨.

➡️ 해결책: Redis를 사용해 서버 간 소통을 하자!

 

✅ Redis가 어떻게 해결해 줄까?

Redis는 "Pub/Sub(발행-구독)" 기능을 제공한다.

💡 Pub/Sub(발행-구독) 개념

  • 각 웹소켓 서버는 Redis의 특정 채널을 구독(Subscribe)
  • 어떤 서버에서든 메시지를 Redis 채널에 발행(Publish)
  • 모든 서버가 이 메시지를 받아서 해당 클라이언트에 전달

📌 결과:

  • 서버가 여러 개여도 문제 없이 메시지가 전달됨!
  • Redis가 웹소켓 서버들 간의 브로커 역할을 해줌.

✅ 실제 동작 방식 예제

  1. A 사용자가 서버 1에 웹소켓 연결
  2. B 사용자가 서버 2에 웹소켓 연결
  3. A가 B에게 메시지를 보냄 → 서버 1에서 처리
  4. 서버 1이 Redis 채널에 "B에게 메시지"를 Publish
  5. 서버 2가 Redis 채널을 구독하고 있다가 메시지 수신
  6. 서버 2가 B에게 웹소켓으로 메시지 전달

➡️ Redis 덕분에 서로 다른 서버에 연결된 사용자끼리도 문제없이 소통 가능!


3. 웹소켓과 동기/비동기의 관계

✅ 동기(Synchronous) vs. 비동기(Asynchronous)

  • 동기 방식: 요청을 보내고 응답이 올 때까지 기다림.
    • 예) console.log(1); alert("Hello"); console.log(2); → alert가 끝나야 console.log(2); 실행됨.
  • 비동기 방식: 요청을 보내고 기다리지 않고 다른 작업 수행, 나중에 응답 처리.
    • 예) setTimeout(() => console.log("Hello"), 1000); console.log("World");
      • 먼저 "World" 출력되고, 1초 후 "Hello" 출력됨.

✅ 웹소켓이 비동기적으로 동작하는 이유

 

웹소켓이 실시간으로 데이터를 주고받으려면, 요청을 보낸다고 멈춰 있으면 안 됨!

  • 서버는 항상 클라이언트에게 새로운 메시지가 올지 모르는 상태
  • 만약 동기 방식이면 → 클라이언트가 응답을 받을 때까지 기다려야 해서 비효율적
  • 비동기 방식이면 → 클라이언트가 요청을 보내지 않아도 서버에서 바로 메시지 전송 가능

📌 즉, 웹소켓은 기본적으로 비동기 이벤트 기반(Event-driven)으로 동작해야 실시간 처리가 가능함! (클라이언트와 서버가 메시지를 주고받을 때, 기다리지 않고 이벤트가 발생하면 처리함.)

const socket = new WebSocket("ws://localhost:8080");

// 웹소켓 연결이 열리면 실행되는 이벤트
socket.onopen = () => {
    console.log("웹소켓 연결 성공!");
    socket.send("안녕, 서버!");
};

// 서버에서 메시지를 받으면 실행되는 이벤트
socket.onmessage = (event) => {
    console.log("서버에서 받은 메시지:", event.data);
};

// 웹소켓이 닫히면 실행되는 이벤트
socket.onclose = () => {
    console.log("웹소켓 연결 종료");
};

 

  • onopen: 연결이 완료되면 실행
  • onmessage: 메시지를 받으면 실행
  • onclose: 연결이 끊어지면 실행

즉, 웹소켓은 클라이언트가 요청을 보낸 후 응답을 기다리는 것이 아니라, 서버에서 메시지가 오면 자동으로 실행됨(비동기 이벤트 기반).

📌 즉, 웹소켓은 비동기 방식으로 동작하기 때문에 실시간 데이터 전송이 가능함! 


 

1️⃣ 웹소켓은 서버와 클라이언트가 실시간으로 양방향 통신하는 프로토콜.

  • HTTP보다 빠르고, 서버에서 클라이언트에게 직접 메시지를 보낼 수 있음.
  • 실시간 채팅, 알림, 주식 차트, 온라인 게임 등에 활용됨.

2️⃣ Redis는 여러 웹소켓 서버가 메시지를 공유하도록 도와줌.

  • 서버가 여러 개일 때, 각 서버가 모든 클라이언트의 연결을 알지 못함.
  • Redis의 Pub/Sub 기능을 이용하면, 서버 간 메시지 공유 가능!

3️⃣ 웹소켓은 비동기적으로 동작해야 실시간 처리가 가능함.

  • 동기 방식이면 서버가 요청을 기다리느라 멈춰야 해서 비효율적.
  • 비동기 방식이면 서버와 클라이언트가 서로 독립적으로 동작 가능.

📌 결론: 웹소켓 + Redis + 비동기 처리를 조합하면, 고성능 실시간 애플리케이션을 만들 수 있다

"이미지"는 도커에서 컨테이너를 실행하기 위한 템플릿을 의미한다.
즉, 도커에서 "이미지"를 사용한다는 건 애플리케이션을 실행할 수 있는 환경을 미리 준비해 놓은 파일을 사용한다는 것이다.


📌 도커 이미지란?

  • 도커 이미지애플리케이션, 라이브러리, 의존성 등을 포함한 실행 환경의 템플릿이다.
  • 이미지는 읽기 전용으로, 여러 개의 컨테이너가 동일한 이미지를 기반으로 실행될 수 있다.

예를 들어:

  • Python 이미지: Python을 실행할 수 있는 모든 환경이 설정된 이미지. 이 이미지를 기반으로 Django, Flask 같은 Python 애플리케이션을 실행할 수 있음.
  • Redis 이미지: Redis 서버가 실행될 수 있는 환경을 설정한 이미지. 이 이미지를 기반으로 Redis 서비스를 실행할 수 있음.

📌 이미지와 컨테이너의 관계

  • 이미지는 실행 환경을 설정한 템플릿.
  • 컨테이너는 이미지를 기반으로 실행된 실제 애플리케이션 인스턴스.

예시:

  1. 이미지: nginx:latest → Nginx 서버를 실행할 수 있도록 설정된 템플릿
  2. 컨테이너: nginx 이미지로 실행된 실제 서버 인스턴스. 이 서버가 동작하고 요청을 처리하는 역할을 함.

📌 이미지의 사용 예시

도커 컴포즈에서 이미지 사용 예시:

services:
  redis:
    image: redis:latest  # redis 이미지를 사용하여 Redis 컨테이너 실행
    ports:
      - "6379:6379"
  django:
    build: .  # 현재 디렉토리의 Dockerfile을 사용해 Django 이미지를 빌드
    ports:
      - "8000:8000"

 

  1. Redis 서비스는 redis:latest라는 이미지를 사용해서 컨테이너를 실행.
  2. Django 서비스는 build: .을 사용해서 현재 디렉토리에서 Dockerfile을 기반으로 이미지를 빌드하고, 그 이미지를 기반으로 컨테이너를 실행.

📌 이미지는 어떻게 생성되나?

  1. 기존 이미지 사용:
    이미 만들어져 있는 이미지를 다운로드해서 사용할 수 있음. 예를 들어, redis:latest나 python:3.10-slim 같은 이미지는 이미 도커 허브(Docker Hub)에 등록된 이미지들이야.
  2. 새 이미지 만들기:
    Dockerfile을 작성해서 자신만의 이미지를 빌드할 수 있음.
    예를 들어, Django 프로젝트를 위한 이미지는 Dockerfile을 작성해서, 해당 파일에 맞는 이미지를 만들 수 있음.
FROM python:3.10-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt

 

이렇게 작성된 Dockerfile을 기반으로 도커 이미지를 만들고, 그 이미지를 실행하면 Django 애플리케이션이 동작하는 컨테이너가 생성됨.


📌 결론

 

"이미지를 사용한다"는 건, 애플리케이션이 실행될 수 있는 환경을 미리 설정한 템플릿을 이용해 컨테이너를 실행하는 것을 의미한다.
이미지는 여러 개의 컨테이너에서 공통으로 사용할 수 있어, 애플리케이션 실행 환경을 일관되게 유지하는 데 매우 유용하다.

 

'TIL(Today I Learned)' 카테고리의 다른 글

TIL 158일 차 (CI/CD)  (0) 2025.03.27
TIL 157일 차 (웹소켓)  (0) 2025.03.26
TIL 155일 차 (Docker: YAML)  (0) 2025.03.24
TIL 154일 차 (Dockerfile 예제(2))  (0) 2025.03.23
TIL 153일 차 (Dockerfile 예제(1))  (0) 2025.03.22

야믈 ~ 이름 귀엽다 야믈 ~


도커 컴포즈(docker-compose.yml) 파일을 보면 확장자가 YAML인 걸 알 수 있다.

 

YAML은 "YAML Ain't Markup Language" 의 약자로, 데이터를 직관적이고 쉽게 표현하기 위한 포맷이다. 

YML은 그냥 파일 확장자 이름일 뿐이고, 실제로는 YAML이라는 포맷을 의미한다.

 

📌 YAML의 특징

  1. 사람이 읽기 쉬운 형식
    • 다른 데이터 포맷(예: JSON, XML)보다 훨씬 가독성이 높고 간단하다.
  2. 계층적 구조
    • 데이터가 계층적(들여쓰기)으로 표현되어 구조적인 데이터를 직관적으로 다룰 수 있음.
  3. 공백과 들여쓰기 사용
    • YAML은 공백과 들여쓰기로 데이터의 계층을 구분.
    • 들여쓰기는 스페이스로만 해야 하며, 은 사용하지 않음.

📌 기본 문법

1. 키:값 쌍 (key-value pairs)

name: John
age: 30

 

  • name과 age는 키, John과 30은 값이다.

2. 리스트 (List)

fruits:
  - Apple
  - Banana
  - Orange

 

  • fruits는 리스트로, -을 사용해 항목들을 나열한다.

3. 객체 (Object)

person:
  name: John
  age: 30
  address: "New York"

 

  • person은 객체로, 그 안에 name, age, address 키와 그 값들이 포함된다.

4. 주석 (Comments)

# 이것은 주석입니다.
name: John  # 인라인 주석

 

  • #으로 시작하는 라인은 주석이다. YAML에서 주석은 코드에 영향을 미치지 않는다.

📌 YAML 사용 예시

도커 컴포즈 (docker-compose.yml) 예시

version: '3'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
  app:
    build: .
    environment:
      - DEBUG=1
    depends_on:
      - web

 

  • services 아래에 여러 서비스(여기선 web과 app)를 정의할 수 있다.
  • 각 서비스는 어떤 이미지나 설정을 사용할지 지정한다.

📌 YAML을 사용하는 이유

  • 간결하고 가독성 높음: 사람과 컴퓨터 모두 읽고 쓰기 쉽다.
  • 설정 파일에서 자주 사용됨: docker-compose.yml, Kubernetes 설정 파일, CI/CD 설정 파일 등에서 YAML이 많이 사용된다.
  • 데이터 구조 표현에 유리: 계층적인 구조나 리스트를 다룰 때 매우 유용하다.
 

어제 올린 도커 파일에 대한 도커 컴포즈 파일이다.

도커 컴포즈는 여러 개의 컨테이너를 실행하기 위한 파일이다.

services:
  redis:
    image: redis:latest
    ports:
      - "6379:6379"
  django:
    build: .
    environment:
      - REDIS_URL=redis://redis:6379/0  # Django에서 Redis URL을 환경 변수로 설정
    depends_on:
      - redis
    ports:
      - "8000:8000"
    volumes:
      - ../.env:/app/.env
    command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]

 

이 docker-compose.yml 파일은 Django + Redis를 컨테이너에서 실행하기 위한 설정이다.


각 항목을 하나씩 분석해보자.

 

📌 services (서비스)

services:
  redis:
    ...
  django:
    ...

 

 

  • services: 도커에서 실행할 컨테이너 목록을 정의하는 부분.
  • 여기서는 Redis와 Django 두 개의 컨테이너를 실행함.

📌 Redis 서비스

redis:
  image: redis:latest
  ports:
    - "6379:6379"

 

 

 

  • image: redis:latest
    → 최신 버전의 Redis 컨테이너를 사용함.
  • ports: "6379:6379"
     컨테이너의 6379 포트를 로컬(호스트)의 6379 포트와 연결 (Redis의 기본 포트).
    → 로컬에서 redis-cli -h localhost -p 6379로 접근 가능!

📌 Django 서비스

django:
  build: .
  environment:
    - REDIS_URL=redis://redis:6379/0
  depends_on:
    - redis
  ports:
    - "8000:8000"
  volumes:
    - ../.env:/app/.env
  command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]

 

 

🔹 1. build: . (Django 컨테이너 빌드)

build: .

 

  • 현재 디렉토리(.)에 있는 Dockerfile을 기반으로 Django 컨테이너를 빌드함.

🔹 2. environment (환경 변수 설정)

environment:
  - REDIS_URL=redis://redis:6379/0

 

  • Django가 Redis를 사용할 수 있도록 환경 변수를 설정함.
  • redis://redis:6379/0
    → redis 서비스 컨테이너의 6379 포트를 통해 0번 DB에 연결.

🔹 3. depends_on (의존성 설정)

depends_on:
  - redis

 

 

  • Redis 컨테이너가 먼저 실행된 후 Django 컨테이너가 실행됨.
  • 하지만 depends_on은 단순 실행 순서만 보장하고, Redis가 준비될 때까지 기다려주진 않음.
    → 만약 Redis가 완전히 실행될 때까지 Django가 기다리게 하려면 wait-for-it 같은 도구를 사용해야 함.

🔹 4. ports (포트 연결)

ports:
  - "8000:8000"

 

 

 

  • 호스트(로컬)의 8000번 포트를 Django 컨테이너의 8000번 포트와 연결.
  • 로컬에서 http://localhost:8000으로 Django에 접근 가능!

🔹 5. volumes (파일 공유)

volumes:
  - ../.env:/app/.env

 

 

 

  • 호스트의 .env 파일을 컨테이너 내부 /app/.env로 마운트함.
  • 로컬의 .env 파일을 그대로 Django 컨테이너에서 사용 가능하게 해줌.
    → .env 파일에는 Django 환경 변수(DB 정보, SECRET_KEY 등)가 들어갈 가능성이 높음.

🔹 6. command (실행 명령)

command: ["python", "manage.py", "runserver", "0.0.0.0:8000"]

 

 

 

  • Django 컨테이너가 실행될 때 python manage.py runserver 명령어를 실행.
  • 0.0.0.0:8000
     컨테이너 외부에서 Django 서버에 접근할 수 있도록 함.
    → 만약 127.0.0.1:8000으로 설정하면, 컨테이너 내부에서만 접속 가능함.

📌 전체 동작 흐름

 

1️⃣ docker-compose up -d 실행
2️⃣ redis 컨테이너 실행 (6379 포트 오픈)
3️⃣ django 컨테이너 실행 (8000 포트 오픈)
4️⃣ Django는 REDIS_URL을 사용해 Redis에 연결
5️⃣ 로컬에서 http://localhost:8000로 Django 접속 가능 


📌 결론

  • Redis와 Django를 컨테이너로 실행하는 docker-compose.yml 설정 파일
  • Redis 컨테이너를 실행하고, Django 컨테이너에서 Redis를 사용할 수 있도록 환경 변수 설정
  • Django 컨테이너가 실행될 때 runserver 명령어로 개발 서버를 실행
  • 포트 및 환경 변수 설정이 포함되어 있어 손쉽게 로컬 개발 환경을 구축 가능!
 

 

Dockerfile은 Django 애플리케이션을 도커 컨테이너에서 실행하기 위한 설정 파일이다!

 

다음은 내 프로젝트의 도커 파일이다.

# Python 3.10 이미지를 기반으로 시작합니다.
FROM python:3.10-slim

# 시스템 종속성 설치 (예: libpq-dev는 PostgreSQL 데이터베이스를 위한 필수 패키지입니다)
RUN apt-get update && apt-get install -y libpq-dev

# 작업 디렉토리를 /app으로 설정
WORKDIR /app

# 의존성 목록을 복사하여 설치합니다.
COPY requirements.txt /app/

# 필요 패키지 설치
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 소스 코드 복사
COPY . /app/

# Django 환경 변수 설정
ENV PYTHONUNBUFFERED 1

# 데이터베이스와 같은 외부 서비스가 준비될 때까지 기다리기 위한 패키지 설치
# RUN pip install wait-for-it

# Django의 기본 포트인 8000번을 공개합니다.
EXPOSE 8000

# Django 서버 실행 명령
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

 

하나하나 보면서 감만 잡아보도록 하자.


1️⃣ 베이스 이미지 설정

FROM python:3.10-slim

 

 

  • Python 3.10을 기반으로 한 Slim 버전(필수 패키지만 포함된 가벼운 버전)의 리눅스를 사용함.
  • Python 실행 환경을 컨테이너 안에서 제공함 (로컬에 Python 설치할 필요 없음).

2️⃣ 시스템 패키지 설치

RUN apt-get update && apt-get install -y libpq-dev

 

 

  • libpq-dev: PostgreSQL과 Django가 연동되려면 필요함.
  • apt-get update: 패키지 목록 업데이트.
  • apt-get install -y: 필요한 패키지를 설치.

3️⃣ 작업 디렉토리 설정

WORKDIR /app

 

 

 

  • 컨테이너 내부에서 /app 폴더를 기본 작업 디렉토리로 설정함.
  • 이후 복사되는 파일들이 /app 경로 아래로 들어감.

4️⃣ 의존성 파일 복사 및 패키지 설치

COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt

 

 

 

  • requirements.txt를 컨테이너 내부 /app/ 디렉토리로 복사
  • Python 패키지를 설치 (Django, psycopg2 같은 패키지가 포함됨).
  • --no-cache-dir: 설치 후 불필요한 캐시 파일을 남기지 않도록 설정 (컨테이너 크기 최적화).

5️⃣ 애플리케이션 소스 코드 복사

COPY . /app/

 

 

  • 현재 디렉토리(로컬 프로젝트 폴더) 내의 모든 파일을 컨테이너의 /app/ 경로로 복사.

6️⃣ 환경 변수 설정

ENV PYTHONUNBUFFERED 1

 

 

  • Python 로그 출력을 버퍼링하지 않도록 설정 (즉, 즉시 출력되도록 함).
  • Django 로그가 실시간으로 출력됨 (버퍼링이 되면 로그가 늦게 출력될 수도 있음).

7️⃣ 외부 서비스가 준비될 때까지 기다리는 패키지 (주석 처리됨)

# RUN pip install wait-for-it

 

 

 

  • wait-for-it는 데이터베이스가 실행될 때까지 Django 서버 실행을 지연하는 도구임.
  • 주석 처리되어 있지만, 필요하면 활성화할 수 있음.

8️⃣ 컨테이너에서 Django 서버 실행을 위한 포트 개방

EXPOSE 8000

 

 

  • Django의 기본 실행 포트인 8000을 컨테이너 외부에서 접근할 수 있도록 개방.

9️⃣ Django 서버 실행 명령어

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

 

 

  • 컨테이너가 실행되면 Django 개발 서버가 실행됨
  • 0.0.0.0:8000 → 외부에서 컨테이너의 8000번 포트로 접근 가능하게 설정.

📌 요약

  • Python 3.10 환경을 기반으로 Django 프로젝트를 실행하기 위한 컨테이너 구성.
  • PostgreSQL과 연결할 수 있도록 libpq-dev 패키지 설치.
  • requirements.txt를 이용해 Django 및 필요한 패키지 설치.
  • 프로젝트 소스 코드 복사 후 Django 서버 실행.
  • 컨테이너가 실행되면 python manage.py runserver로 개발 서버 시작! 

이제 docker build로 이미지 만들고 docker run으로 실행하면 컨테이너에서 Django 앱이 동작할 것이다.

 

+ Recent posts