Google Cloud with Kubernetes 여기서의 목표는 우리가 개발한 코드를 Kubernetes Engine 에서 실행되는 Kubernetes에서 실행되는 복제된(replicated) application으로 만드는 것입니다. 여기서는 간단한 node-js 앱을 개발할 것입니다. 여기서 사용되는 다양한 Google Cloud Platform의 다양한 컴포넌트를 볼 수 있습니다. Kubernetes는 오픈 소스 프로젝트로 (kubernetes.io) 고 가용성을 가진 다중의 노드 클러스터에 이르기까지 다양한 환경에서 실행할 수 있습니다. 공개의 Cloud나 on-premise 배포서부터, VM(Virtual Machine)에서 실제 machine(bare metal)까지 실행 가능합니다. 여기서는 Kubernetes Engine(Compute Engine에서 실행되는 Kubernetes의 Google 호스팅 버전)과 같은 관리 환경을 사용하여 기본 infrastructure를 설정하는 대신, Kubernetes에 많은 경험을 할 수 있습니다. node-js 서버를 생성합니다. Docker container image를 생성합니다. container 클러스터(cluster)를 생성합니다. Kubernetes pod를 생성합니다. service를 scale-up 해봅니다. https://cloud.google.com/?hl=ko 로그인을 진행하고 콘솔로 이동합니다. 콘솔로 이동하면 다음의 사이트로 보입니다. GCP(Google Cloud Platform)에서 오른쪽 상단 툴바의 Cloud Shell 아이콘을 클릭합니다. "Start Cloud Shell" 버튼을 클릭합니다. 환경을 제공하고 연결하는 데 몇 분이 걸립니다. Cloud Shell을 사용하여 Kubernetes Engine에 배포할 application을 작성합니다. 다음은 간단한 Node.js 서버를 만드는 코드입니다. 다음의 코드를 채워 놓습니다. server.js를 저장하고 나옵니다. Cloud Shell에는 node를 실행할 수 있도록 설치되어 있습니다. node를 실행해봅시다. Cloud Shell의 기본적으로 제공하는 ‘웹 미리보기 기능'을 사용하여 새 브라우저 탭을 열고 방금 시작된 port 8080에서 요청을 하도록 프록시(proxy)합니다. 파란색 동그라미의 ‘웹 미리 보기’를 클릭하고 포트에서 미리 보기 8080을 클릭합니다. 새로운 tab에서 다음과 같은 결과가 나옵니다. 실행중인 node server를 멈추기 위해서는 Ctrl+C를 입력합니다. 이제 중요한 것은 Docker Container에 application을 패키지(package)하는 것입니다. 다음으로는, 빌드(build)할 image를 설명하는 Dockerfile을 생성합니다. Docker Container image는 기존의 image에서 확장될 수 있습니다. 여기의 image는 기존의 node image에서 확장됩니다. Edit를 시작합니다. 내용을 추가합니다. 여기서의 code에서는 - Docker Hub에 있는 node image에서 시작합니다. - port 8080을 Expose 합니다. - server.js 파일을 image로 복사합니다. - node server.js 명령어를 수행합니다. 다음의 image를 빌드(build)합니다. PROJECT_ID를 본인의 project ID로 수정합니다. 모든 것을 다운로드하고, 압축하는데 다소의 시간이 걸리며, image가 빌드됨에 따라 진행 막대가 표시됩니다. 완료되면 새롭게 Docker Container 생성됩니다. 이 Container image를 daemon으로 실행되는 port 8080에서 테스트해봅시다. 결과는 다음과 같습니다. Cloud Shell에서 제공하는 ‘웹 미리보기’ 기능으로 결과를 확인해봅시다. 또는 curl이나 wget 명령어를 사용해봅시다. 결과는 다음과 같습니다. Docker run 명령에 대한 설명서는 다음의 사이트에서 찾을 수 있습니다. https://docs.docker.com/engine/reference/run/ Now let's stop the running container. 이제 실행중인 container를 정지합니다. Docker container ID를 찾아봅시다. 결과는 다음과 같습니다. container ID를 이용해 정지합니다. 결과는 다음과 같습니다. image가 의도하는 대로 작동되므로, Docker image의 비공개 저장소인 GCR(Google Container Registry) push 해봅시다. 초기 push를 완료하는데 시간이 소요됩니다. build되는 동안 프로그레스 바(progress bar)로 확인할 수 있습니다. 결과는 다음과 같습니다. container image는 Tools > Container Registry에서 리스트로 확인할 수 있습니다. 이제 Kubernetes가 접근하고 orchestrate 할 수 있는 Docker image를 사용할 수 있습니다. 이제 Container Engine 클러스터(cluster)를 만들 준비가 되었습니다. cluster는 Google에서 호스팅하는 Kubernetes Master API 서버와 일련의 Worker node로 구성됩니다. Worker node는 Computer Engine의 VM(Virtual Machine)입니다. Console의 Kubernetes cluster 섹션으로 이동하여 시스템이 초기화될 때까지 기다립니다. gcloud에 PROJECT_ID의 설정을 확실하기 위해 Console에 있는 project id로 진행합니다. 클러스터를 구성하기 전에 앞서 GCP의 Instance에 대해서 알아봅시다. https://cloud.google.com/kubernetes-engine/ 인스턴스 가격에 따르면 f1-micro VM은 매달마다 무료로 사용 가능합니다. 다른 인스턴스 가격정보는 다음과 같습니다. https://cloud.google.com/compute/pricing?hl=ko 클러스터를 구성하기 위해서는 VM의 개수가 3대 이상이 필요합니다. Kubernetes Engine 사이트에서도 클러스터를 만들 수 있지만 명령어로 직접 만들어 봅시다. 3 개의 f1-micro 노드로 구성된 cluster를 다음의 명령어로 만듭니다. 완료하는데 몇 분 정도 소요됩니다. 결과는 다음과 같습니다. container registry에서 사용하는 저장소 bucket과 동일한 영역에 cluster를 생성하는 것이 좋습니다. Kubernetes Engine에 의해 구동되는 Kubernetes 클러스터는 완벽하게 작동합니다. 자 이제 우리의 컨테이너화된 application을 Kubernetes 클러스터에 배포할 차례입니다. 이제부터는 kubectl(Cloud Shell 환경에 설정되어 있음)을 사용합니다. Kubernetes 포드(pod)는 관리와 네트워킹 목적으로 함께 묶인 container 그룹입니다. 단일 또는 다중의 container를 포함할 수 있습니다. 여기서는 private container registry에 있는 Node.js image로 빌드된 하나의 container를 사용합니다. 여기서는 port 8080에서 내용을 제공합니다. kubectl run의 명령어로 pod를 생성해봅시다. 결과는 다음과 같습니다. 보다시피, 우리는 deployment 객체를 생성했습니다. pod를 만들고, 크기를 조정하는데 deployment가 권장됩니다. 새로운 deployment는 hello-node:v1 image를 실행하는 단일 pod 복제본을 관리합니다. 방금 작성한 deployment를 확인하려면 다음의 명령어를 실행합니다. 결과는 다음과 같습니다. deployment로 만든 pod를 보려면 다음의 명령어를 실행합니다. 결과는 다음과 같습니다. 다음은 kubectl로 클러스터 상태를 확인할 수 있습니다. 기본적으로 pod는 클러스터(cluster)내의 내부 IP로만 액세스할 수 있습니다. hello-node container를 가상의 네트워크 외부에서 액세스를 가능하게 하려면, pod를 kubernetes service로 expose를 해야 합니다. Cloud Shell에서 --type 옵션을 이용해 LoadBalancer와 kubectl expose 결합된 명령어를 통해 pod를 공개 인터넷에 expose할 수 있습니다. 이 옵션은 외부에서 액세스할 수 있는 IP를 생성하는데 필요합니다. https://cloud.google.com/compute/docs/load-balancing/network/ Network Load Balancing을 사용하면 주소(address), 포트(port) 및 프로토콜(protocol) 타입과 같은 들어는 IP 프로토콜 데이터를 기반으로 시스템 부하를 분산시킬 수 있습니다. Network Load Balancing은 forwarding rules를 통해 target pool을 가리킵니다. 이 rules는 load balancing에서 사용할 수 있는 instances를 나열하고, 이러한 instances에서 수행하는 상태 검사 유형을 정의합니다. 이 명령에 사용된 flag는 Computer Engine load balancer를 사용하도록 지정합니다. pod로 직접 expose 않고, deployment를 expose 합니다. 이로 인해 서비스의 결과가 deployment에 의해 모든 pod에 트래픽(traffic)을 load balancing 하게 됩니다. 이 경우에는 1개의 pod이지만, 나중에는 더 많은 복제본(replicas)을 추가합니다. Kubernetes master는 load balancer 그리고 Compute engine forwarding rules 그리고 target pool을 만들어 Google cloud Platform 외부에서 서비스에 완벽하게 액세스 할 수 있습니다. 공개적으로 접근 가능한 서비스(public access IP)에 IP 주소를 찾으려면, kubectl get services 명령어를 입력합니다. 결과는 다음과 같습니다. 목록에서 port 8080을 2개의 IP 주소가 있습니다. 하나(CLUSTER-IP)는 내부 가상 사설망의 IP이며, 다른 하나(EXTERNAL-IP)는 외부 load balancing IP입니다. EXTERNAL-IP는 사용 가능하고 보이기 까지는 몇 분이 걸릴 수 있습니다. 이제 브라우저에서 이 주소로 이동하여 서비스에 연결할 수 있습니다. http://<EXTERNAL_IP>:8080 이 시점에서 우리는 container 그리고 Kubernetes로 이동하여 몇 가지 특징을 얻었습니다. load balancing를 실행할 호스트를 지정할 필요가 없으며, service 모니터링 및 재시작의 이점도 있습니다. 새로운 Kubernetes가 제공하는 강력한 특징 중 하나는 application을 확장하는 것이 얼마나 쉬운 지입니다. application에 갑자기 많은 용량이 필요하다고 가정을 해봅시다. 그 경우에는 pod에 대한 복제본(replicas)의 새로운 수를 관리하도록 replicaiton controller에 지시할 수 있습니다. 업데이트된 deployment를 살펴봅시다. 모든 pod의 리스트를 봅시다. 여기서는 선언적(declarative) 접근법을 사용하고 있습니다. 새로운 instance를 시작하거나 중지하는 대신 항상 실행해야 하는 instance 수를 선언해야 합니다. Kubernetes reconciliation 루프는 사용자가 요청한 것과 일치하는지 확인하고 필요한 경우 액션을 취합니다. 다음은 Kubernetes 클러스터의 상태를 요약한 다이어그램입니다. 어떤 시점에서 개발 환경에서 배포한 application의 bug를 수정하거나 기능 추가가 필요합니다. Kubernetes에는 사용자에게 영향을 주지 않고 새로운 버전으로 배포할 수 있도록 도와줍니다. 먼저 application을 수정해봅시다. server.js를 편집합니다. response의 message를 수정합니다. response.end("Hello Kubernetes World!"); 이제 우리는 업그레이드 버전(v2)로 registry에 새로운 container image를 빌드하고 게시(publish)할 수 있습니다. caching을 최대한 활용하면 업데이트된 image를 만들고 push하는 것이 더 빠를 것입니다. Kubernetes는 replication controller를 새로운 버전의 application으로 원활하게 업데이트할 것입니다. 실행중인 container의 image의 label을 변경하려면 기존 hello-node 배포를 편집하고 image를 gcr.io/PROJECT_ID/hello-node:v1에서 gcr.io/PROJECT_ID/hello-node:v2로 변경해야 합니다. 변경을 위해서 kubectl edit 명령을 사용해서 전체 deployment의 yaml 구성(configuration)을 텍스트 편집기로 열립니다. 전체 yaml 구성을 이해할 필요는 없습니다. pod를 새 image로 업데이트 하도록 spec.template.spec.containers.image 필드를 업데이트하면 됩니다. # Please edit the object below. Lines beginning with a '#' will be ignored, image를 gcr.io/kmu-bigdata/hello-node:v2 로 변경합니다. 변경을 마치고, file을 저장합니다. deployment를 새 image로 업데이트하려면 다음의 명령어를 실행합니다. 기존의 pod는 삭제되고, 새로운 image로 생성된 새로운 pod가 생성됩니다. 위의 일이 발생되는 동안 사용자가 사용하는 서비스는 중단을 하지 않아야 합니다. 조금 후에 application의 새로운 버전에 액세스하기 시작합니다. rolling updates에 대해서 다음의 사이트에서 확인할 수 있습니다. https://cloud.google.com/container-engine/docs/rolling-updates 결과를 확인해봅시다. 그래픽 웹 사용자 인터페이스(dashboard)는 최근 버전의 Kubernetes에서 소개되었습니다. dashboard를 사용하면 신속하게 시작할 수 있으며, CLI에 있는 일부 기능을 시스템에서 보다 쉽게 접근할 수 있습니다. Kubernetes 클러스터 dashboard에 대한 액세스를 구성하려면, Cloud Shell 에서 다음의 명령어를 실행합니다. Cloud Shell 웹 미리 보기에서 포트 변경을 하여 8081로 변경합니다. 포트 번호를 8081로 입력합니다. 그러면 API의 endpoint로 연결됩니다. dashboard로 이동하려면 ?authuser=0을 제거하고 “/ui”와 함께 URL을 추가합니다. https://8081-dot-3604478-dot-devshell.appspot.com/ui ~/.kube/config 를 열어 access-token: 키값을 복사합니다. 다음의 사이트가 열립니다. Token을 선택하여 토큰키값을 붙여넣고 SIGN IN 버튼을 클릭합니다. 로그인이 완료되었습니다 Kubernetes 그래픽 dashboard를 사용하여 container application을 배포하고, 클러스터 모니터링 및 관리에 사용할 수 있습니다.Overview
WHAT YOU’LL DO
Google Cloud Platform
ACTIVATE GOOGLE CLOUD SHELL
Create your Node.js application
$ vi server.js
var http = require('http');
var handleRequest = function(request, response) {
response.writeHead(200);
response.end("Hello World!");
}
var server = http.createServer(handleRequest);
server.listen(8080);$ node server.js
Create a Docker container image
$ vi Dockerfile
FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD node server.js$ docker build -t gcr.io/PROJECT_ID/hello-node:v1 .
$ docker run -d -p 8080:8080 gcr.io/PROJECT_ID/hello-node:v1
d26f28906671f12c87cf7f35c3c09243078b44fe31aa1b0500984bebca6a9572
$ curl http://localhost:8080
Hello World!
$ docker ps
$ docker stop heurstic_nobel
heuristic_nobel
$ gcloud docker -- push gcr.io/PROJECT_ID/hello-node:v1
The push refers to a repository [gcr.io/qwiklabs-gcp-6h281a111f098/hello-node]
ba6ca48af64e: Pushed
381c97ba7dc3: Pushed
604c78617f34: Pushed
fa18e5ffd316: Pushed
0a5e2b2ddeaa: Pushed
53c779688d06: Pushed
60a0858edcd5: Pushed
b6ca02dfe5e6: Pushed
v1: digest: sha256:8a9349a355c8e06a48a1e8906652b9259bba6d594097f115060acca8e3e941a2 size: 2002Create your cluster
$ gcloud config set project PROJECT_ID
$ gcloud container clusters create hello-world \
--num-nodes 3 \
--machine-type f1-micro \
--zone us-central1-fCreating cluster hello-world...done.
Created [https://container.googleapis.com/v1/projects/PROJECT_ID/zones/us-central1-f/clusters/hello-world].
kubeconfig entry generated for hello-world.
NAME ZONE MASTER_VERSION MASTER_IP MACHINE_TYPE STATUS
hello-world us-central1-f 1.5.7 146.148.46.124 n1-standard-1 RUNNINGCreate your pod
$ kubectl run hello-node \
--image=gcr.io/PROJECT_ID/hello-node:v1 \
--port=8080deployment "hello-node" created
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 1 1 1 1 2m$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-node-714049816-ztzrb 1/1 Running 0 6m$ kubectl cluster-info
$ kubectl config view
$ kubectl get events
$ kubectl logs <pod-name>
Allow external traffic
Load Balancing
$ kubectl expose deployment hello-node --type="LoadBalancer"
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node 10.3.250.149 104.154.90.147 8080/TCP 1m
kubernetes 10.3.240.1 <none> 443/TCP 5mScale up your service
$ kubectl get deployment
$ kubectl scale deployment hello-node --replicas=5
$ kubectl get deployment
$ kubectl get pods
Roll out an upgrade to your service
$ vi server.js
$ docker build -t gcr.io/kmu-bigdata/hello-node:v2 .
$ gcloud docker -- push gcr.io/kmu-bigdata/hello-node:v2
$ kubectl edit deployment hello-node
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: 2018-03-06T07:05:28Z
generation: 3
labels:
run: hello-node
name: hello-node
namespace: default
resourceVersion: "151017"
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/hello-node
uid: d05c8fad-210c-11e8-9a78-42010af00005
spec:
replicas: 5
selector:
matchLabels:
run: hello-node
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
run: hello-node
spec:
containers:
- image: gcr.io/PROJECT_ID/hello-node:v2 ## Update this line ##
imagePullPolicy: IfNotPresent
name: hello-node
ports:
- containerPort: 8080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
dnsPolicy: ClusterFirst
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30$ kubectl get deployments
Kubernetes graphical dashboard
$ gcloud container clusters get-credentials hello-world --zone us-central1-f --project <PROJECT_ID>
$ gcloud container clusters get-credentials hello-world --zone us-central1-f --project kmu-bigdata
$ kubectl proxy --port 8081
$ cat ~/.kube/config
'Google Cloud Platform' 카테고리의 다른 글
Google Cloud ML Vision API를 이용한 이미지 텍스트 추출 그리고 번역을 위한 Translation API와 Natural Language API (1) | 2018.04.10 |
---|---|
Deployments 관리 Kubernetes in Google Cloud Platform (0) | 2018.04.08 |
Jenkins Kubernetes Google Cloud (2) | 2018.04.01 |
Docker Hadoop 클러스터 Hive 설치 (0) | 2018.03.28 |
Orchestrating Google Cloud with Kubernetes (0) | 2018.03.12 |