kOpsのチュートリアルをAWSで試してみた
はじめに
コンサルティング部のぐっさんです。
急に寒くなってきましたが、冬の方が好きなので嬉しいです!
kOpsに触れる機会があったので、その検証記録となります。
kOpsとは
Kubernetesの公式プロジェクトで、Kubernetesクラスタを構築・管理・運用するためのオープンソースツールです。
クラウドプロバイダーとしては現在AWSとGCPが公式にサポートされています。
マネージドなサービスを使わずにクラスタの細かい設定をカスタマイズしたり自前の運用をしたい場合、コスト削減の目的などで導入されるケースがあります。
やってみる
今回は基本的に、以下のGetting Started with kOps on AWSの内容に沿って環境構築をしてみました。
なお、自身の環境に合わせて手順と異なることを試した部分もあります。
前提
必要なコマンドのインストールをしておきます。
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アカウントのプロファイル名>
このコマンドを実行するとロールに紐づく一時的な認証情報が返ってくるため、それぞれの値をローカルの環境変数に格納しておきます。
ちなみに、セッションが切れるたびに設定が必要になるため何度も使う場合はスクリプト化しておくととても便利です!
export AWS_ACCESS_KEY_ID="AccessKeyIdの値"
export AWS_SECRET_ACCESS_KEY="SecretAccessKeyの値"
export AWS_SESSION_TOKEN="SessionTokenの値"
なお、今回は検証のためGossipベースのDNSを使用します。
よってRoute53でのドメイン設定は行いません。
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に何もオブジェクトが存在しないことを確認します。

以下のコマンドで、クラスタ設定を作成して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 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のタイムスタンプが変わっていたのでコマンド経由で設定が反映されたことがわかります。

また、先日このまま一度デプロイした際に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ファイルが更新されたようです!

ではいよいよデプロイします。
クラスタ構築
--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
リソースマップはこんな感じです。
パブリックサブネット、ルートテーブル、インターネットゲートウェイができています。

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

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

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

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

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



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

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

クラスターの確認
では手順通り、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を使用したクラスタ構築を試してみました。
ほぼデフォルト設定でインフラ周りのリソースをだいぶ広範囲に自動生成してくれて驚きました。
極めたら低コストで設定をカスタマイズしたクラスタ環境を手軽に作れそうですね。
この記事が誰かの助けになりましたら幸いです。
最後までお読みいただきありがとうございました!







