오늘은 어제에 이어서 Service 타입들을 실습했다.
NodePort, LoadBalancer, ExternalName, Ingress까지 다뤘다.
NodePort는 노드의 포트를 외부에 개방하는 서비스 타입이다.
도커 스웜의 포트 퍼블리싱 방식과 비슷한 개념이다.
NodePort를 이해할 때 핵심은 3개의 포트를 구분하는 것이다.
| 포트 | 설명 |
|---|---|
| nodePort | 외부에서 노드로 접근하는 포트 (30000~32767) |
| port | 서비스가 클러스터 내부에서 사용하는 포트 |
| targetPort | 실제 Pod(컨테이너)가 사용하는 포트 |
apiVersion: v1
kind: Service
metadata:
name: svc-dep
spec:
selector:
app: mydep
type: NodePort
ports:
- nodePort: 30001
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydep
spec:
replicas: 1
selector:
matchLabels:
app: mydep
template:
metadata:
labels:
app: mydep
spec:
containers:
- image: public.ecr.aws/docker/library/httpd:alpine
name: dep-con
중요한 포인트가 있다.
kubectl describe svc에서 Endpoints가 none으로 뜬다. 트러블슈팅할 때 꼭 확인하자.AWS로 따지면 NLB와 비슷한 개념이다.
LoadBalancer 타입은 클러스터 관리자의 도움이 필요한 서비스 타입이다.
LB에 붙을 IP는 노드들이 속한 대역(211.183.3.0/24)의 IP인데, 이 IP는 쿠버네티스 클러스터가 관리하지 않기 때문이다.
EKS 같은 클라우드 환경에서는 AWS가 LB를 제공해주지만, 온프레미스 환경에서는 MetalLB를 설치해서 해결한다.
MetalLB를 설치하면 speaker라는 Pod가 뜨는데, LB에 부여된 IP를 외부 네트워크에 알려주는 역할을 한다.
"내가(클러스터) 로드밸런서 생성해서 211.183.3.200이라는 IP를 부여할테니까 너네들(211.183.3.0/24 대역)도 그렇게 알아!"
# MetalLB IP 풀 설정
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
NodePort와 달리 nodePort 필드를 지정하지 않아도 된다. 생성된 LB는 svc의 포트를 따라간다.
호스트네임을 다루는 타입. Service를 DNS 이름에 매핑하는 방식으로, 클러스터 외부의 서비스를 내부에서 DNS 이름으로 접근할 수 있게 해준다.
일반적인 Service(LoadBalancer, NodePort, ClusterIP)는 path 기반 라우팅이 불가능하다.
Service는 한 종류의 label만 품을 수 있기 때문이다.
www.naver.com/board → svc-board
www.naver.com/login → svc-login
하나의 접속 지점을 통해 여러 svc로 라우팅하려면 Ingress가 필요하다.
Ingress를 구성하기 위해서는 Ingress Controller가 반드시 설치되어 있어야 한다.
AWS EKS에서는 이를 LoadBalancer Controller라고 부른다.
쿠버네티스 공식 문서 기반 정리
모든 매니페스트에는 반드시 아래 4가지 항목이 있어야 한다.
| 항목 | 설명 |
|---|---|
apiVersion | 사용할 API 버전 (예: v1, apps/v1) |
kind | 리소스 종류 (Pod, Deployment, Service 등) |
metadata | 이름, 네임스페이스, 레이블 등 |
spec | 실제 리소스 스펙 정의 |
NodePort
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: my-lb-service
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 80
ExternalName
apiVersion: v1
kind: Service
metadata:
name: my-external-service
spec:
type: ExternalName
externalName: my.database.example.com
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: www.example.com
http:
paths:
- path: /board
pathType: Prefix
backend:
service:
name: svc-board
port:
number: 80
- path: /login
pathType: Prefix
backend:
service:
name: svc-login
port:
number: 80
pathType 종류
| 타입 | 설명 |
|---|---|
Prefix | 해당 경로로 시작하는 모든 요청 매칭 |
Exact | 정확히 일치하는 경로만 매칭 |
오늘은 Service 타입들을 실습하면서 NodePort, LoadBalancer, Ingress의 차이를 확실히 이해했다.
특히 사설 레지스트리 이미지를 클러스터에 배포할 때 이미지를 땡겨오는 주체가 containerd라는 걸 직접 트러블슈팅하면서 배운 게 인상 깊었다. Docker 설정만 바꾸면 된다고 생각했는데 containerd 설정도 따로 해줘야 한다는 게 핵심이었다.
이번 velog는 AWS Kiro를 통해 작성하였다. 배운 내용을 Notion에 정리하고 Kiro를 통해 검토받아 작성하였다.