tk_ch’s blog

インフラエンジニアのブログ

GCP 検証用GKEクラスタを作成する(K8s v1.25)

Kubernetes(K8s)の検証をしたいけど自分でK8sクラスタを立てるのは面倒、、、というときは、パブリッククラウドKubernetesサービスを使うと便利。
中でもGoogle Cloud Platform(GCP)のKubernetesサービスであるGoogle Kubernetes Engine(GKE)はクラスタ作成にかかる時間が短く、無料枠も充実しているのでよく使っている。
検証用のGKEクラスタを準備した際のメモを残しておく。

※無料枠について(2022年10月時点)

  • GCPは、アカウントごとに1回だけ、無料プログラムとして90 日間有効な300ドル分のクレジットを提供してくれる。
  • GKEは、クラスタが存在するだけで1時間1クラスタあたり0.10ドルのクラスタ管理手数料がかかる。
    しかし、GKEの無料枠として1クラスタ分のクラスタ管理手数料相当のクレジット(月額74.40ドル)が毎月提供されるので、1クラスタまではクラスタ管理手数料が実質無料になっている(上記の無料プログラムとは別)。
    標準クラスタを使用する場合は、クラスタ管理手数料以外にワーカーノードのGoogle Compute Engine(GCE)のコストがかかるが、無料プログラムと併用したり、使わないときはインスタンスを停止するなどすればかなり節約できる。

環境

  • GKE:v1.25.1-gke.500

実施内容

作成するGKEクラスタの運用モードを検討

GKEクラスタのタイプの説明を読んで、作成するGKEクラスタの運用モードを検討する。

運用モードには以下の2種類がある。

  • Autopilot: 完全にプロビジョニングされたマネージド クラスタ構成を提供します。Autopilot モードで作成されたクラスタには、クラスタ構成オプションが自動的に作成されます。Autopilot クラスタは、本番環境ワークロードに対応する最適化されたクラスタ構成を使用してあらかじめ構成されています。

  • Standard: クラスタの基盤となるインフラストラクチャに高度な構成の柔軟性を提供します。Standard モードを使用して作成されたクラスタでは、ユーザーが本番環境ワークロードに必要な構成を決定します。

→AutoPilotの方が楽そうだが、GCPに管理を任せる範囲が広い分、Autopilotならではの制約もある。
検証・勉強用途なので、制約の少ないStandardモードにする。

GKEクラスタを作成する

GCPの以下ドキュメントを参考に、GKEクラスタを作成してみる。
cloud.google.com

GCPのナビゲーションメニュー(画面左上)から、「Kubernetes Engine」をクリックする。
GKEを初めて使う場合は、以下のようにKubernetes Engine APIの有効化画面が表示されるので、「有効にする」をクリックする。

Kubernetes Engine APIの有効化
Kubernetes Engine APIの有効化

しばらく待つと以下の画面になるので「作成」をクリックする。

GKEのページ
GKEのページ

次は運用モードの選択。Standardの「構成」をクリックする。

運用モードの選択
運用モードの選択

クラスター名とロケーションタイプを入力する。
ロケーションタイプはデフォルトの「ゾーン」にした。
使用するゾーンはどこでもよいが、自分はGCEの無料枠オレゴンリージョン(us-west1)に作成したVMインスタンスからGKEに接続する予定のため、オレゴンリージョンのゾーンにした。

クラスタの作成1
クラスタの作成1

コントロールプレーンのバージョンを選択する。
今回は出来るだけ新しいバージョンのK8sを使いたかったので、Rapidチャンネルの最新バージョンを選択した。

クラスタの作成2
クラスタの作成2

最後に画面下部の「作成」をクリックする。
※他にもワーカーノードのインスタンスタイプやクラスタのネットワークなど、色々設定ができるが、そこは特に触らずデフォルトのまま作成した。
しばらく待つと、以下のようにGKEクラスタが作成される。

作成されたクラスタ
作成されたクラスタ

クラスタを選択して「ノード」タブを見ると、e2-mediumのGCEインスタンス3台がワーカーノードとしてクラスタに参加していることが分かる。

ワーカーノードの詳細
ワーカーノードの詳細

Cloud ShellからGKEクラスタに接続する

クラスタができたので、kubectlで操作してみる。
とりあえず、こちらのページを参考に、Cloud Shellでクラスタに接続する。

GCPの管理コンソール右上の、「Cloud Shell をアクティブにする」をクリックしてCloud Shellを起動し、以下を実行する。

デフォルトのプロジェクトを設定
$ gcloud config set project {GKEクラスタを作成したプロジェクトのID}

クラスタ名とクラスタが存在するゾーンを指定して、クラスタ認証情報を取得
$ gcloud container clusters get-credentials cluster-1 --region us-west1-a

kubectlが実行できるようになったことを確認
$ kubectl get node
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-71e862dd-7b78   Ready    <none>   69m   v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-lbk8   Ready    <none>   69m   v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-rh0q   Ready    <none>   69m   v1.25.1-gke.500

GKEクラスタの動作確認をする

kubectlを実行できるようになったので、こちらを参考にサンプルAPを使った動作確認をする。
そのままの手順だとServiceがインターネットに公開されてしまうので、Serviceのyaml内の loadBalancerSourceRangesに自分の端末が使っているグローバルIPを指定してソースIP制限している。

サンプルDeploymentのyamlを作成
$ cat <<EOF > hello-server-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-server
  labels:
    app: hello
spec:
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        ports:
        - containerPort: 8080
EOF

サンプルDeploymentを作成
$ kubectl apply -f hello-server-deployment.yaml
deployment.apps/hello-server created

正常に作成されたことを確認
$ kubectl get deployment
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
hello-server   1/1     1            1           27s
$ kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
hello-server-6cfcb8c7df-8bb2z   1/1     Running   0          31s

サンプルServiceのyamlを作成
$ cat <<EOF > hello-server-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello-server
  labels:
    app: hello
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer
  loadBalancerSourceRanges:
  - {自分の端末のグローバルIPを記載}/32
EOF

サンプルServiceを作成
$ kubectl apply -f hello-server-service.yaml
service/hello-server created

EXTERNAL-IPがPENDINGからIPの表示に変わるのを待つ
$ kubectl get service hello-server -w
NAME           TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
hello-server   LoadBalancer   10.96.4.233   <pending>     80:30722/TCP   17s
hello-server   LoadBalancer   10.96.4.233   34.105.117.184   80:30722/TCP   36s

ブラウザで「http://EXTERNAL_IP」にアクセスする。
以下のように表示されれば、正常にサンプルアプリを外部公開できている。

サンプルAPの画面
サンプルAPの画面

確認できたら、動作確認用に作成したリソースを削除する。

$ kubectl delete -f hello-server-service.yaml
service "hello-server" deleted

$ kubectl delete -f hello-server-deployment.yaml
deployment.apps "hello-server" deleted

GCEのVMインスタンス(CentOS7)からGKEクラスタに接続する

諸事情で、Cloud ShellじゃなくGCEのVMインスタンスからkubectlでクラスタを操作したいので、接続を試してみる。 VMインスタンスは以下記事で作成したものを使用する。
tk-ch.hatenablog.com

kubectl をインストールしてクラスタ アクセスを構成する」を参考に設定を進める。

kubectlをインストールする

gcloudコマンドでインストール
$ gcloud components install kubectl

kubectlのバージョンを確認
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22+", GitVersion:"v1.22.14-dispatcher-dirty", GitCommit:"009f3ac5f1d09b1ec5d4dc811b6032271fe61f75", GitTreeState:"dirty", BuildDate:"2022-09-19T01:31:36Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

こちらに以下の記載がある。

Kubernetes バージョン 1.26 がリリースされる前に gcloud CLI を起動する場合は、gke-gcloud-auth-plugin バイナリのインストールが必要になります。インストールされていない場合は、kubectl などのカスタム Kubernetes クライアントの既存のインストールは機能しなくなります。 kubectl などのクライアントで GKE を操作するには、このプラグインをインストールする必要があります。

作業時点で1.26はリリースされていないので、gke-gcloud-auth-pluginが必要。
確認したところ、kubectlと一緒にインストールされていた。

$ gke-gcloud-auth-plugin --version
Kubernetes v1.25.2-alpha+ae91c1fc0c443c464a4c878ffa2a4544483c6d1f

kubectlにGKEクラスタの情報を設定する。

クラスタ名とクラスタが存在するゾーンを指定して、クラスタ認証情報を取得する
$ gcloud container clusters get-credentials cluster-1 --region us-west1-a
Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster-1.

※「gcloud container clusters get-credentials」実行時に、以下のエラーになった場合

クラスタ名とクラスタが存在するゾーンを指定して、クラスタ認証情報を取得する
$ gcloud container clusters get-credentials cluster-1 --region us-west1-a
Fetching cluster endpoint and auth data.
ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Request had insufficient authentication scopes.

If you are in a compute engine VM, it is likely that the specified scopes during VM creation are not enough to run this command.
See https://cloud.google.com/compute/docs/access/service-accounts#accesscopesiam for more information about access scopes.
See https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#changeserviceaccountandscopes for how to update access scopes of the VM.

こちらによると、認証スコープが足りていない。
インスタンスの設定を確認すると、「デフォルトのアクセス権を許可」になっていたので、以下のように「すべての Cloud API に完全アクセス権を許可」に変更して対処した(設定変更時はインスタンスを停止する必要がある)。

APIアクセスを許可
APIアクセスを許可

kubectlでGKEクラスタに接続する。

クラスタに接続出来ているが、WARNINGメッセージが出る
$ kubectl get node
W1016 13:50:03.312107   20207 gcp.go:119] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.26+; use gcloud instead.
To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-71e862dd-7b78   Ready    <none>   3d    v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-lbk8   Ready    <none>   3d    v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-rh0q   Ready    <none>   3d    v1.25.1-gke.500

WARNINGメッセージで案内された「Here's what to know about changes to kubectl authentication coming in GKE v1.26」を見ると、kubectl がgke-gcloud-auth-pluginを使うようにするためには、設定が必要とのこと。
記載されている手順を実行してみる。

環境変数を~/.bashrcに記載
$ echo "export USE_GKE_GCLOUD_AUTH_PLUGIN=True" >> ~/.bashrc

変更を反映
$ source ~/.bashrc

gcloudのコンポーネントを最新版に更新
$ gcloud components update

再度クラスタの認証情報を取得
$ gcloud container clusters get-credentials cluster-1 --region us-west1-a
Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster-1.

WARNINGが出なくなった
$ kubectl get node
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-71e862dd-7b78   Ready    <none>   3d    v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-lbk8   Ready    <none>   3d    v1.25.1-gke.500
gke-cluster-1-default-pool-71e862dd-rh0q   Ready    <none>   3d    v1.25.1-gke.500

kubectlの自動補完とエイリアスの設定をする。

$ sudo yum install -y bash-completion
$ source <(kubectl completion bash)
$ echo "source <(kubectl completion bash)" >> ~/.bashrc
$ echo 'alias k=kubectl' >> ~/.bashrc
$ echo 'complete -F __start_kubectl k' >> ~/.bashrc
$ exit

もう一度ログインすると、kubectlでもkでもtabでのコマンド補完が有効になっている。

$ kubectl
alpha          autoscale      create         exec           logs           rollout        version
annotate       certificate    debug          explain        options        run            wait
api-resources  cluster-info   delete         expose         patch          scale
api-versions   completion     describe       get            plugin         set
apply          config         diff           help           port-forward   taint
attach         cordon         drain          kustomize      proxy          top
auth           cp             edit           label          replace        uncordon

$ k
alpha          autoscale      create         exec           logs           rollout        version
annotate       certificate    debug          explain        options        run            wait
api-resources  cluster-info   delete         expose         patch          scale
api-versions   completion     describe       get            plugin         set
apply          config         diff           help           port-forward   taint
attach         cordon         drain          kustomize      proxy          top
auth           cp             edit           label          replace        uncordon

まとめ