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


Archive»


 
 

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 #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과 동일)를 지원하는데, 그렇다면, 클라우드에서 제공하는 전용 솔루션을 쓰는 것이 좋은가? 아니면 오픈소스나 벤더에 종속적이지 않은 솔루션을 사용하는 것이 좋은가

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


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




피닉스 패턴의 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 타입을 만드는 방법을 알아보도록 하겠다.


Continuous Deployment 
(Auto Deployment)


빌드와 테스트까지 자동화 했으면 그 다음 문제는 배포이다.

수동으로 배포하는 경우 한 두개의 서버라면 별 걱정이 없겠지만, 개발,테스트,운영 환경과 같이 여러 환경에 또한 각 환경에 수십대의 서버에 배포를 해야 한다면, 문제는 달라진다. 그래서 요즘에서 CI에 배포의 개념을 더한 CD (Continuous Delivery 또는 Continuous Deployment)라는 개념이 유행하는데, 이는 빌드가 완료된 후, 배포까지 자동화 하는 방법이다.



이런 배포를 지원하는 도구는 여러가지 타입이 있다.

   특정 솔루션에 종속적인 도구

Tomcat이나 WebLogic 같은 WAS의 경우 각 제품에 특화된 배포 도구를 가지고 있다. Tomcat의 경우 Tomcat Client Deployer (http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#Deploying using the Client Deployer Package ) 와 같은 도구가 있는데, Remote에서 war 파일을 배포해줄 수 있는 도구 이다.

이러한 도구들의 특징은 해당 솔루션에 최적화가 되어 있기 때문에, RunTime Deploy나 기타 해당 솔루션에 특화된 기능을 활용할 수 있기 때문에, 안정적인 배포가 가능하다는 장점을 가지고 있다.

그러나 반대로 솔루션에 관련된 애플리케이션 파일만 배포할 수 있다는 단점을 가지고 있다. 무슨 이야기인가 하면, war 파일 이외에, 다른 디렉토리에 configuration 파일을 배포하고 싶을 경우, 이런 파일들은 배포가 불가능하다는 것이다. 또한 여러개의 인스턴스에 동시 배포를 하고 싶을 때, 인스턴스들이 제품에서 제공하는 클러스터링 기능등을 사용하고 있지 않을 경우, 각 인스턴스들을 일일이 각각 배포해야 하는 단점이 있다. 쉽게 말해서 매우 제품에 종속적이라는 것이다.

   Configuration Management

다음으로는 Puppet이나 Chef와 같은 Configuration Management 도구 기반의 배포 방식이 있다. 이러한 도구들은 원래 태생이 Deployment보다는 초기 솔루션을 설치하거나, 다수의 서버나 솔루션에 대한 Configuration 정보를 중앙 관리하기 위해서이다. 이에 비해서 Deploy 과정은 대부분 파일을 복사하고 서버를 restart 시키는 과정 정도의 단순 작업이기 때문에, 만약에 이러한 Configuration Management 인프라를 갖추고 있거나, 또는 배포 과정이 솔루션의 설정을 포함하여 매우 복잡한 경우 일때는 매우 효율적으로 사용될 수 있으나, 반대로 이러한 인프라가 없는 상태에서 단순한 배포만하고자 할 경우에는 오히려 배보다 배꼽이 커질 수 도 있다.

   Remote Shell 기반의 도구

마지막으로, Remote Shell 기반의 배포 도구가 있다. SSH RSH과 같은 명령을 툴로 실행시켜 주는 도구 인데, 파일 복사에서 부터 커맨드 라인에서 입력하는 명령들을 원격으로 실행시켜 준다.

솔루션에 종속적이지 않으며 또한 자유도가 높으며 사용이 매우 편리하다.

Python 으로 된 도구로는 Python Fabric이라는 도구가 있고, Ruby쪽에서는 Capistrano라는 도구가 있다.

Case Study

필자의 경우 클라우드 프로젝트 이전에만 해도, 환경 자체가 그리 크지 않았기 때문에, 웹로직이나 Tomcat의배포 툴을 사용해서 배포를 진행했었다. 클라우드 환경 기반에서 프로젝트를 진행하고 또한 진행하는 프로젝트의 규모가 커짐에 따라서 이러한 배포 자동화가 꼭 필요하게 되었는데, 이 배포는 Configuration Deployment 두 가지로 나눠서 생각해볼 수 있다.

애플리케이션을 배포하기 전에 먼저 OS Tomcat과 같은 솔루션을 설치 하는 Configuration, 그 다음이 이 환경 위에 애플리케이션을 배포하는 Deployment이다.

Configuration의 경우에는 Puppet이나 Chef를 도입하고 싶었으나, 팀의 규모와 시간 관계상 도입이 어려웠고, 환경의 복잡도가 낮아서 별도의 Configuration management 도구는 도입하지 않기로 결정하였다.

대신 OS Tomcat Pre-install된 표준 VM 이미지를 만들어 놓고, 배포가 필요할때 마다 이 이미지를 Loading한 후에, 애플리케이션을 Deployment 하는 형태를 사용하였다.

이 방식은 표준 이미지를 만들어 놓고 계속 재 사용하기 때문에, 관리가 쉽지만 반대로 Configuration을 변경하고자 할 때, 이미 배포된 이미지들에 대한 Configuration을 일일이 다시 변경해야 하는 단점이 있다. (어느 정도 규모가 되면 Configuration Management 도구로 넘어가는 것이 좋은듯 하다.)

Fabric을 이용한 배포

그러면 Fabric을 이용한 Tomcat 애플리케이션에 대한 간단한 배포 시나리오를 살펴보도록 하자.

구성은 아래와 같다. Load Balancer 아래에 N개의 Tomcat 인스턴스들이 연결되어 있는 구조 이고, 배포는 다음과 같은 순서를 따르도록 한다.

   먼저 배포하고자 하는 Tomcat 인스턴스를 Load Balancer에서 제외한다.

   다음으로 배포하고자 하는 인스턴스를 Stop한다.

   배포하고자 하는 war 파일을 해당 Tomcat 인스턴스에 복사한다.

   그리고 해당 Tomcat 인스턴스를 리스타트한다.

   위의 1)~4) 과정을 다른 인스턴스에도 반복한다.



이 배포 방식은 간단하기는 하지만, 하나의 서비스내에서 배포 과정중에, 배포가 완료된 인스턴스와 배포 예정인 인스턴스에 애플리케이션이 다르기 때문에, 애플리케이션 변경이 많은 경우에는 적용하기가 어렵다 . 대규모 변경이 있는 경우에는 전체 클러스터를 내렸다가 전체 배포 후 서비스를 다시 시작하는 방식을 사용해야 하는데 이 경우에는 배포 중에 서비스에 대한 순간적인 정지가 발생할 수 있다.

무정지 배포 아키텍쳐

이런 문제를 해결 하기 위해서 일부 자바 기반의 application server의 경우 runtime redeployment (시스템을 운영중에, 정지없이 프로그램을 변경하는 행위로, 일부 자바 기반의 application server에서는 WAR와 같은 웹모듈이나, EJB 같은 모듈을 시스템을 무정지 상태로 재 배포 할 수 있는 기능을 제공한다.) 를 제공하는 제품들이 많다. redeployment 의 원리는 새로운 application load하고, classloader reload하는 형식인데, classloader reload이 위험도가 높은 작업이기도 하고, application을 작성할때, redeploy를 고려하지 않은 경우 정상적으로 runtime redeploy가 되지 않는 경우가 많다. 가장 확실한 redeploy 기법은 application server를 정지시킨후, 재배포한후에 restart하는 것이 가장 안정적이다. 이렇게 restart기반으로 redeploy를 할때, 시스템을 정지 상태를 최소화는 구조를 무정지 배포 아키텍쳐라고 하는데, 구조는 다음과 같다.




application server를 두개의 클러스터 그룹으로 나눈후, 각 클러스터 앞에 reverse proxy를 각각 배치 시킨다. 그리고 reverse proxy 앞에는 L4 스위치를 둬서 각 클러스터로 load balancing을 할 수 있도록 한다.

배포를 할 때는 Cluster A 앞에 있는 reverse proxy를 정지 시킨다. 이렇게 하면, 앞단의 L4 로드 밸런서에서 Cluster A request를 보내지는 않으나, Cluster A 자체는 살아 있다. 그 후에 Cluster A의 각 인스턴스에 애플리케이션을 재 배포 한후,Cluster A reverse proxy를 재기동 시킨다. 마찬 가지 방법으로 Cluster B에도 같은 방법으로 redeploy를 수행한다.

이 구조를 택하면 전체 서비스 중지 없이 그리고 애플리케이션 변화에 대해서 일관성 있게 한꺼번에 재 배포가 가능하다.

Fabric을 이용하여 AWS Tomcat war 파일 배포 하기

그러면 실제로 Fabric을 이용해서 어떻게 배포를 할 수 있을까?

다음은 아주 간단한 Fabric을 이용한 배포 스크립트 이다.

순서는 tomcat stop > copy war > start 와 같다. EC2상에서 pem (SSH)를 이용하여, 두대의 Host deploy하는 스크립트이다.

#fabfile.py

from fabric.api import run,env,execute,task

from fabric.operations import local,put

 

def tomcat_cluster():

        env.user ='root'

        env.hosts=['host1.server.com','host2.server.com'] # list of server setting

        env.key_filename='~/pem/pemfile.pem' # pem file

 

def hostname():

        run('uname -a')

 

def start():

        run('/etc/init.d/tomcat6 start')  # tomcat instance stop

 

def stop():

        run('/etc/init.d/tomcat6 stop') # tomcat instance stop

 

def copy():

        put('./dummy.war','/root/war') # file copy

 

def deploy():

        execute(stop)

        execute(copy)

        execute(start)

 

해당 파일을 fabfile.py에 저장후에

%fab tomcat_cluster deploy

명령어로 실행을 하면 아래와 같은 순서로 배포가 진행된다.

host1.stop()

host1.copy()

host1.start()

host2.stop()

host2.copy()

host2.start()

 

위의 예제는 Fabric의 설명을 하기 위한 아주 간단한 예제로, 필요에 따라서 수정해서 사용하기 바란다.

앞의 예제에서는 간단하게 war 파일만을 복사하는 형태로 배포 스크립트를 작성하였지만, maven 설명할때 언급했던 것 처럼, 기타 Configuration 파일을 함께 배포하고, roll back이나 버전 관리가 용이하게하기 위해서 rpm 형태로 배포하는 것을 권장한다. 또한 rpm 파일을 관리하기 위해서 내부적으로 자체 yum repository를 만들어서 관리하는 것이 좋다.

배포에서 고민해야 할것 들

배포주기

근 몇 년전만 해도, 배포는 몇 달간의 개발이 끝나면 테스트를 거쳐서 특정한 날짜를 잡아서 대규모 배포를 형태가 일반적이었다.

그러나 근래에는 전체적인 IT 트렌드가 SNS와 같은 B2C 서비스가 중심이 되면서, 경쟁 서비스에 비해서 좋은 서비스를 빠르게 제공하기 위해서 업데이트 주기가 매우 짧아지고 있다. 이런 이유에서 배포도 자동화가 필요하게 되었고 Continuous Delivery와 같은 개념이 근래에 유행하게 된것일 수도 있는데, SNS 서비스의 경우 빠르면 하루 단위로 배포하는 경우 까지 있다.

배포 주기가 짧은 경우에는 몇 가지 더 고려할 사항이 있는데, 배포는 코드 개발보다는 인프라 관리나 빌드에 관련된 부분이 많다. 그래서 배포의 주체는 이런 운영 주체가 되는 경우가 일반적인데, 배포시 문제가 생기는 경우가 있을 시에는 개발팀의 도움이 필요하고, 배포가 정상적으로 되었을 경우에는 개발팀으로 부터의 확인등이 필요하기 때문에 조직 구조상 운영팀과 개발팀이 분리된 조직에서는 잦은 배포가 여러가지로 어려운점이 많다. 그래서 근래에는 이런 개발과 운영 조직을 합쳐서 개발팀을 운영하는 DevOps (Deveopment + Operation)형태의 조직구조로 전환하여 개발,배포,운영을 통합하여 관리 하는 쪽으로 이동하고 있다.

이 경우 단순히 조직을 합치는 것뿐만 아니라 개발자에게는 인프라나 운영에 대한 이해 능력을 그리고 운영팀에는 개발에 대한 어느정도 선까지의 능력을 요구하게 되고 업무 프로세스등의 변화가 필요하기 때문에 조직을 융합시키는 차원이 아니라 조금 더 높은 수준의 접근이 필요하다.  

수동 배포

운영 환경 배포는 반드시 수동으로 하는 것을 권고한다.

지금까지 자동으로 배포하는 방법을 설명해놓고, 왠 갑자기 수동 배포를 언급하는가 싶을 수도 있을텐데, 이유는 다음과 같다.

배포는 앞서 본 것과 같이 쉘 명령등을 수행해서 여러가지 명령 (Shutdown, Copy, Restart)을 동시에 여러 서버에 수행한다. 즉 중간에 에러가 날 가능성이 매우 높다.

그래서 배포 작업을 수행할때는 반드시 사람이 지켜보면서 배포 스크립트를 수행하는 것이 좋다. 개발환경이나 QA 환경 같은 경우에는 거의 업무 시간에 빌드를 하면서 배포가 수행이 되기 때문에, 배포 오류가 났을 경우에는 사람이 인지하기가 쉽고, 에러가 났을때 서비스에 직접적인 영향을 주지는 않는다. 그래서 개발이나 QA 환경 같은 경우에는 사람이 지켜보지 않고, CI 프로세스의 일부로 빌드 테스트가 끝나면 자동으로 배포를 하도록 해도 된다.

그렇지만 운영 환경의 경우에는 서비스에 직접적인 영향을 주기 때문에, 반드시 사람이 지켜보면서 수동으로 배포를 시작 및 모니터링 하도록 하는 것이 좋다.

배포 roll back

서비스에 대한 배포시, 테스트를 아무리 잘했다하더라도, 에러가 발생할 수 있다.

에러가 발생하였을 때는 이전의 버전으로 신속하게 roll back할 수 가 있어야 하는데, 이렇게 하기 위해서는 애플리케이션의 이전 버전을 반드시 저장하고 있어야 하고, 배포 스크립트 역시 예전 버전을 다시 배포할 수 있는 기능을 구현해야 한다.

릴리즈 노트

마지막으로 배포가 끝나면 반드시 릴리즈 노트를 작성 및 함께 배포하는 것이 좋다.

배포란 개발이나 운영이 주로 주도하는 작업이기 때문에, 비지니스 쪽에서 필요한 기능 변화에 대한 릴리즈 노트의 중요성을 잃어 버리는 경우가 많은데,  서비스가 변경이 되었을때, 어떠한 기능이 추가 되었는지, 그리고 어떠한 버그가 FIX가 되었는지를 사용자에게 알려줄 필요가 있으며, 특히 서비스를 판매나 영업하는 입장에서는 어떤 변화가 있었는지를 확인하는 것이 중요하기 때문에, 이 부분을 반드시 챙기도록 한다.

릴리즈 노트는 배포 되는 대상 (독자)에 따라서 다르게 작성되야 하는데,

내부 릴리즈 노트는 다음과 같은 내용이 포함되는 것을 권고한다.

Ÿ   릴리즈 버전, 날짜 및 빌드 넘버

Ÿ   새로운 기능 및 설명

Ÿ   버그 number 및 버그 수정 내용

또는 JIRA와 같은 Tak Management 도구를 사용하는 경우, JIRA에 등록된 기능이나 Bug 수정 내용을 릴리즈 시기에 자동으로 JIRA로 부터 생성해 낼 수 있다. (JIRA에서 릴리즈 노트 생성하기 https://confluence.atlassian.com/display/JIRA/Creating+Release+Notes)

만약 서비스나 제품 사용자를 대상으로 하는 경우, 위의 릴리즈 노트의 내용을 사용할 수 도 있지만, 조금 더 직관적이고 읽기 쉬운 형태로 릴리즈 노트를 작성하는 것이 좋다.

다음은 몇몇 잘 정의된 릴리즈 노트의 샘플이다.

Ÿ   안드로이드 릴리즈 노트 : http://developer.android.com/sdk/RELEASENOTES.html

Ÿ   Fire Fox 릴리즈 노트 http://www.mozilla.org/en-US/firefox/23.0.1/releasenotes/

Ÿ   Maven 릴리즈 노트 http://maven.apache.org/release-notes-all.html

릴리즈 노트는 청중들에게 이번 릴리즈 기능의 변경 사항을 제대로 알리기 위함이다. JIRA와 같은 시스템의 기능을 이용하건, 아니면 일일이 손으로 새로 쓰건간에 반드시 보는 사람이 어떤 변화가 있었는지 쉽게 이해할 수 있는 형태라야 한다.

http://pds3.egloos.com/pds/200611/26/16/capistrano_niceview.pdf 여기 정리가 잘되어 있네요.

Fabric과 비슷하게 SSH 기반으로 작동하는 도구입니다.

위의 PT에 스크립트 작성하는 전체적인 흐름이 잘 정의 되어 있어서, Fabric 사용할때도 비슷하게 참조할 수 있겠습니다.


Python Fabric Install

프로그래밍/Python | 2013.01.28 18:55 | Posted by 조대협

AWS EC2 (Amazon Linux 기준)


1. Python install (dev package로 설치)

(반드시 dev package가 설치되어 있어야지, pycrypto 설치시 에러가 나지 않음. pycrptyo는 encryption 관련 라이브러리로 C 라이브러리를 사용하는데, 컴파일중, python.h를 사용한다. 이 헤더 파일은 dev package안에 포함되어 있음)


- yum install python-devel 


2. pip install

$ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py

$ [sudo] python get-pip.py


3. gcc가 인스톨 (pycrypto 설치를 위해서 필요함) 

yum install gcc


4. fabric install


pip install pycrypto fabric


5. 설치 확인


from fabric.api import run


def host_type():

    run('uname -s')


MongoDB Deployment 아키텍쳐를 간단하게 보면 다음과 같다.
mongos들을 앞단에 쭈욱 늘어놓고, 이는 라우터의 역할을 한다. mongos간의 load balancing은 앞단에 L4등의 로드 밸런서를 사용하고, Cache Hit율등을 높이기 위해서 L4는 Hash 방식등의 Sticky setting을 한다.
뒷단에 mongod를 배치하고, 최소한 3 copy replica 구조로 설정한다.



inter data center에 대한 replication을 설정하고, 이는 DR이나 Back up 용도로 사용한다
inter data center replication은 항상 여러가지 숙제를 주는데, 이 경우 backbone의 속도 차이로 인하여 data의 일관성이 깨질 수 있으니,
1. DR/Back up 용도로만 사용
2. data center간 초고속 백본만 설치
3. data center A에서는 read/write, B에서는 read만 (Query Off Loading 아키텍쳐) 수행하고, 이 경우에는 B 데이타 센터의 data 반영이 늦음을 예상해서 애플리케이션을 설계한다.

오늘 OKJSP의 테크 트렌드에서 본 좋은 제품 하나.. http://www.zeroturnaround.com/ Java Agent로 JVM을 Weaving하여, Zero downtime으로 redeployment를 가능하게 해준다. 얼마나 Production에서 제대로 동작할지는 모르겠지만, WLP.WLI는 몰라도, WLS에 전통적인 J2EE Application이나 Spring 기반의 Ap에서는 꽤나 쓸만할듯.