このチュートリアルでは、GitLab を使用して Google Kubernetes Engine(GKE)の費用の可視性を開発チームにシフトするためのベスト プラクティスについて説明します。開発プロセスの初期に費用を意識しておくと、Google Cloud 請求書に予期しない費用が記載されている状態を回避できます。タスクまたは情報をプロセスの早期の部分に移動することは、シフトレフトとも呼ばれます。
このチュートリアルは、GKE クラスタの費用を最適化し、本番環境で GitLab を使用するデベロッパー、オペレーター、FinOps 担当者を対象としています。代わりに GitHub を使用する場合は、GitHub を使用して開発サイクルの早い段階で GKE の費用を見積もるをご覧ください。
このチュートリアルは、読者が次の技術を理解していることを前提としています。
- Docker
- GitLab
- Kubernetes
- Cloud Build
- GKE
- Linux
概要
パブリック クラウドを採用する多くのチームが、従量課金制について精通していません。多くの場合に、アプリが実行されている環境(このケースでは GKE)についても十分に理解していません。FinOps の運用モデルでは、この財務説明責任の文化が改善されます。FinOps のベスト プラクティスは、費用の問題が発生した際に対処できるように、チームに費用に関するリアルタイムの情報を提供することです。
このドキュメントでは、費用が請求書の支出項目となる前に費用を見積もり、さらに一歩取り組みを進める方法について説明します。費用の見積もりを行う最も適切なタイミングは、開発段階からコードレビューまでの間の早期の時点です。これにより、実務担当者は新機能とバグ修正の費用に対する影響が顕在化する前に、代替手段を確認し、議論できます。次の図は、この方法の概要を示しています。
図が示すように、デベロッパーはローカル環境で GKE の費用を見積もることができます。見積もりはビルド時に行うのが理想的です。この見積もりにより、本番環境での月々のワークロード費用を適切に把握できます。機能またはバグ修正のコードが完成すると、GitLab CI / CD パイプラインをトリガーして新旧費用の差を確認するマージ リクエストを提案できます。事前定義されたしきい値を超える増加があった場合、パイプラインは自動的に新しいコードレビューをリクエストします。この方法は、本番環境で不安定性が見つかるたびにリソースを追加する代わりに、デベロッパーがワークロード容量をより明確に認識し、アプリケーションの問題をプロアクティブに修正するうえで有効です。
目標
- Kubernetes の費用見積もりツールのイメージをビルドし、push します。
- 新しい GitLab プロジェクトを作成します。
- GKE クラスタで実行するように GitLab ランナーを構成します。
- サンプルコードを GitLab リポジトリに push します。
- コードを変更し、pull リクエストを提案して費用を見積もります。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
-
Google Cloud コンソールでプロジェクトの選択ページに移動します。
-
Google Cloud プロジェクトを選択または作成します。
-
Google Cloud コンソールで、「Cloud Shell をアクティブにする」をクリックします。
Google Cloud コンソールの下部で Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。Google Cloud CLI がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。
環境を準備する
Cloud Shell で
gke-shift-left-cost
GitHub リポジトリのクローンを作成します。git clone https://github.com/GoogleCloudPlatform/gke-shift-left-cost cd gke-shift-left-cost
このリポジトリのコードは、次のフォルダに構成されています。
- ルート: 費用見積もりツールのイメージのビルドに使用される Dockerfile ファイルと、費用見積もりツールのコマンドライン ロジックを実装する
main.go
ファイルが含まれています。 api/
: Kubernetes オブジェクトを操作し、費用見積もりを作成するための Golang API が含まれています。samples/
: Kubernetes マニフェストの例が含まれています。組織に実装する前にこのプロセスを試すことができます。
- ルート: 費用見積もりツールのイメージのビルドに使用される Dockerfile ファイルと、費用見積もりツールのコマンドライン ロジックを実装する
Google Cloud プロジェクト ID、GitLab ユーザー アカウント、メールアドレスを設定します。
export GCP_PROJECT_ID=YOUR_PROJECT_ID export GITLAB_USER=YOUR_GITLAB_USER export GITLAB_EMAIL=YOUR_GITLAB_EMAIL_ADDRESS gcloud config set project $GCP_PROJECT_ID gcloud services enable cloudbilling.googleapis.com \ compute.googleapis.com \ container.googleapis.com \ iamcredentials.googleapis.com \ artifactregistry.googleapis.com gcloud config set compute/region us-central1 gcloud config set compute/zone us-central1-f
次のように置き換えます。
YOUR_PROJECT_ID
: このチュートリアルで使用しているプロジェクトの Google Cloud プロジェクト ID。YOUR_GITLAB_USER
: GitLab アカウントへのログインに使用するユーザー アカウント。YOUR_GITLAB_EMAIL_ADDRESS
: GitLab アカウントで使用するメールアドレス。
必要に応じて、このチュートリアルに別のリージョンとゾーンを使用できます。
Kubernetes の費用見積もりツールのイメージをビルドし、push する
このチュートリアルに付属する Kubernetes 費用見積もりツールは、あくまで実施可能な操作の内容を示す例です。このツールでは、DaemonSet、Deployment、StatefulSet、ReplicaSet、HorizontalPodAutoScaler、PersistentVolumeClaim Kubernetes の各オブジェクトの費用を見積もることができます。独自の費用見積もりツールを実装することも、必要な改善を加えた pull リクエストを提案することもできます。
Cloud Shell で、
application-default
が認証情報を使用できるようにします。gcloud auth application-default login
Kubernetes の費用見積もりバイナリをビルドします。
mkdir ./bin go test ./api go build -v -o ./bin/k8s-cost-estimator .
サンプル フォルダで費用の見積もりを行い、バイナリをテストします。
./bin/k8s-cost-estimator \ --k8s ./samples/k8s-cost-estimator-local/app-v1 \ --config ./samples/k8s-cost-estimator-local/example-conf.yaml \ --v trace
出力には、
./samples/k8s-cost-estimator-local/app-v1/
フォルダの毎月の見積もり費用の詳細を示す Markdown テーブルが表示されます。デベロッパーはリモート リポジトリにコードを push する前に以下のステップを実行すると、アプリケーションの毎月の本番環境費用をより深く把握できます。INFO[0000] Starting cost estimation (version v0.0.1)... ... | KIND | MIN REQUESTED (USD) | MIN REQ + HPA CPU BUFFER (USD) | MAX REQUESTED (USD) | MIN LIMITED (USD) | MAX LIMITED (USD) | |-----------------------|---------------------|--------------------------------|---------------------|-------------------|-------------------| | Deployment | $133.31 | $198.71 | $266.54 | $312.83 | $579.29 | | StatefulSet | $36.33 | $36.33 | $36.33 | $72.67 | $72.67 | | DaemonSet | $29.68 | $29.68 | $29.68 | $53.19 | $53.19 | | PersistentVolumeClaim | $28.88 | $28.88 | $28.88 | $33.68 | $33.68 | | **TOTAL** | **$228.20** | **$293.60** | **$361.43** | **$472.38** | **$738.83** | INFO[0002] Finished cost estimation!
Kubernetes 費用見積もりツールのコンテナ イメージをビルドします。
docker build . -t \ us-central1-docker.pkg.dev/$GCP_PROJECT_ID/docker-repo/k8s-cost-estimator:v0.0.1
イメージを保存する Artifact Registry の Docker リポジトリを作成します。
gcloud artifacts repositories create docker-repo \ --repository-format=docker \ --location=us-central1 \ --description="Docker repository"
Docker の構成ファイルに、認証ヘルパーとして
gcloud
を登録します。gcloud auth configure-docker us-central1-docker.pkg.dev
プロンプトが表示されたら、ファイルの更新を確定します。
イメージを Artifact Registry に push します。
docker push us-central1-docker.pkg.dev/$GCP_PROJECT_ID/docker-repo/k8s-cost-estimator:v0.0.1
新しい GitLab プロジェクトを作成する
Cloud Shell で、サンプル GitLab のディレクトリに移動します。
cd samples/k8s-cost-estimator-gitlab
GitLab の [個人用アクセス トークン] ページで、アクセス トークンを作成します。
- [名前] フィールドに、作成するトークンの名前を入力します。
- [Scope] フィールドで [api] を選択し、[個人用アクセス トークンの作成] をクリックします。
- [新しい個人用アクセス トークン] の値をコピーします。
Cloud Shell で、個人用のアクセス トークンを変数に保存します。
GITLAB_API_TOKEN=YOUR_NEW_PERSONAL_ACCESS_TOKEN
YOUR_NEW_PERSONAL_ACCESS_TOKEN
は、作成した GitLab の個人アクセス トークンに置き換えます。新しい GitLab プロジェクトを作成します。
GITLAB_PROJECT_OUTPUT=$(curl -X POST -H "content-type:application/json" -H "PRIVATE-TOKEN:$GITLAB_API_TOKEN" -d '{"name":"k8s-cost-estimator-gitlab","visibility":"public"}' https://gitlab.com/api/v4/projects) GITLAB_PROJECT_ID=$(echo $GITLAB_PROJECT_OUTPUT | jq ".id") GITLAB_FINOPS_REVIEWER_ID=$(echo $GITLAB_PROJECT_OUTPUT | jq ".owner.id")
統合リクエストの作成時に使用する費用見積もりツールの変数を設定します。
curl -X POST -H "content-type:application/json" -H "PRIVATE-TOKEN:$GITLAB_API_TOKEN" -d "{\"key\": \"GITLAB_API_TOKEN\",\"value\": \"$GITLAB_API_TOKEN\", \"masked\":\"true\"}" https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/variables curl -X POST -H "content-type:application/json" -H "PRIVATE-TOKEN:$GITLAB_API_TOKEN" -d "{\"key\": \"GITLAB_FINOPS_REVIEWER_ID\",\"value\": \"$GITLAB_FINOPS_REVIEWER_ID\"}" https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/variables curl -X POST -H "content-type:application/json" -H "PRIVATE-TOKEN:$GITLAB_API_TOKEN" -d "{\"key\": \"GITLAB_FINOPS_COST_USD_THRESHOLD\",\"value\": \"10\"}" https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/variables
プロジェクトと変数が作成されたことを確認します。
curl -s --header "PRIVATE-TOKEN:$GITLAB_API_TOKEN" \ https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/variables | jq
出力は次のようになります。
[ { "variable_type": "env_var", "key": "GITLAB_API_TOKEN", "value": "Ex...n1", "protected": false, "masked": true, "environment_scope": "*" }, { "variable_type": "env_var", "key": "GITLAB_FINOPS_REVIEWER_ID", "value": "88..87", "protected": false, "masked": false, "environment_scope": "*" }, { "variable_type": "env_var", "key": "GITLAB_FINOPS_COST_USD_THRESHOLD", "value": "10", "protected": false, "masked": false, "environment_scope": "*" } ]
GitLab プロジェクトに構成された変数は、
./samples/k8s-cost-estimator-gitlab/templates/.gitlab-ci.yml.tpl
ファイルでマージ リクエストを更新するために使用されます。変数は次のとおりです。GITLAB_API_TOKEN
: GitLab 個人用アクセス トークン。GITLAB_FINOPS_REVIEWER_ID
: 費用が増加して特定のしきい値を超えた場合、コードレビュー担当者が必要になります。説明をわかりやすくするため、このチュートリアルではこのレビュー担当者として独自のユーザー ID を設定します。ただし、本番環境では、個人ではなくチームを構成することをおすすめします。GITLAB_FINOPS_COST_USD_THRESHOLD
: 米ドルのしきい値。この例では $10 になっています。古い費用と新しい費用の差がこのしきい値を超えると、特別な承認が適用されます。他の値にしきい値を設定することもできます。この機能を試すには、Kubernetes の費用見積もりツールのイメージのビルドと push で./bin/k8s-cost-estimator
コマンドを実行するときに--output
パラメータを追加します。このパラメータにより、使用可能なオプションを表示できる.diff
拡張子を持つファイルが生成されます。
GKE クラスタで実行するように GitLab ランナーを構成する
このセクションでは、Workload Identity を使用して独自の GitLab ランナーを GKE クラスタにインストールし、Kubernetes 費用見積もりツールで Google Cloud 料金カタログをクエリできるようにします。費用見積もりツールでは合計価格が使用され、プリエンプティブル VM や割引は考慮されません。
Cloud Shell で、GKE クラスタを作成します。
gcloud beta container clusters create gitlab-runners \ --enable-ip-alias \ --release-channel=stable \ --workload-pool=$GCP_PROJECT_ID.svc.id.goog \ --enable-autoprovisioning --min-cpu 1 --min-memory 1 --max-cpu 4 --max-memory 16 \ --autoscaling-profile=optimize-utilization \ --preemptible
作成したプロジェクトから GitLab ランナーの登録トークンを取得します。
export GITLAB_RUNNER_TOKEN=$(curl -s --header "PRIVATE-TOKEN:$GITLAB_API_TOKEN" https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID | jq -r '.runners_token') [ -z "$GITLAB_RUNNER_TOKEN" ] && echo "GITLAB_RUNNER_TOKEN is not exported" || echo "GITLAB_RUNNER_TOKEN is $GITLAB_RUNNER_TOKEN"
GKE クラスタに GitLab ランナーをインストールします。
kubectl create namespace gitlab helm repo add gitlab https://charts.gitlab.io sed "s/GCP_PROJECT_ID/$GCP_PROJECT_ID/g; s/GITLAB_RUNNER_TOKEN/$GITLAB_RUNNER_TOKEN/g" templates/gitlab-runner-values.yaml.tpl > gitlab-runner-values.yaml helm install --namespace gitlab --version 0.24.0 gitlab-runner -f gitlab-runner-values.yaml gitlab/gitlab-runner kubectl -n gitlab wait --for=condition=available deployment gitlab-runner --timeout=5m gcloud iam service-accounts create gitlab-runner --display-name=gitlab-runner gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[gitlab/gitlab-runner]" \ gitlab-runner@$GCP_PROJECT_ID.iam.gserviceaccount.com
GitLab プロジェクトの共有ランナーを無効にします。
curl -s --header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" -X PUT "https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID" --form "shared_runners_enabled=false"
デプロイしたランナーが GitLab プロジェクトで有効になっていることを確認します。
curl -s --header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" "https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/runners?status=active" | jq '.[] | select(.is_shared==false)'
出力は次のようになります。
{ "id": 49345561, "description": "gitlab-runner-gitlab-runner-788459d488-jlscn", "ip_address": "35.178.223.199", "active": true, "is_shared": false, "name": "gitlab-runner", "online": true, "status": "online" }
サンプルコードを GitLab リポジトリに push する
SSH 認証鍵ペアを作成して、GitLab リポジトリにサンプルコードを push します。
mkdir -p ssh && cd ssh ssh-keygen -t rsa -b 4096 -N '' -f gitlab-key eval `ssh-agent` && ssh-add $(pwd)/gitlab-key curl -s --request POST --header "PRIVATE-TOKEN:$GITLAB_API_TOKEN" https://gitlab.com/api/v4/user/keys --form "title=k8s-cost-estimator-key" --form "key=$(cat gitlab-key.pub)" cd ..
内容を新しい GitLab リポジトリに push します。
sed "s/GCP_PROJECT_ID/$GCP_PROJECT_ID/g; s/GITLAB_USER/$GITLAB_USER/g; s/GITLAB_EMAIL/$GITLAB_EMAIL/g;" templates/.gitlab-ci.yml.tpl > .gitlab-ci.yml GITLAB_SSH_URL_REPO=$(curl -s --header "PRIVATE-TOKEN:$GITLAB_API_TOKEN" https://gitlab.com/api/v4/users/$GITLAB_FINOPS_REVIEWER_ID/projects | jq '.[] | select(.name=="k8s-cost-estimator-gitlab")' | jq -r '.ssh_url_to_repo') [ -z "$GITLAB_SSH_URL_REPO" ] && echo "GITLAB_PROJECT_SSH_URL is not exported" || echo "GITLAB_PROJECT_SSH_URL is $GITLAB_SSH_URL_REPO" git config --global user.email $GITLAB_EMAIL git config --global user.name $GITLAB_USER git init git remote add origin $GITLAB_SSH_URL_REPO git add -A . git commit -m "Initial commit" git checkout -b main git push -u origin main
コードを変更し、pull リクエストを提案して費用を見積もる
Cloud Shell で、GitLab Web 統合開発環境(IDE)の URL を取得します。
echo "https://gitlab.com/-/ide/project/$GITLAB_USER/k8s-cost-estimator-gitlab/tree/main/-/wordpress/wordpress_hpa.yaml"
出力 URL を Ctrl キーを押しながらクリック(macOS では Cmd キーを押しながらクリック)して、GitLab ウェブ IDE に移動します。
GitLab ウェブ IDE で、
./wordpress/wordpress_hpa.yaml
ファイルを次のように編集します。minReplicas
の値を2
から5
に変更します。- [commit] をクリックします。
次のスクリーンショットに示すように、[Create a new branch] を選択して [Start a new merge request] を選択し、[Commit] をクリックします。
[New merge request] 画面で、ページの下部にある [Create merge request] をクリックします。
新しいマージ リクエストを作成するだけでなく、このステップでは
.gitlab-ci.yml
ファイルに基づいて費用見積もりパイプラインをトリガーします。このパイプラインは、前のセクションで作成したコンテナ イメージを使用します。このパイプラインは、FinOps の承認がいつ必要になるかも決定します。説明をわかりやすくするため、.gitlab-ci.yml
ではマージ リクエスト ベースごとに承認を追加しますが、GitLab プロジェクト レベルで定義された承認ルールを定義して再利用できます。パイプラインが終了するまで 1 分ほど待ちます。終了すると、マージ リクエストに費用の詳細を含むコメントが追加されます。提案するコードの費用が $10 のしきい値を超えたため、FinOps 審査担当者もリクエストされます。
出力は次のようになります。
このチュートリアルでは、デフォルトの構成を使用してマージ リクエストを承認します。Gitlab では、マージ リクエストに異なる構成を選択できます。たとえば、作成者がマージ リクエストを承認しないようにするには、設定 >全般 >マージ リクエスト(MR)承認に移動 >承認設定に移動します。
クリーンアップ
このチュートリアルで使用したリソースに対する Google Cloud アカウントへの課金を回避するには、プロジェクトを削除します。
プロジェクトを削除する
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
GitLab プロジェクトを削除する
GitLab プロジェクトを保持しない場合は、次の操作を行います。
Cloud Shell で、GitLab プロジェクトを削除します。
curl -X DELETE -H "content-type:application/json" -H "PRIVATE-TOKEN:$GITLAB_API_TOKEN" https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID ``` The output is similar to the following: ```none {:.devsite-disable-click-to-copy} {"message":"202 Accepted"}
Cloud Shell との接続が切断された場合は、次の変数を再度設定する必要があります。
GITLAB_API_TOKEN
GITLAB_PROJECT_ID
次のステップ
- GKE でコスト最適化 Kubernetes アプリケーションを実行するためのベスト プラクティスで、GKE の費用の最適化について学習する。
- GitHub を使用して開発サイクルの早い段階で GKE 費用を見積もる方法を確認する。
- Google Cloud アーキテクチャ フレームワーク: 費用の最適化で、Google Cloud ワークロードの費用を最適化するための設計に関する推奨事項とベスト プラクティスを確認する。
- Google Cloud に関するリファレンス アーキテクチャ、図、ベスト プラクティスを確認する。Cloud Architecture Center を確認する。