Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
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
Archives
Today
Total
관리 메뉴

근묵자흑

Service Discovery 심화: Knative 본문

k8s/kubernetes-pattern

Service Discovery 심화: Knative

Luuuuu 2025. 11. 1. 20:33

1. 들어가며: Service Discovery의 진화

1.1 전통적인 Service Discovery의 한계

마이크로서비스 아키텍처에서 Service Discovery는 필수적입니다. 하지만 기존 방식들은 각각의 한계를 가지고 있었습니다:

# 전통적인 Kubernetes Service
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
---
# 별도의 Deployment 필요
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  template:
    # ... 복잡한 설정
---
# 별도의 HPA 필요
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
# ...

문제점:

  • 여러 리소스 관리의 복잡성
  • 수동 스케일링 설정
  • Zero-scaling 불가능
  • 버전 관리의 어려움

관련하여 이 블로그 참고 : https://devstory.tistory.com/52

 
 

1.2 Knative가 제시하는 해결책

Knative는 이 모든 것을 하나로 통합합니다:

# Knative Service - 단 하나의 리소스!
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    spec:
      containers:
      - image: my-app:v1

장점:

  • 단일 리소스로 전체 스택 관리
  • 자동 Service Discovery
  • 자동 오토스케일링 (scale-to-zero 포함)
  • 불변 버전 관리 (Revision)
  • 트래픽 분할 내장

2. Knative란 무엇인가?

2.1 정의와 핵심 개념

Knative는 Kubernetes 위에서 동작하는 오픈소스 서버리스 플랫폼입니다.

핵심 컴포넌트

1. Knative Serving

  • HTTP 워크로드 배포 및 관리
  • 자동 스케일링 (KPA)
  • 트래픽 라우팅
  • Revision 관리

2. Knative Eventing (선택)

  • 이벤트 기반 아키텍처
  • Broker/Trigger 패턴
  • 다양한 이벤트 소스 통합

2.2 아키텍처 개요

┌─────────────────────────────────────────────────┐
│              External Traffic                   │
└────────────────┬────────────────────────────────┘
                 │
┌────────────────▼────────────────────────────────┐
│         Kourier/Istio Gateway                   │
│       (Layer 7 Load Balancing)                  │
└────────────────┬────────────────────────────────┘
                 │
        ┌────────┴────────┐
        │                 │
┌───────▼──────┐  ┌──────▼────────┐
│  Activator   │  │  Queue Proxy  │
│  (Cold Start)│  │  (Metrics)    │
└───────┬──────┘  └──────┬────────┘
        │                │
        └────────┬────────┘
                 │
┌────────────────▼────────────────────────────────┐
│           Application Pods                      │
│                                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐       │
│  │ Pod 1    │  │ Pod 2    │  │ Pod N    │       │
│  └──────────┘  └──────────┘  └──────────┘       │
└─────────────────────────────────────────────────┘
                 ▲
                 │
┌────────────────┴─────────────────────────────────┐
│              Autoscaler (KPA)                    │
│  - Decision Making                               │
│  - Replica Management                            │
│  - Panic Mode Handling                           │
└──────────────────────────────────────────────────┘

3. Knative의 Service Discovery 메커니즘

3.1 자동 DNS 구성

Knative Service를 생성하면 자동으로 여러 레벨의 DNS가 구성됩니다:

# 1. ClusterIP 기반 내부 DNS
http://{service}.{namespace}.svc.cluster.local

# 2. Knative 도메인
http://{service}.{namespace}.example.com

# 3. Revision별 URL
http://{revision}.{service}.{namespace}.example.com

# 4. Tag별 URL (Blue/Green, Canary)
http://{tag}-{service}.{namespace}.example.com

실습 예제

# Service 배포
cat <<EOF | kubectl apply -f -
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: hello
spec:
  template:
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Knative"
EOF

# DNS 자동 생성 확인
kubectl get ksvc hello

# 출력:
# NAME    URL                                      READY
# hello   http://hello.default.svc.cluster.local   True

# 내부에서 접근
kubectl run test --image=curlimages/curl --rm -i --restart=Never -- \
  curl -s http://hello.default.svc.cluster.local

# 출력: Hello Knative!

3.2 Service vs Revision vs Route

Knative의 Service Discovery는 3단계 추상화로 구성됩니다:

Service (사용자 인터페이스)
   ├─ Configuration (선언적 설정)
   │    └─ Revision (불변 스냅샷)
   │         └─ Pod (실제 컨테이너)
   └─ Route (트래픽 라우팅)
        └─ 트래픽 분할 규칙

실제 동작 확인

# Revision 목록
kubectl get revisions

# 출력:
# NAME          CONFIG NAME   GENERATION   READY
# hello-00001   hello         1            True
# hello-00002   hello         2            True

# Route 설정 확인
kubectl get route hello -o yaml

# Traffic 분할 상태
kubectl get ksvc hello -o jsonpath='{.status.traffic}' | jq .

3.3 Load Balancing 메커니즘

Knative는 여러 레이어의 로드밸런싱을 제공합니다:

Layer 1: Gateway (Kourier/Istio)

  • External → Activator/Queue Proxy
  • L7 (HTTP) 로드밸런싱
  • TLS Termination

Layer 2: Activator

  • 콜드 스타트 시 요청 버퍼링
  • 헬스 체크
  • Revision 간 트래픽 분산

Layer 3: Queue Proxy (Sidecar)

  • 각 Pod의 사이드카
  • 동시성 제한
  • 메트릭 수집

Layer 4: Application

  • 실제 워크로드

4. Minikube에서 Knative 구축하기

4.1 환경 준비

# Minikube 시작 (충분한 리소스 할당)
minikube start --cpus=4 --memory=8192 --disk-size=20g

# 상태 확인
minikube status

4.2 Knative 설치

자동 설치 스크립트

#!/bin/bash
# install-knative.sh

KNATIVE_VERSION="1.12.0"

# 1. Knative Serving CRDs
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v${KNATIVE_VERSION}/serving-crds.yaml

# 2. Knative Serving Core
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v${KNATIVE_VERSION}/serving-core.yaml

# 3. Kourier (Networking Layer)
kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v${KNATIVE_VERSION}/kourier.yaml

# 4. Kourier를 기본 네트워킹으로 설정
kubectl patch configmap/config-network \
  --namespace knative-serving \
  --type merge \
  --patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'

# 5. DNS 설정 (Magic DNS)
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v${KNATIVE_VERSION}/serving-default-domain.yaml

# 6. 설치 완료 대기
kubectl wait --for=condition=Ready pods --all -n knative-serving --timeout=300s

echo "Knative 설치 완료!"

설치 검증

# Pod 상태 확인
kubectl get pods -n knative-serving

# 출력 (실제 테스트 결과):
# NAME                                     READY   STATUS
# activator-675dfdd446-8jdck               1/1     Running
# autoscaler-658b65bdcf-vj97v              1/1     Running
# controller-798cdd5cf-wxstx               1/1     Running
# net-kourier-controller-957dbd84b-4jb48   1/1     Running
# webhook-5fc745f5df-tvpmc                 1/1     Running

4.3 첫 번째 Service 배포

# hello-service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: hello
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "1"
        autoscaling.knative.dev/max-scale: "5"
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Knative on Minikube"
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
# 배포
kubectl apply -f hello-service.yaml

# 상태 확인
kubectl get ksvc hello

# 테스트
kubectl run test --image=curlimages/curl --rm -i --restart=Never -- \
  curl -s http://hello.default.svc.cluster.local

# 출력: Hello Knative on Minikube!

5. 핵심 기능 심층 분석

5.1 Scale-to-Zero: 진정한 서버리스

동작 원리

요청 없음 (30초 경과)
    ↓
Pod 수: 1 → 0 (Scale-to-zero)
    ↓
메모리 및 CPU 자원 반환
    ↓
첫 요청 도착
    ↓
Activator가 요청 버퍼링
    ↓
Pod 생성 시작 (Cold Start)
    ↓
Pod Ready (3-5초)
    ↓
요청 전달 및 응답

실습: Scale-to-zero 확인

# scale-to-zero.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: autoscale-zero
spec:
  template:
    metadata:
      annotations:
        # Scale-to-zero 활성화
        autoscaling.knative.dev/min-scale: "0"
        autoscaling.knative.dev/max-scale: "10"

        # 30초 동안 트래픽 없으면 0으로 스케일
        autoscaling.knative.dev/scale-to-zero-pod-retention-period: "30s"

        # 타겟 동시성
        autoscaling.knative.dev/target: "10"
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Scale-to-Zero Demo"
# 배포
kubectl apply -f scale-to-zero.yaml

# 초기 Pod 수 확인
kubectl get pods -l serving.knative.dev/service=autoscale-zero
# 출력: 1개 Pod Running

# 30초 대기
sleep 40

# Scale-to-zero 후 확인
kubectl get pods -l serving.knative.dev/service=autoscale-zero
# 출력: No resources found (0개)

# 콜드 스타트 테스트
time kubectl run test --image=curlimages/curl --rm -i --restart=Never -- \
  curl -s http://autoscale-zero.default.svc.cluster.local

# 실제 테스트 결과: 4초 (콜드 스타트)

콜드 스타트 최적화 전략

# 프로덕션 환경 권장 설정
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: production-service
spec:
  template:
    metadata:
      annotations:
        # 중요 서비스는 min-scale >= 1
        autoscaling.knative.dev/min-scale: "2"

        # 초기 Pod 수 (빠른 시작)
        autoscaling.knative.dev/initial-scale: "3"

        # 느린 scale-down (안정성)
        autoscaling.knative.dev/scale-down-delay: "5m"
    spec:
      containers:
      - image: production-app:v1
        # 빠른 readiness
        readinessProbe:
          httpGet:
            path: /healthz
          initialDelaySeconds: 0
          periodSeconds: 1

5.2 KPA (Knative Pod Autoscaler) 심층 분석

KPA vs HPA 비교

특징 KPA HPA
Scale-to-Zero 지원 미지원 (min=1)
기본 메트릭 Concurrency, RPS CPU, Memory
반응 속도 빠름 (6초 윈도우) 느림 (15초 윈도우)
패닉 모드 지원 미지원
안정화 윈도우 60초 5분
사용 사례 HTTP 워크로드 일반 워크로드

KPA 알고리즘

# KPA 스케일링 알고리즘 (의사 코드)
def calculate_desired_replicas(metrics):
    # 안정 윈도우 (60초) 평균
    stable_concurrency = avg(metrics.last_60_seconds)

    # 패닉 윈도우 (6초) 평균
    panic_concurrency = avg(metrics.last_6_seconds)

    # 패닉 모드 체크
    if panic_concurrency / target_concurrency > panic_threshold:
        # 공격적 스케일링 (200% 초과 시)
        desired = ceil(panic_concurrency /
                      (target_concurrency * target_utilization))
        print(f" PANIC MODE: Scaling to {desired} replicas")
        return desired

    # 일반 모드: 안정적 스케일링
    desired = ceil(stable_concurrency /
                  (target_concurrency * target_utilization))

    return desired

실습: 동시성 기반 스케일링

# concurrency-scaling.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: autoscale-concurrency
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "1"
        autoscaling.knative.dev/max-scale: "20"

        # 각 Pod는 최대 10개 동시 요청
        autoscaling.knative.dev/target: "10"

        # 패닉 모드 (200% 초과 시 발동)
        autoscaling.knative.dev/panic-threshold-percentage: "200"
        autoscaling.knative.dev/panic-window-percentage: "10"
    spec:
      # 하드 리밋
      containerConcurrency: 50

      containers:
      - image: gcr.io/knative-samples/autoscale-go:0.0.1
# 배포
kubectl apply -f concurrency-scaling.yaml

# 초기 Pod 수
kubectl get pods -l serving.knative.dev/service=autoscale-concurrency
# 출력: 1개 (min-scale=1)

# 30개 동시 요청 생성 (target=10이므로 3개 Pod 예상)
for i in {1..30}; do
  kubectl run load-$i --image=curlimages/curl --rm -i --restart=Never -- \
    curl -s "http://autoscale-concurrency.default.svc.cluster.local?sleep=2000" &
done

# 스케일 업 확인
sleep 10
kubectl get pods -l serving.knative.dev/service=autoscale-concurrency
# 예상: 3개 이상 Pod

5.3 Traffic Splitting: 무중단 배포

Blue/Green 배포

# blue-green-v1.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: color-app
spec:
  template:
    metadata:
      name: color-app-blue  # Revision 이름 명시
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Blue Version (v1)"
# blue-green-v2.yaml (Green 배포, 트래픽 0%)
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: color-app
spec:
  template:
    metadata:
      name: color-app-green
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Green Version (v2)"
  traffic:
  # Blue에 100% (기존 버전 유지)
  - revisionName: color-app-blue
    percent: 100
    tag: blue
  # Green은 배포만, 트래픽 0%
  - revisionName: color-app-green
    percent: 0
    tag: green
# blue-green-switch.yaml (Green으로 전환)
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: color-app
spec:
  traffic:
  # Green으로 완전 전환
  - revisionName: color-app-green
    percent: 100
    tag: green
  # Blue는 롤백용 유지
  - revisionName: color-app-blue
    percent: 0
    tag: blue

Canary 배포

# canary-10-percent.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: canary-app
spec:
  template:
    metadata:
      name: canary-app-v2
    spec:
      containers:
      - image: my-app:v2
  traffic:
  - revisionName: canary-app-v1
    percent: 90
    tag: stable
  - revisionName: canary-app-v2
    percent: 10
    tag: canary

점진적 롤아웃 단계:

  1. 10% Canary → 모니터링
  2. 50% Canary → 성능 검증
  3. 100% Canary → 완전 전환

태그 기반 URL 접근

# Stable 버전 접근
curl http://stable-canary-app.default.svc.cluster.local

# Canary 버전 접근
curl http://canary-canary-app.default.svc.cluster.local

# 메인 URL (트래픽 분할 적용)
curl http://canary-app.default.svc.cluster.local

6. 문제 해결 

일반적인 문제와 해결 방법

1. Service가 Ready 상태가 안 됨

# 디버깅 단계
# 1. Pod 상태 확인
kubectl get pods -l serving.knative.dev/service=my-service

# 2. Pod 로그 확인
kubectl logs <POD_NAME> -c user-container

# 3. Events 확인
kubectl get events --sort-by='.lastTimestamp' | grep my-service

# 4. Revision 상태 확인
kubectl describe revision <REVISION_NAME>

# 5. Route 설정 확인
kubectl get route my-service -o yaml

2. 콜드 스타트가 너무 느림

해결책:

# min-scale 설정으로 웜 인스턴스 유지
autoscaling.knative.dev/min-scale: "1"

# 또는 이미지 최적화
# - 멀티스테이지 빌드
# - 경량 베이스 이미지 (alpine)
# - 불필요한 의존성 제거

3. 스케일링이 동작하지 않음

# 1. Autoscaler 로그 확인
kubectl logs -n knative-serving -l app=autoscaler

# 2. Metrics 수집 확인
kubectl top pods

# 3. PodAutoscaler 상태
kubectl get podautoscaler

# 4. ConfigMap 설정 확인
kubectl get configmap config-autoscaler -n knative-serving -o yaml

7. Knative의 강점과 한계

강점

1. 개발자 경험

  • 단일 YAML로 전체 스택 관리
  • 자동 Service Discovery
  • 버전 관리 내장
  • 트래픽 분할 간편

2. 운영 효율성

  • Scale-to-zero로 비용 절감
  • 자동 오토스케일링
  • 무중단 배포 지원
  • Kubernetes 복잡성 추상화

3. 확장성

  • 클라우드 네이티브
  • 멀티 클라우드 지원
  • 풍부한 생태계
  • 활발한 커뮤니티

한계와 고려사항

1. 콜드 스타트

  • 첫 요청 응답 지연 (3-5초)
  • 해결: min-scale 설정

2. 학습 곡선

  • Kubernetes 지식 필요
  • 새로운 개념 (Revision, Route)
  • 해결: 충분한 학습 시간

3. 리소스 오버헤드

  • Sidecar (Queue Proxy)
  • Activator, Autoscaler
  • 해결: 적절한 클러스터 리소스

8. 참고