この記事はAWS CDK Advent Calendar 2022を後から埋めています。
はじめに
CDKのConstrunctsを利用してEKS Clusterを起動する方法は、今までこんな設定が最小だったのですが、
// provisiong a cluster
const cluster = new eks.Cluster(this, 'hello-eks', {
version: eks.KubernetesVersion.V1_21,
});
2022/10/28(=CDK v2.48.0)以降のQuickStartでは、下のように外部モジュールをインポートしてkubectlLayer
を指定する方式となっています。
- v2.55.1現在ではv1.24相当の記述に置き換わっていますが、Optionやモジュールのインポート方法は同様です。
import { KubectlV22Layer } from '@aws-cdk/lambda-layer-kubectl-v22';
// provisiong a cluster
const cluster = new eks.Cluster(this, 'hello-eks', {
version: eks.KubernetesVersion.V1_22,
kubectlLayer: new KubectlV22Layer(this, 'kubectl'),
});
今回はこのアップデートの裏にある
-
kubectlLayer
とは何か?eks.Cluster
に必須なのか? - どうして2021.XXリリースのEKS v.1.22が2022.11まで指定できなかったか
という2点について把握している範囲でご紹介していきます。
1. kubectlLayer
とは何か?
唐突ですが、AWS Lambdaには、複数のFunction間で外部ライブラリ、独自モジュールなどを共有することを主な目的とする、Lambda Layers
という機能があります。
kubectlLayer
はKubernetesクラスターを制御する標準のコマンドラインツールであるkubectl
と、Kubernetesのパッケージマネージャーであるhelm
をLambda Layersで用いるためにプリセットされた、CDK独自のクラスです。
とはいえ、この説明では、「LambdaからK8s(EKS)を操作するための仕組みが、どうしてEKS Clusterの構築に必要なのか」という点がわかりません。もう少し掘り下げてみましょう。
2 eks.Cluster
に必須なのか?
CDKでは下記のように「EKS Clusterのみ」を作成する場合は、kubectlLayerの設定なしでも構築が成功します。
const vpc = new ec2.Vpc(this, 'vpc', {
natGateways: 0,
})
const cluster = new eks.Cluster(this, 'Cluster',{
version: eks.KubernetesVersion.V1_24,
// kubectlLayer: new KubectlV24Layer(this, 'kubectl'),
})
構築の際、暗黙的にKubectlLayer入りのLambdaも展開されます。ちなみにkubectlLayerをコメントアウトしているので、この場合はDefault値のKubectl(v1.20)が設定されます。
このリソースはどんな場合に利用されるのでしょうか?
例えばCDKでは上述のクラスター定義に加えて、以下のような定義もできます。
// apply a kubernetes manifest to the cluster
cluster.addManifest('mypod', {
apiVersion: 'v1',
kind: 'Pod',
metadata: { name: 'mypod' },
spec: {
containers: [
{
name: 'hello',
image: 'paulbouwer/hello-kubernetes:1.5',
ports: [ { containerPort: 8080 } ],
},
],
},
});
これは、CDKで表現したコードを元にAWSのAPIでなく、EKS Clusterが持つAPI(kube-apiserver)へアクセスし、設定を更新するという意味になります。
今回はCDKで表現したManifestをクラスターへ適応させるものでしたが、本例に限らずEKS ClusterにおいてKubernetes固有のエコシステムを用いた設定を行う場合は、AWSのAPIでなくKubernetesクラスターのAPI経由での設定が必要です。したがってCDKで定義できる一部の設定作業に必要なkubectlを導入するためのKubectlLayerと、その実行基盤であるLambdaが、EKS Clusterの設定用にデプロイされているわけです。
ちなみにimportした外部モジュールをkubectlLayerとして明示的に指定する作法はv1.22からですが、その前バージョンであるv1.21は2023.2にEOL予定です。
すなわち、本ブログの公開日時2022/12/22から2か月後には、このkubectlLayerを指定する仕様への対応が必須になります。どうして唐突にこんな仕様になったのか?と次の疑問が湧いてきます。
3. EKS v1.22が指定できていなかったわけ
そもそも2022/4/4に登場したv1.22をCDKが半年近く扱えていなかった理由は何なのでしょうか。この問いについてはこちらのIssueが参考になります。
- KubectlはVersionを持ち、前後1つ違うVersionのKubernetes Clusterに対応している。
- 標準の
lambda-layer-kubectl
はkubectl v1.20が組み込まれており、k8s v1.19~1.21までに対応されている。
- 標準の
- 一方でAWS CDKとしてパッケージのサイズを減らす取り組みをしており、標準モジュールとしてkubectl v1.22をバンドルすることがためらわれていた。
- このため今後の対応も含めて、以下の課題を解決する方針を検討しなくてはならない。
-
lambda-layer-kubectl
にkubectl v1.22を導入する=CDKとしてのパッケージサイズを肥大化させるので難しい - kubectl v1.22に対応しないままEKS v1.22へ対応する=Kubectl+Lambdaを前提とした、CDKでのEKS Cluster管理ができなくなる破壊的変更となってしまう。
- CDK v2からは原則、破壊的変更は避ける開発方針。
-
そんなこんなで2022/5月から水面下での検討が続いていた様子ですが、ここでEKSのライフサイクルを思い出してみましょう。
- Release: v1.22: 2022/4, v.1.23: 2022/8, v1.24: 2022/11
- EOL: v 1.19: 2022/8, v 1.20: 2022/11
つまり2022/8のとある時点では、CDKにおけるEKS Clusterはv 1.20 or v1.21しか扱えない状況だったのです。このまま11月を迎えるとv1.21しか使えなくなる、そもそもこんな状況で今後EKSを扱うチームはCDKを扱うのはかなり厳しくなるんじゃないか、というコメントが殺到しました。(まあ当然かと……)
4、現在の状況
それを受けて、というわけかどうかは定かではありませんが、v1.20がEOLになるギリギリ直前の10月末に、v1.22がリリースできるアップデートが入りました。これが冒頭で紹介したCDK v2.48.0です。
これがきっかけで、
-
KubectlLayer部分は外部モジュールとして、以下に切り出されました。
https://github.com/cdklabs/awscdk-asset-kubectl -
KubectlLayerを明示的に指定するのがほぼ必須となりました。
というのが本件の顛末です。CDK v2.54時点ではEKS v1.24まで対応しており、しばらくは安心してEKSをCDK管理できるようになりました。めでたしめでたし。
この状況が解決するまでは静観していた、Amazon EKS Blueprints for CDKもそろそろ触ってみようかなと思っています。
おわりに
CDKユーザとしては、とりあえず以下を意識しておくと良さそうです。
- EKSを管理する際は今後もCDKを利用できそう。ただし、外部モジュールがほぼ必須。
- 更新状況は要注意。Kubectlは1バージョン違いまでなら吸収できるので、万が一、EKS v1.25がすぐにリリースされなくても、しばらくはこんな記述で許容可能。