본문 바로가기
AWS Cloud School 8기/쿠버네티스

[쿠버네티스] LoadBalancer/ Ingress/ Monolithic/ Micro-service

by YUNZEE 2025. 4. 15.
728x90

쿠버네티스 클러스터 트러블슈팅

더보기

kubectl delete pod --all

# 모든 pod 삭제

 

kubectl run test1 --image=public.ecr.aws/docker/library/nginx:alpine

kubectl run test2 --image=public.ecr.aws/docker/library/nginx:alpine

 

kubectl create deploy test --replicas=2 --image=public.ecr.aws/docker/library/nginx:alpine

# worker-1은 정상

# worker-2는 비정상.

# 정상인 것처럼 보이지만 비정상.

root@master:~# kubectl delete pod --all -n kube-system

# 모든 파드를 삭제해 보자.

# 다시 비정상 파드주소에 curl을 해보자. 그래도 안되면 일단 모든 노드 재부팅.

init 6

# 재부팅 후에 정상이 됐다.

그래도 안된다면 최악의 상황.

1.kubectl delete -f kube-flannel.yml로 flannel CNI 삭제

2. 모든 노드에서 kubeadm reset으로 클러스터 리셋

3. 재부팅을 해서 CNI 관련된 호스트의 설정값들을 초기화

4.kubeadm init 및 kubeadm join으로 클러스터 재구성.

LoadBalancer 타입

- 클러스터 관리자의 도움이 필요한 서비스 타입

- EKS 같은 클라우드 서비스 제공자의 경우.

- Service타입을 LoadBalancer로 명시하기만 해도 이미 기능이 구현되어 있기 때문에 자동으로 LB가 생성.

(aws의 EKS에서 Service 타입을 LoadBalancer로 생성하면 실제 NLB나 classic loadbalancer(기본값)가 생성)

LB는 노드 외부에 존재하며 클러스터와 동등한 대역대(211.183.3.0/24)의 아이피를 갖는다.

 

근데 우리는 온프레미스에 클러스터를 구축했기 때문에 그 기능이 존재하지 않음. Bare-metal환경에 직접 구축을 했기 때문에 metalLB라는 애드온을 추가하여 로드밸런싱기능을 구현해야 함

더보기

 

root@master:~/mani# cd ~
root@master:~# wget https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml

 

- 웹에 올려진 매니페스트를 설치해도 되지만 나중에 클러스터 재구축하면 또 쓸 수 있으므로 wget으로 다운로드를 하자

 

kubectl apply -f metallb-native.yaml

- 설치

- 우리가 서비스 타입을 LoadBalancer로 하여 LB를 생성하면, 211.183.3.0/24 대역의 아이피를 갖는 리소스가 하나 생성이 됨. 하지만 이건 실제 네트워크인 211.183.3.0/24 대역의 입장에서는 가상의 리소스이며, 인지 불가능 클러스터 = 집. 집안에서 만든 리소스, 집 밖의 가상의 주소를 부여받음.

- 따라서 이렇게 부여받은 아이피는 211.183.3.0/24 네트워크 입장에서는 알 수 없음

- 그래서 LB에 부여된 아이피를 집 외부(211.183.3.0/24) 대역에 알려줘야 하는데, 이게 speaker의 역할. 내가 로드벨런서 생성해서 211.183.3.200이라는 아이피를 부여할 거니까 너네도 그렇게 알아 라는 통신을 전달함

 

root에 넣어주기

vi config-metal.yml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 211.183.3.200-211.183.3.240 # 안겹치게 수정
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system

- IPAddressPool: LB를 생성했을 때 부여받을 아이피 대역대 정의

- L2Advertisement: LB에 특정한 아이피가 부여됐다는 사실을 다른 네트워크 구성원들에게 알려주는 역할(설치 시 speaker라는 pod가 정상 동작)

 

root@master:~# vi lbtest.yml

apiVersion: v1
kind: Namespace
metadata:
  name: ip-ns
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ip-dep
  namespace: ip-ns
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myipnginx
  template:
    metadata:
      labels:
        app: myipnginx
    spec:
      containers:
      - name: ip-con
        image: oolralra/ipnginx
---
apiVersion: v1
kind: Service
metadata:
  name: svc-ipnginx
  namespace: ip-ns
spec:
  type: LoadBalancer
  selector:
    app: myipnginx
  ports:
  - port: 80
    targetPort: 80

kubectl delete -f hw1.yml

- 겹칠 수도 있으니까 전에 만든 파일 삭제

 

root@master:~/mani# kubectl apply -f lbtest.yml 

 

root@master:~/mani# kubectl get svc -n ip-ns 
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
svc-ipnginx   LoadBalancer   10.97.198.78   211.183.3.200   80:30996/TCP   3m39s


root@master:~/mani# curl 211.183.3.200
request_method : GET | ip_dest: 10.244.1.25

실습 1)

https://github.com/oolralra/simple_jar

# 이미 빌드가 되어있는 springboot 앱. 8085 포트 사용.

 

211.183.3.150~160정도의 IP로 접속했을 때 위 앱이 뜨도록 한번 만들어보세요.

 

ns : spring-ns

svc: svc-spring

pod의 label => app: spring

 

컨테이너 레지스트리는 제 것을 써도 괜찮고 도커허브 쓰셔도 됩니다.

더보기

git clone https://github.com/oolralra/simple_jar

cd simple_jar

 

root@master:~/mani/simple_jar# vi /etc/docker/daemon.json 

{
"insecure-registries": ["61.254.18.30:5000"]
}

 

vi Dockerfile

FROM 61.254.18.30:5000/openjdk:8-jre-alpine
WORKDIR /app
COPY springbootApp.jar app.jar
CMD ["java","-jar","app.jar"]

 

docker build -t 61.254.18.30:5000/pcm/spring:1 .

 

docker push 61.254.18.30:5000/pcm/spring:1

 

docker rmi -f 61.254.18.30:5000/pcm/spring:1

 

docker run -dp 80:8085 --name test 61.254.18.30:5000/pcm/spring:1

 

docker rm -f test

 

cp ../lbtest.yml ./spring.yml

- 아까 썼었던 매니페스트를 복제.

apiVersion: v1
kind: Namespace
metadata:
  name: spring-ns
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-dep
  namespace: spring-ns
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring
  template:
    metadata:
      labels:
        app: spring
    spec:
      containers:
      - name: spring-con
        image: 61.254.18.30:5000/pcm/spring:1
---
apiVersion: v1
kind: Service
metadata:
  name: svc-spring
  namespace: spring-ns
spec:
  selector:
    app: spring
  type: LoadBalancer
  ports: 
  - port: 80
    targetPort: 8085

- targetPort를 실제 앱이 동작하는 포트인 8085로 해주는 게 가장 중요함

- LB를 생성하면 service의 포트인 80을 따라감

kubectl apply -f spring.yml

kubectl apply -f ../../config-metal.yml

오류/ 해결 방안 - 외부 IP로는 웹사이트 접속이 안된다는 문제

더보기

root@master:~/mani/simple_jar# kubectl describe svc svc-spring -n spring-ns

root@master:~/mani/simple_jar# kubectl get pods -n spring-ns 

- 자체 레지스트리에서 이미지를 문제없이 다운로드할 수 있음

- 이 설정을 추가한 후, 테스트로 이미지를 풀 해보면 정상 동작하는지 확인할 수 있음

 

master, worker-1, worker-2에 다 복붙 해주기

cat <<EOF >> /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."61.254.18.30:5000"]
      endpoint = ["http://61.254.18.30:5000"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."61.254.18.30:5000".tls]
      insecure_skip_verify = true
EOF

- insecure_skip_verify = true -> TLS인증서 검증 건너뛰기

 

master, worker-1, worker-2에 다 복붙 해주기 

systemctl restart containerd

- 모든 노드에서 이걸 해야 함.

- endpoints가 생긴 걸 확인할 수 있음.

- 211.183.3.150으로 접속이 잘 됨.

- 쿠버네티스 클러스터에서 Advertisment를 통해 적극적으로 metalLB가 쓰는 아이피를 알려줬기 때문에 다른 노트북이나 네트워크 구성원들이 이 아이피를 인지할 수 있음

Monolithic vs Micro-service

Monolithic Micro-service
하나의 앱
-> 동일한 개발 환경에서 모든 기능 구현
여러개의 앱
-> 여러개의 개발 환경에서 기능을 나눠서 구현
1개의 컨테이너
-> 초기 개발이 빠르고 쉬움
-> 기능을 추가하거나 규모가 커지면 수정하기 불편
여러개의 컨테이너
-> 초기 개발이 느리고 어려움
-> 기능을 추가하거나 규모가 커지면 수정하기가 편함

- 여러 개의 컨테이너에 각 기능들을 구현하여 path로 라우팅이 가능해야 함

- 일반적인 svc로는 path기반 라우팅이 불가능함

Ingress

- path기반 라우팅이 가능한 리소스

- 만약 위 마이크로 서비스를 LoadBalancer로 구현한다고 하면

- Ingress: 내부 서비스로 라우팅 하는 역할을 하는 리소스를 말함

- Ingress Controller: 클러스터 외부에서 내부 서비스로 트래픽을 효율적으로 전달하고, 다양한 라우팅 규칙을 적용할 수 있음

- 서비스는 한 종류의 label만 품을 수 있기 때문에 이런 한계가 발생함

- Ingress는 클러스터 내에서 요청을 어떻게 처리할지를 정의하는 리소스이고, Ingress Controller는 Ingress리소스의 규칙을 실제로 적용하고 트래픽을 라우팅 하는 실행 엔진임

1. ingress 리소스: 라우팅 규칙을 정의한 리소스

2. ingress Controller: 실제로 트래픽을 처리하는 엔진

- ingress controller가 필요. 되도록이면 인그리스 컨트롤러를 설치할 때 metalLB를 먼저 구성해 주는 게 좋음.

더보기

https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters

- 버전이 계속 바뀌는 ingress-controller 설치 페이지.

 

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/baremetal/deploy.yaml

- 인그리스 컨트롤러 설치 매니페스트 ingress-nginx라는 네임스페이스에 기능이 설치됨

 

vi deploy.yml

- type: LoadBalancer로 수정

 

kubectl apply -f deploy.yaml

kubectl get pod,svc -n ingress-nginx

- 마지막 controller만 1/1이면 됨

kubectl get svc -n ingress-nginx 

- 아이피를 잘 부여받았음

vi deploy-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: svc-ip
spec:
  selector:
    app: ipnginx
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ip-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ipnginx
  template:
    metadata:
      name: ip-pod
      labels:
        app: ipnginx
    spec:
      containers:
      - name: ip-con
        image: 61.254.18.30:5000/ipnginx

 

- 나중에 ingress를 구성할 때 서비스의 이름으로 찾아갈 것이기 때문에, svc의 이름(svc-ip)을 기억해 둬야 됨

 

kubectl apply -f deploy-svc.yml 

kubectl describe svc svc-ip

- svc -> pod로 트래픽이 잘 인가되고, pod도 정산인지 확인하기 위함

- ingress에 문제가 있을 때 트러블슈팅하기 용이함

 

vi ingress.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: rapa.com
      http:
        paths:
        - path: /httpd
          pathType: Prefix
          backend:
            service:
              name: svc-ip #서비스의 이름
              port:
                number: 80 #서비스의 포트

 

✅ Deployment, Service, Ingress의 관계

여기서 복습할 겸 Deployment, Service, Ingress 의 관계 흐름에 대해 설명하자면

Deployment: 실제로 애플리케이션을 실행하고 관리하는 역할을 함

- pod는 애플리케이션이 실행되는 단위인데, Deployment는 여러 pod들을 자동으로 관리해 줌

Service: pod들 간의 네트워크 통신을 돕는 역할을 함

- 언제든지 ip주소가 변경될 수 있기 때문에, 외부에서 직접 연결하는 게 어려워서 Service는 고정된 IP를 제공하고, pod들에 트래픽을 분배해 줌

Ingress: 외부에서 들어오는 http요청을 kubernetes내부의 서비스로 라우팅 하는 역할을 수행

- 클러스터 밖에서 들어오는 트래픽을 어떤 서비스로 보낼지 결정해 주고, 도메인이나 경로에 따라서 트래픽을 분배함

 

이제 각 리소스가 어떻게 서로 연결되는지 흐름을 설명할게:

  1. Deployment: 애플리케이션(예: 웹 서버)을 실행하고 Pod들을 관리함.
    • Pod들이 Deployment에서 관리되고 실행됨.
  2. Service: Deployment로 실행된 Pod들에 대한 고정된 접근 경로를 제공함.
    • 클러스터 내에서 서비스 이름으로 연결되고, 외부에서는 NodePort나 LoadBalancer를 통해 접속할 수 있음
  3. Ingress: 외부 트래픽도메인경로에 따라 적절한 서비스로 라우팅되게 함.
    • Ingress는 Service를 대상으로 외부 요청을 전달하며, Nginx Ingress Controller 같은 컨트롤러가 실제로 요청을 처리함.

# annotations : 추가적인 정보. labels와 비슷하지만 주로 부가적인 기능 명시.

# '인그리스 컨트롤러는 nginx'이며,

 

# rewrite-target: /

# path를 /httpd를 통해서 해당 앱으로 가게 되면 경로를 /httpd가 아닌 '/'로 하겠음.

 

# host: 영문주소, DNS기능이 필요함.

# path: /httpd

# 위의 호스트와 조합하여 'rapa.com/httpd 로 들어왔을 때'를 의미함.

 

# backend: 서비스를 뜻함

 

# service.name: svc-ip

# 연결시켜 줄 svc.

 

vi /etc/hosts

- DNS-server를 구성하긴 그러니까, rapa.com을 안내해 주기 위해 /etc/hosts에 적어줌

- rapa.com 주소가 211.183.3.151로 매칭이 되어있음

- rapa.com에서 ingress-controller의 svc IP를 통해서 ingress로 넘어감(path기반 라우팅)

오류 /해결 방안 - image는 가져오지 못한다고 하는데 curl은 찍어지는 이상한 현실...

실습 2)

rapa.com/httpd 으로 접속했을 때

61.254.18.30:5000/ipnginx 이 보이도록 이미 구성되어 있음.

rapa.com/ 으로 접속했을 때

61.254.18.30:5000/hnginx 이 보이도록 해보세요.

" 하나의 ingress가 여러 개의 svc를 포함한다. "

더보기

1. svc와 deployment 생성

cp ip.yml h.yml

vi h.yml 

apiVersion: v1
kind: Service
metadata:
  name: svc-h
spec:
  selector:
    app: hnginx
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: h-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hnginx
  template:
    metadata:
      name: h-pod
      labels:
        app: hnginx
    spec:
      containers:
      - name: h-con
        image: 61.254.18.30:5000/hnginx

 

kubectl apply -f h.yml

 

2. ingress 수정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: rapa.com
      http:
        paths:
          - path: /httpd
            pathType: Prefix
            backend:
              service:
                name: svc-ip #서비스의 이름
                port:
                  number: 80 #서비스의 포트
          - path: /
            pathType: Prefix
            backend:
              service:
                name: svc-h #서비스의 이름
                port:
                  number: 80 #서비스의 포트

 

질문 1) 노트북에서는 rapa.com 이 접속이 안 되냐? => 안됩니다. 노트북은 rapa.com을 모르기 때문. rapa.com의 IP를 아는 호스트는 현재 /etc/hosts에 등록해 준 master노드뿐임.

 

질문 2) ingress-controller의 svc는 ingress-nginx라는 네임스페이스에 존재하는데 다른 리소스들은 default 네임스페이스에 존재한다. 어떻게 트래픽이 인가되냐? => ingress-controller의 IP는 클러스터 외부에 존재하는 IP이기 때문에 ingress와 svc와 pod들만 같은 네임스페이스에 있으면 됨.

실습 3)

mario라는 이름의 ingress를 생성하세요.

aws8.com/ 로 접속 시 8085 포트로 동작하는 61.254.18.30:5000/pcm/spring:1 , 서비스포트는 8085

aws8.com/h로 접속 시 80 포트로 동작하는 61.254.18.30:5000/hnginx , 서비스포트는 81

aws8.com/ip로 접속 시 80 포트로 동작하는 61.254.18.30:5000/ipnginx , 서비스포트는 81

더보기

로드밸런서 타입의 경우엔, svc의 포트를 따라가지만, ingress 경우엔 그렇지 않음

aws8.com/h로 접속하면 특정 서비스의 포트까지 명시하므로, 따로 포트를 명시할 필요가 없음

 

ex) aws8.com:81/h 이런 식으로 할 필요가 없다는 뜻.

vi ingress.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: aws8-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: aws8.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: svc-spring #서비스의 이름
                port:
                  number: 8085 #서비스의 포트
          - path: /h
            pathType: Prefix
            backend:
              service:
                name: svc-h #서비스의 이름
                port:
                  number: 81 #서비스의 포트
          - path: /ip
            pathType: Prefix
            backend:
              service:
                name: svc-ip #서비스의 이름
                port:
                  number: 81 #서비스의 포트

vi spring.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-dep
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring
  template:
    metadata:
      labels:
        app: spring
    spec:
      containers:
      - name: spring-con
        image: 61.254.18.30:5000/pcm/spring:1
---
apiVersion: v1
kind: Service
metadata:
  name: svc-spring
spec:
  selector:
    app: spring
  type: LoadBalancer
  ports: 
  - port: 8085
    targetPort: 8085

vi h.yml

apiVersion: v1
kind: Service
metadata:
  name: svc-h
spec:
  selector:
    app: hnginx
  ports:
  - port: 81
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: h-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hnginx
  template:
    metadata:
      name: h-pod
      labels:
        app: hnginx
    spec:
      containers:
      - name: h-con
        image: 61.254.18.30:5000/hnginx

vi ip.yml

apiVersion: v1
kind: Service
metadata:
  name: svc-ip
spec:
  selector:
    app: ipnginx
  ports:
  - port: 81
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ip-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ipnginx
  template:
    metadata:
      name: ip-pod
      labels:
        app: ipnginx
    spec:
      containers:
      - name: ip-con
        image: 61.254.18.30:5000/ipnginx

kubectl apply -f spring.yml

kubectl apply -f h.yml

kubectl apply -f ip.yml

vi /etc/hosts 수정

잘되는지 확인

오류/ 해결 방안 - 경고 부분 수정

더보기

- spec.ingressClassName 이 부분을 따로 풀어서 쓰면

spec:

  ingressClassName

- 경고가 뜬 부분을 수정.

728x90