Skip to main content

4 posts tagged with "Pipeline"

View All Tags

· 11 min read

이전 포스팅에서 EKS 클러스터와 어플리케이션 배포 및 테스트를 간단하게 해봤다. 이번에는 AWS ECS 또는 AWS Batch Application을 CircleCI를 통해 배포 및 업데이트 하는 것을 알아본다.

Application 요구사항

기본적으로 현재 업무 중에 IBM클라우드에서 AWS로 데이터를 가져와야 하는 업무가 생겨서 시작되었고 정기적으로 매일 새벽에 크롤링(Pull)방식으로 데이터를 복제해야하는 Use-Case를 구현해야 했다.
CI/CD Pipeline구성이 주 목적으로 Application구현은 포스팅 내용에서 제외하였다.

기본 요구사항

  • Github Account
  • CircleCI Account (Github Auth)
  • AWS ECR(Elastic Container Registry)
  • AWS Batch(ECS)

CI/CD 구성안

실제 프로젝트에 적용할 구성안이다.
기본적으로 모든 구성은 최대한 비용이 들지 않고 AWS 종속성을 제거한 방법으로 구성하였다.

  • Code Repository : Github
  • CI : CircleCI
  • Registry : AWS ECR
  • CD : CircleCI
  • Target : AWS Batch(ECS)
  • Notification : Slack

이번 데모에서는 다음과 같은 시나리오로 진행하려고 한다.

  1. Terraform으로 AWS Batch 생성
  2. Github에 수정된 Batch Code(Shell Script) Commit & Triggering CircleCI
  3. Docker Build & AWS ECR로 Push
  4. S3로 myjob shell 파일 복사
  5. AWS Batch(ECS) Job Definition 변경(Change Image)

AWS Batch

기본적으로 Batch 컴퓨팅을 목적으로 하는 서비스로 컴퓨팅 타입을 Fargate 또는 EC2 중 하나를 선택하여 동적으로 프로비저닝하는 서비스이다.
초기 설정이 번거롭긴 하지만 한번 구성하고 나면 별도 관리가 필요없고 Batch작업이 발생하는것과 컨테이너 이미지 보관비용 이외에는 추가 비용이 발생하지 않기 때문에 비용측면에서 장점이 있는 서비스이다.
위에서 이야기한 정기적으로 새벽마다 크롤링(Pull)방식으로 데이터를 복제해야하는 Use-Case를 구현하는것이 적당한 워크로드 구현방법이라 생각했기 때문에 AWS Batch 서비스를 사용하게 되었다.

간단한 Batch demo는 https://github.com/awslabs/aws-batch-helpers/에서 확인이 가능하며 CircleCI연동을 위해 Fork후 진행하였다.

Demo Repository : https://github.com/ddiiwoong/aws-batch-helpers/

CircleCI

모든 Pipeline은 CircleCI기반으로 작성하였다. 혹자는 AWS Code Commit, Pipeline을 사용하지 않느냐고 문의하시는 분들도 있는데 다음과 같은 이유로 CircleCI를 선택하였다.

  • Fully Managed (Serverless)
  • AWS 종속성 최소화
  • Git, Registry, CD영역의 확장성 고려
  • AWS Console 접속 최소화
  • 쉽고 단순하게 빌드 환경구성
  • 소규모 프로젝트 빠르게 시작 가능

Amazon Elastic Container Registry (ECR)

개인적으로 Registry는 구축형보다는 Managed서비스를 사용하는것이 좋다고 보기 때문에 Webhook을 Native하게 지원하는 DockerHub도 대체 가능하다고 생각한다.

  • Fully Managed
  • Security (IAM) 연동
  • CircleCI Orbs 제공
  • EKS, ECS 연동 용이

Terraform

https://www.terraform.io/docs/providers/aws/index.html

선언적 인프라스트럭처 관리 도구로 많이 사용하고 있는 도구이며 Docs와 블로그 자료가 많은 관계로 따로 설명하지 않겠다.
이번 포스트에서는 AWS Batch를 생성하는 영역을 Terraform이 담당한다.

CircleCI Config 작성

version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@6.1.0
aws-ecs: circleci/aws-ecs@0.0.8
aws-s3: circleci/aws-s3@1.0.11
aws-cli: circleci/aws-cli@0.1.13
jobs:
sh-s3-upload:
docker:
- image: 'circleci/python:2.7'
steps:
- checkout
- aws-s3/copy:
from: ./myjob.sh
to: 's3://batch-ecr-test/myjob.sh'
deploy-batch:
executor: aws-cli/default
steps:
- checkout
- aws-cli/install
- run:
name: Update AWS Batch Job
command: |
aws batch register-job-definition --job-definition-name fetch_and_run --type container --container-properties '{ "image": "823928750534.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_run:v20190623", "vcpus": 1, "memory": 512}'
workflows:
build-and-deploy:
jobs:
- aws-ecr/build-and-push-image:
repo: $AWS_RESOURCE_NAME_PREFIX
tag: v20190623
- sh-s3-upload:
name: sh-s3-upload
requires:
- aws-ecr/build-and-push-image
- deploy-batch:
name: deploy-batch
requires:
- sh-s3-upload

단계별 설명을 위해 부분적으로 설명하도록 하겠다.

  1. Terraform으로 Batch 배포

    resource "aws_batch_compute_environment" "default"{ 
    compute_environment_name = "env_fetch_and_run"
    compute_resources {
    instance_role = "arn:aws:iam::823928750534:instance-profile/ecsInstanceRole"
    instance_type = [
    "optimal",
    ]
    desired_vcpus = 1
    max_vcpus = 1
    min_vcpus = 0
    security_group_ids = [
    "sg-0632cf81b5c4dff17"
    ]
    subnets = [
    "subnet-0c4f8135b536e8fab",
    "subnet-0a261950d894cf27e"
    ]
    type = "EC2"
    }
    service_role = "arn:aws:iam::823928750534:role/service-role/AWSBatchServiceRole"
    type ="MANAGED"
    }

    Batch Computing 환경을 구성하게 되는데 "aws_batch_compute_environment"를 사용한다.

    • compute_environment_name : (필수) 컴퓨팅 환경 이름
    • compute_resources.instance_role : (필수) EC2에 적용되는 Role
    • compute_resources.instance_type : (필수) 사용 가능한 instance 유형
    • compute_resources.desired_vcpus : (옵션) 원하는 CPU수
    • compute_resources.max_vcpus : (필수) 최대 CPU수
    • compute_resources.min_vcpus : (필수) 최소 CPU수
    • compute_resources.security_group_ids : (필수) EC2에 적용되는 Security Group
    • compute_resources.subnets : (필수) Subnets 목록
    • compute_resources.type : (필수) EC2를 기반으로 생성, SPOT instance 사용가능
    • service_role : (필수) AWS Batch가 다른 AWS 서비스를 호출 할수있게 해주는 IAM Role(ARN)
    • type : (필수) MANAGED나 UNMANAGED를 선택할 수 있고, MANAGED의 경우 compute_resources에 세부 사항을 설정할 수 있다.
    resource "aws_batch_job_definition" "default" {
    name = "fetch_and_run"
    type = "container"

    container_properties = <<CONTAINER_PROPERTIES
    {
    "command": [],
    "image": "823928750534.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_run:v20190623",
    "vcpus": 1,
    "memory": 512,
    "volumes": [],
    "environment": [],
    "mountPoints": [],
    "ulimits": []
    }
    CONTAINER_PROPERTIES
    }

    Job Definition 정의("aws_batch_job_definition")에서는 Resource spec 및 Command(Docker RUN), Container IMAGE 등을 선언하게 된다.

    • name : (필수) Job Definition 이름
    • type : (필수) Job Definition 유형, ECS로 처리하기 위해 container로 선택
    • container_properties : (선택) JSON 형태로 작성하는 container 속성정보 (Image, Resources, Command, MountPoint 등)
  2. .circleci/config.yml에 CircleCI 버전 명시 및 관련 orb(ecr,ecs,s3,cli) 추가
    기본적으로 2.1로 설정을 해야 ecs, eks orb 사용이 가능하다.

    version: 2.1
    orbs:
    aws-ecr: circleci/aws-ecr@6.1.0
    aws-ecs: circleci/aws-ecs@0.0.8
    aws-s3: circleci/aws-s3@1.0.11
    aws-cli: circleci/aws-cli@0.1.13
  3. workflow 구성

    build-and-push-image -> sh-s3-upload -> deploy-batch 순으로 순차적으로 pipeline구성을 하였다.

    workflows:
    build-and-deploy:
    jobs:
    - aws-ecr/build-and-push-image:
    repo: $AWS_RESOURCE_NAME_PREFIX # data-crawler-test
    tag: v20190623
    # create-repo: true
    # dockerfile: Dockerfile
    - sh-s3-upload:
    name: sh-s3-upload
    requires:
    - aws-ecr/build-and-push-image
    - deploy-batch:
    name: deploy-batch
    requires:
    - sh-s3-upload

    기본적으로 CircleCI에서는 orb job을 [orb name]/[predefined-job] 형식으로 선언한다.

    I. 첫번째 step에서는 container image를 build하고 push하는 Job을 수행하므로 aws-ecr/build-and-push-image을 선언한다.
    자세한 내용은 https://circleci.com/orbs/registry/orb/circleci/aws-ecr를 확인하자.

    II. 두번째 step에서는 S3에 배치스크립트를 올리는 Custom Job을 수행한다. Job은 Step의 모음으로 선행되어야할 Job은 상위에 requires: 에서 선언하면 된다.

    III. 세번째 step에서는 AWS Batch job definition의 container image를 교체(revision 변경)하는 Custom Job을 수행한다.

  4. custom job 구성 Workflow에서 선언한 Custom Job의 상세 definition을 기재한다.

    jobs:
    sh-s3-upload:
    docker:
    - image: 'circleci/python:2.7'
    steps:
    - checkout
    - aws-s3/copy:
    from: ./myjob.sh
    to: 's3://batch-ecr-test/myjob.sh'
    deploy-batch:
    executor: aws-cli/default
    steps:
    - aws-cli/install
    - run:
    name: Update AWS Batch Job
    command: |
    aws batch register-job-definition --job-definition-name fetch_and_run --type container --container-properties '{ "image": "823928750534.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_run:v20190623", "vcpus": 1, "memory": 512}'

    I. sh-s3-upload 에서는 aws-s3/copy 를 사용하여 원하는 S3버킷에 사용할 스크립트를 업로드 한다. checkout에서는 현재 상태의 git repo를 clone하게 된다.

    II. deploy-batch 에서는 aws-cli/install 를 사용하여 기존에 작성한 Batch Job definition을 awscli로 원하는 새로운 image로 업데이트 하게 된다.

CircleCI 실행

빌드 및 배포과정을 간단하게 설명하면 코드가 업데이트되면 CircleCI는 해당 저장소의 .circleci/config.yml 을 기준으로 빌드 및 배포를 시작하게 된다.

README.md에 Build Status Badge 달기

https://circleci.com/docs/2.0/status-badges/

badge 위 링크와 설정을 참고하여 아래 그림과 같이 Build Statud Badge를 달 수 있다.

badge

정리

이번에는 CircleCI를 가지고 AWS Batch job을 구성하는 데모를 진행하였다.

얼마전인가에도 어형부형님께서도 언급하신 선언적인 구성 기반에 최대한 serverless 환경에서의 배포를 추구하게 되다 보니 아래와 같은 CI/CD Pipeline 시나리오를 구상하게 되었다.

cicd

새로운 기능의 브랜치(New Feature)가 Git에 push되면 빌드와 테스트가 트리거되어 자동으로 진행되고 동시에 개발자가 PR을 작성하면 동료 및 담당 상급자에게 코드 리뷰를 받게 된다.

리뷰가 통과되고 CircleCI에서 빌드가 성공했다면 승인단계를 통해 Merge를 하고 CircleCI 가 한 번 더 빌드를 시작하고 배포까지 수행하게 된다.

ECS나 Batch로 배포는 CircleCI를 통해 직접 배포를 하고 EC2나 EKS로의 배포는 Terraform 및 ArgoCD를 통해 배포를 진행하는 방식이다.

다음번 포스팅에는 위 그림 기반으로 CircleCI와 ArgoCD를 활용하여 EKS기반 배포과정을 정리할 예정이다.

ko-fi

· 11 min read

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
  1. 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)
  1. 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)
  1. 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 테스트
  1. 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 삭제 및 상태 체크
  1. 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를 살펴보려고 한다.

· 15 min read

3번째 포스팅이다.

11/23 "Kubernetes Meetup" 1Day에서 발표한 이야기 연장선으로 작성한다.

고객에게 오퍼링을 위해 준비한 내용과 Kubernetes monitoring과 연계한 내용에 대해서 적어보려고 한다. 최근 발표를 다니면서 많이 받는 질문이 실제 사용할만 한가?라는 질문과 어떻게 활용해야 하는지에 대한 질문들을 많이 받는다. 오늘 최근 Spinnaker Summit 2018에서 중요하게 다뤘던 Kayenta 프로젝트를 가지고 이야기 해보려고 한다.

Kayenta

Kayenta는 자동 Canary 분석 오픈소스(Automated Canary Service(ACA))로 Spinnaker의 마이크로서비스중 하나로 동작한다.
Automated Canary Deployments에 사용되고 자세한 내용은 canary documentation을 확인하면 된다.

새 종류의 하나인 Canary는 1차 세계대전중에 인간이 해를 입기 전에 독성가스를 탐지하는 용도로 사용되었다고 한다. DevOps에서는 CD(Continuous Deployment) 프로세스의 일부로 사용되며 Canary 릴리즈는 새로운 버전의 Software를 Production에 배포하는 위험을 줄여주는 기술이라고 생각하면 된다.

Canary 신규 버전의 Software를 안정적인 기존 버전과 함께 배포하고 특정사용자나 일부 대상에게 트래픽 일부를 흘려 기존 사용자에게 영향을 최소하하고 새로운 버전의 문제를 신속하게 발견하고 이전의 안정된 버전으로 트래픽을 다시 라우팅시키는것이 주요 기능이라고 보면 된다.

보통 품질 테스트 용도로 현재 운영 버전과 신규 버전의 주요한 지표(주로 Prometheus Metric)를 비교하여 평가를 진행하는데 이를 단위 테스트나 통합 테스트를 대체하여 사용해서는 절대 안된다.
위에서 언급하였듯이 예기치 않은 위험을 최소화 하거나 문제를 신속하게 발견하는 것을 주 목적으로 하기 때문이다.

Spinnaker에서는 기본적으로 3가지 Cluster(Logical Application Group)를 사용한다.

  • Production Cluster - 현재 실행중인 운영 버전으로 Replica는 임의로 변경할 수 있다.
  • Baseline Cluster - Production Cluster와 동일한 버전으로 실행됨
  • Canary Cluster - 변경된 신규 버전의 Software로 실행됨

기본적으로 수동으로 진행할 경우에는 로그와 수집된 메트릭을 분석하고 객관적인 지표로 평가를 진행하는게 기본이다. 하지만 직접 사람이 하는 일이라 메트릭 데이터를 보다 보면 편견과 착오가 발생할 수 밖에 없다.

그래서 Netflix는 ACA(Automated Canary Service)라고 하는 자동화된 접근 방식을 통해 카나리 분석을 진행하고 있다. 수동으로 계산된 여러가지 지표를 가중치 기반으로 점수를 내리고 원하는 점수에 도달하면 배포하는 자동화된 방식이다.

Requirements

  • spinnaker cluster - 1.8+ (1.9.3 이상 추천)
  • halyard - 1.0+
  • kubernetes cluster - 1.9+
  • metric services - datadog, prometheus, stackdriver, signalfx
  • persistent storage - S3(or compatible S3), minio, GCS

Kayenta Service 추가하기

이번 포스팅에서는 아래 환경으로 작성하였다.

  • spinnaker cluster - 1.10.5
  • halyard - 1.11
  • kubernetes cluster - 1.9.7
  • metric services - prometheus
  • persistent storage - compatible S3(IBM Object Storage)

일단 기존 halyard config를 백업하자.

$ hal backup create
+ Create backup
Success
+ Successfully created a backup at location:
/Users/ddii/halbackup-Wed_Nov_28_13-35-31_KST_2018.tar

나중에 복구는 아래와 같이 하면 된다.

$ hal backup restore --backup-path <backup-name>.tar

기존 halyard config를 살펴보면 아래와 같이 canary.enabled=false 로 되어있는 것을 확인 할수 있다.

currentDeployment: default
deploymentConfigurations:
- name: default
canary
enabled: false

canary analysis을 활성화 한다.

$ hal config canary enable

그리고 default judgement algorithm은 NetflixACAJudge-v1.0 로 되어있다 다른 걸 이용하려면 다음과 같이 설정할수 있다.

$ hal config canary edit --default-judge CUSTOM_JUDGE

메트릭 소스로 prometheus를 설정한다. 물론 기존에 사용중인 prometheus endpoint url이 필요하다.

hal config canary prometheus enable
hal config canary prometheus account add my-prometheus --base-url http://YOUR_PROMETHEUS_SERVER:PORT

여기서는 IBM Cloud Object Storage(S3 Compatible)을 사용하였지만 aws로 설정한다.

$ hal config canary aws enable
$ hal config canary aws account add my-s3 --bucket spin-bucket --endpoint \
s3.seo-ap-geo.objectstorage.service.networklayer.com --access-key-id ACCESS_ID \
--secret-access-key
$ hal config canary aws edit --s3-enabled=true

여러개의 메트릭을 동시에 설정 및 수집이 가능하므로 그중 prometheus 및 관련 account를 기본으로 설정한다.

$ hal config canary edit --default-metrics-store prometheus
$ hal config canary edit --default-metrics-account my-prometheus
$ hal config canary edit --default-storage-account my-s3

모든 spinnaker cluster가 준비된 상태의 컨피그는 아래와 같다.

currentDeployment: default
deploymentConfigurations:
- name: default
canary:
enabled: true
serviceIntegrations:
- name: google
enabled: false
accounts: []
gcsEnabled: false
stackdriverEnabled: false
- name: prometheus
enabled: true
accounts:
- name: my-prometheus
endpoint:
baseUrl: http://YOUR_PROMETHEUS_SERVER:PORT
supportedTypes:
- METRICS_STORE
- name: datadog
enabled: false
accounts: []
- name: aws
enabled: true
accounts:
- name: my-s3
bucket: spin-bucket
rootFolder: kayenta
endpoint: s3.seo-ap-geo.objectstorage.service.networklayer.com
accessKeyId: ACCESS_ID
secretAccessKey: ACCESS_KEY
supportedTypes:
- OBJECT_STORE
- CONFIGURATION_STORE
s3Enabled: true
reduxLoggerEnabled: true
defaultMetricsAccount: my-prometheus
defaultStorageAccount: my-s3
defaultJudge: NetflixACAJudge-v1.0
defaultMetricsStore: prometheus
stagesEnabled: true
templatesEnabled: true
showAllConfigsEnabled: true

Spinnaker Cluster를 재배포하게 되면 아래와 같이 spin-kayenta deployments가 추가된 것을 확인할 수 있다.

$ hal deploy apply

$ kubectl get pod
NAME READY STATUS RESTARTS AGE
spin-clouddriver-555cfc9765-kvnl8 1/1 Running 0 6d
spin-deck-85845b5b48-49ncm 1/1 Running 0 6d
spin-echo-5f9dd4d8ff-mvt7g 1/1 Running 0 6d
spin-fiat-5b945645d8-s2qcq 1/1 Running 0 6d
spin-front50-5c57fcf587-tqz28 1/1 Running 0 6d
spin-gate-57576b8c45-w5v6r 1/1 Running 0 6d
spin-kayenta-6dcd7767d6-rgb9w 1/1 Running 0 6d
spin-orca-788df6b9cc-tk6lk 1/1 Running 0 6d
spin-redis-6c87c456fc-6qbl2 1/1 Running 0 6d
spin-rosco-f6f845d49-btjnd 1/1 Running 0 6d

이후 Dashboard에 접속하고 application중 하나의 Config에 들어가면 Features에 Canary메뉴가 생긴것을 확인할 수 있다. 사용설정하고 캐싱하는데 시간이 다소 필요하고 Tasks 메뉴에서 해당 job에 대한 내용을 확인할수 있다.

canary

이후 application delivery 메뉴를 보면 pipelines, canary configs, canary reports라는 메뉴가 생기게 된다.

delivery

simple deploy pipeline 추가

https://cloud.google.com/solutions/automated-canary-analysis-kubernetes-engine-spinnaker 가이드 처럼 구성해봐도 되나 stackdriver를 써야하고 prometheus metric을 활용한 가이드가 필요해서 적어보고자 한다.

새로 파이프라인을 추가한 다음

newpipe

Pipeline Actions - Edit Pipeline JSON 에서 https://raw.githubusercontent.com/ddiiwoong/canary-demo-spinnaker/master/simple-deploy.json 을 추가해준다.

해당 json pipeline을 추가하고 나면 다음과 같은 화면을 확인할수 있다. pipe1 pipe2

반드시 Deploy Config, Deploy Stage에서 배포할 Account 지정을 해야한다.

sampleapp image - ddiiwoong/canary-demo-spinnaker:latest

해당 pipeline내의 sampleapp은 python flask 기반으로 구성되어 간단히 internal 500 error를 원하는 비율을 configmap 변수로 구현할 수 있다. prometheus python client를 사용하여 Gauge, Counter, Metric 서버를 간단하게 구성을 해보았다. 그리고 코드내에서 500 error rate를 구한 이유는 18년 11월 기준 spinnaker kayenta 버전에서는 PromQL(rate,irate와 같은 함수) 지원이 되지 않는다. 개발중인 코드에 포함이 된것을 확인하였고 12월 kubecon때 정식 릴리즈에 포함될거라 생각한다.

#!/usr/bin/env python

from random import randrange
from flask import Flask
from prometheus_client import start_http_server, Gauge, Counter
import os

app = Flask('kayenta-tester')
c = Counter('requests', 'Number of requests served, by http code', ['http_code'])
g = Gauge('rate_requests', 'Rate of success requests')

responce_500 = 0
responce_200 = 0
rate_responce = 0

@app.route('/')
def hello():
global responce_500
global responce_200
global rate_responce
if randrange(1, 100) > int(os.environ['SUCCESS_RATE']):
c.labels(http_code='500').inc()
responce_500 = responce_500 + 1
rate_responce = responce_500 / (responce_500+responce_200) * 100
g.set(rate_responce)
return "Internal Server Error\n", 500
else:
c.labels(http_code = '200').inc()
responce_200 = responce_200 + 1
rate_responce = responce_500 / (responce_500+responce_200) * 100
g.set(rate_responce)
return "Hello World!\n"

start_http_server(8000)
app.run(host = '0.0.0.0', port = 8080)

해당앱을 Start Manual Execuction을 통해 배포한다. Comfirm Execution창에서 SUCCESS_RATE를 원하는 값(예:70%)으로 선택하고 배포를 하고 나면 Infrastructure - Clusters 메뉴에서 해당 샘플앱을 확인할 수 있다.

manaul deploy success rate manaul deploy2

실제 해당 서비스를 접속해보면 위에 설정한 SUCCESS_RATE 비율로 200화면과 500에러를 확인할 수 있다.

flaskweb flaskweb2

해당 메트릭의 통계를 확인하기 위해 curl을 반복적으로 실행하는 injection container 를 실행한다.

kubectl -n default run injector --image=alpine -- \
/bin/sh -c "apk add --no-cache --yes curl; \
while true; do curl -sS --max-time 3 \
http://sampleapp:8080/; done"

5분정도 후에 Prometheus로 접속하여 코드내 작성한 rate_requests 메트릭을 확인해본다.
PromQL은 아래 쿼리를 실행하였다.

rate_requests{app="sampleapp",version="prod"}

아래 그림과 같이 4개의 pod에서 70% 정도 200 OK, 30% 정도 500 Error가 발생하는 것을 확인할 수 있다.

500rate

이 메트릭을 Spinnaker 에서 확인하기 위해 Canary Pipeline을 만들자.

https://raw.githubusercontent.com/ddiiwoong/canary-demo-spinnaker/master/automated-canary.json를 JSON으로 Pipeline을 생성한다.

canary_auto

Stage별로 살펴 보기전에

  • Prerequisite
    Canary Config 구성이 먼저 필요하다. Delivery - Canary Configs 메뉴에서 신규 컨피그를 작성한다.
    • Configuration Name - kayenta-test
    • Filter Templates 메뉴를 먼저 생성한다. Canary, Baseline구분을 위해 version 정보를 선택하였다.
    • Metrics - Add Metric 은 분석을 위한 Prometheus Metric을 설정하는 단계로 error_rate가 증가(increase)하면 Pipeline을 중단시키고 Metric은 앞에서 확인한 rate_requests를 지정한다. Filter Template은 위에서 지정한 version을 선택한다. metric config
    • SCORING - 어짜피 예제는 한가지 Metric분석으로 0점 아니면 100점으로 나올것이므로 Maginal 75, Pass 95를 설정한다.
  1. 1st Stage
    • Configuration - Pipeline 실행시 초기 입력값(0-100, 10단위)으로 설정가능한 successRate 라는 Parameter를 설정한다.
  2. 2nd Stage
    • Find Baseline - 위에서 작성한 기본 Deploy Pipeline이 선택되었는지와 확인한다.
    • Deploy Canary Config - 앞에서 선택한 새로운 Parameter(successRate)를 신규 배포할 Canary Pod ConfigMap으로 설정하는 단계이다.
  3. 3rd Stage
    • Deploy Canary - yaml manifest로 Canary 버전을 배포한다. Replicas는 1로 설정하였고 배포될 Account(K8s Cluster)를 지정한다.
    • Deploy Baseline - yaml manifest로 Baseline 버전을 배포한다. 위와 동일하게 Replicas는 1로 설정하였고 배포될 Account(K8s Cluster)를 지정한다.
  4. 4th Stage
    • Canary Analysis - 중요한 Canary 분석 단계로 아래와 같이 설정을 확인한다. Prerequisite에서 설정한 Config(kayenta-test)를 선택하고 짧은 분석을 위해 1분(60초) 간격으로 3번 수행을 하도록 한다. Filter Template에서 지정한 version(version="${scope}") 분석을 위해 Baseline, Canary 설정을 하고 Location은 Namespaces로 생각하면 된다. aca config
  5. 5th Stage
    • Deploy to Production - Canary 분석이 통과하였을 경우 운영에 배포
    • Delete Canary, Delete Baseline - 성공이던 실패이던 Canary, Baseline 배포본을 삭제
  6. 6th Stage
    • Successful deployment - Canary 분석이 통과하였을 경우 최종 완료 표기하는 단계

설정이 마무리가 되면 저장을 하고 Canary 분석에 들어간다. 최초에 successRate을 70으로 배포했다면 그 이하로 설정했을 경우에는 아래와 같이 Score 0점으로 배포가 실패하고 Pipeline이 종료된다.

fail

70 이상으로 설정하게 되면 Score 100점으로 정상 배포됨을 확인할 수 있다.

success

정리

간단하게 Spinnaker 와 Prometheus Metric을 활용하여 Kayenta 기반 Canary 배포를 해봤다. 현재 Spinnaker 1.10에서 istio가 지원된다고 하니 다시 한번 확인하고 istio 기반 canary 배포와 함께 사용하는 방법을 더 연구해봐야 할 것 같다.

올해 AWS re:invent 끝나고 작년보다 큰 현자타임이 왔다. 오픈소스로 먹고사는 사람들의 기분은 다 비슷할거 같다고 생각이 든다. 12월 11일 부터 Kubecon이 열린다고 하니 Kubernetes 관련한 새로운 프로젝트와 기능들에 집중해서 남들보다 한발 나아가야하지 않을까? 오픈소스로 먹고사시는 분들 다들 힘냈으면 좋겠다.

· 8 min read

이전 포스팅 Spinnaker on Kubernetes #1에서 검토할때는 많이 개념을 이해하기 어려웠던것 같지만 어느정도 시간이 지났고 또 몇일 후에 발표도 있어서 다른 이야기를 해보고자 한다.

지난 포스팅에 대충 집고 넘어간 용어들에 대한 정리를 다시 하고 기본적인 사상들을 정리해보고자 한다. 허접한 플랫폼 엔지니어 생각이니 언제든 다른 의견을 환영하는 바이다.

What is spinnaker? (+History)

최근 트렌드인 멀티 클라우드를 지향하는 오픈소스 플랫폼이다.
2014년 Netflix의 Asgard로 시작되어 2015년에 오픈소스화 되었다.
빠른 속도와 신뢰도있는 소프트웨어 릴리즈를 위해 만들어졌으며 대부분의 메이저 클라우드 프로바이더들을 지원한다.(AWS,GCP,Azure,openstack..)
현재 Netflix, Google, MS, Veritas등이 Contribution을 하고 있다.

왜 Spinnaker를 써야하지?

여러가지 이유가 있겠지만

  • Multi-Cloud용 Continuous Delivery/Deployment Platform 으로 대체가 가능
  • 다양한 pipeline 형태로 배포가 가능하고 Rollback이 쉬움
  • 빠른 배포가 가능하고 여러번 배포가 용이함
  • 유연한 pipeline management system을 가지고 있음
  • 다양한 배포전략을 가진다(Blue-Green, Rolling Red/Black, Canary)
  • community 활동 활발 (github, slack) - 답은 잘 안해줌 ㅠㅠ
  • VM과 Container 동시에 통합관리 가능
  • CI통합 용이(Jenkins)
  • CLI를 통한 설치 및 관리(halyard)
  • VM, Helm Packaging 가능
  • RBAC 지원
  • Notification - Email, Slack, Hipchat등
  • Safe Deployment - Judgement (승인기능)
  • Chaos Monkey Built-in

이정도면 무조건 써야하지 않을까?

Jenkins vs Spinnaker

JenkinsSpinnaker
강력한 빌드서버클라우드 자원의 1차 연동
완전한 deployment tool이 아님vm & deployments 안에 빌드되어 있음
스크립팅이 많이 필요함별도의 스크립팅이 많이 필요없음
기능들이 모두 플러그인 형태CI tool이 아님(CI tools이 백엔드로)

Kubernetes vs Spinnaker

KubernetesSpinnaker
리소스 사용 제한정의한 퍼센트로 rollout
slow rollout각 단계별 검증 가능
High rollback costFast rollbacks
Linear rolloutsresource 사용량이 큼
검증단계가 없음

Deploy Pipeline

Spinnaker를 사용할때 기본적으로 아래와 같은 파이프라인으로 구성한다.
수동으로 UI나 API로 트리거링할수 있고, 자동으로 Jenkins 등과 트리거 연동하여 빌드완료시 배포되도록 할수 있다.

spinnaker-pipeline

Deployment Strategies

Spinnaker에서의 배포전략은 다음과 같이 제공된다.

deployment-strategies

Red / Black (same as Blue / Green)

  • 동일한 양의 instance로 이루어진 새로운 Server Group을 생성한다
  • 신규 Server Group이 정상상태가 되면 LB는 신규 Server Group에 트래픽을 분산한다.

Rolling red/black

  • 이전과 동일하지만 인스턴스별 또는 그룹별로 rolling

Canary

  • 가장 작은 개수의 인스턴스를 교체시키고
  • 새로운 버전으로 트래픽을 분산시킨다 (1~5프로)
  • 새로운 버전에 이슈가 없을때까지 테스트를 진행하고
  • 특정시간까지 이슈가 없으면 배포를 늘려간다.

용어정리 2탄

이전 post에서 정리한걸 다시 복기하고 추가적인 내용을들 적어봤다.

사용하면서 혼돈이 많이 생기는 부분이다 이게 GCE나 EC2를 쓰면 용어 매칭이 쉬운데 k8s를 위한 별도의 메뉴가 아닌 기능을 통합하다보니 용어가 조금 혼동스럽게 구성이 되었다.
특히 Load Balancer 부분은 Service로 매핑되고 퍼블릭 k8s에서 제공하는 Type LoadBalancer는 미지원한다.
그리고 모든 Resource들은 Deploy, Delete, Scale, Rollout(Undo, Pause, Resume)을 지원하며 Versioning이 지원된다. Versioning은 여기에 설명된 대로 strategy.spinnaker.io/versioned annotation을 통해 manifest별로 재정의가 가능하다.

SpinnakerKubernetes비고
Server GroupWorkloadsCRD의 경우 별도 Build
ClustersLogical Server Group
Load BalancerServicesLoadBalancer(k8s) 미지원
FirewallNetworkPolicies

Application Management

Spinnaker에서 Application 이란 배포하려는 서비스를 나타내는 구조라 생각하면 된다.

  • pipeline
  • Clusters, Server Group의 집합이며, firewall과 loadbalancer를 포함한다.
  • Canary Config

Cluster

Kubernetes의 Cluster가 아니라 Spinnaker에서 Server Group의 논리적인 그룹

Server Group

기본자원인 서버그룹은 배포할수 있는 artifacts(vm image, docker image, source)와 인스턴스(pod) 수, Auto-Scaling, metadata 등 기본 구성등을 가지고 있다.
서버그룹은 LoadBalacer나 Firewall 도 선택적으로 연결되고, vm이나 pod 형태로 배포된 application의 집합체라 볼수 있다.

Cloud Provider

  • IaaS - AWS, GCP, Azure, Oracle, Openstack
  • PaaS - Google App Engine
  • Orchestrator - K8s, DC/OS
  • Docker v2 Registry

Account

Cloud Provider에 인증하기 위한 Spinnaker에서만 사용하는 Account Name

Pipeline

Pipeline은 주요 배포 관리도구로 사용된다. Stage라고하는 일련의 Action으로 구성되며 파이프라인을 따라 Stage간 매개변수 전달이 가능하다.
수동으로 시작하거나, Jenkins 작업완료, Docker Registry 신규 Docker 이미지, Cron일정 또는 다른 Stage와 같은 이벤트에 의해 자동으로 트리거링되도록 구성할수 있다.
Pipeline 실행중에(시작/완료/실패) mail, slack, hipchat(사라짐)을 통해 Alert가 가능하다.

pipeline

Stage (atomic building block)

Pipeline이 수행할 동작을 말한다.
Deploy, Resize, Disable, Manual Judgement 등을 수행할수 있다.

stage

  • Stage - Multiple steps
  • Step - 진행되기전에 교정/폴링이 필요한 tasks
  • Task - 특정 Cloud Platform으로 동시에 여러 API호출
  • Operation - 단위 API

정리

용어나 개념은 어느정도 정리된듯 하고 다음 포스팅에서는 실제 multi cluster 환경에서 deploy하고 pipeline을 사용하는 내용을 적어볼 예정이다.