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


Archive»


 
 

쿠버네티스 #6

Replication Controller를 이용하여 서비스 배포하기

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


1. 도커 파일 만들기

node.js로 간단한 웹서버를 만들어서 도커로 패키징 해보자.

실습을 진행하기 위해서 로컬 환경에 도커와, node.js 가 설치되어 있어야 한다. 이 두 부분은 생략하도록 한다.

여기서 사용한 실습 환경은 node.js carbon 버전 (8.11.3), 도커 맥용 18.05.0-ce, build f150324 을 사용하였다.

node.js 애플리케이션 준비하기

node.js로 간단한 웹 애플리케이션을 제작해보자 server.js라는 이름으로 아래 코드를 작성한다.

var os = require('os');

 

var http = require('http');

var handleRequest = function(request, response) {

 response.writeHead(200);

 response.end("Hello World! I'm "+os.hostname());

 

 //log

 console.log("["+

               Date(Date.now()).toLocaleString()+

               "] "+os.hostname());

}

var www = http.createServer(handleRequest);

www.listen(8080);


이 코드는 8080 포트로 웹서버를 띄워서 접속하면 “Hello World!” 문자열과 함께, 서버의 호스트명을 출력해준다. 그리고 stdout에 로그로, 시간과 서버의 호스트명을 출력해준다.

코드 작성이 끝났으면, 서버를 실행해보자

%node server.js


다음 브라우저로 접속하면 다음과 같은 결과를 얻을 수 있다.


그리고 콘솔화면에는 아래와 같이 시간과 호스트명이 로그로 함께 출력된다.

도커로 패키징하기

그러면 이 node.js 애플리케이션을 도커 컨테이너로 패키징 해보자

Dockerfile 이라는 파일을 만들고 아래 코드를 작성한다.

FROM node:carbon

EXPOSE 8080

COPY server.js .

CMD node server.js > log.out


이 코드는 node.js carborn (8.11.3) 컨테이너 이미지를 베이스로 한후에,  앞서 작성한 server.js 코드를 복사한후에, node server.js > log.out 명령어를 실행하도록 하는 컨테이너를 만드는 설정파일이다.

설정 파일이 준비되었으면,  도커 컨테이너 파일을 만들어보자


% docker build -t gcr.io/terrycho-sandbox/hello-node:v1 .


docker build  명령은 컨테이너를 만드는 명령이고, -t는 빌드될 이미지에 대한 태그를 정하는 명령이다.

빌드된 컨테이너 이미지는 gcr.io/terrycho-sandbox/hello-node로  태깅되는데, 이는 향후에 구글 클라우드 컨테이너 레지스트리에 올리기 위해서 태그 명을 구글 클라우드 컨테이너 레지스트리의 포맷을 따른 것이다. (참고 https://cloud.google.com/container-registry/docs/pushing-and-pulling)

포맷은 [HOST_NAME]/[GOOGLE PROJECT-ID]/[IMAGE NAME]


gcr.io/terrycho-sandbox는 도커 이미지가 저장될 리파지토리의 경로를 위의 규칙에 따라 정의한 것인데,

  • gcr.io는 구글 클라우드 컨테이너 리파지토리 US 리전을 지칭하며,

  • terrycho-sandbox는 본인의 구글 프로젝트 ID를 나타낸다.

  • 이미지명을 hello-node 로 지정하였다.

  • 마지막으로 콜론(:) 으로 구별되어 정의한 부분은 태그 부분으로, 여기서는 “v1”으로 태깅을 하였다.


이미지는 위의 이름으로 지정하여 생성되어 로컬에 저장된다.




빌드를 실행하면 위와 같이 node:carbon 이미지를 읽어와서 필요한 server.js 파일을 복사하고 컨테이너 이미지를 생성한다.

컨테이너 이미지가 생성되었으면 로컬 환경에서 이미지를 기동 시켜보자


%docker run -d -p 8080:8080 gcr.io/terrycho-sandbox/hello-node:v1


명령어로 컨테이너를 실행할 수 있다.

  • -d 옵션은 컨테이너를 실행하되, 백그라운드 모드로 실행하도록 하였다.

  • -p는 포트 맵핑으로 뒤의 포트가 도커 컨테이너에서 돌고 있는 포트이고, 앞의 포트가 이를 밖으로 노출 시키는 포트이다 예를 들어 -p 9090:8080 이면 컨테이너의 8080포트를 9090으로 노출 시켜서 서비스 한다는 뜻이다. 여기서는 컨테이너 포트와 서비스로 노출 되는 포트를 동일하게 8080으로 사용하였다.


컨테이너를 실행한 후에, docker ps 명령어를 이용하여 확인해보면 아래와 같이 hello-node:v1 이미지로 컨테이너가 기동중인것을 확인할 수 있다.



다음 브라우져를 통해서 접속을 확인하기 위해서 localhost:8080으로 접속해보면 아래와 같이 Hello World 와 호스트명이 출력되는 것을 확인할 수 있다.


로그가 제대로 출력되는지 확인하기 위해서 컨테이너 이미지에 쉘로 접속해보자

접속하는 방법은


% docker exec -i -t [컨테이너 ID] /bin/bash

를 실행하면 된다. 컨테이너 ID 는 앞의 docker ps 명령을 이용하여 기동중인 컨테이너 명을 보면 처음 부분이 컨테이너 ID이다.

hostname 명령을 실행하여 호스트명을 확인해보면 위에 웹 브라우져에서 출력된 41a293ba79a7과 동일한것을 확인할 수 있다. 디렉토리에는 server.js 파일이 복사되어 있고, log.out 파일이 생성된것을 볼 수 있다.  

cat log.out을 이용해서 보면, 시간과 호스트명이 로그로 출력된것을 확인할 수 있다.



2. 쿠버네티스 클러스터 준비

구글 클라우드 계정 준비하기

구글 클라우드 계정 생성은 http://bcho.tistory.com/1107 문서를 참고하기 바란다.

쿠버네티스 클러스터 생성하기

쿠버네티스 클러스터를 생성해보자, 클러스터 생성은 구글 클라우드 콘솔의 Kubernetes Engine > Clusters 메뉴에서 Create 를 선택하면 클러스터 생성이 가능하다.



클러스터 이름을 넣어야 하는데, 여기서는 terry-gke-10 을 선택하였다. 구글 클라우드에서 쿠버네티스 클러스터는 싱글 존에만 사용가능한 Zonal 클러스터와 여러존에 노드를 분산 배포하는 Regional 클러스터 두 가지가 있는데, 여기서는 하나의 존만 사용하는 Zonal 클러스터를 설정한다. (Regional은 차후에 다루도록 하겠다.)

다음 클러스터를 배포한 존을 선택하는데, asia-northeast1-c (일본)을 선택하였다.

Cluster Version은 쿠버네티스 버전인데, 1.10.2 버전을 선택한다.

그리고 Machine type은 쿠버네티스 클러스터의 노드 머신 타입인데, 간단한 테스트 환경이기 때문에,  2 CPU에 7.5 메모리를 지정하였다.

다음으로 Node Image는 노드에 사용할 OS 이미지를 선택하는데, Container Optimized OS를 선택한다. 이 이미지는 컨테이너(도커)를 운영하기 위해 최적화된 이미지이다.

다음으로는 노드의 수를 Size에서 선택한다. 여기서는 3개의 노드를 운용하도록 설정하였다.


아래 부분에 보면  Automatic node upgrades 라는 기능이 있다.


구글 클라우드의 재미있는 기능중 하나인데, 쿠버네티스 버전이 올라가면 자동으로 버전을 업그레이드 해주는 기능으로, 이 업그레이드는 무정지로 진행 된다.


gcloud 와 kubectl 설치하기

클러스터 설정이 끝났으면 gloud (Google Cloud SDK 이하 gcloud)를 인스톨한다.

gcloud 명령어의 인스톨 방법은 OS마다 다른데, https://cloud.google.com/sdk/docs/quickstarts 문서를 참고하면 된다.

별다른 어려운 작업은 없고, 설치 파일을 다운 받아서 압축을 푼후에, 인스톨 스크립트를 실행하면 된다.


kubectl은 쿠버네티스의 CLI (Command Line Interface)로, gcloud를 인스톨한후에,

%gcloud components install kubectl

명령을 이용하면 인스톨할 수 있다.

쿠버네티스 클러스터 인증 정보 얻기

gcloud와 kubectl 명령을 설치하였으면, 이 명령어들을 사용할때 마다 쿠버네티스에 대한 인증이 필요한데, 인증에 필요한 인증 정보는 아래 명령어를 이용하면, 자동으로 사용이 된다.

gcloud container clusters get-credentials CLUSTER_NAME

여기서는 클러스터명이 terry-gke10이기 때문에,

%gcloud container clusters get-credentials terry-gke-10

을 실행한다.


명령어 설정이 끝났으면, gcloud 명령이 제대로 작동하는지를 확인하기 위해서, 현재 구글 클라우드내에 생성된 클러스터 목록을 읽어오는 gcloud container clusters list 명령어를 실행해보자



위와 같이 terry-gke-10 이름으로 asia-northeast1-c 존에 쿠버네티스 1.10.2-gke.3 버전으로 클러스터가 생성이 된것을 볼 수 있고, 노드는 총 3개의 실행중인것을 확인할 수 있다.

3. 쿠버네티스에 배포하기

이제 구글 클라우드에 쿠버네티스 클러스터를 생성하였고, 사용을 하기 위한 준비가 되었다.

앞에서 만든 도커 이미지를 패키징 하여, 이 쿠버네티스 클러스터에 배포해보도록 하자.

여기서는 도커 이미지를 구글 클라우드내의 도커 컨테이너 레지스트리에 등록한 후, 이 이미지를 이용하여 ReplicationController를 통해 총 3개의 Pod를 구성하고 서비스를 만들어서 이 Pod들을 외부 IP를 이용하여 서비스를 제공할 것이다.

도커 컨테이너 이미지 등록하기

먼저 앞에서 만든 도커 이미지를 구글 클라우드 컨테이너 레지스트리(Google Container Registry 이하 GCR) 에 등록해보자.

GCR은 구글 클라우드에서 제공하는 컨테이너 이미지 저장 서비스로, 저장 뿐만 아니라, CI/CD 도구와 연동하여, 자동으로 컨테이너 이미지를 빌드하는 기능, 그리고 등록되는 컨테이너 이미지에 대해서 보안적인 문제가 있는지 보안 결함을 스캔해주는 기능과 같은 다양한 기능을 제공한다.


컨테이너 이미지를 로컬환경에서 도커 컨테이너 저장소에 저장하려면 docker push라는 명령을 사용하는데, 여기서는 GCR을 컨테이너 이미지 저장소로 사용할 것이기 때문에, GCR에 대한 인증이 필요하다.

인증은 한번만 해놓으면 되는데

%gcloud auth configure-docker

명령을 이용하면, 인증 정보가 로컬 환경에 자동으로 저장된다.



인증이 완료되었으면, docker push 명령을 이용하여 이미지를 GCR에 저장한다.

%docker push gcr.io/terrycho-sandbox/hello-node:v1


명령어를 실행하면, GCR에 hello-node 이미지가 v1 태그로 저장된다.


이미지가 GCR에 잘 저장되었는지를 확인하기 위해서 구글 클라우드 콘솔에 Container Registry (GCR)메뉴에서 Images라는 메뉴를 들어가보자




아래와 같이 hello-node 폴더에 v1이라는 태그로 이미지가 등록된것을 확인할 수 있다.

ReplicationController 등록

컨테이너 이미지가 등록되었으면 이 이미지를 이용해서 Pod를 생성해보자,  Pod 생성은 Replication Controller (이하 rc)를 생성하여, rc가 Pod 생성 및 컨트롤을 하도록 한다.


다음은 rc 생성을 위한 hello-node-rc.yaml 파일이다.


apiVersion: v1

kind: ReplicationController

metadata:

 name: hello-node-rc

spec:

 replicas: 3

 selector:

   app: hello-node

 template:

   metadata:

     name: hello-node-pod

     labels:

       app: hello-node

   spec:

     containers:

     - name: hello-node

       image: gcr.io/terrycho-sandbox/hello-node:v1

       imagePullPolicy: Always

       ports:

       - containerPort: 8080


hello-node-rc 라는 이름으로 rc를 생성하는데, replica 를 3으로 하여, 총 3개의 pod를 생성하도록 한다.

템플릿 부분에 컨테이너 스팩에 컨테이너 이름은 hello-node로 하고 이미지는 앞서 업로드한 gcr.io/terrycho-sandbox/hello-node:v1 를 이용해서 컨테이너를 만들도록 한다. 컨테이너의 포트는 8080을 오픈한다. 템플릿 부분에서 app 이라는 이름의 라벨을 생성하고 그 값을 hello-node로 지정하였다. 이 라벨은 나중에 서비스 (service)에 의해 외부로 서비스될 pod들을 선택하는데 사용 된다.


여기서 imagePullPolicy:Always  라고 설정한 부분이 있는데, 이는 Pod를 만들때 마다 매번 컨테이너 이미지를 확인해서 새 이미지를 사용하도록 하는 설정이다.  컨테이너 이미지는 한번 다운로드가 되면 노드(Node) 에 저장이 되어 있게 되고, 사용이 되지 않는 이미지 중에 오래된 이미지는 Kublet이 가비지 컬렉션 (Garbage collection) 정책에 따라 이미지를 삭제하게 되는데, 문제는 노드에 이미 다운되어 있는 이미지가 있을 경우 컨테이너 생성시 노드에 이미 다운로드 되어 있는 이미지를 사용한다. 컨테이너 리파지토리에 같은 이름으로 이미지를 업데이트 하거나 심지어 그 이미지를 삭제하더라도 노드에 이미지가 이미 다운로드 되어 있으면 다운로드된 이미지를 사용하기 때문에, 업데이트 부분이 반영이 안된다.

이를 방지하기 위해서 imagePullPolicy:Always로 해주면 컨테이너 생성시마다 이미지 리파지토리를 검사해서 새 이미지를 가지고 오기 때문에, 업데이트된 내용을 제대로 반영할 수 있다.


%kubectl create -f hello-node-rc.yaml


명령어를 실행해서 rc와 pod를 생성한다.




위의 그림과 같이 3개의 Pod가 생성된것을 확인할 수 있는데, Pod가 제대로 생성되었는지 확인하기 위해서 hello-node-rc-rsdzl pod에서 hello-node-rc-2phgg pod의 node.js 웹서버에 접속을 해볼 것이다.

아직 서비스를 붙이지 않았기 때문에, 이 pod들은 외부 ip를 이용해서 서비스가 불가능하기 때문에, 쿠버네티스 클러스터 내부의 pod를 이용하여 내부 ip (private ip)간에 통신을 해보기 위해서 pod에서 pod를 호출 하는 것이다. kubectl describe pod  [pod 명] 명령을 이용하면, 해당 pod의 정보를 볼 수 있다. hello-node-rc-2hpgg pod의 cluster ip (내부 ip)를 확인해보면 10.20.1.27 인것을 확인할 수 있다.


kubectl exec 명령을 이용하면 쉘 명령어를 실행할 수 있는데, 다음과 같이 hello-node-rc-rsdzl pod에서 첫번째 pod인 hello-node-rc-2phgg의 ip인 10.20.1.27의 8080 포트로 curl 을 이용해 HTTP 요청을 보내보면 다음과 같이 정상적으로 응답이 오는 것을 볼 수 있다.


Service 등록

rc와 pod 생성이 끝났으면 이제 서비스를 생성해서 pod들을 외부 ip로 서비스 해보자

다음은 서비스를 정의한 hello-node-svc.yaml 파일이다.


hello-node-svc.yaml

apiVersion: v1

kind: Service

metadata:

 name: hello-node-svc

spec:

 selector:

   app: hello-node

 ports:

   - port: 80

     protocol: TCP

     targetPort: 8080

 type: LoadBalancer


Selector 부분에 app:hello-node 로 지정하여, pod들 중에 라벨의 키가 app이고 값이 hello-node인 pod 들만 서비스에 연결하도록 지정하였다. 다음 서비스의 포트는 80으로 지정하였고, pod의 port는 8080으로 지정하였다.


서비스가 배포되면 위와 같은 구조가 된다.

%kubectl create -f hello-node-svc.yaml

명령을 이용하면 서비스가 생성이 된다.


다음 생성된 서비스의 외부 ip를 얻기 위해서 kubectl get svc 명령을 실행해보자

아래 그림과 같이 35.200.40.161 IP가 할당된것을 확인할 수 있다.


이 IP로 접속을 해보면 아래와 같이 정상적으로 응답이 오는 것을 확인할 수 있다.


RC 테스트

rc는 pod의 상태를 체크하다가 문제가 있으면 다시, pod를 기동해주는 기능을 한다.

이를 테스트하기 위해서 강제적으로 모든 pod를 제거해보자. kubectl delete pod --all을 이용하면 모든 pod를 제거할 수 있는데, 아래 그림을 보면, 모든 pod를 제거했더니 3개의 pod가 제거되고 새롭게 3개의 pod가 기동되는 것을 확인할 수 있다.



운영중에 탄력적으로 pod의 개수를 조정할 수 있는데, kubectl scale 명령을 이용하면 된다.

kubectl scale --replicas=[pod의 수] rc/[rc 명] 식으로 사용하면 된다. 아래는 pod의 수를 4개로 재 조정한 내용이다.



자원 정리

테스트가 끝났으면 서비스, rc,pod를 삭제해보자.

  • 서비스 삭제는 kubectl delete svc --all 명령어를 이용한다.

  • rc 삭제는 kubectl delete rc --all

  • pod 삭제는 kubectl delete pod --all

을 사용한다.

삭제시 주의할점은 pod를 삭제하기 전에 먼저 rc를 삭제해야 한다. 아니면, pod가 삭제된 후 rc에 의해서 다시 새로운 pod가 생성될 수 있다.


쿠버네티스 #4

Volume (디스크)

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


이번 글에서는 쿠버네티스의 디스크 서비스인 볼륨에 대해서 알아보도록 하겠다.

쿠버네티스에서 볼륨이란 Pod에 종속되는 디스크이다. (컨테이너 단위가 아님). Pod 단위이기 때문에, 그 Pod에 속해 있는 여러개의 컨테이너가 공유해서 사용될 수 있다.

볼륨 종류

쿠버네티스의 볼륨은 여러가지 종류가 있는데,  로컬 디스크 뿐 아니라, NFS, iSCSI, Fiber Channel과 같은 일반적인 외장 디스크 인터페이스는 물론, GlusterFS나, Ceph와 같은 오픈 소스 파일 시스템, AWS EBS, GCP Persistent 디스크와 같은 퍼블릭 클라우드에서 제공되는 디스크, VsphereVolume과 같이 프라이비트 클라우드 솔루션에서 제공하는 디스크 볼륨까지 다양한 볼륨을 지원한다.

자세한 볼륨 리스트는 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes 를 참고하기 바란다.


이 볼륨 타입을 구별해보면 크게 임시 디스크, 로컬 디스크 그리고 네트워크 디스크 등으로 분류할 수 있다.


Temp

Local

Network

emptyDir

hostPath

GlusterFS

gitRepo

NFS

iSCSI

gcePersistentDisk

AWS EBS

azureDisk

Fiber Channel

Secret

VshereVolume


그럼 각각에 대해서 알아보도록 하자

emptyDir

emptyDir은 Pod가 생성될때 생성되고, Pod가 삭제 될때 같이 삭제되는 임시 볼륨이다.

단 Pod 내의 컨테이너 크래쉬되어 삭제되거나 재시작 되더라도 emptyDir의 생명주기는 컨테이너 단위가 아니라, Pod 단위이기 때문에, emptyDir은 삭제 되지 않고 계속해서 사용이 가능하다.

생성 당시에는 디스크에 아무 내용이 없기 때문에, emptyDir  이라고 한다.

emptyDir의 물리적으로 노드에서 할당해주는 디스크에 저장이 되는데, (각 환경에 따라 다르다. 노드의 로컬 디스크가 될 수 도 있고, 네트워크 디스크등이 될 수 도 있다.) emptyDir.medium 필드에 “Memory”라고 지정해주면, emptyDir의 내용은 물리 디스크 대신 메모리에 저장이 된다.


다음은 하나의 Pod에 nginx와 redis 컨테이너를 기동 시키고, emptyDir 볼륨을 생성하여 이를 공유하는 설정이다.


apiVersion: v1

kind: Pod

metadata:

 name: shared-volumes

spec:

 containers:

 - name: redis

   image: redis

   volumeMounts:

   - name: shared-storage

     mountPath: /data/shared

 - name: nginx

   image: nginx

   volumeMounts:

   - name: shared-storage

     mountPath: /data/shared

 volumes:

 - name : shared-storage

   emptyDir: {}


shared-storage라는 이름으로 emptyDir 기반의 볼륨을 만든 후에, nginx와 redis 컨테이너의 /data/shared 디렉토리에 마운트를 하였다.


Pod를 기동 시킨후에, redis 컨테이너의 /data/shared 디렉토리에 들어가 보면 당연히 아무 파일도 없는 것을 확인할 수 있다.

이 상태에서 아래와 같이 file.txt 파일을 생성하였다.



다음 nginx 컨테이너로 들어가서 /data/shared 디렉토리를 살펴보면 file.txt 파일이 있는 것을 확인할 수 있다.



이 파일은 redis 컨테이너에서 생성이 되어 있지만, 같은 Pod 내이기 때문에, nginx 컨테이너에서도 접근이 가능하게 된다.

hostPath

다음은 hostPath 라는 볼륨 타입인데, hostPath는 노드의 로컬 디스크의 경로를 Pod에서 마운트해서 사용한다. 같은 hostPath에 있는 볼륨은 여러 Pod 사이에서 공유되어 사용된다.

또한  Pod가 삭제 되더라도 hostPath에 있는 파일들은 삭제되지 않고 다른 Pod가 같은 hostPath를 마운트하게 되면, 남아 있는 파일을 액세스할 수 있다.


주의할점 중의 하나는 Pod가 재시작되서 다른 노드에서 기동될 경우, 그 노드의 hostPath를 사용하기 때문에, 이전에 다른 노드에서 사용한 hostPath의 파일 내용은 액세스가 불가능하다.


hostPath는 노드의 파일 시스템을 접근하는데 유용한데, 예를 들어 노드의 로그 파일을 읽어서 수집하는 로그 에이전트를 Pod로 배포하였을 경우, 이 Pod에서 노드의 파일 시스템을 접근해야 한다. 이러한 경우에 유용하게 사용할 수 있다.


아래는 노드의 /tmp 디렉토리를 hostPath를 이용하여 /data/shared 디렉토리에 마운트 하여 사용하는 예제이다.


apiVersion: v1

kind: Pod

metadata:

 name: hostpath

spec:

 containers:

 - name: redis

   image: redis

   volumeMounts:

   - name: terrypath

     mountPath: /data/shared

 volumes:

 - name : terrypath

   hostPath:

     path: /tmp

     type: Directory



이 Pod를 배포해서 Pod를 Id를 얻어보았다.


Pod Id를 통해서 VM을 아래와 같이 확인하였다.


VM에 SSH로 접속해서 /tmp/에 hello.txt 파일을 생성하였다.




다음, Pod의 컨테이너에서 마운트된 /data/shared 디렉토리를 확인해보면 아래와 같이 노드의 /tmp 디렉토리의 내용이 그대로 보이는 것을 볼 수 있다.


gitRepo

볼륨 타입중에 gitRepo라는 유용한 볼륨 타입이 하나 있어서 소개한다.

이 볼륨은 생성시에 지정된 git 리파지토리의 특정 리비전의 내용을 clone을 이용해서 내려 받은후에 디스크 볼륨을 생성하는 방식이다. 물리적으로는 emptyDir이 생성되고, git 레파지토리 내용을 clone으로 다운 받는다.




HTML과 같은 정적 파일이나 Ruby on rails, PHP, node.js 와 같은 스크립트 언어 기반의 코드들은 gitRepo 볼륨을 이용하여 손쉽게 배포할 수 있다.


apiVersion: v1

kind: Pod

metadata:

name: gitrepo-volume-pod

spec:

containers:

- image: nginx:alpine

  name: web-server

  volumeMounts:

  - name: html

    mountPath: /usr/share/nginx/html

    readOnly: true

  ports:

  - containerPort: 80

    protocol: TCP

volumes:

- name: html

  gitRepo:

       repository: https://github.com/luksa/kubia-website-example.git

       revision: master

       directory: .


이 설정은 https://github.com/luksa/kubia-website-example.git 의 master 리비전을 클론으로 다운받아서 /usr/share/nginx/html에 마운트 시키는 설정이다.


PersistentVolume and PersistentVolumeClaim

일반적으로 디스크 볼륨을 설정하려면 물리적 디스크를 생성해야 하고, 이러한 물리적 디스크에 대한 설정을 자세하게 이해할 필요가 있다.

쿠버네티스는 인프라에 대한 복잡성을 추상화를 통해서 간단하게 하고, 개발자들이 손쉽게 필요한 인프라 (컨테이너,디스크, 네트워크)를 설정할 수 있도록 하는 개념을 가지고 있다

그래서 인프라에 종속적인 부분은 시스템 관리자가 설정하도록 하고, 개발자는 이에 대한 이해 없이 간단하게 사용할 수 있도록 디스크 볼륨 부분에 PersistentVolumeClaim (이하 PVC)와 PersistentVolume (이하 PV)라는 개념을 도입하였다.


시스템 관리자가 실제 물리 디스크를 생성한 후에, 이 디스크를 PersistentVolume이라는 이름으로 쿠버네티스에 등록한다.

개발자는 Pod를 생성할때, 볼륨을 정의하고, 이 볼륨 정의 부분에 물리적 디스크에 대한 특성을 정의하는 것이 아니라 PVC를 지정하여, 관리자가 생성한 PV와 연결한다.


그림으로 정리해보면 다음과 같다.


시스템 관리자가 생성한 물리 디스크를 쿠버네티스 클러스터에 표현한것이 PV이고, Pod의 볼륨과 이 PV를 연결하는 관계가 PVC가 된다.


이때 주의할점은 볼륨은 생성된후에, 직접 삭제하지 않으면 삭제되지 않는다. PV의 생명 주기는 쿠버네티스 클러스터에 의해서 관리되면 Pod의 생성 또는 삭제에 상관없이 별도로 관리 된다. (Pod와 상관없이 직접 생성하고 삭제해야 한다.)

PersistentVolume

PV는 물리 디스크를 쿠버네티스에 정의한 예제로, NFS 파일 시스템 5G를 pv0003이라는 이름으로 정의하였다.




PV를 설정하는데 여러가지 설정 옵션이 있는데, 간략하게 그 내용을 살펴보면 다음과 같다.

  • Capacity
    볼륨의 용량을 정의한다. 현재는 storage 항목을 통해서 용량만을 지정하는데 향후에는 필요한 IOPS나 Throughput등을 지원할 예정이다.

  • VolumeMode
    VolumeMode는 Filesystem (default)또는 raw를 설정할 수 있는데, 볼륨이 일반 파일 시스템인데, raw 볼륨인지를 정의한다.

  • Reclaim Policy
    PV는 연결된 PVC가 삭제된 후 다시 다른 PVC에 의해서 재 사용이 가능한데, 재 사용시에 디스크의 내용을 지울지 유지할지에 대한 정책을 Reclaim Policy를 이용하여 설정이 가능하다.

    • Retain : 삭제하지 않고 PV의 내용을 유지한다.

    • Recycle : 재 사용이 가능하며, 재 사용시에는 데이타의 내용을 자동으로 rm -rf 로 삭제한 후 재사용이 된다.

    • Delete : 볼륨의 사용이 끝나면, 해당 볼륨은 삭제 된다. AWS EBS, GCE PD,Azure Disk등이 이에 해당한다.

Reclaim Policy은 모든 디스크에 적용이 가능한것이 아니라, 디스크의 특성에 따라서 적용이 가능한 Policy가 있고, 적용이 불가능한 Policy 가 있다.

  • AccessMode
    AccessMode는 PV에 대한 동시에 Pod에서 접근할 수 있는 정책을 정의한다.

    • ReadWriteOnce (RWO)
      해당 PV는 하나의 Pod에만 마운트되고 하나의 Pod에서만 읽고 쓰기가 가능하다.

    • ReadOnlyMany(ROX)
      여러개의 Pod에 마운트가 가능하며, 여러개의 Pod에서 동시에 읽기가 가능하다. 쓰기는 불가능하다.

    • ReadWriteMany(RWX)
      여러개의 Pod에 마운트가 가능하고, 동시에 여러개의 Pod에서 읽기와 쓰기가 가능하다.

위와 같이 여러개의 모드가 있지만, 모든 디스크에 사용이 가능한것은 아니고 디스크의 특성에 따라서 선택적으로 지원된다.


PV의 라이프싸이클

PV는 생성이 되면, Available 상태가 된다. 이 상태에서 PVC에 바인딩이 되면 Bound 상태로 바뀌고 사용이 되며, 바인딩된 PVC가 삭제 되면, PV가 삭제되는 것이 아니라  Released 상태가 된다. (Available이 아니면 사용은 불가능하고 보관 상태가 된다.)

PV 생성 (Provisioning)

PV의 생성은 앞에서 봤던것 처럼 yaml 파일등을 이용하여, 수동으로 생성을 할 수 도 있지만, 설정에 따라서 필요시마다 자동으로 생성할 수 있게 할 수 있다. 이를 Dynamic Provisioning (동적 생성)이라고 하는데, 이에 대해서는 PVC를 설명하면서 같이 설명하도록 하겠다.

PersistentVolumeClaim

PVC는 Pod의 볼륨과 PVC를 연결(바인딩/Bind)하는 관계 선언이다.

아래 예제를 보자 아래 예제는 PVC의 예제이다.



(출처 : https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)


  • accessMode, VolumeMode는 PV와 동일하다.

  • resources는 PV와 같이, 필요한 볼륨의 사이즈를 정의한다.

  • selector를 통해서 볼륨을 선택할 수 있는데, label selector 방식으로 이미 생성되어 있는 PV 중에, label이 매칭되는 볼륨을 찾아서 연결하게 된다.


PV/PVC 예제

그러면 예제를 통해서 PV를 생성하고, 이 PV를 PVC에 연결한후에, PVC를 Pod에 할당하여 사용하는 방법을 살펴보도록 하자. 예제는 구글 클라우드 환경을 사용하였다.

1.물리 디스크 생성

먼저 구글 클라우드 콘솔에서 Compute Engine 부분에서 아래와 같이 Disks 부분에서 물리 디스크를 생성한다.


디스크를 pv-demo-disk라는 이름으로 생성하였다.

이때 주의할점은 디스크의 region과 zone이 쿠베네티스 클러스터가 배포된 region과 zone에 동일해야 한다.


2.생성된 디스크로 PV를 선언

생성된 디스크를 이용하여 PV를 생성한다. 아래는 PV를 생성하기 위한 yaml 파일이다.


existing-pd.yaml

apiVersion: v1

kind: PersistentVolume

metadata:

 name: pv-demo

spec:

 storageClassName:

 capacity:

   storage: 20G

 accessModes:

   - ReadWriteOnce

 gcePersistentDisk:

   pdName: pv-demo-disk

   fsType: ext4


PV의이름은 pv-demo이고, gcePersistentDisk에서 앞에서 생성한 pv-demo-disk 를 사용하도록 정의하였다.

파일을 실행하면, 아래와 같이 pv-demo로 PV가 생성된것을 확인할 수 있다.

3. 다음 PVC를 생성한다.

아래는 앞에서 생성한 pv-demo PV를 사용하는 PVC를 생성하는 yaml 파일이다. 하나의 Pod에서만 액세스가 가능하도록 accessMode를 ReadWriteOnce로 설정하였다.


existing-pvc.yaml

apiVersion: v1

kind : PersistentVolumeClaim

metadata:

 name: pv-claim-demo

spec:

 storageClassName: ""

 volumeName: pv-demo

 accessModes:

   - ReadWriteOnce

 resources:

   requests:

     storage: 20G


4. Pod를 생성하여, PVC를 바인딩

그러면 앞에서 생성한 PV와 PVC를 Pod에 생성해서 연결하자


existing-pod-redis.yaml

apiVersion: v1

kind: Pod

metadata:

 name: redis

spec:

 containers:

 - name: redis

   image: redis

   volumeMounts:

   - name: terrypath

     mountPath: /data

 volumes:

 - name : terrypath

   persistentVolumeClaim:

     claimName: pv-claim-demo


앞에서 생성한 PVC pv-claim-demo를 Volume에 연결한후, 이 볼륨을 /data 디렉토리에 마운트 하였다.

Pod를 생성한후에, 생성된 Pod에 df -k 로 디스크 연결 상태를 확인해 보면 다음과 같다.



/dev/sdb 가 20G로 생성되어 /data 디렉토리에 마운트 된것을 확인할 수 있다.

Dynamic Provisioning

앞에서 본것과 같이 PV를 수동으로 생성한후 PVC에 바인딩 한 후에, Pod에서 사용할 수 있지만, 쿠버네티스 1.6에서 부터 Dynamic Provisioning (동적 생성) 기능을 지원한다. 이 동적 생성 기능은 시스템 관리자가 별도로 디스크를 생성하고 PV를 생성할 필요 없이 PVC만 정의하면 이에 맞는 물리 디스크 생성 및 PV 생성을 자동화해주는 기능이다.




PVC를 정의하면, PVC의 내용에 따라서 쿠버네티스 클러스터가 물리 Disk를 생성하고, 이에 연결된 PV를 생성한다.

실 환경에서는 성능에 따라 다양한 디스크(nVME, SSD, HDD, NFS 등)를 사용할 수 있다. 그래서 디스크를 생성할때, 필요한 디스크의 타입을 정의할 수 있는데, 이를 storageClass 라고 하고, PVC에서 storage class를 지정하면, 이에 맞는 디스크를 생성하도록 한다.

Storage class를 지정하지 않으면, 디폴트로 설정된 storage class 값을 사용하게 된다.


동적 생성 방법은 어렵지 않다. PVC에 필요한 디스크 용량을 지정해놓으면, 자동으로 이에 해당하는 물리 디스크 및 PV가 생성이 된다. 아래는 동적으로 PV를 생성하는 PVC 예제이다.


dynamic-pvc.yaml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

 name: mydisk

spec:

 accessModes:

   - ReadWriteOnce

 resources:

   requests:

     storage: 30Gi


다음 Pod를 생성한다.

apiVersion: v1

kind: Pod

metadata:

 name: redis

spec:

 containers:

 - name: redis

   image: redis

   volumeMounts:

   - name: terrypath

     mountPath: /data/shared

 volumes:

 - name : terrypath

   persistentVolumeClaim:

     claimName: mydisk


Pod를 생성한후에, kubectl get pvc 명령어를 이용하여, 생성된 PVC와 PV를 확인할 수 있다.

PVC는 위에서 정의한것과 같이 mydisk라는 이름으로 생성되었고, Volume (PV)는 pvc-4a…. 식으로 새롭게 생성되었다.

Storage class

스토리지 클래스를 살펴보자,

아래는  AWS EBS 디스크에 대한 스토리지 클래스를 지정한 예로, slow 라는 이름으로 스토리지 클래스를 지정하였다. EBS 타입은 io1을 사용하고, GB당 IOPS는 10을 할당하도록 하였고, 존은 us-east-1d와 us-east-1c에 디스크를 생성하도록 하였다.



아래는 구글 클라우드의 Persistent Disk (pd)의 예로, slow라는 이름으로 스토리지 클래스를 지정하고, pd-standard (HDD)타입으로 디스크를 생성하되 us-central1-a와 us-central1-b 존에 디스크를 생성하도록 하였다.



이렇게 정의한 스토리지 클래스는  PVC 정의시에, storageClassName에 적으면 PVC에 연결이 되고, 스토리지 클래스에 정해진 스펙에 따라서 물리 디스크와 PV를 생성하게 된다.

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




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


Google Cloud Function


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

기본 개념

구글 클라우드 펑션은 서버리스 아키텍쳐를 구현하기 위한 구글 클라우드 서비스이다. 아마존 웹서비스의 람다와 같은 기능이라고 보면 된다.




이벤트가 발생하면, 이벤트에 따라서, 코드를 수행해주는 형태인데, 이벤트의 종류는 다음과 같다.

  • Pub/Sub 메세지 큐에서 들어오는 메세지

  • Firebase 모바일 SDK에 의해서 발생되는 이벤트

  • Google Cloud Storage 서비스에 의해서 파일이 생성,수정,삭데 되었을때

  • 마지막으로 HTTP로 들어오는 요청 (REST API)


개발환경

프로그래밍 언어는 node.js 6.9.1 버전을 기반으로 되어 있으며, node.js의 package.json을 이용하여 왠만한 의존성 모듈은 설치가 가능하다. (node.js express 등)  개발을 위해서는 로컬에 에뮬레이터를 설치하여 개발이 가능하다. https://cloud.google.com/functions/docs/emulator

Hello World

그러면 간단하게, 구글 클라우드 펑션을 사용해보자

클라우드 펑션은 크게 두가지 타입의 펑션이 있는데

  • HTTP 펑션
    HTTP 펑션은 HTTP 로 입력을 받는 형태로 function 펑션이름(req,res)
    req는 HTTP Request, res는 HTTP Response 이다.

  • 백그라운드 펑션
    백르라운드 펑션은 GCS,Pub/Sub 등의 이벤트로 트리거링 되는 펑션으로 function 펑션이름(event,callback)형태로 정의된다. event 객체 안에, GCS나 Pub/Sub 에서 발생된 이벤트 정보가 전송된다.


간단하게 웹에서 Hello World를 출력하는 펑션을 개발해보자.

예제 코드

Index.js 에 다음과 같은 코드를 작성한다


exports.helloworld = function helloworld (req, res) {

       switch(req.method){

         case 'GET':

          res.send('Hello world');

       }

};

위의 코드는 helloworld 라는 이름의 펑션으로 HTTP GET 요청이 들어왔을때, ‘Hello world’ 문자열을 출력하도록 하는 펑션이다.

배포 하기

배포는 크게 Web UI와 CLI (Command Line Interface) 두 가지로 할 수 있다.

배포에 앞서서, 먼저 GCS (Google Cloud Storage) 버킷을 생성해야 한다. 클라우드 펑션은 배포 코드를 클라우드 스토리지 버킷에 저장해놓고 (스테이징 용도) 배포하기 때문이다.


클라우드 스토리지 버킷은 Web UI에서도 생성할 수 있지만 간단하게 CLI 명령을 이용해서 다음과 “terrycho-cloudfunction”이라는 이름의 버킷을 생성한다


%gsutil mb gs://terrycho-cloudfunction

Command Line Interface (CLI)로 배포하기

CLI로 배포하기 위해서는 CLI 명령인 gcloud 명령을 업그레이드 해야 한다. 다음 명령을 수행하면 쉽게 업그레이드할 수 있다.

% gcloud components update beta

% gcloud components install


다음 배포 명령을 실행해보자

% gcloud beta functions deploy helloworld --stage-bucket gs://terrycho-cloudfunction --trigger-http



Web Console로 배포하기

또는 Web Console을 이용할 수 도 있다.

다음은 helloworld 펑션을 us-central1 리전에 128M 메모리 사이즈로 배포하는 화면이다

코드는 ZIP 파일로 직접 업로드 하거나 구글 클라우드 스토리지에 ZIP으로 업로드 하거나 또는 아래 그림과 같이 inline editor에 간단한 코드는 직접 넣을 수 있다.


그리고 마지막으로 export할 모듈명을 정의한다.




실행하기

클라우드 펑션을 배포 하였으면 이제 실행해보자

HTTP 펑션이기 때문에 HTTP URL을 알아야 하는데,  HTTP URL규칙은 다음과 같다.


https://[리전이름]-[프로젝트이름].cloudfunctions.net/[펑션이름]                             


앞에서 만든 펑션은 us-central1에 배포하였고, 프로젝트명은 terrycho-sandbox이고 펑션 이름은 helloworld 이기 때문에 URL과 실행 결과는 다음과 같다


모니터링

모니터링은 CLI와 웹콘솔 양쪽으로 모두 가능하지만 웹 콘솔에서 로그를 확인해보겠다. 펑션 화면에서 펑션을 선택한 후에 우측 메뉴에서 아래 그림과 같이 “See logs”를 누룬다.


로그를 확인해보면 다음과 같다.



펑션이 시작된 것을 확인할 수 있다. 7d로 시작하는 펑션과 de로 시작하는 펑션 인스턴스 두개가 생성된 것을 볼 수 있고 7d로 시작된 펑션의 실행 시간이 702 ms가 걸린것을 확인할 수 있다.

가격 정책

가격 정책 계산 방법은


(가격) = (호출 횟수) + (컴퓨팅 자원 사용량 ) + (네트워크 비용)


으로 구성된다.

  • 호출 횟수는 클라우드 펑션이 호출되는 횟수로 한달에 2백만건까지 무료이며 2백만건 이후로는 백만건당 0.4$ 가 부과 된다.

  • 컴퓨팅 자원은 사용한 메모리와 CPU 파워를 기반으로 100ms 단위 과금이다.


    예를 들어 1.4GHz CPU 1024MB 메모리를 250 ms 사용했다면, 컴퓨팅 자원 사용 비용은 0.000001650 * 3 (250ms는 올림하여 300ms로 계산한다.)

  • 네트워크 비용은 들어오는 비용은 무료이며 인터넷으로 나가는 비용에 대해서만 월 5$를 부과한다.

무료 티어

무료 티어는 매달 2백만콜에 대해서 400,000GB 초, 200,000GHZ 초의 용량 + 5GB 아웃바운드 트래픽에 대해서 무료로 제공한다

결론

사실 클라우드 펑션과 같은 서버리스 서비스는 새로운 기술은 아니다.

그러나 구글 클라우드 플랫폼과 연계되어서, 간단한 HTTP 서비스 개발은 물론, GCS에 저장된 파일에 대한 ETL 처리등 다양한 분야에 사용이 가능하며

특히나 타 클라우드 대비 특징은, 모바일 SDK 파이어베이스의 백앤드로 연동이 가능하기 때문에 모바일 개발자 입장에서 복잡한 API 인증등을 개발할 필요 없이  간단하게 서버 백앤드를 개발할 수 있다는 장점을 가지고 있기 때문에 개발 생산성 향상에 많은 도움이 되리라고 본다.


구글 클라우드 MySQL서비스의 흥미로운 가격 정책

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


구글 클라우드의 MySQL 서비스인 CloudSQL을 보다보니, 신기한 가격 정책이 있어서 정리해놓고자 한다.

1세대와 2세대의 가격 정책이 다른데, 1세대의 가격 정책이 재미있는점이 있다.


기본 가격 정책


1,2세대 모두 기본 적인 가격 정책은 다음과 같다


저장량 + 인스턴스 기동 비용 + 네트워크 비용

  • 저장량은 말 그대로 저장된 데이타의 양에 따라 과금이 된다
  • 네트워크 비용은 outbound로 나가는 트래픽만 과금이 되는데, 이것도 같은 리전 안의 구글 클라우드에서 호출하는 경우에는 과금이 되지 않는다. 과금이 되는 경우는 구글 클라우드를 쓰더라도 다른 대륙의 인스턴스가 호출을 하거나 또는 다른 클라우드 서비스에서 호출을 하는 경우에만 과금이 되기 때문에, 일반적인 상황에서는 거의 네트워크 트래픽 비용이 과금이 되지 않는다.
  • 인스턴스 기동 비용은 인스턴스가 떠있는 동안데 받는 비용인데 이 부분이 흥미롭다.
인스턴스 가동 비용

1세대 CloudSQL 경우 Package plan 과 Pay per use plan 두가지가 있다.
Package Plan은 일단위 과금이며, 인스턴스가 기동이 되어 있는 일 기준으로 과금이 된다. 이건 모 일반적인 것이고
흥미로운 가격 정책이라고 하는것은 Pay per use plan이다. Pay per use plan은 인스턴스가 떠 있는 시간동안 분당 과금을 하는 것이다. 일반적인 분당 과금 처럼 보일 수 있지만 재미 있는 것은 Cloud SQL 인스턴스 생성시 activation policy (활성화 정책) 이라는 것을 설정할 수 있는데, 이 활성화 정책을 ALWAYS(항상) 으로 해놓으면, 인스턴스를 수동으로 내리지 않는 이상은 항상 떠 있는 케이스이다. 여기까지가 일반적인것이고
활성화 정책중 ON DEMAND(요청시)로 해놓으면, MySQL이 15분 동안 아무 Request가 없으면 해당 MySQL 인스턴스는 자동으로 비활성화 되고 인스턴스 비용이 과금되지 않는다. 비활성화 상태에서 요청이 들어오면 자동으로 활성화 상태가 된다. ON DEMAND는 활성화 상태에서 사용량을 분당으로 과금한다.

아래 그림은 CloudSQL 인스턴스를 생성할때, ON DEMAND 활성화 정책 + 사용량에 따른 청구 방식으로 설정하는 화면이다.




쉽게 설명하면, 서버에 요청이 없으면 자동으로 대기 상태로 들어가면서 데이타 저장 비용만 과금이 되고, 인스턴스 비용은 과금이 되지 않는다는 이야기이다.

이는 항상 서버가 돌아도 되지 않는 일 배치나 또는 개발 환경등에 유용하게 사용될 수 있다. 
물론 이렇게 인스턴스가 될때만 과금하게 하는 것은 수동으로 데이타를 백업 받고 인스턴스를 내렸다가 사용할때 인스턴스를 새로 올리고 데이타를 부어도 되고 또는 수동으로 일일이 인스턴스를 껐다 켰다 해도 유사한 효과를 볼 수 는 있지만, AWS의 경우 시간당 과금이기 때문에, 개발 환경처럼 수분을 쓰고 마는 환경에서는 분당 과금인 CloudSQL에 비해서 금액 절약효과를 보기가 어렵고, 무엇보다 귀찮다.

아래는 20GB 용량을 하루에 4시간 정도 D32 인스턴스로(32GB 메모리 머신) , 300만 IO가 발생하는 일배치를 돌리는 시나리오에서 추가 IO가 없다고 가정할때 가격 시뮬레이션 한 케이스인데 Package plan을 이용할 경우 약 한달에 1116$, Pay per use plan을 사용할 경우 약 338$ 로 약 3.4배 정도의 가격 차이가 있는 것을 확인할 수 있다. 
(참고, Package Plan의 D32 인스턴스는 300만 IO까지는 무료이며, Pay Per Plan의 경우 무조건 100만건당 0.1$가 과금된다. 아래 계산 결과는 Pay per use는 모든 IO 가 과금이 되기 때문에 # of IO를 300만으로 입력하였고, Package Plan은 무료 IO를 넘는 부분에 대해서만 입력하기 때문에, 현재 계산에서 300만 IO는 D32 인스턴스 크기에서는 무료이기 때문에 별도 입력하지 않았다.)




1세대의  Pay per use plan을 사용하면 딱 트렌젝션을 돌릴때만 분당 과금을 할 수 있기 때문에 가격이 저렴해진다.
단 주의 할점은 오랜 시간 서버를 돌리는 경우에는 Pay per use plan 보다는 당연히 Package plan이 저렴하기 때문에 일정 시간 이상 인스턴스를 사용하는 경우는 Pay per use 보다는 package plan을 사용하기 바란다.

가격 정책에 대한 자세한 내용은 https://cloud.google.com/sql/pricing 에 있다. 
어떤 정책이 유리한지는 가격 시뮬레이션을 해보면 되는데 시뮬레이션용 계산기는 https://cloud.google.com/products/calculator/ 를 사용하기 바란다.



구글 CloudSQL(MySQL) 접속하기

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


개요 


구글 클라우드에서는 MySQL의 매니지드 서비스 형태로 CloudSQL 서비스를 제공한다. 

이 글에서는 CloudSQL을 서버에서 접근하는 방법과, 일반적인 MySQL 클라이언트로 접근하는 방법에 대해서 설명하고자 한다.


몇가지 배경


CloudSQL은 매니지드 MySQL서비스이다. 아마존에 RDS서비스와 같다고 보면 되는데 현재는 1세대를 서비스하고 있고, 곧 2세대가 서비스 예정이다.

1세대는 500GB까지의 용량까지 지원하고 있지만 2세대는 10테라까지 지원을 한다.

현재 지원되는 MySQL버전은 5.5와 5.6 지원하고, 내부 엔진으로는  InnoDB만을 제공한다.


2 세대에 기대되는 기능으로는 On Prem(호스팅 센터에 있는) MySQL과 복제 구성이 가능하다. On Prem에 있는 서버를 마스터로 할 수 도 있고, 반대로 마스터를 CloudSQL로 사용하고 읽기 노드를 On Prem에 구성하는 등 다양한 하이브리드 구성이 가능하다. (기대되는 부분)


자동 백업, 확장을 위한 읽기 전용 노드 (Read replica)등 필수적인 기능을 제공하고 있다.


연결 방식


CloudSQL은 RDS와는 다르게 private ip (10.x.xx)를 아직 지원하지 않고 public ip만을 지원한다. 그래서 서버에 접근하려면 이 public ip를 통해서 접근하면 된다. 보안을 위한 접근 통제 방법으로 특정 IP 주소에서 들어오는 트래픽만을 받아드리도록 설정이 가능하다.


또는 PaaS서비스인 구글 앱앤진을 사용하는 경우에는 구글 앱앤진의 인스턴스나 그룹 단위로 접근 통제가 가능하다.

다음 그림은 콘솔상에서 접근이 가능한 IP 주소를 지정하는 화면이다.



MySQL 클라이언트를 이용하여 접속을 할때 mysqlclient를 이용하여 직접 ip등을 입력하고 접속을해도 되지만 이 경우에는 CloudSQL에서 Ip를 허용해줘야 하기 때문에 개발이나 기타 운영 환경등에서 IP 주소가 바뀌면 그때 마다 설정을 해줘야 하기 때문에 불편할 수 있다.

이를 조금 더 편하게 하려면 mysqlclient를 사용하지 않고 구글에서 제공하는 "gcloud" 라는 도구를 이용하면, 별도로 접속 IP를 열지 않더라도 접속이 가능하다.

접속 방법은 먼저 gcloud  명령어를 인스톨 한 후에 


$ gcloud config set project [클라우드 프로젝트 이름]

$ gcloud beta sql connect [CloudSQL 인스턴스이름] —user=root

(여기서 --user=root 에서 root 사용자는 MySQL 인스턴스내의 사용자이다)


으로 접속하면 MySQL 클라이언트와 동일한 툴로 접속이 된다.


gcloud 툴킷을 이용한 자세한 접속 방법은 https://cloud.google.com/sql/docs/mysql-client#connect-ssl 를 참고하기 바란다.


참고

  • Toad, MySQL Workbench 등에서 안전하게 연결하는 방법 https://cloud.google.com/sql/docs/admin-tools#squirrel


Auto scaling out

클라우드 컴퓨팅 & NoSQL/Amazon Web Service | 2013.09.11 00:17 | Posted by 조대협

 

클라우드 컴퓨팅 서비스에서 서비스의 부하량과 사용량에 맞게 탄력적으로 컴퓨팅 자원을 늘렸다가 줄였다 하는 auto scaling 기능은 기존의 인프라가 가지지 못한 큰 장점 중의 하나이다. 아마존 클라우드 서비스는 이 auto scaling 기능을 서비스로 제공하고 있다.

 

Auto scaling의 기본 개념

아마존에서 제공하는 auto scaling의 기본 개념은 다음과 같다.

여러 개의 EC 인스턴스들을 auto scaling group이라는 하나의 그룹으로 묶어 놓는다. 그리고 각 인스턴스들은 ELB 로드 밸런서를 통해서 로드가 분산된다.

이 그룹을 Cloud Watch라는 아마존의 클라우드 모니터링 솔루션을 통해서 자동으로 감지하게 되는데, 사용자가 정의 해놓은 일정한 조건 (예를 들어 평균 CPU 사용율이 80% 이상이 5분 이상 지속)이 되면, Auto Scaling 기능을 동작 시키도록 설정해놓을 수 있다.

그러면 auto scaling 기능이 auto scaling group 내에서 사용되고 있는 동일한 VM 이미지를 스토리지로 부터 읽어서, 미리 규칙에 정해 놓은 인스턴스 크기에 수 만큼 인스턴스를 자동으로 추가하고 ELB에 연결한다.

 그리고 반대로 리소스의 사용량이 일정 상항 아래로 내려가게 되면 정해진 규칙에 따라서 EC2 인스턴스를 자동으로 제거하낟.

 


Amazon에서 Auto scaling 설정하기

1) Launch configuration 정의 하기

여기서는 Auto Scaling이 발생했을때, Scaling out 되는 인스턴스를 정의 한다. 어떤 크기의 인스턴스(인스턴스 타입)를 어느 AMI 이미지로 띄울지, EBS Block 디바이스 맵핑,Security Group등이 포함된다.

as-create-launch-config launch-config--image-id ami-00797213 --instance-type m1.large

 

2) Auto scaling group 정의 하기

다음으로는 Auto Scaling group을 정의 한다. group auto scaling이 될 EC2 인스턴스들이 정의 되는 일종의 그릇이다. group이 어느 availability zone (여러개의 Zone에 걸쳐서 정의 가능)들에 걸쳐서 정의 될지, 그리고 group 내에서 유지되는 최소,최대 ec2 인스턴스의 수를 정의하고, 앞에서 정의한 Launch configuration을 정의 함으로써 group 안에 생성되는 ec2 인스턴스의 타입을 정의한다.

as-create-auto-scaling-group TestGroup --launch-configuration MyLC --availability-zones us-east-1a --min-size 1 --max-size 1

min, max 값이 중요한데, min 값의 경우 cloud watch등으로 group내를 모니터링 하다가 ec2 인스턴스가 예측하지 못한 장애등으로 shutdown되었을 경우, 자동으로 Launch configuration에 정의된 EC2 인스턴스를 group내에 생성한다..

 

3) Auto scaling policy

다음은 Auto scaling이 일어나는 방식을 정의 한다. Policy라는 것으로 정의 하는데,Auto Scale out 이 발생할 때, 몇 개의 instance를 늘릴 것인지, 반대로 scale in이 발생할 때 몇개의 인스턴스를 줄일 것인지를 정의 한다. 개수로 정의할 수 도 있고, %로 정의할 수 도 있다.

 

예를 들어 30%의 인스턴스 수 만큼 늘리는 scale out 정책을 정의하면

Ÿ   Policy name = my-scaleout-policy

Ÿ   Auto Scaling group name = my-test-asg

Ÿ   Adjustment = 30

Ÿ   Adjustment type = PercentChangeInCapacity

다음과 같은 CLI 명령어를 이용해서 정책을 정의 한다.

as-put-scaling-policy my-scaleout-policy -–auto-scaling-group ASG --adjustment=30 --type PercentChangeInCapacity

명령을 실행하면 리턴 값으로 ARN 코드라는 것을 다음과 같이 리턴하는데,

arn:aws:autoscaling:us-east-1:987654321012:scalingPolicy:af521352-c2e3-8291-811b-a2a34asdfaf8a:autoScalingGroupName/ ASG:policyName/my-scaleout-policy

나중에 이 ARN 코드를 뒤에서 정의할 Action에 정의 하여, Scale Out이 발생할때, 이 정책에 따라서 인스턴스 수를 늘리도록 하낟.

 

4) Scaling condition (action)

그리고 마지막으로 Auto Scaling이 일어나는 조건 (시점)을 정의 한다.

Cloud Watch Alarm 기능을 이용하는데, Cloud Watch의 특정 모니터링 Matrix이 일정 조건을 만족하면 앞에서 정의한 Scaling policy에 따라서 인스턴스를 늘리거나 줄이도록 한다.

먼저 Cloud Watch에서 Alarm을 정의 한다.

Ÿ   Alarm name = AddCapacity

Ÿ   Metric name = CPUUtilization

Ÿ   Namespace = "AWS/EC2"

Ÿ   Statistic = Average

Ÿ   Period = 120

Ÿ   Threshold = 80

Ÿ   Comparison operator = GreaterThanOrEqualToThreshold

Ÿ   Dimensions = "AutoScalingGroupName=my-test-asg"

Ÿ   Evaluation periods = 2

위의 정의는 EC2 CPU의 평균 값이 80 이상으로 120초 이상 지속 될 경우 Alarm을 발생하도록 하고, 다음과 같이 Alarm이 발생하였을 때 앞에 정의한 policy를 수행할 수 있도록 아래와 같이 ARN값을 binding 시킨다.

Ÿ   Alarm action = arn:aws:autoscaling:us-east-1:123456789012:scalingPolicy:ac542982-cbeb-4294-891c-a5a941dfa787:autoScalingGroupName/ my-test-asg:policyName/my-scaleout-policy

 

이렇게 alarm 방식으로 scaling 하는 것 이외에도, Schedule에 따라서 scaling도 가능하다.

예를 들어 축구 경기가 있는날 치킨집 주문 시스템을 scale out 해놨다가 축구가 끝난후 2시간후 scale in 하거나, 월말 마감이 있는 시스템의 경우 매달 마지막 주에 scale out을 해놓는 시나리오등이 가능하다. Schedule 기반의 scalingas-put-scheduled-update-group-action 명령어를 이용해서 정의 하면 된다.

다음과 같이 특정 시간을 지정하는 방식을 사용할 수도 있고

Ÿ   Name of your scheduled action = ScaleOut

Ÿ   Auto Scaling group name = my-test-asg

Ÿ   Desired Capacity = 3

Ÿ   Start time = “2013-05-12T08:00:00Z”

또는 Unix Cron과 같이 특정 반복 패턴 별로 scaling을 할 수 있다

Ÿ   Name of your scheduled action = Scaleout-schedule-year

Ÿ   Auto Scaling group name = my-test-asg

Ÿ   Desired Capacity = 3

Ÿ   Recurrence = “30 0 1 1,6,12 0”

 

Amazon의 다른 인프라와 연계 하기

ELB 연동

VPC 연동

IP 연동

 

주의 할점

AMI 이미지에서 initialize configuration (startup script)를 잘 정의 해 놓을 것.

Zoo Keeper를 이용한 확장도 고려해볼만 함.

IP가 자기맘대로 지정되기 때문에, 제니퍼와 같은 고정 ip 솔루션 적용이 어려움

 

 

아래 참고 자료

--

ELB에 어떻게 꼽을까요?

http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/US_SetUpASLBApp.html

AutoScaleGroup을 만들때, LoadBalancerNames.member.1 = my-test-asg-loadbalancer parameter를 넣어서, auto scaling out group load balancer binding이 가능함.

 

ELB autoscaling group에 대해서 health check로 사용하려면

Ÿ   Auto Scaling group name = my-test-asg-lbs

Ÿ   Health check type = ELB

Ÿ   Health check grace period = 300

 

group 생성시, health check type ELB로 지정 가능

as-update-auto-scaling-group my-test-asg-lbs –-health-check-type ELB  –-grace-period 300 

 

 

 

IP는 어떻게 배정 할까요?

- EIP를 사용할 경우에는 EIP Pool에서 fetch에서 가지고 올 수 있음

- VPC에는 명시적으로 IP를 지정할 수 없음. auto scaling out 그룹에 subnet을 지정할 수 있음. 그러면 해당 subnet의 주소를 물고 올라옴

as-create-auto-scaling-group myvpcasgroup --launch-configuration myvpclc --availability-zones 
"us-east-1b,us-east-1a" --min-size 0 --max-size 10 --desired-capacity 10 --vpc-zone-identifier 
"subnet-610acd08,subnet-530fc83a"

 

VPC의 경우 ip 주소가 변경된다. 그래서 고정 ip를 이용해서 모니터링 해야 하는 jennifer등을 사용시에는 문제가 있을 수 있기 때문에, fix ip를 사용하는 instance auto scale out instance를 같이 합쳐서 사용하는 것이 좋다.

 

멀티 존의 경우 어떤 순서로 생기나요?

 

자세한 configuration 자료는 http://awsdocs.s3.amazonaws.com/AutoScaling/latest/as-qrc.pdf 를 참고

 

auto scale out 은 초기 설정은 복잡하지만 한번 해놓으면 거의 반복해서 재활용이 가능.

CPU 보다는 JMX 기반으로 thread count, 기타 factor를 사용하여 정교화 하는 것이 좋음

 

 

'클라우드 컴퓨팅 & NoSQL > Amazon Web Service' 카테고리의 다른 글

Auto scaling out  (1) 2013.09.11
Amazon의 CDN 서비스 Cloud Front  (0) 2013.09.10
Amazon Route 53 DNS 서비스  (0) 2013.09.09
Amazon Elastic Load Balancer  (2) 2013.09.09
Amazon Direct connect  (0) 2013.09.06
Amazon VPC (Virtual Private Cloud) 소개  (3) 2013.08.18

Cloud Front

조대협

Cloud Front CDN (Contents Delivery Network) 서비스 이다. 이미지나 동영상 같은 정적인 컨텐츠들을 서비스하는데, 서버가 있는 데이타 센터에서 서비스를 하게 되면, 네트워크 latency 때문에 성능이 저하가 되기 때문에, 전세계의 여러 개의 데이타 센터에 서버(이를 edge node 또는 edge server라고 함) 를 넣고, 클라이언트와 가까운 데이타 센터로 부터 컨텐츠를 제공하는 서비스 이다.

얼마나 많은 지역별 데이타 센터에 edge node를 설치하고 서비스를 제공하느냐, edge node의 네트워크 대역폭이나 용량은 충분하느냐가 서비스의 품질을 결정하는데, 세계적으로 Akamai Limelight 등의 업체가 유명하다.

아마존의 경우에도 얼마전부터 Cloud Front라는 이름으로 CDN 서비스를 제공하는데, 아마존 인프라와 융합되어 몇 가지 특별한 기능들을 제공한다.

아래 http://media.amazonwebservices.com/FS_WP_AWS_CDN_CloudFront.pdf 그림은 Frost & Sullivan 이라는 곳에서 작성한 CDN의 성능 비교표로, 아마존 Cloud Front가 다른 경쟁사에 비해서 성능적으로 우세거나 동등 수준으로 나온다. 물론 테스트 환경이나 시나리오에 따라 다소 다르겠지만, 아마존도 계속 해서 edge node를 증설하고 있는 상황이기 때문에 상용 수준의 CDN 성능을 제공할 수 있을 것이라고 본다.



 

Cloud Front 동작 시나리오

그럼 먼저 Cloud Front가 어떻게 작동하는 지를 살펴보도록 하자.



   Client가 웹사이트에 접속한다. 웹사이트를 www.terry.com이라고 하자.

   Client DNS 서버를 통해서 www.terry.com 의 주소를 look up 한다. 이 때, www.terry.com cloud front URL로 맵핑이 되어있어야 하는데, CNAME 레코드를 이용하여 www.terry.com을 해당 사이트에 대한 Cloud Front URL 로 맵핑 해놓는다. 여기서는 asdf.cloudfront.net이라고 가정하자

   Client asdf.cloundfront.net 의 주소를 다시 look up을 하는데, Route53에 의해서, Client와 가장 가까운 위치에 있는 Cloud Front edge node 주소를 리턴 받게 된다.

   Client는 리턴 받은 ip를 가지고 Cloud Front edge server로 접속을 한다.

   Cloud Front에는 URL에 따라서 resource의 위치를 RULE로 정해놓는데, 위의 예에서는 /image 디렉토리의 파일은 S3에 원본을 두고 Cloud Front에 캐슁하도록 하고, /css/ 아래 파일들은 원격지에 있는 (Amazon이 아닌) 서버에 두고 캐슁을 하도록 하였다. 그리고 *.jsp 파일은 캐슁 없이 직접 원본 서버로 가도록 하였다.

   만약에 /image/ /css/에 있는 파일을 Client가 요청 하였을 경우 edge node의 캐쉬를 체크해보고, 캐쉬에 내용이 없으면 원본 서버로 부터 파일을 읽어서 캐쉬에 저장한 후에, Client에 리턴한다. 캐쉬에 있을 경우에는 바로 리턴을 한다.

Origin Server

앞에서 설명한 시나리오에서 원본 파일이 저장되는 곳을 Origin Server라고 한다.

Origin Server AmazonS3 bucket이나 EC2 인스턴스 또는 Amazon 밖의 서버가 될 수 있다.

서비스가 가능한 컨텐츠의 종류

Cloud Front를 통해서 서비스가 가능한 컨텐츠의 종류는 다음과 같다.

Ÿ   Download Distribution : HTTP 프로토콜을 이용해서 다운로드 받을 수 있는 이미지나 기타 정적인 리소스 파일

Ÿ   Streaming Distribution : HTTP Progressive Down load RTSP(Real Time Streaming Protocol)을 지원하는 동영상 컨텐츠

Cache 동작

CDN은 기본적으로 컨텐츠를 edge node에 캐쉬 해놓는 것을 기능으로 한다. 캐쉬이기 때문에 유지 시간 TTL이 있는데, 기본 TTL 시간은 24시간이고 최대 1시간으로 까지 줄일 수 있다.

그런데 만약 파일을 잘못 올렸거나, 수정이 필요할 때 캐쉬의 TTL 시간에 의해서 수정이 edge node에 반영되는 시간까지 최소 1시간이 소요된다.

이런 문제를 해결하기 위해서 Cloud Frontinvalidation API (특정 파일을 캐쉬에서 지우는 기능)을 제공하는데, 한번에 3개의 invalidation request밖에 실행할 수 없으며, invalidation request는 최대 1000개의 파일까지만 지원한다. 그리고 invalidation request는 모든 edge node에 반영되어야 하기 때문에, 보통 5~10 분 정도의 시간이 소요된다.

그래서 조금 더 빠르게 캐쉬에서 컨텐츠를 업데이트 하기 위해서는 버전을 사용하기를 권장하는데, 쉽게 이야기 해서 파일명을 바꾸도록 하는 것이다. /image/photo.png가 있을때, 이 파일이 변경되기를 원할 경우, HTML 원본에서 해당 이미지 명을 /image/photo_v2.png로 변경하고,새로운 파일명도 photo_v2.png로 저장을 하면 별도의 cache invalidation 작업 없이 바로 변경 내용을 반영할 수 있다.

 

또는 파일명을 바꾸는 게 부담 스러울 경우에는 Query String을 사용할 수 있다.

예를 들어 /image/photo.png?version=1.0 으로 HTML에서 이미지 경로를 걸어 놓으면, Cloud Front "photo.png?version=1.0"을 키로 캐쉬에 파일을 저장한다. Origin server에 이렇게 파일을 요청하게 되면, 이 파일은 정적인 컨텐츠이기 때문에, Query String은 무시 되고, Origin Sever "photo.png" 파일만 리턴한다. 원본 컨텐츠가 바뀌었을 경우, 원본 컨텐츠의 파일명은 변환할 필요가 없이 똑같이 "photo.png" 파일로 저장을 하되, HTML의 참조명을 /image/photo.png?version=2.0으로만 바꿔 주면, Cloud Front입장에서는 resource의 이름이 아까와 다른 이름이기 때문에, Cache에서 찾지 못하고 다시 Origin Server로 요청하게 된다

(Query String을 버전명으로 사용하기 위해서는 Cloud Front설정에서 Query String by pass 기능을 on 해줘야 한다.)

비공개 컨텐츠에 대한 접근 제어

다음으로 이런 정적인 컨텐츠를 다루다 보면 특정 사용자에게만 서비스를 제공해야 하는 경우가 있다. 예를 들어 유료 앱 다운로드나, 유료 동영상 서비스같은 것이 좋은 예가 되는데, Cloud Front Signed URL이라는 기능을 이용해서, CDN 컨텐츠에 대한 접근 제어 기능을 제공한다.

원리는 간단하다. CDN의 특정파일에 대한 접근 권한을 {ip 주소, 다운로드 가능 시간 시작~} (접근 권한의 각 필드는 필수가 아니라 선택 사항이다. 또한 ip 주소는 특정 ip ip 주소 대역으로도 정할 수 있다.) 으로 정하고, URL을 생성한 후 암호화 하여 사용자에게 제공하는 것이다.

그러면 그 URL CDN내의 컨텐츠를 접근하면, 접근 권한에 정의된 조건을 충족하면 다운로드를 할 수 있도록 해준다.

아래는 아마존 웹사이트에서 발췌한 Signed URL 샘플이다.


1) 이 부분의 resource 파일명을 정의한다.

2),3) Query String을 정의 하는 부분이다. 원본 파일(Origin Server)로 전달되는 Query String이다.

4) Policy 로 앞에서 언급한 접근 가능 정책 {ip 주소, 접근 가능 기간} JSON으로 정의한후에 encoding string이다.

5) HMAC과 유사하게 이 URL이 변조되는 것을 막기 위해서 URL에 대한 Signature Base64 encoding을 이용해서 생성해서 붙인 부분이다. (일종의 Hash값으로, URL에 대한 Hash URL이 변조되면 이 Hash 값과 맞지 않는다.)

6) Key로 아마존 Cloud Front 사용을 위해서 발급된 키이다.

Signed URL 이외에 사용자 계정을 통해서 접근을 제어할 수 있는 방법이 있는데, 이 계정은 아마존 계정 서비스인 IAM을 통해서 생성된 계정만을 통해서만 가능하다. 참고로 IAM 계정 서비스는 최대 5000개의 계정만 생성 및 관리가 가능하기 때문에, 대외 서비스에는 적절하지 않고, 소규모 대내 서비스나 또는 내부 관리 용도로 CDN 접근 제어를 할대 유용하게 사용할 수 있다.

부가적인 기능

그 밖에도 몇가지 부가적인 기능들이 있다. SSL을 통해서 컨텐츠를 서비스 하는 기능이나, 또는 컨텐츠 서비스 내용을 HTTP access 로그로 남겨서 S3에 저장하는 기능들이 있다.

성능 향상 방법

Cloud Front를 사용하는데 있어서 몇 가지 성능을 향상 시킬 수 있는 테크닉이 있어서 소개하고자 한다.

1) Domain Sharding : 일반적으로 웹브라우져는 하나의 도메인 주소에 대해서 동시에 열 수 있는 네트워크 Connection 수가 제한이 있다. IE7의 경우에는 한 도메인당 2, Chrome IE8/9 6, Fire Fox의 경우에는 8개이다. 그런데 일반적인 웹 페이지에서 동시에 로딩되는 리소스는 대략 20~50개 정도가 된다.즉 웹브라우져가 여는 Connection 수로는 한꺼번에 모든 리소스 로딩이 어렵다는 것이다. 일반적인 CDN에서도 적용될 수 있는 기법인데, 하나의 시스템에 여러개의 도메인을 적용하는 것이다. 예를 들어 서버의 주소가 210.113.119.210 이라고 하고, 도메인 명이 www.terry.com 이라고 하자.CNAME으로 image.terry.com, resource.terry.com, css.terry.com 등 여러개의 도메인을 같은 URL을 가리키도록 해놓고, HTHL에서도 image url "src="http://image.terry.com/img/myimage.png" 식으로 지정해놓게 되면 브라우져 입장에서는 전혀 다른 사이트로 인식하기 때문에, 별도의 네트워크 Connection을 열 수 있다. 이 방법을 사용하면 브라우져의 Connection을 최대로 열어서 전체적인 웹사이트 Loading Time을 증가시킬 수 있다.

 

2) Compression : CDN은 네트워크에 관련되는 서비스이기 때문에 당연히 원본 컨텐츠의 사이즈가 작으면 성능이 사용하는 대역폭도 작아지고, 성능도 더 잘 나온다. 압축 기능을 사용하기 위해서는 Origin server apache와 같은 웹서버인 경우에는 gzip compression 기능을 웹서버에 적용해주면 되지만, S3 Origin server로 사용하는 경우에는 S3 자체에는 gzip compression 기능을 가지고 있지 않기 때문에, 컨텐츠를 할때 gzip으로 압축해서 올리고 "Content-Encoding" gzip으로 명기해주면 된다.

 

가격 체계

Cloud Front edge node의 위치에 따라서 가격이 다르다. 과금은 Out bound traffic을 기준으로 하는데, 아래 그림과 같이 South Africa가 다른 region에 비해서 가격이 월등하게 비싸다. Cloud Front를 사용하기 전에, 먼저 서비스를 하고자 하는 국가등을 미리 고려한 후에, 가격과 함께 사용지역을 고려하기를 권장한다.



'클라우드 컴퓨팅 & NoSQL > Amazon Web Service' 카테고리의 다른 글

Auto scaling out  (1) 2013.09.11
Amazon의 CDN 서비스 Cloud Front  (0) 2013.09.10
Amazon Route 53 DNS 서비스  (0) 2013.09.09
Amazon Elastic Load Balancer  (2) 2013.09.09
Amazon Direct connect  (0) 2013.09.06
Amazon VPC (Virtual Private Cloud) 소개  (3) 2013.08.18

Amazon Route 53 DNS 서비스

조대협

Route53은 아마존에서 제공하는 DNS 서비스 이다. 일반 DNS와 다르게 몇 가지 아마존에 특성화된 몇 가지 기능을 가지고 있는데, 특화 기능에 앞서서 DNS 의 일반 개념을 먼저 정리해 보자.

DNS domain name (www.example.com) ip 주소로 바꿔 주는 일종의 dictionary 서비스 이다.

이러한 맵핑 정보를 저장해 놓는 파일을 DNS Zone file이라고 한다.

 

이 서비스는 DNS 서버에 저장해놓은 파일을 기반으로 주소를 변환하는데, 여기에 정의되는 레

코드들 중에서 대표적은 레코드는 다음과 같다.

 

   SOA 레코드 : 해당 DNS 서버 자체의 설정 정보를 정의 한다.

Ÿ   DNS 서버는 Primary/Secondary 구조로 장애 대응을 할 수 있는 구조인데, 이를 위해서 SOA 레코드에는 이를 위한 설정이 반영되어 있다.

Ÿ   serial # - revision # Zone 파일이 업데이트 될때 마다 증가하는 일종의 버전

Ÿ   refresh - secondary server primary server로 부터 업데이트를 하는 주기

Ÿ   retry - primary server로 부터의 query가 실패하였을때, 다음 retry 까지 시간.

Ÿ   expire : secondary server에서 zone 파일을 유지 하는 시간

Ÿ   TTL : DNS 응답을 받아가는 서버가 해당 레코드 응답을 얼마나 유지해야 하는 TTL 시간

   NS 레코드 : DNS 서버가 참조하는 다른 DNS 서버이다. DNS 서버 자신에서 domain name에 대한 주소를 알아 내지 못할때, NS 레코드에 정의된 서버로 가서 주소를 알아dhsek.

   CNAME 레코드: 도메인명을 다른 도메인과 맵핑할때 사용 (일종의 alias)

   A 레코드:도메인을 ip로 맵핑

   PTR 레코드 : ip를 도메인으로 맵핑 (Reverse Zone에서 사용)

 

DNS 서버의 특성중에서 주의깊게 봐야 하는 특성은 캐슁이다.

보통 DNS 서버는 클라이언트가 사용하는 로컬 네트워크에 있는 DNS를 사용하게 된다. 회사 네트워크라면 회사내의 DNS 서버,집에서 사용하는 경우 해당 통신사의 DNS서버, 모바일을 사용할 경우, 해당 통신사의 DNS 서버를 사용한다. DNS 서버들은 look up을 요청한 목적 서비스 서버에 대한 ip 주소를 다른 클라이언트가 요청할 때 응답을 빠르게 하기 위해서 자체적으로 캐슁하고 있다.

예를 들어 구글의 A라는 서비스가 있다고 하자. 이 서비스 A는 구글의 DNS 서버에 주소가 정의되었을 것이다. 만약 한국의 사용자가 스마트 폰을 이용하여 이 서비스의 URL을 접근하게 되면, 해당 한국 통신사의 DNS 서버를 통해서 주소를 look up 하게 될 것이고, 이 한국 DNS 서버는 구글의 DNS 서버에 주소를 물어본 후에, 다음 서비스를 위해서 자신의 Cache를 업데이트 한다.

이 캐쉬가 지워지고 다시 업데이트 되는 시간이 TTL 시간인데, TTL은 이후에도 설명하겠지만, 동적으로 DNS 주소를 업데이트하거나 변경하였을때, 로컬의 DNS서버의 캐쉬가 업데이트 되지 않아서 실제 주소가 바뀌더라도 이전 서버의 주소를 리턴하는 경우가 있어서 주소 변경을 어렵게 한다.

이제 Route 53의 고유 기능을 살펴보도록 하자.

Health check & DNS Fail Over

Route53은 자체적으로 Health check 기능을 가지고 있다. 하나의 DNS 명에 대해서 multiple ip address return할 수 있는데, 해당 ip의 서버의 상태를 체크해서 장애 상태인 경우에는 list에서 제외하고, 장애가 복구 되면 다시 리스트에 추가하는 형태이다.

앞에서 언급했듯이 이 기능의 경우 local DNS들의 캐슁 때문에, Route53이 장애를 인지하고 바로 list에서 제외한다 하더라도 local DNS에서 캐쉬가 업데이트 되는 시간이 필요하기 때문에 바로 fail over는 되지 않는다. 되도록 빠른 fail over를 하기 위해서는 Route53에서 TTL 시간을 짭게 주는 것이 좋은데, 아마존의 경우 60초이하 의 값을 권장하고 있다.

Latency based routing

Route53의 기능 중에 상당히 흥미로운 기능중의 하나인데, Route53에 하나의 DNS 주소에 대해서 여러개의 서비스 ip binding 되어 있을 경우, Route53은 클라이언트로 부터 DNS 주소에 대한 look up 요청을 받았을 경우, 클라이언트로 부터 가장 빠른 응답시간을 보장하는 (거리가 가까운) 서버의 ip 주소를 리턴하는 기능이다.

 원리를 설명해보면 다음과 같다. 아마존 인프라는 각 데이타센터로부터 다른 ip주소 대역까지의 네트워크 latency 값을 주기적으로 수집해서 데이타 베이스화 해서 가지고 있다. 예를 들어 미국 아마존 데이타 센터에서 전세계에 대한 latency를 아마존을 가지고 있다. 한국,중국,유럽 등등. 이렇게 latency 자료를 가지고 있다가, DNS look up 요청이 오면, 요청을 한 클라이언트쪽의 ip를 기반으로 내부 데이타 베이스내의 latency를 체크해여 가장 가까운 아마존 데이타 센터의 ip를 리턴하게 되는 원리이다.

이 때 Route 53으로 request를 보내는 클라이언트는 end user browser나 모바일 기기등이 아니라 end user가 접속된 네트워크의 로컬 DNS 서버가 되게 된다.

 Latency based routing의 경우 로컬 DNS가 클라이언트가 접속하는 망내에 있는 것을 전제로 한다.

 

'클라우드 컴퓨팅 & NoSQL > Amazon Web Service' 카테고리의 다른 글

Auto scaling out  (1) 2013.09.11
Amazon의 CDN 서비스 Cloud Front  (0) 2013.09.10
Amazon Route 53 DNS 서비스  (0) 2013.09.09
Amazon Elastic Load Balancer  (2) 2013.09.09
Amazon Direct connect  (0) 2013.09.06
Amazon VPC (Virtual Private Cloud) 소개  (3) 2013.08.18

Amazon VPC (Virtual Private Cloud)

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


VPC Virtual Private Cloud의 약자로 아마존 클라우드 내에서 private ip를 사용하는 일종의 가상 private network 망을 만들어줄 수 있게 해주는 서비스이다.

이 서비스 전에는 EIP 이외에는 정적 서비스를 사용할 수 없었으며, 또한 10.0.x.x와 같은 private ip를 사용할 수 없었다. VPC 서비스와 함께, 내부 ip 대역을 사용할 수 있게 되었으며 조금 더 유연한 네트워크 관리가 가능하게 되었다.


VPC

VPC Amazon 콘솔에서 생성하면 되는데, VPC의 범위는 , 하나의 VPC는 하나의 Region내에서만 생성이 가능하다. VPC를 두개 이상의 region에 걸쳐서 사용이 불가능하다.단 하나의 VPC는 여러개의 Amazon Availibility Zone (이하 AZ) 에 걸쳐서 생성될 수 있다. 또한 하나의 VPC가 가질 수 있는 IP 주소의 Range 2^16 = 65535로 제한된다.

CIDR 표현으로 10.0.0.0/16 (10.0.0.0~10.0.255.255) 범위가 된다. CIDR에 대한 개념과 계산법은 http://www.subnet-calculator.com/cidr.php 계산기를 참고하기 바란다.


Subnet

VPC를 생성했으면, 각각의 Subnet을 생성해야 한다. Subnet의 범위를 다시 한번 보자.

VPC는 앞서 설명한것 처럼, 하나으 region내에서 여러개의 AZ에 걸쳐서 생성이 가능하다. VPC안에서는 여러개의 subnet을 생성할 수 있는데, 하나의 subnet VPC안에서 하나의 AZ에만 생성이 가능하다.



 

Route Table

subnet에는 default subnet과 밖을 연결해주는 router가 생성되고, router route table을 가지고 있다. 대상 ip address routing 경로를 정의하는 것으로 subnet에서 밖으로 나가는 outbound traffic에 대한 routing 경로를 정의한다. route table AWS 콘솔에서 설정이 가능하고, routing 경로는 target의 타입에 따라서, 크게 세가지로 분리할 수 있다.



Ÿ   *  Local : VPC 내의 다른 subnet으로 traffic routing 한다.

Ÿ   Internet gateway : internet gateway를 통해서, 외부 인터넷으로 trafficrouting 한다.

Ÿ   * Virtual private gateway : 관리자가 임의로 정의한 destination으로 trafficrouting한다. VPN 연결을 위한 VPN gateway 등이 그 예가 된다.


아래와 같이 설정을 해놓으면, 10.0.0.0~10.0.255.255 VPC 내부로 routing이 되고, 172.16.0.0~172.31.255.255 vgw-9628c9ff 라고 정의한 routerrouting이 된다.



또 다른 예를 보자.



이 경우에는 172.31.0.0~172.31.255.255는 내부 VPC 내로 routing이 되고, 이 외의 모든 traffic igw-0eab8665 (internet gateway로 정의했음) 을 통해서 외부 인터넷으로 routing이 되게 된다.

모든 subnet1개의 routing table을 가져야 하며, 하나의 routing table은 여러개의 subnet에 중복되서 적용될 수 있다.


Public subnet & Internet gateway

VPC 내에 생성되는 EC2 Instance 10.0.x.x와 같은 private IP이외에 Elastic IP(이하 EIP)를 통해서 일반 인터넷 주소인 pubic IP까지 총 2개의 IP를 가질 수 있다.

Subnet 내의 EC2 instance들이 직접 인터넷에 EIP를 통해서 in/out bound connection이 연결 가능한 subnet public subnet이라고 정의 하는데, in/outbound traffic internet gateway (이하 igw)를 통해서 이루어지며 콘솔에서 설정에 의해서 만들 수 있으며, 생성을 한후에, VPC attach한후, 사용하고자 하는 subnet routing table에 설정을 해주면 된다.



위의 그림과 같이 subnet에서 인터넷으로 traffic EC2 EIP를 통해서 router를 타고, router에 의해 정의된 routing 경로를 따라 internet gateway를 거쳐서 internet에 연결된다.


Private subnet & NAT

Public subnet이 있으면 당연히 private subnet도 있다. Private subnet EIP를 가지지 않고 private IP만 가지고 있으며, Internet으로의 in/outbound 연결이 불가능하며 단지 다른 subnet으로만 연결이 가능하다.



보통 일반적인 회사에서 private network을 구성할때 많이 사용하는 방법인데, private ip를 쓴다 하더라도, 외부 시스템으로의 접속이 필요한 경우가 있다. 예를 들어서 다른 서버와 connection을 하거나 patch를 읽어오는 것과 같은 outbound connection은 사용되는 경우가 많다. 일반 private network의 경우에는 outbound connection에 대해서 public ip binding 하여 연결을 제공하는 방식으로 NAT (Network Address Translator) 라는 장비를 사용하는데, Amazon에서도 마찬가지로 이러한 NAT를 이용해서, Private subnet 내의 instnaceinternet으로 나가는 outbound traffic이 지원될 수 있도록 한다.



NAT를 이용한다고 해서, 특별한 기능을 Amazon이 제공하는 것이 아니고, Software 기반의 NAT public subnet에 설치한후에, private subnet에서 인터넷으로 나가는 outbound traffic에 대한 routing 경로를 이 NAT를 통하게 하는 것이다.

조금 사용을 편리하게 하기 위해서, Amazon에서는 AMI 이미지 형태로 미리 NAT EC2 이미지를 제공하고 있기 때문에, 별도의 선호 제품이 없을 경우에는 이 이미지를 사용하면 된다.

http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html

보통 이 NAT를 사용할 경우, 전체 VPC에 대해서 한두개의 NAT만 사용하는 경우가 있는데, 애플리케이션이 private subnet에서 밖으로 나가는 outbound protocol이 많을 경우에 이 NAT 자체가 병목 구간이 될 수 있기 때문에, NAT에 대한 traffic을 수시로 확인하고 알맞은 용량으로 운영을 해야 한다.

또한 Amazon 내부 서비스라 하더라도, private ip가 아니라 public ip를 쓰는 경우가 많고 이 경우 private subnet에 있는 EC2 인스턴스들은 NAT를 거치기 때문에, Amazon 서비스에 대한 호출도 NAT를 사용함을 인지하고 NAT 용량을 체크해야 한다. (. S3 public ip만 제공한다. 그래서 private subnet에서 S3로의 traffic은 모두 NAT를 거치게 된다.)


VPN

먼저 VPN에 대해서 알아보자. VPN (Virtual Private Network) 서비스의 약자로, public(인터넷) 망을 통해서 회사의 private network 망에 연결하게 해주는 서비스 이다.

예를 들어 회사가 10.0.1.XX 대역의 네트웍을 쓰고 있고, 내가 집에서 노트북으로 회사의 네트웍에 접속하고자 한다고 하자. IP public internet ip 198.12.x.x 를 사용한다고 하자. 회사 네트워크는 private 망이기 때문에 접속이 불가능하다. 그래서 VPN gateway를 회사 네트웍과 내 PC에 설치해놓으면 가상으로 내 PC를 회사 네트웍과 연결하여 같은 네트워크 대역으로 사용할 수 있도록 해준다. 개인PC à 회사 private 네트웍 뿐만 아니라, 물리적으로 분리되어 있는 지역간의 사무실이나 네트웍까지 이 VPN 네트웍을 사용하면 하나의 private network으로 묶을 수 있다.



Amazon에서도 역시 VPN을 사용할 수 있는데, VPN을 사용하기 위해서는 VPN Gateway를 설치해야 한다. 직접 소프트웨어 기반의 VPN을 설치할 수 도 있지만, Amazon에서 제공하는 VPN을 사용할 수 도 있다. VPN은 그 보안 및 암호화 방법에 따라서 IPESC, IKE등 여러가지 방법을 제공하는데, Amazon에서 제공하는 VPN의 경우에도 상당히 다양한 방법의 VPN 프로토콜을 지원 한다. (IPSEC,IKE, SHA-1 방식의 Hashing, BGP peering ).

자세한 내용은 아래 Link 참고
http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/Introduction.html

VPN 을 통해서 VPC에서 할 수 있는 것은 region간의 서로 다른 VPC를 같은 subnet으로 묶거나, 또는 회사 데이타 센타의 subnet VPN을 통해서 VPC와 같은 네트워크 대역으로 묶을 수 있다.



VPN을 구성할때 고려해야 할 점은, VPC를 구성할때, VPN을 통해서 다른 region이나 데이타센터(회사)와 연결할 가능성이 있다면, subnet ip 주소를 이에 맞게 구성해야 한다는 것이다. 만약에 VPC를 구성할때 처음부터 10.0.0.0/16으로 Full range를 다 사용해버리면 나중에 다른 데이타 센터와 VPC로 연결할때 IP가 겹칠 수 있고, 나중에 이를 바꿔야 하는 대 작업이 생길 수 있기 때문에, VPC 디자인시 먼저 subnet ip 대역을 적절하게 분할하여 설계할 필요가 있다.


Security Group

Security GroupVPC 안에서 일종의 방화벽 처럼 사용된다. VPC 가 아니더라도 Security GroupAWS에서 필수적으로 사용되는데, Security 그룹은 inboud 또는 outbound traffic에 대해서 port 별로 접근을 제어할 수 있는 기능을 제공한다. 마치 방화벽과 같은 기능을 하는 서비스라고 생가하면 된다.

 VPC 안에서의 Security Group의 차이점은 VPC를 사용하지 않는 경우 Security Group에서는 inbound traffic에 대해서만 접근 제어가 가능한데, VPC내의 Security Group의 경우에는 in/outbound traffic 모두에 대해서 접근 제어가 가능하다.

그 외에도, 생성할 수 있는 Security Group수나 지원 하는 Protocol의 종류가 차이가 있는데, 자세한 내용은
http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_SecurityGroups.html#VPC_Security_Group_Differences
를 참고하기 바란다.

Security Group 을 이용하면, Hosting 환경에서 사용하는 DMZ와 같은 개념을 구현할 수 있다. 아래 그림을 보자, 아래 아키텍쳐는 Web à REST API à DBMS 세 가지 계층으로 이루어진 시스템이다.



Web Layer public subnet으로 구성하고, 인터넷으로 부터 들어오는 모든 TCP 80 (HTTP) traffic을 받도록 Security Group을 구성한다. REST API 를 제공하는 subnet Web Server들이 위치한 Subnet으로 부터 들어오는 TCP 8080 traffic만 받도록 하고, DB들이 위치한 subnet API Server subnet에서 들어오는 DB 연결용 3306 포트만 받도록 한다.

이런식으로 네트워크를 구성하면 조금 더 높은 수준의 보안을 제공할 수 있다.


Bastion

VPC를 사용하게 되면, private subnet의 경우에는 외부에서 telnet이나 ssh로 접근할 수 있는 방법이 없다. (public ip가 없기 때문에) 또한 public subnet에 있는 EC2 instance의 경우에도 모든 인스턴스에 SSH 연결을 열어 놓게 되면 보안상으로 문제가 발생할 수 있는 가능성이 있다.

그래서 Bastion 이라는 개념을 사용하는데, 일종의 Telnet 접속 Console이라고 생각하면 된다.



VPC 내의 모든 Instance들은 이 Bastion으로 부터의 telnet 또는 SSH 접속 만을 허용하도록 Security Group이 설정하고, Bastion역시 SSH 접속을 운영자의 PC나 운영센터 (회사) IP 대역을 통해서 SSH 접속만을 할 수 있도록 Security Group을 설정해놓으면 VPC로의 접근을 안전하게 통제할 수 있으며, 단일 접속 지점만을 제공하기 때문에, 모든 사용자의 접근 내용을 한군데로 logging해서 감시할 수 있는 장점이 있다.

Bastion은 단일 접속 지점인 만큼 하나의 instance로 운영하는 것보다는 HA를 사용하거나 또는 일반적인 접속을 위한 Bastion, super user만을 위한 (나중에 일반 접속용 Bastion이 장애가 나서 접속이 불가할 때 사용할 용도) 별도의 Bastion 을 포함하여 2개 이상을 운영하는 것이 좋다.


VPC Scenarios

지금까지 간략하게 나마 VPC의 기능에 대해서 알아보았다. VPC를 제대로 사용하면 상당히 다양한 구조의 network 구성을 할 수 있다. 반대로 이야기 하면, 모르면 구성이나 사용이 매우 어렵다는 이야기가 된다.

Amazon에서는 VPC에 대한 주요 사용 패턴에 따라 약 4가지 시나리오를 이미 준비해놓고, VPC Wizard에서 지원하고 있다.

http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenarios.html 를 보면 Amazon에서 제공하는 주요 4가지 시나리오에 대한 설명과 설정 방법을 참고할 수 있다.

 

Dynamo는 새롭게 소개된 AWS의 NoSQL서비스이다.
Key-Value 형태로 대용량의 데이타를 저장할 수 있으며, 고속의 데이타 access를 제공한다.

데이타 모델
먼저 데이타 모델을 살펴보자, RDBMS의 일반적인 테이블 구조와 유사하지만, 조금 더 유연성을 가지고 있다.
RDBMS와 똑같이 테이블이라는 개념을 가지고 있으며, 테이블은 테이블명과 각각의 ROW로 구성된다.
테이블은 Unique한 Primary Key를 가지고 있다. 이를 Key라고 정의한다.
테이블의 ROW에 해당하는 내용은 item이라고 부르는데, 각 item은 key에 의해서 구분된다.
RDBMS와는 다르게, 각 ROW는 똑같은 Column을 갖는 것이 아니라, 각  row 마다 다른 column을 가질 수 있다
그래서, 각 컬럼을 name = value 식으로 정의하는데, 이 각각을 attribute라고 정의한다.



이 개념을 도식화 해보면 위의 그림과 같다.
아마존 웹사이트에 나와 있는 예제를 한번 살펴보자.
ProductCatalog 라는 테이블이 있다고 하자, 이 테이블의 Primary Key는 Id라는 필드를 사용한다. 이 Primary Key 필드는 모든 item들이 가지고 있어야 한다.

Item 1
{ 
   Id = 101                                       
   ProductName = "Book 101 Title"
   ISBN = "111-1111111111"
   Authors = [ "Author 1", "Author 2" ]
   Price = -2
   Dimensions = "8.5 x 11.0 x 0.5"
   PageCount = 500
   InPublication = 1
   ProductCategory = "Book" 
} 
Item 2
{ 
Id = 201
ProductName = "18-Bicycle 201"
Description = "201 description"
BicycleType = "Road"
Brand = "Brand-Company A"
Price = 100
Gender = "M"
Color = [ "Red", "Black" ]
ProductCategory = "Bike"
}

위의 예를 보면 알겠지만, 모든 Item들은 Id라는 Key 필드를 가지고 있지만, 각각의 Column들은 내용이 다르다. Item 1에는 ISBN 필드가 있지만, Item 2에는 ISBN 필드가 없다.

Dynamo는 RDBMS와는 다르게 Index 필드가 없다. (다른 NoSQL도 Index가 없는 경우가 많지만) 대신 range query나 sorting을 지원하기 위해서 range key라는 추가적인 키를 제공한다. Primary Key를 정의시 Unique한 Key 필드 하나만 정의하거나 (이를 Hash Key라고 한다.) 또는 이 range key를 추가로 지정하면, 쿼리 결과가 ascending 순서로 sorting이 되며, 쿼리 역시 이 range key를 기반으로 특정 범위의 데이타만 query 할 수 있다.
이 range key는 table 생성시에 hash key와 함께 정의한다.

성능

내부적으로 SSD 디스크를 이용하기 때문에, 높은 IO 성능을 보장할 수 있으며 read / write 성능을 보장하는 옵션을 가지고 있다.
Read/Write Unit이라는 옵션인데, 1KB item 1개를 1초동안 쓰거나 읽는 단위가 1 Unit이다. 2 Write Unit은 1K 데이타를 1초동안 2개 Write할 수 있는 성능 지표이다.

Units of Capacity required for reads = Number of item reads per second x item size (rounded up to the nearest KB)
Units of Capacity required for writes = Number of item writes per second x item size (rounded up to the nearest KB)
ReadUnit = [초당 읽는 item(row) 수] * [ item 크기 (kb로 반올림) ]
WriteUnit = [초당 쓰는 item(row) 수] * [ item 크기 (kb로 반올림) ]

1 ReadUnit은 초당 1KB짜리 1개의 Item을 읽을 수 있는 성능 단위이다.
예를 들어, 21.5 kb 짜리 item을 초당 100개를 읽는 성능이 필요하다면, Read Unit = 100 * 22 (반올림) = 2200 이 필요하다.
쓰기 성능도, 마찬가지 방식으로 WriteUnit이라는 단위로 지정한다.
각각 최대 10,000 Unit 까지 지원하며, 이 이상을 원할 경우, Amazon Support에 신청하면, 더 높은 Unit으로 올릴 수 있다. (최대 한계는 나와있지 않음)
Unit의 개념은 성능을 보장한다는 개념에서 긍정적이지만, 반대로 성능을 제약한다는 문제를 가지고 있다.
즉 정해진 Unit 보다 많은 read나 write가 발생할 경우, Dynamo는 이를 처리하지 않고 error 처리를 해버린다.
"ProvisionedThroughputExceededException" 그래서 Spike 형태의 request가 들어올 때는 문제가 된다.
프로그램 로직상에서 "ProvisionedThroughputExceededException" 에 대한 처리가 필요한데, 이 에러가 발생하였을 경우에는 프로그램적으로 retry를 하도록 하는 로직을 포함하는 것을 권장한다.

일관성 보장 옵션
Dynamo와 같은 NoSQL 계열의 데이타베이스는 데이타를 여러개의 노드에 나눠서 저장하고, 백업을 위해서 다른 노드로 복제하기 때문에, 복제가 완료되기 전에 클라이언트가 다른 노드에서 데이타를 읽으면 예전의 데이타를 읽을 수 있다. 이런 문제가 일관성 문제인데, 일반적인 NoSQL은 이러한 일관성을 보장하지 않는다. 복제할 때까지 시간이 걸린다는 것을 가정하고, (시간 자체는 짧으나) 그 시간동안은 일관성이 보장이 안되는데, 이러한 일관성 보장 정책을 Eventually Consistent Read라고 한다. 반대로, 데이타를 쓴 다음 모든 노드에서 데이타를 읽었을때, 같은 데이타를 바로 리턴하게 할 수 있는데, 이 경우에는 데이타가 써진 후에, 다른 노드 까지 replicated될때까지 기다려야 한다. 그래서 당연히 Read 응답시간이 Eventually Consistency Read보다 느리다. 이러한 일관성 정책을 Strongly Consistent Read라고 한다. Strong Consistency의 경우 Eventually Contentency와 같은 성능을 보장하려면, 더 빨리 data write를 발생시켜야 하기 때문에, 내부적으로 더 높은 write unit이 필요하게 된다. 그래서, Eventually Consistency의 경우 Strong Consistency에 비해서 가격이 50% 정도 저렴하다.

Query
데이타베이스이기 때문에, 데이타에 대한 Query를 지원한다.
Primary Key를 가지고 get이 가능할 뿐더러, range key를 이용하여, subset을 query하는 range query가 가능하다.
쿼리 후 list(set) 형태의 데이타가 리턴되었을 경우, 한번에 리턴할 수 있는 데이타 set의 최대 크기는 1MB이다.
1MB가 넘을 경우에는 pagenation을 해야 하는데, 1MB 가 넘는 경우 LastEveluatedKey라는 값을 리턴하여, (일종의 DB cursor와 같은 역할) 다음번 read시 부터는 이 키 부터 리드할 수 있도록 pointing을 해준다
또는 명시적으로 Limit 라는 parameter를 이용하여, Query에서 리턴되는 수를 정할 수 있다. (SQL의 "top"과 같은 개념) 전체 쿼리 결과가 1000개라도 Limit 10 으로 하면, 소팅된 순서에서 상위 10개의 item 만 리턴한다.
다음으로는 "Count"라는 parameter가 있는데, 이 Count는 RDBMS의 select count(*)와 같은 개념이다. Query 결과로 리턴되는 총 Item의 수를 리턴한다.
주의할점은 Dynamo는 NoSQL이다. RDBMS와 다르다.
key 기반의 select와, range query는 지원하지만, group by, where, index등의 쿼리 기능은 없다. (데이타 모델 설계 자체를 RDBMS와 다르게 해야 한다.)

Scan
Scan 기능은 테이블의 모든 Item을 순차적으로 읽어오는 기능으로, Query와 마찬가지로, 한번 API call에 1MB까지만 읽어올 수 있고, LastEvaluatedKey 값을 이용해서 다음 데이타를 연속적으로 읽어올 수 있다. 처음부터 테이블을 Scan 하기 때문에, 당연히 많은 시간이 소요된다.

'클라우드 컴퓨팅 & NoSQL > Amazon Web Service' 카테고리의 다른 글

Amazon의 설치 배포 자동화 솔루션 Opsworks  (0) 2013.02.26
간단한 S3 Performance Test  (3) 2013.01.25
아마존의 SSD의 NoSQL 서비스 Dynamo  (0) 2012.12.07
Amazon S3 서비스 소개  (0) 2012.12.06
EMR 특징  (1) 2012.12.06
Dynamo 특징  (0) 2012.12.06

AWS S3 (Simple Stoage Service)는 파일을 저장하기 위한 스토리지이다. 일반적인 파일시스템의 개념과는 약간 다르고, 파일 이름을 대표하는 key와 파일 자체로 구분되는 Object Storage이다.

저장할 수 있는 파일의 크기는 개당 1byte~5TB이고, 총 저장 용량에는 제한이 없다. 디렉토리와 비슷한 개념으로, bucket이라는 개념을 가지고 있다.

S3에 접근하기 위해서는 일반적은 file io api등은 사용할 수 없으며, REST/HTTP 기반의 프로토콜만 지원한다. 그래서, 성능이 다른 파일 시스템에 비해서 느리다.

기본적으로 3 copy를 지원하여, 데이타를 복제하고, 이 복제는 Amazon availability zone (AZ) 단위로 복제가 되기 때문에 데이타 센터 장애에 대한 대응성을 가지고 있다. 단 region 간 복제는 지원하지 않는다. 복제에 관련된 옵션으로는 RRS (Reduced Redundancy Storage)라는 것이 있는데, 이 옵션을 적용하면, 2 copy (원본 + 백업)만을 저장하기 때문에, 가격이 훨씬 더 저렴하다.

3 copy를 저장할 경우, S3에 대한 데이타 신뢰도는 99.999999999% 를 보장하고, 서비스에 대한 가용성은 99.99%를 보장한다.

다른 주목할만한 기능 은 retain 기간을 지정할 수 있다. 즉 파일의 저장 기간을 지정할 수 있고, 그 기간이 지나면 자동으로 삭제가 된다.

또한 파일에 대한 versioning 기능을 가지고 있어서, 잘못되었을 경우, 기존의 파일 내용으로 roll back이 가능하다. S3 서비스는 AWS 내에서 대용량 데이타를 저장하기 가장 알맞은 저장소이다. 그래서 다른 AWS의 서비스 (EMR 나 CloudFront, Glacier 등)에 자연스럽게 연동될 수 있는 기능을 제공하며, 다른 서비스들과 상호보완적인 관계를 갖는다. 예를 들어 SQS와 같은 큐 서비스에는 큰 객체(파일)을 저장할 수 없기 때문에 이벤트 메세지는 SQS에 저장하고, 실제 큰 파일은 S3에 저장해서 레퍼런스를 하던가, Dynamo와 같은 NoSQL DB도 레코드당 데이타 한계로 인해서, 메타 데이타는 Dynamo에 저장하고, 파일과 같은 큰 바이너리 데이타는 S3에 저장하고 레퍼런스를 하게 할 수 있다.

매우 간단한 서비스이기는 하지만, 데이타 손실 가능성이 적고, 사용이 간략하며, 다른 서비스와 연계성이 높기 때문에, 필히 익혀둬야 하는 서비스이다.


몇일전 AWS에서 redshift 라는 이름의 새로운 서비스가 발표되었다.
redshift는 aws 상에서 제공되는 dataware house 서비스이다.
data warehour란, 데이타 분석 및 리포팅의 목적으로, 기업의 모든 데이타를 한곳에 모아서 쿼리에 최적화된 데이타 베이스 서비스를 제공한다.
특징은, 많은 양의 데이타를 보관해야 하며, CUD (Create/Update/Delete)보다는 Select나 Join등에 최적화되어 있다.

AWS의 redshift의 주요 특징을 보면
내부 DB는 postgres로 구현되어 있으며 (실제 구현 제품은 http://www.paraccel.com/ 을 사용하였다.) , IO 성능 최적화에 많은 신경을 썼다.
스토리지는 EBS를 사용하지 않고, 다수의 Local Storage를 사용하며, 클러스터링을 통한 용량 확장을 고려하여, 노드간의 통신은 10G 네트워크를 사용한다.
최소 2TB에서, 클러스터링시 최대 8노드를 묶어서 1.6PB의 용량을 지원할 수 있다.
또한 데이타 Loading을 위해서 aws내의 s3,emr(hadoop),rds,dynamoDB와 연동을 지원하여, 이 데이타소스로 부터 바로 redshift로 데이타를 로딩할 수 있다.
DW는 데이타를 저장하고, 쿼리해주는 것이고, 결과적으로는 UI 기반의 리포팅이 필요한데, redshift는 BI 리포팅의 선두 주자인 Microstrategy를 지원하고, Jaspersoft 제품도 지원한다. 

또한 redshift와 함께 발표된 제품으로 data pipe line 이라는 제품이 있다.



[ aws data pipeline 화면 예시]

이 제품은 일종의 ETL (Extract Transform Loading)과 같은 제품 기능을 갖는데, 
aws의 data storage 서비스간에 데이타를 주기적으로 (Batch형태로) 수집 및 변환한 후 다른 data storage로 넘길 수 있다.
hadoop based의 emr, s3, dynamo, redshift 등이 그 대상에 포함이 되는데,

이 두 시나리오를 종합해보면
EC2에서 발생된 로그를 S3나 Dynamo에 저장했다가 data pipe line을 통해서 주기적으로  emr에 넣어서 데이타를 정제 한후
다시 redshift dw로 옮겨서 리포팅을 제공하는 서비스가 가능하게 된다. 리포팅은 호환성을 갖는 BI 전문 3'rd party를 통해서 제공함으로써,
데이타 생성후의 모든 과정에 대해서 지원을 하게 됨으로써, 빅데이타에 대한 클라우드 서비스를 가능하게 하였다.

현재 redshift와 data pipe line 서비스는 한정된 고객을 대상으로 close beta 서비스 중이다.

아마존의 EC2 서비스는 VM 기반의 컴퓨팅 자원을 제공하는 서비스이다.

클릭 몇 번으로 저기 바다 넘어있는 나라에 내 서버를 만들 수 있으며, 내가 사용한 만큼만 비용을 지불하면 된다.
아마존 EC2에서 제공하는 VM은 성능과 특성에 따라 여러가지 타입을 가지고 있다.

일반적인 인스턴스 
  • 1세대 인스턴스(m1) : m1.* 이름으로 시작하며 아마존에서 일반적으로 제공하는 가상화된 VM 인스턴스 이다.
  • 2세대 인스턴스(m3) : 2012년에 발표한 인스턴스로 m3.* 로 시작하며, 기존에 비해서 50% 이상의 높은 CPU 성능을 가지고 있다.
특수목적 인스턴스 

  • 고용량 메모리 인스턴스(m2) : m2.* 이름으로 시작하며 17,34,68 GB등 많은 용량의 메모리를 가지고 있는 인스턴스이다. (가상코어 역시 그만큼 많이 가지고 있다) 데이타베이스나 메모리 캐쉬 서버등 메모리 사용량이 높은 서비스에 이용할 수 있다. 
  • 고성능 CPU 인스턴스(c1) : c1.* 이름으로 시작하며, 같은 메모리나 디스크를 갖는 m1 시리즈에 비해서 상대적으로  CPU 만 더 많이 가지고 있다.
  • 클러스터링 인스턴스(cc1) : cc1.* 로 시작하며, 아마존 인스턴스 중에서 가장 높은 스펙을 가지고 있다. 많은 CPU와 많은 메모리 그리고 10G 기반의 IO 성능을 가지고 있다. 특히 클러스터링 인스턴스는 placement group이라는 옵션을 지원하는데, 아마존의 VM은 내부에서 생성될때, 어느 위치(Rack)에 생성될지 알 수 가 없다. 그래서 인스턴스간의 네트워크 latency가 예측 불가능 한데, 클러스터링 인스턴스를 placement group으로 묶으면, 인스턴스간의 네트워크 latency를 최소화하고 인스턴스간 10GB 네트웍을 사용한다. 클러스터링된 서비스들은 대부분 인스턴스간의 통신을 하고 그 속도에 많은 영향을 받기 때문에, 클러스터링 된 서비스에 매우 유리하다. Cassandra,MongoDB등과 같이 내부적으로 클러스터링이 되는 NoSQL등에도 사용할 수 있다.
  • 클러스터 GPU 인스턴스(cg) : cg* 로 시작하는 인스턴스로, VM에 GPU (그래픽카드에 들어가는 CPU)가 대거로 포함되어 있다. 우리가 사용하는 그래픽 카드에는 GPU라는 프로세스가 들어 있는데, 이 GPU들은 실수 연산 (floating point)과 같은 수치 연산에 매우 최적화되어 있다. 그래서 수치 해석이나 대규모 병렬처리등에 매우 유리한데, 이러한 GPU들은 CPU와는 다르게 큰 코어를 수개~수십개를 가지고 있는 것이 아니라 수백개의 GPU 코어를 가지고 있기 때문에, 수치 연산에 있어서는 탁월한 성능을 발휘할 수 있다.
  • High IO 인스턴스(hi) : hi*로 시작하며 높은 성능의 네트워크와 디스크 IO성능을 보장한다. 특히 디스크 성능이 탁월하게 높은데 그럴 수 밖에 없는 것이 SSD를 사용한다
EBS(디스크) 성능 옵션

그 외에, 위의 VM을 선택한 후에, VM에 따라 다음과 같은 몇 가지 추가 옵션을 제공한다.
EBS는 나중에 설명하겠지만, iSCSI기반의 SAN 스토리지다. PC로 쉽게 생각하면 외장 하드 정도로 이해하면 된다. (물론 그보다는 훨씬 빠르지만). EC2에서 문제가 되었던게 이 EBS 디스크를 VM에 붙였을때, EBS 디스크에 대한 IO 성능 느리고, 그 성능이 일정하지 않았던 문제를 가지고 있었다. 이를 보와하기 위해서 나온 것이 다음과 같은 두 가지 옵션이다.

Provisioned IOPS (PIOPS)
EBS 디스크 용량에 따라서 IOPS를 보장한다.  보장 가능한 IOPS는 EBS용량에 비례하여 증가한다. GB를 기준으로 N GB사용시, 명시적으로 지정 가능한 최대 IOPS는 N*10 IOPS가 된다. (40GB면 400IOPS, 100GB면 1000IOPS) 현재 최대 1,000 IOPS까지 지원된다.
정확하게는 EC2 VM의 옵션이 아니라 EBS의 옵션으로, Provisioned IOPS를 선택하면, IO 성능을 보장할 수 있는 EBS 디스크 영역에 EBS Volume이 생성된다.

EBS Optimized Instance
EBS Optimized Instance는 EBS와 EC2 인스턴스간에 내부적으로 전용 네트워크를 사용하여 대역폭을 안정적으로 유지해준다. 500Mbps~1000Mbps 사이에 대역폭을 설정할 수 있다.

추가적인 기능
아마존 EC2의 VM 서비스는 몇 가지 추가적인 기능을 가지고 있다.

VM Import/Export
Virtualization 기반의 서비스인 만큼 다른 동작중인 VM에 대한 Snapshot을 뜰 수 있고, 이 Snapshot 파일을 Export할 수 있다. 반대로 Local PC나 자사의 데이타 센터에서 사용하는 VM Image를 Import할 수 도 있다. 현재 지원하는 포맷은 VMDK(VMWare 포맷),VHD(Microsoft), RAW 포맷등을 지원한다.

Amazon Marketplace
Amazon Market Place는 EC2 VM을 생성할때, 미리 소프트웨어가 다 깔려져 있는 VM 이미지를 구매할 수 있는 Market place이다.  예를 들어 VM 생성시 RedHat Enterprise Linux 이미지를 선택하면, RedHat Linux가 깔려 있는 VM이 생성된다. OS 뿐만 아니라 SAP와 같은 패키지 소프트웨어에서 부터 LAMP (Linux + Apache +MySQL + PHP)와 같은 여러 소프트웨어 솔루션의 조합까지 다양한 형태의 이미지들을 구매할 수 있다.



물론 이러한 이미지들은 공짜가 아니다 EC2 시간당 사용 요금에 함께 합쳐서 소프트웨어 라이센스비가 청구된다. 
제품에 따라서는 아마존을 통해서 기술 지원을 받을 수 있는 제품들도 있다. 예를 들어 RedHat Linux의 경우 가격은 일반 Linux VM에 비해서 두배 가량 비싸지만, 아마존을 통해서 기술 지원을 받을 수 있다.

Elastic IP
EC2 VM의 특징중의 하나가, VM이 생성되고 그리고 Restart될 때마다 그 IP 주소가 동적으로 매번 바뀌다는 것이다. 이렇게 IP가 바뀌면 서버간의 통신이나 외부 서비스시에 고정 IP가 없으면 서비스가 어렵기 때문에, 아마존에서는 인터넷 고정 IP 자체를 EIP 라는 이름으로 판매한다. EIP를 구매하면, 인터넷 Public IP가 하나 부여되고, 이를 EC2 인스턴스에 부여하면 고정 IP를 사용할 수 있다.

특성
이외에도 EC2 서비스는 몇 가지 특성을 가지고 있다.

IP 주소 변경
앞의 EIP에서도 설명하였듯이, EC2 인스턴스는 EIP를 배정하지 않는 이상 리스타트 때마다 IP가 변경된다. 고정 IP를 사용하는 방법은 EIP와 VPC (Virtual Private Cloud)를 사용하여 Private IP를 배정하는 방법이 있다. (나중에 설명)

IO 성능
EC2 서비스, 아니 모든 클라우드 서비스에서 가장 신경써야 하는 부분이 IO다. 기본적으로 LOCAL 서버 만큼의 성능이 나오지 않는다. 네트워크 구간 성능, EBS 디스크와 연결된 네트워크 성능 모두 일반 LOCAL 서버에 비해서 낮다.(물론 IO 옵션을 적용하고, 큰 인스턴스를 사용하면 높아진다.) 이 IO 성능은 인스턴스 크기에 비례하고, IO 옵션 (PIOPS, EBS Optimized Instance)에 따라서 높일 수 있다. LOCAL 환경에서 개발한 시스템들이 AWS EC2에 올리면 많은 성능 차이가 나는 이유중의 하나가 이 IO 성능 때문이다. 인스턴스별 IO 성능은  http://aws.amazon.com/ko/ec2/ 를 나와 있다. 주의할점은 EC2의 네트워크는 다른 EC2인스턴스와 공유해서 사용되기 때문에, 그 성능이 일정하지 않다. 큰 인스턴스를 사용하면, 전체적으로 성능은 올라가지만 그 성능에 대한 편차가 크기 때문에 서비스전에 반드시 측정 및 테스트 후에 사용해야 한다.

SLA
SLA는 Service Level Agreement의 약자로, 서비스의 안정성을 백분율로 나타낸 것인데, 100%이면 1년에 장애가 없는 것. 99.95%면 1년에 365일 * 0.05% 만큼 장애가 날 수 있다는 것이다. 그런데 아마존 EC2 서비스의 SLA는 바로 99.95% 이다. 1년에 4.38 시간이 장애가 나도 아마존 책임이 아니라는 이야기. 그래서 AWS에서 설계를 할때는 항상 데이타 센터 자체가 장애가 나거나 region이 장애가 나는 것을 염두 해두고 Zone간 또는 Region 간 Fail over (장애 대응) 시나리오를 고려해서 설계해야 한다.

시간 단위 과금
EC2 사용시 주의해야할 점은 시간 단위의 과금이다. 딱 시간 개념으로만 과금을 한다. 분이나 초의 개념이 없다. 무슨말이냐 하면, 1시간을 사용하던, 1시간00분1초~1시간59분59초는 무조건 2시간으로 과금이 된다. 그래서 EC2 인스턴스의 UP time (기동시간)을 자동화 하거나 스케쥴링 할경우에는 시간을 넘지 않도록 해야 불필요한 시간 과금이 발생하지 않는다.

CPU 단위 ECU
아마존은 EC2 인스턴스의 컴퓨팅 능력 즉, CPU의 단위를 ECU라는 단위로 표현한다.
ECU는 하나의 표현 단위일 뿐이지 1 ECU = 1 vCore나, 1CPU를 뜻 하는 것이 아니다.
아마존 홈페이지의 내용을 인용하면, 1 ECU는 
"
ECU(EC2 컴퓨팅 유닛) 1개는 1.0~1.2GHz 2007 Opteron 또는 2007 Xeon 프로세서와 동일한 CPU 용량을 제공합니다. 이는 원본 설명서에 언급되어 있는 초기 2006 1.7 GHz Xeon 프로세서와도 동일한 수준입니다" 라고 나와 있다. 5~6년전 CPU 성능이다.


인스턴스 과금 방식에 따른 분류
EC2는 계약 방식에 따라 다른 가격 체계를 가지고 있다.
  • Free : 개발이나 테스트를 할 수 있게 일부 인스턴스를 무료로 제공한다. micro 인스턴스의 경우 750시간 무료, 그 이후에는 과금이 되니 주의 바람 (참고 http://aws.amazon.com/ko/ec2/pricing/ )
  • On-Demand Instance : 우리가 일반적으로 사용하는 과금 방식으로, 사용한 시간 만큼 비용을 지불하는 형태이다.
  • Reserved Instance : 일정 기간 인스턴스 사용을 약속하고, 그에 대한 Discount를 받는 방식
  • Spot Instance : 입찰 방식의 사용방법.  사용자가 입찰 가격을 제시해놓으면, 아마존에서 남는 인스턴스들에 대해서 Spot 가격을 책정하는데, 이 가격이 입찰가격 내로 들어오면 인스턴스가 기동되는 방식. 입찰 가격이 넘어가면 자동으로 Spot Instance는 다시 종료 된다. 인스턴스의 가동 시간을 예측할 수 없기 때문에, OLTP식의 일반적인 업무에는 적절하지 않고, Batch 나 분석 업무 같이 대규모의 컴퓨팅 자원을 분산해서 처리 하지만, 항상 인스턴스가 떠 있을 필요가 없는 업무에 적절하다.
아마존을 사용하고, 어느정도 EC2의 볼륨이 확정되면 Reserved Instance를 사용하는 것이 좋다. On-Demand는 가격이 비싸다.
그리고 Map & Reduce와 같은 OLTP용 서비스가 아닌 Batch나 계산 업무는 Spot Instance를 사용하는 것이 좋다.


I have summarized some of the follow-ups below as discussed: User Data and Meta Data – that can be used for bootstrapping as we discussed and I showed you a demonstration of - documentation: http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html IP Addresses in VPC Auto Scaling Groups: Auto Scaling will automatically assign IP addresses using the DHCP provider when a new instance is launched. However, you could bootstrap it to assign additional IP addresses, using the Elastic Network Interface. Please be sure to consider the following too: http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/using-instance-addressing.html#MultipleIP Scaling Down Policies: For Auto Scaling Group policies, please use the following syntax when defining the scale down policy (notice how the negative adjustment value requires an "=" sign to work correctly: as-put-scaling-policy policy_scaledown1 --type ChangeInCapacity --auto-scaling-group koreaASG --adjustment=-1 --region ap-southeast-1 AWS Labs: Please download the AWS Labs that I showed you from the following location. It has step-by-step instructions for many scenarios and is a good way to get "your hands dirty" with the various services. It covers Auto Scaling as well as VPN connectivity to VPC using software-VPN. https://aws-labs.s3.amazonaws.com/latest/AWS%20Labs%20Workbook%20v2.2.zip?AWSAccessKeyId=AKIAI4BYU4OOGEEU5JZQ&Expires=1356896712&Signature=70P0jfBWqZkHy%2BO9hREOYJb5zWY%3D Custom Metrics: I have attached the step-by-step exercise we talked about for setting up custom metrics monitoring. These scripts are written in Perl, but you can use your own favorite language (I believe your preference is Java). For Java you can use the PutMetricDataRequest API. Custom metrics cost USD 0.50 per metric per month. Chef and CloudFormation: Please see below for the article on using CloudFormation with Chef configuration management: https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CC8QFjAA&url=https%3A%2F%2Fs3.amazonaws.com%2Fcloudformation-examples%2FIntegratingAWSCloudFormationWithOpscodeChef.pdf&ei=GKqpUKGlEcbprQeY84GYAg&usg=AFQjCNE8MEewryO9PWVzBC5e086rEWYAwA&cad=rja Also see this link for a range of CloudFormation articles: http://aws.amazon.com/cloudformation/aws-cloudformation-articles-and-tutorials/ CloudFormation Services Not Supported: These are some of the services not supported by CloudFormation (at least not yet). You can see the up-to-date list of supported resources here. Not supported are: Elastic MapReduce, Amazon Fulfillment Web Services, CloudSearch, Simple Workflow Service, Simple Email Service, AWS Direct Connect, Flexible Payment Services, Simple Pay, DevPay, Glacier, Import/Export, Storage Gateway, Alexa, Mechanical Turk. I am still trying to confirm the roadmap for SWF global expansion and Provisioned IOPS. Thanks. Oyvind

어제 발표된 Microsoft Azure의 IaaS 서비스와 Amazon의 AWS 서비스 사이에 가격 비교를 해봤다.

아래 내용은 네트워크 비용이나 Blob Storage 등 부가 서비스를 제외하고 EC2 서비스 만을 비교한 것이다.

 

 

요약 - Linux VM의 경우 동일, Windows VM의 경우 MS가 저렴

Linux VM의 경우 동등 인스턴스 크기에서는 Amazon과 Azure 양쪽 가격이 같다. Azure가 레퍼런스해서 만든 느낌이 가득하다. 

 

Azure 장점 

- Windows Server VM의 경우 Amazon 대비 저렴. Amazon은 Windows VM에 대해서 별도의 가격 정책을 책정하나, Azure의 경우 Linux와 Windows를 모두 동일하게 가져감

 

Azure 단점

- 인스턴스 종류가  XS,S,M,L,XL 로 4개로 한정, 이에 반면 Amazon은 용도에 맞게 High-Memory Instance, High CPU Instance, Cluster Compute Instance, Cluster GPU Instance등을 다양하게 제공

 

결론

Instance의 실제 성능이나 IO 성능등은 테스트해서 비교해봐야겠으나, 일단 가격 정책상으로는 서로 경쟁할만한 위치에 왔다고 보여짐.

 

참고 자료

AWS 가격 - http://www.ec2instances.info/

Azure 가격 - http://www.windowsazure.com/ko-kr/pricing/calculator/?scenario=virtual-machines

 

요즘 잘나간다는 SNS 서비스 (텀블러, PInterest)등의 내부 서비스 아키텍쳐나 운영 구조를 공개된 글을 보면 SNS 시스템들의 기술 트렌드를 읽을 수 있다.

 

1. 소규모 조직이다.

얼마전에 FB에 인수된 Instantgram이나 다른 잘나가는 SNS서비스 업체들을 보면 대부분 인력이 20명이내이다.

영업 조직이 있는 솔루션 업체의 경우는 영업이나 Director들을 포함하더라도 40명이 안넘는 것이 대부분이다.

 

이는 빠른 의사 결정을 가능하게 하기 때문에, 상당히 빠른 서비스 개선을 가능하게 한다.

기술적이나 기획적으로 대단한게 아니라, 하나의 기능을 편하게 만들고 사용자 경험에 상당한 노력을 쏟는다.

 

2. 오픈 소스로 치덕치덕. & Don't invent wheel again

이런 서비스들 치고, 대형 벤더 솔루션 쓰는 곳을 못봤다.

- 대부분 오픈 소스를 사용한다.

- 여러가지 언어를 사용한다. 우리가 한국에서 익숙한 자바나 C는 일부에 사용되지 전체를 자바나 C로만 구현하지는 않는다. 오히려 Erlang, Python, Ruby같은 언어들이 급격하게 올라온다.

- 기존의 오픈 소스를 활용을 하지 새롭게 솔루션을 만드는 경우가 없다.

 

3. Devops
Devops는 Development와 Operaion (개발과 운영)을 합친 말로, 이 두팀을 분리하지 않고 개발팀이 개발과 운영을 모두 맏는 개발 운영 모델이다. 요즘 들어 상당히 유행하는데, 운영에서 얻어지는 노하우나 문제를 개발팀에서 처리하는데 비용을 덜고, 고객으로부터의 요청에 빠르게 대응하기 위한 구조로, 운영 팀을 별도로 두지 않는다.

이 것이 가능한것은 클라우드를 사용하면서 하드웨어 인프라에 대한 운영을 클라우드 업체가 담당하기 때문에, 거창한 운영 조직이 필요없고, 클라우드 상에 배포 구조만 잘 잡으면 되기 때문에 가능해진 일이라고 본다.

 

4. Cloud

앞에서도 이야기 했지만, 잘나가는 서비스들은 AWS (Amazon Web Service)를 사용한다.

초기 투자 비용 (Capex)가 들지 않고, 전 세계 커버리지가 가능하며, HA (High Availibility) 구성이 가능하고, 서비스 부하에 따라서 탄력적으로 컴퓨팅 자원을 늘리거나 줄일 수 있기 때문이다.

 

5. 하나씩 차근차근

놀라운 것중 하나는 수백만명을 대상으로 서비스하는 시스템이라도, 처음부터 수백만명을 지원하기 위한 설계를 하는 것이 아니라 기존에 익숙한 기술을 사용하고, 사용자가 늘어감에 따라 아키텍쳐나 기술셋을 점차적으로 바꿔 나가는 구조를 사용한다.

 

주요 아키텍쳐 구조는

앞단에 Nginx나 Apache와 같은 웹서버

중간에 Redis나 memcached 같은 메모리 데이타 그리드

Tomcat,Django와 같은 WAS

Java 뿐만 아니라 Erlang, Python,RoR과 같은 스크립트 언어 또는 분산 처리 언어

MySQL 을 사용할 경우 Sharding, 또는 NoSQL을 백엔드에 사용

이 전체는 AWS 클라우드 위에 Deployment

아키텍쳐는 REST를 사용하는 구조를 갖는다.

필요에 따라 배치 처리나 분석 처리를 위해서 Hadoop등의 분산 처리 프레임웍을 사용

 

 

 

 

원문 : http://www.isi.edu/~gideon/publications/JuveG-DataSharing.pdf

 

아마존에서 과학관련 HPC 분산 컴퓨팅 시에, 공유 스토리지 (NFS, Shared Storage)에 대한 성능 비교 및 Cost 비교를 해 놓은 문서 입니다. EBS나 Local Disk와 같은 스토리지가 아니라 공유 스토리지에만 한정합니다.

 

Amazon S3, Gluster, NFS, PVFS를 중심으로 비교했는데,

결론 적으로 GlusterFS(NUFA Configuration)이 성능도 높은편에 속하고 Cost도 저렴합니다.

 

그림 1. Cost 비교 

 

 

그림 2. 성능 비교 

 

저도 Gluster를 AWS에서 사용했는데, 무엇보다 AWS에 Gluster를 Deployment하기 위한 Best Practice 문서등이 잘 되어 있습니다.

 

참고하세요.

 

요즘 일이 바뻐서 블로그 포스팅을 거의 못하고 있습니다.
많이 버는 만큼, 그동안 충전해왔던 지식이나 노하우를 주로 방전하는 느낌입니다.

어쨌거나, 클라우드의 양대 산맥인 아마존 AWS와 Microsoft Azure에 대한 이야기를 해보려고 하는데..
Azure vs AWS의 승자가 누구이냐? 인데. 결론 부터 이야기 하면 AWS의 손을 들어주고 싶습니다.
Blob Storage나 DB 서비스와 같은 액세사리성 서비스는 양쪽다 어느정도 구색을 갖춰 놨다고 했을 때, 핵심인 Compute Service가 문제인데.
기본적으로 Azure는 .NET 기반의 PaaS만 지원하지만, Amazon은 모든 플랫폼을 올릴 수 있는 IaaS 수준 서비스를 제공합니다.
이말인즉슨, 내가 필요한 소프트웨어를 마음대로 올릴 수 있다는 겁니다. 단순하게 Java냐, .Net이냐 차이가 아니라
서비스를 하다보면 NFS가 필요할 수 도 있고, 제공해주는 NoSQL 서비스의 성능 문제로, Mongo나 Cassandra를 쓰고 싶을 수 도 있고, 빌드 환경을 만들어보고 싶을 수 도 있고, 여러가지 요구 사항이 존재하는데, Azure는 그게 안되고, 그냥 딱!! .NET 개발만 해야 한다는 것인데, 단순한 웹 애플리케이션 시나리오라면 모르겠지만
요즘과 같이 빅데이타나 분산 아키텍쳐가 유행하는 시절에 이것만으로는 부족하다는 말입니다.

기술적으로 Azure가 상당히 뛰어난점도 많은데, IaaS 단으로 오픈을해서, 조금 더 선택의 폭을 넓혀 줬으면 합니다.
이상 사견이었습니다.