0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EKSなしIRSAへの道 ― 第4回:AWS Cloud Controller Managerを導入する

0
Last updated at Posted at 2026-10-12

はじめに

これまでの記事では、kubeadmで構築したKubernetesクラスターでOIDCエンドポイントを公開し、PodのServiceAccountからIAMロールを引き受けるところまでを確認しました。

以下は、前回の記事です。

次の目標は、EBSのようなAWSリソースをKubernetesから利用することです。そのためにはPodの認証だけでなく、ノードとEC2インスタンスの対応付けも必要になります。

本記事では、kubeadmで構築したKubernetesクラスターにAWS Cloud Controller Manager(以下CCM)を導入し、ノードにEC2に関する情報が設定されることを確認します。

本記事でやること

本記事では、CCMによってKubernetesのノードへEC2インスタンスID、インスタンスタイプ、リージョン、ゾーンなどの情報を設定します。これにより、EBS CSI Driverなど、AWSリソースと連携するKubernetesコンポーネントを利用できる前提を整えます。

Cloud Controller Managerとは

CCMは、クラウド固有の制御ロジックをKubernetesのコントロールプレーンから分離して実行するコンポーネントです。AWS CCMは、KubernetesのノードとEC2インスタンスを対応付け、EC2のインスタンスタイプ、リージョン、ゾーンなどの情報をノードのラベルとして設定します。

※ 以後、CCMは "AWS CCM" を表します。

CCMを利用するためには、CCM Podが動作するEC2インスタンスがAWSから必要な情報を取得できるよう、相応の権限を持つ必要があります。一般的にAWSでこのようなことを実現するにはIAMロールを使います。EC2インスタンスへIAMロールを付与するには、インスタンスプロファイルと呼ばれるリソースがさらに必要です。

CCMはインスタンスプロファイル経由で渡されたIAMロールを使ってEC2 APIを参照します。kubeletがノードへ設定するproviderIDを手掛かりに、CCMがノードの初期化を完了させます。

ccm-node-initialization-edited-Page-1.png

前提条件

第1,2,3回の手順を完了し、EC2上でkubeadmで構築したKubernetesクラスターが稼働しているものとします。

また、以下を前提とします。

  • AWS CLI、Helmfile、kubectlを利用できること
  • CCM用のEC2タグとインスタンスプロファイルを設定できるAWS権限があること

検証環境

本記事では、control-planeとworkerを兼ねる単一ノード構成で検証します。CCM導入前のノードは次の状態です。

$ kubectl get node
NAME          STATUS   ROLES           AGE   VERSION
ip-10-0-0-4   Ready    control-plane   35h   v1.36.5

CCM導入前に付与されているラベルは次のとおりです。

$ kubectl get node --show-labels | tr ',' '\n'
NAME          STATUS   ROLES           AGE    VERSION   LABELS
ip-10-0-0-4   Ready    control-plane   35h   v1.36.5   beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=ip-10-0-0-4
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=

自動化した構成

本記事の手順は、Terraform、Ansible、Helmfileとして自動化しています。

TerraformはEC2のNameタグからinstance ID、接続先、AZ、providerIDを取得してinventoryを生成します。Ansibleはexternal cloud providerの設定とノード再登録・CCM初期化の確認を担当します。

ただし、本記事ではCCMを動かす仕組みを確認しやすいよう、TerraformやAnsibleが実行する内容をAWS CLI、kubectl、Helmfileを使った手順として説明します。

セットアップ手順

1. EC2にCCM用のIAMロールとインスタンスプロファイルを設定する

CCMはEC2 APIを参照するため、EC2にインスタンスプロファイルを付与します。以下の順に、IAMロール、インスタンスプロファイル、EC2タグを設定します。

1-1. 変数を設定する

以下はAWS CLIで作成する例です。値は環境に合わせて置き換えてください。

AWS_REGION=ap-northeast-1
INSTANCE_ID=i-xxxxxxxxxxxxxxxxx
CLUSTER_ID=<cluster-id>
ROLE_NAME=kubernetes-aws-cloud-controller-manager
INSTANCE_PROFILE_NAME=${ROLE_NAME}

CLUSTER_ID は任意の識別子を指定できますが、同一クラスターの対象EC2には同じ値を使ってください。また、IAMロール名(ROLE_NAME)とインスタンスプロファイル名(INSTANCE_PROFILE_NAME)も任意です。ここでは管理しやすいよう、インスタンスプロファイル名をIAMロール名と同じにしています。

1-2. IAMポリシーファイルを作成する

まず、EC2がIAMロールを引き受けるための信頼ポリシーを、ccm-trust-policy.json として作成します。

ccm-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "ec2.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}

次に、CCMがEC2 APIを参照するための許可ポリシーを、ccm-policy.json として作成します。今回必要だった最小権限は次の3つです。

ccm-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "ec2:DescribeRegions",
        "ec2:DescribeAvailabilityZones"
      ],
      "Resource": "*"
    }
  ]
}

1-3. IAMロールとインスタンスプロファイルを作成する

aws iam create-role \
  --role-name "${ROLE_NAME}" \
  --assume-role-policy-document file://ccm-trust-policy.json

aws iam put-role-policy \
  --role-name "${ROLE_NAME}" \
  --policy-name cloud-controller-manager \
  --policy-document file://ccm-policy.json

aws iam create-instance-profile \
  --instance-profile-name "${INSTANCE_PROFILE_NAME}"

aws iam add-role-to-instance-profile \
  --instance-profile-name "${INSTANCE_PROFILE_NAME}" \
  --role-name "${ROLE_NAME}"

1-4. EC2へタグとインスタンスプロファイルを関連付ける

対象EC2には、CCMがクラスターのメンバーとして認識するための kubernetes.io/cluster/<cluster-id>=owned タグを付与します。

aws ec2 create-tags \
  --region "${AWS_REGION}" \
  --resources "${INSTANCE_ID}" \
  --tags "Key=kubernetes.io/cluster/${CLUSTER_ID},Value=owned"

aws ec2 associate-iam-instance-profile \
  --region "${AWS_REGION}" \
  --instance-id "${INSTANCE_ID}" \
  --iam-instance-profile Name="${INSTANCE_PROFILE_NAME}"

EC2にすでに別のインスタンスプロファイルが関連付けられている場合、最後のコマンドは実行しないでください。既存のロールやプロファイルへの影響を確認してから、置換方法を検討してください。

2. kubeletとkube-controller-managerをexternal cloud providerに切り替える

kubeletには、/etc/default/kubelet で次の引数を設定します。

/etc/default/kubelet
KUBELET_EXTRA_ARGS="--cloud-provider=external --provider-id=aws:///ap-northeast-1a/i-xxxxxxxxxxxxxxxxx"

また、/etc/kubernetes/manifests/kube-controller-manager.yaml のcommandへ次を追加します。

/etc/kubernetes/manifests/kube-controller-manager.yaml の一部
- --cloud-provider=external

設定後はkubeletを再起動し、API ServerがReadyへ戻ることを確認します。

sudo systemctl restart kubelet
kubectl get --raw=/readyz

Kubernetes v1.33以降では、kube-apiserverへ--cloud-providerを渡しません。

3. AWS CCMを導入する

CCMはcontrol-planeノードへ配置します。今回利用した設定の要点は次のとおりです。

helmfile-aws-ccm.yaml
hostNetworking: true
image:
  repository: registry.k8s.io/provider-aws/cloud-controller-manager
  tag: v1.36.1
nodeSelector:
  node-role.kubernetes.io/control-plane: ""
tolerations:
  - key: node.cloudprovider.kubernetes.io/uninitialized
    value: "true"
    effect: NoSchedule
  - key: node-role.kubernetes.io/control-plane
    effect: NoSchedule
args:
  - --cloud-provider=aws
  - --configure-cloud-routes=false

以下のコマンドを実行して、AWS CCMをインストールします。

helmfile -f helmfile-aws-ccm.yaml apply

CCMのPodがデプロイされていることを確認します。

$ kubectl get ds,po -A -l k8s-app=aws-cloud-controller-manager
NAMESPACE     NAME                                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                            AGE
kube-system   daemonset.apps/aws-cloud-controller-manager   1         1         1       1            1           node-role.kubernetes.io/control-plane=   49s

NAMESPACE     NAME                                     READY   STATUS    RESTARTS   AGE
kube-system   pod/aws-cloud-controller-manager-pdd7l   1/1     Running   0          49s

4. 既存ノードを再登録する

すでにproviderIDなしで登録済みのノードは、kubeletへ引数を追加しただけではproviderIDが更新されません。そのため、ノードオブジェクトを削除してkubeletを再起動し、再登録させます。

ノードオブジェクトの削除はEC2インスタンスを削除する操作ではありません。ただし単一ノードクラスターでは、再登録と初期化の間にワークロードPodが一時的にPendingになります。

以下のコマンドで、ノードを削除します。
(本記事の例では、ノード ip-10-0-0-4 を削除します)

kubectl delete node ip-10-0-0-4

一時的に、以下のようにノードが1台も起動していない状態となります。

$ kubectl get node
No resources found

続いて、kubeletを再起動してラベルをつけ直します。

sudo systemctl restart kubelet
kubectl label node ip-10-0-0-4 node-role.kubernetes.io/control-plane= --overwrite

すると、ノードが再登録されます。

$ kubectl get node
NAME          STATUS   ROLES           AGE   VERSION
ip-10-0-0-4   Ready    control-plane   22s   v1.36.5

--node-labels=node-role.kubernetes.io/control-plane= をkubeletへ渡す方法は使いません。Kubernetes v1.36では予約済みのラベル名前空間として拒否されます。

5. ノードが初期化されたことを確認する

CCMがEC2と対応付けられると、ノードにEC2の情報が反映されます。

以下のコマンドを実行すると、EC2に関する情報を持つラベルが追加されているのを確認できます。

$ kubectl get node --show-labels | tr ',' '\n'
NAME          STATUS   ROLES           AGE   VERSION   LABELS
ip-10-0-0-4   Ready    control-plane   17m   v1.36.5   beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=t3a.small   # 追加
beta.kubernetes.io/os=linux
failure-domain.beta.kubernetes.io/region=ap-northeast-1 # 追加
failure-domain.beta.kubernetes.io/zone=ap-northeast-1a  # 追加
kubernetes.io/arch=amd64
kubernetes.io/hostname=ip-10-0-0-4
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
node.kubernetes.io/instance-type=t3a.small   # 追加
topology.k8s.aws/zone-id=apne1-az4           # 追加
topology.kubernetes.io/region=ap-northeast-1 # 追加
topology.kubernetes.io/zone=ap-northeast-1a  # 追加

また、spec.providerID にEC2インスタンスのIDが付与されていることも確認できます。

$ kubectl get node ip-10-0-0-4 -o custom-columns=NAME:.metadata.name,PROVIDER:.spec.providerID
NAME          PROVIDER
ip-10-0-0-4   aws:///ap-northeast-1a/i-xxxxxxxxxxxxxxxx

まとめ

EKSを使わないKubernetesでも、EC2のインスタンスプロファイル、kubeletのproviderID、AWS CCMを組み合わせることで、ノードへAWSのEC2に関する情報を設定できます。これで、EBS CSI DriverなどAWSと連携するKubernetesコンポーネントを導入する前提が整いました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?