포스트

[Kubernetes] Kubernetes Availability & Network (3주차)

[Kubernetes] Kubernetes Availability & Network (3주차)

3주차 - Kubernetes Availability & Network

🚢 쿠버네티스 가용성

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

쿠버네티스(Kubernetes) 환경에서는 서비스 가용성(Availability) 확보를 위해 다양한 자동 확장 기능을 제공

쿠버네티스 확장 방법

확장 방식 설명
HPA (Horizontal Pod Autoscaler) Pod의 수를 수평으로 자동 조절 (Scale In/Out)
VPA (Vertical Pod Autoscaler) Pod의 리소스(CPU/Memory 등)를 수직으로 자동 조절 (Scale Up/Down)
CA (Cluster Autoscaler) 노드를 자동으로 추가/제거 (Cloud 환경에서 활용)
  • 이러한 기능을 활용하면 트래픽 증가나 리소스 사용량 변화에 따라 자동으로 자원을 조절하여 시스템의 안정성과 가용성을 높일 수 있음

Metrics Server란?

Metrics Server는 쿠버네티스의 내장 확장 기능(HPA, VPA 등) 이 동작하는 데 필요한 리소스 사용량 정보를 수집하는 컴포넌트

  • Kubelet에서 CPU, 메모리 등 지표를 수집하여 API Server에 전달
  • HPA, VPA와 같은 오토스케일러가 이를 바탕으로 리소스 확장을 수행
  • 모니터링 솔루션이 아닌, 확장을 위한 데이터 제공자

Metrics Server 설치 및 명령어

참고자료

  • 설치
1
2
3
4
5
6
7
8
9
# Metrics Server 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Kubelet 인증서 검증 비활성화 (TLS 오류 방지)
kubectl patch deployment metrics-server -n kube-system --type=json \
  -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'

# 설치 확인
kubectl get pods -n kube-system -l k8s-app=metrics-server

img

  • 리소스 사용량 확인 명령어
1
2
3
4
5
6
7
8
9
10
11
# 전체 노드의 리소스 사용량
kubectl top nodes

# 전체 네임스페이스의 Pod 사용량
kubectl top pods -A

# CPU 사용량 기준 정렬
kubectl top pods -A --sort-by=cpu

# 메모리 사용량 기준 정렬
kubectl top pods -A --sort-by=memory

img

img


HPA

HPA

출처: https://kubernetes.io/ko/docs/tasks/run-application/horizontal-pod-autoscale/

수평 스케일링 (HPA, Horizontal Pod Autoscaling)

  • 부하 기반 자동 스케일링 기능
  • Pod의 수를 자동으로 늘리거나 줄임(Scale Out/In)
  • 기본적으로 CPU와 메모리 사용률, 사용자 정의 지표를 기준으로 작동
  • 지표 수집은 Metrics Server를 통해 이뤄지며, 설정한 임계치(Threshold)를 초과하면 Replica 수를 조정함
  • 작동 원리
    • Metrics Server가 CPU, Memory 사용률을 수집
    • HPA가 지정한 타겟 리소스(Deployment 등)의 부하를 모니터링
    • 설정한 기준치를 초과하면 Pod 수를 자동으로 조절
  • 기본 구성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 배포
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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

img

  • HPA 구성
1
2
3
4
5
6
7
8
# HPA 생성
kubectl autoscale deployment hpa-nginx --cpu-percent=50 --min=1 --max=10

# HPA 확인
kubectl get hpa

# HPA 상세 정보 확인
kubectl describe hpa

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-nginx
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hpa-nginx
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  • Pod 부하 발생시키기
1
2
3
4
5
6
7
8
9
# 터미널 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

img

출처: https://www.sktenterprise.com/bizInsight/blogDetail/dev/4488

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

  • Pod 단위의 CPU, Memory 요청량을 자동으로 튜닝
  • HPA는 수평 확장 / VPA는 수직 확장
  • 조정 대상: CPU, Memory의 Request
  • VPA Recommender가 애플리케이션의 사용량을 분석하여 최적의 리소스를 적용
  • HPA와 VPA는 하나의 Deployment에 동시에 적용 불가
  • Kubernetes v1.33부터 기본 활성화
    • ⚠️ 현재 kind는 v1.32까지만 지원 → 별도 컨트롤러 설치 필요
  • 기본 구성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 테스트

  • 0.1 cpu 를 요청한 2개 Pod 배포 (실제 사용량보다 부족한 상태)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 터미널 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번 (log 확인 용)
kubectl apply -f examples/hamster.yaml        

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

CA, KEDA

쿠버네티스 환경에서는 애플리케이션의 부하가 증가하면 Pod 수뿐만 아니라, Pod를 배치할 노드(Node) 리소스도 부족해질 수 있다.
이럴 때 사용되는 도구가 바로 Cluster Autoscaler (CA)Karpenter 이다.

📦 Cluster Autoscaler (CA)

공식 문서 보기

  • 쿠버네티스 클러스터의 노드 수를 자동으로 조절하는 컴포넌트
  • Pod의 요청 리소스를 만족시킬 수 있는 노드가 없으면 → 노드 자동 추가
  • 일정 시간 동안 유휴 상태인 노드가 있으면 → 노드 자동 삭제
  • 클라우드 환경에서 주로 사용 (AWS, GCP, Azure 등 지원)
  • Pod 단위로 동작하는 HPA, VPA와 달리, 노드 단위에서 작동

🚀 Karpenter

공식 사이트

  • AWS에서 만든 노드 자동 조절 도구
  • CA와 동일하게 노드를 자동 생성/삭제
  • 노드 크기(사양)까지 자동 조절HPA + VPA + CA 기능 통합
  • 더 빠른 노드 프로비저닝(생성) 가능
  • CA의 대체 도구로 각광받고 있음

✅ 정리

항목 Cluster Autoscaler (CA) Karpenter
대상 노드 수 자동 조절 노드 수 + 노드 사양 자동 조절
주요 기능 유휴 노드 축소, 부족 시 확장 적절한 사양과 수의 노드 자동 생성
속도 상대적으로 느림 빠름
운영 환경 다양한 클라우드 AWS 중심
배포 복잡도 비교적 단순 다소 복잡하지만 자동화 강점

⚡ 이벤트 기반 오토스케일링 - KEDA

img

출처: https://keda.sh/docs/2.17/concepts/

KEDA 공식 사이트

  • 이벤트 기반 자동 확장 도구
  • HPA와 연동하여 이벤트 기반으로 Pod 수를 자동으로 조절
  • CPU/Memory 외에도 Kafka, RabbitMQ, Azure Queue, Prometheus, Cron 등 다양한 이벤트 기반 확장 가능

🔧 어플리케이션 변수 관리

ConfigMap

img

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

  • Kubernetes 애플리케이션의 구성 파일이나 환경 설정을 Key-Value 형태로 저장하고 관리
  • 설정 값을 컨테이너 내부 환경 변수나 파일 형태로 주입 가능
  • 애플리케이션 코드를 재빌드하지 않고 설정만 변경할 수 있음

💡 주요 사용 용도

항목 설명
설정 정보 분리 소스 코드와 분리된 외부 설정 파일 관리
환경별 구성 DEV / STG / PRD 등 환경에 따른 설정 값 분리
동적 구성 Pod 재배포 없이 구성 값 수정 가능

기본 구성

1
2
3
4
5
6
7
8
# ConfigMap 샘플 구성
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config # ConfigMap 명칭
data:
  key1: value1    # Key : Value 형태 값 주입
  key2: value2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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

기본활용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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

img

img

ConfigMap 으로 설정 파일 관리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 테스트 파일 생성
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

리소스 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ConfigMap + Deployment 적용
kubectl apply -f configmap.yaml -f config-deploy.yaml  # ConfigMap과 Deployment 배포

# 리소스 확인
kubectl get cm,deploy,pod                             # 생성된 리소스 목록 확인
kubectl describe deploy                               # Deployment 상세 정보 확인
# -> ConfigMap이 어떻게 마운트되었는지 확인 가능

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

# ConfigMap 수정
vim configmap.yaml                                    # 설정 파일 수정
# 예: return 200 'Modify from nginx configmap!';

# 변경 사항 적용
kubectl apply -f configmap.yaml                       # 변경된 ConfigMap 적용
kubectl rollout restart deploy nginx-configmap-deploy # Deployment 재시작으로 ConfigMap 반영

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

img

img

img


🔐 Secret – Kubernetes 민감 정보 관리

img

Secret은 Kubernetes에서 비밀번호, 토큰, API 키 등 민감 정보를 안전하게 관리하기 위한 리소스이고,
ConfigMap과 유사하지만 Base64 인코딩된 형태로 값을 저장한다.

📌 Base64는 암호화가 아닌 인코딩입니다. 디코딩이 쉬우므로 별도의 보안 설정이 필요하다.

✅ 주요 특징

  • 민감 정보 저장 (비밀번호, 토큰 등)
  • Base64 인코딩 필수 (평문 저장 불가)
  • 환경 변수나 파일로 Pod에 주입 가능
  • etcd 저장소에 저장되므로 암호화 및 접근 제어 권장

기본 구성

1
2
3
4
5
6
7
8
9
# Secret 샘플
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: bXl1c2Vy  # base64로 인코딩된 값
  password: bXlwYXNzd29yZA==  # base64로 인코딩된 값
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 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의 이름

기본 활용

1
2
3
4
5
6
7
8
9
10
11
12
13
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

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

# Pod 및 Secret 확인
kubectl get pod,secret

# Secret 상세 정보 확인
kubectl describe secret secret-test

# Pod 상세 정보 확인
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                 # 모든 Pod 삭제
kubectl delete secret secret-test        # Secret 삭제

img

Secret 을 관리하는 다양한 도구

🟡 1. AWS Secrets Store CSI Driver (ASCP)

  • AWS Secrets Manager 또는 Parameter Store의 값을 Kubernetes Secret처럼 사용 가능
  • CSI(컨테이너 스토리지 인터페이스)를 통해 Pod에 자동 주입
  • 자동 rotation, 권한 제어 등 AWS IAM과의 연동 강점

🔗 공식 문서 보기

🟣 2. HashiCorp Vault

  • 강력한 비밀 관리 솔루션
  • 암호화된 데이터 저장, 동적 비밀번호 발급, 정책 기반 접근 제어 지원
  • Kubernetes와 연동하여 토큰을 통한 인증 및 자동 주입 가능

🔗 공식 문서 보기

🟢 3. Sealed Secrets

  • Bitnami에서 제공하는 오픈소스 도구
  • GitOps 환경에 최적화 (Git에 안전하게 저장 가능)
  • SealedSecret → Secret 으로 컨트롤러가 복호화하여 자동 생성
  • 공개키로 암호화, 클러스터 전용 비밀 키로 복호화

🔗 공식 문서 보기


🌐 Kubernetes 네트워크

img

출처: https://kubernetes.io/docs/concepts/cluster-administration/networking/

🔧 서비스 종류

service

  • Kubernetes에서 단일 엔드포인트를 제공하는 리소스
  • 파드(Pod) 집합을 하나의 네트워크 주소로 묶어 외부 혹은 내부 트래픽을 전달
  • 공식 문서 바로가기 🔗

🟢 ClusterIP (기본값)

  • 클러스터 내부 전용 가상 IP 제공
  • 외부에서는 접근 불가
  • 주로 마이크로서비스 간 통신에 사용
    🔗 자세히 보기

🟠 NodePort

  • 노드(Host)의 고정 포트를 통해 외부 접근 허용
  • 외부에서는 NodeIP:Port 방식으로 접근 가능
  • 간단한 테스트나 소규모 서비스 배포에 활용
    🔗 자세히 보기

🔵 LoadBalancer

  • 클라우드 환경에서 외부 로드 밸런서 자동 할당
  • 서비스 엔드포인트에 퍼블릭 IP 부여
  • AWS, GCP, Azure 등에서 사용 가능
    🔗 자세히 보기

🧪 ClusterIP

테스트 환경 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 어플리케이션 배포
cat << EOF >> cluster-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: cluster-pod-1
  labels:
    app: cluster-pod
spec:
  containers:
  - name: container
    image: traefik/whoami
---
apiVersion: v1
kind: Pod
metadata:
  name: cluster-pod-2
  labels:
    app: cluster-pod
spec:
  containers:
  - name: container
    image: traefik/whoami
EOF

# Test 파드
cat << EOF >> netshoot-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: netshoot-pod
spec:
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
EOF

# ClusterIP 서비스 생성
cat <<EOF>> cluster-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: cluster-svc
spec:
  type: ClusterIP
  selector:
    app: cluster-pod
  ports:
    - name: cluster
      port: 8080
      targetPort: 80
EOF

# 배포
kubectl apply -f cluster-pod.yaml -f cluster-svc.yaml -f netshoot-pod.yaml

Pod 생성 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 파드 대역 확인
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
...
10.244.0.0/24 10.244.1.0/24
...

# SVC 대역 확인
kubectl -n kube-system get pods -l component=kube-controller-manager -o yaml | grep service-cluster-ip-range
...
--service-cluster-ip-range=10.96.0.0/16
...

# 확인
kubectl get pod -o wide
...
NAME                                         READY   STATUS    RESTARTS   AGE     IP            NODE          NOMINATED NODE   READINESS GATES
cluster-pod-1                                1/1     Running   0          8m20s   10.244.1.66   kind-worker   <none>           <none>
cluster-pod-2                                1/1     Running   0          8m20s   10.244.1.65   kind-worker   <none>           <none>
netshoot-pod                                 1/1     Running   0          8m20s   10.244.1.67   kind-worker   <none>           <none>
...

# 서비스 확인
kubectl get svc cluster-svc
...
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
cluster-svc   ClusterIP   10.96.138.114   <none>        8080/TCP   9m18s
...

# Endpoint 확인 (Pod IP:Port)
kubectl get endpoints cluster-svc
...
NAME                                ENDPOINTS                       AGE
cluster-svc                         10.244.1.65:80,10.244.1.66:80   9m37s
...

img

ClusterIP 확인 (랜덤 트래픽 분산)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 클라이언트(TestPod) Shell 실행
kubectl exec -it netshoot-pod -- zsh

# 서비스 ClusterIP 주입
SVC=10.96.138.114

curl $SVC:8080
curl -s $SVC:8080 | grep Hostname

# 100 번 반복 호출
for i in {1..100}; do curl -s $SVC:8080 | grep Hostname; done | sort | uniq -c | sort -nr
...
55 Hostname: cluster-pod-1
45 Hostname: cluster-pod-2
...

🌐 NodePort

테스트 환경 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 어플리케이션 배포
cat << EOF > nodeport-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodeport-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nodeport-deploy
  template:
    metadata:
      labels:
        app: nodeport-deploy
    spec:
      containers:
      - name: container
        image: traefik/whoami
EOF

# ClusterIP 서비스 생성
cat <<EOF> nodeport-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nodeport-svc
spec:
  type: NodePort
  selector:
    app: nodeport-deploy
  ports:
    - name: nodeport-svc
      port: 80          # 서비스 포트 (Cluster 내부에서 사용)
      targetPort: 80    # 실제 컨테이너 포트
      nodePort: 31001   # 외부에서 접근할 NodePort
EOF

생성 및 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 생성
kubectl apply -f nodeport-pod.yaml -f nodeport-svc.yaml

# 확인
kubectl get pod,svc
...
NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/nodeport-svc   NodePort    10.96.66.182   <none>        80:31001/TCP   100s
...

# 연결된 IP:Port 목록 조회
kubectl get endpoints nodeport-svc
NAME           ENDPOINTS                       AGE
nodeport-svc   10.244.1.10:80,10.244.1.11:80   2m50s

img

NodePort 동작 확인

1
2
3
4
5
6
7
8
9
10
# 노드의 Port 로 curl 요청
curl http://localhost:31001
curl -s http://localhost:31001 | grep Hostname

# 100 번 반복 호출
for i in {1..100}; do curl -s http://localhost:31001 | grep Hostname; done | sort | uniq -c | sort -nr
...
58 Hostname: nodeport-deploy-59b68567d7-6h562
42 Hostname: nodeport-deploy-59b68567d7-k2cpb
...

img

🚪 Ingress

img

출처: https://outshift.cisco.com/blog/k8s-ingress

참고문서

Ingress 리소스의 주요 특징

  • 클러스터 외부에서 내부 서비스로 HTTP/HTTPS 트래픽을 전달
  • 서비스 유형 (ClusterIP, NodePort, LoadBalancer)을 외부에 노출
  • Ingress를 사용하려면 반드시 Ingress Controller가 필요

대표적인 Ingress Controller

  • Nginx Ingress Controller (가장 널리 사용됨)
  • 클라우드 제공 Ingress Controller
    • AWS: ALB Ingress Controller
    • GCP: GCE Ingress Controller

주요 기능

1.호스트 기반 라우팅

  • 도메인에 따라 트래픽을 분기
  • 예:
    • api.example.com → 서비스 A
    • www.example.com → 서비스 B

2.경로 기반 라우팅

  • 요청 경로(URL)에 따라 트래픽을 분기
  • 예:
    • /growth → 서비스 A
    • /log → 서비스 B

3.TLS 지원

  • HTTPS 구성 가능 (TLS 인증서 활용)

4.로드 밸런싱

  • 여러 백엔드로 트래픽을 분산 처리

기본 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: default
spec:
  rules:
  - host: example.com       # Domain Host
    http:
      paths:
      - path: /service1     # URL Path (example.com/service1)
        pathType: Prefix
        backend:
          service:
            name: service1  # /service1 로 들어온 트래픽을 전송할 service 명
            port:
              number: 80
      - path: /service2     # URL Path (example.com/service2)
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 80    # /service2 로 들어온 트래픽을 전송할 service 명

Nginx Ingress Controller 설치

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 기존 리소스 삭제
kind delete cluster

# kind cluster 재배포
kind create cluster --config kind-2node.yaml

# Nginx Ingress Controller 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# Service 타입 변경
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p \
'{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":80,"nodePort":31000},{"port":443,"targetPort":443,"nodePort":31001}]}}'

# Nginx Ingress Controller 리소스 확인
kubectl get -n ingress-nginx svc,deploy,pod

img

서비스 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Growth 서비스
cat << EOF > svc-growth.yaml
apiVersion: v1
kind: Service
metadata:
  name: growth-service
spec:
  selector:
    app: growth
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: growth-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: growth
  template:
    metadata:
      labels:
        app: growth
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - name: growth-html
              mountPath: /usr/share/nginx/html
      volumes:
        - name: growth-html
          configMap:
            name: growth-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: growth-html
data:
  index.html: |
    <html>
    <body>
      <h1>hello growth</h1>
    </body>
    </html>
EOF

kubectl apply -f svc-growth.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# Log 서비스
cat << EOF > svc-log.yaml
apiVersion: v1
kind: Service
metadata:
  name: log-service
spec:
  selector:
    app: log
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: log-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: log
  template:
    metadata:
      labels:
        app: log
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - name: log-html
              mountPath: /usr/share/nginx/html
      volumes:
        - name: log-html
          configMap:
            name: log-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: log-html
data:
  index.html: |
    <html>
    <body>
      <h1>hello log</h1>
    </body>
    </html>

EOF

kubectl apply -f svc-log.yaml
1
2
3
4
5
6
# 배포 확인
kubectl get pod,svc,cm

# ConfigMap 확인
kubectl describe cm growth-html
kubectl describe cm log-html

img

Ingress 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat << EOF > ingress-sample.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: growth-log-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: / # /growth, /log 요청을 서비스로 전달할 때 접두사 제거. ex) /growth -> growth-service '/'
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /growth
        pathType: Prefix
        backend:
          service:
            name: growth-service
            port:
              number: 80
      - path: /log
        pathType: Prefix
        backend:
          service:
            name: log-service
            port:
              number: 80
EOF

kubectl apply -f ingress-sample.yaml
1
2
3
4
5
# 조회
kubectl get ing,svc

# 상세 정보 조회
kubectl describe ingress growth-log-ingress

img

Ingress 동작 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# growth 경로 호출
curl http://localhost:31000/growth
...
<html>
<body>
  <h1>hello growth</h1>
</body>
</html>
...

# Log 경로 호출
curl http://localhost:31000/log
...
<html>
<body>
  <h1>hello log</h1>
</body>
</html>
...

img

🧑‍💻 Kubernetes Storage

img

출처: https://kubetm.github.io/k8s/03-beginner-basic-resource/volume/

공식문서

📦 emptyDir

  • Pod 내부에서 컨테이너 간 공유되는 임시 스토리지
  • Pod 삭제 시 해당 스토리지도 함께 삭제

🖥️ hostPath

  • Worker Node의 Directory Path를 Pod에 마운트
  • Pod 삭제 시에도 Node에 데이터가 남음
  • 다른 Node와 공유 불가, 해당 Node에만 데이터 존재

💾 PersistentVolume (PV)

  • 쿠버네티스 클러스터 전체에서 공유되는 볼륨
  • 다양한 크기의 PV를 미리 생성해 두고 Pod와 PVC를 통해 연결하여 사용
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.