근묵자흑
Service Discovery 심화: Knative 본문
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
점진적 롤아웃 단계:
- 10% Canary → 모니터링
- 50% Canary → 성능 검증
- 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. 참고
'k8s > kubernetes-pattern' 카테고리의 다른 글
| Kubernetes Pattern: Init Conatiner (2) | 2025.11.15 |
|---|---|
| Kubernetes Pattern: Self Awareness (0) | 2025.11.08 |
| Kubernetes Pattern: Service Discovery (4) | 2025.10.25 |
| Kubernetes Pattern: Stateless Service (8) | 2025.10.18 |
| Kubernetes Pattern: Stateful Service (0) | 2025.10.11 |