Kubernetes Service를 이용한 클러스터 외부 공개

여기에서는 Service를 이용한 클러스터 내부 및 외부 공개하는 방법에 대해서 알아보겠다.

클러스터 내부에서 연결

먼저 클러스터 내에서 연결을 확인한다. 클러스터에 curl 컨테이너가 들어있는 Pod를 생성하고, Shell 연결을 한 후에 helloworld Pod에 Curl의 액세스 테스트를 실행해 보겠다.

먼저, 테스트용 Pod를 생성 실행한다.

% kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created

Pod 목록을 IP를 포함해서 표시(-o wide를 붙인다)한다.

% kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
helloworld   1/1     Running   0          3m44s   172.17.0.3   minikube   <none>           <none>

클러스터 내부에 들어가 curl을 실행한다.

% kubectl run --image curlimages/curl:latest -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $ curl 172.17.0.3:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $

이 결과를 보면, curl에서 helloworld의 IP인 172.17.0.3을 지정하고, 포트를 8080으로 열렸기 때문에, curl 컨테이너로부터 hellorowld 컨테이너에 접속을 할 수 있게 된 것이다.

이는 내부에 있는지 확인하기 위해 curl 컨테이너가 동작한 상태로, 또 하나의 터미널을 열어서 Pod 목록을 IP를 포함해 표시해 보도록 하자.

% kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
curl         1/1     Running   0          23s   172.17.0.4   minikube   <none>           <none>
helloworld   1/1     Running   0          12m   172.17.0.3   minikube   <none>           <none>

컨테이너가 같은 네트워크내에 존재해 있는지 확인할 수 있다.

클러스터 외부에서 연결

다음으로 클러스터 외부에서 연결을 시도하려고 하면 되지 않는다. 이는 Docker의 경우와 동일하며 호스트 IP와 Pod의 IP 범위가 다르기 때문이다. 따라서 액세스할 수 있게 하려면 Service라는 것을 만들고 Pod를 외부에 공개를 해야 한다.

서비스는 Pod를 클러스터 내외에 공개하는 정적 IP 주소를 가진 L4 로드 밸런서를 의미한다. Pod 자체는 언제 중지가 되게 될지 모르기 때문에, 분배 되는 곳에서 서비스를 공개한다고 한다.

Service에는 3개가 있고, 각각 아래와 같은 특징을 가지고 있다.

  • ClusterIP Service (클러스터내 접속)
    언제 소멸할지 불명한 Pod의 IP를 추상화하여, 정적인 IP를 가진 프록시를 두는 것으로 아래와 같은 이점이 있다.
    1. Pod에 액세스할 때, Pod의 IP를 알 필요가 없다.
    2. Pod에 액세스할 때, 로드 밸런스 해준다.
  • NodePort Service (클러스터 내외 접속)
    ClusterIP에서는 불가능했던 클러스터 외부에의 Pod의 공개를 NodeIP와 NodePort를 경유해 가능하게 할 수 있다는 점이 장점이 있다.
    그러나 다음과 같은 단점도 존재한다.
    1. Node IP를 알아야 한다.
    2. Node Port를 알아야 한다.
  • LoadBalancer Service(클러스터 내외 접속)
    프로바이더의 L4 로드 밸런서의 DNS 로부터 각 노드의 특정의 포트에 Routing 하여 Pod에 액세스를 실행한다.
    따라서, Node IP 및 Node 포트를 알 필요가 없다. 다만, 아래와 같은 단점도 있다.
    1. 1개의 Service마다 1개의 로드 밸런서가 작성되기 때문에 고비용이 된다.
    2. L4의 로드 밸런서이므로, L7의 HTTP의 호스트, 패스에서의 LB 배분을 할 수 없다.

위의 각 서비스에 대해 내용을 확인해 보도록 하자.

ClusterIP 서비스

HelloWorld Pod를 ClusterIP Service로 클러스터 내부에 공개하고 동일한 클러스터의 다른 Pod에서 액세스할 수 있음을 살펴보겠다.
아래와 같이 기동하고 있는 Pod에 --type ClusterIP 옵션을 지정하는 것으로 ClusterIP의 Service로서 공개를 실행할 수 있다.

kubectl expose pod [Pod명] --type ClusterIP [Service명]

먼저, 테스트용 Pod를 생성 실행한다. *(기존에 이미 있다면 같은 이름의 Pod가 있다면, kubectl delete pod helloworld 명령으로 삭제 한다.)

% kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created

helloworld Pod을 helloworld-clusterip라는 Service명으로 공개한다.

% kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip
service/helloworld-clusterip exposed

아래 명령을 사용하여 서비스 목록을 조회한다.

% kubectl get service
NAME                   TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
helloworld-clusterip   ClusterIP   10.98.60.0   <none>        8080/TCP   25s
kubernetes             ClusterIP   10.96.0.1    <none>        443/TCP    16h

조회 결과 첫번째 행에 Type이 ClusterIP인 서비스가 생성된 것을 확인할 수 있다.

다음은 curl 컨테이너를 다시 시작하고 해당 컨테이너 내에서 helloworld-clusterip을 통해 helloworld에 접근을 해보도록 하겠다.

% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $

열린 Shell에 curl 명령어로 접속해 본다.

/ $ curl 10.98.60.0:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld

접속한 결과 helloworld에 접근이 가능한 것을 확인할 수 있다. 이 결과는 위에서 설명한 “클러스터 내부에서 연결"에서의 결과와 동일하다.

그러나, 위에서 한 것은 curl 컨테이너에서 직접 helloworld 컨테이너에 연결을 한 것이고, 이번의 실행한 결과는 curl 컨테이너에서 Service인 helloworld-clusterip에 접근해서, 로드 밸런스(1개의 Pod만 생성했기 있기 때문에 특정의 Pod가 되긴 하지만) 기능에 의해 Service가 helloworld에 접속한다는 흐름이 다르다. 따라서, 서로 의미가 다르므로 주의가 필요하다.

NodePort Service

HelloWorld Pod를 NodeIP Service로 클러스터 내부와 외부에 게시하고 동일한 클러스터의 다른 Pod에서 액세스할 수 있음을 살펴보겠다.

아래와 같이 기동하고 있는 Pod에 대해 --type NodePort의 옵션을 지정하는 것만으로 ClusterIP의 Service로서 공개할 수 있다.

kubectl expose pod [Pod명] --type NodePortIP [Service명]

helloworld Pod을 helloworld-nodeport라는 Service명으로 공개한다.

% kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport
service/helloworld-nodeport exposed

아래 명령을 사용하여 서비스 목록을 조회해 본다.

% kubectl get service
NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
helloworld-nodeport    NodePort    10.110.238.186   <none>        8080:31942/TCP   38s
kubernetes             ClusterIP   10.96.0.1        <none>        443/TCP          16h

그 결과 첫번째 행에 TypeNodeport인 서비스가 생성된 것을 확인할 수 있다.

다음은 동일한 클러스터 내에서 접속할 수 있는지 확인한다. 절차는 ClusterIP의 경우와 동일하다. 먼저 기존에 curl 컨테이너를 삭제하고 다시 생성한다.

% kubectl delete pod curl
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $

그러고, 해당 컨테이너 내에서 helloworld-nodeport을 통해 helloworld에 접근을 해보도록 하겠다.

/ $ curl 10.110.238.186:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $

그 결과 helloworld-nodeport를 통해 helloworld에 접속 할 수 있음을 확인할 수 있다.

그럼 다음으로 클러스터 외부(로컬 환경)에서 접속할 수 있는지 확인한다. 연결을 위해 minikube의 IP가 필요하므로 아래 명령을 실행하여 IP를 조회해 본다.

% minikube ip
192.168.49.2

이 IP에 대해 curl 명령을 로컬 환경에서 실행하여 접속해 본다. 이 때 포트는 Pod에서의 31942를 지정한다.

/ $ curl 192.168.49.2:31942
Hello, world!
Version: 1.0.0
Hostname: helloworld

접속 결과 helloworld에 접속을 할 수 있다는 것을 확인할 수 있다.
(minikube 기동시 설정에 따라 액세스 할 수 없는 경우가 있다. 이 경우 minikube service --url helloworld-nodeport 명령을 실행하고 출력된 url에 대해 curl 명령을 실행한다.)

로드밸런서 서비스

HelloWorld Pod를 NodeIP Service로 클러스터 내부와 외부에 게시하고 동일한 클러스터의 다른 Pod에서 액세스할 수 있음을 살펴 보겠다.

아래와 같이 기동하고 있는 Pod에 –type LoadBalancer 옵션을 지정하는 것으로 ClusterIP의 Service로서 공개를 실시할 수 있다.

kubectl expose pod [Pod명] --type NodePortIP [Service명]

helloworld Pod을 helloworld-loadbalancer이라는 Service명으로 공개한다.

% kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-loadbalancer
service/helloworld-loadbalancer exposed

아래 명령을 사용하여 서비스 목록을 조회한다.

% kubectl get service
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
helloworld-loadbalancer   LoadBalancer   10.104.176.59    <pending>     8080:30100/TCP   27s
kubernetes                ClusterIP      10.96.0.1        <none>        443/TCP          16h

그 결과 첫번째 행에 TypeLoadBalancer인 서비스가 생성된 것을 확인할 수 있다.

먼저 동일한 클러스터 내에서 액세스할 수 있는지 확인한다. 절차는 ClusterIP의 경우와 동일하다.

% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $

열린 Shell에 curl 명령어로 접속해 본다.

/ $ curl 10.104.176.59:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $

접속 결과 helloworld-LoadBalancer를 통해 helloworld에 접근이 할 수 있음을 확인할 수 있다.

그런 다음 클러스터 외부(로컬 환경)에서 접근 할 수 있는지 확인한다.

% minikube service helloworld-loadbalancer --url
http://127.0.0.1:53240
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

콘솔을 그대로 두고, 또 다른 콘솔을 켜서 아래 명령으로 접속을 확인 한다.

% curl http://127.0.0.1:53240
Hello, world!
Version: 1.0.0
Hostname: helloworld

실행하면 helloworld에 접근 할 수 있음을 확인할 수 있다.



최종 수정 : 2022-09-08