GitLab を使用して開発サイクルの早い段階で GKE の費用を見積もる


このチュートリアルでは、GitLab を使用して Google Kubernetes Engine(GKE)の費用の可視性を開発チームにシフトするためのベスト プラクティスについて説明します。開発プロセスの初期に費用を意識しておくと、Google Cloud 請求書に予期しない費用が記載されている状態を回避できます。タスクまたは情報をプロセスの早期の部分に移動することは、シフトレフトとも呼ばれます。

このチュートリアルは、GKE クラスタの費用を最適化し、本番環境で GitLab を使用するデベロッパー、オペレーター、FinOps 担当者を対象としています。代わりに GitHub を使用する場合は、GitHub を使用して開発サイクルの早い段階で GKE の費用を見積もるをご覧ください。

このチュートリアルは、読者が次の技術を理解していることを前提としています。

概要

パブリック クラウドを採用する多くのチームが、従量課金制について精通していません。多くの場合に、アプリが実行されている環境(このケースでは GKE)についても十分に理解していません。FinOps の運用モデルでは、この財務説明責任の文化が改善されます。FinOps のベスト プラクティスは、費用の問題が発生した際に対処できるように、チームに費用に関するリアルタイムの情報を提供することです。

このドキュメントでは、費用が請求書の支出項目となる前に費用を見積もり、さらに一歩取り組みを進める方法について説明します。費用の見積もりを行う最も適切なタイミングは、開発段階からコードレビューまでの間の早期の時点です。これにより、実務担当者は新機能とバグ修正の費用に対する影響が顕在化する前に、代替手段を確認し、議論できます。次の図は、この方法の概要を示しています。

費用の早期見積もりに関するベスト プラクティス。

図が示すように、デベロッパーはローカル環境で GKE の費用を見積もることができます。見積もりはビルド時に行うのが理想的です。この見積もりにより、本番環境での月々のワークロード費用を適切に把握できます。機能またはバグ修正のコードが完成すると、GitLab CI / CD パイプラインをトリガーして新旧費用の差を確認するマージ リクエストを提案できます。事前定義されたしきい値を超える増加があった場合、パイプラインは自動的に新しいコードレビューをリクエストします。この方法は、本番環境で不安定性が見つかるたびにリソースを追加する代わりに、デベロッパーがワークロード容量をより明確に認識し、アプリケーションの問題をプロアクティブに修正するうえで有効です。

目標

  • Kubernetes の費用見積もりツールのイメージをビルドし、push します。
  • 新しい GitLab プロジェクトを作成します。
  • GKE クラスタで実行するように GitLab ランナーを構成します。
  • サンプルコードを GitLab リポジトリに push します。
  • コードを変更し、pull リクエストを提案して費用を見積もります。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Google Cloud コンソールでプロジェクトの選択ページに移動します。

    プロジェクト セレクタに移動

  2. Google Cloud プロジェクトを選択または作成します。

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Google Cloud コンソールで、「Cloud Shell をアクティブにする」をクリックします。

    Cloud Shell をアクティブにする

    Google Cloud コンソールの下部で Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。Google Cloud CLI がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。

環境を準備する

  1. 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 マニフェストの例が含まれています。組織に実装する前にこのプロセスを試すことができます。
  2. 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 リクエストを提案することもできます。

  1. Cloud Shell で、application-default が認証情報を使用できるようにします。

    gcloud auth application-default login
    
  2. Kubernetes の費用見積もりバイナリをビルドします。

    mkdir ./bin
    go test ./api
    go build -v -o ./bin/k8s-cost-estimator .
    
  3. サンプル フォルダで費用の見積もりを行い、バイナリをテストします。

    ./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!
    
  4. Kubernetes 費用見積もりツールのコンテナ イメージをビルドします。

    docker build . -t \
    us-central1-docker.pkg.dev/$GCP_PROJECT_ID/docker-repo/k8s-cost-estimator:v0.0.1
    
  5. イメージを保存する Artifact Registry の Docker リポジトリを作成します。

    gcloud artifacts repositories create docker-repo \
            --repository-format=docker \
            --location=us-central1 \
            --description="Docker repository"
    
  6. Docker の構成ファイルに、認証ヘルパーとして gcloud を登録します。

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

    プロンプトが表示されたら、ファイルの更新を確定します。

  7. イメージを Artifact Registry に push します。

    docker push us-central1-docker.pkg.dev/$GCP_PROJECT_ID/docker-repo/k8s-cost-estimator:v0.0.1
    

新しい GitLab プロジェクトを作成する

  1. Cloud Shell で、サンプル GitLab のディレクトリに移動します。

    cd samples/k8s-cost-estimator-gitlab
    
  2. GitLab の [個人用アクセス トークン] ページで、アクセス トークンを作成します。

    GitLab の個人用アクセス トークン ページに移動

    1. [名前] フィールドに、作成するトークンの名前を入力します。
    2. [Scope] フィールドで [api] を選択し、[個人用アクセス トークンの作成] をクリックします。
    3. [新しい個人用アクセス トークン] の値をコピーします。
  3. Cloud Shell で、個人用のアクセス トークンを変数に保存します。

    GITLAB_API_TOKEN=YOUR_NEW_PERSONAL_ACCESS_TOKEN
    

    YOUR_NEW_PERSONAL_ACCESS_TOKEN は、作成した GitLab の個人アクセス トークンに置き換えます。

  4. 新しい 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")
    
  5. 統合リクエストの作成時に使用する費用見積もりツールの変数を設定します。

    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
    
  6. プロジェクトと変数が作成されたことを確認します。

    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 や割引は考慮されません。

  1. 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
    
  2. 作成したプロジェクトから 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"
    
  3. 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
    
  4. 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"
    
  5. デプロイしたランナーが 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 する

  1. 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 ..
    
  2. 内容を新しい 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 リクエストを提案して費用を見積もる

  1. Cloud Shell で、GitLab Web 統合開発環境(IDE)の URL を取得します。

    echo "https://gitlab.com/-/ide/project/$GITLAB_USER/k8s-cost-estimator-gitlab/tree/main/-/wordpress/wordpress_hpa.yaml"
    
  2. 出力 URL を Ctrl キーを押しながらクリック(macOS では Cmd キーを押しながらクリック)して、GitLab ウェブ IDE に移動します。

  3. GitLab ウェブ IDE で、./wordpress/wordpress_hpa.yaml ファイルを次のように編集します。

    1. minReplicas の値を 2 から 5 に変更します。
    2. [commit] をクリックします。
  4. 次のスクリーンショットに示すように、[Create a new branch] を選択して [Start a new merge request] を選択し、[Commit] をクリックします。

    マージ リクエストを開始します。

  5. [New merge request] 画面で、ページの下部にある [Create merge request] をクリックします。

    新しいマージ リクエストを作成するだけでなく、このステップでは .gitlab-ci.yml ファイルに基づいて費用見積もりパイプラインをトリガーします。このパイプラインは、前のセクションで作成したコンテナ イメージを使用します。このパイプラインは、FinOps の承認がいつ必要になるかも決定します。説明をわかりやすくするため、.gitlab-ci.yml ではマージ リクエスト ベースごとに承認を追加しますが、GitLab プロジェクト レベルで定義された承認ルールを定義して再利用できます。

  6. パイプラインが終了するまで 1 分ほど待ちます。終了すると、マージ リクエストに費用の詳細を含むコメントが追加されます。提案するコードの費用が $10 のしきい値を超えたため、FinOps 審査担当者もリクエストされます。

    出力は次のようになります。

    マージ リクエストの費用の詳細を含むコメント。

    このチュートリアルでは、デフォルトの構成を使用してマージ リクエストを承認します。Gitlab では、マージ リクエストに異なる構成を選択できます。たとえば、作成者がマージ リクエストを承認しないようにするには、設定 >全般 >マージ リクエスト(MR)承認に移動 >承認設定に移動します。

クリーンアップ

このチュートリアルで使用したリソースに対する Google Cloud アカウントへの課金を回避するには、プロジェクトを削除します。

プロジェクトを削除する

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

GitLab プロジェクトを削除する

GitLab プロジェクトを保持しない場合は、次の操作を行います。

  1. 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

次のステップ