EKS Kubernetes AutoscalingGroup作成とUserData

※この辺から訂正と追記しました(10/8)
前回でKubernetesへのアクセスができるようになりましたが、ここで一歩引いて EC2 Node を起動するための Autoscaling Group を作成します。

LaunchTemplates と Autoscaling Group だけじゃ味気ないので、UserData でこんなことやってますってのを濃いめに解説するところまで、いきたいと思います。



Launch Template

LaunchConfiguration はもう使わないので、LaunchTemplateにお世話になります。

UserData

UserDataのシェルスクリプトについては、最後に記載と説明をします。
ここのチョットしたポイントとしては、template_file において template = file(“script.sh”) と vars を使わず、templatefile にしているところです。vars では配列やハッシュは使えないので、そのへんを自由に扱える templtefile を採用しています。


Launch Template

特に変わったことはしていないです。


Autoscaling Group

こちらも大したことはしていないです。新しい dynamic を使ってコードをスッキリさせたくらいでしょうか。あとはオンデマンド/スポットを扱えるようにしています。また、CloudWatchによる増減機能は使用しません。

で、これと全く同じ内容で master 用のグループをもう1つ作っています。コードとしては scaler を master に置換しただけのような内容で、count でまとめることもできましたが、明確に役割で分けたほうが扱いやすそうだったので、分けてやりました。

scaler / master の構想については前の記事を参照です。

Notifications

Group に Notification をつけておきます。Group と同じく master にもつけていますが省略します。


UserData スクリプトと解説

LaunchTempalate で指定した UserData のスクリプトと、何をやっているかの解説をします。

まず根本的な、何故 UserData を利用するかですが、そもそも公式のEKS Node用AMIを利用すると、UserData で /etc/eks/bootstrap.sh を実行するように定められています。実行することで、Kubernetes の Node として登録する、という重要な処理を完了させるからです。この辺のベースとなる内容は AWS EKS Introduction | Terraform – HashiCorp Learn をみるとよいでしょう。

基本的に、公式AMIはそのまま使いたいという方針でいます。そのため、Node の OS に手を加えたいことがあれば、この UserData のタイミングで行うことがベターになります。ですが、よほど大きな変更を入れたければ、手を加えた状態で手元のアカウントにAMIを保存して使うというのもアリでしょう。

スクリプト

今のところ、こんな感じです。


Hostname

EC2でホスト名を扱うのは通常、Nameタグと、OS内の hostname になります。

Nameタグは、AutoscalingGroup につけたタグから propagate_at_launch = true することでEC2に伝播する方法がありますが、それだと固定値になってしまいます。クラスタの機能を狭い目で見れば機能的にはそれでも動きますが、EC2一覧でユニークな情報がないとミスが起きたり無駄な判断時間を要するので、Name = ユニーク値 をつけるのがベターです。

で、ここでは Group名 + IPアドレスのドットを x に置換した値を hostname として create-tags しています。この x置換手法は昔に自分で編み出したのですが、長く色々みてると、わりと同じことしているシステムやプラットフォームを見かけたので、それなりに一般的な手法っぽいです。

もう1つ、OS内の hostname ですが、これはあえて処理をコメントアウトしてわかるとおり、変更してしまうとEKS内の情報と食い違うことになり、メトリック取得に失敗したり不都合が出るのでやめています。SSHログインしての調査時のことを考えると変更したいのですが、仕方ありません。いまのところオプションでの辻褄合わせなどできなさそうですが、こちらは変更しないほうが無難なように判断したので深追いはしません。

sysctl

Node にも Pod にも sysctl 設定はあるのですが、一部設定は Node でしか変更できないものがあります。例えば、Pod にて fs.inotify.max_user_watches が不足すると
  • FATAL: Listen error: unable to monitor directories for changes.
  • のようなエラーが出ますが、Pod での変更はできないので Node で事前に変更しておきます。

    スクリプトとしては、Terraform のEKS設定としてsysctl のKeyValueハッシュを置いといて、templatefile から渡して、設定変更&設定ファイル記述 をループさせています。追記してUserDataを更新すれば、次のNodeから反映されるので、このくらいだとAMI更新より良い方法だと思えますね。

    Kubernetes –kubelet-extra-args

    EKS に登録するための /etc/eks/bootstrap.sh の基本的使い方では、–kubelet-extra-args オプションは出てこないと思いますが、ここでは2つの項目を扱うためにオプション行を入れています。

    1つは、–node-labels=kubernetes.io/role=master (or scaler) を指定するためです。Kubernetesのラベルについては別記事で触れますが、Nodeに任意のラベルKeyValue を入れるのはこのタイミングしかありません。

    もう1つは、–register-with-taints=node-role.kubernetes.io/master=:NoSchedule,CriticalAddonsOnly=:NoSchedule を指定するためで、Taints機能も同じく別記事&このタイミングです。

    FQDNっぽいキー名は、EKS内で固定なのですが、一応Terraform設定値に書いて、templatefile から渡すように書いています。

    ぶっちゃけ、このあたりはクソ複雑なので、いきなりこれらを扱おうとしても無意味どころか害になるので、最初は入れないでください。こういう方法があるんだ程度に済ませておいて、後で取りにくる感じがよいと思います。



    下記訂正!とタグについて追記します。
    まず、この時点ではまだNodeの状態がReadyにならないので、Podは起動できません。次の記事の作業が終われば、Node が使える状態になります。

    –kubelet-extra-args 行を削除して Label と Taints を扱わなければ、ここまで作れば desired を増やしてEC2を起動することで、kubectl get nodes -o wide などでNode情報を見ることができるようになります。一応、この時点で手動Pod起動はできますが、あまり意味ないし楽しくないのでやりません。

    AutoscalingGroupのタグとNode追加の関係

    大事なことを忘れていたので追記します。

    AutoscalingGroup の Terraformコードで、dynamic “tag” { とカッコつけて簡略化したタグ付け部分がありますが、この中にEKS Nodeとして仲間入りするための大切なタグがあります。

     ”kubernetes.io/cluster/${local.eks_cluster_name}” = “owned”

    という内容です。このタグが存在することで、EKS が EC2 一覧からクラスタへ利用するノードである、ということを認識します。locals 変数の部分を抜き出してくると、こんな感じのコードになっています。

    まだ話に出していない cluster-autoscaler 用のタグもありますが、ご愛嬌で。scaler / master の役割のために、細分化して merge していますが、結果的に dynamic が使えるようになったおかげで、綺麗に書けた、つもりでいます。



    次からようやくKubernetes に踏み込むので、ちっとは楽しくなっていきます。
    先は長い・・・!