Spinnaker 및 Google Kubernetes Engine을 사용한 지속적 배포 파이프라인

이 가이드에서는 Google Kubernetes Engine(GKE), Cloud Source Repositories, Cloud Build, Resource Manager, Spinnaker를 사용하여 지속적 배포 파이프라인을 만드는 방법을 보여줍니다. 샘플 앱을 만든 후 이러한 서비스를 구성하여 앱을 자동으로 빌드, 테스트, 배포합니다. 앱 코드를 수정하면 변경사항으로 인해 지속적 배포 파이프라인이 트리거되어 새 버전이 자동으로 다시 빌드, 테스트, 배포됩니다.

파이프라인 아키텍처

파이프라인 아키텍처

사용자에게 앱 업데이트를 지속적으로 배포하려면 소프트웨어를 안정적으로 빌드, 테스트, 업데이트하는 자동화된 프로세스가 필요합니다. 코드 변경사항이 아티팩트 생성, 단위 테스트, 기능 테스트, 프로덕션 출시를 포함하는 파이프라인을 자동으로 통과해야 합니다. 경우에 따라서는 코드 업데이트를 전체 사용자층에 푸시하기 전에 실사용 시험을 거치기 위해 사용자 중 일부에만 적용해야 합니다. 이러한 카나리아 출시 버전 중 하나에서 문제점이 드러날 경우 자동화된 절차를 통해 소프트웨어 변경사항을 빠르게 롤백할 수 있어야 합니다.

GKE와 Spinnaker를 사용하면 개발 및 검증을 거친 소프트웨어를 최대한 빠르게 출시하는 데 도움이 되는 견고한 지속적 배포 흐름을 만들 수 있습니다. 최종 목표는 반복 주기의 속도를 높이는 것이지만, 각 앱 버전을 프로덕션 출시 후보로 승격하기 전에 우선 자동화된 일련의 검증을 통과하는지 확인해야 합니다. 특정 변경사항이 자동화 과정을 통과했다면 앱을 수동으로 검증하고 출시 전 테스트를 추가로 수행할 수도 있습니다.

팀에서 앱이 프로덕션 준비가 된 것으로 판정하면 팀원 중 한 명이 프로덕션 배포를 위해 앱을 승인할 수 있습니다.

앱 배포 파이프라인

이 가이드에서는 아래 다이어그램에 표시된 지속적 배포 파이프라인을 구축합니다.

앱 배포 파이프라인

목표

  • Cloud Shell을 실행하고, GKE 클러스터를 만들고, ID 및 사용자 관리 체계를 구성하여 환경을 설정합니다.
  • 샘플 앱을 다운로드하고, Git 저장소를 만들고, Cloud Source Repository에 업로드합니다.
  • Helm을 사용하여 GKE에 Spinnaker를 배포합니다.
  • Docker 이미지를 빌드합니다.
  • 앱이 변경될 때 Docker 이미지를 생성하는 트리거를 만듭니다.
  • Spinnaker 파이프라인을 구성하여 GKE에 앱을 안정적, 지속적으로 배포합니다.
  • 코드 변경사항을 배포하여 파이프라인을 트리거하고 프로덕션으로 진행되는 것을 확인합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음을 비롯한 Google Cloud Platform(GCP)의 구성요소를 사용합니다.

  • GKE
  • Cloud Load Balancing
  • Cloud Build
  • Resource Manager

가격 계산기를 사용하면 예상 사용량을 기준으로 예상 비용을 산출할 수 있습니다.

GCP 신규 사용자는 무료 평가판을 사용할 수 있습니다.

시작하기 전에

  1. Google 계정에 로그인합니다.

    아직 계정이 없으면 새 계정을 등록하세요.

  2. Select or create a Google Cloud Platform project.

    Go to the Manage resources page

  3. 프로젝트에 결제가 사용 설정되어 있는지 확인하세요.

    결제 사용 설정 방법 알아보기

  4. GKE, Cloud Build, Resource Manager APIs를 사용 설정합니다.

    APIs 사용 설정

환경 설정

이 섹션에서는 가이드를 완료하는 데 필요한 인프라 및 ID를 구성합니다.

Cloud Shell 인스턴스 시작 및 GKE 클러스터 만들기

Cloud Shell에서 이 가이드의 모든 터미널 명령어를 실행합니다.

  1. Cloud Shell을 엽니다.

    Cloud Shell 열기

  2. 다음 명령어로 Spinnaker 및 샘플 앱을 배포할 GKE 클러스터를 만듭니다.

    gcloud config set compute/zone us-central1-f
    
    gcloud container clusters create spinnaker-tutorial \
        --machine-type=n1-standard-2
    

ID 및 액세스 관리 구성

Cloud Identity and Access Management(Cloud IAM) 서비스 계정을 만들어 Spinnaker가 Cloud Storage에 데이터를 저장할 수 있도록 권한을 위임합니다. Spinnaker는 안정성과 복원성을 보장하기 위해 파이프라인 데이터를 Cloud Storage에 저장합니다. Spinnaker 배포가 예기치 않게 실패하면 몇 분만에 원본과 같은 파이프라인 데이터에 액세스할 수 있는 동일한 배포를 만들 수 있습니다.

  1. 서비스 계정을 만듭니다.

    gcloud iam service-accounts create  spinnaker-storage-account \
        --display-name spinnaker-storage-account
    

  2. 이후에 명령어에서 사용할 수 있도록 서비스 계정 이메일 주소 및 현재 프로젝트 ID를 환경 변수에 저장합니다.

    export SA_EMAIL=$(gcloud iam service-accounts list \
        --filter="displayName:spinnaker-storage-account" \
        --format='value(email)')
    export PROJECT=$(gcloud info --format='value(config.project)')
    

  3. 서비스 계정에 storage.admin 역할을 부여합니다.

    gcloud projects add-iam-policy-binding \
        $PROJECT --role roles/storage.admin --member serviceAccount:$SA_EMAIL
    

  4. 서비스 계정 키를 다운로드합니다. 이후에 Spinnaker를 설치하고 GKE에 키를 업로드할 때 이 키가 필요합니다.

    gcloud iam service-accounts keys create spinnaker-sa.json --iam-account $SA_EMAIL
    

Helm을 사용하여 Spinnaker 배포

이 섹션에서는 Helm을 사용하여 Charts 저장소에서 Spinnaker를 배포합니다. Helm은 Kubernetes 앱을 구성하고 배포하는 데 사용할 수 있는 패키지 관리자입니다.

Helm 설치

  1. helm 바이너리를 다운로드하고 설치합니다.

    wget https://storage.googleapis.com/kubernetes-helm/helm-v2.7.2-linux-amd64.tar.gz
    

  2. 로컬 시스템에 파일의 압축을 풉니다.

    tar zxfv helm-v2.7.2-linux-amd64.tar.gz
    
    cp linux-amd64/helm .
    

  3. Helm의 서버 측 요소인 Tiller에 클러스터의 cluster-admin 역할을 부여합니다.

    kubectl create clusterrolebinding user-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)
    kubectl create serviceaccount tiller --namespace kube-system
    kubectl create clusterrolebinding tiller-admin-binding --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
    

  4. Spinnaker가 모든 네임스페이스의 리소스를 배포할 수 있도록 cluster-admin 역할을 부여합니다.

    kubectl create clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:default spinnaker-admin
    

  5. Helm을 초기화하여 클러스터에 Tiller를 설치합니다.

    ./helm init --service-account=tiller
    ./helm update

  6. 다음 명령어를 실행하여 Helm이 정상적으로 설치되었는지 확인합니다. Helm이 올바르게 설치되었으면 클라이언트와 서버에 v2.7.2가 표시됩니다.

    ./helm version

    Client: &version.Version{SemVer:"v2.7.2",
    GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6",
    GitTreeState:"clean"}Server: &version.Version{SemVer:"v2.7.2",
    GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6",
    GitTreeState:"clean"}
    

Spinnaker 구성

  1. Spinnaker에서 파이프라인 구성을 저장할 버킷을 만듭니다.

    export PROJECT=$(gcloud info \
        --format='value(config.project)')
    export BUCKET=$PROJECT-spinnaker-config
    gsutil mb -c regional -l us-central1 gs://$BUCKET

  2. 구성 파일을 만듭니다.

    export SA_JSON=$(cat spinnaker-sa.json)
    export PROJECT=$(gcloud info --format='value(config.project)')
    export BUCKET=$PROJECT-spinnaker-config
    cat > spinnaker-config.yaml <<EOF
    storageBucket: $BUCKET
    gcs:
      enabled: true
      project: $PROJECT
      jsonKey: '$SA_JSON'

    # Disable minio as the default minio: enabled: false

    # Configure your Docker registries here accounts: - name: gcr address: https://gcr.io username: _json_key password: '$SA_JSON' email: 1234@5678.com EOF

Spinnaker 차트 배포

  1. Helm 명령줄 인터페이스를 사용하여 설정된 구성으로 차트를 배포합니다. 이 명령어가 완료되려면 일반적으로 5~10분이 걸립니다.

    ./helm install -n cd stable/spinnaker -f spinnaker-config.yaml --timeout 600 \
        --version 0.3.1

  2. 명령어가 완료되면 다음 명령어를 실행하여 Cloud Shell에서 Spinnaker UI로 포트 전달을 설정합니다.

    export DECK_POD=$(kubectl get pods --namespace default -l "component=deck" \
        -o jsonpath="{.items[0].metadata.name}")
    kubectl port-forward --namespace default $DECK_POD 8080:9000 >> /dev/null &
    

  3. Spinnaker 사용자 인터페이스를 열려면 Cloud Shell에서 웹 미리보기를 클릭하고 포트 8080에서 미리보기를 클릭합니다.

    port8080

  4. 시작 화면이 표시된 후 Spinnaker UI가 표시됩니다.

    hello

    spinui

Docker 이미지 빌드

이 섹션에서는 앱 소스 코드의 변경사항을 감지하고 Docker 이미지를 빌드하여 Container Registry에 푸시하도록 Cloud Build를 구성합니다.

소스 코드 저장소 만들기

  1. 소스 코드를 다운로드합니다.

    wget https://gke-spinnaker.storage.googleapis.com/sample-app.tgz
    

  2. 소스 코드의 압축을 풉니다.

    tar xzfv sample-app.tgz
    

  3. 소스 코드로 디렉토리를 변경합니다.

    cd sample-app
    

  4. 이 저장소의 Git 커밋에 대한 사용자 이름과 이메일 주소를 설정합니다. [EMAIL_ADDRESS]를 Git 이메일 주소로, [USERNAME]을 Git 사용자 이름으로 바꿉니다.

    git config --global user.email "[EMAIL_ADDRESS]"
    git config --global user.name "[USERNAME]"
    

  5. 소스 코드 저장소에 대한 최초 커밋을 수행합니다.

    git init
    git add .
    git commit -m "Initial commit"
    

  6. 코드를 호스팅할 저장소를 만듭니다.

    gcloud source repos create sample-app
    git config credential.helper gcloud.sh
    

  7. 새로 만든 저장소를 원격으로 추가합니다.

    export PROJECT=$(gcloud info --format='value(config.project)')
    git remote add origin https://source.developers.google.com/p/$PROJECT/r/sample-app
    

  8. 새 저장소의 마스터 브랜치에 코드를 푸시합니다.

    git push origin master

  9. 콘솔에서 소스 코드를 볼 수 있는지 확인합니다.

    소스 코드 페이지로 이동

빌드 트리거 구성

이 섹션에서는 소스 저장소에 Git 태그를 푸시할 때마다 Docker 이미지를 빌드하여 푸시하도록 Cloud Build를 구성합니다. Cloud Build는 자동으로 소스 코드를 체크아웃하고, 저장소의 Dockerfile로 Docker 이미지를 빌드하고, Container Registry에 해당 이미지를 푸시합니다.

Spinnaker 워크플로

  1. GCP 콘솔의 Cloud Build 섹션에서 빌드 트리거를 클릭합니다.

    빌드 트리거 페이지로 이동

  2. Cloud Source Repository를 선택하고 계속을 클릭합니다.

  3. 새로 만든 sample-app 저장소를 목록에서 선택하고 계속을 클릭합니다.
  4. 다음 트리거 설정을 지정합니다.

    • 이름:sample-app-tags
    • 트리거 유형: 태그
    • 태그(정규 표현식): v.*
    • 빌드 구성: cloudbuild.yaml
    • cloudbuild.yaml 위치: /cloudbuild.yaml

  5. 트리거 만들기를 클릭합니다.

    트리거 만들기

이제부터는 'v' 프리픽스가 있는 Git 태그를 소스 코드 저장소에 푸시할 때마다 Cloud Build에서 자동으로 앱을 빌드하여 Docker 이미지로 Container Registry에 푸시합니다.

이미지 빌드

다음 단계에 따라 첫 번째 이미지를 푸시합니다.

  1. Cloud Shell에서 소스 코드 폴더로 이동합니다.
  2. Git 태그를 만듭니다.

    git tag v1.0.0

  3. 태그를 푸시합니다.

    git push --tags

  4. Container Registry에서 빌드 기록을 클릭하여 빌드가 트리거되었는지 확인합니다. 그렇지 않은 경우 이전 섹션에서 트리거를 올바르게 구성했는지 확인합니다.

    빌드 기록으로 이동

    빌드 기록

배포 파이프라인 구성

이제 이미지가 자동으로 빌드되므로, 이미지를 Kubernetes 클러스터에 배포할 차례입니다.

통합 테스트를 위해 규모가 축소된 환경을 배포합니다. 통합 테스트에 성공한 후에는 변경사항을 직접 승인하여 프로덕션 서비스에 코드를 배포해야 합니다.

배포 파이프라인 구성

앱 만들기

  1. Spinnaker UI에서 Actions(작업)를 클릭한 다음 Create Application(애플리케이션 만들기)를 클릭합니다.

    앱 만들기

  2. New Application(새 애플리케이션) 대화상자에서 다음 필드를 입력합니다.

    • Name(이름): sample
    • Owner Email(소유자 이메일): [내 이메일 주소]

  3. Create(만들기)를 클릭합니다.

    앱 만들기

서비스 부하 분산기 만들기

UI에 직접 정보를 입력할 필요가 없도록 Kubernetes 명령줄 인터페이스를 사용하여 서비스용 부하 분산기를 만듭니다. Spinnaker UI에서 이 작업을 수행할 수도 있습니다.

Cloud Shell의 sample-app 루트 디렉토리에서 다음 명령어를 실행합니다.

kubectl apply -f k8s/services

배포 파이프라인 만들기

이제 지속적 배포 파이프라인을 만들 차례입니다. 이 가이드에서는 'v' 프리픽스가 있는 태그를 가진 Docker 이미지가 Container Registry에 도착하는 시점을 감지하도록 파이프라인을 구성합니다.

  1. Cloud Shell의 새 탭에서 소스 코드 디렉토리에서 다음 명령어를 실행하여 예제 파이프라인을 Spinnaker 인스턴스에 업로드합니다.

    export PROJECT=$(gcloud info --format='value(config.project)')
    sed s/PROJECT/$PROJECT/g spinnaker/pipeline-deploy.json | curl -d@- -X \
        POST --header "Content-Type: application/json" --header \
        "Accept: /" http://localhost:8080/gate/pipelines
    

  2. Spinnaker UI의 상단 탐색 메뉴에서 Pipelines(파이프라인)를 클릭합니다.

    Spinnaker 파이프라인

  3. Deploy 파이프라인에서 Configure(구성)를 클릭합니다.

    파이프라인 구성

    지속적 배포 파이프라인 구성이 UI에 다음과 같이 표시됩니다.

    지속적 배포 파이프라인

수동으로 파이프라인 실행

'v' 프리픽스가 있는 새 Git 태그를 푸시하면 방금 만든 구성에 포함된 트리거가 파이프라인을 시작합니다. 이 가이드 섹션에서는 파이프라인을 수동으로 실행하여 테스트합니다. 다음 섹션에서는 Git 태그를 푸시하고 파이프라인이 자동으로 실행되는지 확인하는 방법으로 테스트합니다.

  1. Pipelines(파이프라인)를 클릭하여 Pipelines(파이프라인) 페이지로 돌아갑니다.
  2. Start Manual Execution(수동 실행 시작)을 클릭합니다.

    직접 시작

  3. Tag(태그) 드롭다운 목록에서 v1.0.0 태그를 선택하고 Run(실행)을 클릭합니다.

    실행

  4. 파이프라인이 시작된 후 Details(세부정보)를 클릭하여 빌드의 진행 상태를 자세히 확인합니다. 이 섹션에서는 배포 파이프라인의 상태와 단계를 보여줍니다. 파란색은 현재 실행 중인 단계, 녹색은 정상적으로 완료된 단계, 빨간색은 실패한 단계입니다. 단계를 클릭하면 세부정보를 볼 수 있습니다.

    3~5분이 지나면 통합 테스트 단계가 완료되고, 파이프라인을 수동으로 승인해야 배포가 계속 진행됩니다.

  5. 노란색 사람 아이콘에 마우스를 가져가고 Continue(계속)를 클릭합니다.

    프로덕션으로 푸시

    프로덕션 프런트엔드 및 백엔드 배포로 출시가 진행됩니다. 이 작업은 몇 분 후에 완료됩니다.

  6. 앱을 확인하려면 Spinnaker UI 오른쪽 상단에서 Load Balancers(부하 분산기)를 클릭합니다.

    부하 분산기

  7. 부하 분산기 목록을 아래로 스크롤하고 sample-frontend-prod 아래의 Default(기본값)를 클릭합니다.

    기본 부하 분산기

  8. 오른쪽의 세부정보 창을 아래로 스크롤하고 Ingress(수신) IP의 클립보드 버튼을 클릭하여 앱의 IP 주소를 복사합니다.

    앱의 IP 주소 복사

  9. 브라우저에 주소를 붙여넣어 앱의 프로덕션 버전을 확인합니다.

    백엔드

    이제 수동으로 파이프라인을 트리거하여 앱을 빌드, 테스트, 배포했습니다.

코드 변경에 따라 파이프라인 트리거

이 섹션에서는 코드를 변경하고, Git 태그를 푸시하고, 여기에 따른 응답으로 파이프라인이 실행되는지 확인하는 방법으로 파이프라인을 엔드 투 엔드 테스트합니다. 'v'로 시작되는 Git 태그를 푸시하면 새 Docker 이미지를 빌드하여 Container Registry에 푸시하도록 Cloud Build가 트리거됩니다. Spinnaker는 'v'로 시작되는 새 이미지 태그를 감지하여 카나리아 환경에 이미지를 배포하고, 테스트를 실행하고, 배포의 모든 포드에 동일한 이미지를 적용하는 파이프라인을 트리거합니다.

  1. 앱의 색상을 주황색에서 파란색으로 변경합니다.

    sed -i 's/orange/blue/g' cmd/gke-info/common-service.go
    

  2. 변경사항에 태그를 지정하고 소스 코드 저장소에 푸시합니다.

    git commit -a -m "Change color to blue"
    git tag v1.0.1
    git push --tags
    

  3. Cloud Build 빌드 기록에 새 빌드가 표시되는지 확인합니다.

  4. Pipelines(파이프라인)를 클릭하여 파이프라인이 이미지 배포를 시작하는지 확인합니다.

  5. 카나리아 배포를 관찰합니다. 프로덕션 적용을 기다리느라 배포가 일시중지되면 앱을 포함하는 탭을 새로고침합니다. 백엔드 중 9개는 앱의 이전 버전을 실행하며, 카나리아 버전을 실행하는 백엔드는 하나뿐입니다. 새로고침을 10번 수행할 때마다 앱의 새로운 파란색 버전이 표시됩니다.

  6. 테스트가 완료되면 Spinnaker 탭으로 돌아가서 배포를 승인합니다.

  7. 파이프라인이 완료되면 앱이 다음 스크린샷처럼 표시됩니다. 코드가 변경되어 색상이 파란색으로 바뀌었으며 Version(버전) 필드가 이제 v1.0.1로 표시됩니다.

    앱 백엔드

    이제 앱이 전체 프로덕션 환경에 정상적으로 출시되었습니다.

  8. 필요한 경우 이전 커밋을 되돌리면 이 변경사항을 롤백할 수 있습니다. 롤백을 수행하면 새 태그(v1.0.2)가 추가되고 v1.0.1을 배포하는 데 사용한 파이프라인을 통해 태그가 다시 푸시됩니다.

    git revert v1.0.1
    git tag v1.0.2
    git push --tags

삭제

이 가이드에서 사용한 리소스 비용이 Google Cloud Platform 계정에 청구되지 않도록 하는 방법은 다음과 같습니다.

  1. Spinnaker 설치를 삭제합니다.

    ../helm delete --purge cd
    

  2. 샘플 앱 서비스를 삭제합니다.

    kubectl delete -f k8s/services
    

  3. 서비스 계정을 삭제합니다.

    export SA_EMAIL=$(gcloud iam service-accounts list \
        --filter="displayName:spinnaker-storage-account" --format='value(email)')
    gcloud iam service-accounts delete $SA_EMAIL
    

  4. GKE 클러스터를 삭제합니다.

    gcloud container clusters delete spinnaker-tutorial
    

  5. 저장소를 삭제합니다.

    gcloud source repos delete sample-app
    

  6. 버킷을 삭제합니다.

    export PROJECT=$(gcloud info --format='value(config.project)')
    export BUCKET=$PROJECT-spinnaker-config
    gsutil -m rm -r gs://$BUCKET
    

  7. 컨테이너 이미지를 삭제합니다.

    export PROJECT=$(gcloud info --format='value(config.project)')
    gcloud container images delete gcr.io/$PROJECT/sample-app:v1.0.0
    gcloud container images delete gcr.io/$PROJECT/sample-app:v1.0.1
    

  8. 위의 선택적 롤백 단계에서 v1.0.2를 만든 경우 해당 컨테이너 이미지를 삭제합니다.

    gcloud container images delete gcr.io/$PROJECT/sample-app:v1.0.2
    

다음 단계

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...