CircleCI - GitHub 연동 및 EKS 구성하기

7 분 소요

CI/CD는 개발단계에서 지속적인 통합, 배포를 통해 효율성을 높여주는 도구라고 말할수 있다. 특히 GitOps가 중요시 되는 최근 트렌드에서 Public Git서비스와 통합은 필수적인 요소이다.

GitHub MarketPlace에서 CI 라고 검색하면 다음과 같은 결과를 얻을수 있다.

github-ci

CircleCI, Travis CI, Google Cloud Build 등 최근 트렌드한 도구들을 확인할 수 있다.

이번 포스팅에서는 CircleCIGitHub과 연동해서 AWS ECR Push 및 EKS로 배포하는 간단한 Pipeline을 구성하는 방법을 적어보고자 한다.

CircleCI - GitHub Accout 연동

circleci.com에 접속하여 Sign Up을 진행하면 GitHub과 BitBucket 계정을 연동할 수 있는데 일반적인 GitHub 3rd Party OAuth연동 진행을 하게된다.

init

위 그림처럼 모든 Repository가 확인되고 Follow할 Repository를 선택하면 초기 구성이 완료된다.

error

첫 연동이 되면 Build를 진행하게 되는데 위 그림과 같이 error를 보게 되는데 이는 기본적으로 circleci가 필요로 하는 기본 설정값(.circleci/config.yaml)이 없어서 발생하는 오류이다.

#!/bin/sh -eo pipefail
# No configuration was found in your project. Please refer to https://circleci.com/docs/2.0/ to get started with your configuration.
# 
# -------
# Warning: This configuration was auto-generated to show you the message above.
# Don't rerun this job. Rerunning will have no effect.
false

위에서 보이는것 처럼 config를 체크하는것도 하나의 가상머신(컨테이너)이 진행하는데 CircleCI콘솔에서 Spin up Environment 로그를 보면 Docker(18.09.6)로 aws Linux기반으로 환경구성을 하는 것을 알 수 있다.

Build-agent version 1.0.11727-b0960fc9 (2019-05-23T02:12:54+0000)
Docker Engine Version: 18.09.6
Kernel Version: Linux 9a20a41aeae4 4.15.0-1035-aws #37-Ubuntu SMP Mon Mar 18 16:15:14 UTC 2019 x86_64 Linux
Starting container bash:4.4.19
  using image bash@sha256:9f0a4aa3c9931bd5fdda51b1b2b74a0398a8eabeaf9519d807e010b9d9d41993
...

CircleCI Grossary

아래 링크는 CircleCI에서 자주 사용하는 용어들을 따로 정리한 페이지이다. 주로 컨테이너 기반으로 동작하기 때문에 용어들은 Docker에서 사용하는 용어과 겹치는 부분이 많다.

https://circleci.com/docs/2.0/glossary/

위 링크 내용을 확인하면 Orbs라는 용어가 나오는데 이는 공유가능한 패키지로 Jenkins의 Plugin과 유사한 개념이라고 보면 된다. CircleCI에서 제공하는 자체 패키지 뿐만 아니라 3rd Party orbs를 제공하고 있다.

MacOS에서는 brew를 통해 cli를 설치하고 orb 리스트를 확인하거나 https://circleci.com/orbs/registry/에서 확인할 수 있다.

$ brew install circleci
$ circleci orb list
Orbs found: 43. Showing only certified orbs.
Add --uncertified for a list of all orbs.

circleci/android (0.1.0)
circleci/artifactory (1.0.0)
circleci/aws-cli (0.1.13)
circleci/aws-code-deploy (0.0.9)
circleci/aws-ecr (6.1.0)
circleci/aws-ecs (0.0.8)
circleci/aws-eks (0.1.0)
circleci/aws-s3 (1.0.11)
...
circleci/jira (1.0.5)
circleci/jq (1.9.0)
circleci/kubernetes (0.3.0)
circleci/lein-nvd (0.0.2)
circleci/maven (0.0.8)
circleci/node (1.0.1)
...
circleci/slack (3.2.0)
circleci/twilio (0.0.1)
circleci/welcome-orb (0.3.1)

In order to see more details about each orb, type: `circleci orb info orb-namespace/orb-name`

Search, filter, and view sources for all Orbs online at https://circleci.com/orbs/registry/

Circle Architecture

circle-arch

GitHub 또는 Bitbucket에서 관리하는 Repository가 CircleCI 프로젝트로 승인되면 최초에는 컨테이너나 가상머신환경(2core 4GB)이 프로비저닝 되고 자동으로 테스트가 진행된다.

테스트가 완료된 후 성공 또는 실패에 대한 Alert설정(Email, Slack)이 가능하고 각 단계(job, workflow)에 대한 결과는 각 단계별 세부 정보 페이지에서 확인할 수 있다.

또한 배포는 AWS CodeDeploy, AWS ECS, AWS S3, AWS EKS, Google Kubernetes Engine (GKE) 및 Heroku 등 다양한 환경에 코드를 배포하도록 구성 할 수 있다. 이외의 클라우드 서비스 배포는 SSH를 통해 직접 사용하거나 terraform과 같은 도구를 가지고 해당 클라우드 서비스의 API통해 자동화가 가능한 구조로 되어있다.

CircelCI AWS EKS

https://github.com/CircleCI-Public/circleci-demo-aws-eks

위 demo는 CircleCI를 이용하여 다음과 같은 workflow (상세내용 아래 config.yaml 참고)를 수행한다.

version: 2.1

orbs:
    aws-eks: circleci/aws-eks@0.1.0
    aws-ecr: circleci/aws-ecr@3.1.0
    kubernetes: circleci/kubernetes@0.3.0

공통적으로 orb를 3가지를 추가하였기 때문에 각단계마다 관련 orb를 추가하는 단계를 거치게 된다.

  1. 환경설정 및 Docker Build 및 ECR로 Push
      workflows:
     deployment:
       jobs:
         - aws-ecr/build_and_push_image:
             name: build-and-push-image
             account-url: AWS_ECR_URL
             region: AWS_DEFAULT_REGION
             repo: eks_orb_demo_app
             dockerfile: ~/project/demo_app/Dockerfile
             path: ~/project/demo_app
             tag: ${CIRCLE_SHA1}
             # repository가 없을 경우 생성하는 옵션
             # create-repo: true
    
    • environment variables 설정
    • Project - BUILD SETTINGS - Environment Variables 에서 Key-Value형태로 입력
      • AWS_DEFAULT_REGION : us-west-2
      • AWS_ECR_URL : 219547004475.dkr.ecr.us-west-2.amazonaws.com/eks_orb_demo_app
    • github 연동 (ssh-key 연동 및 repo clone)
    • aws cli 설치 및 AWS Access, Secret Key설정
    • ECR Login
    • Image Build (https://github.com/ddiiwoong/circleci-demo-aws-eks/blob/master/demo_app/Dockerfile) * Push Image to ECR
  2. EKS클러스터 생성 (No Scripts)
      workflows:
     deployment:
       jobs:
         - aws-eks/create-cluster:
             cluster-name: eks-orb-demo-app-deployment
             aws-region: $AWS_DEFAULT_REGION
             requires:
               - build-and-push-image
    
    • kops, kubectl, aws iam authenticator, aws cli 설치
    • kubectl config 설정 (aws iam authenticator)
    • eksctl 설치
    • eksctl로 클러스터 생성 및 검증 (Cloudformation)
    • variables 사전 설정가능 ($AWS_DEFAULT_REGION)
  3. Demo Application 배포
      jobs:
     deploy-application:
       executor: aws-eks/python3
       parameters:
       ...
       steps:
         - checkout
         - run:
             name: Create deployment manifest
             command: |
               BUILD_DATE=$(date '+%Y%m%d%H%M%S')
               cat deployment/demo-app-deployment.yaml.template |\
                 sed "s|DOCKER_IMAGE_NAME|<< parameters.docker-image-name >>|\
                   g;s|BUILD_DATE_VALUE|$BUILD_DATE|g;s|VERSION_INFO_VALUE|\
                   << parameters.version-info >>|g" > deployment/demo-app-deployment.yaml
         - aws-eks/update-kubeconfig-with-authenticator:
             cluster-name: << parameters.cluster-name >>
             install-kubectl: true
             aws-region: << parameters.aws-region >>
         - kubernetes/create-or-update-resource:
             resource-file-path: "deployment/demo-app-deployment.yaml"
             get-rollout-status: true
             resource-name: deployment/demoapp
         - kubernetes/create-or-update-resource:
             resource-file-path: "deployment/demo-app-service.yaml"
      ...
      workflows:
     deployment:
       jobs:
         - deploy-application:
           cluster-name: eks-orb-demo-app-deployment
           aws-region: $AWS_DEFAULT_REGION
           docker-image-name: "${AWS_ECR_URL}/eks_orb_demo_app:${CIRCLE_SHA1}"
           version-info: "${CIRCLE_SHA1}"
           requires:
             - aws-eks/create-cluster
      ...
    
    • deployment manifest생성 (deployment template)
    • kops, kubectl, aws iam authenticator, aws cli 설치 (orb설정: aws-eks,kubernetes)
    • kubectl config 설정 (aws iam authenticator)
    • resource(deployment, service) 배포 (orb설정: aws-eks,kubernetes)
    • rollout 수행 (0->3)
  4. application test
      workflows:
     deployment:
       jobs:
         - test-application:
           name: test-application
           cluster-name: eks-orb-demo-app-deployment
           aws-region: $AWS_DEFAULT_REGION
           expected-version-info: "${CIRCLE_SHA1}"
           requires:
             - deploy-application
      jobs:
     test-application:
       executor: aws-eks/python3
       parameters:
         ...
       steps:
         - aws-eks/update-kubeconfig-with-authenticator:
             cluster-name: << parameters.cluster-name >>
             install-kubectl: true
             aws-region: << parameters.aws-region >>
         - run:
             name: Wait for service to be ready
             command: |
               kubectl get pods
               kubectl get services
               sleep 30
               for attempt in {1..20}; do
                 EXTERNAL_IP=$(kubectl get service demoapp | awk '{print $4}' | tail -n1)
                 echo "Checking external IP: ${EXTERNAL_IP}"
                 if [ -n "${EXTERNAL_IP}" ] && [ -z $(echo "${EXTERNAL_IP}" | grep "pending") ]; then
                   break
                 fi
                 echo "Waiting for external IP to be ready: ${EXTERNAL_IP}"
                 sleep 10
               done
               sleep 180
               curl -s --retry 10 "http://$EXTERNAL_IP" | grep "<< parameters.expected-version-info >>"
    
    • kops, kubectl, aws iam authenticator, aws cli 설치 (orb설정: aws-eks,kubernetes)
    • kubectl config 설정 (aws iam authenticator)
    • External IP 체크 및 curl 테스트
  5. Demo Application 삭제
      jobs:  
     undeploy-application:
       executor: aws-eks/python3
       parameters:
       ...
       steps:
         - aws-eks/update-kubeconfig-with-authenticator:
             cluster-name: << parameters.cluster-name >>
             install-kubectl: true
             aws-region: << parameters.aws-region >>
         - kubernetes/delete-resource:
             resource-types: "deployment,service"
             label-selector: "app=demo"
             wait: true
         - run:
             name: Check on pod status
             command: |
               kubectl get pods
      workflows:
     deployment:
       jobs:
         - undeploy-application:
           cluster-name: eks-orb-demo-app-deployment
           aws-region: $AWS_DEFAULT_REGION
           requires:
             - test-application
    
    • kops, kubectl, aws iam authenticator, aws cli 설치 (orb설정: aws-eks,kubernetes)
    • kubectl config 설정 (aws iam authenticator)
    • deployment 삭제 및 상태 체크
  6. EKS클러스터 삭제 (No Scripts)
      workflows:
     deployment:
       jobs:
         - aws-eks/delete-cluster:
           cluster-name: eks-orb-demo-app-deployment
           aws-region: $AWS_DEFAULT_REGION
           wait: true
           requires:
             - undeploy-application
    
    • kops, kubectl, aws iam authenticator, aws cli 설치 (orb설정: aws-eks,kubernetes)
    • kubectl config 설정 (aws iam authenticator)
    • eksctl 설치
    • eksctl로 클러스터 삭제 및 검증 (Cloudformation)

상세 config는 다음 링크에서 확인할 수 있다.
https://github.com/ddiiwoong/circleci-demo-aws-eks/blob/master/.circleci/config.yml

pipeline 수행

위 Workflow를 수행하게 되면 마지막에 어플리케이션과 클러스터를 삭제하기 때문에 해당 workflow는 제외하고 수행한다. 해당 config를 commit하면 바로 해당 CI가 트리거 되어 시작되게 된다.

      # - undeploy-application:
      #     cluster-name: eks-orb-demo-app-deployment
      #     aws-region: $AWS_DEFAULT_REGION
      #     requires:
      #       - test-application
      # - aws-eks/delete-cluster:
      #     cluster-name: eks-orb-demo-app-deployment
      #     aws-region: $AWS_DEFAULT_REGION
      #     wait: true
      #     requires:
      #     - undeploy-application

result

클러스터 구성포함해서 총 20분정도 소요되었다. 실제 eksctl로 프로비저닝하게 되면 CloudFormation으로 수행되기 때문에 약 15-20분 정도 소요되니 간단한 빌드,배포,테스트는 5분정도 소요된것을 알 수 있다.

삭제는 역순으로 진행하거나 위에 주석 처리된 영역만 수행하면 된다.

정리

간단하게 CircleCI를 가지고 GitOps와 CI/CD를 구성하는 데모를 진행하였다.

CircleCI는 Jenkins와 유사하지만 Public서비스이고 Slave관리에 대해서 의존적이지 않기 때문에 기존에 Jenkins를 사용한 경험이 있다면 아주 쉽게 구성할 수 있다.

https://circleci.com/docs/2.0/migrating-from-jenkins를 참고하면 Jenkins와 차이점을 알 수 있는데 가장 큰 장점은 병렬로 테스트나 Job을 수행할수 있다는 점과 Lambda와 같은 서버리스 앱을 배포할때 정말 서버리스 환경으로 구성할수 있다는 점이다.

이는 Git Repository를 연동할때도 Java Plugin을 설치해야하는 번거로움을 덜 수 있다. 가장 중요한건 SaaS라는 장점도 무시할수 없다. Travis 무료 플랜과 비교해도 작은 프로젝트의 경우 별도의 Docker environment(2core, 4GB)를 제공받기 때문에 지연없이 바로 빌드가 가능하다는 점이다.

다음번 포스팅에는 terraform을 통해 ECR과 ECS로 배포하는 workflow를 살펴보려고 한다.

댓글남기기