오랜만에 돌아왔습니다. 이 전 내용이 너무 오래되어서 여기다 링크 드려요..
이거를 매일 해야지 해야지 했는데 미루다가 이렇게 됐네요.
또 이거를 시작하게 된 계기가 있습니다. 어제 유스콘이라고 유쾌한 스프링 방에서 진행하는 컨퍼런스인데 제가 아는 분이 발표를 맡게 되었습니다. 좋은 기회로 그 형님께서 티켓을 주셔서 아는 동생과 갔다왔는데 주기적으로 이런 컨퍼런스를 참여하고 싶을정도로 너무 맘에 들었고 동기부여가 되었습니다. 그래서 바로 동기를 잃기전에 미친듯이 달려보려고 합니다.
저번 시간에는 Spring-Cloud-Kubernetes를 설정했습니다.
Kubernetes 환경에서 Spring Boot 애플리케이션을 배포하고 관리하기 위한 도구와 라이브러리를 제공하는 Spring Cloud 프로젝트의 하위 모듈입니다. 이는 특히 마이크로서비스 아키텍처(MSA)에서 유용하게 사용되는데. Spring Cloud Kubernetes는 Kubernetes의 네이티브 기능을 활용하여 애플리케이션의 서비스 디스커버리, 구성 관리, 로드 밸런싱 등을 자동화할 수 있도록 지원합니다
어렵죠? 간단하게 말하면
MSA 배포 할때 씁니다.
어떻게 하냐고요?? 지금부터해볼게요
일단 사용자가 어디 페이지에 접근을 하면 그것은 gateway에 먼저 옵니다 근데 원래는
gateway를 사용하면 Eureka와 같은 서비스 디스커버리가 필요합니다. 하지만 이게 Spring Cloud Kubernetes가 해주기 때문에 필요없습니다.
그러고 나서 저의 파일들을 봐주세요
유레카, frontend 빼고 다 Spring Cloud Kubernetes 의 Discovery 서비스를 사용해서 등록합니다.
Gateway -> build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-loadbalancer'
Spring Cloud Kubernetes Discovery Client 를 사용하면 k8s의 Service 엔드포인트를 검색할 수 있습니다.
기존에는 Eureka server가 application name으로 서비스를 등록 검색하였습니다. 그래서 각 서비스 application 에
@EnableEurekaClient 를 달아놓은것을 볼 수 있습니다.
주의 하실점은 Spring Cloud Eureka Client 와, Spring Cloud Kubernetes Discovery Client를 같이 사용하면 에러가 납니다.
그래서 하나는 꺼주시면 되어요
그러면 한 번 사용해 보아요
저는 배포할때 썼기 때문에 그냥 Eurekaclient를 빼버렸습니다.다른 분들은 개발환경에서는 Eureka를 사용하시게 설정하면 됩니다.
Spring Cloud k8s Client Config
서비스 yml파일에
spring:
application:
name: employee-service
...
cloud:
kubernetes:
discovery:
all-namespaces: true #모든 네임스페이스에서 활성화
Spring Cloud Kubernetes는 클러스터 내 모든 네임스페이스에서 서비스를 검색할 수 있습니다. 즉, 애플리케이션이 배포된 네임스페이스와는 상관없이 클러스터 내 모든 네임스페이스에 존재하는 서비스를 발견하고 연결할 수 있게 됩니다.
보통 로컬환경과 개발환경 두 개의 파일을 쓸때 쓰는데 저는 하나 밖에 없어서 필요가 없기는 합니다.
각 서비스 마다
@EnableDiscoveryClient
는 추가를 해줘야합니다.
server:
port: 8080
error:
include-binding-errors: always
include-message: always
spring:
application:
name: gateway
cloud:
kubernetes:
discovery:
all-namespaces: true
loadbalancer:
mode: service
gateway:
routes:
- id: employee-service
predicates:
- Path=/employee/**
filters:
- StripPrefix=1
그럼 여기서도 이름은 똑같은 이유겠지요 ?
loadbalancer : mode : service -> loadbalancer 모드를 Kubernetes 서비스 이름 기반으로 설정
/employee/** 로 들어오는 요청은 "employee-service" 라는 이름을 가진 네임스페이스 서비스로 라우팅이 됩니다.
그러면 employee-service 서비스 이름 가진 서비스를 만들어줘야겠지요 ?
apiVersion: apps/v1
kind: Deployment
metadata:
name: employee-depl
spec:
replicas: 1
selector:
matchLabels:
app: employee
template:
metadata:
labels:
app: employee
spec:
containers:
- name: employee-backend
image: %%.dkr.ecr.ap-northeast-2.amazonaws.com/harbor-employee:latest
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: employee-service #ingress admin name과 동일해야 한다.
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 8080 # admin service port
selector:
app: employee
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fabric8-rbac
subjects:
- kind: ServiceAccount
name: default
namespace: default # pod의 네임스페이스
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
위에는 pod 이고 하나의 파드를 설정하고, AWS에 올립니다.
중간의 중요한 employee- service라는 서비스를 정의합니다.
metadata:name이 게이트웨이에서 매칭 되는 서비스 명입니다.
selector : app : employee 와 위에 이름을 매칭 시켜줘야합니다.
아래는 "system:serviceaccount:default:default" cannot get services in the namespace 오류 발생 시
Spring Cloud Kubernetes Client 사용 시 ServiceAccount + ClusterRole이 필요한데 이게 설정되어 있지 않을 경우 위와 예외가 발생합니다.
이를 막기 위해 Client를 사용하는 Pod의 네임스페이스에 ServiceAccount + ClusterRole을 생성하여야 합니다.
그러기 위해 추가합니다.
프로젝트 전체 ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: harbor-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
spec:
tls:
- hosts:
- "server.~~.shop"
secretName: harbor-com-tls
rules:
- host: "server.~~.shop"
http:
paths:
- path: / #모든 url요청을 gateway 던진다.
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 80
정리해보면 이렇게 된다.
- 클라이언트가 http://<gateway-host>/employee/updateemployee에 요청을 보냅니다.
- Spring Cloud Gateway가 요청을 employee-service로 라우팅합니다.
- Kubernetes 서비스가 적절한 Pod로 요청을 전달합니다.
- Pod의 컨테이너가 Spring Boot 애플리케이션을 실행하며 요청을 처리합니다.
- 애플리케이션은 요청을 처리하고 응답을 생성합니다.
- 응답은 Kubernetes 서비스와 Spring Cloud Gateway를 통해 클라이언트에게 전달됩니다.
updateemployee 라는 요청을 들고 서비스로 전달됐다가 파드를 통해 전달이 된다.
다음에는 ECR, 도커작성, 등을 해보겠다.
댓글