코알못

[kubernetes] Service - NodePort로 Pod 노출 실습 본문

ETC

[kubernetes] Service - NodePort로 Pod 노출 실습

코린이s 2023. 5. 28. 13:58
728x90

저번 시간에는 ClusterIP로 Pod 통신하는 방법을 배워봤다!

이번 시간에는 NodePort로 Pod 통신하는 실습을 진행해보자!

order 서비스 오브젝트는 주문을 위해 외부 통신을 할 예정이며 NodePort 타입으로 지정한다.

payment 서비스 오브젝트는 order 파드와 통신 용도이기에 외부 통신 하지 않으므로 ClusterIP 타입으로 지정한다.

이제 실습을 위해 order, payment의 Service 오브젝트와 Deployment 를 생성하는 yaml 파일을 만들도록 한다.

# service-v3.yaml

apiVersion: v1
kind: Service
metadata:
  name: order
  namespace: snackbar
  labels:
    service: order
    project: snackbar
spec:
  type: NodePort
  selector:
    service: order
    project: snackbar
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: payment
  namespace: snackbar
  labels:
    service: payment
    project: snackbar
spec:
  type: ClusterIP
  selector:
    service: payment
    project: snackbar
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order
  namespace: snackbar
  labels:
    service: order
    project: snackbar
  annotations:
    kubernetes.io/change-cause: "image 1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      service: order
      project: snackbar
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 2
      maxSurge: 1
  template:
    metadata:
      labels:
        service: order
        project: snackbar
    spec:
      containers:
      - name: order
        image: yoonjeong/order:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment
  namespace: snackbar
  labels:
    service: payment
    project: snackbar
  annotations:
    kubernetes.io/change-cause: "image 1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      service: payment
      project: snackbar
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        service: payment
        project: snackbar
    spec:
      containers:
      - name: payment
        image: yoonjeong/payment:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"

클러스터에 적용한다.

$ kubectl apply -f service-v3.yaml
service/order created
service/payment created
deployment.apps/order created
deployment.apps/payment created

네임스페이스 snackbar 에서 레이블중 project가 snackbar 인 모든 오브젝트를 검색하면 모두 정상적으로 뜬것을 볼 수 있다.

$ kubectl get all -l project=snackbar -n snackbar


NAME                           READY   STATUS    RESTARTS   AGE
pod/order-55468df7b9-kgqsl     1/1     Running   0          49s
pod/order-55468df7b9-sm5j6     1/1     Running   0          49s
pod/order-55468df7b9-zp52t     1/1     Running   0          49s
pod/payment-5cb8974b5f-ct7m7   1/1     Running   0          48s
pod/payment-5cb8974b5f-kgl9z   1/1     Running   0          48s
pod/payment-5cb8974b5f-vt4wz   1/1     Running   0          48s

NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/order     NodePort    10.104.10.55   <none>        80:30140/TCP   52s
service/payment   ClusterIP   10.104.6.180   <none>        80/TCP         51s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/order     3/3     3            3           51s
deployment.apps/payment   3/3     3            3           50s

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/order-55468df7b9     3         3         3       52s
replicaset.apps/payment-5cb8974b5f   3         3         3       51s

스낵바 네임스페이스에 있는 모든 서비스를 조회하면 order 서비스는 NodePort 타입이기에 포트 30140이 할당 된것을 볼 수 있다.

$ kubectl get svc -n snackbar -o wide
NAME      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE     SELECTOR
order     NodePort    10.104.10.55   <none>        80:30140/TCP   2m14s   project=snackbar,service=order
payment   ClusterIP   10.104.6.180   <none>        80/TCP         2m13s   project=snackbar,service=payment

이제 생성한 서비스에 대해 endpoint를 조회하여 파드가 잘 매핑 되었는지 확인하면 정상적으로 매핑 되었다.

$ kubectl get endpoints -n snackbar
NAME      ENDPOINTS                                            AGE
order     10.100.0.35:8080,10.100.2.39:8080,10.100.3.47:8080   2m49s
payment   10.100.0.36:8080,10.100.2.40:8080,10.100.3.48:8080   2m48s

이제 노드 포트 타입으로 호출 하기 위해서는 노드 IP 를 알아야 하므로 아래와 같이 노드 정보를 조회하고, 노드 중 External-ip 하나를 복사한다. 

$ kubectl get node -o wide
NAME                                           STATUS   ROLES    AGE   VERSION           INTERNAL-IP   EXTERNAL-IP     OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
gke-corin-cluster-default-pool-123-w610   Ready    <none>   18d   v1.25.8-gke.500   10.128.0.7    34.12.12.1   Container-Optimized OS from Google   5.15.89+         containerd://1.6.18
gke-corin-cluster-default-pool-123-xq03   Ready    <none>   18d   v1.25.8-gke.500   10.128.0.6    34.12.12.2    Container-Optimized OS from Google   5.15.89+         containerd://1.6.18
gke-corin-cluster-default-pool-123-zy02   Ready    <none>   18d   v1.25.8-gke.500   10.128.0.8    34.12.12.3   Container-Optimized OS from Google   5.15.89+         containerd://1.6.18

이제 'curl [노드 IP]:[노드 PORT]' 로 호출한다.

그러나 통신이 되지 않는다. 이는 해당 노드에 대해 포트가 방화벽으로 막혀 있기 때문이다.

이를 위해 오픈을 해주도록 하자!

$ curl 34.12.12.1:30140
^C

아래와 같이 gcloud 명령어를 이용하여 노드 포트인 30140 포트에 대해 방화벽을 오픈 한다. 

$ gcloud compute firewall-rules create order --allow tcp:30140
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/indigo-kiln-123/global/firewalls/order].
Creating firewall...done.
NAME   NETWORK  DIRECTION  PRIORITY  ALLOW      DENY  DISABLED
order  default  INGRESS    1000      tcp:30140        False

다시 통신히면 정상적으로 데이터를 가져온다.

$ curl 34.12.12.1:30140
Welcome to Snackbar!
Order what you want!

===== Host Info =====
HostIP: 10.100.0.35
HostName: order-55468df7b9-sm5j6

이제 export 로 환경 변수 설정을 하고 메뉴를 조회하면 정상적으로 order 과 통신하여 데이터를 가져오며

$ export ORDER=34.134.43.91:30140
$ curl http://$ORDER/menus
We have 4 snacks!
1. Pizza: 10,000
2. Burger: 5,000
3. Coke: 1,000
4. Juice: 1000

===== Host Info =====
HostIP: 10.100.2.39
HostName: order-55468df7b9-kgqsl

order 파드에 checkout 을 던지면 order 파드에서 payment 도메인(clusterIP)으로 payment 파드와 통신하여 데이터를 정상적으로 가져온다.

$ curl --request POST http://$ORDER/checkout \
> --header 'Content-Type: application/json' \
> --data-raw '{
quote> "Pizza": 1,
quote> "Coke": 1,
quote> "Burger": 0,
quote> "Juice": 0
quote> }'

        Received from http://payment/receipt
        Server is running on
        - HostName: payment-5cb8974b5f-kgl9z
        - HostIP: 10.100.2.40

        === Here is Your Receipt! ===

        [영수증]

        주문한 메뉴
        --------------------------
        Pizza - 10000원
        Coke - 1000원
        Burger - 0원
        Juice - 0원
        --------------------------

        주문금액 11000
        부가세(10%) 1100
        합계 12100

이제 방화벽 리스트를 확인하며

$ gcloud compute firewall-rules list
order                                 default  INGRESS    1000      tcp:30140

실습을 종료하며 생성한 방화벽을 삭제한다.

$ gcloud compute firewall-rules delete order

다음 생성한 오브젝트를 모두 삭제한다.

$ kubectl delete all -l project=snackbar -n snackbar
pod "order-55468df7b9-kgqsl" deleted
pod "order-55468df7b9-sm5j6" deleted
pod "order-55468df7b9-zp52t" deleted
pod "payment-5cb8974b5f-ct7m7" deleted
pod "payment-5cb8974b5f-kgl9z" deleted
pod "payment-5cb8974b5f-vt4wz" deleted
service "order" deleted
service "payment" deleted
deployment.apps "order" deleted
deployment.apps "payment" deleted

끝!

# 오류 

권한 거절 오류가 발생하였고 gcloud 설정이 해당 프로젝트로 되지 않아 발생하는 이슈일 수 있다고 하여

$ gcloud compute firewall-rules create order --allow tcp:30140
Creating firewall...API [compute.googleapis.com] not enabled on project [..]. Would you like to enable and retry
 (this will take a few minutes)? (y/N)?  y

Enabling service [compute.googleapis.com] on project [..]...
Creating firewall...failed.
ERROR: (gcloud.compute.firewall-rules.create) PERMISSION_DENIED: Permission denied to enable service [compute.googleapis.com]

아래와 같이 프로젝트 ID 를 확인한 뒤 설정 하였더니 정상적으로 설정 되었다.

$ gcloud projects list
PROJECT_ID          NAME              PROJECT_NUMBER
indigo-kiln-123  My First Project  123
$ gcloud config set project indigo-kiln-123
Updated property [core/project].
728x90
Comments