이번글에서는 Spring Cloud 기반의 서비스를 Kubernetes와 함께 사용해보는 과정을 가져보겠습니다. 일반적으로는, Kubernetes를 단독으로 사용하여 Ingress를 API Gateway로 사용하고, Service를 Load Balancing 하는데요. 이와 같이 사용하지 않고, 이번 글에서는 Spring Cloud의 Code를 거의 바꾸지않고 K8s의 Orchestration을 사용하고자 하는 개발자분들께서 읽으시면 좋을 것 같습니다.
프로젝트의 구성도는 아래와 같습니다.
- Ingress-seminarhub로 "/" 로 들어오는 요청을 Spring Cloud Gateway로 Routing 합니다.
- Spring Cloud Gateway는 "/seminar", "/member", "/member-seminar" 로 각 서비스에 Routing 합니다.
사실 이 글의 시작은 nhn에서 제공하는 테크영상을 보다가 흥미가 생겨 시작했는데요.
MSA 환경을 k8s 로 전환하는 과정의 큰 Flow와 이유에 대해서 이해하기 정말 쉽습니다.
https://www.youtube.com/watch?v=otss__0kf-g
1. Ingress-nginx-controller를 구성
https://github.com/kubernetes/ingress-nginx/tree/main
우리는 먼저 ingress-nginx-controller를 사용합니다. 본인의 K8s 버전에 맞추어서 설치하셔야합니다. 위의 사이트에서 확인하실 수 있습니다. 저는 k8s 1.28 을 사용하고있습니다.
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/baremetal/deploy.yaml
위의 명령어로 nginx-controller 1.8.2.yaml 파일을 가져옵니다.
이떄 우리는 외부에서 ingress-nginx-controller로 들어올떄 접근할 수 있는 Port를 열어줘야합니다.
그렇기에 Service 부분에 NodePort를 아래와 같이 추가합니다.
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
nodePort: 30100
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
nodePort: 30200
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
이를 통해 우리는 http 프로토콜로 30100 의 포트를 열어주었고,
https 프로토콜에는 30200 의 포트를 열어주었습니다.
공식문서에 아래와 같이 써있습니다.아래의 포트 범위를 일반적으로 사용합니다.
For quick testing, you can use a NodePort. This should work on almost every cluster, but it will typically use a port in the range 30000-32767.
kubectl apply -f ingress-nginx.yaml
우리는 외부에서 Server에 접속할 수 있는 Ingress-nginx-controller를 구성했습니다.
2. ingress-seminarhub 구성
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: seminarhub-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: seminarhub-cloud-gateway-server-dev
port:
number: 80
프로젝트 구성도에서 언급했듯이 "/"로 들어오는 모든 요청을 seminarhub-cloud-gateway-server에 라우팅함으로써 라우팅처리를 cloud-gateway-server 위임합니다.
kubectl apply -f ingress-seminarhub.yaml
3. 각 서비스를 Deployment로 배포해보자
우선 첫번쨰로, seminarhub-cloud-gateway-server를 배포합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: seminarhub-cloud-gateway-server
spec:
replicas: 1
selector:
matchLabels:
name: seminarhub-cloud-gateway-server
template:
metadata:
labels:
name: seminarhub-cloud-gateway-server
spec:
containers:
- image: eoghdhdls/seminarhub-cloud-gateway-server
name: seminarhub-cloud-gateway-server
ports:
- containerPort: 80
serviceAccountName: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
name: seminarhub-cloud-gateway-server-dev
spec:
ports:
- port: 80
protocol: TCP
name: "http"
targetPort: 80
selector:
name: seminarhub-cloud-gateway-server
# serviceAccountName: ingress-nginx
Deployment와 Service 를 활용하여 진행합니다.
kubectl apply -f seminarhub-cloud-gateway-server.yaml
cloud-gateway 가 생성되었습니다.
두번째로는 member 서비스를 배포합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: seminarhub-member-api-server
spec:
replicas: 1
selector:
matchLabels:
name: seminarhub-member-api-server
template:
metadata:
labels:
name: seminarhub-member-api-server
spec:
containers:
- image: eoghdhdls/seminarhub-member-api-server
name: seminarhub-member-api-server
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: seminarhub-member-api-server-dev
spec:
ports:
- port: 8080
protocol: TCP
name: "httpmember"
targetPort: 8080
selector:
name: seminarhub-member-api-server
kubectl apply -f seminarhub-member-api-server.yaml
잘 실행되었나 확인합니다.
kubectl get pods -o wide
모든 Ingress, Deployment, Service Pod가 잘 실행중인지 확인합니다.
kubectl get all
4. Spring Cloud Kubernetes 로 서비스 디스커버리
Spring Cloud 환경에서는 Eureka가 대신에 Service Discovery를 하였었습니다. 그때의 방식은 Client Side Discovery 방식입니다.
k8s에서는 Server Side Discvoery 방식을 활용합니다.
위의 공식사이트에서 제공하는 Spring Cloud Kubernetes 파일을 실행시킵니다.
kubectl apply -f kubernetes-discoveryserver.yaml
서비스 디스커버리가 잘 작동하는지 확인합니다.
curl 10.40.0.6:8761/apps
5. 직접 테스트해보기
우선 현재 k8s Cluster내에서 member-pod가 잘 작동하고 있는 curl로 확인해보겠습니다.
curl 10.40.0.2:8080/api/v1/member/user@example.com
{"member_no":8,"member_id":"user@example.com","member_password":"string","member_nickname":"string","member_from_social":true,"inst_dt":null,"updt_dt":null,"del_dt":null}
이제 직접 Ingress에 요청하여서 제대로 Gateway 가 동작하는지 확인합니다.
그전에 먼저, Gateway 가 먼저 Service Discovery 보다 먼저 실행되엇었다면, Cloud Gateway 를 중지한뒤 다시 실행하셔야합니다.
kubectl delete -f seminarhub-cloud-gateway-server.yaml
kubectl apply -f seminarhub-cloud-gateway-server.yaml
이제 본인의 PC에서 확인합니다.
root@k8s-master-1:~/app/repo# curl 10.0.0.11:30100/api/v1/member/user@example.com
{"member_no":8,"member_id":"user@example.com","member_password":"string","member_nickname":"string","member_from_social":true,"inst_dt":null,"updt_dt":null,"del_dt":null}
혹은 아래와 같이 포트포워딩을 통해서 브라우저에서 접근할 수도 있습니다.
Spring Cloud Kubernetes에 대한 정보는 아래의 글을 읽어보시면 큰 도움이 되실 것 같습니다.
https://docs.spring.io/spring-cloud-kubernetes/reference/discovery-client.html