greatsangho의 이야기

FinPilot - Kubernetes를 이용한 AWS 고가용성 서버 본문

프로그래밍/SK AI 캠프

FinPilot - Kubernetes를 이용한 AWS 고가용성 서버

greatsangho 2025. 2. 25. 03:32

모든 서버는 AWS에 호스팅합니다. 올바른 자격 증명을 설정하려면 @greatsangho에게 문의하세요.

GPT 및 Perplexity에 문답하며 구현함

 

docker 설치

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL <https://download.docker.com/linux/debian/gpg> -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \\
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] <https://download.docker.com/linux/debian> \\
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \\
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker $USER

kubernetes 설치

curl -LO "<https://dl.k8s.io/release/$>(curl -L -s <https://dl.k8s.io/release/stable.txt>)/bin/linux/amd64/kubectl"
curl -LO "<https://dl.k8s.io/release/$>(curl -L -s <https://dl.k8s.io/release/stable.txt>)/bin/linux/amd64/kubectl.sha256"
echo "$(cat kubectl.sha256)  kubectl" | sha256sum --check
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

minikube

curl -LO <https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64>
sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64
minikube start

쿠버네티스를 처음부터 설정하고 운영하는 전체적인 과정을 정리해 줄게. 기본 개념부터 실무 적용까지 단계별로 설명할게.


🚀 쿠버네티스 운영 전체 과정 정리

1️⃣ 쿠버네티스 기본 개념

쿠버네티스(Kubernetes)는 컨테이너 오케스트레이션 툴로, 컨테이너화된 애플리케이션을 자동으로 배포, 관리, 확장하는 시스템이다.

핵심 개념

  • Pod: 컨테이너가 실행되는 최소 단위
  • Service: 네트워크를 통해 Pod에 접근할 수 있도록 제공하는 기능
  • Deployment: 애플리케이션 배포 및 스케일링 관리
  • Ingress: 외부에서 도메인을 통해 클러스터 내부 서비스로 트래픽을 전달
  • ConfigMap & Secret: 설정값과 보안 정보를 저장
  • Persistent Volume (PV, PVC): 데이터를 저장하기 위한 스토리지

2️⃣ 쿠버네티스 클러스터 구축

(1) 쿠버네티스 설치 방법

운영 환경에 따라 다르게 설치 가능

  1. 로컬 개발 환경
    • Minikube: 개발 및 테스트용 (추천)
    • Kind (Kubernetes in Docker): 빠른 로컬 테스트
  2. 클라우드 환경
    • AWS: Amazon EKS
    • GCP: Google Kubernetes Engine (GKE)
    • Azure: Azure Kubernetes Service (AKS)
    • 자체 서버: Kubeadm

(2) Minikube 설치 예제

# Minikube 설치
curl -LO <https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64>
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 클러스터 시작
minikube start


3️⃣ 애플리케이션 배포

(1) ConfigMap과 Secret 생성

apiVersion: v1
kind: ConfigMap
metadata:
  name: fastapi-config
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"
kubectl apply -f configmap.yaml
apiVersion: v1
kind: Secret
metadata:
  name: fastapi-secret
type: Opaque
data:
  # base64 인코딩된 값 사용 (예: echo -n "mypassword" | base64)
  DB_PASSWORD: bXlwYXNzd29yZA==
kubectl apply -f secret.yaml

(2) Deployment 생성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 3  # 원하는 복제본 수로 조정
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi
        image: your-dockerhub-username/fastapi:latest  # 실제 Docker 이미지 이름으로 변경
        ports:
        - containerPort: 80  # FastAPI 애플리케이션이 사용하는 포트 (예: 80 또는 8000)
        envFrom:
          - configMapRef:
              name: fastapi-config
          - secretRef:
				      name: fastapi-secret
kubectl apply -f k8s-deployment.yaml
kubectl get pods

(3) Service 생성

apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  selector:
    app: fastapi
  ports:
    - protocol: TCP
      port: 80         # 클러스터 내에서 노출할 포트
      targetPort: 8000   # 컨테이너의 포트 (애플리케이션 포트와 일치)
  type: LoadBalancer  # 클라우드 환경의 경우 LoadBalancer, 로컬 테스트시 NodePort 등 선택 가능
kubectl apply -f finpilot-service.yaml
kubectl get svc

배포 상태 확인

kubectl get deployments
kubectl get pods
kubectl get services

삭제 / 로그 확인

kubectl delete deployment failure1
kubectl logs failure1-697598db4-qss75

4️⃣ Ingress 설정 (도메인 연결)

Helm 설치

curl <https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3> | bash
helm version

(1) NGINX Ingress Controller 설치

helm repo add ingress-nginx <https://kubernetes.github.io/ingress-nginx>
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace

기본적으로 cloud환경에서 loadbalancer 설정


5️⃣ HTTPS 설정 (Let's Encrypt)

(1) Cert-Manager 설치

helm repo add jetstack <https://charts.jetstack.io>
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
kubectl apply -f <https://github.com/cert-manager/cert-manager/releases/download/v1.16.3/cert-manager.yaml>

(2) Let's Encrypt 인증서 요청

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: <https://acme-v02.api.letsencrypt.org/directory>
    email: myemail@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

kubectl apply -f cluster-issuer.yaml

(3) TLS 적용된 Ingress 설정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - myapp.example.com
    secretName: my-app-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80

kubectl apply -f finpilot-ingress.yaml
kubectl get ingress
kubectl describe clusterissuer letsencrypt-http

기존 인증서 관련 리소스 삭제 후 재시도

kubectl delete certificate finpilot-tls
kubectl delete secret finpilot-tls
kubectl delete challenge -A
kubectl delete order -A

kubectl apply -f finpilot-ingress.yaml

6️⃣ 애플리케이션 모니터링 및 로깅

(1) Prometheus & Grafana 설치

helm repo add prometheus-community <https://prometheus-community.github.io/helm-charts>
helm repo update
helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace

(2) Kibana & Elasticsearch (ELK 스택)

helm repo add elastic <https://helm.elastic.co>
helm repo update
helm install elasticsearch elastic/elasticsearch --namespace logging --create-namespace
helm install kibana elastic/kibana --namespace logging


7️⃣ CI/CD 파이프라인 구축

GitHub Actions 또는 Jenkins를 활용하여 자동 배포 구성 가능.

(1) GitHub Actions 예제

name: Deploy to Kubernetes
on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Set up Kubernetes
        uses: azure/setup-kubectl@v3

      - name: Apply Kubernetes manifests
        run: kubectl apply -f k8s/


정리

1️⃣ 쿠버네티스 설치 (로컬 or 클라우드)

2️⃣ Deployment & Service 생성하여 애플리케이션 배포

3️⃣ Ingress + NGINX Ingress Controller로 도메인 연결

4️⃣ Let's Encrypt & Cert-Manager로 HTTPS 적용

5️⃣ Prometheus & Grafana로 모니터링 구축

6️⃣ CI/CD (GitHub Actions, Jenkins) 자동 배포 적용


Helm을 사용하여 클라우드 환경에서 Kubernetes 애플리케이션을 배포하는 과정을 단계별로 정리하겠습니다. 이 과정은 Kubernetes 클러스터가 이미 준비된 상태에서 Helm Chart를 생성하고, 이를 사용해 애플리케이션을 배포하는 전체 워크플로우를 포함합니다.


1. 클라우드 환경 준비

1.1 Kubernetes 클러스터 생성

클라우드 서비스 제공자(AWS, GCP, Azure 등)를 사용하여 Kubernetes 클러스터를 생성합니다.

예를 들어, AWS에서는 EKS, GCP에서는 GKE, Azure에서는 AKS를 사용할 수 있습니다.

  • AWS EKS:
  • eksctl create cluster --name my-cluster --region us-west-2 --nodes 3
  • GCP GKE:
  • gcloud container clusters create my-cluster --num-nodes=3 --zone=us-west1-a
  • Azure AKS:
  • az aks create --resource-group myResourceGroup --name myAKSCluster --node-count 3 --enable-addons monitoring --generate-ssh-keys

1.2 kubectl 설정

클러스터가 생성되면 kubectl이 해당 클러스터와 통신할 수 있도록 인증 정보를 설정합니다.

aws eks update-kubeconfig --region us-west-2 --name my-cluster

또는 GCP/GKE:

gcloud container clusters get-credentials my-cluster --zone us-west1-a


2. Helm 설치

Helm CLI 도구를 설치합니다. 로컬 환경에 설치되어 있어야 하며, 다음 명령어로 설치할 수 있습니다:

2.1 Helm 설치

  • MacOS (Homebrew):
  • brew install helm
  • Linux (Snap):
  • sudo snap install helm --classic
  • Windows (Chocolatey):
  • choco install kubernetes-helm

2.2 Helm 초기화

Helm 저장소를 업데이트합니다.

helm repo add stable <https://charts.helm.sh/stable>
helm repo update


3. Helm Chart 생성

Helm Chart는 Kubernetes 리소스를 정의하는 템플릿입니다.

3.1 Chart 생성

Helm Chart를 생성할 디렉터리를 준비하고 다음 명령어로 Chart를 생성합니다:

helm create finpilot-chart

생성된 디렉터리 구조는 다음과 같습니다:

finpilot-chart/
├── Chart.yaml        # Chart 메타데이터 정의 파일
├── values.yaml       # 기본 설정값 파일
├── templates/        # Kubernetes 리소스 템플릿 디렉터리
│   ├── deployment.yaml    # Deployment 템플릿
│   ├── service.yaml       # Service 템플릿
│   ├── ingress.yaml       # Ingress 템플릿 (선택)


4. values.yaml 수정

values.yaml 파일을 수정하여 애플리케이션의 설정값을 정의합니다.

예시:

replicaCount: 3

image:
  repository: greatsangho/finpilot-app
  tag: "latest"
  pullPolicy: IfNotPresent

service:
  type: LoadBalancer
  port: 80

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    kubernetes.io/ingress.class: "nginx"
    acme.cert-manager.io/http01-edit-in-place: "true"
  hosts:
    - host: "finpilot.duckdns.org"
      paths:
        - path: /
          pathType: ImplementationSpecific

resources: {}
autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 5

1. Chart 파일 준비

먼저, 로컬 디렉터리(예: finpilot-chart)에 아래와 같이 Chart.yaml, values.yaml, 그리고 templates 폴더 내에 클러스터에 배포할 Kubernetes 리소스 템플릿 파일들을 모두 준비합니다.

  • Chart.yaml
    • Chart 메타데이터(이름, 버전, 앱 버전 등)를 정의합니다.
    • 필요한 경우 description이나 appVersion 등의 필드를 실제 애플리케이션에 맞게 수정합니다.
  • values.yaml
    • Deployment, Service, Ingress 등 템플릿에 전달할 변수들을 설정합니다.
    • 예시에서는 애플리케이션 이미지, replicaCount, 서비스 타입(LoadBalancer), Ingress 도메인(finpilot.duckdns.org)과 TLS 설정, autoscaling 등의 값을 정의했습니다.
  • templates 폴더
    • ClusterIssuer, ConfigMap, Secret, finpilot-deployment, finpilot-service, finpilot-ingress, ingress-nginx 등의 YAML 템플릿 파일들이 위치합니다.
    • 템플릿 파일 내부에는 Helm 템플릿 문법({{ }})을 활용하도록 수정하여 values.yaml의 변수들이 삽입될 수 있도록 합니다.

2. 클러스터에 사전 설치된 리소스 확인

Helm 차트 내부에서 사용하는 cert-manager나 ingress-nginx의 경우 공식 Helm 차트를 통해 별도로 설치해두는 것이 좋습니다.

예를 들어:

  • cert-manager 설치
  • helm repo add jetstack <https://charts.jetstack.io> helm repo update helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version <버전> --set installCRDs=true
  • ingress-nginx 설치
  • helm repo add ingress-nginx <https://kubernetes.github.io/ingress-nginx> helm repo update helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace

이처럼 차트에 직접 포함하지 않는 의존성 리소스가 있다면 미리 클러스터에 설치해 두어야 합니다.

3. Helm 차트 빌드 및 배포

먼저 dry-run을 통해 잘 구성되었는지 확인합니다.

helm install finpilot-release ./finpilot-chart --namespace finpilot --dry-run --debug

준비가 완료되면, 아래 명령어를 통해 finpilot 애플리케이션 및 관련 리소스를 배포할 수 있습니다.

helm install finpilot-release ./finpilot-chart --namespace finpilot --create-namespace

  • finpilot-release
    • Helm에서 내부적으로 관리할 release 이름입니다. 이 이름은 생성되는 리소스 이름의 접두어로 붙습니다.
  • ./finpilot-chart
    • 로컬 디렉터리 내에 있는 finpilot-chart 차트 경로입니다. 이 디렉터리는 Chart.yaml, values.yaml, templates 등을 포함해야 합니다.
  • -namespace finpilot
    • 모든 리소스가 생성될 네임스페이스입니다.
    • 만약 해당 네임스페이스가 존재하지 않으면, 다음 옵션으로 함께 생성합니다.
  • -create-namespace
    • 지정한 네임스페이스가 없으면 자동으로 생성하도록 하는 옵션입니다.

4. 배포 후 확인

배포가 완료된 후 다음 명령어들을 통해 배포된 리소스와 상태를 확인할 수 있습니다.

  • 배포된 release 목록 확인:
  • helm list --namespace finpilot
  • 해당 네임스페이스의 모든 리소스 상태 확인:
  • kubectl get all -n finpilot
  • Ingress 리소스의 EXTERNAL-IP(로드밸런서 IP) 확인:
  • kubectl get svc -n ingress-nginx

또한, 정의된 Ingress에 따라 finpilot.duckdns.org 도메인에 접근했을 때 TLS 인증서가 발급되고, 인증된 HTTPS 요청이 애플리케이션(Pod)으로 정상적으로 라우팅되는지 확인합니다.

5. 업데이트와 삭제

  • 배포한 후, values.yaml이나 템플릿 파일에 변경이 생겼다면 다음과 같이 업데이트할 수 있습니다.
  • helm upgrade finpilot-release ./finpilot-chart --namespace finpilot
  • 차트 배포를 삭제하려면:
  • helm uninstall finpilot-release --namespace finpilot

이와 같이 Helm 차트를 활용하면 여러 YAML 파일을 하나의 패키지로 구성하여 간편하게 배포, 업데이트, 삭제를 관리할 수 있습니다.


1. Kubernetes 설치 (Debian)

1.1. 시스템 업데이트

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl apt-transport-https ca-certificates gnupg lsb-release

1.2. Docker 설치

  1. Docker 패키지 설치:
  2. sudo apt install -y apt-transport-https ca-certificates curl software-properties-common curl -fsSL <https://download.docker.com/linux/debian/gpg> | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] <https://download.docker.com/linux/debian> $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io
  3. Docker 서비스 활성화:
  4. sudo systemctl enable docker sudo systemctl start docker
  5. 현재 사용자 권한 추가:
  6. sudo usermod -aG docker $USER

1.3. Kubernetes 설치

  1. Kubernetes 패키지 설치:
  2. sudo mkdir -p /etc/apt/keyrings curl -fsSL <https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key> | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] <https://pkgs.k8s.io/core:/stable:/v1.29/deb/> /" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt update sudo apt install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl sudo swapoff -a
  3. Swap 비활성화:
    sudo apt update
    sudo apt install -y containerd
    sudo mkdir -p /etc/containerd
    sudo containerd config default | sudo tee /etc/containerd/config.toml
    sudo nano /etc/containerd/config.toml
    
    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
      SystemdCgroup = true
    
    sudo systemctl restart containerd
    sudo systemctl enable containerd
    systemctl status containerd
    
  4. sudo swapoff -a sed -i '/ swap / s/^/#/' /etc/fstab

1.4. 클러스터 초기화

  1. 클러스터 초기화:
  2. sudo kubeadm init --pod-network-cidr=10.244.0.0/16
  3. 사용자 환경 설정:
  4. mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
  5. 네트워크 플러그인 설치 (예: Calico):
  6. kubectl apply -f <https://docs.projectcalico.org/manifests/calico.yaml>

2. NGINX Ingress Controller 설치

2.1. Ingress Controller 설치

kubectl apply -f <https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml>

2.2. 설치 확인

Ingress Controller가 정상적으로 실행 중인지 확인합니다:

kubectl get pods -n ingress-nginx


3. cert-manager 설치 및 HTTPS 설정

3.1. cert-manager 설치

kubectl apply -f <https://github.com/cert-manager/cert-manager/releases/download/v1.16.3/cert-manager.yaml>

3.2. ClusterIssuer 생성

ClusterIssuer를 생성하여 Let's Encrypt 인증서를 발급받도록 설정합니다.

ClusterIssuer 매니페스트 예제:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: <https://acme-v02.api.letsencrypt.org/directory>
    email: your-email@example.com # 이메일 주소 입력 (Let's Encrypt 계정)
    privateKeySecretRef:
      name: letsencrypt-prod-key # 인증서 키 저장용 Secret 이름 지정
    solvers:
    - http01:
        ingress:
          class: nginx # NGINX Ingress와 연동 설정

적용 명령어:

kubectl apply -f clusterissuer.yaml


4. FastAPI 서버 배포

4.1 FastAPI Deployment 및 Service 생성

FastAPI 애플리케이션을 배포합니다.

Deployment 및 Service 매니페스트 예제:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 2 # 복제본 수 설정 (필요에 따라 조정)
  selector:
    matchLabels:
      app: fastapi-app # Service와 일치해야 함.
  template:
    metadata:
      labels:
        app: fastapi-app # Service와 일치해야 함.
    spec:
      containers:
      - name: fastapi-container
        image: greatsangho/finpilot-app:latest # FastAPI 도커 이미지 사용.
        ports:
        - containerPort: 8000

---
apiVersion: v1
kind: Service
metadata:
  name: fastapi-service # Ingress에서 참조할 이름.
spec:
  selector:
    app: fastapi-app # Deployment와 일치해야 함.
  ports:
  - protocol: TCP
    port: 80         # 외부 노출 포트.
    targetPort: 8000 # 컨테이너 내부 포트.

적용 명령어:

kubectl apply -f fastapi-deployment.yaml


5. Ingress 리소스 생성

Ingress 매니페스트 예제 (HTTPS 포함):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fastapi-ingress
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # HTTP를 HTTPS로 리디렉션.
    cert-manager.io/cluster-issuer: "letsencrypt-prod"     # ClusterIssuer 지정.
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - finpilotback.duckdns.org # DuckDNS 도메인 이름.
    secretName: fastapi-tls     # 자동 생성될 TLS Secret 이름.
  rules:
  - host: finpilotback.duckdns.org
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: fastapi-service # FastAPI 서비스 이름과 일치해야 함.
            port:
              number: 80          # FastAPI 서비스 포트와 일치해야 함.

적용 명령어:

kubectl apply -f ingress.yaml


6. DuckDNS 설정

DuckDNS에서 finpilotback.duckdns.org 도메인을 Kubernetes 클러스터의 Ingress Controller 외부 IP로 연결합니다.

  1. Ingress Controller의 외부 IP 확인:
kubectl get svc -n ingress-nginx ingress-nginx-controller

  1. DuckDNS에서 해당 IP를 도메인에 매핑합니다.

7. 테스트

  1. 브라우저에서 https://finpilotback.duckdns.org에 접속하여 FastAPI 서버가 동작하는지 확인합니다.
  2. 인증서 상태 확인 (선택):
kubectl describe certificate fastapi-tls

  1. HTTPS 요청 테스트 (curl):
curl -v <https://finpilotback.duckdns.org>


이 과정을 완료하면, Debian 기반 Kubernetes 클러스터에서 finpilotback.duckdns.org 도메인을 사용하여 HTTPS로 보호된 FastAPI 서버를 실행할 수 있습니다!

반응형