Deployment
디플로이먼트는 포드를 관리하는 오브젝트로 설정 YAML 파일을 작성할 때 여러 속성들 때문에 조금 헷갈렸다. 설정 YAML 파일에서 spec은 생성하려는 오브젝트에 적용하는 속성을 명시하는 부분이다. selector 속성은 생성할 모든 포드를 찾는 방법을 디플로이먼트에 알려주며 matchLabels 속성은 selector 속성이 일치할 레이블을 명시한다. template 속성은 디플로이먼트가 생성할 각 포드의 설정을 정의한다. 즉, metadata 속성과 spec 속성을 다시 명시하는 부분이다. 리뷰 서비스의 디플로이먼트 YAML 파일은 다음과 같다.
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 31 32 33 34 35 36 37 38 39 40 41 | apiVersion: apps/v1 kind: Deployment metadata: name: review spec: replicas: 1 selector: matchLabels: app: review template: metadata: labels: app: review spec: containers: - name: review image: csup96/tour-review env: - name: NODE_ENV value: 'development' - name: PORT value: '3000' - name: MONGO_URI value: 'mongodb://review-mongo:27017/review' - name: REDIS_HOST value: 'review-redis' - name: REDIS_PORT value: '6379' - name: JWT_ACCESS_SECRET value: 'personal-tour-project-in-nodejs-typescript-access' - name: JWT_REFRESH_SECRET value: 'personal-tour-project-in-nodejs-typescript-refresh' - name: NATS_URL value: 'http://nats:4222' - name: NATS_CLUSTER_ID value: 'tour' - name: NATS_CLIENT_ID valueFrom: fieldRef: fieldPath: metadata.name | cs |
Service
포드를 관리하는 디플로이먼트 설정 파일을 작성하는데 크게 어려운 점이 없었지만 서비스의 경우 달랐다. 서비스는 오브젝트의 일종으로 서로 다른 포드 간의 통신을 설정하거나 클러스터 외부에서 포드에 접근할 수 있는 URL을 제공한다. 따라서, 네트워킹이나 통신을 생각할 때는 항상 서비스를 염두에 두어야 한다. 다시 말해, 생성하는 거의 모든 포드나 디플로이먼트는 항상 관련된 서비스를 가진다고 볼 수 있다. Kubernetes는 크게 4개의 서비스를 제공한다. Cluster IP는 클러스터 내에서만 접근 가능한 포드에 쉽게 기억할 수 있는 URL을 설정한다. Node Port는 개발 목적으로만 사용되는 경우가 많으며 포드를 클러스터 외부에서 접근 가능하게 한다. Load Balancer도 포드를 클러스터 외부에 노출한다. External Name은 클러스터 내 요청을 CNAME URL로 리다이렉트 한다.
일단 클러스터 내의 포드 간 통신은 당연히 Cluster IP를 사용하면 된다. 서비스 A 포드가 서비스 B 포드와 이벤트로 통신을 할 경우 서비스 A가 이벤트를 방출하면 이벤트 버스 포드의 Cluster IP로 요청을 보내고 이벤트 버스는 서비스 A 포드의 Cluster IP로 응답을 전송한다. 예를 들어, 리뷰 서비스의 서비스 YAML 파일을 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | apiVersion: v1 kind: Service metadata: name: review spec: selector: app: review ports: - name: review protocol: TCP port: 3000 targetPort: 3000 type: ClusterIP | cs |
클러스터 외부와의 통신의 경우 Node Port와 Load Balancer중 하나를 골라야 하는데 Node Port의 큰 단점은 생성 시 기본적으로 무작위 포트를 열기 때문이다. 정확한 포트를 지정할 수 없고 클러스터 내에서 임의의 포트를 할당받게 받기 때문에 Node Port를 변경하게 되면 할당받는 포트가 다를 가능성이 있다. Load Balancer는 이러한 고민을 없애준다. Load Balancer는 클러스터 전체에 대한 단일 진입 지점을 설정하고 내부에서 요청을 적절한 포드로 라우팅 한다. 다시 말하지만 포드로 라우팅한다는 것은 실제로는 포드에 대해 생성할 Cluster IP를 참조하는 것이다. 그렇다면 라우팅은 어떻게 처리할까? 바로 Ingress 포드이다!
Ingress
이제 문제는 Load Balancer로 들어온 요청을 어느 포드로 전달하는 것이다. 즉, 라우팅 규칙을 설정해야 하는데 이를 관리하는 것이 Ingress 포드이다. 여러 Ingress 포드 중에서 Ingress NGINX 포드를 사용하기로 결정했다. 사실 Load Balancer는 AWS, GCP 그리고 Azure와 같은 클라우드 서비스를 통해 제공받아야 하는데 Ingress-Nginx는 Ingress 포드뿐만 아니라 Load Balancer도 지원한다.
호스트 파일
하나의 Kubernetes 클러스터 내에서 여러 다른 애플리케이션을 다양한 도메인에 호스팅할 수 있는데 예를 들어, 애플리케이션 A는 blog-app.com 애플리케이션 B는 tasty-delivery.org에 있을 수 있다. Ingress NGINX는 여러 애플리케이션을 다양한 도메인에서 호스팅할 수 있음을 전제로 설정된다. 그런데 개발 환경에서는 큰 단점이 있다. 바로 모든 실행 중인 서버에 localhost로 접근한다. 그렇다면 라우팅 규칙이나 특정 도메인을 사용하는 아이디어가 Ingress NGINX와 어떻게 맞아 떨어질까? 개발 환경에서는 도메인을 localhost와 동일하게 인식하도록 속여야 한다. 만약 호스트가 blog-app.com이면 연결하려고 할 때 인터넷에 존재하는 실제 blog-app.com이 아닌 현재 컴퓨터에 연결하도록 속이는 것이다. 이를 위해 호스트 파일의 설정을 변경해야 한다. Windows는 C:\\Windows\System32\Drivers\etc\hosts, MacOS와 Linux는 /etc/hosts 파일을 수정한다.
ingress.yaml
NGINX는 와일드카드를 지원하지 않기 때문에 정규 표현식을 경로에 사용해야 한다. 경로의 순서는 매우 중요하다. 위에서부터 밑으로 경로를 순서대로 확인하기 때문에 OAuth 2.0 HTML 파일과 일치하는 정규 표현식이 가장 밑에 위치해야 한다. 만약 이 경로를 맨 위에 두면 경로 일치가 미리 발생해서 백엔드 경로를 사용할 수 없다. 또한, 리뷰나 예약과 같이 여행을 지칭하는 tours로 시작하는 API의 경우 tours 경로보다 위에 있어야 한다.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tour-ingress annotations: nginx.ingress.kubernetes.io/use-regex: 'true' spec: ingressClassName: nginx rules: - host: tour.xyz http: paths: - path: /api/v1/auth/?(.*) pathType: ImplementationSpecific backend: service: name: auth port: number: 3000 - path: /api/v1/oauth2/?(.*) pathType: ImplementationSpecific backend: service: name: auth port: number: 3000 - path: /api/v1/users/?(.*) pathType: ImplementationSpecific backend: service: name: auth port: number: 3000 - path: /api/v1/admin/users/?(.*) pathType: ImplementationSpecific backend: service: name: auth port: number: 3000 - path: /api/v1/tours/?(.*)/bookings pathType: ImplementationSpecific backend: service: name: booking port: number: 3000 - path: /api/v1/bookings/?(.*) pathType: ImplementationSpecific backend: service: name: booking port: number: 3000 - path: /api/v1/admin/bookings/?(.*) pathType: ImplementationSpecific backend: service: name: booking port: number: 3000 - path: /api/v1/payments/?(.*) pathType: ImplementationSpecific backend: service: name: payment port: number: 3000 - path: /api/v1/tours/?(.*)/reviews pathType: ImplementationSpecific backend: service: name: review port: number: 3000 - path: /api/v1/reviews/?(.*) pathType: ImplementationSpecific backend: service: name: review port: number: 3000 - path: /api/v1/admin/reviews/?(.*) pathType: ImplementationSpecific backend: service: name: review port: number: 3000 - path: /api/v1/tours/?(.*) pathType: ImplementationSpecific backend: service: name: tour port: number: 3000 - path: /api/v1/admin/tours/?(.*) pathType: ImplementationSpecific backend: service: name: tour port: number: 3000 - path: /?(.*) pathType: ImplementationSpecific backend: service: name: client port: number: 3000 | cs |
Skaffold
애플리케이션을 실제 운영 환경에서 배포할 경우 애플리케이션 수정이 발생하면 Docker 이미지를 빌드하고 Docker Hub에 푸시한 후 kubectl rollout restart 명령어를 사용해서 배포를 진행한다. 하지만 개발 환경에서 이 과정은 너무 번거로운데 이를 도와주는 도구가 바로 Skaffold이다. Skaffold는 Kubernetes 개발 환경에서 다양한 작업을 자동으로 처리해주는 CLI 도구이다. 실행 중인 포드의 애플리케이션 코드를 매우 쉽게 수정할 수 있고 프로젝트와 관련된 모든 오브젝트들을 매우 빠르게 생성하고 삭제할 수 있다. Skaffold를 다운로드하고 설정하는 것은 홈페이지에서 쉽게 할 수 있다.
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 31 32 33 34 35 36 37 | apiVersion: skaffold/v4beta3 kind: Config manifests: rawYaml: - ./k8s/**/* build: local: push: false artifacts: - image: csup96/tour-auth context: auth docker: dockerfile: Dockerfile - image: csup96/tour-booking context: booking docker: dockerfile: Dockerfile - image: csup96/tour-expiration context: expiration docker: dockerfile: Dockerfile - image: csup96/tour-payment context: payment docker: dockerfile: Dockerfile - image: csup96/tour-review context: review docker: dockerfile: Dockerfile - image: csup96/tour-tour context: tour docker: dockerfile: Dockerfile - image: csup96/tour-client context: client docker: dockerfile: Dockerfile | cs |
update: 2024.10.22
댓글 없음:
댓글 쓰기