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


Archive»


 
 

쿠버네티스 #19

보안 4/4 - Pod Security Policy

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



SecurityContext가 컨테이너나 Pod의 보안 기능을 정의 하는 것이라면, Pod Security Policy (이하 PSP)는 보안 기능에 대한 정책을 정의 하는 것이다.

예를 들어, 정책으로 Pod를 생성할때는 반드시 root 사용자를 사용하지 못하도록 강제한다던지, Privileged 모드를 사용못하도록 강제할 수 있다. 현재는 (2018년9월1일) 베타 상태이기 때문에 다소의 기능 변경이 있을 수 있음을 염두하고 사용하도록 하자.

개념

개념이 복잡하기 때문에 먼저 기본적인 개념을 이해한 후에, 각 상세를 살펴보도록 하자.

먼저 아래 그림을 보자 PSP는 생성후에, 사용자에게 지정이 된다.

그리고 Pod를 생성할때, Pod의 보안 요건을 SecurityContext를 이용해서 Pod 설정에 정의한다.

Pod를 생성하려고 할때, 생성자(사용자)의 PSP를 레퍼런스 하는데, Pod의 보안 요건이 사용자에게 정의되어 있는 PSP 요건을 만족하면, Pod가 생성된다.



반대로, Pod를 생성할때, Pod의 보안 요건 (SecurityContext)가 Pod를 생성하고자하는 사용자의 PSP요건을 만족하지 않으면, Pod 생성이 거부된다. 아래 그림은 사용자의 PSP에서 Privileged 모드를 사용할 수 없도록 설정하였으나, Pod를 생성할때 Privileged 모드를 Pod 가 사용할 수 있도록 설정하였기 때문에, Pod를 생성에 실패하는 흐름이다.




Pod Security Policy

Pod Security Policy는 Security Context와 달리 클러스터 리소스 (Cluster Resource)이다.

즉 적용하는 순간 클러스터 전체에 적용이 된다는 이야기이다.


정책 종류

Pod Security Policy를 통해서 통제할 수 있는 정책은 다음과 같다.

(출처 https://kubernetes.io/docs/concepts/policy/pod-security-policy/) 자세한 내용은 원본 출처를 참고하기 바란다.


Control Aspect

Field Names

Running of privileged containers

privileged

Usage of host namespaces

hostPID, hostIPC

Usage of host networking and ports

hostNetwork, hostPorts

Usage of volume types

volumes

Usage of the host filesystem

allowedHostPaths

White list of Flexvolume drivers

allowedFlexVolumes

Allocating an FSGroup that owns the pod’s volumes

fsGroup

Requiring the use of a read only root file system

readOnlyRootFilesystem

The user and group IDs of the container

runAsUser, supplementalGroups

Restricting escalation to root privileges

allowPrivilegeEscalation, defaultAllowPrivilegeEscalation

Linux capabilities

defaultAddCapabilities, requiredDropCapabilities, allowedCapabilities

The SELinux context of the container

seLinux

The AppArmor profile used by containers

annotations

The seccomp profile used by containers

annotations

The sysctl profile used by containers

annotations



포맷

PSP의 포맷을 이해하기 위해서 아래 예제를 보자

apiVersion: extensions/v1beta1

kind: PodSecurityPolicy

metadata:

 name: nonroot-psp

spec:

 seLinux:

   rule: RunAsAny

 supplementalGroups:

   rule: RunAsAny

 runAsUser:

   rule: MustRunAsNonRoot

 fsGroup:

   rule: RunAsAny

 volumes:

 - '*'


nonroot-psp 라는 이름으로 PSP를 정의하였고, seLinux,supplementalGroup,fsGroup과 volumes(디스크)에 대한 권한은 모두 허용하였다. runAsUser에 rule (규칙)을 MustRunAsNonRoot로 지정해서, 이 정책을 적용 받은 사용자는 Pod를 생성할때 Pod가 반드시 root 사용자가 아닌 다른 사용자를 지정하도록 정의했다.

PSP 사용자 적용

PSP 를 정의하고 실행한다고 해도, 실제로 적용되지 않는다. PSP를 적용하기 위해서는 생성한 PSP를 RBAC을 이용하여 ClusterRole을 만들고, 이 ClusterRole을 사용자에게 부여해야 실제로 정책이 적용되기 시작한다. 사용자에게 PSP를 적용하는 부분은 뒤의 예제에서 살펴보자

이때 주의할점은 사용자의 정의인데, 쉽게 생각하면 사용자를 사람으로만 생각할 수 있는데, 쿠버네티스의 사용자는 사람이 될 수 도 있지만 서비스 어카운트 (Service account)가 될 수 도 있다.

쿠버네티스에서 Pod를 생성하는 주체는 사용자가 kubectl 등으로 Pod를 직접생성할 경우, 사람이 사용자가 되지만, 대부분의 경우 Pod의 생성과 관리는 Deployment나 ReplicaSet과 같은 컨트롤러를 이용하기 때문에, 이 경우에는 컨트롤러들이 사용하는 서비스 어카운트가 사용자가 되는 경우가 많다.

그래서, PSP를 적용하는 대상은 일반 사용자가 될 수 도 있지만 서비스 어카운트에 PSP를 적용해야 하는 경우가 많다는 것을 반드시 기억해야 한다.

PSP 활성화

PSP는 쿠버네티스 클러스터에 디폴트로는 비활성화 되어 있다. PSP 기능을 사용하기 위해서는 이를 활성화 해야 하는데, PSP는 admission controller에 의해서 컨트롤 된다.

구글 클라우드

구글 클라우드에서 PSP를 활성화 하는 방법은 아래와 같이 gcloud 명령을 이용하면 된다.


%gcloud beta container clusters update {쿠버네티스 클러스터 이름} --enable-pod-security-policy --zone={클러스터가 생성된 구글 클라우드 존}


만약에 활성화된 PSP 기능을 비활성화 하고 싶으면 아래와 같이 gcloud 에서 --no-enable-pod-security-policy  옵션을 사용하면 된다.


gcloud beta container clusters update {쿠버네티스 클러스터 이름}  --no-enable-pod-security-policy --zone={클러스터가 생성된 구글 클라우드 존}

Minikube

minikube start --extra-config=apiserver.GenericServerRunOptions.AdmissionControl=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds,PodSecurityPolicy


주의할점은 PSP 기능이 활성화된후에, PSP가 적용되지 않은 사용자(사람과, 서비스어카운트 모두)의 경우에는 Pod를 생성할 수 없기 때문에, 기존에 잘 생성되던 Pod가 갑자기 생성되지 않는 경우가 많기 때문에, 반드시 기능을 활성화하기 전에 반드시, 사용자마다 적절한 PSP를 생성해서 적용하기 바란다. (PSP기능을 활성화하지 않더라도 기본적으로 PSP 정의및, PSP를 사용자에게 적용하는 것은 가능하다.)

예제

개념에 대한 이해가 끝났으면 이제 실제 예제를 통해서 어떻게 PSP를 생성 및 적용하는지를 알아보도록 하자. 예제는 다음 순서로 진행하도록 한다.

  1. PSP 정의 : Root 권한을 사용이 불가능한 PSP를 생성한다.

  2. 서비스 어카운트 생성 : PSP를 생성할 서비스 어카운트를 생성한다. Pod를 바로 생성하는 것이 아니라 Deployment를 통해서 생성할것이기 때문에 Deployment에서 이 서비스 어카운트를 사용할것이다.

  3. ClusterRole 생성 : 다음 1에서 만든 PSP를 2에서 만든 서비스 어카운트에 적용하기 위해서, PSP를 가지고 있는 ClusterRole을 생성한다.

  4. ClusterRoleBinding을 이용하여 서비스 어카운트에 PSP 적용 : 3에서 만든 ClusterRole을 2에서 만든 서비스 어카운트에 적용한다.

  5. Admission controller 활성화 : PSP를 사용하기 위해서 Admission controller를 활성화 한다.

  6. Pod 정의 및 생성 : 2에서 만든 서비스 어카운트를 이용하여 Deployment 를 정의한다.

  7. 테스트 : 테스트를 위해서, root user를 사용하는 deployment와, root user를 사용하지 않는 deployment 두개를 각각 생성해서 psp 가 제대로 적용되는지를 확인한다.

PSP 정의

PSP를 정의해보자. 아래와 같이 nonroot-psp.yaml 을 작성한다. 이 PSP는 runAsUser에서 MustRunAsNotRoot 규칙을 추가해서, Root 권한으로 컨테이너가 돌지 않도록 하는 정책이다.


# nonroot-psp.yaml

apiVersion: extensions/v1beta1

kind: PodSecurityPolicy

metadata:

 name: nonroot-psp

spec:

 seLinux:

   rule: RunAsAny

 supplementalGroups:

   rule: RunAsAny

 runAsUser:

   rule: MustRunAsNonRoot

 fsGroup:

   rule: RunAsAny

 volumes:

 - '*'


파일을 nonroot-psp.yaml 파일로 저장한후에,

%kubectl create -f nonroot-psp.yaml

명령어를 이용하여 PSP를 생성한후에,

%kubectl get psp

명령을 이용하여, PSP가 생성된것을 확인하자




서비스 어카운트 생성

서비스 어카운트 생성을 위해서 아래 yaml 파일을 작성하고, 서비스 어카운트를 생성하여 확인하자


#nonroot-sa.yaml

apiVersion: v1

kind: ServiceAccount

metadata:

 name: nonroot-sa



ClusterRole 생성 및 적용

서비스 어카운트를 생성하였으면, 앞에 만든 PSP nonroot-psp 를 사용하는 ClusterRole nonroot-clusterrole을 생성하고, 이 롤을 nonroot-clusterrole-bindings를 이용하여, 앞서 만든 서비스 어카운트 nonroot-sa 에 연결한다.


아래와 같이 ClusterRole을 생성하는데, resouces 타입을 podsecuritypolicies 로 정의하고, 리소스 이름은 앞에서 생성한 PSP인 nonroot-psp로 지정한다. 그리고, 이 psp를 사용하기 위해서 verb는 “use”로 지정한다

#nonroot-clusterbinding.yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRole

metadata:

 name: nonroot-clusterrole

rules:

- apiGroups:

 - policy

 resources:

 - podsecuritypolicies

 resourceNames:

 - nonroot-psp

 verbs:

 - use


%kubectl create -f nonroot-clusterrole.yaml

명령어를 이용하여 위의 ClusterRole을 생성한후에, 이 ClusterRole을 서비스 어카운트 nonroot-sa 에 적용하자.

아래와 같이 nonroot-clusterrolebinding.yaml 를 생성한후,


#nonroot-clusterrolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRoleBinding

metadata:

 name: nonroot-clusterrole-bindings

subjects:

- kind: ServiceAccount

 name: sa-nonroot

 namespace: default

roleRef:

 apiGroup: rbac.authorization.k8s.io

 kind: ClusterRole

 name: nonroot-clusterrole


%kubectl create -f nonroot-clusterrolebinding.yaml

명령어를 이용하여 ClusterRole nonroot-clusterrole을 서비스 어카운트 sa-nonroot에 적용한다.

도커 컨테이너 생성

이제 PSP가 생성되었고, 이 PSP를 사용하는 서비스 어카운트 nonroot-sa 가 완성되었으면, 이를 실제로 배포에 적용해보자. 배포에 앞서서 컨테이너 이미지를 만든다.

아래는 Docker 파일인데, 앞의 보안 컨텍스트 설명때 사용한 컨테이너와 동일하다.


#Dockerfile

FROM node:carbon

EXPOSE 8080

RUN groupadd -r -g 2001 appuser && useradd -r -u 1001 -g appuser appuser

RUN mkdir /home/appuser && chown appuser /home/appuser

USER appuser

WORKDIR /home/appuser

COPY --chown=appuser:appuser server.js .

CMD node server.js > /home/appuser/log.out

생성된 도커이미지를 gcr.io/terrycho-sandbox/nonroot-containe:v1 이름으로 docker push 명령을 이용해서  컨테이너 레지스트리에 등록한다.

PSP 기능 활성화

이미지까지 준비가 되었으면, 이제 Pod를 생성할 모든 준비가 되었는데, PSP를 사용하려면, 쿠버네티스 클러스터에서 PSP 기능을 활성화 해야 한다.

다음 명령어를 이용해서 PSP를 활성화한다.

%gcloud beta container clusters update {쿠버네티스 클러스터 이름} --enable-pod-security-policy --zone={클러스터가 생성된 구글 클라우드 존}


아래 그림과 같이 PSP 기능이 활성화 되는 것을 확인한다.


Deployment 생성

기능 활성화가 끝났으면, 이제 Pod를 deploy해보자.

아래는 nonroot-deploy.yaml 파일이다.


#nonroot-deploy.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

 name: nonroot-deploy

spec:

 replicas: 3

 selector:

   matchLabels:

     app: nonroot

 template:

   metadata:

     name: nonroot-pod

     labels:

       app: nonroot

   spec:

     serviceAccountName: nonroot-sa

     securityContext:

       runAsUser: 1001

       fsGroup: 2001

     containers:

     - name: nonroot

       image: gcr.io/terrycho-sandbox/security-context:v1

       imagePullPolicy: Always

       ports:

       - containerPort: 8080


우리가 nonroot-psp를 사용하기 위해서, 이 psp가 정의된 서비스 어카운트 nonroot-sa를 사용하도록 하였다. 그래고 nonroot-psp에 정의한데로, 컨테이너가 root 권한으로 돌지 않도록 securityContext에 사용자 ID를 1001번으로 지정하였다.

%kubectl create -f nonroot-deploy.yaml

을 실행한후,

%kubectl get deploy 명령어를 실행해보면 아래와 같이 3개의 Pod가 생성된것을 확인할 수 있다.


보안 정책에 위배되는 Deployment 생성

이번에는 PSP 위반으로, Pod 가 생성되지 않는 테스트를 해보자.

아래와 같이 root-deploy.yaml 이라는 이름으로, Deployment 스크립트를 작성하자.


#root-deploy.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

 name: root-deploy

spec:

 replicas: 3

 selector:

   matchLabels:

     app: root

 template:

   metadata:

     name: root-pod

     labels:

       app: root

   spec:

     serviceAccountName: nonroot-sa

     containers:

     - name: root

       image: gcr.io/terrycho-sandbox/nonroot-containe:v1

       imagePullPolicy: Always

       ports:

       - containerPort: 8080


이 스크립트는 앞에서 작성한 nonroot-deploy.yaml 과 거의 유사하지만 Security Context에서 사용자 ID를 지정하는 부분이 없기 때문에, 디폴트로 root로 컨테이너가 기동된다. 그래서 PSP에 위반되게된다.


%kubectl create -f root-deploy.yaml

을 실행하면 결과가 아래와 같다.



맨 아래 root-deploy-7895f57f4를 보면, Current 가 0으로 Pod가 하나도 기동되지 않았음을 확인할 수 있다.

원인을 파악하기 위해서 Pod를 만드는 ReplicaSet을 찾아보자

%kubectl get rs

명령을 아래와 같이 ReplicaSet 리스트를 얻을 수 있다.

%kubectl describe rs root-deploy-7895f57f4

명령을 실행해서 ReplicaSet의 디테일과 로그를 확인해보면 다음과 같다.



그림과 같이 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를 생성하게 된다.

구글 클라우드 서버의 HTTP 포트를 SSH 로 터널링해서 로컬에서 접속하기


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


구글 클라우드 VM에 서버를 설치한 후 웹을 접근하고자 할때, 설치한 애플리케이션이 ACL (접근 제어) 처리가 안되어 있는 애플리케이션이 있을 수 있다. 특히 관리자 콘솔 같은 경우에 이런 경우가 많은데, 아파치 에어플로우 역시도 설치 후에 웹 서버를 띄우면 포트가 모두 퍼블릭으로 오픈되기 때문에 관리자만 액세스가 가능하도록 ACL 처리를 할 필요가 있다.


이를 위한 방법으로는 몇가지가 있는데


  1. 방화벽으로 특정 포트만 허용 하는 방법
  2. 앞에 nginx나 apache를 넣어서 HTTP BASIC AUTH등 인증 방식을 추가하는 방법
  3. Google Cloud Identity Aware Proxy를 이용하여, 구글 클라우드 계정 사용자에게 접근 권한을 부여 하는 방법
  4. 해당 HTTP 포트를 SSH로 터널링 하는 방법

1번 방법은 IP 가 바뀌면 접근 제어 하기가 번거로우니 패스, 2번은 웹서버 깔아야 하니 패스, 3번은 제일 좋은 방법인데, 로드밸런서등 구체적인 설정을 해야 해서 패스. 그래서 오늘은 가장 간단한 4번 방법을 설명한다.

4번 방법은 로컬에서 localhost:2222를 접속하면 구글 클라우드 상의 인스턴스:8080 으로 포워딩을 해준다. 이때 프로토콜을 SSH를 통해서 터널링이 된다.

매우 간단하게 할 수 있는데, 로컬에 gcloud SDK가 깔려 있을때

gcloud compute ssh {인스턴스명} --project {내프로젝트ID} --zone {인스턴스가 있는 존 이름} --ssh-flag="-L" --ssh-flag="{랩탑에서 접속할 포트번호}:localhost:{인스턴스의 포트 번호}"

로 기입해주면 된다.

예를 들어 terrycho-ml 프로젝트의 us-central1-f 존에 있는 hello-airflow 인스턴스의 8080 포트를 로컬에서  localhost:2222로 접근하도록 포워딩 설정을 할 경우 다음과 같이 하면 된다.


gcloud compute ssh hello-airflow --project terrycho-ml --zone us-central1-f --ssh-flag="-L" --ssh-flag="2222:localhost:8080"

세번째 책이 나왔습니다.

사는 이야기 | 2016.08.29 13:25 | Posted by 조대협

빠르게 훑어보는 구글 클라우드 플랫폼


오늘 세번째 책이 나왔습니다.



이번에 출간된 책은 구글 클라우드에 대해서 간략한 사용 방법을 소개한 "빠르게 훑어보는 구글 클라우드 플랫폼" 이라는 책입니다.

구글에 입사한지도 이제 3개월이 막 지났는데, 막상 사람들 이야기를 들어보니, 한글 자료가 없고, 기초적인 (SSH설정)에서 부터 막히는 분들이 많아서, 구글 한국 사용자 그룹분들과 함께 간략한 소개 서적을 만들었습니다.


한빛 미디어에서 보정 및 조판 작업을 도와주셨구요. (엔지니어 출신이신 이복연님이 꼼꼼하게 봐주신 덕분에 원고 품질이 많이 올라갔습니다.)


이책은 정보 공유 차원에서 무료 EBOOK 형태로 배포됩니다.

http://www.hanbit.co.kr/realtime/books/book_view.html?p_code=E5359426070


많이들 공유하시고, 구글 클라우드 관심 가져주세요.

다음권으로 모바일 빅데이타 분석 기술에 대한 책도 조만간 출간 예정입니다.


인세등 관련 수익금은 전액 사회 기부 됩니다. 






구글 클라우드의 대용량 분산 큐 서비스인 Pub/Sub 소개 #2


node.js를 통하여 메세지를 보내고 받기

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


node.js에서 메세지 보내고 받기


이번 글에서는 node.js를 이용하여 실제로 pub/sub에 메세지를 보내고 받도록 해보자


키 파일 준비 하기

Pub/Sub에 접속하기 위해서는 보안 인증을 위해서 키 파일이 필요하다.

키 파일은 구글 클라우드 콘솔에서, API manager 메뉴로 들어가서 Credential 부분에서 Create Credential을 선택하면 아래와 같은 화면이 나온다.

다음으로, 메뉴에서 Service account key를 선택하여 키를 생성한다.


키가 생성이 되면 json 파일로 다운로드가 된다.

여기서는 편의상 키 파일명을 “pubsub-key.json”이라고 하겠다.


메세지 보내기

node.js를 이용해서 메세지를 보내보자. 먼저 코드를 보자


var gcloud = require('gcloud');

var pubsub = gcloud.pubsub({

projectId:'terrycho-sandbox',

keyFilename: '/Users/terrycho/keys/pubsub-key.json'

});


var topic = pubsub.topic('projects/terrycho-sandbox/topics/repository-changes.default');


for(var i=0;i<3;i++){

topic.publish({

data:{

userId:process.argv[2]+i,

name:'terry.cho'

}

},function(err){

if(err != null) console.log("Error :"+err);

});

};


pub/sub을 사용하려면 구글 클라우드 라이브러리인 gcloud 모듈이 필요하다.

명령어 창에서 npm install gcloud를 이용해서, gcloud모듈을 먼저 인스톨 해놓자.

다음으로, gcloud라이브러리에서 pubsub 객체를 만든다. 여기서는 projectId와, keyFilename을 지정한다.

projectId는 사용하고자 하는 본인의 구글 프로젝트 ID를 넣으면 되고 (여기서는 ‘terrycho-sandbox’), 키 파일은 앞에서 준비한 키 JSON 파일의 경로를 설정하면 된다.


pubsub 객체가 생성되었으면, 메세지를 보낼 topic을 가져와야 한다. topic은 다음과 같은 pubsub.topic메서드를 이용해서 불러올 수 있다. 이때, topic의 경로를 아래와 같이 적어준다.

var topic = pubsub.topic('projects/terrycho-sandbox/topics/repository-changes.default');

여기서 사용한 topic은 projects/terrycho-sandbox/topics/repository-changes.default 이다.

topic을 받아왔으면, 이 topic에 실제로 메세지를 publish하면 되는데, topic.publish( {메세지},{error callback 함수}); 형태로 지정하면 된다.


pub/sub은 앞의 글에서 설명한바와 같이, message와, message attribute 두가지로 분리가 되는데,

message는

data :{

// 여기에 메세지 정의

}


형태로 정의해서 전달하고,message attribute는

attributes:{

  key1:’value1’,

  key2:’value2’
}


형태로 전달한다.

실제 사용예를 보면 다음과 같다.

var registerMessage = {
 data: {
   userId: 3,
   name: 'Stephen',
   event: 'new user'
 },
 attributes: {
   key: 'value',
   hello: 'world'
 }
};


위의 보내기 예제에서는 userId와, name 필드 두개만, 메세지로 3번 보내도록 하였다.

data:{

userId:process.argv[2]+i,

name:'terry.cho'

}

메세지 받기

메세지를 전달하였으면 이제 메세지를 읽어보도록 한다. 전체 코드는 다음과 같다.


var gcloud = require('gcloud');

var pubsub = gcloud.pubsub({

projectId:'terrycho-sandbox',

keyFilename: '/Users/terrycho/keys/pubsub-key.json'

});


var topic = pubsub.topic('projects/terrycho-sandbox/topics/repository-changes.default');

var options = {

 reuseExisting: true, // if the subscription is already exist reuse subscription, option is not changed

 interval:10,

 maxInProgress:5,

 autoAck:false

};


topic.subscribe('nodejs-subscription',options,function(err,subscription,apiResponse){

if(err != null){

console.log('subscription creation failed :'+err);

exit(1);

}

console.log('Subscription :'+subscription);

subscription.on('error',function(err){

console.log('error:'+err);

});


subscription.on('message',function(message){

// read message from queue

console.log(message);

// send ack

subscription.ack(message.ackId,function(err,apiResponse){

console.log('info:sent ack');

});

});

});

topic을 생성하는 것까지는 앞의 메세지 보내기 부분의 코드와 같다.

topic으로 부터 메세지를 받기 위해서, subscription에 대한 옵션을 설정한다.


var options = {

 reuseExisting: true,

 interval:10,

 maxInProgress:5,

 autoAck:false

};

reuseExisting은 별도로 subscription을 생성하지 않고, 기존의 subscription을 사용한다. 이 경우에는, 기존 subscription의 옵션이 그대로 적용되며, 새로운 option이 적용되지 않는다.

interval은 10초 단위로 subscription을 polling 하는 것이고, maxInProgress는 한번에 읽어올 수 있는 메세지 수를 정의한다.

autoAck는 메세지를 보낸 후에, 자동으로 ack를 보내는 옵션인데, 여기서는 false로 하였기 때문에, 수동으로 ack를 보내야 한다.


옵션을 정의하였으면 아래와 같이 topic에 대한 subscription에 대해서, 메세지를 subscription 한다.

topic.subscribe('nodejs-subscription',options,function(err,subscription,apiResponse){

‘nodejs-subscription’은 subscription 이름이고, options는 subscription에 대한 옵션 그리고 마지막은 콜백함수 있다.

메세지를 받았을때 처리 방법을 정의해야 하는데, 앞의 콜백 함수에서 전달되는 subscription객체에 “message”라는 이벤트에 대해서 핸들러를 작성하면 메세지를 받을 수 있다.


아래는 핸들러 코드이다.

subscription.on('message',function(message){

// read message from queue

console.log(message);

// send ack

subscription.ack(message.ackId,function(err,apiResponse){

console.log('info:sent ack');

});

});


메세지가 들어오면 console에 메세지를 출력하고, subscription.ack를 이용하여 ack를 보낸다. 이때, 메세지에서 들어오는 message.ackId를 인자로 하여, 그 메세지에 대해서 ack를 보낸다.


다음은 명령어를 실행하여 메세지를 보내는 실행화면이다.


그리고 다음은 메세지를 받는 프로그램을 수행하여 실제로 메세지를 받은 결과 화면이다.




참고

  • node.js pub/sub 라이브러리 레퍼런스 https://googlecloudplatform.github.io/gcloud-node/#/docs/v0.36.0/pubsub


구글 클라우드 시작하기

계정 생성과 VM 생성하기

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


구글 클라우드 플랫폼에서 가상머신 VM을 생성해주는 GCE (Google Compute Engine)을 통해서 간단하게 VM을 생성하고 웹서버를 띄우는 방법에 대해서 알아보자.

계정 가입

먼저 GCP 클라우드를 사용하기 위해서는 구글 계정에 가입한다. 기존에 gmail 계정이 있으면 gmail 계정을 사용하면 된다. http://www.google.com/cloud 로 가서, 좌측 상당에 Try it Free 버튼을 눌러서 구글 클라우드에 가입한다.




다음 콘솔에서 상단의 Google Cloud Platform 을 누르면 좌측에 메뉴가 나타나는데, 메뉴 중에서 “결제" 메뉴를 선택한후 결제 계정 추가를 통해서 개인 신용 카드 정보를 등록한다.


개인 신용 카드 정보를 등록해야 모든 서비스를 제한 없이 사용할 수 있다.  단 Trial의 경우 자동으로 한달간 300$의 비용을 사용할 수 있는 크레딧이 자동으로 등록되니, 이 범위를 넘지 않으면 자동으로 결제가 되는 일이 없으니 크게 걱정할 필요는 없다.


프로젝트 생성

계정 생성 및 결제 계정 세팅이 끝났으면 프로젝트를 생성한다.

프로젝트는 VM이나 네트워크 자원, SQL등 클라우드 내의 자원을 묶어서 관리하는 하나의 집합이다. 여러 사람이 하나의 클라우드를 사용할때 이렇게 프로젝트를 별도로 만들어서 별도로 과금을 하거나 각 시스템이나 팀별로 프로젝트를 나눠서 정의하면 관리하기가 용이하다.


화면 우측 상단에서 프로젝트 생성 메뉴를  선택하여 프로젝트를 생성한다.



프로젝트 생성 버튼을 누르면 아래와 같이 프로젝트 명을 입력 받는 창이 나온다. 여기에 프로젝트명을 넣으면 된다.


VM 생성


프로젝트가 생성되었으면, 이제 VM을 만들어 보자

좌측 메뉴에서 Compute Engine을 선택한다.


다음으로 바뀐 메뉴에서 좌측 VM 인스턴스를 선택한 후에, “인스턴스 만들기"를 통해서 인스턴스를 생성한다.

VM 인스턴스는 다음과 같은 조건으로 생성할것이다.


  • 인스턴스 이름은 ubuntu-instance

  • 가장 작은 사이즈의 인스턴스 (초소형 인스턴스 vCPU *1, 0.6G 메모리)

  • 10 GB의 로컬 디스크

  • Ubuntu 14.04LTS

  • 유동 외부 IP

  • HTTP 트래픽 허용


VM 생성창에서 위의 조건에 따라 아래 화면과 같이 설정값을 세팅 한후 VM을 생성한다. 나머지 값들은 디폴트로 놔두면 된다.





몇가지 주의할점은 “ID 및 API 액세스" 부분에서 “액세스 범위"를 “모든 Cloud API에 대한 전체 액세스 허용" 으로 세팅해줘야 한다. 이부분은 구글 클라우드에서 제공하는 API나 CloudSQL,BigQuery,Vision API 등 다른 서비스를 이 VM이 호출 할 수 있는 권한을 주는 것이다. 이 설정은 VM 생성 초기에 하지 않으면 차후에 변경이 불가능하니 반드시 설정 초기에 하기 바란다.


다음으로 “네트워크 부분”에 “외부 IP” 부분을 “임시”로 설정한다.


외부 IP 는

  • 지정하지 않음

  • 임시

  • 고정 주소


3가지를 선택할 수 있는데, 지정하지 않을 경우 이 VM은 외부 IP (Public IP)를 가지지 않기 때문에 인터넷에서 직접적으로 이 VM에 접근할 수 없다. HTTP 요청의 경우 별도의 프록시나 로드밸러서를 앞에 놓고 접근을 하거나 SSH와 같은 쉘 접근도 같은 내부 네트워크 (Private IP) 대역에 있는 다른 VM을 통해서만 접근이 가능하다. ( 이미 잘 알고 있겠지만 ) 외부 IP 주소를 가지지 않는 VM은 외부로 부터 접근을 차단하여 보안성을 높이기 위한 의도이다.


그리고 VM 생성시에 영역 (Zone)을 설정하는데, Zone은 클라우드 VM이 생성되는 장소라고 생각하면 된다.

리젼이 가장 큰 개념으로 대륙을 정의 한다. 미국 중부,서부,아시아,유럽 등이 리전에 해당하고, 각 리전안에는 여러개의 데이타 센타가 있는데, 이 데이타 센타를 영역 (Zone)으로 생각하면 된다. 이 예제에서는 asia-east1-a에 인스턴스를 생성한다.


인스턴스가 생성되면 아래 화면과 같이 생성된 인스턴스가 기동됨을 확인할 수 있다.



브라우져를 통한 SSH 접속

인스턴스가 생성되었으면 이제 생성된 인스턴스로 SSH로 접속해보자 PC의 Putty와 같은 SSH 터미널을 이용해서 접근하는 방법은 http://bcho.tistory.com/1103 링크를 참고하기 바란다.

이러한 방법이 복잡할 경우 화면에서 VM 우측에 SSH 버튼을 누른다.


그러면 별도의 SSH 터미널이 없이도 아래 그림과 같이 웹 브라우져 상에서 SSH 터미널을 오픈해준다.

아파치 웹서버 설치


SSH로 접속을 했으면, 이제 아파치 웹서버를 설치하고 기동해보자 설치는 우분투의 apt-get 유틸리티를 사용할것이다.

먼저 apt-get 저장소를 최신으로 업데이트 하기 위해서 다음 명령어를 실행한다.

%sudo apt-get update

다음으로 apache2 웹 서버를 설치해보자

%sudo apt-get install apache2


설치가 끝나면 자동으로 apache 웹서버가 기동이 된다. 혹시 기동이 되고 있지 않다면 다음 명령어를 이용해서 기동하자

%sudo apachectl start


기동이 되었는지를 확인하려면 이 VM의 외부 IP(public ip)로 브라우져를 통해서 접속해보자.

접속이 성공하면 다음과 같은 페이지가 브라우져에 뜨는 것을 확인할 수 있다.




VM 삭제


만약에 서비스를 계속해서 하지 않을 것이면 VM 을 정지하거나 삭제하면된다.

정지와 삭제의 차이는  정지된 VM은 나중에 재 시작이 가능하다. 단 스토리지 비용은 계속 과금 된다. 삭제는 VM을 없애 버리는 것으로 다시 재시작이 불가능하고 당연히 아무 비용도 과금되지 않는다.


VM의 정지나 삭제는 아래 그림과 같이 인스턴스 목록에서 정지 또는 삭제하고자 하는 VM을 선택한 후, 상단 메뉴에서 [정지] 또는 [삭제] 메뉴를 선택하면 된다.




참고 자료



구글 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


구글 클라우드 VM으로 SSH  접속하기


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


클라우드에서 VM을 생성하면, 이 VM에 접속하기 위해서 리눅스 VM의 경우 일반적으로 SSH 연결을 사용한다.

구글 클라우드에서 SSH를 이용하여 VM에 접속하는 방법을 알아본다.


1. SSH 키페어 생성

ssh-keygen 명령어를 이용하여 다음과 같이 RSA 키페어를 생성한다.

%ssh-keygen -t rsa -C "구글계정명"



2. 키페어가 생성이 되었으면 *.pub으로 끝나는 이름의 퍼블릭키의 내용(텍스트)를 복사한후, 콘솔창에서 "Compute Engine > Metadata > SSH Keys"  부분에 복사한 텍스트를 붙여 넣어서 키를 등록한다.




3. 키 등록이 끝났으면, 이 키를 이용하여 SSH로 접속한다.

% ssh -i [Private 키 파일] 계정@호스트명



다르게 생각해볼만한 클라우드 컴퓨팅 활용 전략


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


근래에 스타트업 기반의 빠른 속도의 개발을 경험하고, 클라우드 컴퓨팅 도입 전략에 대해서 고민할 기회가 생겨서 여러 자료를 검토하던중에 퍼블릭 클라우드 도입 전략에 대해서 기존과 다른 접근 방식이 필요하다고 생각되어 그 내용을 정리합니다.


특정 벤더의 의존성 배제


퍼블릭 클라우드 하면 거의 공식 처럼 AWS 클라우드가 소위 말해서 갑이었으나, 근래에 들어서 구글이나 마이크로소프트가 큰 딜을 잡아나가면서 약간씩 구도가 바뀌고 있는 형상이다.  

 특히 구글의 Spotify와, Quizlet의 사례를 보면 구글 사용사례이기 때문에 구글이 좋다는 이야기지만, 내용을 디테일하게 살펴보면 꽤나 재미 있는 인사이트를 얻을 수 있다.

  • Quizlet의 사례 https://quizlet.com/blog/whats-the-best-cloud-probably-gcp
  • Spotify의 사례 https://news.spotify.com/us/2016/02/23/announcing-spotify-infrastructures-googley-future/




Quizlet의 사례는 가격과 성능에 대한 이야기인데 내용을 요약하면 비슷한 VM이면 구글이 더 싸고 성능 (CPU,메모리, 네트워크)이 훨씬 좋다는 것이다. 아마존은 다양한 가격정책으로 다양한 컴퓨팅 파워를 제공하지만 그만큼 세밀한 가격 정책에 의해서, 높은 성능을 내려면 그만큼 추가 상품을 사야 하는데 비해서, 구글의 경우에는 기본 VM들의 네트워크가 IO 성능들이 높다는 것이다.


여기서 구글의 우수성을 보는것 보다, 이게 왜 좋은지에 대한 인사이트를 얻어야 하는데, 아마존은 다른 클라우드 벤더에 비해서 포트폴리오가 매우 다양하다. 인코딩, IAM, 하드웨어 기반의 키 보안 기술 등 그래서 한번 특정 클라우드에 들어가면 다른 클라우드로 옮기기가 쉽지 않은게 사실인데, 잘 생각해보면, 근래의 클라우드 기반의 아키텍쳐는 다음과 같은 트렌드를 갖는다.


VM위에 직접 설치해서 사용


EC2와 같은 VM만 있으면 그위에 직접 소프트웨어를 설치해서 운영을 하면 된다는 것이다. 아마존에서 제공하는 RDS나 RedShift 와 같은 서비스도 결국은 MySQL이나 Postgres와 같은 오픈 소스 기반이고 대부분이 오픈소스나 기존 제품을 기반으로 되어있기 때문에 교체가 가능하다는 것이다. 강한 기술조직을 가지고 있는 기업의 경우 직접 이러한 제품들을 설치 및 운영이 가능하기 때문에 특정 벤더에 Lock in이 되는것을 최소화할 수 있다.

단 이런 소프트웨어를 설치해서 사용하기 위해서는 VM 자체의 성능과 가격이 중요해진다. 네트워크나 디스크 IO의 속도나 GPU 지원 여부등이 중요한 판단 포인트로 작용을 하게 된다.


즉 이 이야기는 EC2와 같은 컴퓨팅과 S3와 같은 스토리지와 같은 필수 서비스만 제공한다면 어떤 클라우드가 되던지 크게 문제가 없다는 것으로 생각할 수 있다.


매니지드 서비스의 분리


스타트업이나 또는 운영을 자동화하여 개발에 집중하는 조직의 경우 RDS와 같은 클라우드 서비스 제공자가 운영을 대신 해주는 managed 서비스를 이용하는 것을 선호하는데,  근래에 들어서 매니지드 서비스를 전문적으로 제공하는 업체들이 많아졌다. mongoDB나 Redis와 같은 NoSQL의 솔루션을 매니지드 서비스의 형태로 제공하는 compose.io를 보면, 이러한 서비스를 AWS, IBM Softlayer, Digital Ocean등의 몇몇 클라우드 (IaaS)위에서 제공한다는 것이다. 


내가 어떤 IaaS를 사용하건간에, 전문화된 업체를 통해서 특정 솔루션을 매니지드 서비스 형태로 사용이 가능하다. 또 다른 사례중의 하나는 PaaS 플랫폼으로 유명한 Heroku의 경우인데, Heroku는 PaaS 이지만, 사실상 아래 인프라는 AWS로 되어 있다. 현재는 AWS만 지원 하지만, 클라우드 시장이 커감에 따라서 다른 인프라를 충분히 지원이 가능하다고 볼 수 있다. Heroku의 경우 아마존 회사가 아니라 Salesforce.com에 인수되었기 때문에 아마존을 꼭 사용해야 하는 이유가 없다, Cloud Foundary라는 오픈소스를 이용해서 구현이 되었기 때문에 VM만 있다면 큰 문제 없이 다른 인프라에 배포가 가능하다.  (Heroku는 CF를 기반으로 하지 않는다. IBM의 Bluemix가 CF 기반임)





정리해서 말하자면 인프라 클라우드 사업자가 있고 그 위에 매니지드 서비스를 제공하는 전문 사업자들이 점점 더 늘어날 것이고, 이 사업자들은 인프라에 대한 종속성이 없기 때문에, 인프라 클라우드의 차별화가 그다지 크지 않아질 수 있어서 특정 벤더에 대한 종속성이 약해질것이라고 본다.


오픈 API를 통해서 하이브리드 클라우드 기반의 서비스 분산 배치


오픈 소스로 대체가 불가능한 특별한 서비스들이 있는데, AI나 빅데이타에 관련된 것들이 그러하다, 마이크로 소프트나 구글의 경우 머신 러닝 기능을 OPEN API 형태로 제공하고 있고, 알고리즘이 자사의 노하우가 들어가 있는 형태이기 때문에, 다른 오픈소스로 대처가 어렵다 물론 Spark ML과 같은 라이브러리등이 있기는 하지만 개발에 들어가는 노력이나 알고리즘의 품질이 차이가 많이 난다. 얼마전에 구글이 영상 인식을 가능하게 해주는 VISION API를 발표하였고, 마이크로 소프트도 이 보다 많은 기능을 가지고 있는 영상 인식 API를 발표하였다. 흥미로운 점은 이것들이 API로 서비스가 된다는 것이고 이말인 즉, 원격에서 호출이 가능하다는 이야기다. 

이런 API의 특성상 처리 시간이 호출시간에 비해서(네트워크 시간) 길기 때문에, 리모트로 호출한다고 해서 아주 크게 문제가 되지 않고, 근래의 아키텍쳐 특성상 MSA(마이크로 서비스 아키텍쳐)와 같은 분산 서비스 아키텍쳐가 주류를 이루고 있기 때문에, 메인 시스템과 이러한 API 시스템이 꼭 같은 위치에 있지 않더라도 크게 문제가 없다.


클라우드 서비스 제공자 선택은 가격 보다는 부가 서비스와 기술 지원이 관건


Spotify에 사례를 보면 재미있는 것중에 하나가 구글 클라우드를 선택한 주요 이유가 빅데이타 플랫폼과 기술 지원이다.

 Spotify 의 블로그 내용을 보면 가격은 크게 의사 결정 요소로 작용하지 않았다는 것이다. 실제로 요즘 클라우드 시장이 과열이 되면서 디스카운트가 많이 들어가고 있고, 특히 소위 잘나가는 벤더와 잘나가지 못하는 벤더 (조이언트나 랙스페이드 등)가 갈려지면서, 잘 나가지 못하는 벤더들이 레퍼런스를 잡기 위해서 파격적인 할인에 나서고 있다. 클라우드 컴퓨팅의 인프라 가격은 규모의 경제 측면에서 큰 벤더들이 계속해서 시장을 잠식해 나갈 것이고 자체 기술 개발을 통해서 점점 더 가격을 낮춰갈것이다. 아마존의 경우에도 자사의 데이타 센터에 최적화된 CPU를 인텔에 주문했을정도로 이제 인프라 최적화는 점점 더 가속화되어가고 있고, ARM CPU 기반의 서버도 시장에 조금씩 나오는 만큼 가격 경쟁은 가속화 되리라 본다. 특히 통계를 보면 클라우드 가격은 매년 13% 정도씩 감소하고 있다고 한다.


그러면 Spotify가 구글 클라우드 플랫폼을 선택한 이유는 무엇일까?

빅데이타 플랫폼에서 찾을 수 있다. 구글이 경쟁사 대비 더 좋은 빅데이타 플랫폼 서비스를 제공하고 있다는 것인데, AWS의 빅데이타 플랫폼의 하둡이나 스파크, RedShift와 같은 기존의 오픈 소스를 매니지스 서비스로 제공하는 것이 주요 전략이라면, (물론 Dynamo처럼 직접 원천 기술을 만들어서 제공하는 서비스도 있다.) 구글은 기술의 종가답게 이러한 기술들에 대해서 강점을 가지고 있다고 Spotify 블로그에서 전하고 있다.


즉 앞에서 설명한것과 같이 VM 서비스는 평준화 되어 크게 비교 포인트가 되지 못할 것이며, 부가 서비스들 중에서 AI나 빅데이타 영역과 같이 특화되어 대체가 어려운 서비스를 가지고 있는 업체가 강점을 가지게 될것이다.


아울러 기술 지원 부분은 기술 도입에 있어서 중요한데, AWS의 경우 일주일이 멀다하고 계속해서 신기술과 업데이트가 발표되고 있다. 이러한 상황에서 실무 입장에서 새로운 기술을 일일이 찾아보고 자사의 시스템을 클라우드 서비스 제공자에 최적화 하는데는 많은 공부가 필요하고 서비스 제공자에게 서비스 개선등을 요청하기 위해서 원할한 커뮤니케이션 채널이 필요하다. 이를 흔히 프리세일즈(물건을 팔기전에 기술적으로 기술을 설명해주는)와 포스트 세일즈(물건을 판후에, 잘 사용할 수 있도록 지원하는)라고 하는데, 클라우드는 특성상 Self Service의 개념을 가지고 직접 배워서 직접 사용한다는 개념인데, 그러기에는 기술의 속도가 너무 빨라서 이에 대한 지원이 필요하다는 것이다. 실제로 엔터프라이즈 시장에서 성공했던 오라클이나 IBM과 같은 공룡들도 많은 매출이 제품을 판 후에 구현을 도와주는 포스트 세일즈에서 발생을 하였고, 프리세일즈 과정에도 많은 리소스를 투여했던 것이 사실이다.


아직은 클라우드 서비스 제공자의 프리/포스트 세일즈가 강하지는 않지만 (있기는 있다). 이쪽이 성장하면서 좋은 프리/포스트 세일즈 조직을 가진쪽이 비지니스 딜에 좋은 포지션을 가지게 될것이라고 생각해본다.


하이브리드 클라우드 전략


기업의 클라우드 전략을 보면 크게 두가지 갈래로 나뉘어 지는데, 자체 데이타 센터 구축 전략과 클라우드 활용 전략이다.

페이스북과 같은 경우 자체 클라우드를 사용하고, 애플의 경우에도 자체 데이타 센터를 구축하고 있는 것으로 알려지고 있다. http://fortune.com/2016/02/02/apple-data-center-move/

페이스북이나 구글같은 전통적인 테크 기업이면서 서비스 볼륨이 일정 규모 이상되는 경우는 규모의 경제상의 경제상에서 자체 데이타 센터를 구축하고, 자체 서비스에 맞는 인프라를 최적화 해가는 방향으로 집중을 하고 있다. 


반면 Netflix나 Spotify와 같은 서비스 기업은 서비스 개발에 집중을 하고, 인프라는 퍼블릭 클라우드를 사용하는 형태로 방향을 잡아가고 있다. 아무리 인력을 투여해도 퍼블릭 클라우드에서 개발하는 신규 기능을 따라 잡기도 힘들뿐더러, 비용 최적화 면에서도 규모의 경제 특성상 퍼블릭 클라우드가 유리하다는 판단하에서다.





그러면 퍼블릭 클라우드와, 자체 데이타 센터 무엇이 정답일까? 사실은 잘 모르겠다. 

하나 힌트를 얻자면, 애플의 클라우드 전략에서 살펴볼 수 있는데, 애플은 규모의 경제면에서 자체 클라우드를 갖출 정도로 큰 iCloud 서비스를 사용하고 있지만, 자체 클라우드 전략의 이면에서는 데이타 보안에 대한 부분이 있다. 고객의 중요 데이타를 타사의 클라우드에 넣는 것이 계속해서 부담이 되어 왔다. 


그렇다면, 중요 데이타나 중요 시스템은 자사의 클라우드에서 서비스하고, 다른 서비스나 또는 모자른 자원은 퍼블릭 클라우드를 사용하는 하이브리드 클라우드 전략을 갖추지 않을까 조심스럽게 생각해본다.


근래에 얻은 인사이트를 기록해놓고자 정리를 하였지만, 클라우드 컴퓨팅은 이제 거의 필수제가 되어가는것 같다. 특히나 구글,MS,아마존과 같이 규모의 경제를 앞세운 거대 기업들이 이 주도권을 잡아가면서 다른 사업자들은 힘을 잃어가면서 대형 서비스 제공자만 살아 남을것으로 보이고, Digital Ocean과 같은 niche vendor (특정 도메인에 선택과 집중을 통해서 가치를 창출해나가는)들은 특화된 서비스로 특화된 시장을 열어 나갈것이라고 보인다.


서비스 전략이나 시스템 아키텍쳐 설계도 이러한 클라우드 벤더의 변화에 맞춰서 다양화를 해나가야 하지 않을까?

예전 같으면 AWS를 깔고 시스템을 디자인 했다면, 요즘에 다시 시스템을 디자인 한다면 One of IaaS 서비스 + Compose.IO 와 같은 매니지스 서비스 기반의 설계가 조금 더 실용적이 아닐까 생각해본다.