社内プロダクトではこんな感じで GKE Autopilot を使ってます

注意する箇所
Terraform
- google provider のバージョンを一定以上に上げる必要がある
- 公式の GCP Terraform Module では,
enable_autopilotオプションは未サポート
→google_container_clusterリソースを使用する - 設定できないアドオンを記述している場合はエラーが出るので削除する
利用できるアドオン
- HTTP ロードバランシング (NEG等)
- VPA (垂直 Pod オートスケーリング)
デフォルト
- CSI ドライバ
- NodeLocal DNSCache
利用できないアドオン
- DataPlane V2 (Cillium)
GKE Autopilot Terraform Sample
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.90.1"
}
google-beta = {
source = "hashicorp/google-beta"
version = "3.90.1"
}
}
}
resource "google_container_cluster" "synthetics" {
provider = google
name = "${local.name}-synthetics"
project = var.project_id
location = var.region
node_locations = ["${var.region}-a", "${var.region}-b", "${var.region}-c"]
network = google_compute_network.this.id
enable_autopilot = true
release_channel {
channel = "REGULAR"
}
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "10.0.2.0/28"
}
subnetwork = "projects/${var.project_id}/regions/${var.region}/subnetworks/${google_compute_subnetwork.tokyo.name}"
min_master_version = local.gke_min_release_version
logging_service = "logging.googleapis.com/kubernetes"
monitoring_service = "monitoring.googleapis.com/kubernetes"
vertical_pod_autoscaling {
enabled = true
}
master_authorized_networks_config {
dynamic "cidr_blocks" {
for_each = merge(
local.master_authorized_networks_config,
var.additional_master_authorized_networks_config
)
content {
cidr_block = cidr_blocks.value.cidr_block
display_name = cidr_blocks.value.display_name
}
}
}
addons_config {
http_load_balancing {
disabled = false
}
horizontal_pod_autoscaling {
disabled = false
}
}
ip_allocation_policy {
cluster_secondary_range_name = local.pod_2_range_name
services_secondary_range_name = local.service_2_range_name
}
maintenance_policy {
daily_maintenance_window {
start_time = "15:00"
}
}
lifecycle {
ignore_changes = [node_pool, initial_node_count, resource_labels["asmv"], resource_labels["mesh_id"]]
}
timeouts {
create = "45m"
update = "45m"
delete = "45m"
}
}
Spot Instance (≒ Preemptive / SpotVM)
- GKE クラスタ構築時には特に設定の必要はなし
- Pod の NodeSelector に
cloud.google.com/gke-spot=trueを指定する - Spot 含めて、課金は Pod が利用するリソース単位で kube-system の Pod は含まれない
スポットの場合
- CPU = 1vCPU/H: $0.0133 = 1.6円
- Memory = 1GB/H: $0.0014767 = 18円
- Volume = 1GB/H: $0.0000548 = 0.007円
リソースの制限参考
- デフォルト:CPU (500m) / Memory (2GiB) / Storage (1GiB)
- 最低:CPU (250m) / Memory (512MiB) / Storage (10MiB)
※ クラスタの料金は別途かかります
運用
考えないこと
Cluster / Node のアップグレードの実施
→ 利用するリソースの API Version 互換性を追従しメンテナンスすることは必要
Node / Pod のスケール実施
→ 自動で実施してくれるため静観
※ Cluster Autoscaler がたまにエラーを吐いてスケールできないことがあるのでそこの監視は忘れずに
考えること
ロギング
実行が終了して空いたノードに関しては,縮退されるので Cloud Logging でみるのがいいかも(例 CronJob / Job など)
早めのスケールをしたい
Scheduling API の PriorityClass を低めに設定した バルーン Pod を設置する Adding spare capacity to GKE Autopilot with balloon pods
- 余剰リソースを停止すれば,Pod がスケジュールできると判断すればそのように動く (数秒待機)
- 余剰リソースを停止してもスケジュールできないと判断すればノードを増やす (数分待機)
- Helm とか実行する時に admission 系の Pod が検査してから流すタイプのやつは待機時間があるので注意が必要
注意
余剰バルーンをどれくらい用意するかで「コスト」や「余剰リソースで差し替え可能か」が決まること
kube-system の制限
参照のみ許可されている
→ 地道に検索
注意
- ツール や Helm Charts によっては default で kube-system にリソースを作成するものもある
例:argocd cluster add ${KUBE_CONTEXT} -system-namespace kube-system
| Resource | GET | CREATE | UPDATE | DELETE |
| pods | ○ | × | × | × |
| sa | ○ | × | × | × |
| role | ○ | ○ | ○ | ○ |
| rolebinding | ○ | ○ | ○ | ○ |
| others | ○ | × | × | × |
ノードの制限
参照のみ許可されている
kubectl api-resources --namespaced=false -o wide
注意
- Node にラベル付与等はできない
- ある Pod と ある Pod を同じノードで管理したくない場合は,
PodAntiAffinityで頑張る
ノードに対する権限
| Resource | GET | CREATE | UPDATE | DELETE |
| nodes (NodeMetrics) | ○ | × | × | × |
Affinity に利用できそうな topologyKey
| Key Name |
| failure-domain.beta.kubernetes.io/region |
| failure-domain.beta.kubernetes.io/zone |
| kubernetes.io/hostname |
Affinity のサンプル
- 外形監視 Pod (k6-core / blackbox-exporter) 用
管理系のPodと同居させたくない場合
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/instance
operator: In
values:
- external-dns
- kube-prometheus-stack
- kube-prometheus-stack-alertmanager
- prometheus-statsd-exporter
- victoria-metrics
- kube-prometheus-stack-prometheus
topologyKey: kubernetes.io/hostname
- 管理系の Pod にも Affinity いれるとよい
例:app.kubernetes.io/part-of=service/app.kubernetes.io/part-of=system - ここら辺のラベルを埋め込んでると楽かも
Pod Security Policy
利用できません.GKE Autopilot は GateKeeper になります
注意
helm で rbac.pspEnabled 系のパラメータは OFF にすること
PSP → Gatekeeper をどう扱うべきか
利用する場合は、Helm Chart が対応されるまで気合い ?
例 https://github.com/appvia/psp-migration
任意のポリシーエンジンに変換して出力してくれるツール
Helm template で特定のチャートファイルだけ出力して変換する例
helm template test prometheus-community/kube-prometheus-stack -s templates/prometheus-operator/psp.yaml --set global.rbac.pspEnabled=true | psp-migration --engine=gatekeeper | pbcopy
リソース名は変わらないので,更にいじるなら Kustomize … ?
kustomize helm plugin
- base/kustomization.yaml
helmCharts:
- name: minecraft
includeCRDs: false
valuesInline:
minecraftServer:
eula: true
difficulty: hard
rcon:
enabled: true
releaseName: moria
version: 3.1.3
repo: https://itzg.github.io/minecraft-server-charts
# 利用できるパラメータ (https://github.com/kubernetes-sigs/kustomize/blob/2fe04496c285bc2fa7a7233a7a584ab96e21f88d/api/types/helmchartargs.go#L33)
コメント
- helmfile とか使ってる方達は作業量ほぼ変わらなさそうなので意外と良い
- kustomize に集約できるのはそれはそれで嬉しい
- ksops + secret generator で helm value の復号ができるかは要調査
psp-migration
- Before
# Source: kube-prometheus-stack/templates/prometheus-operator/psp.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: test-kube-prometheus-stack-operator
labels:
app: kube-prometheus-stack-operator
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: test
app.kubernetes.io/version: "33.2.1"
app.kubernetes.io/part-of: kube-prometheus-stack
chart: kube-prometheus-stack-33.2.1
release: "test"
heritage: "Helm"
spec:
privileged: false
# Allow core volume types.
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
# Permits the container to run with root privileges as well.
rule: 'RunAsAny'
seLinux:
# This policy assumes the nodes are using AppArmor rather than SELinux.
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
# Allow adding the root group.
- min: 0
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
# Allow adding the root group.
- min: 0
max: 65535
readOnlyRootFilesystem: false
- After
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: psp-k8spspprivilegedcontainer-219e3
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters: null
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
name: psp-k8spsphostnamespace-21bdb
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters: null
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
name: psp-k8spsphostnetworkingports-f1289
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters:
hostNetwork: false
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPVolumeTypes
metadata:
name: psp-k8spspvolumetypes-b8f49
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters:
volumes:
- configMap
- emptyDir
- projected
- secret
- downwardAPI
- persistentVolumeClaim
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
name: psp-k8spspallowedusers-ec048
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters:
supplementalGroups:
rule: MustRunAs
ranges:
- min: 0
max: 65535
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
name: psp-k8spspallowedusers-de2b6
spec:
match:
kinds:
- apiGroups:
- ""
kinds:
- Pod
parameters:
fsGroup:
rule: MustRunAs
ranges:
- min: 0
max: 65535
まとめ
良い点
- GateKeeper がこういう設定にしてねと怒ってくれるの体験がいい楽
- kubectl を使える (Kubernetes をよく使う人にとってはインターフェースが変わらず嬉しい)
- GKE のノードスケールよりも多分早い (1分ちょい)
- Daemonset が使えます (EKS Fargate 比較)
悪い点
- たまにクラスタ修復中ですになり、利用料金見るとちょっと値引きされてる
- (人によっては) e2シリーズのインスタンスタイプのみ利用する (amd64)