Amazon Elastic Container Service for Kubernetes (EKS) を Terraform で素振り

少し前に EKS が Tokyo リージョンで使えるようになったので素振りしたメモ。残骸はこちら

なお、てっきり EKS も Fargate が使えるものだと思っていたのですが、そうでもなかったので(将来的にはできるようになる?)、EC2 でワーカーノード作ってます。

EKS の費用

EKS クラスタ を作成すると 1 時間あたり 0.20 USD、さらにクラスタのワーカーノードのために EC2/EBS の料金、あと Service で LoadBalancer を指定すると ELB の費用も必要です。

kubectl と aws-iam-authenticator

EKS を使用するためには Kubernetes の kubectl コマンドと、kubectl で IAM 認証を使うための aws-iam-authenticator をインストールする必要があります。

kubectl は Kubernetesの公式ドキュメント に則ってディストリビューションのパッケージマネージャーでインストールしてもよいし、AWSでバイナリがホストされている のでそれを直でインストールしても良いです。

aws-iam-authenticator も AWS にバイナリがホストされているのでそこからインストールします。

クラスタを作成

EKS クラスタの作成には結構な時間がかかります(8分ぐらいかかった)。

ECS クラスタは一瞬で作成されていましたが、ECS の場合はなにかインスタンス的なものが作られているわけではないのに対して、EKS クラスタの場合は Kubernetes のコントロールプレーン(Kubernetes Master)のインスタンスが実際にプロビジョニングされるためです(たぶん)。ELB や RDS と同類のものだと思えば良いですね。

なお、始めにお試しでマネジメントコンソールから作成してみたところ下記の記事のような問題で kubectl が失敗したので AWS CLI で作成するか Terraform などで作成するのが良さそうです。

タグ

EKS で使用する VPC・サブネット・EC2インスタンス には kubernetes.io/cluster/${cluster_name} のような名前のタグが必要です。このタグを目印に EKS がこれらを制御するようです。

shared はその VPC やサブネットが複数のクラスタから使用されることを許可します。値 owned はそのクラスタ専用になるようですが、どういう違いがあるのかはよくわかりませんでした。

なお、EKS のユーザーガイドにはそのような記述が無いようなのですが、ワーカーノードにアタッチするセキュリティグループにも同様にタグが必要です。

コントロールプレーンのセキュリティグループ(クラスタ作成時に指定するセキュリティグループ)ではなく、EC2インスタンスにアタッチするセキュリティグループです。Kubernetes が ELB を自動的に作成した際に ELB のセキュリティグループからワーカーノードのセキュリティグループへアクセス可能にするために、ワーカーノードのセキュリティグループが Kubernetes によって自動的に更新されるため、そのためにタグ付けが必要です。

タグがないと、ELB の作成時の更新(ELB のセキュリティグループからのアクセス許可を追加)は行われるものの、ELB の削除時の更新(追加されたアクセス許可を削除)が行われなくなります。

kubeconfig

EKS クラスタの作成後、kubectl で制御できるように ~/.kube/config を作成する必要があります。手作業で作成しなくても AWS CLI で下記のようにさっと作成できます。

aws eks update-kubeconfig --name hello-eks

Launch Configuration

EKS と直接関係はありませんが、ワーカーノードを Auto Scaling で作成できるようにするために Launch Configuration を作成する場合、使用している IAM User や IAM Role が下記のようにソースアドレスで制限されているとダメでした。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "192.0.2.123/32"
          ]
        }
      }
    }
  ]
}

Launch Configuration 以外にもいくつかソースアドレスで制限しているとダメな AWS リソースがあったと思います。

aws-auth の ConfigMap

ワーカーノードをクラスタと結合(普通はジョインと言うと思う)するためにはクラスタの作成後に Kubernetes に EC2 インスタンスプロファイルを認証するための ConfigMap を反映する必要があります。

aws-auth-cm.yaml をダウンロードしてインスタンスプロファイルの Role の ARN(Terraform の aws_iam_role.node.arn)を書き換えて反映します。

curl -O https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-08-30/aws-auth-cm.yaml
vim aws-auth-cm.yaml # rolearn  の部分を書き換え
kubectl apply -f aws-auth-cm.yaml

Kubernetes の Deployment や Service を作成

Service は ELB を使うので spec.typeLoadBalancer にします。

kubectl apply -f deploy.yaml

Service を作成すると ELB および ELB にアタッチされるセキュリティグループが自動的に作成され、さらに ELB からワーカーノードにアクセスできるようにするために、ワーカーノードのセキュリティグループに ELB のセキュリティグループからのアクセス許可が自動的に追加されます。

ELB の DNS 名は kubectl で確認できます。

kubectl get service httpd -o json | jq '.status.loadBalancer.ingress[].hostname' -r

サブネットの構成

クラスタの作成時に指定するサブネットで Public と Private を両方含めておくと、Kubernetes は自動的にサブネットの Public と Private を判断して Internet facing な ELB は Public に配置されます。

Private サブネットにはワーカーノードが配置されるわけですが、それは Kubernetes によって行われるわけではなく普通に EC2 インスタンスを実行したり AutoScaling を使うなりで配置するものなので、クラスタ作成時のサブネット指定は ELB が配置される Public サブネットだけで良いような気もしたのですが、ユーザーガイドを読んだ感じ Private サブネットも指定する必要があるようです。

クラスタ作成時に指定したサブネットには Kubernetes のコントロールプレーンと通信するための ENI が自動的に作成されるようなので、ワーカーノードが配置される Private サブネットも指定する必要がある、ということだと思います。

さいごに

EKS のユーザーガイドは下記にあります。

がしかし、これだけだと EKS の Kubernetes とは無関係な AWS の特有の事情しかわからないので、ちゃんと使うなら Kubernetes のドキュメントを読み進める必要があります。

クラスタを作成するだけでワーカーノードがなくても費用がかかるし、EC2 でワーカーノードを準備する必要があるので ECS と比べてお手軽感はありませんね。

また、ECS ならマネジメントコンソールで Task や Service の状態がいろいろ見れますが、EKS だとマネジメントコンソールではほとんどなにも見えなくて、基本的には kubectl を使う必要があります。ただ、どうせ CLI メインになるだろうので AWS CLI とか ECS CLI とかよりも kubectl で操作できる EKS の方が良いかもしれません。GUI が必要なら Kubernetes Dashboard というものも使えるようです。

EKS と直接は関係ない問題ですが、ワーカーノードを作成するために AutoScaling を使ってみましたが Terraform だと AutoScaling で AMI のアップデードに課題がありそうです。Rolling Update や Blue/Green Deployment は Terraform 単体できれいにやるのは難しそうです。