(追記)
この記事はEKSでのARMインスタンスサポートがパブリックプレビューだったころに書かれたもので、すでにARMインスタンスサポートはGAとなっています。
eksctlなどによるサポートも行われており、基本的に特別なことはなく、通常のAMD64クラスタへの追加もeksctlを使ってできます。
なので今後この記事を参考にする必要はありません。
はじめに
Amazon EKS(Elastic Kubernetes Service)はAWSが提供するマネージドKubernetesサービスです。
ワーカーノードとしてEC2インスタンスを割り当てるアンマネージドNodeGroupと、AWS側でそれを管理するマネージドNodeGroup、サーバレスコンピューティングエンジンのFargateをワーカノードとして利用するNodeGroupが選択できます。
また、Amazon EC2ではARM64プロセッサを搭載したA1インスタンスが利用できます。
そこでAmazon EKSのアンマネージドNodeGroupにA1インスタンスを追加すればARMプロセッサをEKSクラスタから利用できるのでは?と考えました。
本記事は実際にそれを行うための環境が整ったため、実験してみた記録です。
投稿時点ではTry & Errorで試してみただけの段階のため、詳細は一部割愛しています。今後、追加検証を行って手順の詳細を追加するかもしれません。
前提情報
「はじめに」にだけを読むと簡単にできそうですが、実際にはそこまで簡単ではありません。
実際、AWSはEKSでのArmサポート(パブリックプレビュー)を2019年4月に公表しており、それに関するユーザーガイドを提供していますが、その中に考慮事項として以下が挙げられています:
- ワーカーノードは任意の A1 インスタンスタイプにできますが、すべてのワーカーノードは A1 インスタンスタイプである必要があります。
- ワーカーノードは、Kubernetes バージョン 1.13 または 1.14 でデプロイする必要があります。
- 今回の実験では1.14を使用しますが、新しくサポートされた1.15にも対応していると思われます。
- A1 インスタンスワーカーノードを使用するには、新しい Amazon EKS クラスターをセットアップする必要があります。既存のワーカーノードがあるクラスターにワーカーノードを追加することはできません。
しかし、ユーザーガイドを読んだ限りでは1つめと3つめは技術的困難さがあるというよりも単に「当該ユーザーガイドの手順には含まれていない」というだけで、実際には可能と思われるので実験を行います。
tl; dr
要するにCNIとkube-proxyを実行するDaemonSetをAMD64 Node用とARM64 Node用とで用意してやる必要があります。AMD64 NodeとARM64 Nodeの用意するインスタンス数によってはCoreDNSのDeploymentもARM64 Node用を用意してもいいかもしれません。
あと疎通のためSecurityGroupの設定が追加で必要になるかもしれません。
EKSクラスタの作成
eksctlコマンドで。今回はCoreDNSを修正しないのでAMD64 NodeGroupとして1つはインスタンスを追加しておく必要があります。
ARM64 Node用kube-proxy/aws-node DaemonSetの作成
既存のkube-proxy/aws-node をAMD64 Nodeのみに制限
nodeAffinityを追加して、AMD64 NodeにのみPodを配置するよう変更します。
なお、NodeのCPUアーキテクチャの判別にはNodeのLabelを用いますが、実験時は kubernetes.io/arch
と beta.kubernetes.io/arch
の2種類のラベルが混在していました。 Nodeにはどちらも設定されているのでどちらを使っても問題ありませんが、そろえておくほうがよいでしょう。
ARM64 Node用kube-proxy/aws-node を作成
ユーザガイドに従って作成するが、マニフェストを直接適用せずにダウンロードし、変更して適用します。また、CoreDNSの変更は行いません。
DaemonSetにnodeAffinityを追加してPodがARM64 Nodeにのみ配置されるよう変更します。
A1インスタンスでアンマネージドNodeGroupの起動
ユーザガイドに従ってNodeGroupを起動します。
A1インスタンスNodeGroupをクラスタに結合
ユーザガイドにならって aws-auth
ConfigMapを編集します
。
すでにクラスタ内にConfigMapが設定されているはずなのでそれを取得して編集します。
次のように変更します:
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::012345678901:role/eksctl-yourclustername-nodegroup-NodeInstanceRole-ABCDEFGHIJKL
username: system:node:{{EC2PrivateDNSName}}
+ - groups:
+ - system:bootstrappers
+ - system:nodes
+ rolearn: arn:aws:iam::012345678901:role/eksctl-yourclustername-nodegroup-NodeInstanceRole-MNOPQRSTUVWX
+ username: system:node:{{EC2PrivateDNSName}}
mapUsers: |
[]
kind: ConfigMap
metadata:
creationTimestamp: "2020-01-01T00:00:00Z"
name: aws-auth
namespace: kube-system
resourceVersion: "0"
selfLink: /api/v1/namespaces/kube-system/configmaps/aws-auth
uid: 01234567-89ab-cdef-0123-456789abcdef
ここで rolearn
フィールドの arn:aws:iam::012345678901:role/eksctl-yourclustername-nodegroup-NodeInstanceRole-MNOPQRSTUVWX
は <インスタンスのロールの ARN (インスタンスプロファイルではない)>
の値で置き換えます。
SecurityGroupの設定
aws-auth
ConfigMapを適用してしばらくするとARM64 NodeGroupがEKS上のNodeとして見えるようになります。
ただこれだけではARM64 NodeとAMD64 Node間での通信ができません。これはSecurityGroupの設定が不十分なためと考えられます。
aws
コマンドやAWSのWebコンソールでAMD64 NodeGroupのNodeとして動作しているEC2インスタンスのSecurityGroupを確認すると、おそらく SharedNodeSecurityGroup
という文言を含む SecurityGroupが見つかると思います。
当該のSecurityGroupをA1 NodeGroupのインスタンスに追加することでARM64/AMD64 Node間の通信が行えるようになります。