(初日くらい少しは実のある記事を書きたい)
前置きが少し長くなったのでせっかちな人は実装のとこまで飛ばしてください
前置き
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の一部が
- 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
以下の内容が返ってきています
{
"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する、という方法にします
実装
ざっくりで!
#!/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
- 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
この部分を、以下のように変更します
- 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を誤ってキャッシュしてしまうと期限切れまで延々それを使おうとするなどちょっとした課題もありますが、そっとファイルを消してください
その他不具合があったらごめんなさい