Estimer les coûts GKE dès le début du cycle de développement à l'aide de GitLab


Ce tutoriel présente la bonne pratique qui consiste à transférer la visibilité des coûts Google Kubernetes Engine (GKE) à l'équipe de développement à l'aide de GitLab. En comprenant les coûts dès le début du processus de développement, vous évitez les surprises sur votre facture Google Cloud. Le déplacement d'une tâche ou d'informations vers une partie antérieure d'un processus est parfois appelé décalage à gauche.

Ce tutoriel est destiné aux développeurs, aux opérateurs et aux professionnels FinOps qui souhaitent optimiser les coûts des clusters GKE et utilisent GitLab en production. Si vous utilisez GitHub, consultez la page Estimer les coûts GKE dès le début du cycle de développement à l'aide de GitHub.

Pour ce tutoriel, nous partons du principe que vous connaissez bien les technologies suivantes :

Présentation

De nombreuses équipes qui adoptent le cloud public ne sont pas habituées à la facturation à l'utilisation. Il est fréquent qu'ils ne comprennent pas complètement l'environnement sur lequel leurs applications s'exécutent, à savoir dans le cas présent, GKE. Le modèle d'exploitation FinOps favorise cette culture de la responsabilité financière. Une bonne pratique FinOps consiste à fournir aux équipes des informations en temps réel sur leurs dépenses afin de résoudre les problèmes de coûts dès qu'ils surviennent.

Ce document vous explique comment aller plus loin en estimant les coûts avant qu'ils ne deviennent une dépense sur votre facture. Le meilleur moment pour estimer les coûts doit se situer au début du processus, au cours du développement et au moment de la revue de code. De cette façon, les professionnels peuvent comprendre et discuter des alternatives pour l'impact au niveau du coût des nouvelles fonctionnalités et corrections de bugs avant que cela ne devienne un problème. Le schéma suivant résume cette pratique.

Il s'agit d'une bonne pratique consistant à estimer les coûts de manière anticipée.

Comme le montre le schéma, les développeurs peuvent estimer les coûts liés à GKE dans leur environnement local, de préférence au moment de la compilation. Cette estimation leur donne une bonne compréhension du coût mensuel de la charge de travail de production. Lorsque la fonctionnalité ou la correction de bug est terminée, elle peut proposer une requête de fusion qui déclenche un pipeline CI/CD GitLab permettant de vérifier la différence entre l'ancien et le nouveau coût. Si les augmentations dépassent un seuil prédéfini, le pipeline demande automatiquement un nouvel examen du code. Cette pratique aide les développeurs à prendre connaissance de la capacité de leur charge de travail et à corriger les problèmes d'application de manière proactive au lieu d'ajouter des ressources chaque fois qu'une instabilité est détectée en production.

Objectifs

  • Créer et transférer l'image de l'estimateur de coûts Kubernetes
  • Créer un projet GitLab
  • Configurer l'exécuteur GitLab de sorte qu'il s'exécute sur un cluster GKE
  • Transférer l'exemple de code vers un dépôt GitLab
  • Modifier le code et proposer une requête de fusion pour tester l'estimation des coûts

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. Dans Google Cloud Console, accédez à la page de sélection du projet.

    Accéder au sélecteur de projet

  2. Sélectionnez ou créez un projet Google Cloud.

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  4. Dans la console Google Cloud, activez Cloud Shell.

    Activer Cloud Shell

    En bas de la fenêtre de la console Google Cloud, une session Cloud Shell démarre et affiche une invite de ligne de commande. Cloud Shell est un environnement shell dans lequel Google Cloud CLI est déjà installé, et dans lequel des valeurs sont déjà définies pour votre projet actuel. L'initialisation de la session peut prendre quelques secondes.

Préparer votre environnement

  1. Dans Cloud Shell, clonez le dépôt GitHub gke-shift-left-cost :

    git clone https://github.com/GoogleCloudPlatform/gke-shift-left-cost
    cd gke-shift-left-cost
    

    Le code dans ce dépôt est structuré avec les dossiers suivants :

    • Racine : contient un fichier Dockerfile permettant de créer l'image de l'estimateur de coûts et le fichier main.go qui met en œuvre la logique de ligne de commande pour l'estimateur de coûts.
    • api/ : contient l'API Go permettant de manipuler les objets Kubernetes et d'estimer les coûts.
    • samples/ : contient des exemples de fichiers manifestes Kubernetes afin que vous puissiez tester le processus avant de le mettre en œuvre dans votre organisation.
  2. Définissez l'ID de votre projet Google Cloud, votre compte utilisateur GitLab et votre adresse e-mail :

    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
    

    Remplacez les éléments suivants :

  • YOUR_PROJECT_ID  : ID du projet Google Cloud que vous utilisez dans ce tutoriel.
  • YOUR_GITLAB_USER  : compte utilisateur avec lequel vous vous connectez à votre compte GitLab.
  • YOUR_GITLAB_EMAIL_ADDRESS : adresse e-mail que vous utilisez dans votre compte GitLab.

Vous pouvez éventuellement définir une région et une zone différentes dans ce tutoriel.

Créer et transférer l'image de l'estimateur de coûts Kubernetes

L'outil d'estimation des coûts de Kubernetes fourni avec ce tutoriel est un exemple de ce qu'il est possible de faire. Il offre la possibilité d'estimer les coûts des objets Kubernetes DaemonSet, Deployment, StatefulSet, ReplicaSet, HorizontalPodAutoScaler et PersistentVolumeClaim. Vous pouvez également mettre en œuvre votre propre outil d'estimation des coûts ou proposer des demandes d'extraction avec les améliorations souhaitées.

  1. Dans Cloud Shell, autorisez application-default à utiliser vos identifiants :

    gcloud auth application-default login
    
  2. Créez le binaire de l'estimateur de coûts Kubernetes :

    mkdir ./bin
    go test ./api
    go build -v -o ./bin/k8s-cost-estimator .
    
  3. Testez le binaire en exécutant l'estimation des coûts dans un exemple de dossier :

    ./bin/k8s-cost-estimator \
        --k8s ./samples/k8s-cost-estimator-local/app-v1  \
        --config ./samples/k8s-cost-estimator-local/example-conf.yaml \
        --v trace
    

    Dans la sortie, vous voyez un tableau Markdown qui détaille les coûts mensuels estimés pour le dossier ./samples/k8s-cost-estimator-local/app-v1/. Pour mieux comprendre le coût mensuel de production de leurs applications, les développeurs peuvent exécuter cette étape avant de procéder au transfert vers le dépôt distant.

    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. Créez l'image du conteneur de l'estimateur de coûts Kubernetes :

    docker build . -t \
    us-central1-docker.pkg.dev/$GCP_PROJECT_ID/docker-repo/k8s-cost-estimator:v0.0.1
    
  5. Créez le dépôt Docker Artifact Registry pour stocker l'image :

    gcloud artifacts repositories create docker-repo \
            --repository-format=docker \
            --location=us-central1 \
            --description="Docker repository"
    
  6. Enregistrez gcloud en tant qu'assistant d'identification dans le fichier de configuration Docker.

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

    Si vous y êtes invité, confirmez la mise à jour du fichier.

  7. Transférez l'image vers Artifact Registry :

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

Créer un projet GitLab

  1. Dans Cloud Shell, remplacez le répertoire par l'exemple GitLab :

    cd samples/k8s-cost-estimator-gitlab
    
  2. Sur la page GitLab Jetons d'accès personnels, créez un jeton d'accès :

    Accéder à la page GitLab "Jetons d'accès personnels"

    1. Dans le champ Nom, saisissez le nom du jeton que vous créez.
    2. Dans le champ Scope (Champ d'application), sélectionnez api, puis cliquez sur Create personal access token (Créer un jeton d'accès personnel).
    3. Copiez la valeur de votre nouveau jeton d'accès personnel.
  3. Dans Cloud Shell, enregistrez votre jeton d'accès personnel dans une variable :

    GITLAB_API_TOKEN=YOUR_NEW_PERSONAL_ACCESS_TOKEN
    

    Remplacez YOUR_NEW_PERSONAL_ACCESS_TOKEN par le jeton d'accès personnel GitLab que vous avez créé.

  4. Créez un projet 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. Définissez les variables que l'outil d'estimation des coûts doit utiliser lors de la création d'une requête de fusion :

    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. Vérifiez que votre projet et vos variables ont été créés :

    curl -s --header "PRIVATE-TOKEN:$GITLAB_API_TOKEN" \
    https://gitlab.com/api/v4/projects/$GITLAB_PROJECT_ID/variables | jq
    

    Le résultat ressemble à ce qui suit :

    [
        {
        "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": "*"
        }
    ]
    

    Les variables configurées dans votre projet GitLab sont utilisées par le fichier ./samples/k8s-cost-estimator-gitlab/templates/.gitlab-ci.yml.tpl pour mettre à jour les requêtes de fusion. Elles se présentent comme suit :

    • GITLAB_API_TOKEN : votre jeton d'accès personnel GitLab.
    • GITLAB_FINOPS_REVIEWER_ID : examinateur de code requis chaque fois que le coût dépasse un seuil donné. Par souci de simplicité, nous définissons votre propre ID utilisateur en tant qu'examinateur dans ce tutoriel. Cependant, dans un environnement de production, nous vous recommandons de configurer une équipe plutôt qu'une personne individuelle.
    • GITLAB_FINOPS_COST_USD_THRESHOLD : seuil exprimé en USD, dans ce cas 10 $. Lorsque la différence entre l'ancien et le nouveau coûts dépasse ce seuil, une approbation extraordinaire est appliquée. Vous pouvez également définir des seuils pour d'autres valeurs. Pour découvrir cette fonctionnalité, vous pouvez ajouter le paramètre --output lorsque vous exécutez la commande ./bin/k8s-cost-estimator de la section Créer et transférer l'image de l'estimateur de coûts Kubernetes. Ce paramètre génère un fichier avec une extension .diff qui vous permet d'afficher les options disponibles.

Configurer l'exécuteur GitLab pour qu'il s'exécute sur un cluster GKE

Dans cette section, vous allez installer l'exécuteur GitLab dans votre propre cluster GKE à l'aide de Workload Identity pour permettre à l'outil d'estimation de Kubernetes d'interroger le catalogue des prix de Google Cloud. L'estimateur utilise des prix bruts, et ne prend en compte ni les VM préemptives, ni les remises.

  1. Dans Cloud Shell, créez un cluster 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. Récupérez le jeton d'enregistrement de l'exécuteur GitLab dans le projet que vous avez créé :

    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. Installez l'exécuteur GitLab dans votre cluster GKE :

    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. Désactivez les exécuteurs partagés dans votre projet 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. Vérifiez que l'exécuteur que vous avez déployé est activé dans votre projet 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)'
    

    Le résultat ressemble à ce qui suit :

    {
        "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"
    }
    

Transférer l'exemple de code vers votre dépôt GitLab

  1. Créez une paire de clés SSH pour transférer l'exemple de code vers votre dépôt GitLab :

    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. Transférez le contenu vers votre nouveau dépôt GitLab :

    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
    

Modifier le code et proposer une requête de fusion pour tester l'estimation des coûts

  1. Dans Cloud Shell, obtenez l'URL de l'environnement de développement intégré (IDE) Web de GitLab :

    echo "https://gitlab.com/-/ide/project/$GITLAB_USER/k8s-cost-estimator-gitlab/tree/main/-/wordpress/wordpress_hpa.yaml"
    
  2. Appuyez sur Ctrl+clic (Cmd+clic sur macOS) sur l'URL de sortie pour accéder à l'IDE Web de GitLab.

  3. Dans l'IDE Web de GitLab, modifiez le fichier ./wordpress/wordpress_hpa.yaml comme suit :

    1. Remplacez la valeur minReplicas 2 par 5.
    2. Cliquez sur Commit.
  4. Comme illustré dans la capture d'écran suivante, sélectionnez Create a new branch (Créer une branche) et Start a new merge request (Démarrer une nouvelle requête de fusion), puis cliquez sur Commit (Valider).

    Lancez une requête de fusion.

  5. Sur l'écran New merge request (Nouvelle requête de fusion), cliquez sur Create merge request (Créer une requête de fusion) au bas de la page.

    En plus de créer une requête de fusion, cette étape déclenche un pipeline d'estimation des coûts basé sur le fichier .gitlab-ci.yml. Ce pipeline utilise l'image de conteneur que vous avez créée dans une section précédente. Ce pipeline détermine également le moment où une approbation FinOps est requise. Pour plus de simplicité, .gitlab-ci.yml ajoute des approbations à chaque base de requête de fusion, mais vous pouvez définir et réutiliser des règles d'approbation définies au niveau du projet GitLab.

  6. Attendez environ une minute que l'exécution du pipeline soit terminée. Une fois l'opération terminée, un commentaire avec les détails des coûts est ajouté à la requête de fusion. Comme l'augmentation du coût du code que vous proposez dépasse le seuil de 10 $, un examinateur FinOps est également requis.

    Le résultat ressemble à ce qui suit :

    Commentaire avec les détails des coûts dans la requête de fusion.

    Dans ce tutoriel, la configuration par défaut est utilisée pour les approbations des requêtes de fusion. Vous pouvez sélectionner différentes configurations pour vos requêtes de fusion dans Gitlab. Par exemple, pour empêcher l'auteur d'approuver les requêtes de fusion, accédez à Settings (Paramètres) > General (Général) > Merge request (MR) approvals (Approbation des requêtes de fusion) > Approval settings (Paramètres d'approbation).

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel ne soient facturées sur votre compte Google Cloud, vous pouvez supprimer le projet.

Supprimer le projet

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Supprimer le projet GitLab

Si vous ne souhaitez pas conserver votre projet GitLab, procédez comme suit :

  1. Dans Cloud Shell, supprimez votre projet 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"}
    

    Si vous perdez votre connexion à Cloud Shell, vous devez à nouveau définir les variables suivantes :

    • GITLAB_API_TOKEN
    • GITLAB_PROJECT_ID

Étapes suivantes