ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kubernetes] 쿠버네티스 설치하기 (5) - Using a Service to Expose Your App
    인프라/Kubernetes 2020. 11. 18. 16:52
     

    Using a Service to Expose Your App

    Objectives Learn about a Service in Kubernetes Understand how labels and LabelSelector objects relate to a Service Expose an application outside a Kubernetes cluster using a Service Overview of Kubernetes Services Kubernetes Pods are mortal. Pods in fact h

    kubernetes.io

    Using a Service to Expose Your App

    Objectives

    • Learn about a Service in Kubernetes
    • Understand how labels and LabelSelector objects relate to a Service
    • Expose an application outside a Kubernetes cluster using a Service

    Private에서만 접근가능한 Pod속 container속 우리의 App을 외부에서도 접근가능하도록 만들어보자!

    kubectl proxy를 통해 API를 사용할 수 있지만 Service를 알고 있으면 훨씬더 쉬울 듯 하다!

     

    • Service에 대해 배워보자.
    • labels and LabelSelector가 Service와 어떠한 관계가 있는지 알아보자.
    • Service를 통해 외부 네트워크와도 통신이 가능하도록 해보자!

     


    Overview of Kubernetes Services

    Kubernetes Pods are mortal. Pods in fact have a lifecycle. When a worker node dies, the Pods running on the Node are also lost. A ReplicaSet might then dynamically drive the cluster back to desired state via creation of new Pods to keep your application running. As another example, consider an image-processing backend with 3 replicas. Those replicas are exchangeable; the front-end system should not care about backend replicas or even if a Pod is lost and recreated. That said, each Pod in a Kubernetes cluster has a unique IP address, even Pods on the same Node, so there needs to be a way of automatically reconciling changes among Pods so that your applications continue to function.


    쿠버네티스 Service에 대한 사전지식을 얻어보자.

    우리가 배포하고 실행한 Pods도 lifecycle을 가진다. Node가 죽으면 당연하게도 Node위에서 돌고있는 Pods도 죽기마련이다.

    여기서 ReplicaSet이란 녀석은 동적으로 Pods를 생성하면서 우리가 만든 application이 계속해서 실행되도록 해준단다.

    예로 3개의 복제되고 서로 교환가능한 back-end 서버가 있으면 font-end는 back-end가 몇개든 말든, 그안에서 몇개가 죽든, 다시 생성되든 신경쓰지 않고 하나의 경로요청을 하면 된다.

    그런데 3개의 Pod가 있다는건 3개의 Unique한 IP가 존재한다는것인데 이를 어떻게 자동적으로 하나로 인식하게하여 front-end가 끊김없이 지속적으로 요청이 가능하도록 할것인지가 우리가 앞으로 배울 Service에 대한 내용인 것 같다.

     

     

    A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them. Services enable a loose coupling between dependent Pods. A Service is defined using YAML (preferred) or JSON, like all Kubernetes objects. The set of Pods targeted by a Service is usually determined by a LabelSelector (see below for why you might want a Service without including selector in the spec).


    쿠버네티스에서 Service란 Pod들에 접근하기위해 Pods의 집합, 정책을 모아놓은 것이다. 이는 Pod들간에 의존성을 느슨하게 만들 수 있단다. 즉 서로 Pod들간에 서로 누군지 몰라도 Service가 알아서 해주는다는 것.

    YAML 파일로의 설정을 권장하고, 쿠버네티스의 객체들이 JSON형식인 것 처럼 JSON으로도 설정이 가능하다고 한다.

    Service에 의해 타겟이된 Pod의 집합은 일반적으로 LabelSelector에 의해 결정되어 진단다.

     

     

    Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. Services allow your applications to receive traffic. Services can be exposed in different ways by specifying a type in the ServiceSpec:

    • ClusterIP (default) - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.
    • NodePort - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using <NodeIP>:<NodePort>. Superset of ClusterIP.
    • LoadBalancer - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. Superset of NodePort.
    • ExternalName - Exposes the Service using an arbitrary name (specified by externalName in the spec) by returning a CNAME record with the name. No proxy is used. This type requires v1.7 or higher of kube-dns.

    각각의 Pod들이 Unique한 IP를 가지고 있지만 쿠버네티스 클러스터 환경 외부에서의 접근은 가능하지 않다!

    그러나 Service가 있으면 이를 가능케 해준다! ServiceSpec를 통해 어떤 방법으로 외부로의 접근을 가능하게 하는지 알아보자.

    • ClusterIP (default) - 클러스터 환경 내부 IP에만 Service를 노출, Service는 클러스터 내부로 부터 접근가능하다.

     

    • NodePort - Service에 선택된 Node에 동일한 Port로 NAT(Network Address Translation)와 같이 접근가능, <NodeIP>:<NodePort>와 같은형태로 Service를 통해 외부에서 Node에 접근가능하다. ClusterIP의 확장형 (내부 IP에 대해서 Port로 접근하므로)

     

    • LoadBalancer - 현재 클러스터환경(cloud)에 외부에서 접근할 수 있는 로드밸런스를 생성, 고정된 외부 IP를 Service에 할당하여 접근가능하다. NodePort의 확장형

     

    • ExternalName - 서비스를 임의의 이름 (spec에 따른 externalName)으로 노출한다. 이 임의로 생성한 이름으로 CNAME record가 반환된다. proxy는 사용되어지지 않고 v1.7이상의 kube-dns가 필요하다!

      coreDNS가 kube-dns 역할을 하고있는 듯 한데, 임의의 이름 -> CNAME record -> A record 순으로 접근하여 내부 Node IP로 접근을 하는것이 아닌가 싶다.

     

     

     

    More information about the different types of Services can be found in the Using Source IP tutorial. Also see Connecting Applications with Services.


    추가적으로 Service Type을 알고싶으면 해당 링크들을 통해 알아보자.

     

     

    Additionally, note that there are some use cases with Services that involve not defining selector in the spec. A Service created without selector will also not create the corresponding Endpoints object. This allows users to manually map a Service to specific endpoints. Another possibility why there may be no selector is you are strictly using type: ExternalName.


    selector를 만들지 않고 Service를 만들면 연결되어지는 Endpoints object가 만들어지지 않는다고 한다.

    그래서 수동적으로 map형식의 Service : endpoint를 만들 수 있다고 한다. 아마 직접 매핑이 Service -> Nodes 의 매핑이 가능하다는 의미 같다. 또다른 방법으로는 ExternalName의 ServiceSpec을 쓰란다.

     

     


    Services and Labels

    A Service routes traffic across a set of Pods. Services are the abstraction that allow pods to die and replicate in Kubernetes without impacting your application. Discovery and routing among dependent Pods (such as the frontend and backend components in an application) is handled by Kubernetes Services.

    Services match a set of Pods using labels and selectors, a grouping primitive that allows logical operation on objects in Kubernetes. Labels are key/value pairs attached to objects and can be used in any number of ways:

    • Designate objects for development, test, and production
    • Embed version tags
    • Classify an object using tags

    Service는 클러스터 외부로부터 들어온 트래픽을 Pods쪽으로 보내고, 우리가 실제로 실행할 application에 영향을 미치지 않고 Pods의 소멸, 복제를 가능케 해준다고 한다. Pods를 발견하고 어떤 Pod로 트래픽을 전송할 것인지 전부 담당하는녀석이 쿠버네티스 Service 라고 한다!!!

    Service는 labels and selectors를 통해 그루핑된 Pods를 찾는 것 같다. Labels 는 key/value 쌍으로 생성된다. Label을 이용하는 몇가지 방법에 대해 이야기 하고있다.

    • 개발, 테스트, 운영으로 오브젝트를 디자인
    • Embed version 태그
    • 태그를 이용하여 오브젝트 분류

     

    왼쪽의 그림을보면

    A, B Deployment가 생성되어있고

    A Deployment에 대하여 A Service가 1010.10.9.1 -> 내부 Pod IP 10.10.10.1로 구성

     

    B Deployment에 대하여 Service B 10.10.9.2 -> 내부 Pod IP 10.10.10.2, 10.10.10.3, 10.10.10.4로 구성

     

     


     

     

     

    위와 같은 구성에서 Label 과 Label Selector가 어떻게 구성되어 있는지 보여주고 있다.

     

     

     

     

     


    Labels can be attached to objects at creation time or later on. They can be modified at any time. Let's expose our application now using a Service and apply some labels.

     

    Label들은 생성될 때, 혹은 그 뒤에 언제든 붙여질 수 있고 수정되어질 수 있다고 한다! 이제 본격적으로 Service와 label을 배워보자!

     

     


    현재 나의 쿠버네티스 클러스터 환경은 이러하다.

    Master Node 1대 (192.168.5.1), Slave Node 2대 (192.168.5.2, 192.168.5.128)

    kube-node2는 192.168.5.3을 누가 사용하고 있어서 DHCP로 그냥 바꿔서 128을 할당 받았다.

     

    kubectl get deployment

    현재 생성된 deployment 1건, kubernetes-bootcamp 아무런 옵션도 주지않고 그냥 생성했다.

    그냥 생성했더니 kube-node1 에만 현재 배포되어 있다.

    kubectl get pods

    배포, 생성되어 있는 pods

     

    kubectl get services

    기본적으로 생성되어있는 kubernetes service 이다.

     

    kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

    deployment로 생성되어있는 name kubernetes-bootcampNodePort type으로 8080번을 접근 할 수있도록 service를 생성했다.

    생성된 kubernetes-bootcamp Service는 CLUSTER-IP(10.97.28.219는 Service IP이다)를 부여받았고

     

    아래의 명령어를 사용하여 kubernetes-bootcamp service에 대해 알아보자

    kubectl describe services/kubernetes-bootcamp

    IP - 쿠버네티스 클러스터 내부에서 사용되는 Unique한 Service IP 이다.

    Port - 내부 클러스터에서 사용하는 Port

    TargetPort - Pod가 Listener하고 있는 Port

    NodePort - 외부에 노출되어있는 Port

    Endpoints - Node -> Pod -> container의 IP:PORT

     

    NodePort -> Port -> TargetPort 순으로 진행

     

    아직 자세하게 어떤 의미인지 <unset>은 어떤 의미인지 잘모르겠지만 Type이 NodePort일 때 NAT와 같이 동작을 하니 위의 설명은 이러하다. "Service의 내부 클러스터 IP는 10.97.28.219로 할당, 외부랑 연결되어있는 host interface에 port 31119로 접근하면 172.16.0.2:8080으로 포트포워딩 된다."

    여기서 클러스터 IP란 쿠버네티스 클러스터 환경 내부에서만 쓰이고 Service에만 할당되는 Virtual IP라고 한다. 물리적인 network interface가 존재하지 않는다. 이것에 대해서 따로 글을 작성해야겠다.

    docker를 이용할때 -p <sourcePort>:<targetPort> 하는것 처럼 host pc에서 31119로 접근하면 172.16.0.2:8080 로 접근가능한 것이다.

    그러면 한번 접속해보자.

    host pc ip 192.168.5.1:31119 로의 접속 결과이다! 아주 좋다!

     

     


    위에서도 Labels를 볼 수 있지만 아래의 명령어로 deployement에 대한 설명에서도 볼 수 있다.

    kubectl describe deployment

    이 Labels의 값으로 pods를 검색할 수도 있다.

    kubectl get pods -l app=kubernetes-bootcamp

    -l 은 label에 대한 쿼리라고 한다.

     

    또한 service도 검색가능

    kubectl get services -l app=kubernetes-bootcamp

     

    아래의 label 명령어를 사용하여 pod에 대한 label을 변경할 수 있다

    kubectl label pod $POD_NAME $key=$value

    나는 version=v1 라는 label을 pod에 추가했다.

    kubectl describe pods $POD_NAME

    기존에 추가되었던 app=kubernetes-bootcamp 와 별개로 version=v1이 추가되었다!

     

    물론 새로추가한 label을 이용하여 검색도 가능하다 ^_^

    kubectl get pods -l version=v1

    label 명령어는 pod, service 다 적용가능한 것 같다.

     


     label을 이용해 service를 삭제해보자.

    kubectl delete service -l app=kubernetes-bootcamp

    label을 이용하여 모든 검색이 가능할 듯 싶다. 자유롭게 사용하자.

     

    Service를 삭제했으니 외부로의 접근은 불가능할 것으로 보인다. curl을 실행해보자

    이로서 Service가 외부와 내부Pod간의 연결을 도와주고있는 것을 알게되었다.

     

    pod가 실행되고 있지 않아서 그런것 일 수도 있으니 pod에 직접 명령어를 날려보자

    kubectl exec -ti $POD_NAME -- curl localhost:8080

     

     


    내부에서만 접근가능하던 Pod를 외부로 내보내는 챕터를 마무리 했다!!!

    지금은 deployment를 생성할 때 아무런 옵션을 주지않아 1개의 Pod만 생성되었는데 다음챕터에서 트래픽이 증가함에 따라 Scaling 하는 방법에 대해 알아보자!

    댓글

Designed by Tistory.