본문 바로가기

끄적끄적/IT공부

[IT공부]Kubernetes Availablity

실습 환경 배포

필수 세팅

# Install Kind
brew install kind
kind --version

# Install kubectl
brew install kubernetes-cli
kubectl version --client=true

# Install Helm
brew install helm
helm version

Docker Engine Resource

  • vCPU 4
  • Memory 8GB

kind 및 툴 설치

 

kind 기본 사용 - 클러스터 배포 및 확인

# 클러스터 배포 전 확인
docker ps

# Create a cluster with kind
kind create cluster

# 클러스터 배포 확인
kind get clusters
kind get nodes
kubectl cluster-info

# 노드 정보 확인
kubectl get node -o wide

# 파드 정보 확인
kubectl get pod -A
kubectl get componentstatuses

# 컨트롤플레인 (컨테이너) 노드 1대가 실행
docker ps
docker images

# kube config 파일 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시

# 클러스터 삭제
kind delete cluster

# kube config 삭제 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시


쿠버네티스 가용성

쿠버네티스 가용성 확보를 위한 다양한 방법

쿠버네티스의 가용성을 확보하기 위한 다양한 방법

  • HPA (Horizontal Pod Autoscaling) : Pod 수평 확장 (스케일 In - Out)
  • VPA (Vertical Pod Autoscaling) : Pod 수직 확장 (스케일 Up)
  • CA (Cluster Autoscaling) : Node 확장 (Cloud 환경)
  • Metrics Server 설치
    • Kubernetes 에 내장된 확장 파이프라인을 위한 컨테이너 지표 수집 서버
    • Kubelet 의 지표를 수집하고 노출하여 API Server 에 전달
    • HPA, VPA 같은 자동 확장 사용 목적 (모니터링 솔루션 X)
# Metrics Server 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Metrics Server SSL 무시
kubectl patch deployment metrics-server -n kube-system --type=json \
  -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'

# Metrics Server 배포 확인
kubectl get pods -n kube-system -l k8s-app=metrics-server

# 쿠버네티스 리소스 자원 사용량 확인
kubectl top node
kubectl top pods -A

# CPU, Memory 내림차순
kubectl top pods -A --sort-by=cpu
kubectl top pods -A --sort-by=memory

HPA

수평 스케일링(Horizontal Pod Autoscaling)

  • 애플리케이션 부하(Load)에 따라 Pod 개수를 자동으로 늘리거나 줄이는 기능
  • 모니터링 대상: CPU, Memory, 사용자 정의 지표
  • Metrics Server 가 감시한 지표를 활용하여 설정된 임계치를 초과하면 Replica 수 조정
  • 기본 구성
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-sample
spec:
  scaleTargetRef:          # Scale 타겟 지정
    apiVersion: apps/v1
    kind: Deployment
    name: my-app           # Deployment 이름
  minReplicas: 2           # 최소 Pod
  maxReplicas: 10          # 최대 Pod
  metrics:                 # Scale 기준 지표 설정
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 50  # CPU 사용률 50% 기준
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 70  # 메모리 사용률 70% 기준

HPA 구성

  • Deployment 배포
cat << EOF >> hpa-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hpa-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hpa-nginx
  template:
    metadata:
      labels:
        app: hpa-nginx
    spec:
      containers:
      - name: hpa-nginx
        image: nginx
        resources:
          requests:
            cpu: 50m
          limits:
            cpu: 100m
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hpa-nginx
  labels:
    app: hpa-nginx
spec:
  ports:
  - port: 80
  selector:
    app: hpa-nginx
EOF

cat hpa-nginx.yaml

# Deployment 배포
kubectl apply -f hpa-nginx.yaml

kubectl get deploy,pod

  • HPA 구성
# HPA 생성
kubectl autoscale deployment hpa-nginx --cpu-percent=50 --min=1 --max=10

# HPA 확인
kubectl get hpa
...
NAME        REFERENCE              TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
hpa-nginx   Deployment/hpa-nginx   cpu: 0%/50%   1         10        1          17s
....

# HPA 상세 정보 확인
kubectl describe hpa

 

  • yaml 형태(kubectl get hpa -o yaml) 출력
apiVersion: v1
items:
- apiVersion: autoscaling/v2
  kind: HorizontalPodAutoscaler
  metadata:
    creationTimestamp: "2025-05-10T15:08:41Z"
    name: hpa-nginx
    namespace: default
    resourceVersion: "1262"
    uid: 5ffd1aa2-b1e0-4462-93b0-2273543e5dd3
  spec:
    maxReplicas: 10
    metrics:
    - resource:
        name: cpu
        target:
          averageUtilization: 50
          type: Utilization
      type: Resource
    minReplicas: 1
    scaleTargetRef:
      apiVersion: apps/v1
      kind: Deployment
      name: hpa-nginx
  status:
    conditions:
    - lastTransitionTime: "2025-05-10T15:08:56Z"
      message: recent recommendations were higher than current one, applying the highest
        recent recommendation
      reason: ScaleDownStabilized
      status: "True"
      type: AbleToScale
    - lastTransitionTime: "2025-05-10T15:08:56Z"
      message: the HPA was able to successfully calculate a replica count from cpu
        resource utilization (percentage of request)
      reason: ValidMetricFound
      status: "True"
      type: ScalingActive
    - lastTransitionTime: "2025-05-10T15:08:56Z"
      message: the desired count is within the acceptable range
      reason: DesiredWithinRange
      status: "False"
      type: ScalingLimited
    currentMetrics:
    - resource:
        current:
          averageUtilization: 0
          averageValue: "0"
        name: cpu
      type: Resource
    currentReplicas: 1
    desiredReplicas: 1
kind: List
metadata:
  resourceVersion: ""

Pod 부하 발생

# 터미널 1번
while true; do kubectl get hpa; kubectl top pods; sleep 1s; done

# 터미널 2번
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while true; do wget -q -O- http://hpa-nginx.default.svc.cluster.local; done"

# 실습 종료 후 리소스 삭제
kubectl delete hpa --all
kubectl delete -f hpa-nginx.yaml

VPA

수직 스케일링 (VPA, Vertical Pod Autoscaling)

  • Pod 의 리소스 요청값(Request) 을 자동으로 조정하는 기능
  • 적용 대상 : Request (CPU, Memory)
  • Pod 의 개수를 늘리는 HPA 와 다르게 Pod 의 리소스 크기를 조정
    • VPA Recommender 에 의해 최적의 리소스 상태를 찾아서 조정
  • 하나의 Deployment 에 HPA, VPA 를 같이 사용할 수 없음 > 충돌 발생
  • Kubernetes v1.33 버전 부터는 기본 활성화 상태
  • but, kind 는 현재 v1.32 까지만 사용가능하므로 별도 controller 설치 필요
  • 기본 구성
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:                   # Scale 대상
    apiVersion: apps/v1
    kind: Deployment
    name: my-app               # Deployment 명칭
  updatePolicy:
    updateMode: "Auto"         # VPA Recommender 에 의해 자동 조정 활성화
  resourcePolicy:
    containerPolicies:
      - containerName: my-app-container # Container 명칭 "*" 사용 가능
        minAllowed:            # 컨테이너가 할당받을 수 있는 최소 리소스
          cpu: "200m"
          memory: "512Mi"
        maxAllowed:            # 컨테이너가 할당받을 수 있는 최대 리소스
          cpu: "2"
          memory: "2Gi"
  • VPA 배포
# EKS Workshop 소스 사용
git clone https://github.com/kubernetes/autoscaler.git

# VPA 배포
cd autoscaler/vertical-pod-autoscaler/
./hack/vpa-up.sh

# VPA Controller 확인
kubectl get pods -n kube-system | grep vpa

# VPA 제거
./hack/vpa-down.sh

  • VPA 테스트
    • 0.1 cpu 를 요청한 2개 Pod 배포 (실제 사용량보다 부족한 상태)
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
  name: hamster-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: hamster
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 50Mi
        maxAllowed:
          cpu: 1
          memory: 500Mi
        controlledResources: ["cpu", "memory"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hamster
spec:
  selector:
    matchLabels:
      app: hamster
  replicas: 2
  template:
    metadata:
      labels:
        app: hamster
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody
      containers:
        - name: hamster
          image: registry.k8s.io/ubuntu-slim:0.14
          resources:
            requests:
              cpu: 100m
              memory: 50Mi
          command: ["/bin/sh"]
          args:
            - "-c"
            - "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"
# 터미널 1번
while true;
 do date "+%Y-%m-%d %H:%m:%S";
 kubectl get pod -l app=hamster; 
 kubectl get vpa; 
 kubectl describe pod | grep "Requests:" -A2; 
 echo "=============="; 
 sleep 5s; 
done

# 터미널 2번
kubectl apply -f examples/hamster.yaml        

# 자원 삭제
kubectl delete -f examples/hamster.yaml

CA, KEDA

CA (Cluster Autoscaler)

  • Cluster Autoscaler
    • 쿠버네티스 클러스터에서 노드 수를 자동으로 확장, 축소하는 도구
    • HPA, VPA 는 Pod 단에서의 동작이지만, CA 는 워커 노드 단에서의 동작
    • 클라우드 환경에서 사용되며 파드를 배포할 노드의 리소스가 부족해지면 노드를 자동으로 확장
  • Karpenter
    • CA 와 동일하게 쿠버네티스 노드 수를 자동으로 확장, 축소하는 도구
    • CA 와는 다르게 Node 의 크기까지 자동으로 변경 (HPA + VPA 기능)
    • CA 에 비해 노드의 빠른 확장 및 축소 가능

KEDA (Kubernetes Event-Driven Autoscaler)

  • 기존 HPA(Horizontal Pod Autoscaler)는 리소스(CPU, Memory) 메트릭 기반 스케일링
  • KEDA 는 이벤트 기반의 Autoscaler
  • HPA 와 함께 사용하여 이벤트 기반으로 유연하게 확장 가능
    • ex) 특정 시간대에 미리 확장

애플리케이션 변수 관리

ConfigMap

?https://foxutech.medium.com/about-configmap-in-kubernetes-b6b9c0918ac2

 

 

 

  • Kubernetes 애플리케이션의 구성 파일이나 환경 설정Key-Value 형태로 저장하고 관리
  • 애플리케이션의 설정 정보를 외부에서 관리하고 Pod 와 컨테이너에서 참조
  • 주요 사용 용도
    1. 애플리케이션 설정 관리
      • 애플리케이션 구성 정보 (DB URL, 변수 등)을 ConfigMap 에 저장하여 Pod 환경 변수나 파일로 사용
    2. 애플리케이션 환경에 맞는 설정 값 변경
      • 애플리케이션을 재빌드 하지 않고 설정 값 변경
      • DEV, STG, PRD 환경에 따라 각각 다른 파일 구성으로 관리 목적
  • 기본 구성
# ConfigMap 샘플 구성
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config # ConfigMap 명칭
data:
  key1: value1    # Key : Value 형태 값 주입
  key2: value2
# ConfigMap 사용 예시
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
    - name: my-container
      image: my-image
      env:
        - name: MY_CONFIG_KEY  # 컨테이너에서 사용할 변수 Key 값
          valueFrom:
            configMapKeyRef:
              name: my-config  # 사용할 ConfigMap의 이름
              key: key1        # ConfigMap 내의 키 -> 값: value1

 

ConfigMap 기본 활용

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
data:
  DBNAME: mydatabase
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-configmap
spec:
  containers:
  - image: nginx
    name: nginx-configmap
    env:
    - name: DB
      valueFrom:
        configMapKeyRef:
          name: mysql
          key: DBNAME
EOF

# 오브젝트 확인
kubectl get cm,pod

# 상세 정보 조회
kubectl describe cm mysql
kubectl describe pod nginx-configmap

# pod 내부 변수 확인
kubectl exec -it nginx-configmap -- /bin/bash -c env
...
DB=mydatabase
...

# 리소스 삭제
kubectl delete pod --all
kubectl delete cm nginx-configmap

ConfigMap으로 설정 파일 관리

 

# 테스트 파일 생성
cat << EOF >> config-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-configmap-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-configmap
  template:
    metadata:
      labels:
        app: nginx-configmap
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx-configmap
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 31001
  type: NodePort
EOF

cat << EOF >> configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    events {}
    http {
        server {
            listen 80;
            location / {
                return 200 'Hello from nginx configmap!';
            }
        }
    }
EOF

 

  • 리소스 배포
kubectl apply -f configmap.yaml -f config-deploy.yaml

#
kubectl get cm,deploy,pod
kubectl describe deploy
...
    Mounts:
      /etc/nginx/nginx.conf from config-volume (rw,path="nginx.conf")
  Volumes:
   config-volume:
    Type:          ConfigMap (a volume populated by a ConfigMap)
    Name:          nginx-config
    Optional:      false
...

# Nginx 접속
open http://localhost:31001

# Nginx ConfigMap 변경
vim configmap.yaml
...
return 200 'Modify from nginx configmap!';
...

#
kubectl apply -f configmap.yaml

# pod 재시작
kubectl rollout restart deploy nginx-configmap-deploy

# 리소스 삭제
kubectl delete -f configmap.yaml -f config-deploy.yaml

https://aws.plainenglish.io/kubernetes-auto-restart-deployments-when-k8s-configmap-or-secret-is-updated-ad2c042a745f

  • ConfigMap 변경 시 Pod 수동 재배포가 필요 → 비효율적
  • ConfigMap, Secret 의 변동 사항을 주기적으로 확인해서 자동으로 Rollout 을 해주는 오픈소스 도구

Secret

https://www.macstadium.com/blog/how-to-k8s-kubernetes-secrets-made-simple

  • Kubernetes 에서 민감 정보를 안전하게 관리하는 객체 (비밀번호, 토큰, SSH 키 등)
  • ConfigMap 과 달리 Base64 로 인코딩된 형태로 데이터 저장
  • → Base64 는 암호화인가??
  • Secret 파일에 Base64 로 인코딩된 값이 아니면 사용할 수 없음
  • 주요 사용 용도
    • 비밀번호, API 키 등의 민감정보 저장
    • ConfigMap 과 동일하게 Pod 의 환경 변수나 파일로 주입 가능
  • 기본 구성
# Secret 샘플
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: bXl1c2Vy  # base64로 인코딩된 값
  password: bXlwYXNzd29yZA==  # base64로 인코딩된 값
# Secret 사용 예시
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
    - name: my-container
      image: my-image
      env:
        - name: DB_USER        # Container 에서 사용할 변수명
          valueFrom:
            secretKeyRef:
              name: my-secret  # 사용할 Secret의 이름
              key: username    # Secret 내의 키
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: my-secret  # 사용할 Secret의 이름
              key: password    # Secret 내의 키
...
# 마운트 방법
      volumeMounts:
        - name: secret-volume     # Volume 명칭
          mountPath: /etc/secrets # 컨테이너 내부 마운트 위치
  volumes:
    - name: secret-volume         # Volume 명칭
      secret:
        secretName: my-secret     # 사용할 Secret의 이름

 

Secret 기본 활용

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: secret-test
type: Opaque
data:
  username: YWRtaW4=  # 'admin'을 base64 인코딩한 값
  password: cGFzc3dvcmQ=  # 'password'를 base64 인코딩한 값
EOF

# Base64 인코딩 방법
echo -n 'admin' | base64
echo -n 'password' | base64

 

#
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: nginx
    image: nginx
    env:
    - name: DB_USER
      valueFrom:
        secretKeyRef:
          name: secret-test
          key: username
    - name: DB_PASS
      valueFrom:
        secretKeyRef:
          name: secret-test
          key: password
EOF

#
kubectl get pod,secret

# 상세 정보 조회
kubectl describe secret secret-test
kubectl describe pod secret-pod

# pod 내부 변수 확인
kubectl exec -it secret-pod -- /bin/bash -c env
...
DB_USER=admin
DB_PASS=password
...

# 리소스 삭제
kubectl delete pod --all
kubectl delete secret secret-test

  • Secret 을 관리하는 다양한 도구
    • ASCP (AWS Secret Store CSI Driver) - AWS Secret Manager 활용
    • HashiCorp Vault
    • Sealed Secret - OSS

참고) Sealed Secret

  • K8S Secret 을 암호화할 수 있는 OSS 도구
  • 기존 Base64 로 인코딩 되어 저장하는 Secret 이 아닌 암호화 되어 저장
  • Code Repository (Git) 에 암호화된 Secret 이 올라가기 때문에, GitOps Flow 를 그대로 사용할 수 있는 장점이 있음
  • Client Side(암호화) - Server Side (복호화)
# Mac Brew 설치 (Client-Side)
brew install kubeseal

# Server-Side 설치 - SealedSecret Controller
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install my-release sealed-secrets/sealed-secrets

# SealedSecret Controller 조회
kubectl get pods -l app.kubernetes.io/name=sealed-secrets

# Secret 생성
kubectl create secret generic mysecret \
  --from-literal hello=world \
  --dry-run=client \
  -o yaml > mysecret.yaml

# 
cat mysecret.yaml

# base64 디코딩
grep 'hello:' mysecret.yaml | awk '{print $2}' | base64 --decode

# Sealed Secret 생성
cat mysecret.yaml | \
  kubeseal \
   --controller-name my-release-sealed-secrets \
   --controller-namespace default -o yaml > mysealed-secret.yaml

# Sealed Secret 암호화 적용 확인
cat mysealed-secret.yaml
grep 'hello:' mysealed-secret.yaml | awk '{print $2}' | base64 --decode

#
kubectl apply -f mysealed-secret.yaml
kubectl get secret

# secret 확인
kubectl get secret mysecret -o json
kubectl get secret mysecret -o jsonpath="{.data.hello}" | base64 -d