728x90
반응형

이전 상태

이전까지 상태

  • Deployment
    • API Gateway
    • Discovery
    • Config
  • Service
    • NodePort : API Gateway
    • NodePort : Discovery

[이전까지 완료한 상태]

API Gateway는 30010으로 열려있고, Discovery Service는 30007번, Config Service는 30008번으로 열려있다.
마이크로서비스인 User-service API를 요청하려면 API Gateway를 통해서 Discovery Service에 등록된 User Service API를 요청해야 한다.
즉, API Gateway의 IP로 /user-service/** 요청이 들어오면 User-Service API로 요청을 보내라는 의미이므로 API Gateway가 라우팅을 통해 User-service를 요청하는지 확인해야 된다.

(그러기 위해서 User-service에 간단한 API 인 /health_check 를 만들어둔 상태)

해결 과정

1. [Discovery Service를 제외하고 API Gateway와 User-Service 사이에는 문제가 없는지 확인]

먼저, Discovery Service에 등록해주지 않고 API Gateway가 User-Service API로 라우팅을 해주는지부터 확인을 해주었다.
그래서 API Gateway에 라우팅되는 주소에 서비스 이름인 USER-SERVICE 대신에 user-service의 ip주소를 넣어주었다.

실패 : User-Service의 NodePort를 만들어서 해당 URI를 API-Gateway에 등록

User-Service의 IP를 등록하기 위해서 NodePort를 만들고, NodePort의 해당 IP를 API Gateway에 등록하였다. 예를 들어, 쿠버네티스의 IP가 1.1.1.1 이고 NodePort를 30011 번 port를 열었다면 아래와 같이 API Gateway가 라우팅 하게 해주었다. 하지만 {API-Gateway 주소}/user-service/health_check 로 보낸 요청은 실패했다.

  cloud:
    gateway:
      routes:
        - id: user-service
          uri: <http://1.1.1.1:30011>
          predicates:
            - Path=/user-service/**

[실패 이유]
NodePort의 개념을 정확히 몰라서 그랬던 것이다. NodePort는 ClusterIP를 뚫고, 해당 포트를 외부로 연결해주는 포트일 뿐이다. 따라서 외부에서 NodePort로 접속하면 ClusterIP를 거쳐 Pod로 통신이 가능하도록 해주는 것이다.
그러나 API Gateway는 외부 NodePort를 등록하면 안된다. 쿠버네티스의 통신은 내부에서 일어나므로 API Gateway에는 ClusterIP를 등록해주어야 한다.

해결 : User-Service에 Cluster IP를 만들어서 해당 URI를 API-Gateway에 등록

Service 종류를 ClusterIP로 만들어서 해당 ClusterIP의 URI를 등록해준다. 작성한 user의 Deployment와 Service는 다음과 같다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: users-deployment
  labels:
    app: users
spec:
  replicas: 1
  selector:
    matchLabels:
      app: users
  template:
    metadata:
      labels:
        app: users
    spec:
      containers:
      - name: users
        image: msa.harbor.com/library/usersservice:1.0
        imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: users
  ports:
    - port: 46279
      protocol: TCP
      targetPort: 46279

이렇게 한 뒤 API Gateway IP로 User Service API에 요청한다면 요청이 성공한다.
그럼 API Gateway와 User Service 사이에는 문제가 없다는 의미이다.

2. API Gateway와 User-Service를 Discovery Service에 등록해서 확인

API Gateway가 정상적으로 마이크로서비스를 라우팅한다는 사실을 알았으니, Discovery Service에 API Gateway와 User-service를 등록한 뒤, 요청을 해보았다.
Eureka 페이지는 NodePort로 30007번으로 열었기 때문에 해당 화면에서 연결된 서비스들을 확인할 수 있었다.

USER-SERVICE의 URL에 마우스 커서를 올리면 연결된 곳이 나온다.
나는 USER-SERVICE의 애플리케이션(jar)은 0번 포트로 열었기 때문에 랜덤 포트로 연결되어 있다. 그래서 해당 User-service는 Spring Cloud Gateway에 등록해두었다.
http://{API Gateway IP 주소}/user-service/health_check
문제는 Discovery Service가 User Service가 열린 포트로 연결해서 호출해줘야하는데, 계속해서 user-service에 등록한 {spring.application.instance_id} 으로 연결되는게 문제였다.
로그를 확인해 본 결과 Discovery Service가 이상한 값인 spring.application.instance_id 이 값을 보고 있는데 이런 값은 등록한 적이 없으니 요청이 되지 않고 500 에러가 계속해서 발생했다.
예를 들어, users-deployment-65db46d67b-gtn8l 로 계속해서 연결되었다. 이 값은 쿠버네티스에서 Deployment를 만들고 뒤에 랜덤 해시값을 붙여서 배포하기 때문에 저런 이상한 값이 나오게 되는 것이다. 당연히 이 주소로 들어가면 연결이 되지 않는다.
내가 원하는 것은 http://{API Gateway}/user-service/health_check 로 호출하면 http://{user-service}/health_check 로 요청되는 것을 원한다.

3. User-Service 앞에 ClusterIP를 만들어줘서 ClusterIP → Pod

Discovery Service가 User-Service의 Pod를 등록하고 있어서 문제가 생기고 있다고 생각하여, ClusterIP를 User-Service 앞에 두어서 API Gateway가 Pod가 아닌, ClusterIP를 등록하도록 해서 이어줄려고 하였다.
(그럼 API Gateway는 User의 ClusterIP를 통해서 Pod이름이 뭐든 간에 User service의 API를 요청할 수 있을것이니까)
그런데 ClusterIP를 User-Service로 등록해두어도 ClusterIP가 등록되지 않고 계속해서 Discovery Service는 User Service의 Pod를 등록하고 있었다. 즉, ClusterIP가 사용되지 않고 있었다.

방안 생각

‘Discovery Service에 ClusterIP의 주소를 직접 등록하면 되지 않을까’ 라고 알려주셔서 해당 방법으로 해결하였다.

즉, 직접 Pod를 등록하지 않고 User-SVC(쿠버네티스 객체인 서비스를 의미, ClusterIP)를 Discovery Service에 등록해준다.

이유

해당 방법이 된다고 생각한 이유는 쿠버네티스의 마스터에서 User의 ClusterIP를 통해서 API를 Discovery Server로 curl 요청을 했을 때 성공하였다.
curl [http://{쿠버네티스 주소}:30007/eureka](<http://172.10.40.174:30007/eureka>) → 성공

해결 방법 1 : eureka.instance.homePageUrl 사용 (실패)

11. Service Discovery: Eureka Clients

 

11. Service Discovery: Eureka Clients

Service Discovery is one of the key tenets of a microservice-based architecture. Trying to hand-configure each client or some form of convention can be difficult to do and can be brittle. Eureka is the Netflix Service Discovery Server and Client. The serve

cloud.spring.io

User-Service에 eurkea.instance.homePageUrl 에 ClusterIP를 등록하면 해결 가능할 것이라 생각해여기에 등록했는데 결과적으로 잘 되지 않았다.

해결 방법 2 : prefer-ip-address=true , ip-address={ClusterIP 주소}

Eureka InstanceConfigBean에서 IpAddress 지정하는 부분만 찾아야한다.
그리고 해당 내용을 설정 파일에 등록해주면 된다.

eureka:
  instance:
  # home-page-url: <http://10.100.225.34>
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
    prefer-ip-address: true
    ip-address: {User-service의 Cluster IP 주소}

이렇게 변경해서 배포하면 성공한다.
http://{API gateway:NodePort}/user-service/health_check 를 하면 잘 요청이 되는 것을 확인할 수 있다.

 

ClusterIP에서 IP 고정

지금은 동적 할당이기 때문에 ClusterIP의 spec에서 ClusterIP를 고정할 수 있다.

apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  clusterIP: 10.104.193.23

바꾸고 kubectl replace -f users-service.yml --force 적용

728x90
반응형

+ Recent posts