Jenkins로 Kubernetes Engine에 지속적 배포

이 가이드에서는 Jenkins와 GKE를 사용하여 아래 다이어그램과 같은 지속적 배포 파이프라인을 설정하는 방법을 보여줍니다.

jenkins cd arch

목표

  • 샘플 애플리케이션 이해
  • Kubernetes에 애플리케이션 배포
  • Cloud Source Repositories에 코드 업로드
  • Jenkins에 배포 파이프라인 만들기
  • 개발 환경 배포
  • 카나리아 출시 버전 배포
  • 프로덕션 환경 배포

비용

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

  • Compute Engine
  • Google Kubernetes Engine
  • Cloud Build

가격 계산기를 사용하여 이 가이드의 예상 사용량을 기준으로 예상 비용을 산출할 수 있습니다. GCP 신규 사용자는 무료 평가판을 사용할 수 있습니다.

시작하기 전에

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

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

  2. Google Cloud Platform 프로젝트를 선택하거나 만듭니다.

    리소스 관리 페이지로 이동

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

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

  4. 필요한 Compute Engine, Kubernetes Engine, Cloud Build APIs를 사용 설정합니다.

    APIs사용 설정

환경 준비

  1. GKE에서 Jenkins 설정 가이드를 완료합니다.

  2. Cloud Shell에서 샘플 애플리케이션 디렉토리로 이동합니다.

    cd continuous-deployment-on-kubernetes/sample-app
    

애플리케이션 이해

지속적 배포 파이프라인에 샘플 애플리케이션인 gceme를 배포하려고 합니다. 이 애플리케이션은 Go 언어로 작성되었으므로 저장소의 sample-app 디렉토리에 있습니다. Compute Engine 인스턴스에서 gceme 바이너리를 실행하면 앱에서 정보 카드에 인스턴스의 메타데이터를 표시합니다.

gceme 정보 카드

이 애플리케이션은 마이크로 서비스를 모방하여 두 가지 작동 모드를 지원합니다.

  • 백엔드 모드에서 gceme는 포트 8080을 수신 대기하고 Compute Engine 인스턴스 메타데이터를 JSON 형식으로 반환합니다.

  • 프런트엔드 모드에서 gceme는 백엔드 gceme 서비스를 쿼리하고 결과 JSON을 사용자 인터페이스에 렌더링합니다.

gceme 아키텍처

프런트엔드 및 백엔드 모드에서는 두 가지 URL을 추가로 지원합니다.

  • /version은 실행 중인 버전을 출력합니다.
  • /healthz는 애플리케이션의 상태를 보고합니다. 프런트엔드 모드에서는 백엔드에 도달할 수 있으면 상태가 OK로 표시됩니다.

Kubernetes에 샘플 앱 배포

배포 환경을 기술하는 매니페스트 파일을 사용하여 gceme 프런트엔드 및 백엔드를 Kubernetes에 배포합니다. 이 파일은 가이드의 뒷부분에서 업데이트하는 기본 이미지를 사용합니다.

두 가지 환경에 애플리케이션을 배포합니다.

  • 프로덕션. 사용자가 액세스하는 실제 사이트입니다.

  • 카나리아. 사용자 트래픽 중 일정 비율을 수용하는 소규모 사이트입니다. 이 환경을 사용하여 실제 트래픽으로 소프트웨어의 이상 유무를 확인한 후 실제 환경에 소프트웨어를 배포합니다.

우선 애플리케이션을 프로덕션 환경에 배포하여 파이프라인에 실제 작동 코드를 적용합니다.

  1. Kubernetes 네임스페이스를 만들어 프로덕션 배포를 논리적으로 격리합니다.

    kubectl create ns production
    
  2. 카나리아 및 프로덕션 배포와 서비스를 만듭니다.

    kubectl --namespace=production apply -f k8s/production
    kubectl --namespace=production apply -f k8s/canary
    kubectl --namespace=production apply -f k8s/services
    
  3. 프로덕션 환경 프런트엔드를 확장합니다.

    kubectl --namespace=production scale deployment gceme-frontend-production --replicas=4
    
  4. 프로덕션 서비스의 외부 IP를 검색합니다. 부하 분산기 IP 주소가 확인될 때까지 몇 분 정도 걸릴 수 있습니다.

    kubectl --namespace=production get service gceme-frontend
    

    프로세스가 완료되면 EXTERNAL-IP 열에 IP 주소가 표시됩니다.

    NAME             TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
    gceme-frontend   LoadBalancer   10.35.254.91   35.196.48.78   80:31088/TCP   1m
    

  5. 프런트엔드 서비스 부하 분산기 IP를 환경 변수에 저장합니다.

    export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=production services gceme-frontend)
    
  6. 브라우저에서 프런트엔드 외부 IP 주소를 열어 두 서비스가 정상 작동하는지 확인합니다.

  7. 다음 섹션에서 지속적 업데이트를 관찰할 수 있도록 별도의 터미널을 열고 프로덕션 엔드포인트의 /version URL을 폴링합니다.

    while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1;  done
    

샘플 앱 소스 코드를 호스팅하는 저장소 만들기

다음으로, gceme 샘플 앱의 복사본을 만들고 Cloud Source Repositories에 푸시합니다.

  1. Cloud Source Repositories에 저장소를 만듭니다.

    gcloud source repos create gceme
    
  2. 로컬 Git 저장소를 초기화합니다.

    git init
    git config credential.helper gcloud.sh
    export PROJECT_ID=$(gcloud config get-value project)
    git remote add origin https://source.developers.google.com/p/$PROJECT_ID/r/gceme
    
  3. 이 저장소의 Git 커밋에 대한 사용자 이름과 이메일 주소를 설정합니다.

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

    [EMAIL_ADDRESS]를 Git 이메일 주소로 바꿉니다.

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

    [USERNAME]을 Git 사용자 이름으로 바꿉니다.

  4. 파일을 추가, 커밋, 푸시합니다.

    git add .
    git commit -m "Initial commit"
    git push origin master
    

파이프라인 만들기

Jenkins를 사용하여 gceme 복사본을 테스트하고 빌드한 후 Kubernetes 클러스터에 배포하는 파이프라인을 정의하고 실행합니다.

서비스 계정 사용자 인증 정보 추가

사용자 인증 정보를 구성하여 Jenkins가 코드 저장소에 액세스하도록 허용합니다.

  1. Jenkins 사용자 인터페이스의 왼쪽 탐색 메뉴에서 Credentials(사용자 인증 정보)를 클릭합니다.
  2. Credentials(사용자 인증 정보) 테이블에서 Jenkins 링크를 클릭합니다.

    Jenkins 사용자 인증 정보 그룹

  3. Global Credentials(전역 사용자 인증 정보)를 클릭합니다.

  4. 왼쪽 탐색 메뉴에서 Add Credentials(사용자 인증 정보 추가)를 클릭합니다.
  5. Kind(종류) 드롭다운에서 Google Service Account from metadata(메타데이터의 Google 서비스 계정)를 선택합니다.
  6. OK(확인)를 클릭합니다.

이제 전역 인증 정보가 두 개 있습니다. 이 가이드에서 이후에 사용할 수 있도록 두 번째 인증 정보의 이름을 기록해 둡니다.

Jenkins 사용자 인증 정보

Jenkins 작업 만들기

다음으로, Jenkins Pipeline 기능을 사용하여 빌드 파이프라인을 구성합니다. Jenkins Pipeline 파일은 Groovy 유사 구문을 사용하여 작성됩니다.

Jenkins 사용자 인터페이스로 이동하고 다음 단계에 따라 파이프라인 작업을 구성합니다.

  1. 인터페이스 왼쪽 상단의 Jenkins 링크를 클릭합니다.

  2. 왼쪽 탐색 메뉴에서 New Item(새 항목) 링크를 클릭합니다.

  3. 프로젝트 이름을 sample-app으로 지정하고 Multibranch Pipeline(다중 브랜치 파이프라인) 옵션을 선택한 후 OK(확인)를 클릭합니다.

  4. 다음 페이지에서 Add Source(소스 추가)를 클릭하고 git를 선택합니다.

  5. Cloud Source Repositories에 있는 sample-app 저장소의 HTTPS clone URL(HTTPS 복제본 URL)Project Repository(프로젝트 저장소) 필드에 붙여넣습니다. [PROJECT_ID]를 프로젝트 ID로 바꿉니다.

    https://source.developers.google.com/p/[PROJECT_ID]/r/gceme
    
  6. Credentials(사용자 인증 정보) 드롭다운에서 서비스 계정을 추가할 때 생성한 사용자 인증 정보의 이름을 선택합니다.

  7. Scan Multibranch Pipeline(다중 채널 파이프라인 검색) 섹션에서 Periodically if not otherwise run(별도로 실행되지 않는 경우 주기적으로 실행) 상자를 선택합니다. Interval(간격) 값을 '1 minute'으로 설정합니다.

  8. Save(저장)를 클릭합니다.

    Jenkins 작업 만들기 설정

이 단계를 완료하면 'Branch indexing'이라는 작업이 실행됩니다. 이 메타 작업은 저장소의 브랜치를 식별하고 기존 브랜치에 변경사항이 발생하지 않았는지 확인합니다. Jenkins를 새로고침하면 master 브랜치에 이 작업이 표시됩니다.

다음 단계에서 코드를 변경하기 전에는 최초 작업 실행에 실패합니다.

파이프라인 정의 수정

카나리아 환경용으로 canary라는 브랜치를 만듭니다.

git checkout -b canary

이 파이프라인을 정의하는 Jenkinsfile 컨테이너는 Jenkins Pipeline Groovy 구문으로 작성됩니다. Jenkinsfile을 사용하면 전체 빌드 파이프라인을 소스 코드와 함께 상주하는 단일 파일로 표현할 수 있습니다. 파이프라인은 병렬화, 사용자의 직접 승인 요청과 같은 강력한 기능을 지원합니다.

프로젝트 ID가 1행에 포함되도록 Jenkinsfile을 수정합니다.

카나리아 출시 버전 배포

이제 파이프라인이 적절히 구성되었으므로, gceme 애플리케이션을 변경하고 파이프라인으로 테스트, 패키징, 배포를 진행할 차례입니다.

카나리아 환경은 카나리아 출시 버전으로 설정됩니다. 따라서 변경사항이 프로덕션 부하 분산기 뒤에 있는 포드 중 일부에만 적용됩니다. 이렇게 하려면 Kubernetes에서 같은 라벨을 공유하는 여러 배포를 유지하면 됩니다. 이 애플리케이션에서 gceme-frontend 서비스는 app: gcemerole: frontend 라벨을 갖는 모든 포드를 대상으로 부하를 분산합니다. k8s/frontend-canary.yaml 카나리아 매니페스트 파일은 복제본을 1로 설정하며 gceme-frontend 서비스에 필요한 라벨을 포함합니다.

현재 프런트엔드 포드 5개 중 1개에서 카나리아 코드를 실행 중이며, 다른 4개는 프로덕션 코드를 실행 중입니다. 따라서 카나리아 코드를 전체 포드에 적용하기 전에 사용자에게 부정적인 영향이 없는지를 미리 확인할 수 있습니다.

  1. html.go를 열고 blue가 나오는 두 곳을 orange로 바꿉니다.
  2. main.go를 열고 버전 번호를 1.0.0에서 2.0.0으로 변경합니다.

     const version string = "2.0.0"
    
  3. 다음으로, 해당 파일을 로컬 저장소에 추가하고 커밋합니다.

     git add Jenkinsfile html.go main.go
     git commit -m "Version 2"
    
  4. 마지막으로, 원격 Git 서버에 변경사항을 커밋합니다.

     git push origin canary
    
  5. Git 저장소에 변경사항이 푸시된 후 Jenkins 사용자 인터페이스로 이동하여 빌드가 시작되었는지 여부를 확인합니다.

    Jenkins 최초 빌드 화면

  6. 빌드가 실행되었으면 왼쪽 탐색 메뉴에서 빌드 옆의 아래쪽 화살표를 클릭하고 Console Output을 선택합니다.

    Jenkins 콘솔 탐색

  7. 몇 분 동안 빌드 출력을 추적하면서 kubectl --namespace=production apply... 메시지가 시작되는지 지켜봅니다. 이 메시지가 시작되면 프로덕션 /version URL을 폴링하고 있는 터미널로 돌아가서 요청 중 일부에서 변화가 나타나기 시작하는지 관찰합니다. 이제 사용자 중 일부에게 변경사항이 적용된 상태입니다.

  8. 카나리아 환경에 변경사항이 배포되었으면 코드를 master 브랜치와 병합하고 Git 서버에 푸시하여 나머지 사용자에게 계속 적용할 수 있습니다.

    git checkout master
    git merge canary
    git push origin master
    
  9. 약 1분 후에 sample-app 폴더의 master 작업이 실행됩니다.

    Jenkins 마스터 작업

  10. master 링크를 클릭하면 파이프라인의 단계, 성공/실패 정보, 타이밍 특성이 표시됩니다.

    Jenkins 파이프라인 프로덕션

  11. 프로덕션 URL을 폴링하여 새 버전인 2.0.0이 적용되었으며 모든 사용자의 요청을 처리하고 있는지 확인합니다.

    export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)
    while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1;  done
    

프로젝트의 Jenkinsfile을 확인하여 워크플로를 살펴볼 수 있습니다.

개발 브랜치 배포

작업하는 변경사항이 중대하여 카나리아 환경에 직접 푸시할 수 없는 경우도 있습니다. 개발 브랜치는 개발자가 코드 변경사항을 제출하여 실제 사이트에 통합하기 전에 테스트하는 데 사용하는 환경 세트입니다. 이러한 환경은 애플리케이션의 축소된 버전이지만 실제 환경과 동일한 메커니즘으로 배포됩니다.

형상 브랜치로부터 개발 환경을 만들려면 브랜치를 Git 서버에 푸시하고 Jenkins를 통해 환경을 배포합니다. 공개용 부하 분산기는 개발 시나리오에서 사용하지 않습니다. 애플리케이션의 보안을 강화하려는 경우 kubectl 프록시를 사용할 수 있습니다. 이 프록시는 Kubernetes API에 자신을 인증하며, 내 서비스를 인터넷에 노출하지 않고도 로컬 머신의 요청을 클러스터의 서비스로 중계합니다.

  1. 다른 브랜치를 만들고 Git 서버에 푸시합니다.

    git checkout -b new-feature
    git push origin new-feature
    

새 작업이 생성되고, 개발 환경은 생성 중인 상태가 됩니다. 작업의 콘솔 출력 하단에는 환경에 액세스하는 방법에 대한 안내가 표시됩니다.

  1. 백그라운드에서 프록시를 시작합니다.

    kubectl proxy &
    
  2. localhost를 사용하여 애플리케이션에 액세스할 수 있는지 확인합니다.

    curl http://localhost:8001/api/v1/proxy/namespaces/new-feature/services/gceme-frontend:80/
    
  3. 이제 이 브랜치에 코드를 푸시하여 개발 환경을 업데이트할 수 있습니다. 작업을 마쳤으면 브랜치를 canary에 다시 병합하여 카나리아 환경에 해당 코드를 배포합니다.

    git checkout canary
    git merge new-feature
    git push origin canary
    
  4. 코드가 프로덕션 환경에서 문제를 일으키지 않을 것으로 확인되었으면 canary 브랜치에서 master 브랜치로 병합하여 배포를 실행합니다.

    git checkout master
    git merge canary
    git push origin master
    
  5. 개발 브랜치 사용을 마쳤으면 서버에서 해당 브랜치를 삭제하고 Kubernetes 클러스터에서 환경을 삭제합니다.

    git push origin :new-feature
    kubectl delete ns new-feature
    

삭제

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

프로젝트 삭제

청구되지 않도록 하는 가장 쉬운 방법은 가이드에서 만든 프로젝트를 삭제하는 것입니다.

프로젝트를 삭제하는 방법은 다음과 같습니다.

  1. GCP Console에서 프로젝트 페이지로 이동합니다.

    프로젝트 페이지로 이동

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

다음 단계

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

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