Phase 6:OKE(Kubernetes)¶
目標¶
- Terraform で OKE(Container Engine for Kubernetes)クラスタを作り、その上で nginx を動かしてロード・バランサ(Load Balancer)経由で公開する
- マネージド Kubernetes で「誰が何を管理するのか」を理解する
- Kubernetes の自己修復、スケール、drain を体験する
OKE とは¶
標準の upstream Kubernetes(CNCF 認定)で、kubectl / Helm / manifest の使い方は他の環境と同じです。≒ AWS EKS、Azure AKS、Google GKE。
OCI に依存しているのは「接続レイヤー」だけです。
| K8s のオブジェクト / 機能 | OCI 上で起きること |
|---|---|
Service type: LoadBalancer |
cloud-controller-manager が OCI の LB を作成 |
PersistentVolumeClaim |
CSI driver が OCI のブロック・ボリューム(Block Volume) を作成 |
| kubeconfig の認証 | oci ce cluster generate-token(OCI IAM、≒ aws eks get-token) |
| Pod ネットワーク | flannel(overlay)または VCN-Native(Pod が VCN の IP を直接持つ) |
誰が何を管理するか¶
| 部分 | 管理者 | 説明 |
|---|---|---|
| コントロール・プレーン(Control Plane、apiserver / etcd / scheduler など) | Oracle | Oracle 自身のテナンシ(Tenancy)内に作られ、ユーザーからこれらの VM は見えない。VCN(仮想クラウド・ネットワーク)には API エンドポイントの IP が 1 つ現れるだけ |
| VCN / サブネット(Subnet) / セキュリティ・リスト(Security List) | 自分 | ルールを間違える → ノードが登録できない、LB がつながらない |
| ワーカー・ノード(Worker Node) | 自分(軽め) | シェイプ(Shape)、台数、イメージ(Image)。OS パッチと K8s のアップグレードは自分で開始する(イメージを変更 → ノードを 1 台ずつ入れ替え)。kubelet などは OKE がプリインストール |
| アプリケーション | 自分 | kubectl。LB / ブロック・ボリュームは K8s が間接的に作るもので、Terraform の state には含まれない |
| クラスタ・タイプ | コントロール・プレーン | 備考 |
|---|---|---|
BASIC_CLUSTER |
無料、SLA なし | 今回はこちらを使用 |
ENHANCED_CLUSTER |
時間課金 | SLA、アドオン管理、virtual nodes など |
| ノード・タイプ | 説明 |
|---|---|
| Managed nodes | ユーザーがノード・プール(Node Pool)を管理し、OKE が VM の作成と登録を担当(今回はこちらを使用) |
| Virtual nodes | フルマネージドで VM の概念がない(≒ AWS Fargate)。Pod 単位の課金で、Enhanced が必要 |
| Self-managed nodes | 自分で VM を作ってクラスタに参加させる |
ワーカー・ノードに対する考え方が変わる
Phase 2〜4 では nginx を cloud-init / Ansible で VM にインストールしていました。今は nginx がコンテナの中で動き、VM はコンテナを動かす場所にすぎません。 管理するのはその台数とバージョンで、中に何が入っているかは管理しません。壊れたら別の 1 台に入れ替え、修理はしません。
構成¶
flowchart LR
PC[ローカル PC my_ip] -->|:80| LB
CS[Cloud Shell<br/>private network] -->|kubectl :6443| API
subgraph OCI_ORACLE["Oracle のテナンシ(見えない)"]
CP[コントロール・プレーン]
end
subgraph VCN["VCN 10.6.0.0/16"]
subgraph SAPI["api 10.6.0.0/28 プライベート"]
API[K8s API エンドポイント]
end
subgraph SNODES["nodes 10.6.10.0/24 プライベート"]
N1[ワーカー A1 #1]
N2[ワーカー A1 #2]
end
subgraph SLB["lb 10.6.20.0/24 パブリック"]
LB[Service LB<br/>flexible 10Mbps]
end
end
CP --- API
API --> N1 & N2
LB -->|NodePort| N1 & N2
- Pod CIDR
10.244.0.0/16(flannel の overlay で、VCN の IP は消費しない)/ Service CIDR10.96.0.0/16 - ワーカー:A1.Flex 1 OCPU / 6GB ×2、ブート・ボリューム(Boot Volume)50GB ×2 → Always Free の範囲内
設計上の選択¶
API エンドポイントはプライベートにし、kubectl は Cloud Shell で実行¶
- ローカル PC には OCI CLI をインストールできない(Phase 5b のパス長の問題)が、kubeconfig の認証には
ociコマンドが必要 - Cloud Shell には
ociとkubectlが最初から入っている - パブリック・エンドポイントにした場合:Cloud Shell の送信元 IP は固定されない → 6443 を
0.0.0.0/0に開放するしかない(Phase 2 の SSH と同じ問題) - → API エンドポイントはプライベート・サブネットに置き、Cloud Shell は private network で
nodesサブネットに接続、6443 は nodes の CIDR にだけ開放
サブネットごとにセキュリティ・リストを 1 つ¶
Phase 4 の network モジュール(module)はすべてのサブネットで 1 つのセキュリティ・リストを共有していましたが、OKE ではサブネットごとに必要なルールが異なります → 今回はモジュールを使わず、リソースを直接書きました。
my_ip ──:80──→ [lb] LB ──:30000-32767 / :10256──→ [nodes] ワーカー ×2
[nodes] ワーカー / Cloud Shell ──:6443 / :12250──→ [api] K8s API エンドポイント
[api] コントロール・プレーン ──all──→ [nodes](kubelet 10250 など)
OKE にセキュリティ・リストを自動変更させない¶
cloud-controller-manager はデフォルトで LB 用のルールをセキュリティ・リストに自分で追加します → Terraform で管理しているセキュリティ・リストで、plan のたびにドリフト(drift)が出ます。
→ NodePort の範囲(30000-32767)とヘルスチェック・ポート(10256)を Terraform で事前に許可し、manifest で自動管理を無効にします。
metadata:
annotations:
service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "10"
oci.oraclecloud.com/security-rule-management-mode: "None"
結果:LB を作成したあとも terraform plan は No changes のまま ✅
ノード・イメージの自動選択¶
oci_containerengine_node_pool_option の sources を名前で絞り込みます:aarch64 + K8s バージョンが一致 + GPU 版を除外し、名前の降順で先頭を取ります(= 日付が最新のもの)。
node_images = {
for s in data.oci_containerengine_node_pool_option.this.sources : s.source_name => s.image_id
if length(regexall("^Oracle-Linux-[0-9.]+-aarch64-.*-OKE-${replace(local.k8s_ver, ".", "\\.")}-", s.source_name)) > 0
&& !strcontains(s.source_name, "GPU")
}
node_image_name = reverse(sort(keys(local.node_images)))[0]
操作手順¶
1. terraform apply¶
14 added。クラスタは約 7 分、ノード・プールは約 3 分。
補足
Terraform がノード・プールの "Creation complete" を表示しても、ノードが ready とは限りません。SDK の get_node_pool().nodes で各ノードが ACTIVE であることを確認します。
2. Cloud Shell を VCN に接続し、kubeconfig を生成¶
Cloud Shell の Network → Ephemeral private network setup → VCN tflab6-vcn / Subnet tflab6-subnet-nodes
oci ce cluster create-kubeconfig --cluster-id <cluster OCID> \
--file $HOME/.kube/config --region ap-osaka-1 \
--token-version 2.0.0 --kube-endpoint PRIVATE_ENDPOINT
kubectl get nodes -o wide
NAME STATUS ROLES VERSION OS-IMAGE CONTAINER-RUNTIME
10.6.10.228 Ready node v1.36.4 Oracle Linux Server 9.8 cri-o://1.36.3
10.6.10.92 Ready node v1.36.4 Oracle Linux Server 9.8 cri-o://1.36.3
- ワーカーだけで、control-plane ノードはない → マスターはマネージドなので見えない
- ノード名はプライベート IP。arm64
- コンテナ・ランタイムは CRI-O(Docker / containerd ではない)。K8s は CRI インターフェース経由で呼び出すだけなので、manifest には影響しない
3. nginx + Service LB をデプロイ¶
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx LoadBalancer 10.96.189.195 203.0.113.130 80:32248/TCP
- ローカル PC から
http://<EXTERNAL-IP>にアクセス →Welcome to nginx! 32248は NodePort。トラフィック:ローカル PC → LB:80 → node:32248 → kube-proxy → Pod:80(別のノード上の Pod に転送されることもある)- SDK で LB が
flexible10/10 Mbps であることを確認(annotation が有効) - この LB の名前は UUID で、タグがなく、Terraform の state にも含まれない → コンソール(GUI)では誰が作ったのかわかりにくい
Kubernetes の実験¶
自己修復¶
- すぐに新しい Pod が現れる:Deployment の期待値は
replicas: 2で、ReplicaSet が不足に気づいて補充する(reconcile loop) - 新しい Pod は名前も IP も変わる → Pod IP を直接使わず、Service 経由でアクセスする
- Terraform がドリフトを修正するのは apply を実行したときだけだが、K8s は常にバックグラウンドで自動修正している
flannel の IP 割り当て¶
あるノード上の Pod はすべて 10.244.1.x、もう一方はすべて 10.244.0.x → flannel はノードごとに /24 を 1 つ割り当てる。
スケール¶
scheduler が自動的に 2 + 2 に分け、2 台のノードに分散しました。
drain(ノード・メンテナンスの模擬)¶
- ノードが
Ready,SchedulingDisabledになり、その上の nginx(とcoredns)が退避され、もう一方のノードで再作成される - これがノード・プールのアップグレード時に OKE が自動で行うこと:cordon → drain → ノード入れ替え
drain 時に表示される DaemonSet = OKE が各ノードに配置しているコンポーネント:
| DaemonSet | 役割 |
|---|---|
kube-proxy |
Service / NodePort の転送 |
kube-flannel-ds |
Pod ネットワーク(overlay) |
csi-oci-node |
OCI ブロック・ボリュームのマウント |
proxymux-client |
コントロール・プレーン → ノードの通信経路。kubectl logs/exec はここを通る(セキュリティ・リストの 12250) |
oke-node-problem-detector |
ノードの異常検知 |
oke-dataplane-observability-agent |
監視エージェント |
uncordon のあと¶
- Pod は自動では戻りません:K8s がノードを選ぶのは新しい Pod を作るときだけで、自分から再配置はしない
- 2 にスケールダウンしたとき削除されたのは新しく作られた 2 つ → 結果として 2 つの Pod が同じノード上に = 冗長性がない
- 本番環境での対策:
topologySpreadConstraints/podAntiAffinity:Pod を別々のノードに強制的に分散PodDisruptionBudget:drain 時に最低 N 個の Pod が動いていることを保証- すでに偏っている場合:
kubectl rollout restart deployment nginxで再配置
クリーンアップ¶
順序が重要
kubectl delete -f nginx.yaml→ OKE が作った LB を OKE 自身に削除させる- LB がなくなったことを確認
- Cloud Shell の Network を Public に戻す
terraform destroy
順序が逆だと、LB が残って枠を使い続け(課金されることもあり)、VCN も削除できません。
ハマりどころ¶
nodes サブネットの削除に 8 分 41 秒かかった
サブネットに IP が 1 つ残っていて、名前は UUID → Cloud Shell の private network の VNIC でした。 Cloud Shell のウィンドウを閉じてから約 95 秒後にようやく解放されました。Terraform は競合があるとリトライし続けるので、最終的には自動で削除されました。
- 予防:destroy の前に Cloud Shell の Network を
Publicに戻しておく - 調査:
list_private_ips(subnet_id=...)でサブネットに何が残っているかを確認
kubectl delete pod 10.6.10.228 → NotFound
それはノード名です。Pod 名は nginx-598968dd58-xxxxx のような形式です。
コード全体¶
06-oke/oke.tf
# ------------------------------------------------------------
# OKE(Container Engine for Kubernetes):クラスタ = コントロール・プレーン(Control Plane)、ノード・プール(Node Pool)= ワーカー・ノード(Worker Node)
# 費用:BASIC_CLUSTER のコントロール・プレーンは無料。ENHANCED_CLUSTER は時間課金 → 使用しない
# ワーカー = A1.Flex(Always Free 枠内)。Service LB は annotation で flexible 10Mbps を指定
# ------------------------------------------------------------
data "oci_identity_availability_domains" "this" {
compartment_id = var.compartment_ocid
}
# ノード用のイメージ(Image):OKE 専用の Oracle Linux(kubelet 等がプリインストール済み)
# 名前の例:Oracle-Linux-9.8-aarch64-2026.09.18-0-OKE-1.36.4-1923
# 条件:aarch64(A1 は ARM)+ K8s バージョンと一致 + GPU 版は除外 → 名前の降順で先頭を取得(= 最新日付)
data "oci_containerengine_node_pool_option" "this" {
node_pool_option_id = "all"
compartment_id = var.compartment_ocid
}
locals {
k8s_ver = trimprefix(var.kubernetes_version, "v")
node_images = {
for s in data.oci_containerengine_node_pool_option.this.sources : s.source_name => s.image_id
if length(regexall("^Oracle-Linux-[0-9.]+-aarch64-.*-OKE-${replace(local.k8s_ver, ".", "\\.")}-", s.source_name)) > 0
&& !strcontains(s.source_name, "GPU")
}
node_image_name = reverse(sort(keys(local.node_images)))[0]
}
resource "oci_containerengine_cluster" "this" {
compartment_id = var.compartment_ocid
name = "${local.name_prefix}-oke"
kubernetes_version = var.kubernetes_version
vcn_id = oci_core_vcn.this.id
type = "BASIC_CLUSTER" # ENHANCED_CLUSTER は有料
cluster_pod_network_options {
cni_type = "FLANNEL_OVERLAY"
}
# API エンドポイントはプライベート・サブネット(Subnet)に配置し、パブリック IP は割り当てない → VCN(仮想クラウド・ネットワーク)内からのみアクセス可能(Cloud Shell のプライベート・ネットワーク)
endpoint_config {
subnet_id = oci_core_subnet.api.id
is_public_ip_enabled = false
}
options {
# Service type=LoadBalancer のロード・バランサ(Load Balancer)はこのサブネットに作成
service_lb_subnet_ids = [oci_core_subnet.lb.id]
kubernetes_network_config {
pods_cidr = "10.244.0.0/16" # flannel のオーバーレイ用。VCN と重複しなければよい
services_cidr = "10.96.0.0/16" # ClusterIP 用
}
}
freeform_tags = local.common_tags
}
resource "oci_containerengine_node_pool" "this" {
compartment_id = var.compartment_ocid
cluster_id = oci_containerengine_cluster.this.id
name = "${local.name_prefix}-pool"
kubernetes_version = var.kubernetes_version
node_shape = "VM.Standard.A1.Flex"
node_shape_config {
ocpus = 1
memory_in_gbs = 6
}
node_source_details {
source_type = "IMAGE"
image_id = local.node_images[local.node_image_name]
boot_volume_size_in_gbs = 50 # 最小値。ブロック・ボリューム(Block Volume)は合計 200GB まで無料
}
node_config_details {
size = var.node_count
# 大阪は可用性ドメイン(Availability Domain)が 1 つのみ
placement_configs {
availability_domain = data.oci_identity_availability_domains.this.availability_domains[0].name
subnet_id = oci_core_subnet.nodes.id
}
node_pool_pod_network_option_details {
cni_type = "FLANNEL_OVERLAY"
}
freeform_tags = local.common_tags
}
freeform_tags = local.common_tags
}
06-oke/security.tf
# ------------------------------------------------------------
# セキュリティ・リスト(Security List):サブネット(Subnet)ごとに 1 つ(ルールは OKE ドキュメントの flannel の例を参考に、Always Free の検証用に最小化)
#
# my_ip ──:80──→ [lb] LB ──:30000-32767 / :10256──→ [nodes] ワーカー ×2
# [nodes] ワーカー / Cloud Shell ──:6443 / :12250──→ [api] K8s API エンドポイント
# [api] コントロール・プレーン ──all──→ [nodes](kubelet 10250 等)
#
# Service LB のルールは OKE に自動変更させない:
# cloud-controller-manager はデフォルトでセキュリティ・リストに自らルールを追加する → Terraform 管理のセキュリティ・リストで毎回 plan にドリフト(drift)が出る
# → ここで NodePort 範囲を事前に許可し、manifest 側で annotation により自動管理を無効化(k8s/nginx.yaml)
# ------------------------------------------------------------
locals {
node_port_min = 30000
node_port_max = 32767
kube_proxy_hc = 10256 # LB のヘルスチェックは kube-proxy の /healthz 宛て
services_cidr_sg = data.oci_core_services.all.services[0].cidr_block
}
# ---- api(K8s API エンドポイント)----
resource "oci_core_security_list" "api" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-sl-api"
# ワーカーと Cloud Shell(いずれも nodes サブネット)→ kube-apiserver
ingress_security_rules {
source = local.subnet_cidrs.nodes
protocol = "6"
description = "kube-apiserver from nodes / Cloud Shell"
tcp_options {
min = 6443
max = 6443
}
}
# ワーカー → コントロール・プレーン(Control Plane)の通信(OKE 専用ポート)
ingress_security_rules {
source = local.subnet_cidrs.nodes
protocol = "6"
description = "worker to control plane"
tcp_options {
min = 12250
max = 12250
}
}
ingress_security_rules {
source = local.subnet_cidrs.nodes
protocol = "1"
icmp_options {
type = 3
code = 4
}
}
# コントロール・プレーン → ワーカー(kubelet 10250、exec / logs 等)
egress_security_rules {
destination = local.subnet_cidrs.nodes
protocol = "all"
description = "control plane to workers"
}
# コントロール・プレーン → OKE / OCI の API(サービス・ゲートウェイ(Service Gateway)経由)
egress_security_rules {
destination = local.services_cidr_sg
destination_type = "SERVICE_CIDR_BLOCK"
protocol = "6"
description = "to OCI services"
tcp_options {
min = 443
max = 443
}
}
freeform_tags = local.common_tags
}
# ---- nodes(ワーカー・ノード(Worker Node)+ Cloud Shell)----
resource "oci_core_security_list" "nodes" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-sl-nodes"
# ノード間はすべて許可(flannel のオーバーレイ = UDP 8472 / Pod 間の通信)
ingress_security_rules {
source = local.subnet_cidrs.nodes
protocol = "all"
description = "node to node / pod to pod"
}
ingress_security_rules {
source = local.subnet_cidrs.api
protocol = "6"
description = "control plane to workers"
}
ingress_security_rules {
source = local.subnet_cidrs.lb
protocol = "6"
description = "LB to NodePort"
tcp_options {
min = local.node_port_min
max = local.node_port_max
}
}
ingress_security_rules {
source = local.subnet_cidrs.lb
protocol = "6"
description = "LB health check to kube-proxy"
tcp_options {
min = local.kube_proxy_hc
max = local.kube_proxy_hc
}
}
ingress_security_rules {
source = "0.0.0.0/0"
protocol = "1"
icmp_options {
type = 3
code = 4
}
}
# エグレス:インターネット(NAT)、OCI サービス(SGW)、API エンドポイントをすべて許可
egress_security_rules {
destination = "0.0.0.0/0"
protocol = "all"
}
freeform_tags = local.common_tags
}
# ---- lb(Service LB)----
resource "oci_core_security_list" "lb" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-sl-lb"
ingress_security_rules {
source = "${var.my_ip}/32"
protocol = "6"
description = "HTTP from my IP"
tcp_options {
min = 80
max = 80
}
}
egress_security_rules {
destination = local.subnet_cidrs.nodes
protocol = "6"
description = "LB to NodePort"
tcp_options {
min = local.node_port_min
max = local.node_port_max
}
}
egress_security_rules {
destination = local.subnet_cidrs.nodes
protocol = "6"
description = "LB health check to kube-proxy"
tcp_options {
min = local.kube_proxy_hc
max = local.kube_proxy_hc
}
}
freeform_tags = local.common_tags
}
06-oke/network.tf
# ------------------------------------------------------------
# Phase 6:OKE(Container Engine for Kubernetes)用のネットワーク(flannel オーバーレイ版)
# VCN(仮想クラウド・ネットワーク) 10.6.0.0/16 ─ IGW / NAT GW / Service GW
# ├─ api 10.6.0.0/28 private:K8s API エンドポイント(パブリック IP なし)
# ├─ nodes 10.6.10.0/24 private:ワーカー・ノード(Worker Node)。Cloud Shell のプライベート・ネットワークもここに接続
# └─ lb 10.6.20.0/24 public :Service type=LoadBalancer が作成する OCI ロード・バランサ(Load Balancer)
# Pod の IP(10.244.0.0/16)は flannel がノード間でオーバーレイ化するため、VCN の IP は消費しない
#
# 04 のネットワーク・モジュール(module)は「全サブネット(Subnet)で 1 つのセキュリティ・リスト(Security List)を共用」する構成だが、
# OKE はサブネットごとに必要なルールが異なる → ここではモジュールを使わず、リソースを直接記述(セキュリティ・リストは security.tf)
# ------------------------------------------------------------
locals {
name_prefix = "tflab6"
vcn_cidr = "10.6.0.0/16"
subnet_cidrs = {
api = "10.6.0.0/28"
nodes = "10.6.10.0/24"
lb = "10.6.20.0/24"
}
common_tags = {
project = "tf-lab"
managed_by = "terraform"
phase = "6"
}
}
resource "oci_core_vcn" "this" {
compartment_id = var.compartment_ocid
cidr_blocks = [local.vcn_cidr]
display_name = "${local.name_prefix}-vcn"
dns_label = local.name_prefix
freeform_tags = local.common_tags
}
# ---- Gateway ----
resource "oci_core_internet_gateway" "this" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-igw"
enabled = true
freeform_tags = local.common_tags
}
# ワーカー・ノードが Docker Hub 等の外部イメージを pull するために使用
resource "oci_core_nat_gateway" "this" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-natgw"
freeform_tags = local.common_tags
}
data "oci_core_services" "all" {
filter {
name = "name"
values = ["All .* Services In Oracle Services Network"]
regex = true
}
}
# ワーカー・ノードの OKE への登録、OCIR イメージの pull、Cloud Shell のトークン取得(containerengine API)はすべてここを経由
resource "oci_core_service_gateway" "this" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-sgw"
services {
service_id = data.oci_core_services.all.services[0].id
}
freeform_tags = local.common_tags
}
# ---- Route Table ----
resource "oci_core_route_table" "public" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-rt-public"
route_rules {
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.this.id
}
freeform_tags = local.common_tags
}
resource "oci_core_route_table" "private" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
display_name = "${local.name_prefix}-rt-private"
route_rules {
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_nat_gateway.this.id
}
route_rules {
destination = data.oci_core_services.all.services[0].cidr_block
destination_type = "SERVICE_CIDR_BLOCK"
network_entity_id = oci_core_service_gateway.this.id
}
freeform_tags = local.common_tags
}
# ---- Subnet ----
resource "oci_core_subnet" "api" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
cidr_block = local.subnet_cidrs.api
display_name = "${local.name_prefix}-subnet-api"
dns_label = "api"
route_table_id = oci_core_route_table.private.id
security_list_ids = [oci_core_security_list.api.id]
prohibit_public_ip_on_vnic = true
freeform_tags = local.common_tags
}
resource "oci_core_subnet" "nodes" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
cidr_block = local.subnet_cidrs.nodes
display_name = "${local.name_prefix}-subnet-nodes"
dns_label = "nodes"
route_table_id = oci_core_route_table.private.id
security_list_ids = [oci_core_security_list.nodes.id]
prohibit_public_ip_on_vnic = true
freeform_tags = local.common_tags
}
resource "oci_core_subnet" "lb" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.this.id
cidr_block = local.subnet_cidrs.lb
display_name = "${local.name_prefix}-subnet-lb"
dns_label = "lb"
route_table_id = oci_core_route_table.public.id
security_list_ids = [oci_core_security_list.lb.id]
prohibit_public_ip_on_vnic = false
freeform_tags = local.common_tags
}
06-oke/k8s/nginx.yaml
# nginx ×2 + Service type=LoadBalancer
# Cloud Shell で実行:kubectl apply -f nginx.yaml
# 削除時:先に kubectl delete -f nginx.yaml で、OKE が作成した LB を OKE 自身に削除させる → その後 terraform destroy
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27 # multi-arch イメージ(Image)のため A1(arm64)でも動作
ports:
- containerPort: 80
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
# flexible 10Mbps = Always Free のロード・バランサ(Load Balancer)(未指定の場合はデフォルトで 100Mbps の LB となり、Always Free を超過)
service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "10"
# OKE にセキュリティ・リスト(Security List)を自動変更させない(ルールは Terraform の security.tf に記述済み)
oci.oraclecloud.com/security-rule-management-mode: "None"
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80