본문 바로가기
Kubernetes

[Kubernetes] 커스텀 도커이미지 빌드 후 배포하기

by 우솨 2025. 3. 3.

1. 먼저 이미지할 빌드의 기본 폴더 구성

my-builder/

├── Dockerfile
├── requirements.txt
└── my-code.py  # 실제 실행할 코드

폴더를 생성 후 위와 같이 구성을 만들어준다.

1-1. Dockerfile 의 예시

# 1. Python 공식 이미지를 사용 (최신 버전 권장)
FROM python:3.10

# 2. 작업 디렉토리 생성
WORKDIR /app

# 3. requirements.txt 파일 복사
COPY requirements.txt /app/

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

# 5. 애플리케이션 파일 복사
COPY . /app/

# 6. 컨테이너 실행 시 실행할 명령어
CMD ["python", "web-producer.py"]

1-2. requirements.txt 예시

# 필요한 라이브러리를 작성
asyncio
websockets
kafka-python

1-3. my-code.py 예시 
자신이 실행하고 싶은 코드를 작성한다.

import asyncio
import websockets
import json
import os
import logging
from kafka import KafkaProducer

# 로그 설정
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

# 환경 변수 설정 (Docker & Kubernetes에서 사용)
API_TOKEN = os.environ.get("API_TOKEN", "your_default_token")
KAFKA_BROKER = os.environ.get("KAFKA_BROKER", "localhost:9092")
symbols_str = os.environ.get("SYMBOLS", '["BINANCE:BTCUSDT", "AAPL"]')

# 문자열을 JSON 형식으로 파싱해서 리스트로 변환
symbols = json.loads(symbols_str)

# Kafka Producer 설정
producer = KafkaProducer(
    bootstrap_servers=KAFKA_BROKER,
    value_serializer=lambda v: json.dumps(v).encode("utf-8")
)

# WebSocket 연결 및 데이터 처리 함수
async def handle_websocket_data(uri, symbols):
    max_retries = 10
    retry_count = 0
    backoff_time = 1

    while retry_count < max_retries:
        try:
            async with websockets.connect(uri) as websocket:
                logging.info("WebSocket 연결 성공!")
                retry_count = 0
                backoff_time = 1

                for symbol in symbols:
                    ws_message = json.dumps({"type": "subscribe", "symbol": symbol})
                    await websocket.send(ws_message)
                    logging.info(f"Sent subscribe message: {ws_message}")

                while True:
                    message = await websocket.recv()
                    logging.info(f"Received message: 메세지 받음")

                    try:
                        data = json.loads(message)
                        producer.send("stock_data", value=data)
                        logging.info(f"Sent to Kafka: 메세지 전송 성공")
                    except json.JSONDecodeError:
                        logging.warning(f"Failed to parse message: 메세지 전송 실패")

        except websockets.exceptions.ConnectionClosed as e:
            logging.error(f"WebSocket 연결이 닫힘: {e}. {backoff_time}초 후 재연결 시도...")
        except Exception as e:
            logging.error(f"WebSocket 오류 발생: {e}. {backoff_time}초 후 재연결 시도...")

        retry_count += 1
        await asyncio.sleep(backoff_time)
        backoff_time = min(backoff_time * 2, 60)

    logging.error("최대 재연결 횟수 초과. 프로그램 종료.")

# WebSocket URI 설정
websocket_uri = f"wss://ws.finnhub.io?token={API_TOKEN}"


# 실행
if __name__ == "__main__":
    asyncio.run(handle_websocket_data(websocket_uri, symbols))


1-3-1. 실행되는 부분
if __name__ == "__main__":
    asyncio.run(handle_websocket_data(websocket_uri, symbols))
이 부분이 실행된다.

1-3-2. 환경 변수 설정
민감한 정보들은 os.environ.get() 으로 yaml에서 작성하여 넣어 줄 수 있다.

1-3-3. 로그 설정
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
print는 볼 수 없으므로 print문을 logging.info로 바꾸어 진행상황이나 에러사항 등을 확인하며 작업한다.


2. DockerHub에 이미지 빌드

2-1. 폴더로 이동 후 이미지 빌드

docker build -t web-producer:latest .


2-2. 빌드된 이미지 확인

docker images


2-3. 도커에 로그인

docker login -u <ID>
<Password>


2-4. 태그 달기

docker tag <로컬 이미지 이름>:<태그> <Docker Hub 사용자 이름>/<레포지토리 이름>:<태그>

# ex
docker tag web-producer:latest wsh120/web-producer:latest


2-5 DockerHub Push

docker push <Docker Hub 사용자 이름>/<레포지토리 이름>:<태그>

# ex
docker push wsh120/web-producer:latest

도커허브에 들어가 레포에 푸쉬된 것을 확인가능하다.


3. yaml 파일 작성 및 배포

yaml 파일 예시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-producer
  labels:
    app: web-producer
spec:
  replicas: 1  # 필요한 경우 2~3개로 확장 가능
  selector:
    matchLabels:
      app: web-producer
  template:
    metadata:
      labels:
        app: web-producer
    spec:
      containers:
        - name: web-producer
          image: wsh120/web-producer:latest  # Docker Hub 또는 Container Registry에서 이미지 가져오기
          env:
            - name: API_TOKEN
              value: ""
            - name: KAFKA_BROKER
              value: ""
            - name: SYMBOLS
              value: ""


3-1. 빌드한 이미지 넣기
도커허브에 푸쉬해둔 이미지명을 넣어준다.

spec:
  containers:
    - name: web-producer
      image: <이미지>:<버전>

3-2. 환경변수 설정
환경변수들을 입력해준다.

  env:
    - name: API_TOKEN
      value: ""
    - name: KAFKA_BROKER
      value: ""
    - name: SYMBOLS
      value: '["BINANCE:BTCUSDT", "AAPL"]'

 

3-3. yaml 배포

kubectl apply -f <name>.yaml -n <namespace>

 

kubectl get pod -n <namespace>
정상적으로 배포 된 것을 확인

에러가 발생한다면
kubectl logs <podname> -n <namespace>
명령어로 로그 확인이 가능하다.