完全マネージドな k8s ! GKE Autopilot を解説する

Kazuu
google-cloud-jp
Published in
17 min readFeb 24, 2021

Kubernetes / GKE ファンの皆様こんにちわ。Google Cloud の Kazuu (かずー) です。GKE Autopilot が GA になりました。弊社公式ブログに続きまして、GKE Autopilot を日本語で解説していきたいと思います。
本記事は以下、3 部構成となります。

  1. GKE Autopilot 概要
  2. GKE Autopilot を試してみる
  3. GKE Autopilot がハマりそうなユースケースは?

1. GKE Autopilot 概要

GKE Autopilot は GKE の新しいモードです。Control Plane に加えて、Node が完全マネージドになります。これまでの GKE では Node はユーザー自身が必要台数分作成し、以後の Day 2 オペレーション (e.g. アップグレード) 等も気に掛ける必要がありました。GKE Autopilot では Node は Control Plane と同様、Google の SRE が管理することになります。

GKE Autopilot の登場により、今後 GKE は以下 2 つのモードが存在することになります。

  • GKE Standard (従来の GKE)
  • GKE Autopilot

GKE Autopilot にすると何が嬉しいのか?

簡単にまとめると以下 2 点になるかと思います。

  • 運用がより簡単に
    Node の管理が無くなったことで、Day 2 オペレーションが軽減され、ユーザーはワークロードに集中して運用を行うことが出来るようになります。0 から Kubernetes をはじめる場合においても、より導入がしやすくなるかと思います。
  • コストの最適化
    これまでの GKE では予めプロビジョニングした Node (GCE のインスタンス) に対して課金が発生しており、実際には Pod として利用されていないリソース分までが課金対象になっていましたが、GKE Autopilot では Pod 単位での課金となり、ケースバイケースですがコストを最適化することが可能です。

従来の GKE との相違点

  • Node は Pod のスケジューリングに合わせて必要量が自動的にプロビジョニングされます、ユーザー自身で Node を 直接作成したり、追加したり、削除したり出来ません。GKE Autopilot では Cluster autoscaler 及び Node auto provisioning がデフォルトで有効になっています。(無効化できません)
  • Node のイメージは cos_containerd です。変更できません。
  • Autopilot の Node (GCE のインスタンス) はユーザーの VPC 内に存在し他の VPC 内リソースとのネットワーク接続性もありますが、$ gcloud compute instaces list してもユーザーからは見えません。
    ただし $ kubectl get nodes では確認出来ます。
  • Node pool にデフォルトで付いていた GCE のサービスアカウントはありません。その代わりデフォルトで Workload Identity が有効になっています。
  • クラスタのタイプはリージョン クラスタとなります、リリースチャネルに登録されており、Control plane / Node ともにオートアップグレードが有効になっており変更出来ません。2021 年 2 月 25 日 現時点では Rapid / Regular チャネルから選択可能です。
  • Pod レベルで SLA が付きます。2 つないし 3 つの zone のNode に跨ってスケジュールされた Pod は 99.9 % の SLO が設定されます。
  • 利便性とのトレードオフでいくつか制約があります。(後述)
  • ユーザーは Pod レベルで課金されます。(後述)

構成のイメージ

従来の GKE と同様、Public Cluster と Private Cluster (Node に Public IP が付かない) からクラスタ作成時に選択可能です。以下は Private Cluster の場合のイメージですが、アーキテクチャとしては GKE Standard と同じです。ユーザーの VPC 内に存在するのでネットワーク的な条件は変わりません。ただ、Node がユーザーからは見えなく & 弄れなくなります。

Node / Pod のスペックや決まりごと

Node のデフォルトのマシンタイプは e2-medium です。
スケジューリングされた Pod のサイズに応じて、Node auto provisioning により必要なサイズの Node が自動作成されます。e2-medium に収まる Pod サイズの場合はそのまま Cluster autoscaler により e2-medium の Node が水平スケールします。

デフォルトの Pod のスペックは以下の通りです。

  • CPU: 0.5 vCPU
  • Memory: 2GiB
  • Ephemeral Storage: 1GiB

CPU は 0.25 vCPU 単位でインクリメントされます。
中途半端な値を指定すると自動で是正されるので注意してください。
# Pod anti-affinity を使った場合は0.5 vCPU 刻みになります。
e.g. 0.66 vCPU >> 0.75 vCPU

CPU と Memory は 1 対 6.5 の割合以内に収まっている必要があります。
こちらもルールに則っていないと自動で是正されます。
e.g.1vCPU & 7 G Memory>> 1.25 vCPU & 7 GB Memory

Ephemeral storage は 10MiB and 10 GiB の間で割当可能です。

このあたりの決まりごとは公式ドキュメントにが記載されていますので確認してみてください。

主な制約 (詳細はこちら)

  • Privileged pod は利用出来ません。
  • HostPort や HostNetwork は利用出来ません。hostPath は /var/log に対する read のみ利用可能です。
  • sysctl や kubelet のパラメーター チューニングは出来ません。
  • 2021 年 2 月 24 日時点ではマシンタイプは e2 シリーズのみ、GPUサポートはありません。
  • Guaranteed QoS Class です。(request/limit が同じ値である必要あり)
  • Node へは SSH でアクセスすることが出来ません。
  • nodeSelector、nodeAffinity/nodeAntiAffinity 利用できる Key は限定されます。詳細はこちらをご確認ください。
  • Tolerations は workload を分離して配置する目的でのみ利用可能です、Taints は Node auto provisioning 時に自動的に追加されます。
  • リリースチャネル により Control plane / Node ともに自動アップグレードがデフォルトで有効です。(変更出来ません)

価格

vCPU / Memory / Ephemeral storage に対して時間課金されます。以下は東京リージョンの例です。詳細はこちらをご確認ください。

2. GKE Autopilot を試してみる

GKE Autopilot はあくまで GKE のいち機能に過ぎないので、APIを新たに有効する必要はありません。
以下のコマンドでクラスタを作成します。`create-auto` になっているところがポイントです。コマンド実行しようとして「そんなコマンドないよ」と怒られた場合は、 `gcloud components update` を実行してから再度試してみてください。Network や Subnet は GKE Standard と同様に指定します。VPC Native Cluster なので Services や Pod で使う IP アドレスレンジも指定しておきます。デフォルトは Public Cluster ですが、今回は Private Cluster で作ってみます、そのため Control plane (Master) の IP アドレスレンジも指定しておきます。

❯ gcloud container clusters create-auto $CLUSTER_NAME \
--impersonate-service-account=$SERVICE_ACCOUNT_EMAIL \
--release-channel=rapid \
--region=$REGION \
--project $PROJECT_ID \
--network=vpc-01 \
--subnetwork=subnet-11 \
--services-secondary-range-name=service \
--cluster-secondary-range-name=pod \
--enable-private-nodes \
--master-ipv4-cidr=10.255.255.0/28```

Private Cluster では各 Node に External IP が無いので、Pod を作成してもそこから直接外部へ接続することは出来ません。そのため Cloud NAT を作っておきます。

❯ gcloud compute routers create router-01 \
--network vpc-01 \
--region us-central1 \
❯ gcloud compute routers nats create nat-01 \
--region us-central1 \
--router router-01 \
--nat-all-subnet-ip-ranges \
--auto-allocate-nat-external-ips \

GKE Autopliot の話に戻ります。クラスタの作成が完了した直後のNodeの状態です。e2-medium が 2 つ。e2-medium は 2vCPUs / 4 GB メモリのインスタンスタイプです。

❯ k get nodes -L beta.kubernetes.io/instance-type
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE
gk3-auto-cluster-01-default-pool-20884490-n2ll Ready <none> 94m v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-b8b54a97-g1kf Ready <none> 94m v1.18.12-gke.1210 e2-medium```

NS: kube-system の pod はGKE Standard と変わらないので割愛します。私が試した環境では Node Local DNSCacheGCE PD の CSI Driver がデフォルトで有効になっていました。この辺は GKE の最新のベストプラクティスが積極的に採用されています。

ユーザーからは Autopilot で使われてる GCE のインスタンスは見えません。#ただしネットワークの接続性はあります

❯ gcloud compute instances list
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS

では早速ワークロードをデプロイして挙動を確認してみましょう。
0.25 vCPU 、1G の Memory をリクエストしたコンテナ (Pod) を 6 つ作ります。

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi
spec:
replicas: 6
selector:
matchLabels:
app: fastapi
template:
metadata:
labels:
app: fastapi
spec:
containers:
- name: fastapi-container
image: gcr.io/kzs-sandbox/fastapi:v1
resources:
requests:
cpu: 250m
memory: 1Gi
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
EOF

2 つの e2-medium ではリソースが不足してるので、Cluster autoscaler により、e2-medium の Node が 3 つ追加され、Pod も作成されました。

❯ k get nodes -L beta.kubernetes.io/instance-type
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE
gk3-auto-cluster-01-default-pool-20884490-n2ll Ready <none> 157m v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-20884490-q3tm Ready <none> 4m48s v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-20884490-zm4b Ready <none> 4m46s v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-b8b54a97-bzjv Ready <none> 4m12s v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-b8b54a97-g1kf Ready <none> 157m v1.18.12-gke.1210 e2-medium
❯ k get pods
NAME READY STATUS RESTARTS AGE
fastapi-7497884bb-4gtg8 1/1 Running 0 4m55s
fastapi-7497884bb-rcpsd 1/1 Running 0 4m55s
fastapi-7497884bb-sfm5s 1/1 Running 0 4m55s
fastapi-7497884bb-vs7fj 1/1 Running 0 4m55s
fastapi-7497884bb-xv99c 1/1 Running 0 4m55s
fastapi-7497884bb-z2922 1/1 Running 0 4m55s

コンテナのサイズを e2-medium ではホスト出来ないくらい大きなサイズに変更してみます。

❯  kubectl patch deployment fastapi -p '{"spec":{"template":{"spec":{"containers":[{"name":"fastapi-container", "resources":{"requests":{"cpu":"3000m","memory":"6Gi"}}}]}}}}'

Node auto-provisioning により適切なスペックの Node が新たに作成され、Pod (新たに指定したサイズのコンテナ)が再作成されます。結果としては、クラスタ作成当初から存在する e2-medium の Node * 2 はそのままに、e2-standard-4 の Node が 4 つ追加されました。

❯ k get nodes -L beta.kubernetes.io/instance-type
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE
gk3-auto-cluster-01-default-pool-20884490-n2ll Ready <none> 166m v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-default-pool-b8b54a97-g1kf Ready <none> 167m v1.18.12-gke.1210 e2-medium
gk3-auto-cluster-01-nap-11p3vkbo-90134ae9-25mg Ready <none> 6m58s v1.18.12-gke.1210 e2-standard-4
gk3-auto-cluster-01-nap-11p3vkbo-90134ae9-39z6 Ready <none> 5m36s v1.18.12-gke.1210 e2-standard-4
gk3-auto-cluster-01-nap-11p3vkbo-90134ae9-x78w Ready <none> 5m44s v1.18.12-gke.1210 e2-standard-4
gk3-auto-cluster-01-nap-11p3vkbo-93cde396-h4v6 Ready <none> 6m54s v1.18.12-gke.1210 e2-standard-4
gk3-auto-cluster-01-nap-11p3vkbo-93cde396-qchf Ready <none> 6m56s v1.18.12-gke.1210 e2-standard-4
gk3-auto-cluster-01-nap-11p3vkbo-93cde396-x965 Ready <none> 5m36s v1.18.12-gke.1210 e2-standard-4
❯ k get pods
NAME READY STATUS RESTARTS AGE
fastapi-78d8b9c746-5cd45 1/1 Running 0 8m29s
fastapi-78d8b9c746-cfk6k 1/1 Running 0 6m45s
fastapi-78d8b9c746-khkkv 1/1 Running 0 8m30s
fastapi-78d8b9c746-m7tr7 1/1 Running 0 6m54s
fastapi-78d8b9c746-nqjpm 1/1 Running 0 8m30s
fastapi-78d8b9c746-x8xkm 1/1 Running 0 6m50s

3. GKE Autopilot がハマりそうなユースケース

GKE Autopilot の特徴を改めて整理してみると、

  • Pod : Node は n : 1だが、スケジュールされた Pod に必要なリソースが既存の Node にない場合は、Node を水平スケールしたり適切なマシンタイプの Node を新規で作成する。Podが終了すれば不要な Node は削除される。
  • 予め Node だけたくさん用意しておいて、負荷に応じて HPA で Pod だけ高速にスケールさせるという方法は取れない。# PriorityClassを使って予め Balloon Pod を作って余剰 Capacity を作っておくことで、高速にスケールアウトさせる方法はあるようです。詳しくはこちら
  • Pod 単位の課金。
  • Kubernetes の Control plane 及び Node の運用をユーザーが行わなくてよい。

上記からハマりそうなユースケースを考えみると、

  • バッチ
    並列で重めの処理とか/ ML やデータ基盤系など。課金体系的にも、ある一定の時間内で処理を行って役割を終える類のものが向いてそうです。
  • 必要リソースに変動の少ない Static なシステム
    Cluster autoscaler や Node auto provisioning により Node の作成 > Pod の作成 になることが多いので、オートスケール自体のスピードは早くないです。スパイクがあまりなく、オートスケールのスピードを要求しないケースに向いていると思います。
  • 大規模かつ大量のリクエストトラフィックを捌かないシステム
    Node 周りの設定は一切弄れないため、、パフォーマンス向上目的でNode のカーネル パラメータを弄らなくてよいシステムに向いています。
  • ステートレスなアプリケーション
    自動アップグレードが必須のため、Pod 自体に State を持たせないアプリケーションだとサービスへのクリティカルな影響は最小限にして運用が行えると思います。

如何だったでしょうか? いくつか考慮すべき制約はあるものの、利便性が大きく向上し、これまで Kubernetes / GKE に中々飛び込めなかった方や、もっと楽に Kubernetes を利用したかった方には喜んでもらえるのではないかなと思います。みなさんも是非 GKE Autopilot を試してみてください!

--

--

Kazuu
google-cloud-jp

Customer Engineer at Google Cloud Japan. GKE & Cloud Run enthusiast. Opinions are my own, NOT views of my employer.