🏮

OCIのAlways Free枠で VM.Standard.A1.Flex のOKE(Kubernetes)を構築しようとした

に公開

はじめに

Oracle Cloud Infrastructure(OCI)を触る機会があり、特にOKE周辺の知識を整理するためにこの記事を書き始めました。今回の記事はマネージドKubernetesを構築できるOKE (Container Engine for Kubernetes) をAlways Freeの範囲内で利用しようとした記録を書いていきます。
結果として、Always Freeの範囲内でOKEを立てる構成を作ることは可能ですが、A1インスタンスの在庫が切れる場合があり、不安定な挙動になってしまうということが分かりました。

OCIについて

OCIはOracle社によって運営されているパブリッククラウドサービスです。下り通信、(Engress)、ロードバランサの安価さ、コンピュート単価の低さ、Oracle製品との親和性、後述するAlways Free(恒久無料インスタンス)の豊富さなどが他クラウドと比較した優位性です。

2026年6月以降の変更

OCIのAlways Free枠で最も人気のインスタンスはARMの VM.Standard.A1.Flexです。
以前は4 OCPU / 24GB が無期限で無料という破格の条件でしたが、2026年6月15日から 2 OCPU / 12GB に半減しています。公式アナウンスの無い変更だったので、注意が必要です。

公式ドキュメントの現在の記載:
初めに、1,500 OCPU 時間と 月当たり9,000 GB時間が無料です。
これは2つのOCPUと12GBのメモリに相当します。

ちなみに、アイドル状態のAlways Freeインスタンスは、Oracleに回収(停止)される場合があります。(7日間のCPU使用使用率95パーセンタイルが20%未満)
https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm
その他の主なAlways Free枠のリストをまとめておきます:

リソース 枠
Ampere A1 1,500 OCPU時間 / 9,000 GB時間(= 常時2 OCPU/12GB)
AMD micro VM.Standard.E2.1.Micro × 2
Block Volume 合計200GB / バックアップ5個
Object Storage 20GB / 50,000リクエスト/月
Flexible LB 1台(10Mbps固定)
VCN 2つまで
送信データ転送 10TB/月

NAT / Internet / Service Gateway は無料枠に含まれており、時間課金がないのは嬉しいポイントです。

https://linuxiac.com/oracle-quietly-cuts-free-tier-ampere-a1-resources-in-half/

OKEについて

OKEはOCIにおけるk8sのマネージド型サービスです。
クラスタの管理費自体は無料ですが、ワーカーノードは別途コンピュータの課金が必要です。完全無料枠のみで試したい場合は、ワーカーをすべてAlways Free枠にに収める必要があります。
また、現在ワーカーに利用できるインスタンスは前述したVM.Standard.A1.Flexのみです。
まとめるとこのような構成になります。

  • Basic cluster
  • VM.Standard.A1.Flex 1 OCPU / 6GB × 2ノード
  • ブートボリューム 50GB × 2 = 100GB

クラスタ作成

Developer SevicesからOKEを選択します。

ClusterからCreate clusterを選択します。

Quick createを選択します。

Managed、Private workerを選択します。

ノードプールのサイズ、使用するNode shapesを選択します。

今回、Nodeの個数は2に設定してあります。

コンソールでクラスタを作ろうとするとこのように表示されます:
You have not selected any Enhanced cluster features. An Enhanced cluster will be created unless you select the checkbox below. Creating a Basic cluster will prevent you from using features restricted to Enhanced cluster until you upgrade your cluster.

この時、何も選ばず作成すると有料のEnhancedが作成されます。無料のBasicにするには、明示的にチェックボックスをオンにしてください。
なお、Basic→Enhancedは後からアップグレード可能です。
CLIで作成する場合は、--type BASIC_CLUSTER を明示してください。

VCNをクイック作成する

VCNはAWS、Google CloudのVPCに相当する機能です。プライベートなIPアドレス帯(CIDR)を定義し、サブネットを作成して、仮想マシンなどのリソースを配置することができます。
VCNの設定は初心者には複雑なので、クイック作成を選択します。
実際にこのようなリソースが作られました。

Create virtual cloud network   oke-vcn-quick-cluster1-xxxx           Done
Create internet gateway        oke-igw-quick-cluster1-xxxx           Done
Create NAT gateway             oke-ngw-quick-cluster1-xxxx           Done
Create service gateway         oke-sgw-quick-cluster1-xxxx           Done
Create route tables            oke-private-routetable-cluster1-xxxx  Done
                               oke-public-routetable-cluster1-xxxx   Done
Create security lists          oke-svclbseclist-quick-cluster1-xxxx  Done
                               oke-nodeseclist-quick-cluster1-xxxx   Done
                               oke-k8sApiEndpoint-quick-cluster1-xxx Done
Create subnets                 oke-svclbsubnet-...-regional          Done
                               oke-nodesubnet-...-regional           Done
                               oke-k8sApiEndpoint-subnet-...-regional Done
Create cluster                 cluster1                              Done
Create node pool               pool1                                 Done

なお、この画面には「Save as atack」ボタンがあり、作成内容をTerraformスタック(Resource Manager)として保存できます。Terraformの学習の参考にもなりそうです。

クラスターがアクティブになったか確認します。

user@cloudshell:~ (ap-osaka-1)$ oci ce cluster list --compartment-id $TENANCY_OCID --query 'data[].{name:name,type:type,state:"lifecycle-state"}' --output table
+----------+----------+---------------+
| name     | state    | type          |
+----------+----------+---------------+
| cluster1 | CREATING | BASIC_CLUSTER |
+----------+----------+---------------+
user@cloudshell:~ (ap-osaka-1)$ oci ce cluster get --cluster-id $CLUSTER_ID --query 'data."lifecycle-state"' --raw-output
ACTIVE

CLI上では無事アクティブが確認されました。

ノードプール作成後

クイック作成は全ステップ Done になりました、クラスタもACTIVEです。しかし、Nodeが確認できません。

oci ce node-pool get --node-pool-id $NODEPOOL_ID --query 'data.nodes[].{name:name,state:"lifecycle-state"}' --output table
Command returned empty list, no table to display.

設定自体は意図とずれていません。

{
  "nodeCount": 1,
  "shape": "VM.Standard.A1.Flex",
  "shapeConfig": { "memory-in-gbs": 6.0, "ocpus": 1.0 },
  "size": 2
}

NodeがCREATINGのまま現れたり消えたりしていることがわかりました。

ログの見方

原因を探るため、ログをチェックします。

+--------------------+-------------+---------------------------+
| op                 | status      | time                      |
+--------------------+-------------+---------------------------+
| CLUSTER_CREATE     | SUCCEEDED   | 2026-08-07T06:50:23+00:00 |
| NODEPOOL_CREATE    | FAILED      | 2026-08-07T06:50:24+00:00 |
| NODEPOOL_RECONCILE | FAILED      | 2026-08-07T07:00:37+00:00 |
| NODEPOOL_RECONCILE | FAILED      | 2026-08-07T07:02:52+00:00 |
| NODEPOOL_RECONCILE | FAILED      | 2026-08-07T07:06:07+00:00 |
| NODEPOOL_RECONCILE | FAILED      | 2026-08-07T07:11:19+00:00 |
| NODEPOOL_RECONCILE | IN_PROGRESS | 2026-08-07T07:20:28+00:00 |
+--------------------+-------------+---------------------------+

エラー内容を見てみます。

{
  "code": "Service Error",
  "message": "Work request exceeded max retry count"
}
| Creating node pool with 2 nodes                                                            |
| 2 node(s) need be provisioned, 0 node(s) provisioning, will provision 2 additional node(s) |
| Validating nodes: 0 provisioned, 0 provisioning, 2 remaining                               |
| Validating nodes: 0 provisioned, 0 provisioning, 2 remaining                               |
| Validating nodes: 0 provisioned, 0 provisioning, 2 remaining                               |
|  ...延々と同じ                                                                              |

どうやら起動処理に入れていないことが判明しました。

切り分け:インスタンスを試しに一台だけ起動してみる

Compute APIを直接叩いて、インスタンスの挙動を確かめてみます。

oci compute instance launch \
  --availability-domain "$AD" \
  --compartment-id $TENANCY_OCID \
  --shape VM.Standard.A1.Flex \
  --shape-config '{"ocpus":1,"memoryInGBs":6}' \
  --image-id $IMAGE_ID \
  --subnet-id $SUBNET_ID \
  --display-name capacity-test
{
  "code": "InternalError",
  "message": "Out of host capacity.",
  "status": 500,
  "operation_name": "launch_instance"
}

500エラーであることが判明しました。

インスタンスの在庫を確認

インスタンスの在庫を確認したときはこのように余裕があるように見えました。

| standard-a1-core-count             | AD     | 41  |
| standard-a1-core-regional-count    | REGION | 16  |
| standard-a1-memory-count           | AD     | 277 |
| standard-a1-memory-regional-count  | REGION | 96  |
| standard-a1-core-count-reservable  | AD     | 0   |
oci limits resource-availability get --service-name compute --limit-name standard-a1-core-count --availability-domain "$AD" ...
{
  "available": 41,
  "fractional-availability": 41.0,
  "used": 0
}

available: 41 と表示されながら、実際は1コアも起動できませんでした。
どうやら、この数値は「テナンシのリミット上の空き」であり、「物理ホストの空き在庫」では無いようです。
さらに、 standard-a1-core-count-reservable が 0であることから、空きが出るまで待たなければいけないことが分かりました。OCIには容量予約という仕組みがありますが、無料アカウントは利用できません。
在庫を確保する手段が存在せず、毎回その場の空き待ち状況に賭けるしかないです。

代替手段

トライアルの$300クレジットが残っていたので、x86シェイプで同じクラスタにノードプールを追加しました。トライアル期間中の超過部分はクレジットから消費され、カードに自動請求されることはありません、ただし、トライアルで作ったソースは期間終了後に回収される点には注意が必要です。

oci ce node-pool create \
  --cluster-id $CLUSTER_ID \
  --compartment-id $TENANCY_OCID \
  --name pool-x86 \
  --kubernetes-version v1.36.1 \
  --node-shape VM.Standard.E5.Flex \
  --node-shape-config '{"ocpus":1,"memoryInGBs":8}' \
  --node-image-id $X86_IMAGE_ID \
  --node-boot-volume-size-in-gbs 50 \
  --size 2 \
  --cni-type OCI_VCN_IP_NATIVE \
  --pod-subnet-ids "[\"$SUBNET_ID\"]" \
  --placement-configs "[{\"availabilityDomain\":\"$AD\",\"subnetId\":\"$SUBNET_ID\"}]"

約10分で2ノードとも ACTIVEになりました。

+------------+-------------------------------------------+--------+
| ip         | name                                      | state  |
+------------+-------------------------------------------+--------+
| 10.0.10.40 | oke-...-0                                 | ACTIVE |
| 10.0.10.33 | oke-...-1                                 | ACTIVE |
+------------+-------------------------------------------+--------+
oci ce cluster create-kubeconfig --cluster-id $CLUSTER_ID --file $HOME/.kube/config --region ap-osaka-1 --token-version 2.0.0 --kube-endpoint PUBLIC_ENDPOINT
NAME         STATUS   ROLES   AGE   VERSION   OS-IMAGE                   CONTAINER-RUNTIME
10.0.10.33   Ready    node    25m   v1.36.1   Oracle Linux Server 8.10   cri-o://1.36.0
10.0.10.40   Ready    node    25m   v1.36.1   Oracle Linux Server 8.10   cri-o://1.36.0

動作確認

OKEのコンテナランタイムがCRI-Oで、短縮イメージ名が禁止されているため、完全修飾名でないと動作しません。CRI-Oはk8sに最適化された軽量なランタイムとして開発されたCNCFのIncubating(発展中)プロジェクトです。例として、nginxとだけ指定して作成を試してみます。
https://cri-o.io/

kubectl create deployment hello --image=nginx --replicas=2

この場合失敗します。

Failed to pull image "nginx": short name mode is enforcing,
but image name nginx:latest returns ambiguous list

完全修飾名で書き直します。こちらでは作成に成功しました。

kubectl set image deployment/hello nginx=docker.io/library/nginx:latest

VCN-Native Pod Networkingの挙動

VCN-Native Pod Networkingとは、VCN(ネットワークの単位)のCIDRブロックからポッドへのIPアドレスを提供する機能です。リソースがKubernetesクラスタ内のポッドと直接通信できるようになります。

NAME                     READY   STATUS    IP            NODE
hello-5fbf6577d6-fk4v9   1/1     Running   10.0.10.203   10.0.10.40
hello-5fbf6577d6-fkpvl   1/1     Running   10.0.10.128   10.0.10.33

このように、IPアドレスがそれぞれのpodに割り当てられたことが分かりました。
次は、実際にpod内で実行されているイメージの中身を見に行きます。

kubectl expose deployment hello --port=80 --type=ClusterIP
kubectl run curl-test --image=docker.io/curlimages/curl:latest --rm -it --restart=Never -- curl -s hello
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<h1>Welcome to nginx!</h1>
<p>If you see this page, nginx is successfully installed and working.

nginxのページが無事起動しています。
イメージを差し替えることで、いろいろなアプリケーションを展開することが可能です。

まとめ

「無料枠がある」ことと、「無料枠の選択肢がすぐに使える」ということは別の問題だとわかりました。OCIのA1は選択肢として利用可能になっていますが、実際には物理容量が提供されるまで待ち時間が必要です。すぐに試したい人はクレジットからの利用をお勧めします。

Discussion