[EKS] kubectlを高速化する

（初日くらい少しは実のある記事を書きたい）

前置きが少し長くなったのでせっかちな人は実装のとこまで飛ばしてください

# 前置き

AWSのmanaged kubernetesサービス、EKS
kubernetes運用経験がある人がEKSを触ると

kubectlが遅い…

割と皆さん感じてるかと思います
私は入力補完の遅さで特にストレスを感じていました

この遅さの理由はEKSのクラスタ認証にあって
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/managing-auth.html

クラスタにアクセスするためには、まずAWSにそのためのtokenを発行してもらう必要があるからです

ほとんどの人は、eksクラスタにアクセスするためのkubeconfigを作成する際に
`aws eks update-kubeconfig`
このコマンドを利用しているかと思います
そうすると出来上がるkubeconfigの一部が

```yaml
- name: my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - my-cluster
      command: aws
      env:
      - name: AWS_PROFILE
        value: my-profile
      provideClusterInfo: false
```

このような形になっているはずです
これはつまり、kubectlの認証に、 `aws eks get-token` を使用しているということで、kubectlコマンドを実行するごとに（入力補完の一部にも）このget-tokenを実行しているということです
そしてこのget-tokenはkubectlの実行より時間がかかっています（体感調べ）

# 高速化を試みる

で、この `aws eks get-token` 以下の内容が返ってきています

```json
{
  "kind": "ExecCredential",
  "apiVersion": "client.authentication.k8s.io/v1alpha1",
  "spec": {},
  "status": {
    "expirationTimestamp": "2021-12-02T17:05:31Z",
    "token": "**************************************************"
  }
}
```

`expirationTimestamp` がおよそ15分後に設定されているのがわかります
どうやらこのtokenは15分有効らしいです
なので、kubectlするごとにget-tokenしなくても、1回get-tokenしたらその後15分間はこのtokenを使えばよさそう

今回はこのtokenをファイルに保存して、kubectl実行時にtokenの期限までn秒を切っていたら再びget-tokenする、という方法にします

# 実装

ざっくりで！

```bash
#!/bin/bash
# 引数
# p : aws profile
# c : cluster name

# jq使わせてくださいすいません
if ! type jq >/dev/null; then
    echo "sorry, plz install jq ;)"
    exit 1
fi

CACHE_DIR=~/.kube/cache # tokenファイルを保存するディレクトリ（お好きな場所で）
AWS_REGION=ap-northeast-1 # 雑に固定
REORDER_BEFORE=60 # キャッシュの有効期限がこの秒を割ると再取得する

while getopts c:p: OPT
do
    case $OPT in
        c) CLUSTER_NAME=$OPTARG ;;
        p) AWS_PROFILE=$OPTARG ;;
    esac
done

if [ -z ${CLUSTER_NAME} ] || [ -z ${AWS_PROFILE} ]; then
    echo "reqired args -c [cluster-name] -p [aws-profile]"
    exit 1
fi

if [ ! -d ${CACHE_DIR} ]; then
    mkdir -p ${CACHE_DIR}
fi

CACHE_FILE=${CACHE_DIR}/${AWS_PROFILE}:${CLUSTER_NAME} # [profile名]:[クラスタ名] という形で保存（お好きな形で）
if [ -e ${CACHE_FILE} ]; then
    # 以下のdateコマンドが絡むものはbsdのdateでのみ有効なので
    # linuxや、macでもgdateとかにエイリアス貼ってる場合はコメントをヒントにしていい感じに
    # 他にもTZとか環境によっては変更する必要があるかも
    NOW_UNIX=$(date -j -f %Y-%m-%dT%H:%M:%SZ $(date -u +%Y-%m-%dT%H:%M:%SZ) +%s) # 現在時刻のunixtimeを取得
    EXPIRE=`cat ${CACHE_FILE} | jq -r '.status.expirationTimestamp'` # キャッシュファイルから有効期限を取得
    EXPIRE_UNIX=`date -j -f "%Y-%m-%dT%H:%M:%SZ" ${EXPIRE} +%s` # 有効期限をunixtimeに変換
    
    CACHE_TTL=`expr ${EXPIRE_UNIX} - ${NOW_UNIX}`
    
    if [ ${CACHE_TTL} -lt ${REORDER_BEFORE} ]; then
        aws eks get-token --cluster=${CLUSTER_NAME} --profile=${AWS_PROFILE} --region=${AWS_REGION} >${CACHE_FILE}
    fi
else
    aws eks get-token --cluster=${CLUSTER_NAME} --profile=${AWS_PROFILE} --region=${AWS_REGION} >${CACHE_FILE}
fi

cat ${CACHE_FILE}

```

このようなシェルスクリプトを作成し、実行権限を付与してパスの通る場所に置きます
今回は、 `eks-get-token-use-cache` とします

作ったら、先程のkubeconfig

```yaml
- name: my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - my-cluster
      command: aws
      env:
      - name: AWS_PROFILE
        value: my-profile
      provideClusterInfo: false
```

この部分を、以下のように変更します

```yaml
- name: my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - -p
      - my-profile
      - -c
      - my-cluster
      command: eks-get-token-use-cache
      provideClusterInfo: false
```

ここまで設定すれば、kubectl実行時にtokenのキャッシュファイルを作成し、期限切れ直前に更新する、という動きになります
当然ですが、tokenを更新する時だけは遅いままです

# その後

人間というのは贅沢なもので、これに慣れると今度は約15分に1回訪れる更新が気になってしまいます
なのでこの15分を伸ばしてやろうと思い、色々調べてみたのですが現状では無理みたいです
https://github.com/aws/aws-sdk-go/issues/2167
ので、そこだけは耐えましょう
ちなみに、 `aws eks get-token` ができるまでは `aws-iam-authenticator` というものが使われていたのですが、こっちのほうが少し速いので（環境差あるかも？）、そっちを使えば更新も少し速くなります

あとは、無効なtokenを誤ってキャッシュしてしまうと期限切れまで延々それを使おうとするなどちょっとした課題もありますが、そっとファイルを消してください
その他不具合があったらごめんなさい