kOpsのチュートリアルをAWSで試してみた

kOpsのチュートリアルをAWSで試してみた

2025.10.30

はじめに

コンサルティング部のぐっさんです。
急に寒くなってきましたが、冬の方が好きなので嬉しいです!

kOpsに触れる機会があったので、その検証記録となります。

kOpsとは

Kubernetesの公式プロジェクトで、Kubernetesクラスタを構築・管理・運用するためのオープンソースツールです。
クラウドプロバイダーとしては現在AWSとGCPが公式にサポートされています。

https://kops.sigs.k8s.io/

https://github.com/kubernetes/kops

マネージドなサービスを使わずにクラスタの細かい設定をカスタマイズしたり自前の運用をしたい場合、コスト削減の目的などで導入されるケースがあります。

やってみる

今回は基本的に、以下のGetting Started with kOps on AWSの内容に沿って環境構築をしてみました。
なお、自身の環境に合わせて手順と異なることを試した部分もあります。

https://kops.sigs.k8s.io/getting_started/aws/

前提

必要なコマンドのインストールをしておきます。

https://kops.sigs.k8s.io/install/

MacOSの場合はHomebrewでインストールできて便利です。

brew update && brew install kops
brew install kubernetes-cli
  • 検証環境の各ツールバージョン
項目
macOS 15.5
kOps 1.33.1
kubectl v1.34.1
aws-cli 2.26.1

認証情報の準備

公式手順では専用のIAMユーザーを作成するとありますが、検証ということもあり新規で発行せずにIAMロールを利用した認証情報を使いました。
実際は、このロールの権限を適切に絞っての対応が必要かと思います。

新しくユーザーやロールを作成する場合、以下の権限が必要です。

AmazonEC2FullAccess
AmazonRoute53FullAccess
AmazonS3FullAccess
IAMFullAccess
AmazonVPCFullAccess
AmazonSQSFullAccess
AmazonEventBridgeFullAccess

今回試した方法は以下のコマンドでまずスイッチ先のアカウントのIAMロールの認証情報を取得します。
JumpアカウントにMFAを設定しているため、オプションに--serial-number--token-codeを使用しています。

aws sts assume-role \
    --role-arn arn:aws:iam::<スイッチ先アカウントID>:role/<IAMロール名> \
    --role-session-name kops-session \
    --serial-number arn:aws:iam::<JumpアカウントID>:mfa/<MFA名> \
    --token-code <MFA CODE> \
    --profile <Jumpアカウントのプロファイル名>

このコマンドを実行するとロールに紐づく一時的な認証情報が返ってくるため、それぞれの値をローカルの環境変数に格納しておきます。
ちなみに、セッションが切れるたびに設定が必要になるため何度も使う場合はスクリプト化しておくととても便利です!

https://dev.classmethod.jp/articles/aws-cli-assume-role/

export AWS_ACCESS_KEY_ID="AccessKeyIdの値"
export AWS_SECRET_ACCESS_KEY="SecretAccessKeyの値"
export AWS_SESSION_TOKEN="SessionTokenの値"

なお、今回は検証のためGossipベースのDNSを使用します。
よってRoute53でのドメイン設定は行いません。

https://kops.sigs.k8s.io/gossip/

Gossipプロトコルは、その名の通り噂話のようにノード間で各ノードの状態やIP情報を直接共有可能なピアツーピア通信プロトコルです。

使う場合はクラスターのドメイン名を.k8s.localで終わらせるという条件があります。
独自ドメインを使用する場合は手順に沿ってRoute53を設定しましょう。

今回はスキップします!

State Store(S3バケット)を作成

クラスターの設定を保存するための専用S3バケットを作成します。
東京リージョンに作りたかったので、以下のコマンドで作成しました。コンソールから作っても問題なさそうです。

aws s3api create-bucket \
    --bucket kops-tutorial-state-store-test-1 \
    --region ap-northeast-1 \
    --create-bucket-configuration LocationConstraint=ap-northeast-1 \
    --profile <プロファイル名>

手順では次に、Cluster OIDC store用のバケットを作成するとあります。
これはノード内のPod(ServiceAccounts)から例えばS3等、他のAWSサービスへのアクセスを可能にするための設定です。
今回はkOpsを使用したクラスターの作成までをゴールとするため、この設定はスキップします。

State Store用に作成したバケットはデフォルト暗号化が有効になっているため、次の手順に移ります。

SSHキーペアの作成

以下のコマンドでローカル環境にSSHキーペアを作成しておきます。

ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ""

ローカル環境の準備

以下の環境変数を設定します。ただし、コマンドのオプションでも設定できるため必須ではないようです。
Gossipを使用するためクラスター名は.k8s.localで終わるように設定します。

export NAME=mytestcluster.k8s.local
export KOPS_STATE_STORE=s3://kops-tutorial-state-store-test-1

クラスタ構成の作成

事前にState Storeに何もオブジェクトが存在しないことを確認します。

kops_s3_1

以下のコマンドで、クラスタ設定を作成してState Storeに保存します。

kops create cluster \
  --name=${NAME} \
  --cloud=aws \
  --zones=ap-northeast-1a \
  --state=${KOPS_STATE_STORE}

しばらくすると処理が走り、以下のようなメッセージが返ってきました。

Cluster configuration has been created.

Suggestions:
 * list clusters with: kops get cluster
 * edit this cluster with: kops edit cluster mytestcluster.k8s.local
 * edit your node instance group: kops edit ig --name=mytestcluster.k8s.local nodes-ap-northeast-1a
 * edit your control-plane instance group: kops edit ig --name=mytestcluster.k8s.local control-plane-ap-northeast-1a

Finally configure your cluster with: kops update cluster --name mytestcluster.k8s.local --yes --admin

この状態でS3を確認すると、確かにオブジェクトが追加されています!

kops_s3_2

kops_s3_3

kops_s3_4

クラスタ設定の編集

設定の確認がてら、内容を編集してみます。

kops edit cluster --name ${NAME}

以下のような内容が出力され、編集可能な状態となります。

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: kops.k8s.io/v1alpha2
kind: Cluster
metadata:
  creationTimestamp: "2025-10-29T15:33:21Z"
  name: mytestcluster.k8s.local
spec:
  api:
    loadBalancer:
      class: Network
      type: Public
  authorization:
    rbac: {}
  channel: stable
  cloudProvider: aws
  configBase: s3://kops-tutorial-state-store-test-1/mytestcluster.k8s.local
  etcdClusters:
  - cpuRequest: 200m
    etcdMembers:
    - encryptedVolume: true
      instanceGroup: control-plane-ap-northeast-1a
      name: a
    manager:
      backupRetentionDays: 90
    memoryRequest: 100Mi
    name: main
  - cpuRequest: 100m
    etcdMembers:
    - encryptedVolume: true
      instanceGroup: control-plane-ap-northeast-1a
      name: a
    manager:
      backupRetentionDays: 90
    memoryRequest: 100Mi
    name: events
  iam:
    allowContainerRegistry: true
    legacy: false
  kubeProxy:
    enabled: false
  kubelet:
    anonymousAuth: false
  kubernetesApiAccess:
  - 0.0.0.0/0
  - ::/0
  kubernetesVersion: 1.33.4
  networkCIDR: 172.20.0.0/16
  networking:
    cilium:
      enableNodePort: true
  nonMasqueradeCIDR: 100.64.0.0/10
  sshAccess:
  - 0.0.0.0/0
  - ::/0
  subnets:
  - cidr: 172.20.0.0/16
    name: ap-northeast-1a
    type: Public
    zone: ap-northeast-1a
  topology:
    dns:
      type: None

ぱっと見、ネットワーク設定が全空きのものがありそうなので2箇所編集しておきます。

変更前

kubernetesApiAccess:
 - 0.0.0.0/0
 - ::/0


変更後 (自身のGIPを設定)

kubernetesApiAccess:
 - xx.xx.xx.xx/32

変更前

sshAccess:
 - 0.0.0.0/0
 - ::/0


変更後 (自身のGIPを設定)

sshAccess:
 - xx.xx.xx.xx/32

この状態で保存します。viのイメージで、編集後「:wq」で保存できました。
プロンプトが戻ってからS3を確認すると、configのタイムスタンプが変わっていたのでコマンド経由で設定が反映されたことがわかります。

kops_s3_5

また、先日このまま一度デプロイした際にCoreDNS(クラスター内部の名前解決に使用する機能)がレプリカを2つ起動しようとしてPending状態から遷移しなかったため、ワーカーノードを増やしてみます。
デフォルト設定でデプロイするとワーカーノードが1台の状態で作られますが、おそらくtopologySpreadConstraintsの設定によりノードへのPod偏りが制限されているのかなと考えました。

ノードを増やす場合は、ClusterではなくInstanceGroupの設定を編集します。
kops getコマンドで現在クラスタ設定に存在するインスタンスグループを確認します。

test-1 % kops get instancegroups --name ${NAME}
NAME				ROLE		MACHINETYPE	MIN	MAX	ZONES
control-plane-ap-northeast-1a	ControlPlane	t3.medium	1	1	ap-northeast-1a
nodes-ap-northeast-1a		Node		t3.medium	1	1	ap-northeast-1a
test-1 % 

「nodes-ap-northeast-1a」がワーカーノードのグループっぽいです。

kops edit ig nodes-ap-northeast-1a --name ${NAME}

以下のような設定が見えました!

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2025-10-29T15:33:22Z"
  labels:
    kops.k8s.io/cluster: mytestcluster.k8s.local
  name: nodes-ap-northeast-1a
spec:
  image: 099720109477/ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-20250610
  machineType: t3.medium
  maxSize: 1
  minSize: 1
  role: Node
  subnets:
  - ap-northeast-1a

maxSize、minSizeの値を2にして保存します。

S3を見ると、instancegroupフォルダ配下のnodes-ap-northeast-1aファイルが更新されたようです!

kops_s3_6

ではいよいよデプロイします。

クラスタ構築

--yesオプションが入るとアップデートが実行されるようです。

kops update cluster --name ${NAME} --yes --admin --state=${KOPS_STATE_STORE}

しばらく処理が動き、以下のようなメッセージとともにプロンプトが返ってきました。

kOps has set your kubectl context to mytestcluster.k8s.local

Cluster is starting.  It should be ready in a few minutes.

Suggestions:
 * validate cluster: kops validate cluster --wait 10m
 * list nodes: kubectl get nodes --show-labels
 * ssh to a control-plane node: ssh -i ~/.ssh/id_rsa ubuntu@
 * the ubuntu user is specific to Ubuntu. If not using Ubuntu please use the appropriate user based on your OS.
 * read about installing addons at: https://kops.sigs.k8s.io/addons.

リソース確認

様々なリソースが作成されていますが、主なリソースについてコンソールをみてみます!

VPC

リソースマップはこんな感じです。
パブリックサブネット、ルートテーブル、インターネットゲートウェイができています。

kops_vpc_1

ちなみにこんな感じのタグを自動でつけてくれています。

kops_vpc_2

セキュリティグループ

NLB用のセキュリティグループ。全空きだった部分が自分のIPになっていることを確認できました。
これはKubernetes APIサーバーへのアクセス経路です。

kops_sg_1

ワーカーノードのセキュリティグループ。同じく、SSHポートが自分のIPになっています。

kops_sg_2

マスターノードのセキュリティグループ。こちらも同じく、SSHポートが自分のIPになっています。

kops_sg_3

なおアウトバウンドルールは全許可となっていました。

NLB

ロードバランサー(NLB)が一つ立ち上がっており、
リスナーのターゲットグループはそれぞれマスターノードへルーティングされるようになっていました。

kops_nlb_1

kops_nlb_2

kops_nlb_3

EC2

インスタンスは想定通り、マスターノード1台、ワーカーノード2台が立ち上がっています!

ec2_1

また、Auto Scaling Groupも出来ています。
ワーカーノードの希望するキャパシティ/最小/最大数が2になっています。

asg_1

クラスターの確認

では手順通り、kubectlを使用してノードのステータスを確認してみます。
インスタンスIDは一部マスクしていますが、全てのノードが「Ready」状態であることがわかります。

kubectl get nodes
test-1 % kubectl get nodes
NAME                  STATUS   ROLES           AGE   VERSION
i-02fffffffffffffff   Ready    node            44m   v1.33.4
i-03fffffffffffffff   Ready    control-plane   46m   v1.33.4
i-04fffffffffffffff   Ready    node            44m   v1.33.4
test-1 % 

次にvalidateコマンドを実行してみます。

kops validate cluster --wait 10m

結果、以下のように「Your cluster mytestcluster.k8s.local is ready」が返ってきました!

INSTANCE GROUPS
NAME				ROLE		MACHINETYPE	MIN	MAX	SUBNETS
control-plane-ap-northeast-1a	ControlPlane	t3.medium	1	1	ap-northeast-1a
nodes-ap-northeast-1a		Node		t3.medium	2	2	ap-northeast-1a

NODE STATUS
NAME			ROLE		READY
i-02fffffffffffffff	node		True
i-03fffffffffffffff	control-plane	True
i-04fffffffffffffff	node		True

Your cluster mytestcluster.k8s.local is ready

ちなみに以前、ワーカーノード数をデフォルト(1)のままデプロイした時はここで以下のようなエラーが出ていました。

VALIDATION ERRORS
KIND	NAME						MESSAGE
Machine	i-0d41ef24dede31488				machine "i-0d41ef24dede31488" has not yet joined cluster
Pod	kube-system/coredns-76df845d96-c9hsv		system-cluster-critical pod "coredns-76df845d96-c9hsv" is pending
Pod	kube-system/coredns-autoscaler-f4ffb48df-tpg55	system-cluster-critical pod "coredns-autoscaler-f4ffb48df-tpg55" is pending

Validation Failed
W1022 00:46:40.954803  60840 validate_cluster.go:242] (will retry): cluster not yet healthy

最後に、以下のコマンドPod一覧を見てみます。

kubectl -n kube-system get po

以下、全てのPodでステータスが「Running」になっていることがわかります。
corednsも全てRunning状態です。デフォルト設定の際は、corednsの一つが「Pending」のままでした。

test-1 % kubectl -n kube-system get po
NAME                                            READY   STATUS    RESTARTS      AGE
aws-cloud-controller-manager-4sd78              1/1     Running   0             52m
aws-node-termination-handler-6dc8987d5c-gg82p   1/1     Running   0             52m
cilium-jbdw6                                    1/1     Running   0             50m
cilium-kjbxf                                    1/1     Running   0             50m
cilium-m87dp                                    1/1     Running   0             52m
cilium-operator-dd48f4998-t9xwc                 1/1     Running   0             52m
coredns-76df845d96-6r7x6                        1/1     Running   0             52m
coredns-76df845d96-qzz7l                        1/1     Running   0             49m
coredns-autoscaler-f4ffb48df-qz4l9              1/1     Running   0             52m
ebs-csi-controller-5d4759c466-rjbnq             6/6     Running   0             52m
ebs-csi-node-88p96                              3/3     Running   0             52m
ebs-csi-node-sfv59                              3/3     Running   0             50m
ebs-csi-node-w2fxw                              3/3     Running   0             50m
etcd-manager-events-i-03fffffffffffffff         1/1     Running   0             52m
etcd-manager-main-i-03fffffffffffffff           1/1     Running   0             52m
kops-controller-lrt7w                           1/1     Running   0             52m
kube-apiserver-i-03fffffffffffffff              2/2     Running   1 (53m ago)   52m
kube-controller-manager-i-03fffffffffffffff     1/1     Running   3 (53m ago)   52m
kube-scheduler-i-03fffffffffffffff              1/1     Running   0             52m
test-1 % 

お片付け

一通り確認できたので、片付けます!

以下のコマンドで、削除されるリソースを確認します。

kops delete cluster --name ${NAME}

削除しても良い場合は「--yes」オプションをつけて実行します。

kops delete cluster --name ${NAME} --yes

処理が終わると以下のようなメッセージが返ってきます。

Deleted cluster: "mytestcluster.k8s.local"

コンソールからも削除されていることを確認して検証完了です。

おわりに

今回はkOpsを使用したクラスタ構築を試してみました。
ほぼデフォルト設定でインフラ周りのリソースをだいぶ広範囲に自動生成してくれて驚きました。
極めたら低コストで設定をカスタマイズしたクラスタ環境を手軽に作れそうですね。

この記事が誰かの助けになりましたら幸いです。
最後までお読みいただきありがとうございました!

この記事をシェアする

FacebookHatena blogX

関連記事