1 mkdir 4 cd 4 vi Dockerfile FROM python:3.11-slim WORKDIR /app # 파이썬은 package.json 대신 requirements.txt를 사용합니다. COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["python", "main.py"] # 필요한 패키지가 있다면 파일 안에 적어주세요. 예: flask, pandas 등 # 지금은 테스트를 위해 빈 파일을 생성합니다. touch requirements.txt echo "print('Hello, Docker! Python is running successfully.')" > main.py 이제 ls -al을 하면 파일이 3개가 되어야 합니다: Dockerfile, requirements.txt, main.py. 2 빌드 및 실행 방법 작성한 Dockerfile을 사용해 이미지를 만들고 컨테이너를 띄우는 터미널 명령어입니다. 이미지 빌드: docker build -t my-app-name . 컨테이너 실행: docker run --name my-running-app my-python-app Hello, Docker! Python is running successfully. 만약 웹 서버(Flask 등)를 띄우고 싶다면? 나중에 실제 서비스를 하실 때는 requirements.txt 안에 flask라고 적고, main.py에 서버 코드를 작성하신 뒤 -p 8080:5000 같은 포트 포워딩 옵션을 주어 실행하시면 됩니다. 지금까지 완료하신 작업 요약 Dockerfile 작성: 파이썬 3.11 환경을 구축하겠다는 설계도 작성. 재료 준비: 필요한 라이브러리 목록(requirements.txt)과 실행 파일(main.py) 준비. 이미지 빌드 (docker build): 설계도와 재료를 합쳐 어디서든 실행 가능한 my-python-app이라는 완제품(Image) 생성. 컨테이너 실행 (docker run): 이미지를 격리된 환경에서 실제로 작동시켜 결과 확인. 4 다음 단계로 해볼 만한 것들 단순 출력을 넘어 실제 프로젝트처럼 발전시키고 싶다면 다음 옵션들을 시도해 보세요. 외부 라이브러리 설치: requirements.txt에 requests나 pandas 같은 라이브러리 이름을 적고 다시 빌드해 보세요. 파일 수정 후 재빌드: main.py 내용을 수정하고 다시 빌드하면 도커가 수정된 부분(Layer)만 빠르게 업데이트하는 것을 볼 수 있습니다. 백그라운드 실행: docker run -d --name my-app my-python-app 명령어로 컨테이너를 백그라운드에서 띄워보세요. 컨테이너 정리하기 (Clean up) 테스트가 끝난 컨테이너는 삭제해 주는 것이 좋습니다. Bash # 실행 중인 컨테이너 중지 docker stop my-running-app # 컨테이너 삭제 docker rm my-running-app # 이미지 삭제 (필요 없는 경우) docker rmi my-python-app -------------------------------------- Kubernetes(EKS) 배포를 위한 진행 1 성공적으로 도커 이미지를 만드셨으니, 이제 이 이미지를 클라우드(AWS EKS) 환경에 배포할 차례입니다. EKS 배포는 크게 이미지 저장 -> 배포 정의(YAML) -> 실행의 3단계로 이루어집니다. 현재 터미널이 eks-demo 환경인 것으로 보아, 이미 EKS 클러스터는 준비되어 있다는 가정하에 다음 단계를 안내해 드립니다. 2 # 참고 단계: 이미지를 저장소(ECR)에 업로드하기 EKS(쿠버네티스)는 내 컴퓨터에 있는 이미지를 직접 가져갈 수 없습니다. AWS의 이미지 저장소인 **ECR(Elastic Container Registry)**에 이미지를 올려야 합니다. ECR 리포지토리 생성: aws ecr create-repository --repository-name my-python-app # 로그인 (Region은 본인의 설정에 맞게 변경) aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin [본인_계정_ID].dkr.ecr.ap-northeast-2.amazonaws.com # 이미지 태그 변경 (ECR 주소에 맞게) docker tag my-python-app:latest [본인_계정_ID].dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest # 이미지 업로드 docker push [본인_계정_ID].dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest 2단계: 배포용 YAML 파일 작성 쿠버네티스에게 "이 이미지를 몇 개 띄워줘"라고 명령하는 명세서(deployment.yaml)를 만듭니다. apiVersion: apps/v1 kind: Deployment metadata: name: python-app-deployment spec: replicas: 2 # 2개의 컨테이너를 띄웁니다. selector: matchLabels: app: python-app template: metadata: labels: app: python-app spec: containers: - name: python-app-container image: [본인_계정_ID].dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest ports: - containerPort: 80 3단계: EKS에 배포 실행 이제 kubectl 명령어를 통해 EKS 클러스터에 배포를 요청합니다. 배포 적용: kubectl apply -f deployment.yaml 상태 확인: # Pod이 잘 생성되었는지 확인 kubectl get pods 4단계: (선택) 외부 노출을 위한 Service 설정 만약 이 앱이 웹 서버라면 외부에서 접속할 수 있도록 주소를 만들어야 합니다. kubectl expose deployment python-app-deployment --type=LoadBalancer --name=my-python-service --port=80 이후 kubectl get svc 명령어를 통해 생성된 External-IP로 접속할 수 있습니다. 가장 먼저 하셔야 할 일은 이미지를 ECR로 업로드하는 것입니다. 혹시 AWS CLI 설정(aws configure)이 되어 있으신가요? 설정 여부를 확인하시려면 aws sts get-caller-identity를 입력해 보세요. 계정 정보가 나온다면 바로 1단계를 진행하시면 됩니다. 진행 중 막히는 부분이 생기면 말씀해 주세요! aws sts get-caller-identity ----------- 실습 1 1. ECR 로그인 및 리포지토리 생성 먼저 이미지를 올릴 공간을 만들고 도커가 접근할 수 있게 인증합니다. # 1. ECR 리포지토리 생성 aws ecr create-repository --repository-name my-python-app --region ap-northeast-2 # 2. ECR 로그인 (인증 토큰 사용) aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com 2 이미지 태그 및 푸시 (Push) 로컬에 있는 my-python-app 이미지를 AWS 주소 형식에 맞춰 업로드합니다. # 3. 이미지에 ECR 주소 태그 붙이기 docker tag my-python-app:latest 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest # 4. ECR로 이미지 업로드 docker push 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest 3 Kubernetes 배포 파일 작성 (deployment.yaml) 이제 EKS가 이 이미지를 가져가도록 설정 파일을 만듭니다. vi deployment.yaml을 입력하고 아래 내용을 복사해서 저장하세요. vi deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: python-app-deployment spec: replicas: 2 selector: matchLabels: app: python-app template: metadata: labels: app: python-app spec: containers: - name: python-app image: 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest ports: - containerPort: 80 4 EKS 배포 실행 및 확인 # 5. EKS 클러스터에 배포 적용 kubectl apply -f deployment.yaml # 6. 배포된 Pod 상태 확인 kubectl get pods (topasvga@eks-demo:N/A) [root@kops-ec2 ~]# watch -d kubectl get svc,deploy,pods ------------- 5 Every 2.0s: kubectl get svc,deploy,pods Sat Feb 14 16:26:23 2026 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/game-2048-service LoadBalancer 10.100.230.99 a6b068925521f40b986eb6163b7cd7fc-830694143.ap-northeast-2.elb.amazonaws.com 80:31717/TCP 17h service/kubernetes ClusterIP 10.100.0.1 443/TCP 18h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/game-2048 1/1 1 1 17h deployment.apps/python-app-deployment 0/2 2 0 92s NAME READY STATUS RESTARTS AGE pod/game-2048-664d7db956-h9p2b 1/1 Running 0 17h pod/python-app-deployment-75ffbb774b-8c4fr 0/1 CrashLoopBackOff 3 (48s ago) 92s pod/python-app-deployment-75ffbb774b-c5ktm 0/1 Completed 4 (44s ago) 92s 이 코드는 메시지를 출력하고 나면 더 이상 할 일이 없어서 프로세스가 바로 종료됩니다. 도커 컨테이너(및 쿠버네티스 Pod)는 내부 프로세스가 종료되면 컨테이너 자체도 종료된 것으로 간주하고 다시 살리려고 시도(Restart)하기 때문에 무한 루프에 빠지게 됩니다. 6 해결 방법 1: 프로세스가 종료되지 않게 유지 (임시 확인용) 파이썬 코드가 계속 살아있도록 while 루프를 추가하여 수정해 보겠습니다. main.py 수정: vi main.py echo "import time while True: print('Hello, Docker! Python is running successfully.') time.sleep(60)" > main.py 7 이미지 재빌드 및 푸시: # 빌드 docker build -t my-python-app . # 태그 docker tag my-python-app:latest 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest # 푸시 docker push 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest 8 Pod 재시작 (이미지 갱신): 이미지가 바뀌었으므로 배포를 재시작해 줍니다. Bash kubectl rollout restart deployment/python-app-deployment kubectl logs pod/python-app-deployment-75ffbb774b-8c4fr 9 Every 2.0s: kubectl get svc,deploy,pods Sat Feb 14 16:30:13 2026 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/game-2048-service LoadBalancer 10.100.230.99 a6b068925521f40b986eb6163b7cd7fc-830694143.ap-northeast-2.elb.amazonaws.com 80:31717/TCP 17h service/kubernetes ClusterIP 10.100.0.1 443/TCP 18h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/game-2048 1/1 1 1 17h deployment.apps/python-app-deployment 0/2 1 0 5m21s NAME READY STATUS RESTARTS AGE pod/game-2048-664d7db956-h9p2b 1/1 Running 0 17h pod/python-app-deployment-75ffbb774b-8c4fr 0/1 CrashLoopBackOff 5 (2m15s ago) 5m21s pod/python-app-deployment-75ffbb774b-c5ktm 0/1 CrashLoopBackOff 5 (2m22s ago) 5m21s pod/python-app-deployment-86b79899d8-z25r9 0/1 CrashLoopBackOff 3 (19s ago) 63s 10 requirements.txt 수정 (Flask 추가): echo "flask" > requirements.txt main.py 수정 (웹 서버 코드): cat < main.py from flask import Flask import os app = Flask(__name__) @app.route('/') def hello(): return "Hello! Python App is Running on EKS!" if __name__ == '__main__': # 포트는 80으로 설정 (deployment.yaml과 맞춤) app.run(host='0.0.0.0', port=80) EOF 2. 이미지 재빌드 및 ECR 푸시 코드가 바뀌었으니 새로운 이미지를 만들어 AWS로 보냅니다. # 빌드 docker build -t my-python-app . # 태그 (계정 번호 확인: 697016550159) docker tag my-python-app:latest 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest # 푸시 docker push 697016550159.dkr.ecr.ap-northeast-2.amazonaws.com/my-python-app:latest 3. EKS 배포 갱신 이미지를 새로 올렸으므로, EKS가 새 이미지를 내려받아 Pod를 다시 생성하도록 명령합니다. kubectl rollout restart deployment/python-app-deployment 11 결과 확인 잠시 기다린 후 다시 상태를 확인해 보세요. kubectl get pods 12 Every 2.0s: kubectl get svc,deploy,pods Sat Feb 14 16:32:56 2026 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/game-2048-service LoadBalancer 10.100.230.99 a6b068925521f40b986eb6163b7cd7fc-830694143.ap-northeast-2.elb.amazonaws.com 80:31717/TCP 17h service/kubernetes ClusterIP 10.100.0.1 443/TCP 18h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/game-2048 1/1 1 1 17h deployment.apps/python-app-deployment 2/2 2 2 8m5s NAME READY STATUS RESTARTS AGE pod/game-2048-664d7db956-h9p2b 1/1 Running 0 17h pod/python-app-deployment-774b4558f5-5rzdq 1/1 Running 0 8s pod/python-app-deployment-774b4558f5-n65hk 1/1 Running 0 6s 13 kubectl expose deployment python-app-deployment --type=LoadBalancer --name=python-app-service --port=80 실시간 로그 확인 kubectl logs -f -l app=python-app 14 보안그룹 확인 웹브라우저로 접속 확인 15 아키텍처 현재 구성된 환경은 단순히 앱을 띄운 것을 넘어, 아래와 같은 현대적인 인프라 구조를 갖추고 있습니다. Load Balancer: 외부의 접속 요청을 받아 안정적으로 분산합니다. Deployment: 2개의 Pod(컨테이너)를 유지하며, 하나가 죽어도 자동으로 다시 살려줍니다 (Self-healing). ECR: 여러분이 만든 소중한 코드가 안전하게 이미지 형태로 저장되어 있습니다. 16 다음으로 도전해 볼 만한 주제들 이제 기초적인 배포에 성공하셨으니, 다음 단계로 이런 것들을 시도해 보며 실력을 키울 수 있습니다. HPA (Horizontal Pod Autoscaler): 접속자가 많아지면 자동으로 Pod 개수를 2개에서 10개로 늘려주는 설정을 해볼 수 있습니다. CI/CD 파이프라인: 코드를 수정하고 git push만 하면 자동으로 EKS까지 배포되도록 Github Actions 등을 연결해 보세요. Ingress 설정: 지금은 서비스마다 로드밸런서가 생기지만, Ingress를 사용하면 하나의 로드밸런서로 여러 앱(2048 게임, 파이썬 앱 등)을 경로별(.../game, .../python)로 나누어 관리할 수 있습니다. 17 삭제 실습 종료 후 정리 (중요!) AWS 로드밸런서(LoadBalancer)는 시간당 비용이 발생합니다. 실습이 끝났고 더 이상 유지할 필요가 없다면 아래 명령어로 리소스를 삭제해 비용을 절감하세요. # 서비스 삭제 (로드밸런서 제거) kubectl delete svc python-app-service # 배포 삭제 (컨테이너 제거) kubectl delete deploy python-app-deployment 18 삭제 서비스 리소스만 삭제 (가장 먼저 수행) 사용자가 직접 만든 앱과 통로를 제거합니다. 특히 LoadBalancer 타입의 서비스는 AWS에서 실제 비용을 발생시키는 주범이므로 반드시 먼저 삭제해야 합니다. # 1. 외부 노출용 서비스 삭제 (로드밸런서 제거) kubectl delete svc python-app-service kubectl delete svc game-2048-service # 2. 배포된 애플리케이션 삭제 kubectl delete deploy python-app-deployment kubectl delete deploy game-2048 클러스터 자체 삭제 (실습 종료 시) 현재 eks-demo 또는 kops 환경을 사용 중이시라면, 클러스터 전체를 삭제하여 가상 서버(EC2)와 관리 도구들을 모두 날려야 합니다. # eksctl을 사용했다면 eksctl delete cluster --name <클러스터_이름> # 클러스터 삭제 설정 (실제 삭제는 --yes를 붙여야 함) kops delete cluster --name <클러스터_도메인_이름> --yes AWS 저장소 및 기타 리소스 정리 이미지 저장소(ECR)와 설정 파일들도 삭제하면 완벽합니다. ECR 리포지토리 삭제: aws ecr delete-repository --repository-name my-python-app --force S3 버킷 (kops 사용자용): kops 설정 파일이 담긴 S3 버킷도 더 이상 필요 없다면 비우고 삭제하세요. 마지막 체크리스트 (비용 폭탄 방지) 명령어를 모두 실행한 뒤, 반드시 AWS 콘솔에 접속하여 다음 항목들이 남아있는지 확인하세요. EC2 인스턴스: 실행 중인 노드가 모두 Terminated 상태인지 확인. Load Balancers: '로드밸런서' 메뉴에 남아있는 항목이 없는지 확인. Volumes: 사용하지 않는 EBS 볼륨(디스크)이 남아있는지 확인. 19 완전 정리법 1단계: 생성한 서비스 삭제 (공통) 로드밸런서는 클러스터를 삭제해도 간혹 '삭제 중' 상태로 꼬여서 남는 경우가 있으므로, 수동으로 먼저 지워주는 것이 안전합니다. # 생성한 모든 서비스와 배포 삭제 kubectl delete svc,deploy --all 2단계: 클러스터 완전 삭제 A. kOps를 사용하는 경우 (프롬프트의 root@kops-ec2 기준) kOps는 EC2, Auto Scaling Group, VPC 등을 직접 생성하므로 아래 명령어로 모든 인프라를 한꺼번에 날려야 합니다 # 1. 삭제할 리스트 확인 # 2. 실제 삭제 진행 (확인 후 실행) kops delete cluster --name ${NAME} --yes ${NAME} 변수가 설정되어 있지 않다면, 이전에 사용하셨던 클러스터 풀네임(예: mycluster.k8s.local)을 직접 적어주세요 eksctl delete cluster --name <클러스터_이름> 3단계: 이미지 저장소(ECR) 삭제 빌드해서 올렸던 이미지 저장소도 비용이 발생하므로 삭제합니다 aws ecr delete-repository --repository-name my-python-app --force --region ap-northeast-2 4단계: AWS 콘솔 최종 수동 점검 (매우 중요) 명령어가 성공했더라도 반드시 AWS 웹 콘솔에 로그인하여 다음 메뉴에서 "남아있는 것이 없는지" 눈으로 확인해야 합니다. EC2: Running 중인 인스턴스가 0개인지 확인. ELB (로드밸런서): 'Load Balancers' 메뉴에 리스트가 비어있는지 확인. (비용의 주범입니다) EBS (볼륨): 'Volumes' 메뉴에서 available 상태로 방치된 디스크가 없는지 확인. S3 (kOps 사용 시): kOps 설정 파일이 들어있는 버킷을 비우고 삭제. 모든 삭제가 완료되면 보통 15~20분 정도 후에 AWS 리소스들이 완전히 사라집니다. 내일쯤 AWS Billing(결제) 대시보드에서 'Yesterday's costs'를 확인하여 더 이상 과금되지 않는지 체크해 보세요. ------- eksctl로 생성하셨다면 클러스터 삭제 과정이 훨씬 간결하고 명확합니다. eksctl은 AWS CloudFormation 스택을 통해 생성된 모든 리소스(VPC, 서브넷, IAM 역할, 노드 그룹 등)를 자동으로 역순으로 추적하며 지워주기 때문입니다. 다음 단계에 따라 환경을 완전히 정리해 주세요. 1. EKS 클러스터 삭제 (핵심 단계) 이 명령어 하나로 클러스터와 연결된 모든 컴퓨팅 리소스를 제거합니다. # 클러스터 이름 확인 (모르실 경우: eksctl get cluster) eksctl delete cluster --name <클러스터_이름> eksctl get cluster --region ap-northeast-2 # 리전을 명시하여 삭제 실행 eksctl delete cluster --name eks-demo --region ap-northeast-2 소요 시간: 약 15~20분 정도 걸립니다. 작동 원리: eksctl이 CloudFormation에 접속하여 노드 그룹을 먼저 제거한 후, 마지막으로 컨트롤 플레인을 삭제합니다. ECR 리포지토리 삭제 이미지를 저장했던 ECR은 클러스터 삭제와 별개이므로 수동으로 지워야 비용이 청구되지 않습니다. Bash aws ecr delete-repository --repository-name my-python-app --force --region ap-northeast-2 3. 최종 확인 (AWS 콘솔) 명령어가 완료된 후, 아래 리스트를 눈으로 직접 확인하는 것이 가장 안전합니다. CloudFormation: eksctl-<클러스터이름>-cluster 형태의 스택이 DELETE_COMPLETE 상태이거나 사라졌는지 확인하세요. EC2 인스턴스: 노드 그룹에 속했던 서버들이 모두 Terminated 되었는지 확인하세요. ELB (로드밸런서): kubectl delete svc를 미리 안 하셨더라도 eksctl이 삭제를 시도하지만, 간혹 남는 경우가 있습니다. 'Load Balancers' 메뉴가 비어있는지 꼭 확인하세요. 주의사항 만약 eksctl delete cluster 도중 "Resource localhost:8080 refused" 같은 에러가 나거나 멈춘다면, 해당 터미널의 자격 증명(IAM) 문제일 수 있습니다. 그럴 때는 AWS 웹 콘솔의 CloudFormation 메뉴로 직접 들어가서 해당 클러스터 이름의 스택을 선택하고 **[Delete]**를 눌러주시면 됩니다. ---------- # 주요 리전을 하나씩 확인 (가장 흔한 케이스) eksctl get cluster --region us-west-2 eksctl get cluster --region us-east-1 # 현재 계정의 모든 EKS 클러스터 이름만 출력 aws eks list-clusters --region ap-northeast-2 aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "Reservations[*].Instances[*].[InstanceId,Tags[?Key=='Name'].Value|[0]]" --output table aws elbv2 describe-load-balancers --query "LoadBalancers[*].[LoadBalancerName,DNSName]" --output table