Kubernetes cluster 안에서 아래의 리소스를 이용해서 내/외부에서 호출할 수 있습니다.
Kubernetes안에서 Replicaset에 대한 경로나 Client가 하나의 이름으로 접근할 수 있도록 하는 Service discovery를 제공하는 리소스 입니다.
아래는 release속성값으로 spring과 summer를 추가한 ReplicaSet Manifest파일입니다.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo-spring
labels:
app: echo
release: spring
spec:
replicas: 1
selector:
matchLabels:
app: echo
release: spring
template:
metadata:
labels:
app: echo
release: spring
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:patched
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo-summer
labels:
app: echo
release: summer
spec:
replicas: 2
selector:
matchLabels:
app: echo
release: summer
template:
metadata:
labels:
app: echo
release: summer
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:patched
ports:
- containerPort: 8080
$ kubectl apply -f simple-replicaset-with-label.yaml
replicaset.apps/echo-spring created
replicaset.apps/echo-summer created
$ kubectl get pod -l app=echo -l release=spring
NAME READY STATUS RESTARTS AGE
echo-spring-dvs8k 2/2 Running 0 2m57s
$ kubectl get pod -l app-echo -l release=summer
NAME READY STATUS RESTARTS AGE
echo-summer-kp8b7 2/2 Running 0 3m14s
echo-summer-q6bgb 2/2 Running 0 3m14s
위 manifest파일에서 설정한 replicas숫자대로 release=spring은 1개, release=summer는 2개의 Pod가 생성된 것을 확인할 수 있습니다.
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
app: echo
release: summer
ports:
- name: http
port: 80
위는 app=echo & release=summer인 Pod만 접근할 수 있는 서비스 manifest파일입니다.
그림처럼 app=echo & release=spring Pod에는 접근할 수 없습니다.
$ kubectl apply -f simple-service.yaml
service/echo created
$ kubectl get service echo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo ClusterIP 10.104.121.79 <none> 80/TCP 16s
Service는 Kubernetes cluster안에서만 접근할 수 있습니다. 따라서, debugging용 임시 container를 배포하고, curl명령으로 release=summer pod에만 트래픽이 전달되는지 확인해보겠습니다.
$ kubectl run -i --rm --tty debug --image=gihyodocker/fundamental:0.1.0 --restart=Never -- bash -il
$ debug:/# curl http://echo/
Hello DOcker!!
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
debug 1/1 Running 0 76s
echo-spring-dvs8k 2/2 Running 0 16m
echo-summer-kp8b7 2/2 Running 0 16m
echo-summer-q6bgb 2/2 Running 0 16m
$ kubectl logs -f echo-summer-q6bgb -c echo
2020/10/10 04:38:52 start server
2020/10/10 04:38:52 image changed
2020/10/10 04:55:19 received request
$ kubectl logs -f echo-spring-dvs8k -c echo
2020/10/10 04:38:22 start server
2020/10/10 04:38:22 image changed
http://echo/로 호출 후, release=summer Pod를 보면 received request
로그를 통해 트래픽이 전달된 것을 확인할 수 있습니다.
http호출시, 2개의 release=summer Pod에 랜덤으로 트래픽이 전달됩니다.
반면, release=spring Pod
에는 트래픽이 없는 것을 확인할 수 있습니다.
ClusterIP는 서비스의 여러 type 중 하나로, default 값입니다.
ClusterIP는 Kubernetes Cluster의 내부 IP 주소에 Service를 공개할 수 있습니다.
따라서 Pod간 접근할 때 서비스를 거쳐가도록 할 수 있습니다. 다만, 외부에서 접근할 수 없습니다.
Cluster 외부에서 접근할 수 있는 서비스입니다.
각 노드에서 서비스 포트로 접속하기 위한 Global port를 개방하는 점이 ClusterIP와 차이점입니다.
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
type: NodePort
selector:
app: echo
ports:
- name: http
port: 80
$ kubectl apply -f simple-service-nodeport.yaml
service/echo configured
$ kubectl get svc echo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo NodePort 10.104.121.79 <none> 80:31787/TCP 23m
$ curl http://127.0.0.1:31787
Hello Docker!!%
NodePorty type으로 새로운 Service를 만들어 apply해줍니다.
svc port정보를 보면, 80:31787/TCP라고 명시되어 있습니다. Node의 31787 port로 서비스에 접근할 수 있다는 내용입니다.
이렇게 Service를 Kubernetes Cluster 외부로 공개할 수 있습니다.
Local Kubernetes환경에서는 사용할 수 없는 서비스입니다.
GCP(Cloud Load Balancing), AWS(Elastic Load Balancing)와 같은 클라우드 플랫폼에서 제공하는 LoadBalancer와 연동하기 위해 사용됩니다.
Kubernetes cluster 외부로 Service를 노출시키긴 위해서 NodePort를 사용할 수 있습니다.
이 방법은 L4 Level까지만 다룰 수 있고, HTTP/HTTPS처럼 경로 기반으로 서비스를 전환하는 L7 레벨의 제어는 불가능 합니다.
이를 해결하기 위한 리소스가 Ingress입니다.
Service를 이용한 Kubernetes cluster를 외부에 노출할 수 있고, 가상 호스트 및 경로 기반의 HTTP Routing을 양립시킬 수 있습니다.
$ kubectl apply -f \
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.16.2/deploy/mandatory.yaml
$ kubectl apply -f \
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.16.2/deploy/provider/cloud-generic.yaml
$ kubectl -n ingress-nginx get service,pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/default-http-backend ClusterIP 10.103.51.46 <none> 80/TCP 133m
service/ingress-nginx LoadBalancer 10.107.202.110 localhost 80:32287/TCP,443:31337/TCP 132m
NAME READY STATUS RESTARTS AGE
pod/default-http-backend-57fb4c77b4-ccmdx 1/1 Running 0 3m3s
pod/nginx-ingress-controller-7bfbcc484-khz6j 1/1 Running 0 2m44s
Ingress가 작동하려면, 클러스터는 실행 중인 Ingress Controller가 반드시 필요합니다.
위의 명령어로 nginx_ingress_controller를 설치했고, service,pod가 생성된 것을 확인할 수 있습니다.
위의 https://rwa.githubusercontent.com 경로대로 설치하면, Deployment의 apiVersion이 오류가 발생합니다.
Pod가 생성되지 않는 이슈가 있어, 해당 내용 중, Deployment의 apiVersion만 apps/v1으로 변경해 kubectl apply -f {{ file_name }} 을 실행했습니다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo
spec:
rules:
- host: ch05.gihyo.local
http:
paths:
- path: /
backend:
serviceName: echo
servicePort: 80
$ kubectl apply -f simple-ingress.yaml
ingress.extensions/echo created
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
echo <none> ch05.gihyo.local 80 5s
$ curl http://localhost -H 'Host: ch05.gihyo.local'
Hello Docker!!%
curl 명령어를 통해 Pod까지 요청이 들어가는 것을 확인할 수 있습니다.