Post

EKS kubectl 토큰 캐싱으로 응답 속도 개선하기

EKS kubectl 토큰 캐싱으로 응답 속도 개선하기

On-Premise와 연결된 Kubernetes Cluster를 사용하는 것과 EKS 환경에서 kubectl 명령어를 실행할 때 체감되는 지연 시간에 차이가 있어, aws eks update-kubeconfig로 가져온 클러스터 인증 정보를 통해 kubectl에 EKS Cluster에 접근하는 방법에 대해 알아봤습니다.
해당 지연 문제는 여러 클러스터를 오가며 작업하거나, 스크립트에서 kubectl을 반복 호출할 때 더욱 두드러지게 되며 이로 인해 소중한 시간을 빼앗기게 됩니다.
이번 포스트에서는 이 문제의 원인을 파악하고, 토큰 캐싱 스크립트를 통해 해결하는 방법을 다뤄보겠습니다.


1. 문제 상황

1.1. kubeconfig exec 인증 방식

EKS 클러스터에 접근하기 위해 aws eks update-kubeconfig 명령으로 kubeconfig를 설정하면, 다음과 같은 exec 인증 방식이 구성됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
users:
  - name: arn:aws:eks:ap-northeast-2:123456789012:cluster/my-cluster
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: aws
        args:
          - eks
          - get-token
          - --cluster-name
          - my-cluster
          - --region
          - ap-northeast-2

이 설정은 kubectl 명령을 실행할 때마다 aws eks get-token을 호출하여 Bearer 토큰을 발급받습니다.

1.2. 발생하는 문제점

매번 토큰을 새로 발급받는 방식은 다음과 같은 문제를 야기합니다.

문제설명
응답 지연명령어마다 500ms~2초 이상의 추가 지연 발생
네트워크 의존성네트워크 불안정 시 타임아웃으로 명령 실패
API 호출 급증스크립트에서 kubectl 반복 호출 시 AWS API 호출량 급증
Rate Limiting 위험대량 호출 시 AWS API Rate Limit에 도달할 가능성

실제로 간단한 kubectl get nodes 명령도 토큰 발급 시간이 포함되어 체감 속도가 느려집니다.

1
2
3
4
5
6
7
8
# 토큰 발급 시간 포함time kubectl get nodes
NAME                                              STATUS   ROLES    AGE   VERSION
ip-10-0-1-100.ap-northeast-2.compute.internal     Ready    <none>   5h    v1.33.0-eks

real    0m1.847s
user    0m0.523s
sys     0m0.089s

2. 해결 방안 - 토큰 캐싱 전략

2.1. 핵심 아이디어

EKS 토큰은 발급 후 15분간 유효합니다. 이 특성을 활용하면 다음과 같은 캐싱 전략을 적용할 수 있습니다.

  1. 토큰을 파일에 캐싱
  2. kubectl 호출 시 캐시된 토큰의 유효성 확인
  3. 유효하면 캐시 사용, 만료 임박 시 새로 발급
  4. 만료 60초 전에 미리 갱신하여 안전 마진 확보

2.2. 토큰 구조

aws eks get-token 명령의 출력은 다음과 같은 JSON 구조입니다.

1
2
3
4
5
6
7
8
9
{
  "kind": "ExecCredential",
  "apiVersion": "client.authentication.k8s.io/v1beta1",
  "spec": {},
  "status": {
    "expirationTimestamp": "2026-01-30T12:15:00Z",
    "token": "k8s-aws-v1.aHR0cHM6Ly9zdHMuYX..."
  }
}

status.expirationTimestamp 필드를 파싱하여 토큰 만료 시간을 확인할 수 있습니다.


3. 토큰 캐싱 스크립트

3.1. 스크립트 전체 코드

다음 스크립트를 ~/.kube/eks-token-cache.sh로 저장합니다.

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/bin/bash
set -euo pipefail

# 사용법: eks-token-cache.sh <cluster-name> <region> [profile]
CLUSTER_NAME="${1:?cluster name required}"
REGION="${2:?region required}"
PROFILE="${3:-default}"

# 캐시 디렉토리 설정
CACHE_DIR="${HOME}/.kube/eks-token-cache"
mkdir -p "$CACHE_DIR"
chmod 700 "$CACHE_DIR"

# 캐시 파일명: 클러스터명 + 프로파일 조합으로 고유 키 생성
CACHE_KEY="${CLUSTER_NAME}_${PROFILE}"
CACHE_FILE="${CACHE_DIR}/${CACHE_KEY}.json"

# Safety Margin: 만료 60초 전에 갱신
SAFETY_MARGIN=60

# 디버그 모드 (EKS_TOKEN_DEBUG=1 설정 시 활성화)
debug() {
    if [[ "${EKS_TOKEN_DEBUG:-0}" == "1" ]]; then
        echo "[DEBUG] $*" >&2
    fi
}

# 현재 시간을 Unix timestamp로 반환 (macOS/Linux 호환)
get_current_timestamp() {
    if [[ "$(uname)" == "Darwin" ]]; then
        date +%s
    else
        date +%s
    fi
}

# ISO 8601 시간을 Unix timestamp로 변환 (macOS/Linux 호환)
parse_timestamp() {
    local iso_time="$1"
    if [[ "$(uname)" == "Darwin" ]]; then
        # macOS: GNU date가 없으면 Python 사용
        if command -v gdate &>/dev/null; then
            gdate -d "$iso_time" +%s
        else
            python3 -c "from datetime import datetime; print(int(datetime.fromisoformat('${iso_time}'.replace('Z', '+00:00')).timestamp()))"
        fi
    else
        # Linux
        date -d "$iso_time" +%s
    fi
}

# 캐시 유효성 검증
is_cache_valid() {
    if [[ ! -f "$CACHE_FILE" ]]; then
        debug "Cache file not found"
        return 1
    fi

    # jq로 expirationTimestamp 추출
    local exp_time
    exp_time=$(jq -r '.status.expirationTimestamp // empty' "$CACHE_FILE" 2>/dev/null)

    if [[ -z "$exp_time" ]]; then
        debug "Invalid cache format"
        return 1
    fi

    local exp_ts current_ts
    exp_ts=$(parse_timestamp "$exp_time")
    current_ts=$(get_current_timestamp)

    # 만료 시간에서 Safety Margin을 뺀 값과 현재 시간 비교
    local valid_until=$((exp_ts - SAFETY_MARGIN))

    if [[ $current_ts -lt $valid_until ]]; then
        local remaining=$((valid_until - current_ts))
        debug "Cache valid, ${remaining}s remaining"
        return 0
    else
        debug "Cache expired or expiring soon"
        return 1
    fi
}

# 새 토큰 발급 및 캐싱
refresh_token() {
    debug "Fetching new token from AWS"
    local token_json

    if [[ "$PROFILE" == "default" ]]; then
        token_json=$(aws eks get-token --cluster-name "$CLUSTER_NAME" --region "$REGION")
    else
        token_json=$(aws eks get-token --cluster-name "$CLUSTER_NAME" --region "$REGION" --profile "$PROFILE")
    fi

    echo "$token_json" > "$CACHE_FILE"
    chmod 600 "$CACHE_FILE"
    echo "$token_json"
}

# 메인 로직
main() {
    if is_cache_valid; then
        debug "Using cached token"
        cat "$CACHE_FILE"
    else
        refresh_token
    fi
}

main

3.2. 스크립트 주요 구성 요소

구성 요소설명
인자 처리클러스터명(필수), 리전(필수), AWS 프로파일(선택)
캐시 키 생성클러스터명_프로파일 조합으로 고유한 캐시 파일 생성
유효성 검증jq로 expirationTimestamp 파싱 후 현재 시간과 비교
Safety Margin만료 60초 전 자동 갱신으로 토큰 만료 방지
macOS/Linux 호환시간 파싱 시 OS별 분기 처리
디버그 모드EKS_TOKEN_DEBUG=1 환경변수로 상세 로그 출력

4. 적용 방법

4.1. 스크립트 설치

1
2
3
4
5
6
7
8
9
10
11
12
# 스크립트 저장
mkdir -p ~/.kube
cat > ~/.kube/eks-token-cache.sh << 'EOF'
# 위 스크립트 내용 붙여넣기
EOF

# 실행 권한 부여
chmod +x ~/.kube/eks-token-cache.sh

# jq 설치 확인 (필수 의존성)
which jq || brew install jq  # macOS
# which jq || sudo apt install jq  # Ubuntu/Debian

4.2. kubeconfig 수정

기존 kubeconfig의 exec 설정을 캐싱 스크립트로 변경합니다.

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
# 변경 전 (기본 exec)
users:
- name: arn:aws:eks:ap-northeast-2:123456789012:cluster/my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: aws
      args:
        - eks
        - get-token
        - --cluster-name
        - my-cluster
        - --region
        - ap-northeast-2

# 변경 후 (캐싱 적용)
users:
- name: arn:aws:eks:ap-northeast-2:123456789012:cluster/my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: /Users/username/.kube/eks-token-cache.sh
      args:
        - my-cluster
        - ap-northeast-2
        - default  # AWS 프로파일 (선택)
      interactiveMode: Never

interactiveMode: Never를 추가하면 토큰 발급 시 프롬프트가 표시되지 않습니다.


5. 성능 비교

5.1. 캐싱 전후 응답 시간 비교

캐싱 적용 전 (매번 토큰 발급)

1
2
3
4
5
6
7
time kubectl get nodes
NAME                                              STATUS   ROLES    AGE   VERSION
ip-10-0-1-100.ap-northeast-2.compute.internal     Ready    <none>   5h    v1.33.0-eks

real    0m1.847s
user    0m0.523s
sys     0m0.089s

캐싱 적용 후 (캐시 히트)

1
2
3
4
5
6
7
time kubectl get nodes
NAME                                              STATUS   ROLES    AGE   VERSION
ip-10-0-1-100.ap-northeast-2.compute.internal     Ready    <none>   5h    v1.33.0-eks

real    0m0.312s
user    0m0.098s
sys     0m0.045s

약 83% 응답 시간 감소 (1.847s → 0.312s)

5.2. 디버그 모드로 동작 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 디버그 모드 활성화
export EKS_TOKEN_DEBUG=1

# 첫 번째 호출 (캐시 미스 → 새 토큰 발급)
❯ kubectl get nodes
[DEBUG] Cache file not found
[DEBUG] Fetching new token from AWS
NAME                                              STATUS   ROLES    AGE   VERSION
...

# 두 번째 호출 (캐시 히트)
❯ kubectl get nodes
[DEBUG] Cache valid, 847s remaining
[DEBUG] Using cached token
NAME                                              STATUS   ROLES    AGE   VERSION
...

6. 주의사항 및 팁

6.1. 의존성

  • jq: JSON 파싱을 위해 필수로 설치되어 있어야 합니다
  • Python3: macOS에서 GNU date가 없는 경우 시간 파싱에 사용됩니다

6.2. 보안

  • 캐시 디렉토리는 700 권한으로 생성되어 소유자만 접근 가능합니다
  • 캐시 파일은 600 권한으로 저장됩니다
  • 토큰은 15분간만 유효하므로 유출되어도 피해가 제한적입니다

6.3. 멀티 클러스터 / 멀티 프로파일

  • 클러스터명과 프로파일 조합으로 캐시 키가 생성되어 충돌이 발생하지 않습니다
  • 여러 클러스터를 오가며 작업해도 각각 독립적으로 캐싱됩니다
1
2
3
4
5
# 캐시 파일 확인ls ~/.kube/eks-token-cache/
my-cluster_default.json
prod-cluster_prod-profile.json
staging-cluster_default.json

6.4. 캐시 강제 갱신

토큰을 강제로 갱신하려면 캐시 파일을 삭제하면 됩니다.

1
2
3
4
5
# 특정 클러스터 캐시 삭제
rm ~/.kube/eks-token-cache/my-cluster_default.json

# 전체 캐시 삭제
rm -rf ~/.kube/eks-token-cache/

7. Reference


궁금하신 점이나 추가해야 할 부분은 댓글이나 아래의 링크를 통해 문의해주세요.
Written with KKamJi

This post is licensed under CC BY 4.0 by the author.