まえがき
たとえばプライベート証明書を使ったコンテナリポジトリを使っている場合、ノードにプライベート証明書をインストールする必要があります。EKS最適化AMIを使ったマネージドノードグループでこれをするには起動テンプレートをカスタマイズすればいいです。Amazon Linux 2023のEKS最適化AMIを使ったマネージドノードの場合の例を記載します。
参考
- Use private certificates to enable a container repository in Amazon EKS
- 起動テンプレートを使用してマネージドノードをカスタマイズする
Terraformのサンプル
結論としては以下のようなコードでマネージドノードグループと起動テンプレートを作成すればいいです。Terraform内のextra_scripts
に追加処理のシェルスクリプトを記述します。例だとS3バケットに配置したプラベート証明書をインストールするシェルスクリプトを書いています。
ちなみに、以下コードはVPCをAWS VPC Terraform module、EKSをAWS EKS Terraform moduleで作成して変数を参照しています。ノードグループのIAMロールにはS3へのアクセス権も付与してあります。
resource "aws_eks_node_group" "extra" {
cluster_name = module.eks.cluster_name
node_group_name = "extra"
node_role_arn = module.eks.eks_managed_node_groups.default.iam_role_arn
subnet_ids = module.vpc.private_subnets
scaling_config {
desired_size = 1
max_size = 1
min_size = 1
}
launch_template {
id = aws_launch_template.extra.id
version = "$Latest"
}
}
# AL2023 EKS最適化AMIの最新IDを取得
data "aws_ssm_parameter" "eks_ami_image_id" {
name = "/aws/service/eks/optimized-ami/${module.eks.cluster_version}/amazon-linux-2023/x86_64/standard/recommended/image_id"
}
# 変数にuserdataの内容を格納
locals {
user_data = base64encode(templatefile("./al2023_user_data.tpl", {
apiServerEndpoint = module.eks.cluster_endpoint
certificateAuthority = module.eks.cluster_certificate_authority_data
cidr = module.eks.cluster_service_cidr
name = module.eks.cluster_name
extra_scripts = "aws s3 --region リージョン cp s3://バケット名/証明書 /etc/pki/ca-trust/source/anchors/ && update-ca-trust extract"
}))
}
resource "aws_launch_template" "extra" {
name = "extra"
image_id = nonsensitive(data.aws_ssm_parameter.eks_ami_image_id.value)
user_data = local.user_data
vpc_security_group_ids = [module.eks.node_security_group_id]
monitoring {
enabled = true
}
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 2
instance_metadata_tags = "disabled"
}
}
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"
--//
Content-Type: application/node.eks.aws
---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
apiServerEndpoint: ${apiServerEndpoint}
certificateAuthority: ${certificateAuthority}
cidr: ${cidr}
name: ${name}
--//
Content-Type: text/x-shellscript
#!/bin/bash
${extra_scripts}
--//--
解説
EKSへの参加
2024/10現在、EKS最適化AMIのAmazonLinuxはAL2
とAL2023
の2つがあり、EKSへの参加方法も異なります。AL2
はbootstrap.shというシェルスクリプト使っています。このスクリプトを実行してEKSへの参加を行いますが、その際AWSのDescribeCluster
APIを使用していました。これだと大規模な環境ではAPIの大量実行が発生する恐れもあったそうです。そこでAL2023
ではnodeadmを使うように変更されました。今までDescribeCluster
で取得していた情報をYAMLに記述することでAPIの大量実行を防ぐようになりました。nodeadmはServiceとして登録されておりOS起動時に自動実行され、起動時の設定はuserdataから読み込まれるようです。
参考
- Amazon Linux 2 から Amazon Linux 2023 にアップグレードする
- awslabs/amazon-eks-ami: Packer configuration for building a custom EKS AMI (github.com)
cloud-init(userdata)
Amazon Linuxのインスタンス初期設定はcloud-initを使用しており、ユーザーデータに書かれた処理が実行されます。ユーザーデータは以下のようなMIMEマルチパートドキュメントの形式で書かれています。--//
で囲まれた部分が1つの塊で、Content-Typeでデータの型(type/subtype;parameter=value)を指定し、型に沿った内容(Content)を記述します。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"
--//
Content-Type: type/subtype;parameter=value
Content
--//
Content-Type: type/subtype;parameter=value
Content
--//--
AL2
のEKS最適化AMIの場合、bootstrap.shの実行が記述されています。AL2023
の場合はnodeadmの設定が記述されています。nodeadmの設定はContent-Type:application/node.eks.aws
の型を使用します。この型はnodeadm設定用であるため、任意のコマンドを実行したい時はConntent-Type:text/x-shellscript
を追加すればいいです。たとえば以下のユーザーデータならnodeadmの設定をしつつファイル「hogehoge」を作成します。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"
--//
Content-Type: application/node.eks.aws
---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
apiServerEndpoint: APIサーバーのエンドポイント
certificateAuthority: EKSクラスタの証明書
cidr: サービスCIDR
name: クラスタ名
--//
Content-Type: text/x-shellscript
#!/bin/bash
touch hogehoge
--//--
参考
ノードグループと起動テンプレートの設定
Terraformだとaws_eks_node_groupとaws_launch_templateで似たような設定項目があります。例えばセキュリティグループは両方にパラメータが用意されています。起動テンプレートをカスタマイズする場合にどちらで設定すべきかはAWSのドキュメントに記載があります。セキュリティグループは起動テンプレートで設定します。
参考
起動テンプレートのメタデータオプション
カスタムでないデフォルトのマネージドノードグループの場合、起動テンプレートはIMDSv2が必須になっておりHttpPutResponseHopLimit
も2に設定されています。カスタムした起動テンプレートを使う場合、明示的にこれらの設定をします。特にHttpPutResponseHopLimit
を2にしないとPodがノードのIAMロールを継承できません。IRSAでPodにIAMを付与するかHttpPutResponseHopLimit
を2に設定して回避します。サンプルのTerraformではHttpPutResponseHopLimit
を2に設定しています。
参考