블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Zipkin을 이용한 MSA 환경에서 분산 트렌젝션의 추적 #1

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

개념

분산 트렌젝션이랑 여러개의 서비스를 걸쳐서 이루어 지는 트렌젝션을 추적하는 기능을 정의한다.

마이크로 서비스 아키텍쳐 (이하 MSA)와 같은 구조에서는 하나의 HTTP 호출이 내부적으로 여러개의 서비스를 거쳐서 일어나게 되는데, 그러면 어느 구간에서 병목이 생기는지 추적하기가 어려워진다.

아래 그림을 보면 클라이언트가 Service A를 호출하고, Service A 가 Service B,D 를, Service B가 Service C를 호출한다.


이렇게 트렌젝션이 여러 컴포넌트의 조합을 통해서 발생하기 때문에 Jennifer와 같은 전통적인 APM (Application Performance Monitoring) 도구를 이용해서 추적하기가 어렵기 때문에 별도의 분산 로그 추적 시스템이라는 것이 필요하다.

작동 원리

그러면 이러한 분산 로그는 어떻게 수집 및 추적하는 것일까? 통상적으로 Trace와 Span 이라는 개념을 사용한다.



클라이언트가 서버로 호출한 하나의 호출을 Trace라고 했을 때, 서비스 컴포넌트간의 호출을 Span이라고 한다.각 서비스 컴포넌트들은 하나의 클라이언트 호출을 추적하기 위해서 같은 Trace Id를 사용하고, 각 서비스간의 호출은 각각 다른 Span Id를 사용한다. 이렇게 함으로써 전체 트렌젝션 시간을 Trace로 추적이 가능하고, 각 서비스별 구간 시간은 Span으로 추적할 수 있다.

솔루션

이러한 분산 로그 추적을 위한 솔루션 중에 오픈소스로는 트위터에서 개발된 ZipKin(https://zipkin.io/) , Jagger(https://jaeger.readthedocs.io/en/latest/) , Opencensus(https://opencensus.io/) 등이 있는데, 이러한 분산 로그 추적은 구글의 Dapper 논문을 기초로 디자인 되어 개발되었다.

Zipkin

그 중에서, 가장 활성화 되어 있는 오픈소스 중 하나가 Zipkin인데, 오픈 소스 생태계가 활발해서 플러그인이나 부가적인 도구들이 많다.

전체적인 구조는 다음과 같다.


<그림 . Zipkin 아키텍쳐 >


지원 프로토콜

Zipkin으로 추적할 수 있는 분산 트렌젝션은 HTTP를 기본으로 지원하고 , 이외에도 많이 사용되는 리모트 프로토콜인 gRPC를 함께 지원한다.

클라이언트 라이브러리

Zipkin 클라이언트 SDK는 https://zipkin.io/pages/existing_instrumentations 에 있는데, Zipkin에서 공식적으로 지원하는 라이브러는 아래와 같이 C#, Go, Java, Javascript,Ruby,Scala 등이 있다.




이외에도 오픈 소스 커뮤니티에서 지원하는 라이브러리로 파이썬, PHP등 대부분의 언어가 지원이 가능하다.

Zipkin 라이브러리는 수집된 트렌젝션 정보를 zipkin 서버의 collector 모듈로 전송한다. 이 때 다양한 프로토콜을 사용할 수 있는데, 일반적으로 HTTP를 사용하고, 시스템의 규모가 클 경우에는 Kafka 큐를 넣어서 Kafka 프로토콜로 전송이 가능하다.

스토리지

Zipkin 클라이언트 SDK에 의해서 전송된 정보는 스토리지에 저장된다.

사용할 수 있는 스토리지는 다음과 같다

  • In-memory

  • MySQL

  • Cassandra

  • Elastic Search

메모리는 별도의 스토리지 설치가 필요없기 때문에 간단하게 로컬에서 테스트할 수 있는 정도로 사용하는 것이 좋고, MySQL은 소규모 서비스에 적절하다. 실제로 운영환경에 적용하려면 Cassandra나 Elastic Search를 저장소로 사용하는 것이 바람직하다.

대쉬 보드

이렇게 수집된 정보는 대쉬 보드를 이용하여 시각화가 가능하다. Zipkin 서버의 대쉬보드를 사용할 수 있고, Elastic Search 백앤드를 이용한 경우에는 Kibana를 이용하여 시각화가 가능하다.


Spring Sleuth

Zipkin 라이브러리 중에서 주목해서 살펴볼 부분은 Spring / Java 지원인데, Spring에서 Sleuth라는 모듈 이름으로 공식적으로 Zipkin을 지원하기 때문에, Spring (& Springboot) 연동이 매우 쉽다.

자바 애플리케이션에서 Trace 정보와 Span 정보를 넘기는 원리는 다음과 같다.


여러개의 클래스의 메서드들을 거쳐서 트렌젝션이 완성될때, Trace 정보와 Span 정보 Context가 유지가 되어야 하는데, 자바 애플리케이션에서는 쓰레드마다 할당되는 쓰레드의 일종의 전역변수인 Thread Local 변수에 이 Trace와 Span Context 정보를 저장하여 유지한다.


분산 트렌젝션은 HTTP나 gRPC로 들어오기 때문에, Spring Sleuth는 HTTP request가 들어오는 시점과 HTTP request가 다른 서비스로 나가는 부분을 랩핑하여 Trace와 Span Context를 전달한다.

아래 그림과 같이 HTTP로 들어오는 요청의 경우에는 Servlet filter를 이용하여, Trace Id와 Span Id를 받고 (만약에 이 서비스가 맨 처음 호출되는 서비스라서 Trace Id와 Span Id가 없을 경우에는 이를 생성한다.)

, 다른 서비스로 호출을 할 경우에는 RestTemplate 을 랩핑하여, Trace Id와 Span Id와 같은 Context 정보를 실어서 보낸다.



HTTP를 이용한 Trace와 Span 정보는 HTTP Header를 통해서 전달되는데


위의 그림과 같이 x-b3로 시작하는 헤더들과 x-span-name 등을 이용하여 컨택스트를 전달한다.

이렇게 ServletFilter와 RestTemplate을 Spring 프레임웍단에서 랩핑해줌으로써, 개발자는 별도의 트레이스 코드를 넣을 필요 없이 Spring을 이용한다면 분산 트렌젝션을 추적할 수 있도록 해준다.


다음글에서는 실제로 Spring Sleuth와 Zipkin을 이용하여 분산로그를 추적하는 예제를 구현해보도록 하겠다.


Apt.ly를 이용한 데비안 리포지토리 생성


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




앞의 글에서 Jenkins + Maven 조합을 통해서 애플리케이션 설치 파일을 데비안 패키지로 패키징하는 방법에 대해서 알아보았다. 이제 이 패키지를 서버에 설치하는 방법을 살펴본다.

패키지를 설치하는 방법은 간단하게 데비안 패키지 파일을 설치하고자 하는 서버에 복사해놓은 다음에, sudo apt-get install을 이용해서 설치하는 방법도 있지만, 설치하고자 하는 서버마다 복사하기가 번거롭기 때문에 조금 더 쉬운 접근을 위해서 데비안 패키지 서버를 올리는 방법이 있다. 우리가 JDK나  node.js 등 다양한 유닉스 패키지를 apt-get 을 이용하여 설치가 가능한것은 미리 데비안 패키지 리파지토리 서버가 지정되어 있고, 그 서버내에 패키지들이 등록되어 있기 때문인데, 애플리케이션 패키지를 같은 방법으로 설치할 수 있게 하려면 애플리케이션 데비안 패키지 파일을 등록할 리포지토리 서버를 설정하면 된다.


지금까지 구현해온 파이프라인은 아래 그림과 같다

  1.  gitHub 로 부터 Jenkins가 자바 코드를 자바 코드를 당겨온다

  2. 이 코드를 Maven을 이용하여 빌드한다

  3. Maven은 코드 빌드가 끝나고 이를 데비안 패키지로 패키징 한다.

  4. Jenkins는 데비안 패키징 파일을 로컬 리포지토리인 apt.ly에 저장한다.

  5. Spinnaker에서 설치할때 데비안 패키지를 apt.ly에서 당겨서 설치한다.


앞의 글에서 까지 1,2,3과정까지 진행을 하였고, 이 글에서는 4번 과정을 구현할 예정이다.

다양한 오픈소스가 있지만, 플랫폼 종속성이 없고 손쉽게 설치가 가능한 apt.ly (www.aptly.info) 를 기준으로 설명을 하고자 한다.


apt.ly 설치

여기서 설명하는 설치는 데비안 리눅스 9을 기준으로 하여 설명한다.

설치는 앞의 글에서 설치한 Jenkins 서버에 그대로 설치하도록 한다.

설치 방법은 간단하다. www.aptly.info 사이트에서 설치 메뉴얼을 체크하여, 현재 사용하는 리눅스 버전에 맞는 바이너리를 wget을 이용해서 다운 로드 받은 후에, chmod +x 로 실행 권한만 주면 된다.


$ wget https://dl.bintray.com/smira/aptly/0.9.5/debian-squeeze-x64/aptly

$ chmod +x aptly


명령어가 설치 되었으면 리파지토리를 생성해야 한다.

리포지토리 생성 과 확인

리포지 토리 생성은 aptly repo crete {리포지토리 명} 을 입력하면 된다.  아래 명령은 “terry-repo”라는 이름의 리포지토리를 생성한것이다.

%./aptly repo create terry-repo


아래 명령은 terry-repo 라는 리포지토리에 대한 정보를 조회 하는 명령이다.

%./aptly repo show -with-packages terry-repo


아래는 실제 실행결과 인데, 테스트를 위해서 helloterry_1.0_all 이라는 패키지를 등록해놨기 때문에 하나의 패키지가 등록되서 보이는 것을 확인할 수 있다.



apt.ly 에 패키지 등록하기

리포지토리가 생성되었으면, maven 에서 빌드한 패키지를 apt.ly 리포지토리에 등록해보자

등록하는 방법은 aptly repo add -force-replace {리포지토리명} {데비안 패키지 파일명} 식으로 사용하면 된다.

아래는 terry-repo에 helloworld.deb 파일을 등록하는 명령이다.

%./aptly repo add -force-replace terry-repo helloworld.deb

apt.ly 리포지토리 퍼블리슁하기

패키지를 등록했으면 외부에서 억세스사 가능하도록 리포지토리 퍼블리쉬를 해야 하는데, 퍼블리쉬는 어떤 버전의 OS와 CPU 타입에 설치할 수 있는지등의 메타 정보를 함께 등록한다.

명령어 사용법은 aptly publish repo -distribution=”{OS 버전 정보}" -architecture=”{CPU 타입}” -skip-signing=true {리포지토리명}

식으로 사용한다.

원래 데비안 패키지를 외부로 배포를 할때는 패키지의 변경(원하지 않은)을 막기 위해서 패키지에 사이닝을 하는데, 여기서는 -skip-signing 을 이용하여 사이닝 단계를 건너뛰도록 하였다. 이 리파지토리는 외부에서 억세스하는 용도가 아니라 내부에서 CI/CD 파이프라인 단계에서만 사용되기 때문에 사이닝을 생략하였다.


아래 명령은 데비안 stretch 버전에 amd64 (intel CPU)에 terry-repo 이름으 리포지토리를 퍼블리슁한것이다.

%./aptly publish repo -distribution=stretch -architectures="amd64" -skip-signing=true terry-repo


apt.ly 서버 기동

퍼블리슁이 되었다고 당장 리포지토리를 접근 가능한것이 아니다. apt-get을 이용한 인스톨은 HTTP 프로토콜을 이용해서 접근하기 때문에 apt.ly 파일 저장소를 접근 가능하게 하는 웹서버를 올려야 한다.

간단한 방법으로는 aptly serve 명령어를 이용해서 웹서버를 올리는 방법이 있다.

아래 명령어 처럼 aptly serve -listen={IP:포트}를 적으면 된다.


% ./aptly serve -listen=:9090 > aptly.log &


이 보다는 제대로 서비스를 하기위해서는 웹서버에 올리는게 좋은데,

(참고 : https://www.spinnaker.io/guides/tutorials/codelabs/hello-deployment/)

% sudo apt-get install nginx

를 통해서 nginx 를 설치한 후에, /etc/nginx/sites-enabled/default 파일을 다음과 같이 편집한다.


server {
       listen 9999 default_server;
       listen [::]:9999 default_server ipv6only=on;
       root /var/lib/jenkins/.aptly/public;
       index index.html index.htm;
       server_name localhost;
       location / {
               try_files $uri $uri/ =404;
       }
}


이때 root에 aptly의 public 디렉토리를 명시해줘야 하는데, aptly를 설치한 디렉토리의 .aptly/public 이 되는게 일반적이다. 여기서는 /var/lib/jenkins 디렉토리 아래에 리포지토리를 만들었기 때문에 /var/lib/jenkins/.aptly/public 디렉토리를 홈 디렉토리로 설정하였다.


nginx 를 기동하면 http 9999번 포트로 데비안 패키지 서비스를 시작한다.

apt.ly 를 통한 패키지 설치

데비안 패키지 서버를 설치하고 패키지를 등록했으면 실제로 패키지를 다른 서버에서 인스톨 해보자

다른 서버에서 이 패키지 서버에 대한 정보를 알고 있어야 하는데 (서버 주소) 이 정보는 /etc/apt/sources.list 라는 파일에 아래와 같은 형태로 등록 되어 있다.


deb http://deb.debian.org/debian/ stretch main

deb-src http://deb.debian.org/debian/ stretch main

deb http://security.debian.org/ stretch/updates main

deb-src http://security.debian.org/ stretch/updates main

deb http://deb.debian.org/debian/ stretch-updates main

deb-src http://deb.debian.org/debian/ stretch-updates main


이 파일에 앞서 설정한 데비안 리포지토리 서버 (apt.ly) 서버의 주소와 정보를 입력해주면 된다.

만약 http://myserver-ip:9999 포트로 서버를 올렸다면 아래와 같은 정보를 /etc/apt/sources.list 에 추가해주면 된다.


deb http://myserver-ip:9999 stretch main


설정이 끝났으면

%sudo apt-get update

명령을 실행하면 아래와 같이 새로운 리포지토리에서 정보를 읽어오는 것을 확인할 수 있다.


모든 준비가 끝났다.

인스톤을 해보자. 인스톨은 sudo apt-get install을 이용하면 된다.

앞서 등록한 패키지 명이 helloterry 였기 때문에 간단하게 아래와 같이 sudo apt-get install helloterry 명령어를 실행하면 된다.



이외에도 유사한 툴로 pulp (https://docs.pulpproject.org/user-guide/introduction.html#what-pulp-can-do)

클라우드 서비스로는 cloudsmith.io (https://cloudsmith.io/)등이 있다. 

작은 규모의 팀이라면 관리 문제도 있으니 클라우드 서비스를 쓰는 것도 좋은 방안이 되지 않을까 한다.



Jenkins와 gitHub 연동


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


가장 널리 사용하는 Jenkins와, 소스 코드 리포지토리 서비스인 GitHub를 연동하는 방법에 대해서 알아본다. 시나리오는 gitHub에 코드를 푸쉬하면 Jenkins가 이를 인지해서 자동으로 코드를 내려 받아서 빌드 스크립트를 실행하는 순서로 한다.


GitHub에서 Credential 생성


gitHub 자신의 계정으로 로그인 한 후 우측 상단의 자신의 사진이 있는 아이콘을 누르면 메뉴가 나오는데, 여기서 Setting > Developer settings 메뉴로 들어간 후에 아래와 같이 Personal access tokens 메뉴로 들어간다.

다음 우측 상단의 Generate new token 메뉴를 선택한다.



다음 토큰으로, 접근할 수 있는 범위를 설정한다. 접근 범위는 “repo”와 “admin:repo_hook” 을 선택한다.




선택이 끝나고 토큰을 생성하면 문자열로 된 토큰이 생성된다.


Jenkins에서 GitHub 연결 설정

앞에서 생성된 토큰을 Jenkin의 GitHub 연결 부분에 설정하도록 하겠다.

Jenkins 초기화면에서 Jenkins > Manage Jenkins > Configure System 메뉴로 들어가면 GitHub 계정을 설정하는 부분이 있다.



Name은 이 GitHub 연결 설정을 구별할 이름으로 정의하고 API URL은 default로 https://api.github.com 으로 설정되어 있는데 default 값을 사용한다.

다음 접속 credential을 설정해야 하는데, credentials 부분에서 Add 버튼을 눌러서 Credential 설정 메뉴를 실행한다.




위와 같은 메뉴가 나오면 Kind는 “Secret text”를 선택하고 Secret 에 앞에 gitHub에서 생성한 키를 입력한다. ID에는 본인 gitHub ID를 입력한다.  Credential 입력이 끝나면,  아래 그림과 같이 Credentials 메뉴 아래에 Test Connection 버튼이 있는데, 이 버튼을 눌러서 제대로 github와 연결이 되는지를 테스트 한다.




Jenkins 프로젝트 생성 및 설정

Jenkins와 gitHub 연결 설정이 끝났으면, Jenkins에서 프로젝트를 생성한다.

Git 연결 설정

프로젝트 설정에서 아래와 같이 Git 메뉴로 이동한다.



여기서 Repository URL을 입력한다. Repository URL은 본인 gitHub Repository에서 우측 상단의 녹색 “Clone or download” 버튼을 누르면 HTTPS 로 된 URL이 나온다. 이 URL을 입력하면 된다.



다음 이 repository에 연결할 연결 정보를 입력해야 하는데, Jenkins에서 credentials 메뉴로 들어간다.

이 메뉴에서 Kind를 “Username with password” 를 선택하고 Username에는 본인의 github id, Password에는 github 비밀번호를 입력한다.



빌드 트리거 설정

다음 어떤 조건에서 Jenkins 빌드를 실행할지를 설정하는데, GitHub에 코드가 푸쉬되면 빌드를 트리거링 하도록 설정을 할것이다. 아래 그림과 같이 Build Triggers 메뉴에서 GitHub hook trigger for GitScm Polling을 선택한다.




이렇게 설정하면 GitHub에서 코드 푸쉬가 될때 webHook 메세지를 Jenkins에 보내주는데, 이 WebHook 메세지를 받을 때마다 빌드를 하게 된다.


GitHub에서 WebHook 설정

Jenkins 가 GitHub 에서 보내는 WebHook에 의해서 Triggering이 되도록 설정했으면, 이제 GitHub에서 코드가 푸쉬 될때 마다 WebHook을 Jenkins에 보내도록 설정해야 한다.




GitHub Repository로 들어가면 우측 상단에 Settings라는 메뉴가 있다.

이 메뉴에 들어가서 좌즉에 Integration & Service 라는 메뉴를 선택한다.


Services 메뉴에서 “Add service” 버튼을 클릭한 후에 “Jenkins (GitHub plugin)” 을 선택한다.



다음 플러그인 설정에 Jenkins hook url에 Jenkins가 WebHook을 받을 HTTP 경로를 입력한다.

일반적으로 http://{Jenkins server의 URL}/github-webhook 이 된다.




이제 모든 설정이 끝났다.

제대로 작동하는 것을 확인하기 위해서 코드를 commit 한 후에 Push를 해보면 빌드가 자동으로 진행이 된다.

Jenkins의 해당 project에서 좌측의 “GitHub Hook Log”를 보면 WebHook을 잘 받았는지 확인이 가능하다. 아래는 실제로 WebHook이 발생한 내용을 확인한 화면이다.




Spinnaker #3

Hello Spinnaker

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


Spinnaker에 대한 개념 이해 및 설치가 끝났으면, 이제 간단한 애플리케이션을 배포해보자.

여기서 사용하는 애플리케이션은 node.js로 8080 포트에 “This is Default” 라는 메세지를 출력하는 간단한 애플리케이션이다. VM이 기동되면 자동으로 이 node.js 서버가 기동되도록 설정을 해놓은 VM이미지를 만들어놓았다. 만약에 같은 테스트를 하고자 한다면 간단한 애프리케이션을 만들어도 좋고, nginx나 apache 웹서버를 설치해놓은 이미지를 사용해도 좋다.

Create Application

먼저 node.js 클러스터를 배포할 애플리케이션을 정의한다. 아래 처럼 메뉴에서 애플리케이션을 선택한 후에, 우측 상단의 Action 메뉴에서 Create Appliaction 메뉴를 선택한다.



다음 애플리케이션 정보에 애플리케이션명을 “hellospinnaker”로 입력하고, 관리자 이메일을 입력한다.





Load Balancer 생성

애플리케이션이 생성되었으면, 애플리케이션에서 사용할 로드밸런서를 사용한다. 구글 클라우드에는 여러 타입의 로드 밸런서가 있지만, 설정이 쉬운 Network 로드 밸런서를 사용하겠다.

Network Load Balancer는 TCP/UDP를 지원하는 Pass through (IP가 바뀌지 않는다.) 방식의 L4 로드 밸런서로, 구글의 망가속 기능을 사용하지 않는 리전 단위의 로드 밸런서이다.



로드 밸런서 타입을 선택했으면 상세 정보를 입력한다.

  • region을 선택한다. 여기서는 일본 리전인 asia-northeast1을 선택하였다.

  • 다음 로드밸런서의 포트를 선택해야 하는데, Listener 부분에서 TCP 프로토콜을 선택하고, 입력 포트를 8080으로 선택한다.

  • 그리고 마지막으로 중요한것은 Health Check 부분을 명시해야 하는데, Health check는 HTTP를 사용하게 된다. HTTP/GET request를 이용하여 Health check를 할 서버의 HTTP URL과 Port를 지정해야 한다. node.js 서버가 8080 포트를 통해 서비스 하기 때문에 Health Check도 8080 포트에 “/” 디렉토리로 지정한다.





Server 생성

로드 밸런서 설정이 끝났으면 여기에 붙일 서버 그룹을 정의해야 한다. 서버그룹 정의는 Clusters 메뉴에서 가능한데, 먼저 Clusters 메뉴로 들어간후, 우측 상단의 Create Server Group 버튼을 클릭하여, 서버 그룹 생성 화면을 불러온다.





서버 그룹에 정보에서는 아래 그림과 같이 region을 선택하고, VM을 생성할때 사용할 Image를 선택한다. 이 예제에서는 앞서 설명한것 처럼 node.js 애플리케이션을 “simple-node-server-default-image”라는 이미지로 준비해놓았다.

다음 Load Balancers 메뉴에서 로드 밸런서를 선택한다. 로드 밸런서는 앞 단계에서 만든 “hellospinnaker” 를 선택한다.





다음으로는 인스턴스 타입을 선택한다. 인스턴스 타입은 먼저 Zone 을 선택해야 선택할 수 있다. Zone은 두개의 존 이상에 걸치도록 설정하기 위해서 “Distribute instance multiple zones” 체크 박스를 클릭하면 선택한 리전에서 두개 이상의 존에 걸쳐서 인스턴스가 생성된다.

그리고 인스턴스 타입을 선택한다. 아래에서는 n1-standard-2 인스턴스를 선택하였다.

마지막으로 Number of instances에 기동시킬 인스턴스 수를 지정한다. 여기서는 4개의 인스턴스를 기동하도록 하였다.




서버 기동 확인

모든 설정이 끝났으면, 인스턴스가 기동되는 것을 확인할 수 있다. 아래 그림과 같이 인스턴스가 정상적으로 올라오면 초록색으로 표시가 된다. 만약 문제가 있어서 인스턴스가 올라오지 않으면 붉은 색으로 표시된다. (대부분 실패 하는 경우는 HeartBeat 설정이 제대로 되어 있지 않는 경우가 많다.)




실제로 구글 클라우드 콘솔의  Compute Engine탭을 확인해 보면 아래와 같이 VM들이 생성 된것을 확인할 수 있다. VM이름은 hellospinnaker-vxxx 라는 이름으로 생성이 되는것을 확인할 수 있다.



테스트

그러면 제대로 작동을 하는지 확인해보자. 로드밸런서의 IP를 확인해야 하는데,  생성된 로드밸런서를 클릭하면 로드밸런서의 IP가 아래 그림과 같이 우측에 나타난다.



이 IP로, HTTP 8080 포트로 접속을 해보면 아래 그림과 같이 접속이 되는 것을 확인할 수 있다.



지금까지 Spinnaker에 대한 제일 간단한 사용방법을 알아보았다.

실제 운영 환경에서는 이런식으로 사용하는 경우는 드물고, github등의 코드 Repository에서 코드가 변경되면 이를 Jenkins 등을 이용하여 빌드하고, 패키징 한 후에, VM등에 배포하는 파이프라인을 거치게 된다.

다음 글에서는 이러한 파이프라인을 하나 만들어 보도록 하겠다.




Spinnaker #2 - 설치


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


설치


설치 문서는 https://www.spinnaker.io/setup/  를 참고하면 된다.

설치 가이드를 보면 Quick Install 가이드와 수동 인스톨 가이드를 제공하고 있다.



퀵 인스톨 가이드는 대규모 운영용으로는 어렵고 하나의 인스턴스에, 모든 마이크로 서비스가 인스톨 되는 모델로, 소규모 운영이나 또는 데모용으로 손쉽게 사용이 가능하다. 수동으로 인스톨 하는 방법은 다소 까다롭기 때문에, Quick Install 부터 진행하는 것을 권장한다.


Quick Install 페이지에 들어가면, 각 클라우드와 쿠버네티스 클러스터에 설치 하는 방법이 가이드 되어 있다.


구글 클라우드에 Spinnaker 설치

구글 클라우드에 Spinnaker를 설치하려면,간단하게  Google Cloud Launcher를 이용하면 손쉽게 설치가 가능하다.

설치에 앞서서, Spinnaker는 Google Cloud API를 이용하여, 인스턴스 생성과 스토리지등을 접근하기 때문에, 구글 클라우드 프로젝트에서 해당 API들을 활성화 해줘야 한다. (매우 중요) 활성화 해야하는 API는 아래와 같다.


다음은 Spinnaker를 설치해보자.

Cloud Launcher 페이지에서 Spinnaker를 선택한 후



“Launch on compute engine” 을 선택하면, 4 CPU/20GB VM에 Spinnaker가 설치된다.

아래와 같이 인스턴스 이름을 입력하고, Zone을 선택하면 된다.만약에 필요하다면 VM의 Machine Type을 좀 큰 인스턴스로 해서 운영환경에 적용해도 된다.




만약에 Kubernetes Cluster를 연동해서 사용하고자 한다면, https://www.spinnaker.io/guides/tutorials/codelabs/gcp-kubernetes-source-to-prod/#enable-apis 설치 가이드를 참고하기 바란다.

실행

Spinnaker 를 디폴트로 설치하고 나면 별도의 ID 인증 기능이 설정되어 있지 않기 때문에, 접속 포트가 인터넷으로 열려 있지 않고 local host 로만 접속을 허용한다.

그래서 SSH 터널링을 통해서 로컬 PC의 Local port 9000번과 8084번 포트를 Spinnaker VM의 포트와 맵핑을 시키도록 한다.

9000번은 웹사이트 8084번은 웹사이트가 호출하는 gate 컴포넌트이다.

SSH 터널링은 gcloud compute ssh명령을 이용하면 된다.

사용 방법은 다음과 같다.

gcloud compute ssh --project={구글 클라우드 프로젝트명} --zone={Spinnaker 인스턴스가 배포된 존 이름} {인스턴스명} -- -L 9000:localhost:9000  -L 8084:localhost:8084


다음은 terrycho-sandbox라는 프로젝트 명을 가지고 spinnaker-demo 라는 인스턴스를 asia-northeast-1c에 배포해놓고 접속한 예이다.


gcloud compute ssh --project=terrycho-sandbox --zone=asia-northeast1-c spinnaker-demo -- -L 9000:localhost:9000  -L 8084:localhost:8084


명령을 실행한 후에, 브라우져에서 localhost:9000 번으로 접속하면 Spinnaker 콘솔을 볼 수 있다.



Spinnaker #1 - 소개


Spinnaker

Spinnaker 는 넷플릭스에서 개발하여 오픈 소스화한 멀티 클라우드를 지원하는 Continuous Delivery Platform 이다. 구글 클라우드, 아마존, 마이크로소프트등 대부분의 메이져 클라우드를 지원하며, Kubernetes 나, OpenStack 과 같은 오픈소스 기반의 클라우드 또는 컨테이너 플랫폼을 동시에 지원한다.

시나리오

Spinnaker 의 특징은 멀티 클라우드 지원성뿐만 아니라, 오케스트레이션 파이프라인 구조를 지원한다 특징인데,  배포 단계는 여러개의 스텝이 복합적으로 수행되는 단계이기 때문에, 복잡한 워크 플로우에 대한


관리가 필요하다.

하나의 배포 시나리오를 통해서 오케스트레이션 파이프라인에 대해서 이해해보도록 하자

  • 코드를 받아서 빌드를 하고,

  • 빌드된 코드를 VM에 배포하여 이미지로 만든 후에, 해당 이미지를 테스트한다.

  • 테스트가 끝나면, Red/Black 배포를 위해서 새버전이 배포된 클러스터를 생성한 후에

  • 새 클러스터에 대한 테스트를 끝내고

  • 새 클러스터가 문제가 없으면 트래픽을 새 클러스터로 라우팅한다.

  • 다음으로는 구버전 클러스터를 없앤다.

각 단계에서 다음 단계로 넘어가기 위해서는 선행 조건이 필요하다. 예를 들어 이미지가 빌드가 제대로 되었는지 안되었는지, 새 클러스터가 제대로 배포가 되었는지 안되었는지에 대한 선/후행 조건의 확인 들이 필요하다.

Spinnaker에서는 이러한 오케스트레이션 파이프라인을 “파이프라인”이라는 개념으로 구현하였다. 파이프라인 흐름에 대한 예를 보면 다음과 같다.


위의 파이프라인은 이미지를 찾아서 Red/Black 배포를 위해서 Production에 새로운 이미지를 배포하고, Smoke 테스트를 진행한 후에, 구 버전을 Scale down 시키고, 소스를 태깅 한다. 이때 구 버전을 Destory 하기 전에, Manual Approval (사람이 메뉴얼로 승인) 을 받고 Destory 하는 흐름으로 되어 있다.


또한  각 단계별로 하위 테스크가 있는 경우가 있다. 예를 들어 새로운 클러스터를 배포하기 위해서는 클라우드 내에 클러스터 그룹을 만들고, 그 안에 VM들을 배포한 후에, VM 배포가 완료되면 앞에 로드 밸런서를 붙이고, Health check를 설정해야 한다. 그리고 설정이 제대로 되었는지 체크를 한다음에 다음 단계로 넘어간다.


이러한 개념을 Spinnaker에서는 Stage / Steps/ Tasks/ Operation 이라는 개념으로 하위 태스크를 구현하였다. 개념을 보면 다음과 같다.



파이프라인 컴포넌트

파이프라인은 워크 플로우 형태로 구성이 가능하다. 아래 그림은 파이프라인을 정의하는 화면의 예시이다.


<그림. 파이프라인 예제>

출처 http://www.tothenew.com/blog/introduction-to-spinnaker-global-continuous-delivery/


파이프라인에서 스테이지별로 수행할 수 있는 테스크를 선택할 수 있다.  샘플로 몇가지 스테이지를 보면 다음과 같다.

  • Bake : VM 이미지를 생성한다.

  • Deploy : VM 이미지 (또는 컨테이너)를 클러스터에 배포한다.

  • Check Preconditions : 다음 단계로 넘어가기전에 조건을 체크한다. 클러스터의 사이즈 (EX. 얼마나 많은 VM이 생성되서 준비가 되었는지)

  • Jenkins : Jenkins Job 을 실행한다.

  • Manual Judgement : 사용자로 부터 입력을 받아서 파이프라인 실행 여부를 결정한다

  • Enable/Disable Server Group : 이미 생성된 Server Group을 Enable 또는  Disable 시킨다

  • Pipeline : 다른 파이프라인을 수행한다.

  • WebHook : HTTP 로 다른 시스템을 호출한다. 통상적으로 HTTP REST API를 호출하는 형


개념 구조


Spinnaker는 리소스를 관리하기 위해서, 리소스에 대한 계층구조를 정의하고 있다.



<그림. Spinnaker의 자료 구조 >

출처 : ttp://www.tothenew.com/blog/introduction-to-spinnaker-global-continuous-delivery/



가장 최상위에는 Project, 다음은 Application 을 가지고 있고, Application 마다 Cluster Service를 가지고 있고, 각 Cluster Service는 Server Group으로 구성된다. 하나하나 개념을 보자면,


Server Group 은, 동일한 서버(같은 VM과 애플리케이션)로 이루어진 서버군이다. Apache 웹서버 그룹이나 이미지 업로드 서버 그룹식으로 그룹을 잡을 수 도 있고, 이미지 서버 그룹 Version 1, 이미지 서버 그룹 Version 2 등으로 버전별로 잡는등 유연하게 서버군집의 구조를 정의할 수 있다.

이러한 서버 그룹은 Cluster 라는 단위로 묶일 수 있다.


아래 예제 그림을 통해서 개념을 좀더 상세하게 살펴보자


위의 그림은 이미지 서비스(Image service)를 제공하는 서비스를 Cluster로 정의한것이다.

위의 구조는 Image Service를 Service Group으로 정의했는데, v1,v2,v3 버전을 가지고 있고 각 버전이 Service Group으로 정의된다 (이런 이유는 멀티 버전을 이용한 카날리 테스트나 Red/Black 배포를 이용하기 위해서 여러 버전을 함께 운용하는 경우가 생긴다.)

그리고, 리전별로 별도의 Image Service를 각각 배포하는 모델이다.

리전과 멀티 클라우드의 개념은 Spinnaker 문서에 나온 자료 구조 이외에, 중요한 자료 구조인데, 리소스를 정의할때 클라우드 계정을 선택함으로써 클라우드를 선택할 수 있고, 서비스의 종류에 따라 리전을 선택하는 경우가 있는데 이 경우 리전별로 리소스를 분류해서 보여준다.


Cluster는 Application 내에서 생성될때 , Service Group을 생성시 입력하는  {Account}-{stack}-{Detail} 을 식별자로하여 Cluster를 식별한다. 같은 식별자를 가진 Service Group을 하나의 Cluster로 묶는다.

아래는 Service Group을 생성하는 화면으로 Account, Stack, Detail을 입력하는 메뉴가 있는 것을 확인할 수 있다.



아래 그림은 myapplication 이라는 이름을 갖는 Application 내에, 각각 MY-GOOGLE-ACCOUNT라는 account를 이용하여, myapplication-nodestack-cluster1과, myapplication-nodestack-cluster2 두개의 클러스터를 생성한 예제이다.





또는 자주 쓰는 구성 방식중 하나는 Red/Black (또는 Blue/Green  이라고도 함) 형태를 위해서 하나의 클러스터에 구버전과 새버전 서버 그룹을 각각 정의해놓고 구성하는 방법이 있다.


Application은 Cluster의 집합이고, Project는 Application의 집합이다.

개발하고 배포하고자 하는 시스템의 구조에 따라서 Project, Application, Cluster를 어떻게 정의할지를 고민하는 것이 중요하다.


예를 들어 하나의 서비스가 여러개의 애플리케이션으로 구성되어 있는 경우, 예를 들어 페이스북 처럼, 페이스북 앱, 웹 그리고 앱 기반 페북 메신져가 있는 경우에는 페이스북이라는 프로젝트 아래, 페이스북 앱 백앤드, 웹 백앤드, 앱 백앤드로 Application을 정의할 수 있고,각각의 Application에는 마이크로 서비스 아키텍쳐 (MSA) 방식으로 각각서 서비스를 Cluster로 정의할 수 있다.

아키텍쳐

마지막으로 Spinnaker의 내부 아키텍쳐를 살펴보도록 하자.

Spinnaker는 MSA (마이크로 서비스 아키텍쳐) 구조로 구성이 되어 있으며, 아래 그림과 같이 약 9 개의 컴포넌트로 구성이 되어 있다.



각 컴포넌트에 대해서 알아보도록 하자


  • Deck : Deck 컴포넌트는 UI 컴포넌트로, Spinnaker의 UI 웹사이트 컴포넌트이다.

  • Gate : Spinnaker는 MSA 구조로, 모든 기능을 API 로 Expose 한다, Gate는 API Gateway로, Spinnaker의 기능을 API로 Expose 하는 역할을 한다.

  • Igor : Spinnaker는 Jenkins CI 툴과 연동이 되는데, Jenkins에서 작업이 끝나면, Spinnaker Pipeline을 Invoke 하는데, 이를 위해서 Jenkins의 작업 상태를 Polling을 통해서 체크한다. Jenkins의 작업을 Polling으로 체크 하는 컴포넌트가 Igor이다.

  • Echo : 외부 통신을 위한 Event Bus로, 장애가 발생하거나 특정 이벤트가 발생했을때, SMS, Email 등으로 notification을 보내기 위한 Connector라고 생각하면 된다

  • Rosco : Rosco는 Bakering 컴포넌트로, Spinnaker는 VM또는 Docker 이미지 형태로 배포하는 구조를 지원하는데, 이를 위해서 VM이나 도커 이미지를 베이커링(굽는) 단계가 필요하다. Spinnaker는 Packer를 기반으로 하여 VM이나 도커 이미지를 베이커링 할 수 있는 기능을 가지고 있으며, Rosco가 이 기능을 담당 한다.

  • Rush : Rush는 Spinnaker에서 사용되는 스크립트를 실행하는 스크립트 엔진이다.

  • Front50 : Front 50은 파이프라인이나 기타 메타 정보를 저장하는 스토리지 컴포넌트이다.

  • Orca : Oraca는 이 모든 컴포넌트를 오케스트레이션하여, 파이프라인을 관리해주는 역할을 한다.

  • CloudDriver : 마지막으로 Cloud Driver는 여러 클라우드 플랫폼에 명령을 내리기 위한 아답터 역할을 한다.




CI/CD 레퍼런스 아키텍쳐


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


Continuous Deployment를  구현하기 위해서는 여러가지 프레임웍을 조합할 수 있다. 배포를 위한 Chef,Puppet과 같은 Configuration management tools, 그리고 네트워크, VM등을 코드로 설정하기 위한 Terraform 과 같은 Infrastructure as a code, VM 이미지를 만들기 위한 Packer 등 다양한 솔루션 조합이 가능한데, 이 글에서는 이러한 솔루션을 조합하여 어떻게 Continuous Deployment 파이프라인을 구현할 수 있는지에 대해서 설명하고, 구체적인 솔루션 제안을 통하여 레퍼런스 아키텍쳐를 제안하고자 한다.

1. Terraform + Ansible 기반의 Continuous Delivery

가장 기본적인 조합으로는 Terraform 을 이용해서 코드로 정의된 설정을 이용하여 인프라를 설정한 후에,

VM에, Ansible을 이용하여 애플리케이션 서버등의 소프트웨어를 설치한 후,  애플리케이션 코드를 배포하는 방식이다.

아래 그림은 Terraform으로 먼저 VM 인스턴스 그룹을 만든 후에, Load Balancer에 연결하고, CloudSQL (DB)인스턴스를 배포하는 구조이다.




이후에, 각 VM에 대한 설치는 Ansible을 이용하는 구조이다 Ansible은 Jenkins와 같은 CD 툴에 의해서 코드 변경등이 있으면 호출되서 자동화 될 수 있다.


이러한 구조는 전통적인 Continuous Delivery 기반의 애플리케이션 배포 자동화 구조이다.


2. Packer를 추가한 Foundation Image 사용방식

앞의 구조에서 VM은 애플리케이션 서버를 코드 배포 단계에서 배포할 수 도 있지만 애플리케이션 코드 이외에는 변경이 없기 때문에, Terraform으로 인프라를 배포할때, Packer와 Ansible을 이용하여, 애플리케이션이 설치되어 있는 이미지를 만들어놓고, 이를 이용해서 배포할 수 있다. (이미지를 만드는 과정을 베이킹 = 굽는다. 라고 한다.)

아래 그림을 보면, Terraform에서, Packer를 호출하고, Packer가 VM 이미지를 만드는데, 이 과정에서 Ansible을 이용하여, 애플리케이션 서버를 설치하도록 설정하는 구조를 가지고 있다.



위의 구조에서는 node.js server 애플리케이션 서버를 사용했지만, 실제 인프라를 구축할때는 redis나 웹서버등 다양한 애플리케이션의 설치가 필요하기 때문에, 이 구조를 사용하면 전체 인프라 구축을 코드로 정의하여 자동화를 할 수 있다.

3. Spinnaker를 이용한 Continuous Deployment 구조

코드만 배포하고 업데이트 할 경우, 서버의 패치 적용등의 자동화가 어렵기 때문에, 매번 배포시 마다, VM 설정에서 부터 OS 설치와 패치 그리고 애플리케이션 설치와 코드 배포까지 일원화하여 VM 단위로 배포할 수 있는데, 이를 Continuous Deployment 라고 한다.


솔루션 구성은 2번의 구조와 유사하나, Terraform으로는 VM과 로드밸런서를 제외한 다른 인프라를 설정하고 Spinnaker를 이용하여, 로드밸런서와 VM을 이용한 배포를 실행한다.


Spinnaker로 배포할 수 있는 범위는 방화벽, 로드밸런서, VM 과 같이 워크로드를 받는 부분인데, Spinnaker는 Packer와 Ansible과 협업하여, VM에 모든 스택을 설치하고, 이를 VM 단위로 배포할 수 있도록 해준다. 복잡한 네트워크 설정이나, CloudSQL과 같은 클라우드 전용 서비스는 Spinnaker로 설정이 불가능하기 때문에, 먼저 Terraform으로 기본 인프라를 설정하고, VM관련된 부분만을 Spinnaker를 사용한다.

이렇게 VM전체를 배포하는 전략을 피닉스 서버 아키텍쳐라고 한다. 피닉스 서버 패턴은 http://bcho.tistory.com/1224?category=502863 글을 참고하기 바란다.


Spinnaker를 이용한 배포 전략

Spinnker를 이용하면, VM 기반의 배포뿐 아니라, 다양한 배포 전략을 수행할 있다.



그림 https://sdtimes.com/cloud/google-open-source-platform-spinnaker-1-0/


Blue/Green deployment

블루 그린 배포 전략은 새버전의 서버그룹을 모두 배포 완료한 후에, 로드밸런서에서 트래픽을 구버전에서 새버전으로 일시에 바꾸는 방식이다.

Rolling deployment

롤링 배포는, 새버전의 서버를 만들어가면서 트래픽을 구버전 서버에서 새버전으로 점차적으로 옮겨가는 방식이다. 예를 들어 구서버가 10대가 있을때, 새 서버 1대가 배포되면, 구서버 9대와 새서버 1대로 부하를 옮기고, 새서버 2대가 배포되면 구서버:새서버에 8:2 비율로 부하를 주면서 7:3,6:4,5:5,.... 이런식으로 부하를 옮겨가며 전체 부하를 새 서버로 옮기는 방식이다.


블루 그린 배포 전략은 서버 대수의 2배수의 서버가 필요한 반면, 롤링 배포 방식은 같은 서버의 수 (위의 예의 경우 10대만 있으면 됨)를 가지고 배포를 할 수 있기 때문에 서버 자원이 한정되어 있는 경우에 유리하게 사용할 수 있다.

Canary deployment

카날리 배포를 설명하기 전에 카날리 테스트에 대한 용어를 이해할 필요가 있다.

카날리 테스트는 옛날에 광부들이 광산에서 유독가스가 나오는 것을 알아내기 위해서 가스에 민감한 카나리아를 광산안에서 키웠다고 한다. 카나리아가 죽으면 유독가스가 나온것으로 판단하고 조치를 취했다고 하는데, 이 개념을 개발에서 사용하는것이 카날리 테스트 방식이다.

예를 들어 사용자가 1000명이 접속해 있을때, 일부 사용자에게만 새 버전을 사용하도록 하고, 문제가 없으면 전체 사용자가 새 버전을 사용하도록 하는 방식인데, 안드로이드 앱 배포의 경우에도 10%의 사용자에게만 새 버전을 배포해보고 문제가 없으면 100%에 배포하는 것과 같은 시나리오로 사용된다.


이 개념을 배포에 적용한것이 카날리 배포 방식인데, 일부 서버에만 새 버전을 배포하여 운영한 후에, 문제가 없는 것이 확인되면 전체 서버에 새 버전을 배포하는 방식이다.

Docker를 이용한 배포 효율화

이러한 VM 기반의 Continuous deployment 구조는 피닉스 서버 패턴을 기반으로 하여, 모든 업데이트 추적이 가능하다는 장점을 가지고 있지만, 매번 VM을 베이킹해야 하기 때문에 시간이 많이 걸리고, VM 이미지는 사이즈가 커서 스토리지를 많이 사용한다는 단점이 있다.

이러한 배포 구조와 잘 맞는 것이 Docker (Docker 개념 http://bcho.tistory.com/805 ) 인데, Docker는 컨테이너 기반으로 경량화가 되어 있기 때문에, 이미지 베이킹 시간이 상대적으로 짧고, 이미지 사이즈가 작아서 저장이 용이하며, 이미지를 저장하기 위한 리파지토리와 같은 개념이 잘되어 있다.


Spinnaker의 경우 이런 Docker 기반의 피닉스 서버 패턴 기반의 배포를 지원하는데, 특히 Kubernetes 클러스터를 매우 잘 지원하기 때문에, 오히려 VM 기반의 배포 보다는 Docker + Kubernetes 배포 구조를 선택하는 것이 좋다.


이 경우 인프라 배포에 있어서는 애플리케이션을 서비스하는 VM워크로드는 도커를 사용하되, Redis, RDBMS와 같은 미들웨어 솔루션은 재 배포가 거의 발생하지 않기 때문에, VM에 배포하여 사용하는 것이 성능적으로 더 유리하기 때문에, 도커와 VM 을 하이브리드 구조로 배포하는 방식을 권장한다.


클라우드 전용 배포 솔루션  VS 오픈소스 (Terraform)

앞에서 설명한 아키텍쳐에서 사용한 솔루션은 모두 오픈 소스 기반이다. 클라우드 벤더의 경우에는 구글은 Deployment Manager와, 아마존은 CloudFormation을 이용하여, 코드 기반의 배포 (Terraform과 동일)를 지원하는데, 그렇다면, 클라우드에서 제공하는 전용 솔루션을 쓰는 것이 좋은가? 아니면 오픈소스나 벤더에 종속적이지 않은 솔루션을 사용하는 것이 좋은가

오픈소스의 배포툴의 경우에는 요즘 트랜드가 다른 영역으로 확장을 해가는 추세가 있기 때문에, 코드 기반의 인프라 배포 이외에도 애플리케이션 코드 배포등 점점 더 넓은 영역을 커버할 수 있는 장점이 있고, 오픈 소스 생태계내에서 다른 제품들와 연동이 쉬운점이 있다. 그리고 특정 클라우드 벤더나 인프라에 종속성이 없기 때문에 조금 더 유연하게 사용이 가능하지만, 클라우드 벤더에서 제공되는 새로운 서비스나 기능 변화를 지원하는 것에는 상대적으로 클라우드 벤더에서 제공하는 도구보다 느리다. 예를 들어 구글 클라우드에서 새로운 서비스가 나왔을때, 테라폼에서 이 기능을 지원하는데 까지는 시간이 걸린다는 것이다.


양쪽다 좋은 선택지가 될 수 있기 때문에, 현재 환경에 맞는 솔루션을 선택하는 것을 권장한다.




Packer와 Ansible을 이용하여, node.js 이미지 생성하기


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


앞서 글에서 패커를 이용한 이미지 생성 및, 이미지 타입(http://bcho.tistory.com/1226) 에 대해서 알아보았다. 이번 글에서는 node.js 가 깔려있는 파운데이션 타입의 구글 클라우드 VM이미지를 패커와 앤서블을 이용해서 구현해 보도록 한다. 이 글을 이해하기 위해서는 http://bcho.tistory.com/1225 에 대한 이해가 필요하다.


구성은 다음과 같다. 패커를 이용하여, Debian OS 기반의 이미지를 만든 후에, 패커의 Provisioner를 이용하여 Ansible을 설치하고, 이 설치된 Ansible을 이용하여 node.js등을 설치하는 playbook 을 실행하는 순서로 node.js용 이미지를 만든다.  



패커 스크립트는 다음과 같다.

builder 부분은 예전과 같다.(http://bcho.tistory.com/1225) Debian 이미지를 기반으로 VM을 생성한다.

VM 생성후에, 소프트웨어 설치등을 정의하는 부분은 provisioner 라는 부분에 정의되는데, 두 타입의 Provisioner가 사용되었다. 첫번째는 shell 타입이고 두번째는 ansible-local 형태의 provisioner이다.


{

 "variables":{

   "project_id":"terrycho-sandbox",

   "prefix":"debian-9-nodejs"

 },

 "builders":[

  {

   "type":"googlecompute",

   "account_file":"/Users/terrycho/keys/terrycho-sandbox-projectowner.json",

   "project_id":"{{user `project_id`}}",

   "source_image":"debian-9-stretch-v20180105",

   "zone":"us-central1-a",

   "ssh_username":"ubuntu",

   "image_name":"{{user `prefix`}}-{{timestamp}}",

   "machine_type":"n1-standard-4"

  }

 ],

 "provisioners":[

   {

     "type":"shell",

     "execute_command":"echo 'install ansible' | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",

     "inline":[

               "sleep 30",

               "apt-add-repository ppa:rquillo/ansible",

               "/usr/bin/apt-get update",

               "/usr/bin/apt-get -y install ansible"

               ]

   },

   {

      "type":"ansible-local",

      "playbook_file":"./nodejs_playbook.yml"

   }


 ]


}


첫번째 provisioner에서는 ansible을 apt-get으로 설치하기 위해서 sudo 권한으로 apt-get update를 실행하여, 리파지토리 정보를 업데이트 한후에, apt-get -y install ansible을 이용하여, ansible을 설치한다.


두번째 provisioner는 ansible-local provisioner로, 앞단계에서 설치된 ansible을 로컬에서 실행하여, playbook을 실행해주는 코드이다.

ansible은 Configuration management & Deployment 도구로, 나중에 기회가 되면 다른글을 이용해서 소개하도록 한다.

이 코드에서 호출된 nodejs_playbook.yml 파일의 내용은 다음과 같다.

- hosts: all

 tasks:

       - name : create user node

         become : true

         user :

             name: nodejs

             state : present

       - name : update apt-get install

         shell : curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -

       - name : install node.js LTS

         become : true

         #become_user: nodejs

         apt : pkg=nodejs state=installed update_cache=true


hosts:all로, ansible에 등록된 모든 호스트에 대해서 스크립트를 실행하도록 한다. 여기서는 별도의 호스트를 등록하지 않았고, ansible-local 타입으로 실행하였기 때문에, 이 호스트 (localhost)에만 스크립트가 실행된다.

크게 3단계로 실행이 되는데, 첫번째가 nodejs라는 사용자를 만드는 단계로, user 라는 모듈을 사용하여 nodejs라는 사용자를 생성하였다. 이 사용자 계정은 향후 애플리케이션이 배포되었을때, nodejs를 실행할 계정으로 사용된다. 사용자 계정을 만들기 위해서는 root 계정을 획득해야하기 때문에, become: true로 하여 sudo 로 명령을 실행하도록 하였다.

두번째는 node.js를 인스톨하기 위해서 설치전 사전 스크립트를 실행하는 부분이다. apt-get install을 디폴트 상태에서 실행하게 되면 node.js 4.x 버전이 인스톨된다. 최신  8.X 버전을 인스톨하기 위해서, 스크립트를 실행한다. 앤서블 모듈중에서 shell 모듈을 이용하여 쉘 명령어를 실행하였다.

세번째 마지막은 apt 모듈을 이용하여, node.js를 인스톨하도록 한다.


스크립트 작업이 끝났으면, 이미지를 생성해보자

%packer build node.json


으로 실행을 하면 이미지가 생성된다. 생성된 이미지는 구글 클라우드 콘솔의 GCE (Google Compute Engine)의 Images 메뉴에서 확인이 가능하다.

다음과 같이 debian-9-nodejs-*로 새로운 이미지가 생성된것을 확인할 수 있다.



생성된 이미지가 제대로 되었는지를 확인하기 위해서, 이 이미지로 VM을 생성해서 nodejs 버전을 확인해보면 다음과 같이 8.9.4 가 인스톨 되었음을 확인할 수 있다.

또한 nodejs로 된 계정이 생성되었는지를 확인하기 위해서 /etc/passwd 내에 사용자 정보가 생성되었는지를 확인해보면 아래와 같이 nodejs 이름으로 계정이 생성되었음을 확인할 수 있다.



참고 : https://blog.codeship.com/packer-ansible/



피닉스 패턴의 VM 이미지 타입


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


피닉스 서버 패턴을 이용해서 이미지를 만들때, 그러면 이미지에 어디까지 패키징이 되어야할지 결정할 필요가 있다. 정답은 없지만 몇가지 정형화된 패턴을 찾을 수 는 있다


OS Image

가상화 환경이나 클라우드를 사용하면 디폴트로 사용하는 패턴으로 이미지가 OS 단위로 되어 있는 패턴이다. 우분투 이미지, 윈도우 이미지와 같이 OS 단위로 이미지가 되어 있다.




피닉스 패턴을 사용할 경우 애플리케이션 배포시, 이미지를 이용해서 VM 을 생성하고 VM 이 기동될때, Configuration management 도구를 이용하여 소프트웨어 스택 (미들웨어, 라이브러리등)과 애플리케이션 코드를 배포하는 방식이다.

Foundation Image

Foundation Image는 이미지를 OS단위가 아니라 서비스 플랫폼, 예를 들어 Ruby on rails 환경, PHP환경과 같은 환경 별로 관리하는 방법이다.



일종의 PaaS와 같은 개념의 이미지로 생각되는데, 가장 적절한 절충안이 아닌가 싶다.


Immutable Image

마지막으로는 Immutable Image (불변) 이미지인데, 이 이미지 타입은 배포마다 매번 새롭게 이미지를 만드는 패턴이다.


항상 OS 부터 애플리케이션 까지 전체 스택이 같이 이미지화 되어 배포되기 때문에, 최신 업데이트를 유지하기가 좋지만, 빌드 시간이 많이 걸리고 관리해야 하는 이미지 양이 많아진다.

이 패턴으로 갈거면 도커를 쓰는게 오히려 정답이 아닐까 싶다.


 OS 이미지 패턴의 경우 VM이 올라오면서 소프트웨어들이 설치되고 애플리케이션이 설치되는 모델인데, 소프트웨어 특히 npm이나 pip들을 이용해서 라이브러리를 설치할때 외부 저장소를 이용하는 경우, 외부 저장소가 장애가 날 경우 소프트웨어 설치가 안되기 때문에 외부 시스템 장애에 대한 의존성을 가지고 있고 설치 시간이 길기 때문에 그다지 좋은 패턴으로는 판단이 안되고, immutable 패턴은 위에서도 언급했듯이 빌드 시간이 길고, 여러 이미지를 관리해야하기 때문에 그다지 권장하고 싶지 않지만, 전체를 매번 묶어서 배포함으로써 일관성 유지가 가능한 장점이 있기 때문에 만약에 해야 한다면 도커를 이용해서 구현하는 것이 어떨까 한다. Foundation Image 패턴이 가장적절한 패턴으로 판단되는데, 다음글에서는 Packer를 이용하여, Foundation Image 타입을 만드는 방법을 알아보도록 하겠다.


Packer


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


Packer (https://www.packer.io/) 는 HashiCorp에서 개발한 가상 머신 이미지를 만들어주는 오픈소스이다.

예를 들어서, 아마존 클라우드 AMI이미지나, 구글 클라우드 이미지를 스크립트를 이용하여 생성이 가능하다.

하나의 스크립트를 이용하여, 구글 클라우드, VMWare, 아마존 클라우드 등 여러 클라우드 환경 (가상화 환경)과 컨테이너 엔진용 이미지를 생성할 수 있다.


Chef,Puppet,Ansible과 같은 Configuration management 툴과 혼동이 될 수 있지만, Packer는 OS 이미지를 만들어주는 역할을 하고, Configuration management 툴들은 이렇게 만들어진 이미지 위에 소프트웨어를 설치하고, 이를 설정하는 상호 보완적인 역할을 하게 된다.

특히 피닉스 서버 패턴에서 VM 이미지를 생성하는데 매우 유용하게 사용될 수 있다. 피닉스 서버 패턴은 http://bcho.tistory.com/1224 를 참고하기 바란다.

템플릿

전체 컨셉은 VM의 설정을 JSON 파일에 정의해놓고, packer 툴을 이용하여 이미지를 생성하는 방식이다.

VM의 설정을 정의한 파일을 템플릿 파일이라고 하는데, 다음과 같은 구조를 가지고 있다.


  • Variable : 변수를 정의하는 섹션으로, 동적으로 변경될 수 있는 클라우드 프로젝트명, 리전명등을 정의하는 부분이다. 메인 템플릿내에 섹션으로 정의할 수 도 있고, 또는 환경 변수나 별도의 변수만 지정한 파일 또는 CLI 옵션으로도 변수값을 전달할 수 있다.

  • Builder : 가장 핵심이 되는 부분으로 OS 버전등 VM 설정에 대한 부분을 정의한다.

  • Provisioner : 이미지에서 OS 설정이 끝난후에, 소프트웨어 스택을 설치하는 부분을 정의한다. 앞에서도 언급하였지만 Packer는 다양한 가상환경에 대한 이미지 생성에 최적화 되어 있지 소프트웨어 설치를 용도로 하지 않기 때문에, Provisioner에서는 다른 configuration management 툴과의 연계를 통해서 소프트웨어를 설치하도록 지원한다. 간단한 쉘을 이용하는것에서 부터, ansible,chef,puppet,salt stack등 다양한 configuration management 도구를 지원하도록 되어 있다. https://www.packer.io/docs/provisioners/index.html
    이 과정에서 OS 설치 후, 소프트웨어 스택 설치 뿐만 아니라, 패치 및 기타 OS 설정 작업을 진행할 수 있다.

  • Post-Processor : Builder와 Provisioner에 의한 이미지 생성이 끝나면 다음으로 실행되는 명령이다.

간단한 예제

이해를 돕기 위해서 직접 간단한 이미지를 만들어보도록 하자.

예제는 맥북에서 packer를 사용하여 구글 클라우드 이미지를 만드는 예제이다. 구글 클라우드의 간단한 사용법은 http://bcho.tistory.com/1107 문서를 참고하기 바란다.

설치 하기

설치는 매우 간단하다. packer는 커맨드 라인 형태의 툴이기 때문에, https://www.packer.io/downloads.html 에서 다운로드 받은후에, 압축을 푼후, PATH에 추가해서 사용하면 된다.


환경 준비

구글 클라우드 API 활성화

packer의 이미지 생성은 구글 클라우드에 접속하여 VM을 만들어서 이미지를 생성하고 이를 구글 클라우드에 등록하는 방식이기 때문에, 구글 클라우드의 관련 API들을 호출해야 한다.

그래서 이 API를 외부에서 호출이 가능하도록 Enable 해줘야 하는데, 아래와 같이 구글 클라우드 메뉴에서 APIs & Services 항목에 들어가면 필요한 API들을 활성화 할 수 있다.



필요한 API는

  • Google Cloud Billing API

  • Google Compute Engine API

를 Enable(활성화) 해줘야 한다

Service Account 파일 생성

packer가 구글 클라우드 API를 사용하기 위해서는 API를 호출하기 위한 인증과 권한 인가가 필요하다. 구글 클라우드는 여러가지 방법을 제공하는데, 여기서 사용할 방법은 service account 를 이용하는 방법이다. 콘솔에서 service account를 생성하고, 이 계정에 여러가지 권한을 부여할 수 있는데, 이렇게 생성된 service account에 대한 인증 정보는 파일로 생성이 된다. 이 예제에서는 이 파일의 경로를 지정하여 service account의 권한을 이용하여 이미지를 생성하도록 하였다.

Service account 파일을 생성하는 자세한 방법은 http://bcho.tistory.com/1166 를 참고하기 바란다.

예제 코드

준비가 끝났으면 이제 실제로 간단한 이미지를 만들어보자. 아래는 gce.json 파일로, n1-standard-4 사이즈 VM에 debian-9 OS로 된 이미지를 구글 클라우드에 만드는 예제이다.


{

 "variables":{

   "project_id":"terrycho-sandbox",

   "prefix":"terrycho-packer"

 },

 "builders":[

  {

   "type":"googlecompute",

   "account_file":"/Users/terrycho/keys/terrycho-sandbox-projectowner.json",

   "project_id":"{{user `project_id`}}",

   "source_image":"debian-9-stretch-v20180105",

   "zone":"us-central1-a",

   "ssh_username":"ubuntu",

   "image_name":"{{user `prefix`}}-{{timestamp}}",

   "machine_type":"n1-standard-4"

  }

 ]

}

이 예제가 제대로 작동하기 위해서는 variables의 project_id를 본인것으로 변경해야 하고,  account_file 부분에 본인이 생성하여 다운로드 받은 service account 파일의 경로를 지정해야 한다.


설정 파일의 내용을 상세하게 알아보도록 하자.

  • account_file : 구글 클라우드 API 에 접근하기 위한 Service account 파일 경로

  • project_id : 이미지 생성에 사용할 구글 클라우드 프로젝트 ID를 지정한다. 여기서는 프로젝트 이름을 terrycho-sandbox로 지정하였다.

  • source_image : 이미지를 생성할때 베이스 이미지를 선택한다. 베이스 이미지는 구글 클라우드에 등록된 이미지를 기준으로 하는데, 이미지 목록은 google cloud CLI 명령인 gcloud  명령을 이용하면 된다.
    %gcloud  compute images list
    명령을 이용하면 현재 가용한 이미지 목록을 볼 수 있고, 거기서 필요한 이미지 이름을 사용하면 된다. 여기서는 debian-9 이미지를 사용하였다.

  • image_name : 생성될 이미지 명. 구글 클라우드 GCE에 이 이름으로 이미지가 등록된다.

  • zone : 이미지를 만드는 방식이 실제 구글 클라우드에서 VM 인스턴스를 만들었다가 이를 기반으로해서 이미지를 추출하는 방식이기 때문에, 이미지를 추출하기 위한 이 VM을 어느 zone에서 기동 시킬지를 지정한다.

예제 실행


파일 작성이 끝난후 아래와 같이 프롬프트 상에서 packer build 명령을 이용하면 이미지 생성이 시작된다.

%packer build gce.json


아래는 명령어를 실행한 결과이다. 로그를 보면 구글 클라우드내에서 설정에 따라서 VM을 만들었다가 이미지를 추출하고, VM을 지우는 과정을 확인할 수 있다.



이 과정이 끝나고 구글 클라우드 콘솔에서 Compute Engine > Image 메뉴를 들어가보면 아래 그림과 같이 terrycho-packer-.... 라는 이름으로 이미지가 생성되어 등록된것을 확인할 수 있다.



이 이미지를 이용하여, 새로운 VM을 만들면 된다. 



피닉스 서버

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


근래에 들어서 인프라 스트럭쳐를 소프트웨어로 정의하는 Infrastructure As a Code (줄여서 IaC라고 부름)를 관심있게 보고 있는데, CI/CD의 단순 연장선상의 하나의 툴링정도로 생각했는데, 생각보다 상당히 넓은 생태계라서 좀더 깊게 보고 있다.

IaC는 일반적인 툴이나 단순한 프로세스가 아니라 하나의 사상이기 때문에 이를 제대로 이해하기 위해서는 툴링 관점의 접근 보다는 사상과 배경에 대해서 제대로 이해할 필요가 있다.

IaC 개념을 이해하는데 도움이 되는 개념으로 Snowflakes Server (스노우플레이크 서버)와 Phoenix Server(피닉스 서버) 두 가지 개념에 대해서 알아볼 필요가 있다.

Snowflakes Server (스노우 플레이크 서버)

예전에 일반적으로 서버를 운영하는 방법은 서버를 설치한 후 OS를 인스톨한 후에, 필요한 소프트웨어와 애플리케이션을 설치하여 운영하는 형태였다. 여기에 문제가 생긴 경우 패치를 하거나 정기적인 보안 패치 튜닝들을 해당 서버에 지속적으로 적용하고, 애플리케이션은 CI/CD 등의 툴을 이용하여 배포하는 구조를 가지고 있었다.


이렇게 한번 설치한 서버에 계속해서 설정을 변경하고 패치를 적용하는 등의 업데이트를 지속적으로 적용하여 운영하는 서버를 스노우 플레이크 서버 (눈송이 서버)라고 하는데, 이렇게 설정된 서버는 다시 똑같이 설정하기가 매우 어렵다. 모든 설정과정이 문서화가 잘되어 있으면 모르겠지만 대부분 문서화가 꼼꼼한 경우도 드물뿐더러,  담당자가 바뀌거나 관리 조직이 바뀌는 경우에는 그 이력이 제대로 유지되는 경우가 없다. 그래서 장비를 업그레이드 하거나 OS를 새로 인스톨해서 같은 환경을 꾸미고자 할때 예전 환경과 동일한 환경을 구성하기가 어렵고 그래서, 누락된 설정이나 패치등에 의해서 장애가 발생하는 경우가 많다.

이렇게 한번 설정을 하고 다시 설정이 불가능한, “마치 눈처럼 녹아버리는" 서버의 형태를 스노우 플레이크 서버라고 한다.


재 구성의 문제뿐 아니라, 이런 스노우 플레이크 서버는 구성 편차를 유발하기도 하는데, 여러대의 웹서버를 운영하고 있는 조직에서, 문제가 있어서 특정 서버를 패치한 경우, 다른 동일한 웹서버를 모두 패치 하지 않는 이상 구성이 달라진다.  이는 또 운영상의 문제를 일으킬 수 있다.

Phoenix Server (피닉스 서버)

그래서 나온 서버 패턴이 피닉스 서버 패턴인데, 피닉스(불사조)는 불멸로도 알려져있지만 정확히는 불속에서 다시 태어나는 re-born (재탄생)의 개념을 가지고 있다. 이 재탄생의 개념을 서버 설정 방식에 적용한 패턴이 피닉스 서버 패턴이다.

새로운 소프트웨어를 인스톨하거나 설정을 변경할때 기존 서버에 변경 작업을 더 하는 것이 아니라, 처음 OS 설치에서 부터, 소프트웨어 인스톨, 설정 변경까지를 다시 반복하는 것이다.

예를 들어 우분투 16, 톰캣 7.0 버전으로 운영되고 있는 서버가 있을때, 이 서버에 로그 수집 모듈은 fluentd를 설치하는 케이스가 있다고 가정하자.


스노우플레이크 서버 패턴의 경우에는 이미 운영되고 있는 서버에 새롭게 fluentd를 일일이 설치하거나 자동화가 되어 있는 경우에는 ansible 이나 chef등의 configuration management 도구를 이용하여 fluentd를 설치하게 된다.


피닉스 서버 패턴의 경우에는 새 VM을 다시 만들고, 우분투 16 OS를 설치하고, 톰캣 7.0을 설치하고 fluentd를 설치한 다음. 이 VM으로 기존 VM 을 교체한다.


매번 전체 설치를 반복한다면 매우 많은 시간이 들텐데, 어떻하냐? 물론 매번 이렇게 새롭게  모든 스택을 설치하지 않는다. 어느정도 공통 스택은 가상머신의 베이스 이미지 (VM Base Image)로 만들어놓고, 이 이미지를 이용하여 VM을 생성한 후에, 차이가 나는 부분만 설정을 하는 구조를 설정하는 구조를 사용하게 되고 이 과정은 스크립트 코드를 이용해서 자동화하기 때문에, 그렇게 많은 시간이 소요되지 않는다.

피닉스 서버 패턴에서는 매번 전체를 스크립트를 이용해서 설치하기 때문에, 다음과 같은 장점을 가지게 된다.


  • 스크립트에 모든 설정 정보가 유지되게 된다.

  • 이 스크립트 코드를, git와 같은 소스 코드 관리 시스템을 이용해서 관리하게 되면, 어떤 부분을 누가 어떻게 수정을 했는지 추적이 가능하게 된다.

피닉스 서버 패턴을 이용한 배포 구조

그러면 이 피닉스 서버 패턴을 이용한 배포 구조를 보도록 하자

앞의 예제와 같이 Ubuntu 16, Tomcat 7이 설치된 VM서버 2대가 서비스되고 있고, 이 서버들은 앞단에 로드밸런서에 연결되어 있다고 생각하자. 이 VM들은 Ubuntu16, Tomcat 7이 설치되어 있는 Base Image로 생성했다고 가정하자.



Fluentd를 설치하기 위해서는 피닉스 서버 패턴 처럼, Fluentd가 설치된 새로운 base image를 생성하고, 이 이미지를 이용하여 새로운 VM들을 만든다. 이 VM들 그룹은 아직 서비스가 되기 전으로, 이 그룹을 Pre-production 그룹이라고 한다.



Pre-production 그룹이 정상적으로 들어왔으면 로드밸런서를 변경하여 기존의 구 버전 VM으로 들어가던 트래픽을 pre-production 그룹으로 옮겨준다.


그리고 마지막으로, 기존의 운영환경을 지워주면 아래와 같이 새 환경으로 서비스 하는 환경만 남게 된다.


이렇게 서버가 구 버전에서 새버전으로 재탄생(re-born)하는 것이 피닉스 서버 패턴이다.


이 패턴의 문제는 VM 이미지를 빌드하기 때문에, 빌드 및 배포 시간이 상대적으로 오래 걸리고, 또한 배포 당시 기존 Production 환경과 Pre-production 환경이 공존하기 때문에, 다소 추가 비용이 소요될 수 있다.


이 피닉스 서버 패턴에서 중요한것은 기존 이미지를 이용하여 변경을 주고, 이를 다시 이미지로 만들어낼 수 있지만, 이렇게 하면 스노우플레이크 서버이지 피닉스 서버가 아니다. 피닉스 서버는 기존 이미지를 재 사용하는게 아니라 처음부터 모든 스택을 새로 설치해야 하기 때문에, 처음부터 모든 스택을 설치하여 이미지를 만들 수 있는 자동화 툴이 필요하다. 다음 글에서는 이미지 생성을 자동화 해주는 HashiCorp의 Packer라는 오픈소스에 대해서 알아보도록 하겠다.


전 위메프 CTO 김요섭님의 DEVOPS


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


오늘 GSSHOP에서 전 위메프 CTO 인 김요섭님의 DEVOPS에 대한 강의를 들었다.

그간의 경험이나 고민이 묻어나는 꽉 찬 강의 였다고나 할까?




내용을 정리해보면 다음과 같다.

DEVOPS의 발전 단계

DEVOPS는 조직의 성숙도나 역량에 따라서 단계적인 발전 단계를 갖는다.

첫번째 단계는 자동화를 통해서 자동 빌드와 배포 (CI/CD)를 구축하는 단계, 두번째 단계는 운영 환경에서 나온 로그나 각종 지표를 참고로 하여 개발의 요구 사항에 반영 하는 과정, 세번째 단계는 운영 상황에 개발팀이 참여하여 실제 배포나 장애 상황에 대해서 같이 고민하는 과정, 마지막으로 네번째 단계는 개발 단계에서 운영을 고려하여 설계 및 개발을 진행하는 단계이다.


케이스 스터디

DEVOPS에 대해서 고민을 하면서 자체적으로 많은 스터디를 하신 듯한데, 그중에서 케이스 스터디 내용에서 많은 인사이트를 얻을 수 있었다.


페이스북의 사례

  • 하루에 2번 마이너 업데이트, 일주일에 한번 메이져 업데이트

  • 배포는 테스트 환경에서 배포가 완료되면, 내부 사용자가 사용할 수 있는 단계로 배포하는 H1 배포, 다음으로, 실사용자중 1%의 사용자만 사용할 수 있게 하는 H2 배포, 마지막으로 전체 사용자가 사용하는 환경으로 H3 배포
    일반적인 개발환경에서 봤을때, H1은 Pre-production, H2는 AB테스트 환경으로 배포, H3는 운영 환견으로 보면 되겠다.

  • 비트 토렌토를 이용하여 전세계 서버로 배포를 진행하며, 빌드에 15분, 배포에 약 15분이 소요된다. 예전 자료이기 때문에 현재는 훨씬 향상이 되었을듯.

  • IRC를 통해서 배포 상황 및 에러에 대해서 대응을 하고, 개발자가 IRC에서 수분내로 응답 하지 않을 경우에는 그 개발자가 개발한 코드는 빼고 배포한다.

  • 배포 후 모니터링을 시스템 뿐 아니라 페이스북 뿐 아니라 트위터와 같은 외부 SNS를 통해서도 배포 결과에 문제가 없었는지 등을 크롤링해서 모니터링 한다.

  • 배포에 있어서 문화는 문제가 생기면 롤백을 하기 보다는 빠르게 문제를 해결해서 재 배포 하는 방향으로 가고, 개발자에게 카르마(평판)을 부여하여 배포가 실패할때 마다 카르마를 깍고 카르마가 낮은 엔지니어는 릴리즈 엔지니어가 엄격하게 리뷰 한다.


플리커의 사례

  • 하루에 10번 배포를 하는데 이를 소개한 Youtube 영상이 유명하다고 하니 참고할것. 유투브는 못찾았고, 슬라이드 쉐어만 찾았는데, http://www.slideshare.net/jallspaw/10-deploys-per-day-dev-and-ops-cooperation-at-flickr

  • 개발 코드, QA 코드, 그리고 인프라 설정 스크립트등을 하나의 SCM으로 합쳐서 모든 팀이 정보를 공유해서 문제를 찾아나갈 수 있도록 했다.


Etsy

  • Change behind flag 라는 기능을 제공해서 특정 기능을 끄거나 킬 수 있도록 했다. 배포 후 문제가 생기면 재 배포를 하는 것이 아니라, 이 플래그를 꺼서 해당 기능을 사용할 수 없게 하고 버그 수정후 빠르게 업데이트를 한다.


넥플릭스

  • 별도로 배포를 진행하는 팀이 존재한다.

  • 3개의 코드 브랜치를 사용 (Test, Release, Prod branch). 각 단계가 끝나면 다음 브랜치로 코드를 이동함.

  • 카날리 분석 (Canary analytics)

    • 예전 광산에서 나쁜 가스나 굉도 붕괴 전조를 알아내기 위해서 카나리아를 갱도속에 넣고 일했던 것에 착안

    • 운영 환경과 같은 환경 (Pre prod)환경을 만들어 놓고, HTTP status code, response time, load avg 등 약1000개의 지표를 모니터링 한 후, 100점 만점에 90점이 넘어야 배포를 승인.

    • 실제로 위메프에서도 이런 방식을 사용하였는데, 전체 노드중 한대의 노드에만 새 버전을 배포한후 뉴렐릭을 통해서 여러 지표를 모니터링 한 후 문제가 없으면 전체 서버에 배포하는 방식을 사용

  • 넥플릭스의 배포방식중 재미있는 점은 클라우드를 활용하기 때문에 기존 인스턴스를 사용하지 않고, 기존 인스턴스는 놔두고, 새로운 버전용 인스턴스를 새로 배포한 후, 문제가 없으면 새로운 인스턴스들로 트래픽을 돌리고 기존 인스턴스를 없애는 방식을 사용함.

  • 넥플릭스도 역시 배포중에 IRC 채널을 이용한 상황 공유


구글

  • SRE (Site Reliability Engineering)팀을 별도 운영, 운영 팀으로 넘기기 전에 문서,코드등을 리뷰 하는 단계의 관문 같은 팀.

  • 개발 완료 후 6개월 정도 개발팀이 운영하고, 운영 메뉴얼등을 첨부하여 SRE팀에 넘기면 SRE팀이 리뷰하고 오케이가 되야 운영팀으로 넘어감.

  • 페이스북의 카르마처럼, 구글은 팀단위로 Reliability budget 이라는 것을 부여 하여, 배포가 실패할때 마다 이 점수를 깎고, 이 점수가 0이 되면 SRE 팀의 리뷰를 다시 받은 후 점수를 다시 확보해서 배포를 하는 구조


참고할만한 내용들

발표 중간 중간에 참고하면 좋은 글과 책에 대한 소개가 있었다.  내용들이 좋은 것 같아서 일단 메모.

Lean Enterprise




린 스타트업과 유사하지만 다르게 일반 기업에 린 방법론을 적용할 수 있는 방법을 가이드 함

http://www.amazon.com/Lean-Enterprise-Performance-Organizations-Innovate/dp/1449368425/ref=sr_1_1?ie=UTF8&qid=1464945431&sr=8-1&keywords=lean+enterprise


The Phoenix project




http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=The+Phoenix+project


IT 소설로, 프로젝트를 진행하면서 겪는 일들을 풀어나감. Devops에 대한 내용도 있었다고 했던가?


기능 ON/OFF 인 Feature toggle 에 대한 마틴파울러 옹의 글

http://martinfowler.com/articles/feature-toggles.html


다양한 팀 모델에 따른 Devops 구조

http://web.devopstopologies.com/


사례를 통해서 볼 수 있는 인사이트

  • 큰 조직의 경우 배포 팀을 가지고 있는 경우가 많고, 이 경우 배포팀은 인프라 측면 뿐 아니라 코드 리뷰가 가능한 수준의 개발 능력까지 가지고 있는 경우가 많다.

  • 각 개발자에게 배포 포인트 (버짓, 카르마)등을 부여하여, 자주 배포가 실패하는 팀이나 사람에게는 엄격한 리뷰를 하도록 한다.

  • 배포 시에는 IRC또는 슬랙에서 상황을 공유하여 바로 대응한다.

  • 배포 실패시 롤백 보다는 빠르게 버그를 수정하며, 특히 기능을 On/Off 할 수 있는 기능을 제공해서, 버그 발생시 그 기능을 꺼 버린다.

  • Devops 모델은 그 팀의 구조에 따라 적절하게 구성할 필요가 있다. (devopstopologies)


김요섭 CTO도 계속 강조했던 내용이자만 DEVOPS는 기본적으로 자동화 도구와 함께 문화의 변경이 필수적으로 필요하다. 이 문화의 변경이 쉽지 않은데, 재미있는 문장을 인용한것이 있어서 메모한다.


“You can’t change culture directly, buy u can change behavior and behavior becomes culture.

“ (직접 문화를 바꿀 수 있지만, 작은 행동 하나하나를 바꾸면, 그 행동이 결국은 문화가 된다.)


시간이 없어서 질문을 하지는 못했지만 작은 토론 이라도 했으면 조금 더 배울 수 있었던 아쉬움이 남는다. 좋은 인사이트를 얻은 것에 대해서 만족하고 서점으로 책사러~~



1편 글 링크 - http://bcho.tistory.com/815

Devops의 정의  

이러한 개념들을 적극적으로 적용한 기업들이 Netflix, Flicker와 같은 인터넷 서비스 기업이다. 기존 개발 프로세스에 비해서 훨씬 빠르게 고객의 요구 사항을 반영해 내가고 있다. Flicker의 경우에는 하루에 10번 정도 [1]Deploy를 한다고 한다. 일반적인 인터넷 서비스가 한달에 한번 업데이트 빨라야 일주에 한번인데, 하루에 10번이라면, 경쟁 구조 자체가 틀려진다.

PuppetLab (Configuration management 자동화툴)의 블로그[2]에 따르면 Devops를 적용할 경우,경쟁사에 비해서 30배 정도 더 자주 Deployment를 할 수 있으며, Deployment 실패 비율도 50% 이상이나 줄일 수 있다는 것이다.

그렇다면 이렇게 장점이 많은 Devops는 무엇인가?

일반적인 Devops의 정의는 개발과 운영이 분리되면서 오는 문제점을 해결하기 위해서, 개발과 운영을 하나의 조직으로 합쳐서 팀을 운영하는 문화이자 방법론이다앞에서도 설명하였듯이, 개발과 운영을 합치는 것이다. 조금 더 정확하게 이야기 하면, 개발 운영 뿐만 아니라 테스트까지 하나의 팀에 합치는 것이다.


[3]

상당 부분의 테스트는 이미 TDD (Test Driven Development), CI (Continuous Integration)를 통해서 개발 과정의 일부로 들어와 있는 경우가 많다.

Devops, “엔지니어가, 프로그래밍하고, 빌드하고, 직접 시스템에 배포 및 서비스를 RUN한다. 그리고, 사용자와 끊임 없이 Interaction하면서 서비스를 개선해 나가는 일련의 과정이자 문화이다.”

Puppet lab Devops Engineer에 대한 정의를 보면 조금 더 이 개념을 확장하고 있는 것을 볼 수 있는데, “사용자와 끊임 없이 Interaction” 하는 부분은 원론적으로 보면 개발자의 역할 보다는 기존에는 마케팅이나 고객 접점에 있는 서비스 기획자의 역할이었다.

“The DevOps engineer encapsulates depth of knowledge and years of hands-on experience,” Kelsey said. “You’re battle tested. This person blends the skills of the business analyst with the technical chops to build the solution - plus they know the business well, and can look at how any issue affects the entire company.” - See more at: http://puppetlabs.com/blog/what-is-a-devops-engineer#sthash.J5yNwCpX.dpuf

큰 의미에서 보면 단순히 개발,운영이라는 기술적인 접근 뿐만 아니라 사용자와의 의사 소통을 통한 서비스의 개선이라는 비즈니스적인 역할까지 확장한 개념이 된다.

기본적인 개념은 이해 했으리라 본다. 그렇다면 Devops의 실체는 무엇일까? Scrum이나 XP와 같은 방법론? 아니면 조직 체계? Devops는 팀운용 방법론이기도 하지만 정확하게 이야기 하면 문화이다. 개발 문화.

하나의 엔지니어가 멀티롤을 하면서 권한이 많아지게 되고, 예전 전통적인 소프트웨어 개발처럼 요구사항을 받아서, 개발하고 운영에 넘기는 개발 라인에 서 있는 하나의 리소스보다는 같이 생각하고 같이 서비스를 개발해야 하는 협업중심의 문화 체계로 바뀌게 되는 것이다. Devops는 하나의 방향을 제시 한다면, 이를 수행하기 위한 구체적인 방법은 팀에서 정의하고 만들어나가야 한다. (매뉴얼이 없다!!)

Devops의 특징

그래도 최소한 Devops를 적용하기 위해서는 어떻게 해야 할까? “팀을 합치고 문화를 바꾸세요.” 이건 너무 추상적이지 않나? 몇가지 제공되는 가이드 들이 있는데, 다음은 영국정부에서 제공하는 “Good Habit for Devops[4]의 내용을 정리한것이다. 기본적인 내용이지만, 참 많은 의미를 담고 있는 내용들이라서 몇번을 다시 생각해봐도 의미가 있는 내용이다.

     Cross functional team 하나의 팀에 각각 다른 역할을 할 수 있는 팀원들로 셋업해서 전체 End 2 End 서비스를 운용할 수 있도록 한다. 앞에서 개발자가 만능이되야 한다고 이야기 했지만, 그렇다고 만능 개발자로 전체 팀을 채워서 일을 하라는 것이 아니다. 개발자의 커버러지가 넓어지고 협업은 해야 하겠지만, 그렇다고 모든 개발자가 그렇게 수퍼개발자일리는 없고, 엄연하게 다른 역할이 존재 한다. 예를 들어, 테스트 엔지니어, 빌드엔지니어등.

단 여기서 Cross functional team이란, 한 팀내에서 서비스의 기획에서부터 운영 그리고 더 나아가서 영업등 해당 서비스에 관련된 모든 것 “ALL!!”을 할 수 있는 구조로 팀을 셋업 하라는 것이다.

     Widely Shared Metris 개인적으로 가장 중요하다고 생각하는 항목중의 하나인데, 팀 전체가 기준으로 삼을 수 있는 서비스에 대한 공통적인 지표 (Metric)이 필요하다. 서비스를 개발하고 개선했을 때, 이를 평가하고 현재의 서비스의 진행 상태 (성공 여부, 시스템의 안정성, 사용자의 반응 등)를 인지할 수 있는 기준이 필요하다는 것이다.

예를 들어, 일 방문자수, 평균 체류 시간, 가입자수와 같은 비즈니스 지표에서부터, CPU 사용률, 메모리 사용률, 응답 시간등 기술 지표등이 있다.

기존 개발에서는 요건 받아서 개발하고, 운영으로 던져버렸기 때문에, 사용자들이 서비스에 만족하는지 운영에는 문제가 없는지에 대한 피드백이 전혀 없었다. Metric을 팀 전체에 공유하고 꾸준하게 추적함으로써, 팀 전체가 서비스의 상태를 인지하고, 협업을 통해서 이에 대한 개선 작업을 진행할 수 있게 되는 것이다.

    대형 TV나 모니터등으로, 기본 서비스 및 시스템 운영 지표에 대해서는 사무실에 붙여 놓는 것도, 나쁘지 않다.

     Automating repetitive tasks 반복적인 작업을 툴을 이용해서 자동화 한다. 일반적으로 우리가 CI (Continuous Integration)이나 CD (Continuous Delivery)등을 이용해서 다루는 빌드, 배포, 테스트 자동화 들이 이에 속한다. 반복적인 작업의 자동화를 통해서 똑똑한 개발 자원들이 반복작업에 투여되는 시간을 줄여서 작업의 효율을 높이고 여기에 더해서 배포나 테스트에 관련된 시간을 줄여서 빠른 서비스 업데이트를 가능하게 하며, 마지막으로 이런 자동화 시스템 구축을 통해서 전체 시스템에 대한 이해도를 높일 수 있다.

     Post mortems 직역하자면 해부? 사후 검증 정도의 의미가 되는데, 장애나 이슈가 있을때, 처리 후에, 그 내용을 전체 팀과 공유해야 한다. 서비스를 운영하는 팀의 문제점은 이슈등에 대한 심각도가 얼마나 높은지를 인지하지 못하는 경우가 많다. 시스템이 정지되었을 때, 비즈니스 적으로 손실이 어떤지,얼마나 심각한 문제를 인지하고 궁극적으로는 원인을 파악함으로써 다음 부터는 같은 이슈가 다시 발생하지 않도록 할 수 있다.

     Regular release 마지막으로 정기 릴리즈이다. 시스템 릴리즈는 많은 협업이 필요한 작업이다. 개발도 끝내야 하고, 테스트, 배포 과정을 거쳐야 하고, 릴리즈가 끝나면 다음 릴리즈를 위한 기능 정의 등의 과정을 거쳐야 한다.  그래서 정기적으로 릴리즈 주기를 설정하면, 전체 협업을 하는 입장에서 언제 어떤 협업을 해야 할지도 명확해지고, 개발이 리듬(?)을 타게 된다.

첨언을 하자면, 짧은 주기의 정기 릴리즈를 통해서, 빠르게 서비스의 기능을 개선하고, 고객의 VoC를 반영해나갈 수 있다.

Devops 기반의 개발팀

Devops 기반의 서비스 팀은 End 2 End 서비스를 커버할 수 있어야 한다.

그리고 Devops는 개발과 운영을 포함한 팀 운영 방법론이라고 소개했었다. 그렇다고 기존 팀 모델에 개발과 운영만 합쳐 놓는다고 모든 문제가 해결 되는 것이 아니다. 다양한 Devops 기반의 팀 모델링이 있게지만, 몇 가지 레퍼런스를 소개하고자 한다.

영국 정부가 운영 하는 https://www.gov.uk/service-manual/the-team 에 역할이 잘 정리되어 있음. Scrum 방법론 기반이 아니라 익숙하지는 않지만, 유사한 팀 모델링. 100% 따라하기 보다는 레퍼런스. 개발뿐만 아니라 전체 비즈니스, 기획적인 면에서 많이 고려가 되어 있으며, 상세한 내용과, R&R, 그리고, Job Description까지 나와 있다. 

사실 디테일 자체는 다를 수 있지만 기본적으로 Devops 기반의 팀의 조직 구조는 대부분 유사하다.



전체 서비스를 관장하는 역할을 갖는 사람이 있다. Service Manager, Program Manager 보통 정의 하는데, 개발,운영뿐만 아니라 전체 서비스 기획, Stake holder등과의 Communication등 전체 프로젝트에 대한 전반적인 내용을 커버 한다.

Product manager가 중요한 역할인데, 서비스를 기획하고 요구 사항을 정의하며, 우선 순위를 메긴다. 기존의 개발 방식에서도 기획이 있었는데, 기존 기획은 요구 사항을 정의하고 개발에 넘기면 끝이었지만, 이러한 팀의 모델링 구조에서는 개발팀과 계속 협업하면서 모자른 요구 사항을 재정의 및 다듬어 나가고, 우선 순위를 끊임 없이 조정해 나간다.

UX Product manager와 아주 밀접한 관계에서, 서비스에 대한 UX 디자인을 프로토타입에서, 개발 단계까지 정의하고, 사용자의 피드백에 따라서, 끊임 없이 UX를 개선해 나간다.

그리고,실제 개발팀을 이끄는 Project Leader Scrum Manager가 있다. 일정관리, 개발 리소스 관리등을 담당한다. 또 전체 시스템에 구조와 틀을 잡는 아키텍트 역할이 있고, (아키텍트의 종류 - http://bcho.tistory.com/668 대규모 팀에서는 아키텍트도 역할을 나눌 필요가 있다.)

필요에 따라서 테스트 엔지니어를 별도로 두기도 하는데, 일반적인 기능 테스트 등은 개발자가 함께 테스트 케이스를 작성해서 자동화 해서 수행하는 경우가 많고, 경우에 따라서는 성능 테스트까지 함께 하는 경우가 있다. 성능 엔지니어링이 복잡한 경우에는 별도의 성능 테스트 엔지니어를 두는 경우도 있다.

빼먹기 쉬운 역할 중에 하나가 Contents Writer/Technical Writer인데, 서비스에 들어가는 컨텐츠에 대한 컨텐츠를 작성하고 리뷰등을 수행한다. 다국어 번역이나, 컨텐츠의 내용이 해당 서비스 국가에 문제가 없는지 까지 검증하는 역할을 한다. 일반적인 웹사이트에서는 웹 컨텐츠, 테크니컬 사이트의 경우에는 샘플 코드나, 가이드등의 작업을 한다.

마지막으로, 서비스 전략/user researcher라는 역할을 들 수 있는데, 이 역할은 Product manager보다 선행해서, 서비스나 제품이 나가야할 방향을 정의한다. 시장 상황을 분석하고, 수익 구조 및 비즈니스 모델을 정의하고, 주요 제품 로드맵을 정의한다. Product manager와 역할이 겹치는 부분이 있지만, Product managerdetail 한 서비스에 대한 기획은 서비스 자체 관점에서 한다면, user researcher는 조금 더 넓은 범위에서 제품의 방향과 비즈니스 및 수익 관점에서 서비스를 바라본다.

Devops 기반의 팀의 개발 싸이클

그렇다면 Devops 기반의 개발팀의 서비스 개발 싸이클은 어떻게 될까?

영국 정부가 운영하는 사이트 https://www.gov.uk/service-manual/the-team 의 가이드를 참고해 보면 다음과 같은 시나리오로 개발을 진행하도록 되어 있다.

     사용자의 needs 분석. VoC 수집

     사용자 스토리 작성 (요구 사항 작성)

     사용자 스토리에 대한 scope 정의 및 우선순위 지정

     Stakeholder에 대한 리포팅 및 관리 (내부 영업, 보고 등)

     다른 프로젝트와 연관성(dependency) 관리

     필요의 경우 솔루션 (오픈소스 또는 상용) 평가 및 도입

     개발!! (디자인, 빌드,테스트, 데모.-iterative way)

     테스팅. 실 사용자 대상 테스팅 포함

     서버에 배포

     Security 관리, Compliance 관리 (개인 정보 보호, 국가별 법적 사항 확인등)

     서비스 운영, 모니터링.

     대 고객 지원 (Customer Support) 추가 하였음

이런 프로세스를 한마디로 정리 해보면 결국 Devops 기반의 개발팀의 특징은, 한 팀내에서 모든 개발,테스트,배포 운영이 이루어진다는 것이고, 가장 중요한 것은, 운영을 통해서 사용자의 피드백을 접수하고, 이것이 새로운 요구 사항으로 연결되는데, 이 싸이클이 매우 빠르며 연속적이고 서로 연결 되어 있다 라는 것이다.



참고 : 개발팀의 성숙도별 개발 모델 http://bcho.tistory.com/721

조금 더 정리해서 말하자면 기존 개발팀은 기획팀이 요구사항을 개발팀에 던지고, 개발팀은 개발 내용을 운영에 던지는, waterfall 모델 처럼, 각 팀이 개발 단계별로 자기 역할을 한 후에, 다음 단계로 던지고 잊어 버리는 (fire & forget)  형태라면, Devops 형태의 개발팀은, 던지는 것이 아니라 과정 내내 같이 수행한다. 요구 사항을 개발팀에 넘겨도, 개발팀과 계속 협의를 하면서 요구 사항을 구체화 하고, 개선하며, 개발중에 운영인원과 같이 협의 하면서 최적의 구조를 논의 하면서 개발이 진행된다.

Devops 팀의 개발자의 필요 역량

그럼 Devops 엔지니어가 되고 싶다면? Puppet의 포스팅을 [5]보면 Devops engineer가 가져야 할 역량에 대해서 잘 설명이 되어 있다.

기본적인 소양으로는

Ÿ   코딩능력은 필수 이며

Devops 엔지니어는 기본적으로 개발자를 기본으로 하고 있기 때문에, 개발을 위한 기본적인 코딩 능력. 만약에 운영이나 시스템쪽에 치우친 엔지니어라면 자동화를 만들 수 있는 스크립트 작성 능력등은 필수이다.

Ÿ   다른 사람과 잘 협업하고 커뮤니케이션할 수 있는 능력

Devops는 앞서 설명한바와 같이 큰 틀에서 협업 문화이다. 시작 자체가 개발과 운영간의 소통 문제를 해결하고자 한것이기 때문에, 다른 팀원의 의견을 존중하고 문제를 함께 해결해나갈 수 있는 오픈 마인드 기반의 커뮤니케이션 능력이 매우 중요하다.

Ÿ   그리고 프로세스를 이해하고 때로는 그 프로세스를 재 정의할 수 있는 능력

마지막으로, Devops는 언뜻 보기에는 정형화된 프로세스가 없어 보일 수 있지만, 테스트 자동화, 배포, 그리고 요구 사항에 대한 수집 및 정의등은 모두 프로세스이며, 해당 팀의 모델이나 서비스의 성격에 따라서 만들어나가야 한다. 그래서, 프로세스를 이해하고 준수하며, 같이 만들어나갈 수 있는 능력을 가져야 한다.

필자의 경험상 위의 3가지는 정말로 중요한 요소인데, 많이 놓치는 부분같다. 특히 프로세스 부분에 대해서는 다들 제각각의 프로세스나 자기 사상으로 프로젝트를 진행해서 생기는 문제가 많아 보인다. 사실 프로세스를 지켜 나가는 건 어떻게 보면 귀찮은 일일 수 도 있지만, 같이 일하는 환경이라면 최소한의 기준은 필요하다고 본다.

이런 기본적인 소양 이외에, 몇가지 역량을 예로 들었다.

Ÿ   오픈소스 제품과 툴에 대한 이해

Ÿ   코딩 능력

Ÿ   인프라 시스템에 대한 이해와 시스템 운영 경험

ŸŸ   자동화된 툴 (컴파일,테스트,배포)에 대한 이해

   비지니스에 대한 이해

   오픈 마인드, 커뮤니케이션 및 협업 능력

그리고, Devops 팀의 엔지니어는 부족한 부분을 메꾸기 위해서 공부는 필수이다. 그 보다 더 중요한 것은 경험이다.. 운영은 직접 겪어 보기전에는 알 수 없다. 그리고 오픈 마인드 기반으로 커뮤니케이션을 해가면서 문제를 풀고 협업하는 능력은 책이 아니라 직접 겪어야 얻을 수 있는 능력이다. 

요즘 같이 비지니스 변화가 심하고 멀티롤 개발자가 필요한 시점에 Devops 를 수행할 수 있는 능력의 개발자의 가치는 점점 높아지고 있다. Mashable에 따르면 가장 빠르게 성장하고 있는 IT Job 중의 하나가 Devops Engineer이다. http://mashable.com/2013/11/13/fastest-growing-jobs/ 

Devops팀을 셋업 할때 주의할점

Devops 팀에 대한 확실한 정의나 가이드는 없다. 그럼에도 불구 하고, 여러 블로그나 몇몇 서적등에서 Devops의 개념에 대해 설명할때, Devops 팀 셋업시 주의할점을 몇가지 드는 것이 있다.

첫번째가 Devops 팀을 만들지 말것.
Devops 팀은 개발과 운영을 합쳐서 같이 운영하는 것이지 이를 위해서 개발과 운영을 모두 할 수 있는 팀을 새로 만들어서 개발팀과 운영팀 내에 배치하게 되면, 오히려 추가적인 burden을 더 넣는 것이다. Devops는 개발과 운영을 하나의 팀으로 합쳐서, 커뮤니케이션에서 오는 부하를 줄이기 위함임을 잊지 말자

Devops 엔지니어를 채용하지 말아라
여기에 대해서는 의견이 분분한 면이 있는데, 내 경우에는 이 의견에 어느정도 공감한다. Devops 엔지니어를 채용해서 팀을 Devops화 시킨다... 이건 한마디로 돈으로 Devops를 사겠다. 즉 돈으로 "문화"를 사겠다는 의미인데, Devops 엔지니어는 Devops 팀에서 일하는 하나의 사람일 뿐이다 Devops를 하려면 전체 조직 문화를 변경 시켜야 한다. 이는 한 두사람의 엔지니어를 채용한다고 되는 일이 아니라. 경영자가 이에 대한 확실한 의지를 가지고 있을때, Devops에 대해서 외부로 부터 가이드나 도움은 받을 수 있겠지만, 어떻게 문화를 바꿀 수 있는지에 대해서 접근하고, 조직 내부에서 부터의 문화 변경을 시도하는 것이 좋다. 경영자가 Devops에 대한 이해가 없고, 단기간내에 성과를 내려고 한다면, 글쎄.. 개인적인 생각으로는 성공하기 쉽지 않으리라 본다. 이미 애자일 방법론을 적용할때, 경영자의 이해와 강력한 스폰서 쉽 그리고 문화의 변경을 기다려 주는 인내가 없는 경우 도입에 실패하는 경우를 숱하게 봤다. 이런 문화적인 변화는 수동적으로 시킨다고 되는것이 아니다. 조직 전체에 공감대가 형성이 되고, 능동적인 자세 아래서, 변화가 가능한 것이다.
재미있는 사례가 있는데, 쿠팡(소셜커머스 업체)가 많은 개발자가 있음에도 불구하고, 1년여간에 걸쳐서 애자일 방법론을 성공적으로 도입한 사례이다. http://blog.naver.com/coupang1104/140200775250
Devops는 아니지만, 문화를 변경한다는 관점에서, 주목해볼만한 사례이다.

Devops 팀에서는 개발자가 개발 및 운영을 다한다? 아니면 별도의 운영자가 있다?
사실 Devops에 대한 개념을 잡는 것중에서 가장 헷갈렸던 부분이 부분인데, 개발팀과 운영팀을 합쳐서 하나의 팀을 만들었다고 하자. 그러면. 개발자가 개발 및 운영을 다하는 것인가? 아니면 그 안에서도 개발과 운영롤을 나눠야 하는 것인가?
사실 내 대답은 "그때 그때 달라요"이다. 팀내에 개발하는 사람이 운영을 다할 수 있으면, 개발자가 운영까지 하는 모델로 가는 것이고, 기존 팀이 개발과 운영으로 갈려 있었다면, 팀내에서도 개발롤과 운영롤로 나누되, 둘간의 협업을 잘 만들어내는 것이 관건이다.
사실 결과적으로는 개발역할과 운영 역할이 팀 내에서도 나눠 질 수 밖에 없다고 본다. 개발자의 역량 한계상, 모든 것을 다할 수는 없고, 각자 선호하는 분야가 있기 때문이다.

Devops의 경우 소규모 스타트업 기업에 유리. 조직이 큰 경우 인내심을 가지고 차근차근 적용해 나가야
소규모 스타트업의 경우 개발과 운영팀을 분리할 규모도 안되서 각각의 엔지니어가 여러 역할을 동시 수행해야 하고, 빠른 개발 주기를 가지고, 개발 문화를 초반 부터 만들어나가야 하는 단계이기 때문에, 매우 적절하다고 볼 수 있다. 그러나 이미 크기가 커버린 일반적인 개발팀의 경우에는 전체 문화를 바꾸는 것 자체가 모험이다. 단기적인 전략보다는 장기적인 전략으로 Devops라는 문화 변경 프로젝트를 바라봐야 할것이며, 또한 그 변화의 기간동안 인내심 있게 이를 지원해줄 조직의 경영층이 필요하다.


한마디로 Devops란 개발과 운영을 합쳐서 하나의 조직내에서 서비스를 독립적으로 개발 및 운영할 수 있는 협업 체계이자 개발 문화라고 정의할 수 있다. 

참고 자료들

l  Atlassian Devops 관련 자료 - https://www.atlassian.com/devops/

l  What is Devops engineer? - http://puppetlabs.com/blog/what-is-a-devops-engineer

l  What is Devops ? http://dev2ops.org/2010/02/what-is-devops/ (개념 정리가 제일 잘되어 있음)

l  Jez Humble의 Continuous Delivery를 번역한 사이트 -   http://cdkr.egloos.com/




기존 개발 체계의 문제점

전통적인 개발 운영 체계

일반적인 개발 운영 체계는 다음과 같다. 개발팀에 의해서 개발이 끝나면, 시스템은 테스트를 거쳐서 운영팀에 이관되고, 운영팀은 해당 시스템을 배포 관리 운영한다.



일단 이관된 시스템은, 개발팀이 일체 관여하지 않고, 운영팀에 의해서 현상 유지 된다.


문제점 1. 누구의 잘못인가? 불행의 시작

시스템을 운영하다 보면, 반드시 장애가 생기기 마련인데, 문제는 여기부터 시작된다. 개발은 애플리케이션 있지만, 아랫단의 인프라 시스템 있는 능력이 없다. 반대로 운영팀은 인프라 시스템 알지만, “애플리케이션자체에 대해서는 모른다.

그러다 보니, 서로 자기 분야의 문제가 아니라고 하면서 서로 책임 미루기를 하게 되고, 문제 해결은 지연된다. 이러한 책임 미루기에 대해서 “Fingerpointyness”라는 말로 표현한 것이 있는데, 정확하게, 누가 어떤 문제를 해결해야 하는지 정의 되지 않은 상황에서, 협업이 없어지고 문제 해결이 엉뚱한 방향으로 가는 현상이다.


[1]

    Freaking out & find fault 단계 (문제 발견)

자아. 문제가 발생했다. 문제의 내용을 먼저 파악한다. 이때 협업은 없다. 단지 자기 분야에서 문제가 어떤 것인지, 한정된 지식으로 현상 자체를 인지하는 수준이 된다. 근본적인 문제에 대한 원인 파악보다는 대충 파악하는 단계 정도의 수준이 된다. 단계에서 누가 문제를 파악할지에 대한 owner ship 자체가 정해지지 않는다.

    Blaming Covering ass 단계 (욕하기)

그러다가, 어느 정도 문제의 현상 (정확한 원인이 아니라) 정도가 파악되면, 서로 미루기를 한다. “애플리케이션 문제네..”, “데이터 베이스 문제네..” 식으로, 정확한 원인 파악 없이 자기 문제가 아닌 처럼, 다른 쪽으로 미루기를 시작하면서, 상대편을 욕하는 단계가 된다. “데이터 베이스 구성을 그렇게 하니까는 그렇지.. 인덱스는 아냐?”. 내지는 애플리케이션 구조에 맞춰서 배포는 한거야?” 이러면서 문제의 근본적인 원인은 해결되지 않고 시간은 계속 간다.

    Whining, Hiding. Hurt Ego 단계 ( 상처 입기)

계속 해서 문제를 서로에게 넘기다 보면, 문제를 숨기거나 상대방을 헐뜯거나 하면서 결국은 서로 상처를 입게 되고, 점점 커뮤니케이션은 없어지고 관계는 악화되어 간다.

    Figuring it out (문제 원인 분석)

결국 문제를 해결해야 하는 시간이 가까워 오면, 문제를 풀긴 풀어야 하니,  어떻게든지 스스로 서로 모여서 문제를 같이 보게 되거나, 상위 메니져를 통해서 강제적으로 같이 모여서 문제에 대한 원인 분석을 해서 결국은 원인을 파악하게 된다.

    Fixing things (문제 해결)

그리고, 결과적으로 원인 파악 문제가 해결된다.

아주 전형적인 개발과 운영간의 장애 처리 프로세스이다. 그나마 똑똑한 팀장을 가지고 있는 조직은 장애나 문제가 발생했을때, “모두 모이세요.”해서 초기부터 문제를 같이 보고 해결하거나, 개발팀이나 운영팀 자체가 상대방의 분야를 있는 능력을 갖춰서 문제를 해결하는 경우가 많다. 예를 들어 운영팀이 애플리케이션에 대한 장애 대응 능력을 갖거나, 개발자가 OS, 데이타베이스 또는 미들웨어등에 대한 인프라 운영 능력을 갖는 경우이다.


문제점 2. 운영 이슈에 대한 전달 문제

다른 문제점을 살펴보자, 앞에서도 언급 했듯이, 개발은 운영으로 이관 후에, 서비스에 대해서 이상 관심을 갖지 않는다. 그리고, 고객과의 접점도 거의 없다. 그러나 운영은 (단순히 시스템을 운영하는 시스템 운영만이 아닌 실제 서비스 운영을 포함) 계속 해서 사용자와 interaction 하고, 사용자로부터 끊임 없이 VOC (Voice Of Customer) 받는다.



서비스를 운영하는 입장에서, 사용자의 의견을 들어서 서비스를 개선하고 싶은 것은 당연한 이치이고, 여러 VOC 모아서 개발팀에 서비스 개선 요청을 하지만, 이미 개발과 운영은 멀어져있는 상태이고, 운영은 명시적으로 개발팀에 요구 사항을 정의할 있는 권한이 없기 때문에 (이러한 권한은 일반적으로 서비스 기획팀에서 갖는다). 이러한 개선 요청 요구 사항은 개발팀 입장에서는 추가적인 일이 되고, 개발팀은 이러한 신규 요구 사항에 대해서 저항하거나 또는 거절하게 된다.


문제점 3. 변경 요건

서비스가 운영 배포된 후에도, 비즈니스 (기획팀) 의해서, 계속 해서 서비스에 대한 신규 요구 사항은 나오게 되고, 새로운 변경 요건은 신규 개발과, 테스트 배포 그리고 지속적인 운영을 요구 하게 된다.



그런데, 근래의 서비스들의 경우에는 빠른 비즈니스 환경 변화에 따라가기 위해서 많은 변경 요구하게 되고, 이는 필연적으로 잦은 변경 배포를 요구 하게 된다. 제대로 많은 변경으로 인하여 제대로 테스트 시간을 거치지 못한 애플리케이션의 경우에는 잦은 장애를 유발한다.

이런 배경으로 인해서 운영팀은 잦은 배포를 꺼려하게 되고, 조금 전통적이고 형식적인 관점에서 주기적인 릴리즈와 테스트를 요구하게 된다. 애플리케이션단에 문제가 있다 하더라도 긴급 배포가 어려운 경우가 많고, 긴급 배포를 했다 하더라도, 개발팀의 실수를 뒷처리 하는 입장으로 인식하기 때문에, 계속 해서 개발팀과 운영팀의 관계는 악화 되어 간다.


그러면 해결책은?

그렇다면 구조적으로 이렇게 개와 고양이처럼 앙숙일 밖에 없는 개발팀과 운영팀과의 관계는 어떻게 해결 것이며, 문제로 인해서 발생하는

         서비스 요구 사항의 신속한 반영의 문제

         고객의 요구 사항에 민감한 소프트웨어 개발

문제들은 어떻게 극복할 있을까?


Solution 1. 협업 하자  - 기획과 개발을 합치자.

답은 간단하다. 기획,개발,운영 모두 사이좋게 지내면 된다. 어떻게 사이좋게? 서로 대화도 많이하고 팀웍을 다지면 된다. 이런 활동의 일환으로 시작된 것이 애자일 방법이다. 기획팀과 개발팀을 하나의 팀으로 합쳐서, 요구 사항 변화에 빠르게 반응할 있는 구조로 바꾸고, Iterative 개발(반복적), Short Release 이용한 잦은 릴리즈를 통해서 비즈니스의 요구 사항을 신속하게 반영하고, 변화에 대응할 있는 구조를 갖추는 것이다.


Solution 2. 개발과 운영을 합쳐 버리자. (Devops)

첫번째 솔루션은 분명히 좋은 방법이긴 하지만, 조금 최적화 시킬 수는 없을까? 애자일 방법론을 적용해도 여전히 운영과 개발은 앙숙인 관계이다. 그렇다면? 기획과 개발을 합쳐 버렸듯이,


좋은 개념을 이제야?

간단하게 개발과 운영을 합쳐 버리면 될텐데, 이걸 이제서야 할까? 결론부터 이야기 하면, 예전에는 어려웠다. 개발과 운영은 영역 자체가 매우 상이하고, 요구 되는 기술 능력도 많이 차이가 나기 때문에, 일반적인 엔지니어가 양쪽을 모두 커버하기가 어려웠다.

또한 기술 자체에 대한 습득 경로가 교육이나 서적으로 제한 되어 있었고, 인터넷을 통해서 요즘 처럼 이렇게 쉽게 정보를 얻기가 어려웠다.


인터넷의 발전

인터넷은 더욱더 발전해서, 내가 필요한 자료는 인터넷에서 찾을 있을뿐만 아니라, 오픈소스 커뮤니티에서 남들이 만든 코드를 보고 배울 있고, YouTube에서 강의를 들을 있으며, Slideshare에서 요약된 PPT 있다. 지식을 습득할 있는 채널이 다양해지고, 쉬워졌다.


오픈 소스의 발전

인터넷이 발전되면서, IT 흐름이 크게 바뀐 것중에 하나는 이상 오라클이나 IBM 같은 대형 벤더 주도의 기술이 아니라 페이스북이나 구글과 같은 거대 B2C 서비스가 IT 흐름을 이끌기 시작했고, 이러한 업체들이 오픈소스를 적극적으로 후원 장려하기 시작했다. 오픈 소스를 통해서 전세계의 개발자들과 함께 이야기를 , 일을 있고 오픈 소스를 잘하면 이런 구글이나 페이스북과 같은 좋은 회사에도 취직할 있다. 그래서 개발자들이 오라클이나 SAP 같은 엔터프라이즈 제품을 공부하지 않고, 오픈소스를 개발하면서 논다(enjoy~)”


오픈소스 Stitching

이렇게 오픈소스가 발전하다 보니, 요즘 개발은 하나의 프로그램 언어로 하나부터 열까지 모두 개발하는 것이 아니라, 여러 오픈소스들을 모아다가 합쳐서, 하나의 서비스를 만드는 형태로 바뀌고 있다

이제 모두 내가 개발할 필요도 없이 찾아서 조합 하면 되고, 문제가 있는 오픈소스는 내가 직접 고치거나, 오픈 소스 개발자들에게 부탁해서 수정을 할 수 있다. 솔루션에 대한 선택 기회가 넓어지고,  코드 자체 개발 뿐만 아니라, 효율적으로 오픈소스 솔루션을 조합 및 구현하는 개발 형태의 중요성이 높아지고 있다.


좋은 도구들

오픈소스의 발전으로 이루어진 혜택중의 하나가, 좋은 툴이 많아 졌다는 것이다. 개발에 관련된 뿐만 아니라, 빌드,배포에 대한 툴과, 모니터링에 대한 툴도 많아졌기 때문에, 운영 업무에 해당 하는 이런 부분을 상당 부분 자동화를 있다.


클라우드의 등장

클라우드 컴퓨팅의 가장 특징 중의 하나는 사용자가 인프라 (서버 설치, 네트워크 케이블 구성) 구성할 필요가 없이, 간단하게 책상 앞에 앉아서 웹사이트를 몇번 클릭 하는 것만으로 지구 반대편의 데이터 센터에 서버, 스토리지 구성, 네트워크 구성이 가능하게 되었다는 것이다.

이상 개발자는 새로운 기술을 익히는 , 책을 뒤져가면서, 새로운 교육을 들어가면서 지식을습득할 필요가 없다. Googling 하면 개발에 대해 필요한 자료를 얻을 있다.

개발을 할때는 필요한 모듈을 오픈 소스를 조합해서 만들 있으며, 여러가지 좋은 도구들을 통해서 빌드나 배포등을 손쉽게 자동화할 있으며, 클라우드를 통해서 개발자도 네트워크, 서버등에 대한 설정들을 있다. 인프라에 대한 지식이 부족하면 이것 또한 인터넷을 검색하면 된다.  결과적으로 개발자가 있는 영역이 더욱 넓어졌다.

바꿔 말하면, 인프라에 대한 전문 지식이 없이도, 인터넷과 오픈 소스 그리고 클라우드의 도움을 받아서, “운영 겸업 있는 환경이 마련 되었다는 것이다.

2편 글 링크 - http://bcho.tistory.com/817


오랜만의 포스팅입니다. 그간 많이 바뻤습니다.

요즘 시스템 운영쪽에 관심이 많아서 Devops (Development + Operation)쪽을 틈틈이 보고 있습니다. 오늘은 조직의 성숙도별 개발 모델과 함께, CD (Continuous Delivery)와 Devops에 대해서 설명해보고자 합니다.



회사의 규모나 성숙도에 따라서 개발 모델을 크게 다음과 같이 3단계로 나눠볼 수 있습니다.


1. 스타트업


소규모에 처음 서비스 개발을 시작한 스타트업 기업 같은 경우에는 일단 모든 의사 결정이 빠르다. 아이디어가 나오면 별도의 승인이나 분석 없이 바로 개발하고, 개발이 끝나면 바로 배포 한다. 규모가 작고 모든 의사 결정이 팀내에서 이루어지기 때문에 매우 빠르다. 그리고 인력이 적기 때문에, 분석/설계/개발 및 운영이 같은 그룹에서 이루어진다.


2. 성숙된 개발 조직

어느정도 조직이 성숙되고, 인원이 많아지고 이익에 대해서 고민을 하게 되면, 조금더 체계화된 개발 프로세스를 원하게 된다.

한정된 예산으로 서비스를 개발하게 되며, 인원이 많아짐으로써 품질 저하를 막기 위해서 역할이 세분화 되고 체계화 된다.




아마 대부분의 일반적인 서비스 개발 이나 시스템 개발 기업들은 이러한 프로세스를 따를 것이다. 아이디어가 나오면, 발표하고 경영진을 설득하여 예산을 정하고, 요구 사항 분석을 통해서 범위를 정한후, 개발/테스트/수정을 한후, 모든 테스트를 통과하면 릴리즈 일정을 결정하고 산출물을 정리한후, 운영팀으로 이행한다.


체계화 되어 있기는 하지만, 앞서 설명한,Start up에 비해서는 전체적인 프로세스가 느리고, 운영으로 이관후, 자잘한 Fix나 Enhancement가 어렵다. 그리고, 새로운 기능이나 컴포넌트를 개발하려면, 새로운 프로젝트를 시작해서 위와 같은 전과정을 다시금 거쳐야 한다.


3. CD와 Devops기반의 개발 모델

요즘 같이 새로운 서비스가 많이 나오는 시절에, 저런형태의 개발 프로세스는 빠른 기능 추가등이 불가능하고, 운영중의 피드백을 받기 어려워서 SNS와 같은 서비스에는 적절하지가 않다. 

그래서 CD (Continuous Delivery)와 Devops라는 개념을 사용하는데


CD

CD는 Continuous Delivery의 약어로

운영 시스템에 계속해서 Fix나 새로운 기능을 지속적으로 Release를 하는 개념이다.

쉽게 예를 들어보면, 프로젝트 기간이 끝나면 릴리즈를 하는게 아니라, 매일매일 새로운 FIX나 기능이 추가되면 거의 매일 릴리즈를 하는 개념으로 보면 된다.

Face Book의 경우 이런식으로 매일 개발자가 새로운 기능을 운영 환경에 반영 및 추가 하는 것으로 알고 있다.


Devops

Devops는 Netflix에서 주로 시작된 개념으로 개발팀과 운영팀을 하나로 묶어서, 커뮤니케이션에서 오는 장애를 해소하고 빠른 서비스 개발과 반영을 하고자 함에 있다.

보통 개발팀과 운영팀이 나눠져 있는 것이 전통적인 모델인데, 이 경우에는 운영중에 고객의 요구 사항등이 개발쪽에 잘 전달되지 않고, 매일 서비스를 운영하면서 개선 사항이 있더라도 개발팀에 전달되기가 어려운 경우가 많다. 반대로, 개발쪽에서 무엇인가를 수정하면 수정 내용이 운영쪽에 제대로 전달되지 않아서 배포 실수등을 유발하여 시스템 장애를 유발하는 경우가 많다

그래서 Devops는 두팀을 하나로 합침으로써, 서로간의 의사소통을 빠르게 하고, 개발자가 직접 운영환경을 컨트롤함으로써 빠른 피드백을 받고, 빠른 반영을 통해서 서비스의 신속성을 향상 시키는 모델이다.


보통 이런 개념을 채용한 개발 모델은 다음과 같다.


위의 그림은 TDD를 채용한 그림인데, 먼저 테스트 계획서를 작성한후, 개발 및 테스트를 수행한후, 운영환경에 배포하고, 모니터링을 한다. 그리고 바로 신규 기능에 대한 피드백이나 효과를 모니터링해서 다시금 요구 사항을 정의하는 형태를 따른다

이렇게 Devops와 CD를 적용하기 위해서 중요한것은 자동화된 툴셋이 매우 중요하다.

개발 반영시 자동으로 꼼꼼하게 테스트를 할 수 있어야, 운영시 발생하는 장애를 방지할 수 있으며, 위의 전체 프로세스의 주체는 개발자가 되기 때문에, 복잡한 인프라나 미들웨어에 대한 배포를 자동으로 할 수 있어야 한다.

물론 자동화 툴셋은 어디까지나 구현 관점이다. 더 중요한것은 문화적인 차이점을 이해해야 하고, 프로세스의 변화를 인지하고 바꿔야 한다.

기존의 조직처럼 운영과 개발이 나눠져 있는 경우 조직을 합친다는 것은 기존에 가지고 있는 프로세스,  조직 구조를 모두 바꿔야 하는 것을 의미하며, 아울러서 기술셋도 모두 바꿔야 한다.

아울러 예산 집행 방식에 있어서도 기존에는 개발비용과 운영 비용을 나눠서 미리 잡아놓고 집행했기 때문에 초기 투자비와 운영비용(Running Cost또는 Opex), Devops 방식은 있는 인원들이 쭈욱 업그레이드와 운영을 계속해서 나가는 방식이라서 초기 투자비용보다는 운영비용(Running Cost)에 대한 부분이 커진다.


Devops나 CD의 경우에는 분명히 서비스 관점에서 가지는 이득은 매우 많지만, 변화의 폭이 기존 개발 방식에 비해서 매우 크기 때문에, 함부로 달려들 것은 아니라고 본다. 

그러나 스타트 업에서 규모가 커질 경우 위에서 언급한 정형화된 프로세스보다는 CD/Devops기반의 개발 프로세스로 비교적 쉽게 이동할 수 있고 얻는 이득도 많다.

기존의 대기업이나 SI기업의 경우에는 Devops 모델을 도입하기에는 변경되어야 하는 부분이 매우 많기 때문에, 매우 신중한 접근이 요구 된다.


Ganglia 아키텍쳐

클라우드 컴퓨팅 & NoSQL/운영 & Devops | 2012.12.03 12:44 | Posted by 조대협

RRD 기반의 Monitoring 시스템 Ganglia



주요 특징

- RRD 기반의 스토리지

- 웹 인터페이스 제공

- 클러스터링을 통한 scale out