일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- gradle
- Zeppelin
- Cluster
- Kafka
- 레디스
- ec2
- fastcampus
- Jenkins
- 자바
- 로그인
- 설정
- hive
- vue
- Mac
- aws
- Docker
- 머신러닝
- 클러스터
- SpringBoot
- spring
- java
- 자동
- 젠킨스
- Redis
- config
- EMR
- 예제
- login
- 간단
- redash
- Today
- Total
코알못
[kubernetes] Service 소개 및 ClusterIP로 Pod 노출 실습 본문
클러스터에 구축한 파드에 접근하기 위해서는 어떻게 해야 할까 ?
Pod IP는 클러스터 내부에서만 접근 가능하므로 외부에서 접근이 불가능하다. 우리는 이를 위해 Service 오브젝트를 사용하면 된다!
서비스 오브젝트를 이용하면 파드 집합에 대해 단일 엔드 포인트로 접근 가능하며 로드 밸런서 기능을 이용할 수 있다!
주의 사항은 pod보다 서비스가 먼저 생성 되어야하고 같은 네임스페이스에 있는 파드만 관리한다.
Service 오브젝트의 타입은 세가지로 아래와 같으며 목적에 맞게 사용하면 된다.
서비스 타입 | 설명 |
ClusterIP | 외부에서 접근 불가능 Internal IP만 할당, External IP 할당 받지 않음 내부 통신 목적시에 사용 internal IP를 클러스터 내부에서 호출하면 적합한 파드로 포워딩 해줌 |
NodePort | 외부에서 접근 가능 Internal IP 할당, External IP 할당 받지 않으나 NodePort를 할당 받음 외부 통신 목적시에 사용 노드 IP, NodePort 호출시 서비스 internal IP 로 전달되며 해당 서비스에서 적합한 파드로 포워딩 해줌 노드 IP를 직접 호출 하므로 해당 노드가 죽었을때 서비스 불가능 > LoadBalancer 이용! |
LoadBalancer | 외부에서 접근 가능 Internal IP 할당, External IP 할당 받음, NodePort 할당 받음 외부 통신 목적시에 사용 서비스 External IP 호출시 적합한 노드(노드 IP를 호출 하지 않으며, 정상 노드로 호출한다.)의 NodePort를 통해 서비스 internal IP 로 전달되며 해당 서비스에서 적합한 파드로 포워딩 해줌 |
서비스 오브젝트는 관련된 파드 항목에 대한 Endpoints(매핑된 파드 정보) 리소스를 구성한다. 이를 이용하여 서비스 구성을 정상적으로 했는지 확인 가능하다.
실습을 위해 네임스페이스 snackbar를 생성한다.
$ kubectl create namespace snackbar
namespace/snackbar created
order 서비스 오브젝트, 해당 오브젝트에 매핑되는 order Deployment 생성하고
payment 서비스 오브젝트, 해당 오브젝트에 매핑되는 payment Deployment 생성하며
모든 오브젝트는 snackbar 네임스페이스에 생성하도록 한다.
서비스 오브젝트의 경우 아래와 같이 yaml 파일을 작성하며 spec type 을 ClusterIP 로 지정한다.
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: order
namespace: snackbar
labels:
service: order
project: snackbar
spec:
type: ClusterIP
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
spec:
replicas: 2
selector:
matchLabels:
service: order
project: snackbar
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
spec:
replicas: 2
selector:
matchLabels:
service: payment
project: snackbar
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.yaml
service/order created
service/payment created
deployment.apps/order created
deployment.apps/payment created
-n 은 네임스페이스내에서 확인하는 명령어로 snackbar 네임스페이스에 해당하는 모든 오브젝트를 불러온다.
모두 정상적으로 기동 되었다.
$ kubectl get all -n snackbar
NAME READY STATUS RESTARTS AGE
pod/order-55468df7b9-bxxfk 1/1 Running 0 3m46s
pod/order-55468df7b9-r86z4 1/1 Running 0 3m46s
pod/payment-5cb8974b5f-gq287 1/1 Running 0 2m34s
pod/payment-5cb8974b5f-kgwcj 1/1 Running 0 2m21s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/order ClusterIP 10.104.11.12 <none> 80/TCP 8m37s
service/payment ClusterIP 10.104.5.184 <none> 80/TCP 8m36s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/order 2/2 2 2 3m48s
deployment.apps/payment 2/2 2 2 3m47s
NAME DESIRED CURRENT READY AGE
replicaset.apps/order-55468df7b9 2 2 2 3m49s
replicaset.apps/payment-5cb8974b5f 2 2 2 2m37s
svc 라는 명령어로 서비스 오브젝트를 조회하며 External IP 가 없고 설정한 80포트로 활성화 되었다.
$ kubectl get svc order -o wide -n snackbar
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
order ClusterIP 10.104.11.12 <none> 80/TCP 9m31s project=snackbar,service=order
$ kubectl get svc payment -o wide -n snackbar
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
payment ClusterIP 10.104.5.184 <none> 80/TCP 9m54s project=snackbar,service=payment
엔드포인트의 경우 아래와 같이 확인하며 해당 서비스에 연결된 파드 IP, PORT 정보가 나온다.
파드 IP 를 확인하여 정상적으로 매핑 되었는지 확인하면 정상적으로 매핑 되었다.
$ kubectl get endpoints order -n snackbar
NAME ENDPOINTS AGE
order 10.100.0.31:8080,10.100.3.41:8080 10m
$ kubectl get endpoints payment -n snackbar
NAME ENDPOINTS AGE
payment 10.100.2.36:8080,10.100.3.43:8080 10m
$ kubectl get pod -o wide -n snackbar
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
order-55468df7b9-bxxfk 1/1 Running 0 6m16s 10.100.3.41 gke-corin-cluster-default-pool-d2d86113-xq03 <none> <none>
order-55468df7b9-r86z4 1/1 Running 0 6m16s 10.100.0.31 gke-corin-cluster-default-pool-d2d86113-w610 <none> <none>
payment-5cb8974b5f-gq287 1/1 Running 0 5m4s 10.100.3.43 gke-corin-cluster-default-pool-d2d86113-xq03 <none> <none>
payment-5cb8974b5f-kgwcj 1/1 Running 0 4m51s 10.100.2.36 gke-corin-cluster-default-pool-d2d86113-zy02 <none> <none>
아래와 같이 IP 만 결과를 받아볼 수 있다.
$ kubectl get svc order -o jsonpath="{.spec.clusterIP}" -n snackbar
10.104.11.12
해당 클러스터 IP로 호출하면 Cluster IP 이기에 외부에서 바로 통신 되지 않는다.
$ curl 10.104.11.12
아래와 같이 포트 포워딩을 이용하여 파드에 접근하여 서비스 오브젝트 문제가 아닌것을 확인해보자!
$ kubectl port-forward service/order 8080:80 -n snackbar
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
정상적으로 데이터 나오는 부분 확인 할 수 있다. (서비스 오브젝트에 연결 했음에도 같은 파드 IP만 접근하는것을 볼 수있다.)
$ curl localhost:8080
Welcome to Snackbar!
Order what you want!
===== Host Info =====
HostIP: 10.100.0.31
HostName: order-55468df7b9-r86z4
$ curl localhost:8080
Welcome to Snackbar!
Order what you want!
===== Host Info =====
HostIP: 10.100.0.31
HostName: order-55468df7b9-r86z4
$ curl localhost:8080
Welcome to Snackbar!
Order what you want!
===== Host Info =====
HostIP: 10.100.0.31
HostName: order-55468df7b9-r86z4
이제 부터 파드간 통신하는 실습을 진행해보도록 하자 !
방법은 세가지가 있다.
- 서비스 IP, PORT 직접 호출
- 서비스 오브젝트가 파드에 설정한 환경 설정 (서비스 생성전에 만들어진 파드에는 환경설정이 적용되지 않는다.)
- DNS (서비스 이름으로 호출)
1번의 경우 파드 접속하여 서비스 IP,PORT 로 직접 호출하는것으로 아래와 같이 간단하게 가능하다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- curl [서비스클러스터IP]:[서비스포트]
Welcome to Snackbar!
Order First Before Payment!
===== Host Info =====
HostIP: 10.100.3.43
HostName: payment-5cb8974b5f-gq287
2번인 서비스 오브젝트가 파드에 설정한 환경 설정 값으로 파드 통신 방법을 알아보자!
서비스 생성 시점 이후에 생성된 파드에 해당 서비스에 대한 IP, PORT 가 설정 파일에 존재 한다.
이미 생성 되어있는 파드의 경우 수정하지 않는점을 주의하자!
우선 파드 정보를 보고 order 의 파드명을 복사하다.
$ kubectl get pod -n snackbar
NAME READY STATUS RESTARTS AGE
order-55468df7b9-bxxfk 1/1 Running 0 19m
order-55468df7b9-r86z4 1/1 Running 0 19m
payment-5cb8974b5f-gq287 1/1 Running 0 18m
payment-5cb8974b5f-kgwcj 1/1 Running 0 17m
order 파드에서 payment 서비스의 호스트 IP, PORT를 얻을 수 있다.
[서비스명]_SERVICE_HOST, [서비스명]_SERVICE_PORT로 설정 된다.
$ kubectl exec order-55468df7b9-bxxfk -n snackbar -- env | grep PAYMENT
PAYMENT_PORT_80_TCP_ADDR=10.104.5.184
PAYMENT_PORT_80_TCP_PORT=80
PAYMENT_PORT_80_TCP_PROTO=tcp
PAYMENT_SERVICE_HOST=10.104.5.184
PAYMENT_SERVICE_PORT=80
PAYMENT_PORT=tcp://10.104.5.184:80
PAYMENT_PORT_80_TCP=tcp://10.104.5.184:80
payment 파드에서도 동일하게 order 서비스에 대한 HOST, PORT 정보를 확인 할 수 있다.
$ kubectl exec payment-5cb8974b5f-gq287 -n snackbar -- env | grep ORDER
ORDER_PORT_80_TCP=tcp://10.104.11.12:80
ORDER_SERVICE_PORT=80
ORDER_PORT_80_TCP_PROTO=tcp
ORDER_PORT_80_TCP_ADDR=10.104.11.12
ORDER_PORT=tcp://10.104.11.12:80
ORDER_SERVICE_HOST=10.104.11.12
ORDER_PORT_80_TCP_PORT=80
이제 order 파드에 접속하여 sh 를 실행하며 curl 로 서비스 환경 변수 불러와서 통신하면 정상적으로 응답값을 불러 올 수 있다.
서비스의 경우 로드밸런싱이 되므로 아래와 같이 호출마다 파드 IP 가 다르다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/usr/src/app # curl $PAYMENT_SERVICE_HOST:$PAYMENT_SERVICE_PORT
Welcome to Snackbar!
Order First Before Payment!
===== Host Info =====
HostIP: 10.100.2.36
/usr/src/app # curl $PAYMENT_SERVICE_HOST:$PAYMENT_SERVICE_PORT
Welcome to Snackbar!
Order First Before Payment!
===== Host Info =====
HostIP: 10.100.3.43
이제 3번 방법인 서비스 이름을 통해 호출하는 방법 (쿠버네티스 DNS)을 알아보자!
order 파드에서 curl 서비스명:서비스포트로 호출해보면 정상적으로 응답을 받을 수 있다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- curl payment:80
Welcome to Snackbar!
Order First Before Payment!
===== Host Info =====
HostIP: 10.100.3.43
HostName: payment-5cb8974b5f-gq287
어떻게 서비스명으로 통신이 되는지 확인하기 위해 우선 host 파일 설정 되어있는지 보면 안되어 있다.
호스트 설정으로 되는것이 아니였다..! 그럼 어떤것일까?
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.100.3.41 order-55468df7b9-bxxfk
DNS 설정을 보면 아래와 같이 설정 되어 있다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- cat /etc/resolv.conf
search snackbar.svc.cluster.local svc.cluster.local cluster.local us-central1-a.c.indigo-kiln-385910.internal c.indigo-kiln-385910.internal google.internal
nameserver 10.104.0.10
options ndots:5
nameserver는 컨테이너에서 사용할 DNS 서버 주소이며
search는 클러스터의 기본 도메인으로 DNS 서버에서 호스트 네임을 찾을때 사용할 검색 리스트이다.
예를 들어 payment:80 호출하면 payment.snackbar.svc.cluster.local 검색, payment.svc.cluster.local 검색 등 이런식으로 검색한다.
서비스에 대한 도메인은 [서비스명].[네임스페이스명].svc.cluster.local 이므로 첫번째에서 서비스 IP 를 얻을 수 있다.
만약 호출을 하는 파드와 호출 받는 파드가 네임스페이스가 다르다면 payment.<호출받는파드의네임스페이스>:80 으로 호출하면 2번째인 svc.cluster.local에서 서비스 IP 를 얻을수 있다. (pyment.<호출받는네임스페이스>.svc.cluster.local 이 되니까)
클러스터 구성시 기본으로 생성되는 네임 스페이스인 kube-system의 떠있는 서비스인 kube-dns의 IP 와 DNS 네임서버 IP와 일치한다.
$ kubectl get all -n kube-system | grep kube-dns
pod/kube-dns-5b5dfcd97b-js5rc 4/4 Running 30 (17d ago) 17d
pod/kube-dns-5b5dfcd97b-k7wzn 4/4 Running 0 17d
pod/kube-dns-autoscaler-5f56f8997c-gsckv 1/1 Running 0 17d
service/kube-dns ClusterIP 10.104.0.10 <none> 53/UDP,53/TCP 20d
deployment.apps/kube-dns 2/2 2 2 20d
deployment.apps/kube-dns-autoscaler 1/1 1 1 20d
replicaset.apps/kube-dns-5b5dfcd97b 2 2 2 20d
replicaset.apps/kube-dns-autoscaler-5f56f8997c 1 1 1 20d
서비스명으로 호출가능한것은 확인한 바와 같이 기본적으로 구성되는 쿠버네티스 DNS 서버에서 제공 하는것으로 서비스 IP를 확인할 필요 없으니 편하게 호출할 수 있다.
위에서 언급한 다른 네임스페이스의 파드와 통신하는 실습을 진행해보자!
우선 새로운 네임스페이스를 생성한다.
$ kubectl create namespace fancy-snackbar
namespace/fancy-snackbar created
새로운 네임스페이스 fancy-snackbar에 서비스와 deployment 생성하는 yaml 을 만들고
# service-v2.yaml
apiVersion: v1
kind: Service
metadata:
name: delivery
namespace: fancy-snackbar
labels:
service: deliverry
project: snackbar
spec:
type: ClusterIP
selector:
service: delivery
project: snackbar
ports:
- port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: delivery
namespace: fancy-snackbar
labels:
service: delivery
project: snackbar
spec:
replicas: 2
selector:
matchLabels:
service: delivery
project: snackbar
template:
metadata:
labels:
service: delivery
project: snackbar
spec:
containers:
- name: delivery
image: yoonjeong/my-app:2.0
ports:
- containerPort: 8080
resources:
limits:
memory: "64Mi"
cpu: "50m"
클러스터에 적용한다.
$ kubectl apply -f service-v2.yaml
service/delivery created
deployment.apps/delivery created
모든 네임스페이스에서 검색하기 위해 --all-namespaces 옵션을 붙여 오브젝트를 확인한다.
$ kubectl get all -l project=snackbar --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
fancy-snackbar pod/delivery-6c8c4bd4-88dgq 1/1 Running 0 78s
fancy-snackbar pod/delivery-6c8c4bd4-v4v6n 1/1 Running 0 78s
snackbar pod/order-55468df7b9-bxxfk 1/1 Running 0 75m
snackbar pod/order-55468df7b9-r86z4 1/1 Running 0 75m
snackbar pod/payment-5cb8974b5f-gq287 1/1 Running 0 74m
snackbar pod/payment-5cb8974b5f-kgwcj 1/1 Running 0 74m
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fancy-snackbar service/delivery ClusterIP 10.104.6.51 <none> 80/TCP 80s
snackbar service/order ClusterIP 10.104.11.12 <none> 80/TCP 80m
snackbar service/payment ClusterIP 10.104.5.184 <none> 80/TCP 80m
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
fancy-snackbar deployment.apps/delivery 2/2 2 2 80s
snackbar deployment.apps/order 2/2 2 2 75m
snackbar deployment.apps/payment 2/2 2 2 75m
NAMESPACE NAME DESIRED CURRENT READY AGE
fancy-snackbar replicaset.apps/delivery-6c8c4bd4 2 2 2 81s
snackbar replicaset.apps/order-55468df7b9 2 2 2 75m
snackbar replicaset.apps/payment-58c97cc4cd 0 0 0 75m
snackbar replicaset.apps/payment-5cb8974b5f 2 2 2 74m
새로 생성한 delivery 엔드 포인트를 확인하여 파드가 정상 매핑 됐는지 확인한다.
$ kubectl get endpoints delivery -n fancy-snackbar
NAME ENDPOINTS AGE
delivery 10.100.2.37:8080,10.100.3.44:8080 2m7s
order 파드에서 다른 네임스페이스인 delivery 서비스 클러스터 IP를 호출하면 정상적으로 호출 된다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- curl 10.104.6.51
Welcome to Version 2!
===== Host Info =====
HostIP: 10.100.2.37
HostName: delivery-6c8c4bd4-88dgq
이제 DNS 를 이용해보자!
위에서 설명한 바와 같이 네임스페이스가 다르면 search 항목에 해당 네임스페이스 관련 주소를 찾지 못하니 실패 하고
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- curl delivery
curl: (6) Could not resolve host: delivery
command terminated with exit code 6
아래와 같이 네임스페이스명을 정의하면 가능하다!
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- curl delivery.fancy-snackbar
Welcome to Version 2!
===== Host Info =====
HostIP: 10.100.3.44
HostName: delivery-6c8c4bd4-v4v6n%
추가적으로 order 파드는 delivery 서비스가 생성 되기전에 만들어졌기에 delivery 관련 서비스 환경 변수는 없다.
$ kubectl exec -it order-55468df7b9-bxxfk -n snackbar -- env | grep DELIVERY
환경 변수는 생성 시점에 따라서 없는 경우도 있기 때문에 dns 로 접근하거나 IP 로 통신하기로 하자!
이제 실습이 종료 되었으니 모두 삭제한다.
$ kubectl delete all -l project=snackbar --all-namespaces
끝!
'ETC' 카테고리의 다른 글
[kubernetes] Service - LoadBalancer로 Pod 노출 실습 (1) | 2023.05.28 |
---|---|
[kubernetes] Service - NodePort로 Pod 노출 실습 (0) | 2023.05.28 |
[kubernetes] Deployment - 배포 전략 Recreate, RollingUpdate 및 롤백 (1) | 2023.05.26 |
[kubernetes] Deployment 란? (0) | 2023.05.20 |
[kubernetes] ReplicaSet 실습 - pod 수 조정, 롤백 (0) | 2023.05.20 |