(연습) k3s VIP 설정 (MetalLB)

2025. 11. 20. 14:21·인프라/Kubernetes
반응형

3대의 노드에 하나의 ip로 서비슬르 만들기 위해서 처음에 구상할때는 keepalived + haproxy 를 이용하려고 했다.

그런더 검색을 하다보니 이방법이 예전방식이고 Metallb 가 사실상 표준이 되었다고 한다.

 

MetalLB 설치

마스터 노드에서 설치 명령 실행

$ sudo k3s kubectl get nodes
NAME        STATUS   ROLES                  AGE     VERSION
k3s-node1   Ready    control-plane,master   6h40m   v1.33.5+k3s1
k3s-node2   Ready    <none>                 6h34m   v1.33.5+k3s1
k3s-node3   Ready    <none>                 6h31m   v1.33.5+k3s1

먼저 노드는 모두 잘 살아 있는지 확인 하고

 

$ sudo kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/servicel2statuses.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
configmap/metallb-excludel2 created
secret/metallb-webhook-cert created
service/metallb-webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created

뭔가 엄청 빠른 속도로 끝이 났다.

 

각 노드에서 잘 설치 되었는지 확인해 보자.

$ sudo k3s kubectl get pods -n metallb-system
NAME                          READY   STATUS    RESTARTS   AGE
controller-654858564f-tkxcc   1/1     Running   0          3h41m
speaker-4hm7x                 1/1     Running   0          3h41m
speaker-r5pvd                 1/1     Running   0          3h41m
speaker-w5k89                 1/1     Running   0          3h41m

컨트롤 1개에 노드 3개니까 스피커 3개면 정상

restarts 가 0에 가까워야 이슈없음

$ sudo k3s kubectl get ds -n metallb-system
NAME      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
speaker   3         3         3       3            3           kubernetes.io/os=linux   3h42m

Desired : 3, 즉 3대의 노드에 실행되기를 희망하는데 현재 3개가 돌고 있으므로 잘 설정됨

 

이제부터는 k3s 설치후 처음으로 설정파일을 만들어 보려고 한다.

설정파일은 어디에 두어도 좋다고 하는데

나는 루트 밑에 k8s 디렉토리를 만들어서 두려고 한다.

 

master 에만 두어도 되는건지 아직은 잘 모르겠으나 일단 가이드대로 해본다.

 

AI가 이런식으로 설정 구조를 가져가라고 추천해준다.

일단 이렇게 해보는것이 시행착오를 줄일것 같으니 해보자.

1단계: IPAddressPool 생성 (IP 주소 범위 정의)

@k3s-node1:/k8s/system/metallb

위치에 생성한다.

$ sudo vi ipaddresspool.yaml
# ipaddresspool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: my-proxmox-vip-pool
  namespace: metallb-system
spec:
  # 10.34.1.150 단일 IP만 할당하기 위해 /32 서브넷 마스크를 사용합니다.
  addresses:
  - 10.34.1.150/32
~
~

$ sudo kubectl apply -f ipaddresspool.yaml
ipaddresspool.metallb.io/my-proxmox-vip-pool created

적용까지 하니까 뭔가 빠르게 끝난다.

 

2단계: L2Advertisement 생성 (L2 모드 광고 활성화)

정의된 IP 주소 풀을 L2(ARP/NDP) 모드로 클러스터 노드가 네트워크에 광고하도록 설정하는 설정이라고 한다.

내가 이런 아이피를 vip를 쓸거야 니들 노드들 잘 알고 있어..~ 뭐 이런건가 보다.

# l2advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-advertisement-for-vip
  namespace: metallb-system
spec:
  # 위에서 정의한 IPAddressPool 이름을 지정합니다.
  ipAddressPools:
  - my-proxmox-vip-pool
  
  
$ sudo kubectl apply -f l2advertisement.yaml
l2advertisement.metallb.io/l2-advertisement-for-vip created

 

3단계: 서비스 생성 및 VIP 할당 확인

2단계까지 했으면 실제 VIP 셋팅은 끝난것으로 보인다.

그럼 실제로 서비스 + pod 를 만들어서 잘 되는지를 확인해 보면 될것 같다.

일단 nginx 를 하나 올리고 기본 페이지가 뜨는 것을 해보도록 한다.

 

nginx pod 배포

파일 구조는 아래처럼 하려고 한다.

베이스를 두고 설정이 달라질수 있는 부분을 별도로 빼서 관리하는게 정석이라고 안내를 해준다.

# k8s/apps/test-nginx/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1 # 기본값은 1개
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
# k8s/apps/test-nginx/base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-vip-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer # MetalLB가 인식하는 타입
# k8s/apps/test-nginx/base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml

순서대로 이렇게 만들어 주고 production 설정을 만든다.

내용을 쭉보니 base 에서 만든설정들을 베이스로 overwrite 를 해서 최종 설정을 하는듯 하다.

 

production 설정

# k8s/apps/test-nginx/production/kustomization.yaml 최종 수정본

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../base
- ingress.yaml

patches:
# --- 패치 1: Deployment의 Pod 개수(replicas) 수정 (유지) ---
- target:
    kind: Deployment
    name: nginx-deployment
  patch: |
    - op: replace
      path: /spec/replicas
      value: 3
# --------------------------------------------------

# --- 패치 2: Service 타입을 ClusterIP로 변경 (새로 추가) ---
- target:
    kind: Service
    name: nginx-vip-service
  patch: |
    - op: replace
      path: /spec/type
      value: ClusterIP # LoadBalancer 대신 ClusterIP로 변경
# -----------------------------------------------------------

 

ingress 도 설정한다.

(Ingress는 클러스터 외부에 Pod의 IP 주소나 NodePort를 직접 노출하지 않으면서, 사용자 친화적인 방식으로 서비스에 접근할 수 있게 해줍니다.)

$ vi ingress.yaml
# nginx-ingress.yaml 파일 수정 (또는 새로운 ingress 추가)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-default-ingress
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  # --- 기존 Host 규칙 ---
  - host: nginx.prod.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-vip-service
            port:
              number: 80
~
~
~

 

여기까지 하고 적용하면

$ sudo kubectl apply -k /k8s/system/apps/test-nginx/production
service/nginx-vip-service created
deployment.apps/nginx-deployment configured

 

요렇게 잘 끝났다고 나온다.

그럼 잘 돌아가는지 한 번 볼까?

$ sudo k3s kubectl get svc nginx-vip-service
NAME                TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx-vip-service   LoadBalancer   10.43.229.103   <pending>     80:32558/TCP   2m36s

 

이제 호출해보자

$ curl -H "Host: nginx.prod.local" http://10.34.1.150
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
taehyongi@k3s-node1:/k8s/system/apps/test-nginx/production$

성공했다.

그런데 왜 curl 로 했느냐..

traefik 이라는 솔루션은 Host 기반으로 처리한다고 한다.

가상 컨테이너 구조상 같은 vip 로 여러 서비스가 올라갈텐데 서비스를 구분하기 위해서 

포트를 구분할수도 있을텐데 도메인으로 구분한다는 것이다.

설정을 하면 아이피로도 할수 있는것 같은데 host 가 기본이고 이것이 맞으므로 일단 그대로 둔다.

 

브라우저에서 10.34.1.150 으로 접속하면 not found 에러가 나온다.

Git 으로 설정 관리

참고로 여기까지 하고 이 설정들이 master 노드에 있다면 이 노드인 1번 서버가 죽어버리면 어떻게 되는거지?

하는 의문이 생겼다. 검색해보니.. etcd 라는 내부 저장소에 이것들이 모두 올라간다고 한다.

그럼 실제 노드들끼리는 그 etcd 를 바라본다는 얘기이다.

위에서 만든 yaml 파일을을 kubectl 로 apply 하는 과정은 설치 과정 뿐만 아니라 etcd 에 올리는 과정이 포함되어 있을것이라고 본다.

그럼 이 설정파일들을 잊어버리면 안되므로 git 을 통해 최신화 관리를 하는것이 바람직한 방법으로 보인다.

 

다음으로는 도메인으로 어느 서비스로 갈지 분기하는것을 해보자.

ssl 인증서도 자동 셋팅하고...

반응형

'인프라 > Kubernetes' 카테고리의 다른 글

k3s 에서 dnszi 유동아이피 연동 스케쥴 추가하기  (0) 2025.11.30
pfSense 와 CertManager 연동 오류  (0) 2025.11.29
(실전) k8s 설치부터 https 서비스 포팅까지  (0) 2025.11.23
(연습) k3s HA 구성 트래픽 흐름 구조  (0) 2025.11.21
(연습) k3s 설치하기 (마스터1, 워커2 설치)  (0) 2025.11.17
'인프라/Kubernetes' 카테고리의 다른 글
  • pfSense 와 CertManager 연동 오류
  • (실전) k8s 설치부터 https 서비스 포팅까지
  • (연습) k3s HA 구성 트래픽 흐름 구조
  • (연습) k3s 설치하기 (마스터1, 워커2 설치)
GG.Lab
GG.Lab
GG.Lab
    반응형
  • GG.Lab
    GG.Lab
    GG.Lab
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • APP (25)
        • 함쓰가계부 (22)
        • 랭킹구구단 (3)
      • 인프라 (18)
        • Docker (1)
        • Proxmox (4)
        • Kubernetes (8)
        • Network (3)
        • Cloudflare (2)
      • DB (8)
        • Postgresql (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 함쓰 메뉴얼
    • 함쓰 카페
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자작앱
    k3s
    앱출시
    구구단
    커플가계부
    가계부편의기능
    k3s외부서비스
    부부가계부
    patroni
    함께쓰는가계부
    해외통화가계부
    Kubernetes
    공유가계부
    쿠버네티스
    Proxmox
    연인가계부
    Flutter
    함쓰가계부
    문자자동인식
    해외통화지원
    postgresql이중화
    pfsense
    K8s
    함쓰
    external-svc
    문자자동인식가계부
    traefik
    플러터
    sms인식가계부
    PostgreSQL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
GG.Lab
(연습) k3s VIP 설정 (MetalLB)
상단으로

티스토리툴바