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


Archive»


 
 

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/)등이 있다. 

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



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는 여러 클라우드 플랫폼에 명령을 내리기 위한 아답터 역할을 한다.




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/


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

요즘 시스템 운영쪽에 관심이 많아서 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 모델을 도입하기에는 변경되어야 하는 부분이 매우 많기 때문에, 매우 신중한 접근이 요구 된다.