kubernetes 어디까지 써봤니? 삽질기(2)
Kubernetes 삽질하다 일어난일
kubernetes 삽질의 시작은 이전글을 참조하기 바란다. 이번 글에서는 나의 작은 실수로 인해 분석가를 식겁하게 한 에피소드에 대해 이야기 해 보려 한다. 그전에 k8s에 deploy하기 위한 기본 개념에 대해 살펴볼 예정이다.
pod로 띄우기
pod는 한개 이상의 컨테이너로 구성되는 k8s에서 가장작은 deploy를 위한 단위이다. 이는 자신의 어플리케이션 스택에 서로 다른 docker image를 혼합하여 올릴 수 있다는 것이다. 다음의 예를 보자
pod-test.yaml 아래와 같이 작성하고 kubectl create -f pod-test.yaml이라고 명령하면 pod가 생성된다.
1 2 3 4 5 6 7 8 9 10 11
apiVersion: v1 kind: Pod metadata: name: pod-test spec: containers: - name: nginx image: nginx - name: centos image: centos command: ["/bin/sh", "-c", "while : ;do curl http://localhost:80/; sleep 3; done"]
kind에 deploy할 유형을 정의한다. metadata의 이름은 pod의 name이 된다. 컨테이너의 image는 centos와 nginx 두개를 구동할 것이며 centos에서는 nginx로 접근을 테스트 하는 예제이다. 다음과 같이 pod의 log를 확인해 보자
kubectl logs pod-test -c centos
centos컨테이너에 대해 logs를 확인해 보는것이다. centos의 명령어를 nginx를 call하는 명령어 이기 때문에 log 끝에 다음과 같이 curl이 수행된 메시지를 확인 할 수 있다.
100 612 100 612 0 0 430k 0 --:--:-- --:--:-- --:--:-- 597k
replication controller로 띄우기
pod의 replica의 개념으로 pod의 set을 제어할 수 있다. 사용자가 정의한 숫자에 따라 pod의 개수를 정하여 내부적으로 특정 pod의 문제가 발생했을때 pod를 재 생성하여 특정 개수의 프로세스를 유지한다. 아래 예제는 kafka를 동일 image로 5개 띄우는 예제이다. replicas는 5로 설정하였다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
{ "apiVersion": "v1", "kind": "ReplicationController", "metadata": { "creationTimestamp": null, "labels": { "app": "kafka-new", "service": "kafka-new" }, "name": "kafka-controller-new" }, "spec": { "replicas": 5, "selector": { "app": "kafka-new" },
다음과 같이 5개의 pod가 구성되었다.
1 2 3 4 5
kafka-controller-new-1qjv7 1/1 Running 0 33s kafka-controller-new-3zx3m 1/1 Running 0 33s kafka-controller-new-50625 1/1 Running 0 33s kafka-controller-new-dth9p 1/1 Running 0 33s kafka-controller-new-zvpvr 1/1 Running 0 33s
1 2
NAME DESIRED CURRENT READY AGE kafka-controller-new 5 5 5 1m
deployment 로 띄우기
deployment는 pod와 replica set(replication controller의 다음버전)에 대한 선언적 업데이트를 제공한다. 다음의 예제를 보자. jupyter notebook을 deployment로 띄운 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: jupyter-notebook spec: replicas: 1 selector: matchLabels: component: jupyter-notebook template: metadata: labels: component: jupyter-notebook spec: containers: - name: spark-jupyter image: jerryjung/jupyter-notebook:latest command: ["start-notebook.sh"] ports: - containerPort: 8888 resources: requests: cpu: 100m --- kind: Service apiVersion: v1 metadata: name: jupyter-notebook spec: type: LoadBalancer ports: - port: 80 targetPort: 8888 selector: component: jupyter-notebook
replication controller처럼 replicas를 설정 할 수 있으며 deploy시 rollback도 가능하다
Service동작시키기
위의 예에서 Service부분이 추가 되었다. k8s에 다양한 어플리케이션을 올리고 어플리케이션간 통신이 필요한 경우 Service로 오픈하여 외부에 오픈하거나 다른 어플리케이션 간 통신에 활용 할 수 있다. 위의 예에서는 80 port로 jupyter접근 port를 지정한 예이다. aws 에서 구동한 경우 LoadBalancer를 ELB로 제공하므로 개별적인 ELB가 할당 되고 사용자는 그것을 통해 컨테이너에 접근 할 수 있다. k8s 클러스터 내에 어플리케이션 간 통신이 필요한 경우라면 Service name으로 접근 가능 하다.
Volume붙이기
컨테이너에 존재하는 file들은 ephemeral(임시) 이다. 즉, 컨테이너가 어떠한 문제 발생으로 재 생성 되는경우 컨테이너 안의 데이터는 사라지게 된다. 글 서두에 언급했던 분석가를 식겁하게 만든일이 이것과 관련이 되어있다. 분석가는 k8s에 구성된 kafka와 jupyter를 통해 열심히 분석 코드(data preparation 및 algorithm)를 구현하였고 3일이 지난날 갑자기 모든것이 초기화 되었다며 난감한 표정을 지었다. 무엇이 문제였을까?
persist volume을 따로 안 붙여준 나도 문제였고 작성한 코드를 백업하지 못한 흐음... 해당 pod를 분석가가 활기차게 돌린 덕분에 pod는 재 실행 되었고 컨테이너 안의 데이터는 깔끔하게 사라지게 되었다.
k8s의 볼륨은 docker의 볼륨과 마찬가지로 mount 하는 개념이다. 즉, pod에서 disk를 붙이면서 설정 정보나 필요 파일들을 추가로 붙인 볼륨에 적용 하려면 pod를 생성다음 mount이후에 bootstrap 스크립트로 이동 시켜야 한다. 다음의 예는 아마존 EBS에서 volume을 생성한후 mount하는 방식이다.
1 2 3 4 5 6 7 8 9 10 11 12 13
spec: volumes: - name: ebs-volume awsElasticBlockStore: volumeID: vol-xxxxxxxxxxxxx fsType: ext4 containers: - name: jupyter-aws image: jerryjung/jupyter-notebook:latest volumeMounts: - mountPath: "/home/jupyter/work" name: ebs-volume command: ["start-notebook.sh"]
위의 예에서 volume관련 추가가 되었다. 위와 같이 하면 ebs 볼륨을 pod에 mount할 수 있게 되고 이렇게 되면 당연한 이야기겠지만 pod가 몇 번이 재 생성 되더라도 file은 휘발되지 않는다. 다음편에서는 k8s 과는 왠지 궁합이 맞을것 같지 않은 shared nothing architecture에 대해 deploy하고 멘붕을 겪은 에피소드를 소개하려고 한다. 필자에겐 성공사례는 보이지 않는다. 실패 사례를 통해 이 기술을 경험하는 다른 분들의 삽질을 조금이라도 줄여주었으면 한다.
TO BE CONTINUED