본문 바로가기

IT 엔지니어/CLOUD

K8S - Service

[Service]

  • Cluster IP 10.233.0.0/18
    • SM : 10.233.0.0 - 10.233.63.255
  • Service Pod: 10.233.64.00.00 - 10.233.255.255

서비스 유형

🔹 1. ClusterIP (기본값)

  • 역할: 클러스터 내부에서만 접근 가능한 고정 IP 제공
  • 외부 접근: ❌ (클러스터 내부에서만 사용 가능)
  • 특징 : 동일 레이블 가지는 파드에 대한 단일 지점 가상 IP 주소 제공
    • 서비스 유형 미지정 시 디폴트값 제공
  • 주 용도: 파드 간 통신, 마이크로서비스 구조에서 내부 백엔드 연결
  • 예시: 프론트엔드 → 백엔드, 백엔드 → DB

1-1 . 자동할당

vi cluster.yml

apiVersion: v1
kind: Service
metadata:
  name: mycluster
    
spec:
  selector:
    app: webui
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

 

 

1-2. 고정 할당

> Deployment
vi mydeploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydp
    
spec:
  replicas: 3
 *** selector:
    matchLabels:
      app: webui***
  template:
    metadata:
      name: mypod
      ***labels:
        app: webui***
    spec:
      containers:
      - name: mycon
        image: nginx:1.14
        
 apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      labels:
        app: webui
    spec:
      containers:
      - name: mycon
        image: nginx:1.14
        ports:
        - containerPort: 80

1-2-1. 서비스 생성

vi clusterip.yml

 apiVersion: v1
kind: Service
metadata:
  name: myclusterip
spec:
  type: ClusterIP
  clusterIP: 10.233.10.10
  ***selector:
    app: webui // 동일해야 서비스 연결 가능***
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

 

 

 

Deployment로 생성한 웹 파드 접속 시
해당 서비스 IP로 로드 밸런싱 가능

 

clusterIP 로 로드 밸런싱 확인

 

서비스이름으로도 접속 가능

 

 

[포트 포워딩]

 

ClusterIP는 내부 클러스터에서만 접속 가능하지만 개발/테스트용으로 포트 포워딩 시

외부에서 내부로 접근 가능하다

'

Vmware 포트 포워딩 설정
Vmware 설치한 호스트 PC

 

 

 

🔹 2. NodePort

  • 역할: 클러스터 외부에서 모든 노드의 IP 주소 + 고정 포트를 통해 서비스에 접근 가능
  • 외부 접근: ⭕ (모든 노드의 IP에서 접근 가능)
  • 주 용도: 간단한 외부 노출 테스트, 작은 규모 서비스
  • 기본 포트 범위: 30000~32767
  • 구성 흐름: ClusterIP → NodePort 설정 → 외부에서 접근 가능
http://<NodeIP>:<NodePort>

[NodePort 구성]

vi mynodeport.yml

apiVersion: v1
kind: Service
metadata:
name: my-nodeport

spec:
  type: NodePort
  selector:
    app: webui
  ports:
    - port: 80      # 서비스 내부 포트
      targetPort: 8080  # 파드 컨테이너가 사용하는 포트
      nodePort: 30080   # 노드 외부에서 접근할 수 있는 고정 포트

[ 외부 사용자 ] 
      |
  192.168.10.100:30080 (노드 IP + NodePort)
      ↓
  [ NodePort 서비스 ]
      ↓
  [ app=webui 라벨 가진 파드들 중 하나 ]

 

모든 노드에서 서비스 접근 가능 / nmap -p 30100 192.168.10.100 접근 가능 확인

 

🔹 3. LoadBalancer

  • 역할: 클라우드 제공업체의 로드밸런서를 사용하여 외부에 서비스 노출
  • 외부 접근: ⭕ (공인 IP 제공)
  • 주 용도: 실제 운영 서비스 외부 노출, 클라우드 환경에서 가장 많이 사용
  • 특징:
    • 내부적 ClusterIP + NodePort 동시 생성
    • 퍼블릭 클라우드(GCP, AWS, Azure 등)에서만 동작 (on-prem에서는 MetalLB 등 필요)

3-1. Service 생성

vi loadbalacner.yml

apiVersion: v1
kind: Service
metadata:
name: myloadbalance

spec:
	type: LoadBalancer
	clusterIP: 10.233.10.100
	selector:
		app: webui
	ports:
	- protocol: TCP
		port: 80
		targetPort: 80
		nodePort: 32000

 

3-2. HA Proxy

dnf -y install haproxy
vi /etc/hosts

vi /etc/haproxy/harpoxy.cfg

파일 수정

67 frontend main
68				bind *: 80 // 80으로 변경
#    acl url_static  path_beg   -i /static /images /javascript /stylesheets
#    acl url_static  path_end   -i .jpg .gif .png .css .js
#    use_backend static  if url_static  // 주석 처리 3줄

				
 85 backend app
 86     balance     roundrobin
 87     server  app1 191.168.10.100:32000 check
 88     server  app2 191.168.10.150:32000 check
 89     server  app3 191.168.10.200:32000 check
/// 각 노드로 수정 
				
				systemctl restart haproxy

 

HA Proxy 주소 접근 -> 노드 IP 주소+ nodeport로 접근

 

서비스 로드밸런서 IP 주소로 접근 / 서비스 이름으로 접근 가능

 

 

http://<External LoadBalancer IP> 접근

 

🔹 4. Headless

  • 역할 : 단일 진입점 없이 모든 파드 접근 가능
  • 일반 서비스와 달리 ClusterIP를 생성하지 않고, 대신 DNS를 통해 각 파드의 IP를 직접 반환하는 서비스
  • 파드 개별 접근이 가능하도록 로드밸런싱 없이 파드 목록을 직접 노출

🔸 역할

상황 설명

StatefulSet과 함께 사용 DB나 캐시처럼 각 인스턴스가 고유해야 할 때 사용 (예: MongoDB, Cassandra, Kafka 등)
파드 직접 접근 필요 로드밸런싱 없이 파드 하나하나에 직접 접근해서 다르게 동작시켜야 할 때
spec:
  clusterIP: None

기본적으로 Kubernetes에서

파드는 직접 접근 대상이 아니다

  • 파드는 생성/삭제/재시작 자동 수행 → IP 상시 변경
  • **Service(서비스)**를 통해 접근 가능
  • → "단일 진입점" (ex: ClusterIP)

✅ Headless Service는?

spec:
  clusterIP: None  # 단일 진입점이 없다!

→ 이건 서비스가 로드밸런싱을 안 해주고,

DNS 질의 결과로 파드의 "실제 IP들"을 모두 응답

 

my-headless-service.default.svc.cluster.local 로 접근하면

→ "서비스 IP" 하나가 아니라

→ pod-a, pod-b, pod-c 각각의 IP 확인 가능


🎯 정리하자면

항목 일반 Service Headless Service

DNS 응답 ClusterIP 하나 각 파드의 IP 목록
접근 방식 로드밸런싱된 하나의 진입점 파드에 직접 접근
의미 서비스 이름으로 요청 시 어느 파드가 응답할지 모름 서비스 이름으로 요청하면 원하는 파드에 직접 연결 가능

💡 그럼 "누가 파드에 접근하냐"면?

  • 다른 파드나 컨테이너가 접근하는 것.
  • 예를 들어:
    • 데이터베이스 클러스터 구성 시,
    • cassandra-1이 cassandra-0에 직접 붙어야 한다면 → DNS로 직접 IP를 알아야 함.
    • 상태 있는 앱에서 파드 간 통신 시 → “어느 노드에게 붙을지” 지정해야 함.

  • 일반 서비스는 “콜센터 대표번호” , 누가 받을지 몰라.
  • Headless는 “직통 번호” 같아서, 특정 파드 확인 가능

✅ 왜 Headless Service는 StatefulSet과 함께 쓰일까?

StatefulSet은 파드에 고유한 이름과 고정된 네트워크 ID를 부여

상태가 있는 애플리케이션(예: DB, Kafka 등)에 적합

일반 Service는 로드밸런싱해서 파드 중 아무나 연결

→ 이건 상태 있는 애플리케이션에 비적합

각 파드 직접 연결 가능Headless Service 필요


🔷 Cassandra 클러스터 배포

1. Headless Service 정의

apiVersion: v1
kind: Service
metadata:
  ***name: cassandra***
spec:
  ***clusterIP: None***  # ✅ 핵심!
  selector:
    app: cassandra
  ports:
    - port: 9042

2. StatefulSet 정의 (일부만)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
spec:
  ***serviceName: cassandra***  # ✅ Headless Service 이름과 같아야 함
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      containers:
        - name: cassandra
          image: cassandra:latest


📌 파드 DNS 이름 어떻게 될까?

StatefulSet은 파드명 순차적 생성

cassandra-0.cassandra.default.svc.cluster.local
cassandra-1.cassandra.default.svc.cluster.local
cassandra-2.cassandra.default.svc.cluster.local

파드이름.서비스이름.네임스페이스.svc.cluster.local

→ 이 DNS 이름을 통해 각 파드에 직접 연결 가능


🎯 정리

항목 설명

Headless Service 파드 각각에 직접 연결할 수 있도록 도와주는 서비스
StatefulSet 이름이 고정된 파드 생성 (예: pod-0, pod-1...)
같이 쓰는 이유 파드마다 상태(데이터 등)를 유지하고, 고정된 네트워크 주소로 접근해야 하기 때문
  • Headless Service는 "서비스 이름으로 요청하면 로드밸런서 거치지 않고 파드 IP를 직접 알려준다."
  • 그래서 파드 하나하나에 "정확히" 붙을 수 있는 구조가

 

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydp

spec:
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      name: test
      labels: 
	      app: webui
    spec:
      containers:
      - name: mycon
        image: nginx:1.14

---
apiVersion: v1
kind: Service
metadata:
  name: myhead

spec:
  type: ClusterIP
  clusterIP: None
  selector:
    app: webui
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

nslookup myhead.default.svc.cluster.local

 

nslookup으로 클러스터 IP 주소 확인

 

dig myhead.default.svc.cluster.local

 

Deployment의 주소

 

 

🔹 5. ExternalName

  • 역할: 서비스 이름을 외부 DNS 이름으로 매핑
  • 외부 접근: ❌ (내부에서 외부 서비스로 접근)
  • 주 용도: 외부 데이터베이스나 외부 API 서버를 DNS 이름으로 접근
  • 접근 가능한 FQDN를 CNAME으로 매핑
  • 특징:
    • 파드에서
    • ex-name.namespace.svc.cluster.local 형태로 접근
    • 자동으로 외부 도메인으로 리디렉션
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.external.com

 

www.google.com

 

kubectl run mypod -it --image ubuntu
apt-get update

apt-get -y install dnsutils
dlg myex.default.svc.cluster.local

apt-get -y install iputils-ping 
ping myex.default.svc.cluster.local

 

www.google.com으로 리다이렉션

 

  • ExternalName 서비스는 클러스터 내부에서 myex.default.svc.cluster.local 을 사용하면, 내부적으로 CNAME DNS를 통해 외부 도메인(여기선 www.google.com)으로 리다이렉션.
  • 실제로 포트 포워딩은 안 되고, 단지 DNS 이름을 외부 도메인으로 매핑하는 역할만 합니다.
  • 즉, 이건 단순한 도메인 이름 연결 트릭이지, TCP 로드밸런싱 같은 건 해주지 않습니다.

🔹 6. KUBE-proxy

  • ClusterIP , NodePort로 접근 가능
  1. userspace proxy mode
  2. iptables proxy mode
  3. IPVS(IP Virtual Server) proxy mode
userspace mode
> 클라이언트의 서비스 요청을 iptables 통해 
kube proxy가 수신 후 연결 모드

iptables mode 
> Default Kubernetes Network Mode

IPSV mode
> kubespray 설치 시 사용하는 모드
kubectl get ds -A 
daemonset 

get ds -A -o wide | head -1 ; kubectl get pod -A -o wide | grep kube-proxy

 

 

'IT 엔지니어 > CLOUD' 카테고리의 다른 글

Labels/ Annotations  (1) 2025.06.01
K8S - ingress  (0) 2025.05.31
K8S - STATEFULSET  (0) 2025.05.29
k8S - REPLICASET  (0) 2025.05.28
K8S- daemonset  (0) 2025.05.27