[K8S] Ingress 도메인 라우팅 규칙 적용 (Feat. Mac M1 with Docker Desktop)

mDev_97·2023년 10월 10일
0

Kubernetes

목록 보기
1/10
post-thumbnail

◉ 실습과제

주제는 ingress 오브젝트를 통해 도메인 라우팅 규칙 적용하기 입니다.

📌 실습 환경

  • Mac OS m1 pro
  • kubernetes With Docker Desktop
  • kubernetes Cilent Version: v1.28.2
  • kubernetes Server Version: v1.27.2

📌 해당 게시물에서 사용하는 React와 Node.js 프로젝트 파일과 Kubernetes 메니페스트는 아래 깃허브 링크에서 확인하실 수 있습니다.
https://github.com/moonstar0331/docker-fullstack-app

Zero! 실습 환경 구축

실습을 시작하기에 앞서 우선 Mac M1 환경에서 Kubernetes를 실습하기 위한 환경을 구축할 수 있도록 합니다.

  1. Docker Desktop 설치
    Install Docker Desktop on Mac를 통해서 Docker Desktop 설치를 진행해줍니다.
    설치 후에는 아래와 같은 화면을 볼 수 있습니다.
    저 같은 경우에는 이미 활성화 되어있는 컨테이너가 있지만, 처음 실행하시는 분들은 빈 화면을 보실 수 있습니다.

  1. Kubernetes 활성화 on Docker Desktop

    Docker Desktop의 우측 상단에 톱니바퀴 모양을 클릭 후에 Enable Kubernetes를 선택하고 Apply & restart를 클릭해줍니다.

    이 작업은 시간이 상당히 많이 소요되기 때문에 물 한잔 드시고 오시면 좋습니다.😊

    위의 과정을 거치시면 Docker Desktop 좌측 하단에 Docker와 Kubernetes가 정상적으로 동작하는 것을 확인하실 수 있습니다.

  2. 로컬 환경에서 Kubernetes 동작 확인
    Kubernetes 활성까지 끝나셨다면 이제 Terminal을 통해서 확인을 해줍니다.

    로컬 터미널에서 아래의 명령어를 통해서 Kubernetes Cilent와 Server의 버전을 확인해줍니다.

    kubectl version

    명령어를 통해서 Mac M1 로컬 환경에서 명령어가 잘 동작하는 것을 확인할 수 있습니다.



First! 두 개의 서비스(Service) 배포

[문제]

먼저, 두 개의 서비스를 배포합니다.

"web-service""api-service"라는 이름으로 포트 80과 8080으로 서비스를 생성합니다.

  • Service Object 2개

    1. web-service 오브젝트 80 포트

    2. api-service 오브젝트 8080 포트

  • web-app이라는 이름의 deployment 배포

    1. 웹 에플리케이션 Image 중 하나

    2. Replicas는 2

    3. Container Port는 80

  • api-app 이라는 이름의 deployment 배포.

    1. API 어플리케이션 Image 중 하나.

    2. Replicas는 2

    3. Container Port는 8080

[해결]

다음과 같이 서비스와 파드를 생성하기 위한 매니페스트를 작성합니다.

우선 Frontend 측면을 배포하기 위한 web-service 서비스에는
web-app이라는 Deployment를 통해서 web-app 파드를 연결합니다.

# web-deployment.yaml

apiVersion: v1
kind: Service
metadata:
  name: web-service
  labels:
    app: ingress-project
spec:
  ports:
    - port: 80
      targetPort: 3000
  selector:
    app: ingress-project
    tier: web
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: ingress-project
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ingress-project
      tier: web
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: ingress-project
        tier: web
    spec:
      containers:
      - image: moonsungkim/frontend
        imagePullPolicy: Always
        name: web-app
        ports:
        - containerPort: 80
          name: web-app

그 다음으로는 Backend 측면을 배포하기 위한 api-service 서비스에
api-app이라는 Deployment를 통해서 api-app 파드를 연결하기 위한 매니페스트를 작성해줍니다.

# api-deployment.yaml

apiVersion: v1
kind: Service
metadata:
  name: api-service
  labels:
    app: ingress-project
spec:
  ports:
    - port: 8080
      targetPort: 5000
  selector:
    app: ingress-project
    tier: api
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-app
  labels:
    app: ingress-project
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ingress-project
      tier: api
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: ingress-project
        tier: api
    spec:
      containers:
      - image: moonsungkim/backend
        imagePullPolicy: Always
        name: api-app
        env:
        - name: DB_HOST
          value: mysql
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 8080
          name: api-app

그리고 Backend에 연결하기 위한 MySQL를 띄우기 위한 매니페스트를 작성해주도록 합니다.

# mysql-deployment.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: ingress-project
spec:
  ports:
    - port: 3306
  selector:
    app: ingress-project
    tier: mysql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: ingress-project
spec:
  volumeName: mysql-pv-volume
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: ""
---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume
  labels:
    app: ingress-project
spec:
  storageClassName: ""
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mysql/mysql_data
    path: DirectoryOrCreate

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deploy
  labels:
    app: ingress-project
spec:
  selector:
    matchLabels:
      app: ingress-project
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: ingress-project
        tier: mysql
    spec:
      containers:
      - image: moonsungkim/mysql
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        - name: MYSQL_DATABASE
          value: myapp
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

여기서 DB의 Password와 같은 민감한 정보를 숨기기 위해서는 시크릿 을 통해서 저장합니다.
이를 위해서 다음 명령어로 kustomization.yaml 내에 시크릿 제네레이터를 추가합니다.

❗️YAML 파일의 이름은 무조건 kustomization.yaml 또는 kustomization.yml 이어야 합니다.

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=1234
resources:
  - mysql-deployment.yaml
  - api-deployment.yaml
  - web-deployment.yaml
EOF

Second! Ingress 리소스 생성

[문제]

다음으로, Ingress 리소스를 생성하여 서비스들을 라우팅할 규칙을 정의합니다.

[해결]

쿠버네티스에서는 인그레스 컨트롤러가 있어야 인그레스를 충족할 수 있습니다.
즉, 인그레스 리소스만 생성한다면 효과는 없습니다.

이를 위해서 먼저 인그레스 컨트롤러를 설치하도록 합니다.
그 중에서 많은 사용되는 Ingress-NGINX Controller를 사용하도록 합니다.

INGRESS-NGINX Controller 설치 방법 을 참고하여 진행하시면 됩니다. 저는 아래와 같은 명령어를 통해서 설치를 진행하였습니다.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml

위의 명령어를 실행한 후에 아래의 명령어를 실행하면

kubectl get all -n ingress-nginx

다음과 같이 LoadBalancer 타입으로 ingress-nginx-controller 가 생성된 것을 확인할 수 있습니다.


Third! Ingress 적용

[문제]

Ingress 리소스를 적용하여 외부에서 yourdomain.com/ 으로 접근하면 "web-service"

yourdomain.com/api 로 접근하면 "api-service"로 연결되도록 설정합니다.

[해결]

이제 요청 경로에 따라 서비스를 연결하는 인그레스 메니페스트를 작성하도록 합니다.
엔드포인트가 / 인 요청은 web-service에 연결하고 엔드포인트가 /api 인 요청은 api-service에 연결하도록 합니다.

# project-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

📌 주의할 점
nginx-ingress-controller를 설치하면 기본적으로 오브젝트들의 라벨명이 ingress-nginx로 설정이 되어 있습니다.
따라서 배포할 Ingress의 이름을 기본적으로 ingress-nginx로 설정 해주어야 매핑이 됩니다.

이제 다음 명령어를 통해서 Ingress를 생성하여 확인하면
//api에 정상적으로 매핑이 되는 것을 알 수 있습니다.
또한, 서비스인 web-serviceapi-service가 아직은 생성되지 않았기 때문에 endpoints not fount가 뜨는 것을 보실 수 있습니다.

kubectl apply -f project-ingress.yaml
kubectl describe ing ingress-nginx


Last! 위 명령을 실행하여 Ingress 리소스를 적용합니다.

[문제]

그리고 나서 도메인 주소를 통해 yourdomain.com/webyourdomain.com/api 로 접근해보세요.

이렇게 설정된 Ingress를 통해 서비스들이 제대로 라우팅되는지 확인하실 수 있습니다.

※ 도메인 주소의 DNS 설정은 따로 하지 않습니다.

[해결]

이제 다음 명령어를 통해 서비스를 생성하여 정상적으로 라우팅 되는지를 확인해보도록 합니다.

kubectl apply -k ./

그럼 처음부터 만들어둔 SecretService 그리고 Deployment가 생성이 됩니다.

kubectl describe ing ingress-nginx

또한 파드의 IP:PORT로 서비스가 정상적으로 연결되는 것을 볼 수 있습니다.

이제 http://localhost 로 접속을 해보면 다음과 같은 결과를 마주할 수 있습니다.

마지막으로 Input 박스에 값을 추가하여 DB와도 정상적으로 연결되는지도 확인할 수 있습니다.

profile
안녕하세요. 백엔드, 클라우드, 인프라에 관심과 열정이 있는 김문성입니다. 😊

0개의 댓글