GitLab을 사용하여 개발 주기 초반에 GKE 비용 예측


이 튜토리얼에서는 GitLab을 사용해 Google Kubernetes Engine(GKE) 비용에 대한 가시성을 개발팀에 제공하기 위한 권장사항을 설명합니다. 개발 단계 초기에 비용을 인지하면 Google Cloud에서 예기치 못한 비용이 청구되는 상황을 피할 수 있습니다. 초반부터 태스크 또는 정보를 고려하는 것을 Shifting Left(개발 초기부터 고려)라고도 부릅니다.

이 튜토리얼은 GKE 클러스터의 비용을 최적화하기를 원하며 프로덕션에서 GitLab을 사용하는 개발자, 운영자, FinOps 실무자를 대상으로 합니다. GitHub를 사용하는 경우 GitHub를 사용하여 개발 주기 초반에 GKE 비용 예측을 참조하세요.

본 튜토리얼에서는 사용자가 다음에 익숙하다고 가정합니다.

개요

퍼블릭 클라우드를 사용하는 많은 팀은 사용한 만큼만 지불하는 결제 방식에 익숙하지 않습니다. 이들은 GKE와 같이 자신의 앱이 실행되는 환경을 완전히 이해하지 못하는 경우가 많습니다. FinOps 운영 모델은 이러한 재무 책임 문화를 촉진시킵니다. FinOps 권장사항은 비용 문제가 발생하면 이를 해결할 수 있도록 지출 내역에 관한 실시간 정보를 팀에 제공하는 것입니다.

이 문서에서는 비용 결제 문제가 커지기 전 비용 예측을 통해 이를 한 단 계 더 발전시키는 방법을 보여줍니다. 비용 예측의 최적 시기는 개발 및 코드 검토 시기의 초기입니다. 이렇게 함으로써 실무자는 문제가 커지기 전 새로운 기능 및 버그 수정이 비용에 미치는 영향을 이해하고 그에 대한 대안을 논의할 수 있습니다. 다음 다이어그램은 이러한 방식을 요약해서 보여줍니다.

조기 비용 예측에 대한 권장사항

다이어그램에서 보다시피 개발자는 로컬 환경, 이상적으로는 빌드 시점에 GKE 비용을 예측할 수 있습니다. 이러한 예측을 통해 월별 프로덕션 워크로드 비용을 효과적으로 이해할 수 있습니다. 기능 또는 버그 수정 코드가 완성되면 이전 비용과 신규 비용 사이의 차이를 확인하기 위해 GitLab CI/CD 파이프라인을 트리거하는 병합 요청을 제안할 수 있습니다. 사전 정의된 임곗값 이상으로 값이 증가하면 파이프라인에서 새로운 코드 검토를 자동으로 요청합니다. 이렇게 하면 개발자가 워크로드 용량을 보다 효과적으로 인지하고 프로덕션에서 불안정성이 발견될 때마다 리소스를 더 추가하는 대신 애플리케이션 문제를 사전에 해결할 수 있습니다.

목표

  • Kubernetes 비용 예측 도구 이미지를 빌드하고 푸시합니다.
  • 새 GitLab 프로젝트를 만듭니다.
  • GKE 클러스터에서 실행되도록 GitLab 실행기를 구성합니다.
  • 예시 코드를 GitLab 저장소로 푸시합니다.
  • 실제 비용 예측을 확인하기 위해 코드를 변경하고 병합 요청을 제안합니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Google Cloud Console에서 프로젝트 선택기 페이지로 이동합니다.

    프로젝트 선택기로 이동

  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 객체를 조작하고 비용 예측을 수행하기 위한 Go API를 포함합니다.
    • samples/: 조직에서 구현하기 전 프로세스로 실험할 수 있도록 Kubernetes 매니페스트 예시를 포함합니다.
  2. Google 클라우드 프로젝트 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 비용 예측 도구 이미지 빌드 및 푸시

이 튜토리얼에 제공되는 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/ 폴더의 월별 예상 비용이 자세히 나온 마크다운 테이블이 표시됩니다. 애플리케이션의 월별 프로덕션 비용을 더 잘 이해하기 위해 개발자가 원격 저장소로 코드를 푸시하기 전에 이 단계를 실행할 수 있습니다.

    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. gcloud를 Docker 구성 파일에 사용자 인증 정보 도우미로 등록합니다.

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

    메시지가 표시되면 파일 업데이트를 확인합니다.

  7. 이미지를 Artifact Registry로 내보냅니다.

    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. 범위 필드에서 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: USD 단위의 임곗값으로 이 경우에는 $10입니다. 이전 비용과 새로운 비용의 차이가 이 임곗값을 초과하면 특별한 승인이 적용됩니다. 다른 값의 임곗값을 설정할 수도 있습니다. 이 기능을 살펴보려면 Kubernetes 비용 예측 도구 이미지 빌드 및 푸시에서 ./bin/k8s-cost-estimator 명령어를 실행할 때 --output 매개변수를 추가하면 됩니다. 이 매개변수는 사용 가능한 옵션을 볼 수 있는 .diff 확장자의 파일을 생성합니다.

GKE 클러스터에서 실행되도록 GitLab 실행기 구성

이 섹션에서는 Kubernetes 예측 도구가 Google Cloud 가격 카탈로그를 쿼리할 수 있도록 워크로드 아이덴티티를 통해 자체 GKE 클러스터에 GitLab 실행기를 설치합니다. 예측 도구에서는 총 가격을 사용하며 선점형 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 저장소로 푸시

  1. GitLab 저장소에 샘플 코드를 푸시하도록 SSH 키 쌍을 만듭니다.

    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 저장소로 콘텐츠를 푸시합니다.

    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
    

실제 비용 예측을 확인하기 위해 코드를 변경하고 병합 요청을 제안

  1. Cloud Shell에서 GitLab 웹 통합 개발 환경(IDE)의 URL을 가져옵니다.

    echo "https://gitlab.com/-/ide/project/$GITLAB_USER/k8s-cost-estimator-gitlab/tree/main/-/wordpress/wordpress_hpa.yaml"
    
  2. Ctrl 키(macOS의 경우 Cmd 키)를 누른 채로 출력 URL을 클릭하여 GitLab 웹 IDE로 이동합니다.

  3. GitLab 웹 IDE에서 ./wordpress/wordpress_hpa.yaml 파일을 다음과 같이 수정합니다.

    1. minReplicas 값을 2에서 5로 변경합니다.
    2. 커밋을 클릭합니다.
  4. 다음 스냅샷에 표시된 것처럼 새 분기 만들기새 병합 요청 시작을 선택한 후 커밋을 클릭합니다.

    병합 요청을 시작합니다.

  5. 새 병합 요청 화면의 페이지 하단에서 병합 요청 만들기를 클릭합니다.

    이 단계는 새 병합 요청을 만드는 것 외에도 .gitlab-ci.yml 파일을 기반으로 비용 예측 파이프라인을 트리거합니다. 이 파이프라인에서는 이전 섹션에서 만든 컨테이너 이미지를 사용합니다. 이 파이프라인은 FinOps 승인이 필요한 시점도 결정합니다. 편의를 위해 .gitlab-ci.yml에서 각 병합 요청 기반에 대한 승인을 추가하지만 GitLab 프로젝트 수준에서 정의된 승인 규칙을 정의하고 재사용할 수 있습니다.

  6. 파이프라인이 완료될 때까지 1분 정도 기다립니다. 완료되면 비용 세부정보가 포함된 주석이 병합 요청에 추가됩니다. 제안된 코드의 비용 증가가 $10 임곗값을 초과하기 때문에 FinOps 검토자도 요청됩니다.

    출력은 다음과 비슷합니다.

    병합 요청의 비용 세부정보가 포함된 주석입니다.

    이 튜토리얼에서는 병합 요청 승인에 기본 구성을 사용합니다. Gitlab에서 병합 요청에 서로 다른 구성을 선택할 수도 있습니다. 예를 들어 작성자가 병합 요청을 승인하지 못하게 하려면 설정 > 일반 > 병합 요청(MR) 승인 > 승인 설정으로 이동합니다.

삭제

이 튜토리얼에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 프로젝트를 삭제하면 됩니다.

프로젝트 삭제

  1. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

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

다음 단계