여기에서는 애플리케이션이 올라와 있는 것을 볼 수 있다.
티스토리 뷰
<출처>
https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/
Objectives
- K8S에서의 서비스에 대해 배운다.
- 레이블과 레이블셀렉터 오브젝트가 어떻게 서비스와 관계하는지 이해한다.
- 서비스를 이용하여 K8S 클러스터 외부로 애플리케이션을 노출한다.
Overview of Kubernetes Services
K8S 파드들은 언젠가는 죽게된다. 실제 파드는 생명주기를 갖는다. 워커 노드가 죽으면, 노드 상에서 동작하는 파드들 또한 종료된다. 레플리케이션 컨트롤러는 여러분의 애플리케이션이 지속적으로 동작할 수 있도록 새로운 파드들의 생성을 통해 동적으로 클러스터를 미리 지정해 둔 상태로 되돌려 줄 수도 있다. 또 다른 예시로서, 3개의 복제본을 갖는 이미지 처리용 백엔드를 고려해 보자. 그 복제본들은 대체 가능한 상태이다. 그래서 프론트엔드 시스템은 하나의 파드가 소멸되어 재생성이 되더라도, 백엔드 복제본들에 의한 영향을 받아서는 안된다. 즉, 동일 노드 상의 파드들이라 할지라도, 쿠버네티스 클러스터 내 각 파드는 유일한 IP 주소를 가지며, 여러분의 애플리케이션들이 지속적으로 기능할 수 있도록 파드들 속에서 발생하는 변화에 대해 자동으로 조정해 줄 방법이 있어야 한다.
K8S에서 서비스는 하나의 논리적인 파드 셋과 그 파드들에 접근할 수 있는 정책을 정의하는 추상적 개념이다. 서비스는 종속적인 파드들 사이를 느슨하게 결합되도록 해준다. 서비스는 모든 쿠버네티스 오브젝트들과 같이 YAML (보다 선호하는) 또는 JSON을 이용하여 정의된다. 서비스가 대상으로 하는 파드 셋은 보통 레이블셀렉터에 의해 결정된다 (스펙에 selector가 포함되지 않은 서비스를 왜 필요로 하게 될 수 있는지는 아래에서 확인해 보자).
비록 각 파드가 고유의 IP를 가지고 있기는 하지만, 그 IP들은 서비스의 도움없이 클러스터 외부로 노출되어질 수 없다. 서비스들은 여러분의 애플리케이션들에게 트래픽이 실릴 수 있도록 허용해준다. 서비스들은 "ServiceSpec"에서 "type"을 지정함으로써 다양한 방식들로 노출시킬 수 있다:
- ClusterIP (기본값) - 클러스터 내에서 내부 IP 에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.
- NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. "<NodeIP>:<NodePort>"를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. "CluserIP"의 상위 집합이다.
- LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. "NodePort"의 상위 집합이다.
- ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 "externalName"으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.
다른 서비스 타입들에 대한 추가 정보는 소스 IP 이용하기 튜토리얼에서 확인 가능하다. 또한 서비스들로 애플리케이션에 접속하기도 참고해 보자.
부가적으로, spec에 "selector"를 정의하지 않고 말아 넣은 서비스들의 몇 가지 유즈케이스들이 있음을 주의하자. "selector" 없이 생성된 서비스는 상응하는 엔드포인트 오브젝트들 또한 생성하지 않는다. 이로써 사용자들로 하여금 하나의 서비스를 특정한 엔드포인트에 매핑 시킬수 있도록 해준다. selector를 생략하게 되는 또 다른 가능성은 여러분이 "type: ExternalName"을 이용하겠다고 분명하게 의도하는 경우이다.
쿠버네티스 서비스는 논리적 파드 셋들을 정의하고 외부 트래픽을 노출, 로드밸런싱 그리고 그 파드들에 대한 서비스 디스커버리를 가능토록 해 주는 추상 계층이다.
Services and Labels
서비스는 파드 셋에 걸쳐서 트래픽을 라우트한다. 여러분의 애플리케이션에 영향을 주지 않으면서 K8S에서 파드들이 죽게도 하고, 복제가 되게도 해주는 추상적 개념이다. 종속적인 파드들 사이에서의 디스커버리와 라우팅은 (하나의 애플리케이션에서 프로트엔드와 백엔드 컴포넌트와 같은) K8S 서비스들에 의해 처리된다.
서비스는 대해 논리 연산을 허용해주는 기본 그룹핑 단위인, 레이블과 셀렉터를 이용하여 파드 셋과 매치시킨다. 레이블은 오브젝트들에 붙여진 키/밸류 쌍으로 다양한 방식으로 이용 가능하다:
- 개발, 테스트, 그리고 상용환경에 대한 객체들의 지정
- 임베디드된 버전 태그들
- 태그들을 이용하는 객체들에 대한 분류
여러분은 kubectl 명령에 --expose 옵션을 사용함으로써 디프롤이먼트 생성과 동일 시점에 서비스를 생성할 수 있다.
레이블은 오브젝트의 생성 시점 또는 이후 시점에 붙여질 수 있다. 언제든지 수정이 가능하다. 이제 서비스를 이용하여 우리의 애플리케이션을 노출도 시켜보고 레이블도 적용해 보자.
Interactive Tutorial - Exposing Your App
이번 시나리오에서 kubectl 노출 명령을 이용하여 클러스터 외부로 K8S 애플리케이션을 노출시키는 방법을 배우게 될 것이다. 또한 kubectl label 명령을 통해 오브젝트들에 레이블을 적용하고 확인하는 방법도 배우게 될 것이다.
Step 1: Create a new service
우리의 애플리케이션이 잘 동작하고 있는지 확인해 보자. "kubectl get" 명령을 이용하여 파드가 존재하는지 찾아 볼 것이다.
1 2 3 | root@zerobig-vm:~# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-5c69669756-d4kgp 1/1 Running 1 10h | cs |
현재 클러스터 상의 서비스에 대한 리스트를 살펴 보자.
1 2 3 | root@zerobig-vm:~# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d | cs |
minikube 가 클러스터를 시작시킬 때, 기본적으로 생성된 kubernetes라는 서비스가 있다. 새로운 서비스를 생성하고 그것을 외부 트래픽에 노출시키기 위해 우리는 NodePort 를 파라미터로 하여 함께 노출 명령에 이용할 것이다. (minikube 에서는 LoadBalancer 옵션이 아직 지원되지 않는다.)
1 2 | root@zerobig-vm:~# kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080 service/kubernetes-bootcamp exposed | cs |
다시 "get services" 명령을 수행해 보자.
1 2 3 4 | root@zerobig-vm:~# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d kubernetes-bootcamp NodePort 10.97.92.75 <none> 8080:32036/TCP 1m | cs |
이제 kubernetes-bootcamp라 불리는 서비스가 동작 중이다.
고유한 cluster-IP 와 내부포트 그리고 external-IP (노드의 IP) 가 할당된 것을 볼수 있다.
(실제로 Minikube 환경에서는 external-IP가 할당되지 않는다.)
어떤 포트가 외부로 오픈되었는지 (NodePort 옵션에 의해서) "describe service" 명령을 수행해 볼 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | root@zerobig-vm:~# kubectl describe services/kubernetes-bootcamp Name: kubernetes-bootcamp Namespace: default Labels: run=kubernetes-bootcamp Annotations: <none> Selector: run=kubernetes-bootcamp Type: NodePort IP: 10.97.92.75 Port: <unset> 8080/TCP TargetPort: 8080/TCP NodePort: <unset> 32036/TCP Endpoints: 172.17.0.5:8080 Session Affinity: None External Traffic Policy: Cluster Events: <none> | cs |
1 2 3 | root@zerobig-vm:~# export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}') root@zerobig-vm:~# echo NODE_PORT=$NODE_PORT NODE_PORT=32036 | cs |
이제 "curl" 을 이용하여 클러스터 외부로 노출된 앱을 테스트 해볼 수 있다, 노드의 IP 와 외부로 노출된 포트는 다음과 같다.
1 2 3 | root@zerobig-vm:~# curl $(minikube ip):$NODE_PORT Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5c69669756-d4kgp | v=1 | cs |
서버로부터 응답을 받았다. 서비스가 노출되어진 것이다.
Step 2: Using labels
디플로이먼트는 파드에 대한 레이블을 자동으로 생성해준다. "describe 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 | root@zerobig-vm:~# kubectl describe deployment Name: kubernetes-bootcamp Namespace: default CreationTimestamp: Thu, 09 Aug 2018 00:31:44 +0900 Labels: run=kubernetes-bootcamp Annotations: deployment.kubernetes.io/revision=1 Selector: run=kubernetes-bootcamp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: run=kubernetes-bootcamp Containers: kubernetes-bootcamp: Image: gcr.io/google-samples/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: kubernetes-bootcamp-5c69669756 (1/1 replicas created) Events: <none> | cs |
1 2 3 4 | root@zerobig-vm:~# kubectl get pods -l run=kubernetes-bootcamp NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-5c69669756-d4kgp 1/1 Running 1 10h | cs |
존재하는 서비스의 리스트에 대해서도 마찬가지 방식으로 수행 가능하다.
1 2 3 4 | root@zerobig-vm:~# kubectl get services -l run=kubernetes-bootcamp NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes-bootcamp NodePort 10.97.92.75 <none> 8080:32036/TCP 27m | cs |
파드의 이름을 확인하여 POD_NAME 환경변수에 그 값을 저장한다.
1 2 3 4 | root@zerobig-vm:~# export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') root@zerobig-vm:~# echo Name of the Pod: $POD_NAME Name of the Pod: kubernetes-bootcamp-5c69669756-d4kgp | cs |
새로운 레이블을 적용하기 위해 오브젝트 타입을 뒤에 추가하여 레이블 명령을 사용한다.
1 2 | root@zerobig-vm:~# kubectl label pod $POD_NAME app=v1 pod/kubernetes-bootcamp-5c69669756-d4kgp labeled | cs |
파드에 새로운 레이블이 적용될 것이다(우리는 파드에 애플리케이션 버전을 붙여두었다). "describe pod" 명령으로 그것을 확인할 수 있다.
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 36 37 38 39 40 41 42 43 44 45 46 | root@zerobig-vm:~# kubectl describe pods $POD_NAME Name: kubernetes-bootcamp-5c69669756-d4kgp Namespace: default Node: minikube/10.0.2.15 Start Time: Thu, 09 Aug 2018 00:31:44 +0900 Labels: app=v1 pod-template-hash=1725225312 run=kubernetes-bootcamp Annotations: <none> Status: Running IP: 172.17.0.5 Controlled By: ReplicaSet/kubernetes-bootcamp-5c69669756 Containers: kubernetes-bootcamp: Container ID: docker://7174b4be1ebce8c7516680bb45ff300d64b38c6b66710f9e38f2d6a59dfed47a Image: gcr.io/google-samples/kubernetes-bootcamp:v1 Image ID: docker-pullable://gcr.io/google-samples/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af Port: 8080/TCP Host Port: 0/TCP State: Running Started: Thu, 09 Aug 2018 09:25:51 +0900 Last State: Terminated Reason: Error Exit Code: 255 Started: Thu, 09 Aug 2018 00:32:58 +0900 Finished: Thu, 09 Aug 2018 09:24:40 +0900 Ready: True Restart Count: 1 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-7d4h2 (ro) Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: default-token-7d4h2: Type: Secret (a volume populated by a Secret) SecretName: default-token-7d4h2 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: <none> | cs |
여기에서 현재 파드에 붙여져 있는 레이블을 확인할 수 있고 이 새로운 레이블을 이용하여 파드의 리스트를 쿼리해 볼 수 있다.
1 2 3 4 | root@zerobig-vm:~# kubectl get pods -l app=v1 NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-5c69669756-d4kgp 1/1 Running 1 11h | cs |
그리고 이제 파드가 보인다.
Step 3: Deleting a service
서비스를 삭제하기 위해 "delete service" 명령을 이용할 수 있다. 이때 역시 여기서도 레이블을 이용할 수 있다.
1 2 | root@zerobig-vm:~# kubectl delete service -l run=kubernetes-bootcamp service "kubernetes-bootcamp" deleted | cs |
서비스가 없어졌는지 확인해 본다.
1 2 | root@zerobig-vm:~# kubectl get services No resources found. | cs |
이는 서비스가 제거되는 것을 확인 시켜준다. 라우트가 더 이상 노출되지 않음을 확인하기 위해 이전에 노출시켰던 IP 와 Port 에 curl 을 수행해 볼 수 있다.
1 2 3 | root@zerobig-vm:~# curl $(minikube ip):$NODE_PORT curl: (7) Failed to connect to 192.168.99.100 port 32036: Connection refused | cs |
1 2 3 | root@zerobig-vm:~# kubectl exec -it $POD_NAME curl localhost:8080 Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5c69669756-d4kgp | v=1 | cs |
'Kubernetes' 카테고리의 다른 글
10 Kubernetes Basics - Performing a Rolling Update (0) | 2018.08.23 |
---|---|
09 Kubernetes Basics - Running Multiple Instances of Your App (0) | 2018.08.23 |
07 Kubernetes Basics - Viewing Pods and Nodes (0) | 2018.08.19 |
06 Kubernetes Basics - Using kubectl to Create a Deployment (4) | 2018.08.19 |
05 Kubernetes Basics - Using Minikube to Create a Cluster (0) | 2018.08.19 |