관리 메뉴

근묵자흑

DefaultBuildHandlerChain 깊게 파헤치기 본문

k8s

DefaultBuildHandlerChain 깊게 파헤치기

Luuuuu 2025. 7. 10. 00:26

웹 서버가 HTTP 요청을 받았을 때, 단순히 "요청 받고 → 처리하고 → 응답 보내기"만 하면 될까요?

실제로는 훨씬 복잡합니다. 특히 Kubernetes처럼 수많은 컨테이너와 애플리케이션을 관리하는 시스템의 API 서버라면 더욱 그렇습니다. 인증은 누가 하고, 권한 검사는 언제 하며, 동시에 몰려오는 수천 개의 요청은 어떻게 처리할까요?

이 글에서는 Kubernetes API 서버의 핵심인 DefaultBuildHandlerChain 함수를 통해, 하나의 HTTP 요청이 어떤 여정을 거쳐 처리되는지 상세히 살펴보겠습니다. Go 언어와 Kubernetes를 처음 접하는 분들도 이해할 수 있도록, 기초부터 차근차근 설명하겠습니다.

목차

  1. Go 언어의 HTTP 처리 기초
  2. 미들웨어 패턴이란?
  3. Kubernetes API 서버 아키텍처 개요
  4. DefaultBuildHandlerChain 함수 분석
  5. 주요 필터들의 역할과 구현
  6. filterlatency - 성능 추적의 비밀
  7. 실제 요청 처리 흐름 따라가기
  8. 마치며

1. Go 언어의 HTTP 처리 기초

HTTP 핸들러란?

Go에서 웹 서버를 만들 때 가장 기본이 되는 개념은 http.Handler 인터페이스입니다. 이 인터페이스는 단 하나의 메서드만 가지고 있습니다:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

이게 뭔지 쉽게 설명하면, "HTTP 요청이 왔을 때 어떻게 처리할지를 정의하는 규칙"입니다.

간단한 예제를 보겠습니다:

package main

import (
    "fmt"
    "net/http"
)

// HelloHandler는 http.Handler 인터페이스를 구현합니다
type HelloHandler struct{}

func (h HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "안녕하세요!")
}

func main() {
    handler := HelloHandler{}
    http.ListenAndServe(":8080", handler)
}

위 코드를 실행하고 브라우저에서 http://localhost:8080에 접속하면 "안녕하세요!"가 출력됩니다.

http.HandlerFunc - 함수를 핸들러로

매번 구조체를 만들기 번거롭죠? Go는 일반 함수를 핸들러로 변환하는 편리한 방법을 제공합니다:

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "안녕하세요!")
}

func main() {
    // http.HandlerFunc는 함수를 Handler 인터페이스로 변환합니다
    handler := http.HandlerFunc(helloHandler)
    http.ListenAndServe(":8080", handler)
}

2. 미들웨어 패턴이란?

양파 껍질 같은 구조

미들웨어(Middleware)는 요청과 응답 사이에 끼어들어 특정 작업을 수행하는 소프트웨어 컴포넌트입니다. 양파 껍질처럼 여러 겹으로 감싸는 구조를 상상하면 됩니다.

요청 → [로깅] → [인증] → [권한검사] → [실제 처리] → [권한검사] → [인증] → [로깅] → 응답
         ↓        ↓         ↓           ↓           ↑          ↑        ↑         ↑

Go에서의 미들웨어 구현

Go에서 미들웨어는 보통 이런 패턴으로 구현합니다:

// 미들웨어 함수의 기본 형태
func MyMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 1. 요청 전처리 (Before)
        fmt.Println("요청을 받았습니다:", r.URL.Path)

        // 2. 다음 핸들러 호출
        next.ServeHTTP(w, r)

        // 3. 응답 후처리 (After)
        fmt.Println("응답을 보냈습니다")
    })
}

미들웨어 체인 만들기

여러 미들웨어를 연결하는 예제를 보겠습니다:

func LoggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("[로그] %s %s\n", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token == "" {
            w.WriteHeader(http.StatusUnauthorized)
            fmt.Fprintf(w, "인증이 필요합니다")
            return // 여기서 중단! next를 호출하지 않음
        }
        next.ServeHTTP(w, r)
    })
}

func main() {
    // 실제 비즈니스 로직을 처리하는 핸들러
    finalHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "비밀 데이터입니다!")
    })

    // 미들웨어 체인 구성 (역순으로 감싸기)
    handler := LoggingMiddleware(AuthMiddleware(finalHandler))

    http.ListenAndServe(":8080", handler)
}

실행 순서:

  1. LoggingMiddleware가 요청을 받음
  2. 로그를 출력하고 AuthMiddleware 호출
  3. AuthMiddleware가 인증 토큰 확인
  4. 토큰이 있으면 finalHandler 호출
  5. 응답이 역순으로 돌아감

3. Kubernetes API 서버 아키텍처 개요

Kubernetes란?

Kubernetes(쿠버네티스, 줄여서 k8s)는 컨테이너화된 애플리케이션을 자동으로 배포, 확장 및 관리하는 오픈소스 플랫폼입니다.

예를 들어, 온라인 쇼핑몰을 운영한다고 가정해봅시다:

  • 평소에는 서버 3대로 충분하지만
  • 블랙프라이데이에는 30대가 필요할 수 있습니다
  • Kubernetes는 이런 확장/축소를 자동으로 처리합니다

API 서버의 역할

Kubernetes API 서버는 Kubernetes의 모든 구성 요소와 사용자가 통신하는 중앙 허브입니다.

비유하자면:

  • 경찰서의 신고접수대: 모든 요청이 여기를 거칩니다
  • 은행의 금고: 중요한 데이터(etcd)에 대한 접근을 통제합니다
  • 공항의 보안검색대: 모든 요청의 신원과 권한을 확인합니다

API 서버가 처리해야 할 것들

  1. 인증(Authentication): "당신은 누구입니까?"
  2. 인가(Authorization): "당신은 이 작업을 할 권한이 있습니까?"
  3. 입력 검증: "요청이 올바른 형식입니까?"
  4. 감사(Audit): "누가 언제 무엇을 했는지 기록"
  5. 속도 제한: "너무 많은 요청을 보내지 않도록 제한"
  6. 변경 사항 적용: "실제로 요청된 작업 수행"

4. DefaultBuildHandlerChain 함수 분석

이제 본격적으로 Kubernetes API 서버의 핵심인 DefaultBuildHandlerChain 함수를 살펴보겠습니다.

함수의 구조

func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
    handler := apiHandler

    // 여기서부터 역순으로 핸들러를 감쌉니다
    handler = filterlatency.TrackCompleted(handler)
    handler = genericapifilters.WithAuthorization(handler, c.Authorization.Authorizer, c.Serializer)
    handler = filterlatency.TrackStarted(handler, c.TracerProvider, "authorization")

    // ... 더 많은 핸들러들 ...

    return handler
}

왜 역순으로 구성하는가?

코드에서는 아래에서 위로 핸들러를 추가하지만, 실제 실행은 위에서 아래로 됩니다. 이것은 양파 껍질을 만드는 것과 같습니다:

코드 작성 순서:         실제 실행 순서:
3. 인증 추가     →     1. 인증 확인
2. 로깅 추가     →     2. 로그 기록  
1. 핵심 로직     →     3. 핵심 로직 실행

필터 체인의 전체 구조

DefaultBuildHandlerChain은 약 25개의 필터를 순서대로 연결합니다. 주요 필터들을 실행 순서대로 정리하면:

  1. 감사 초기화 (WithAuditInit)
  2. 패닉 복구 (WithPanicRecovery)
  3. 서버 준비 상태 확인 (WithMuxAndDiscoveryComplete)
  4. 요청 시간 기록 (WithRequestReceivedTimestamp)
  5. 요청 정보 파싱 (WithRequestInfo)
  6. 지연 시간 추적 (WithLatencyTrackers)
  7. HTTP 로깅 (WithHTTPLogging)
  8. 캐시 제어 (WithCacheControl)
  9. 타임아웃 설정 (WithTimeoutForNonLongRunningRequests)
  10. CORS 처리 (WithCORS)
  11. 인증 (WithAuthentication)
  12. 감사 로깅 (WithAudit)
  13. 사용자 가장 (WithImpersonation)
  14. 속도 제한 (WithPriorityAndFairness)
  15. 권한 검사 (WithAuthorization)

5. 주요 필터들의 역할과 구현

5.1 요청 정보 파싱 (WithRequestInfo)

모든 처리의 시작점입니다. URL을 분석해서 어떤 리소스에 대한 어떤 작업인지 파악합니다.

func WithRequestInfo(handler http.Handler, resolver request.RequestInfoResolver) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        // URL 분석: /api/v1/namespaces/default/pods/nginx
        // → namespace: default, resource: pods, name: nginx
        info, err := resolver.NewRequestInfo(req)
        if err != nil {
            // 파싱 실패시 500 에러
            responsewriters.InternalError(w, req, err)
            return
        }

        // 파싱된 정보를 Context에 저장
        req = req.WithContext(request.WithRequestInfo(req.Context(), info))
        handler.ServeHTTP(w, req)
    })
}

예시:

  • GET /api/v1/pods → 모든 Pod 조회
  • POST /api/v1/namespaces/prod/deployments → prod 네임스페이스에 Deployment 생성
  • DELETE /api/v1/nodes/worker-1 → worker-1 노드 삭제

5.2 인증 (WithAuthentication)

"당신은 누구입니까?"를 확인하는 단계입니다.

func WithAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler, ...) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        // 다양한 인증 방법 시도 (토큰, 인증서, 등)
        resp, ok, err := auth.AuthenticateRequest(req)

        if err != nil || !ok {
            // 인증 실패 → 실패 핸들러로 처리
            failed.ServeHTTP(w, req)
            return
        }

        // 인증 성공: Authorization 헤더 제거 (보안상)
        req.Header.Del("Authorization")

        // 사용자 정보를 Context에 저장
        req = req.WithContext(genericapirequest.WithUser(req.Context(), resp.User))
        handler.ServeHTTP(w, req)
    })
}

지원하는 인증 방법:

  • Bearer Token: Authorization: Bearer <token>
  • Client Certificate: TLS 클라이언트 인증서
  • Basic Auth: Authorization: Basic <base64(username:password)>
  • Service Account Token: Kubernetes 내부 서비스용

5.3 권한 검사 (WithAuthorization)

"당신은 이 작업을 할 권한이 있습니까?"를 확인합니다.

func WithAuthorization(handler http.Handler, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        // Context에서 요청 정보와 사용자 정보 추출
        attributes, err := GetAuthorizerAttributes(req.Context())
        if err != nil {
            responsewriters.InternalError(w, req, err)
            return
        }

        // 권한 확인
        authorized, reason, err := a.Authorize(req.Context(), attributes)

        if authorized == authorizer.DecisionAllow {
            // 권한 있음 → 계속 진행
            handler.ServeHTTP(w, req)
            return
        }

        // 권한 없음 → 403 Forbidden
        responsewriters.Forbidden(req.Context(), attributes, w, req, reason, s)
    })
}

권한 검사 예시:

  • user1이 namespace1의 Pod를 생성할 수 있는가?
  • serviceaccount1이 모든 Secret을 조회할 수 있는가?
  • admin 그룹이 Node를 삭제할 수 있는가?

5.4 감사 로깅 (WithAudit)

모든 API 호출을 기록합니다. 보안과 디버깅에 필수적입니다.

func WithAudit(handler http.Handler, sink audit.Sink, policy audit.PolicyRuleEvaluator, ...) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        // 감사 이벤트 생성
        ac, err := evaluatePolicyAndCreateAuditEvent(req, policy, sink)

        // ResponseWriter를 감싸서 응답도 기록
        respWriter := &auditResponseWriter{
            ResponseWriter: w,
            event:         ac,
        }

        // 패닉이 발생해도 감사 로그는 남김
        defer func() {
            if r := recover(); r != nil {
                ac.ProcessEventStage(ctx, auditinternal.StagePanic)
                panic(r)  // 다시 패닉 발생
            }
            ac.ProcessEventStage(ctx, auditinternal.StageResponseComplete)
        }()

        handler.ServeHTTP(respWriter, req)
    })
}

감사 로그에 기록되는 정보:

  • 누가 (User)
  • 언제 (Timestamp)
  • 무엇을 (Resource)
  • 어떻게 (Verb: get, create, delete 등)
  • 결과 (성공/실패)
  • 응답 코드

5.5 속도 제한 (WithPriorityAndFairness)

API 서버가 과부하되지 않도록 요청 속도를 제한합니다.

func WithPriorityAndFairness(handler http.Handler, ...) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 요청 분류 (우선순위 결정)
        classification := classifyRequest(r)

        // 대기열에 추가
        queued := fc.QueueRequest(classification)

        if !queued {
            // 대기열이 가득 참 → 429 Too Many Requests
            tooManyRequests(r, w, retryAfter)
            return
        }

        // 순서가 되면 실행
        handler.ServeHTTP(w, r)
    })
}

우선순위 예시:

  • system:masters: 최고 우선순위 (관리자)
  • system:nodes: 높은 우선순위 (노드 하트비트)
  • 일반 사용자: 보통 우선순위
  • 익명 사용자: 낮은 우선순위

5.6 패닉 복구 (WithPanicRecovery)

Go 프로그램에서 panic이 발생하면 프로그램이 종료됩니다. 이를 방지합니다.

func WithPanicRecovery(handler http.Handler, resolver request.RequestInfoResolver) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        defer func() {
            if r := recover(); r != nil {
                // 패닉 발생! 하지만 서버는 계속 동작
                http.Error(w, "Internal Server Error", http.StatusInternalServerError)

                // 스택 트레이스 로깅
                logStackTrace(r)
            }
        }()

        handler.ServeHTTP(w, req)
    })
}

5.7 타임아웃 처리 (WithTimeoutForNonLongRunningRequests)

요청이 너무 오래 걸리지 않도록 제한합니다.

func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning LongRunningCheck) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if longRunning(r) {
            // Watch, Proxy 등은 타임아웃 없음
            handler.ServeHTTP(w, r)
            return
        }

        // 일반 요청: 60초 타임아웃
        ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
        defer cancel()

        done := make(chan bool)
        go func() {
            handler.ServeHTTP(w, r.WithContext(ctx))
            done <- true
        }()

        select {
        case <-done:
            // 정상 완료
        case <-ctx.Done():
            // 타임아웃!
            http.Error(w, "Gateway Timeout", http.StatusGatewayTimeout)
        }
    })
}

6. filterlatency - 성능 추적의 비밀

filterlatency 패키지의 역할

filterlatency 패키지는 각 필터의 실행 시간을 정밀하게 측정합니다. 이는 성능 병목 현상을 찾고 최적화하는 데 필수적입니다.

구현 원리

// TrackStarted: 필터 실행 시작 시점 기록
func TrackStarted(handler http.Handler, tp trace.TracerProvider, name string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // OpenTelemetry span 시작
        ctx, span := tracer.Start(r.Context(), name)
        defer span.End()

        // 시작 시간 기록
        fr := &requestFilterRecord{
            name:             name,
            startedTimestamp: clock.Now(),
        }
        r = r.WithContext(withRequestFilterRecord(ctx, fr))

        handler.ServeHTTP(w, r)
    })
}

// TrackCompleted: 이전 필터의 완료 시점 측정
func TrackCompleted(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 이전 필터가 막 완료된 시점
        completedAt := clock.Now()

        // 다음 핸들러 실행 (defer로 먼저 측정)
        defer handler.ServeHTTP(w, r)

        // 지연시간 계산 및 메트릭 기록
        if fr := requestFilterRecordFrom(r.Context()); fr != nil {
            latency := completedAt.Sub(fr.startedTimestamp)
            metrics.RecordFilterLatency(r.Context(), fr.name, latency)

            // 100ms 이상이면 로그에 기록
            if latency > minFilterLatencyToLog {
                httplog.AddKeyValue(r.Context(), fmt.Sprintf("fl_%s", fr.name), latency.String())
            }
        }
    })
}

측정 패턴 이해하기

// DefaultBuildHandlerChain에서의 사용 예
handler = filterlatency.TrackCompleted(handler)
handler = genericapifilters.WithAuthorization(handler, ...)
handler = filterlatency.TrackStarted(handler, tp, "authorization")

실행 순서:

  1. TrackStarted("authorization") - 시작 시간 기록
  2. TrackCompleted - 이전 필터 완료 시간 측정
  3. WithAuthorization - 실제 인가 처리
  4. 다음 필터로 진행...

이렇게 각 필터를 TrackStartedTrackCompleted로 감싸서 정확한 실행 시간을 측정합니다.

7. 실제 요청 처리 흐름 따라가기

예시: Pod 생성 요청

사용자가 nginx Pod를 생성하는 요청을 보낸다고 가정해봅시다:

kubectl create -f nginx-pod.yaml

이 명령은 다음과 같은 HTTP 요청으로 변환됩니다:

POST /api/v1/namespaces/default/pods
Authorization: Bearer <token>
Content-Type: application/json

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": "nginx"
  },
  "spec": {
    "containers": [{
      "name": "nginx",
      "image": "nginx:latest"
    }]
  }
}

단계별 처리 과정

1단계: WithAuditInit

[감사 초기화] 새로운 감사 이벤트 ID 생성: audit-12345

2단계: WithPanicRecovery

[패닉 복구] 준비 완료. 이후 패닉 발생시 복구 예정

3단계: WithRequestReceivedTimestamp

[시간 기록] 요청 수신 시각: 2024-01-15 10:30:45.123

4단계: WithRequestInfo

[요청 파싱] 
- Verb: create
- Resource: pods
- Namespace: default
- APIVersion: v1

5단계: WithHTTPLogging

[HTTP 로그] POST /api/v1/namespaces/default/pods (from 192.168.1.100)

6단계: WithAuthentication

[인증] Bearer 토큰 확인...
[인증] 사용자 확인됨: user1 (groups: [developers])

7단계: WithAudit (요청 단계)

[감사] RequestReceived 단계 기록
- User: user1
- Verb: create
- Resource: pods
- Namespace: default

8단계: WithImpersonation

[사용자 가장] 가장 요청 없음. 원래 사용자로 진행

9단계: WithPriorityAndFairness

[속도 제한] 요청 분류: workload-low (일반 사용자)
[속도 제한] 대기열 위치: 3번째
[속도 제한] 예상 대기 시간: 50ms
... 50ms 후 ...
[속도 제한] 처리 시작

10단계: WithAuthorization

[권한 검사] user1이 default 네임스페이스에 pods를 create할 수 있는가?
[권한 검사] RBAC 규칙 확인 중...
[권한 검사] 허용됨 (Role: pod-creator)

11단계: 실제 API 처리

[API 핸들러] Pod 생성 시작
[API 핸들러] 유효성 검사 통과
[API 핸들러] etcd에 저장
[API 핸들러] Pod 생성 완료: nginx

응답 단계 (역순으로)

[감사] ResponseComplete 단계 기록 (StatusCode: 201)
[지연시간] authorization: 5ms
[지연시간] audit: 2ms
[지연시간] authentication: 10ms
[지연시간] 전체: 120ms

최종 응답

HTTP/1.1 201 Created
Content-Type: application/json
Audit-ID: audit-12345

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": "nginx",
    "namespace": "default",
    "uid": "550e8400-e29b-41d4-a716-446655440000",
    "creationTimestamp": "2024-01-15T10:30:45Z"
  },
  "spec": { ... },
  "status": {
    "phase": "Pending"
  }
}

에러 시나리오

인증 실패 시:

[인증] Bearer 토큰 확인...
[인증] 토큰이 만료됨
[감사] 인증 실패 기록
→ HTTP 401 Unauthorized

권한 부족 시:

[권한 검사] user2가 kube-system 네임스페이스에 pods를 create할 수 있는가?
[권한 검사] 거부됨 (권한 없음)
[감사] 권한 거부 기록
→ HTTP 403 Forbidden

속도 제한 시:

[속도 제한] 대기열이 가득 참 (최대: 100)
→ HTTP 429 Too Many Requests
→ Retry-After: 5 (5초 후 재시도)

필터 체인의 실행 흐름 다이어그램

클라이언트 요청
    │
    ▼
┌─────────────────────────┐
│   WithAuditInit         │ ← 감사 이벤트 초기화
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   WithPanicRecovery     │ ← 패닉 복구 준비
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   WithRequestInfo       │ ← URL 파싱, 리소스 정보 추출
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   TrackStarted          │ ← "authentication" 시작 시간 기록
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   TrackCompleted        │ ← 이전 필터 완료 시간 측정
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   WithAuthentication    │ ← 사용자 인증
└─────────────────────────┘
    │ (인증 실패시 401 반환)
    ▼
┌─────────────────────────┐
│   TrackStarted          │ ← "authorization" 시작
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   TrackCompleted        │ ← "authentication" 완료 시간 측정
└─────────────────────────┘
    │
    ▼
┌─────────────────────────┐
│   WithAuthorization     │ ← 권한 검사
└─────────────────────────┘
    │ (권한 없으면 403 반환)
    ▼
┌─────────────────────────┐
│   API Handler           │ ← 실제 비즈니스 로직
└─────────────────────────┘
    │
    ▼
   응답 반환

8. 마치며

핵심 정리

Kubernetes API 서버의 요청 처리 파이프라인은:

  1. 계층적 구조: 각 필터가 특정 책임을 가지고 독립적으로 동작
  2. 조기 종료: 문제가 발견되면 즉시 중단하여 리소스 절약
  3. 포괄적 로깅: 모든 단계가 추적되어 디버깅과 보안 감사 가능
  4. 확장 가능: 새로운 필터를 쉽게 추가 가능

이런 복잡한 구조가 필요한 이유

  1. 보안: 여러 단계의 검증으로 안전성 확보
  2. 안정성: 패닉 복구, 타임아웃 등으로 서버 안정성 보장
  3. 성능: 속도 제한과 우선순위로 과부하 방지
  4. 관찰 가능성: 상세한 로깅과 메트릭으로 문제 추적 용이

DefaultBuildHandlerChain의 설계 철학

  1. 관심사의 분리: 각 필터는 하나의 책임만 가짐
  2. 조합 가능성: 필터들을 자유롭게 조합하고 순서 변경 가능
  3. 투명성: 각 단계의 성능과 동작을 측정 가능
  4. 실패 격리: 한 필터의 실패가 전체 시스템을 중단시키지 않음

실무에서의 시사점

이러한 설계 패턴은 Kubernetes뿐만 아니라 다른 시스템에서도 활용할 수 있습니다:

  • 마이크로서비스 API 게이트웨이
  • 엔터프라이즈 애플리케이션 서버
  • IoT 플랫폼의 디바이스 관리 시스템
  • 금융 거래 시스템의 요청 처리

더 알아보기

  • Go의 미들웨어 패턴에 대해 더 깊이 공부하고 싶다면 net/http 패키지 문서를 참고하세요
  • Kubernetes의 RBAC(역할 기반 접근 제어)에 대해 알아보면 권한 시스템을 더 잘 이해할 수 있습니다
  • OpenTelemetry를 통한 분산 추적에 대해 공부하면 filterlatency 패키지의 역할을 더 잘 이해할 수 있습니다

이 글이 Kubernetes API 서버의 내부 동작을 이해하는 데 도움이 되었기를 바랍니다!