클라우드 컴퓨팅 & NoSQL/도커 & 쿠버네티스

쿠버네티스용 Continuous Deployment 툴인 Skaffold #2

Terry Cho 2019. 7. 4. 01:06

쿠버네티스를 위한 CD 툴, Skaffold #2

조대협 (http://bcho.tistory.com)

Skaffold 설정 파일의 구조

Skaffold의 개념과 기본적인 사용법을 이해하였으면, 다음으로 Skaffold 설정 파일에 대해서 알아보도록 하자.

Skaffold의 설정 파일은 아래와 같이 크게 두가지가 있다. 

  • Pipeline config
    우리가 앞에서 살펴본 skaffold.yaml 파일이 파이프라인 설정 파일에 해당한다.
    컨테이너 빌드 및 레지트리 등록, 테스트 및 컨테이너 배포 일련의 파이프라인에 대한 행동을 정의한다. 

  • Global config
    ~/.skaffold/config 파일에 저장되어 있는 정보로 skaffold의 기본 설정 정보를 정의한다. 예를 들어 디폴트 도커 레지스트리 경로등을 정의한다. 

pipeline config (skaffold.yaml)

파이프라인 설정은 앞에서 언급했듯이, 컨테이너 빌드, 빌드된 컨테이너 등록, 테스트 그리고 쿠버네티스 클러스터에 컨테이너와 쿠버네티스 리소스를 배포 하는 파이프라인 흐름을 정의하는데, 크게 build,test,deploy 그리고 profiles 4 가지 영역으로 구분된다. 개념적으로 표현해보면 아래와 같다. 


<그림 skaffold.yaml 파일에서 정의한 파이프라인 별 영역>


각 영역을 살펴보자

build

build는 컨테이너 빌드와, 빌드된 컨테이너에 대한 태깅 그리고 태그된 컨테이너 이미지를 컨테이너 레지트스리에 등록하는 역할을 정의한다


Builder

Skaffold는 각 행위를 정의 하기 위해서 단계별로 사용할 수 있는 컴포넌트들을 정의하는데, 빌드에 관련된 내용은 Builder에 의해서 처리된다.

Builder는 컨테이너 이미지를 빌드 하는 역할을 하는데, 다음 플랫폼 들을 지원한다.

  • 로컬 Docker 를 이용해서 Dockerfile을 기반으로 컨테이너를 빌드

  • Dockerfile을 기반으로 구글 클라우드의 Google Cloud Build를 이용해서 리모트로 빌드

  • Dockerfile을 기반으로 쿠버네티스 클러스터에서 빌드를  할 수 있는 Kaniko 를 이용한 빌드

  • 로컬에서 Bazel(구글이 만든 make와 같은 빌드 스크립트)

  • jlib를 이용하여 maven이나 gradle 프로젝트를 로컬에서 빌드 

  • jlib를 이용해서 Google Cloud Build 를 이용하여 리모트에서 빌드

  • 또는 커스텀 빌드 스크립트를 이용한 빌드

등이 있다. 


Tagger

이렇게 빌드된 이미지들은 컨테이너 레파지토리에 저장되는데, 컨테이너 레파지토리의 경로는 앞에서 언급한 global config 에 의해서 정의 된다.

레파지토리로 컨테이너가 푸쉬 되기 전에, 컨테이너 이미지의 이름에 태그(tag)를 부여해야 하는데, 이는 Tagger에 의해서 실행 된다.

컨테이너의 태그로 사용할 수 있는 것들은 다음과 같다.

  • dateTime : 날짜와 시간을 태그로 사용한다.

  • sha256 : 컨테이너 이미지의 sha256 해쉬 값을 추출하여 태그로 사용한다.

  • 환경변수 : 환경 변수로 정의된 값을 태그로 사용한다. 

  • gitcommit ID : git commit ID를 태그로 사용한다.


추천 하는 방법은 git를 사용하는 경우 가능하면 git commit ID를 사용하는 것이 코드 변경에 대한 컨테이너 이미지에 대한 추적성을 제공하기 때문에 이 방법이 가장좋고, 또는 dateTime을 사용하면, 일자/시간에 따라서 컨테이너 이미지 변경을 추적할 수 있기 때문에 이 방법도 추천한다. 


아래는 Tagger를 이용하여 빌드 과정에서 컨테이너 태그를 dateTime으로 하도록 하는 예제이다. 


apiVersion: skaffold/v1beta11

kind: Config

build:

 tagPolicy:

   dateTime:

     format: "2006-01-02_15-04-05.999_MST"

     timezone: "Local"

 artifacts:

 - image: gcr.io/terrycho-personal/node-example

     : (중략)

이렇게 skaffold.yaml 파일을 작성한 후에, skaffold run을 실행한 결과의 일부를 보면 다음과 같다.


       : (중략)

Successfully built 852d1d5a8f90

Successfully tagged gcr.io/terrycho-personal/node-example:2019-06-26_23-22-58.301_KST

The push refers to repository [gcr.io/terrycho-personal/node-example]

5ba8e7a42d0b: Preparing

520c8d5849cb: Prepari...


컨테이너의 태그 이름이 앞에서 지정한 날짜와 시간형식으로 지정된것을 확인할 수 잇다. 

test

테스트 단계는 그 위에 탑재되는 애플리케이션을 테스트 하지는 않다. 대신 컨테이너가 제대로 만들어 졌는지 특히 파일들이나 디렉토리들은 원하는 대로 제대로 배포되었는지 등을 확인하는데, skaffold에서는 이러한 컨테이너 테스트를 container-structure-test  라는 프레임웍을 사용해서 진행한다. 

deploy

이렇게 만들어지고 테스트된 컨테이너 이미지는 쿠버네티스로 배포하게 된다. 

배포는 Deployer 를 이용해서 쿠버네티스에 배포되는데,

쿠버네티스 디폴트 CLI인 kubectl 뿐만 아니라, helm, kustomize 를 모두 지원한다.  

Helm을 사용하게 되면, Helm Chart를 기반으로 새로운 릴리즈를 만들어서 배포를 한다. 

아래는 skaffold-helm 을 이용해서 배포한 결과인데, Helm 의 새로운 릴리즈가 생성된것을 확인할 수 있다. 


%helm list

NAME         REVISION UPDATED                 STATUS  CHART              APP VERSION NAMESPACE

skaffold-helm 1       Thu Jun 27 00:10:10 2019 DEPLOYED skaffold-helm-0.1.0           default  


Helm과 Skaffold를 이용하면 장점이 Helm의 버전 관리를 이용해서 버전 관리가 간편해지고, 리소스를 삭제할때도 Helm이 의존되는 리소스를 모두 같이 삭제해주기 때문에 깔끔한 배포 및 자원 관리가 가능하다. 



profile

일반적으로 하나의 애플리케이션을 개발하면, 여러환경을 함께 써야 하는 경우가 있다. 예를 들어 단일 코드를 개발,QA,운영 환경등 여러환경에 배포해야 할 경우가 있다. 

아래 예제 그림을 보면, git 의 소스코드를 개발 환경에서는 리파지토리에 저장하지 않고, 로컬의 minikube 클러스터에 배포하도록 해서 개발 테스트를 하고, 운영 환경에서는 빌드된 도커 컨테이너 이미지를 리파지토리에 저장한 다음, 다른 리소스들과 함께 Helm 으로 패키징해서 운영용 쿠버네티스 클러스터에 배포하도록 한다. 




이런 여러 종류의 배포 파이프라인을 하나의 skaffold 설정안에서 관리하기 위해서 skaffold는 profile이라는 개념을 가지고 있다. 

skaffold에서 profile 정의는, 디폴트 설정이 있고, 디폴트 설정과 다른 부분만 profiles 섹션에서 정의하면 된다. 아래는 dev 와 production 두개의 프로파일을 정의한 내용이다. 


apiVersion: skaffold/v1beta11

kind: Config

build:

 artifacts:

 - image: gcr.io/terrycho-personal/node-example

   context: backend

   sync:

     manual:

     # Sync all the javascript files that are in the src folder

     # with the container src folder

     - src: 'src/**/*.js'

       dest: .

profiles:

- name : dev

 build:

   local:

     push: false

- name : production


production은 디폴트 설정과 다르지 않게 설정하였기 때문에, profile 설정 부분에는 별다른 다른 내용을 넣지 않는다. dev에서 build 부분을 로컬 빌드로 하고, 도커 리파지토리로 이미지를 푸쉬하지 않도록 설정하였다.