본문 바로가기

IT 엔지니어/CLOUD

K8S - Load Balance

✅ 핵심 요약

kubectl port-forward는 "Pod 전체"에 대해 동작하고,

Pod 안에 있는 특정 컨테이너를 직접 선택해서 포워딩하지는 않습니다.

즉, Pod 안의 여러 컨테이너가 각각 다른 포트를 사용하면,

그 포트들로 Pod 전체에 포트 포워딩을 할 수 있어요.

어떤 컨테이너가 그 포트를 리슨 중인지에 따라 응답이 달라지는 거죠.


🛠 예시: 외부에서 각각 접근

mypod 안에 다음과 같은 구조가 있다고 가정할게요:

  • mycon2 → 81번 포트에서 Nginx 실행
  • mycon3 → 82번 포트에서 Nginx 실행

그리고 kubectl port-forward를 다음처럼 실행합니다:

kubectl port-forward pod/mypod 8081:81 8082:82

  • 외부의 localhost:8081 → Pod 내부의 81번 포트로 연결 (즉, mycon2)
  • 외부의 localhost:8082 → Pod 내부의 82번 포트로 연결 (즉, mycon3)

📌 주의할 점

  • 포트 포워딩은 로컬 PC에서만 접근 가능합니다. 즉, kubectl port-forward를 실행한 그 PC에서만 유효합니다.
  • Pod 내부에서 실행 중인 각 Nginx 인스턴스는 반드시 daemon off; 명령을 통해 foreground로 실행되어야 합니다
  • 각각의 Nginx 설정에서 listen 81;, listen 82;가 정확히 되어 있어야 합니

🔄 로드밸런싱 테스트

Deployment + Service 조합


🔧 1. Nginx Deployment (3개의 Pod 생성)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80


🌐 2. ClusterIP 타입의 Service (내부 통신 테스트용)

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

또는 NodePort로 외부에서 접근하고 싶다면 아래처럼 바꾸면 돼:

type: NodePort
ports:
- port: 80
  targetPort: 80
  nodePort: 30080  # 포트는 네트워크 여유에 따라 조정


🔍 3. 로드밸런싱 확인 방법

# 반복적으로 호출해보기
curl <노드IP>:30080

Pod마다 HTML 내용이나 hostname 다르게 넣는 방법


✍ Pod마다 다르게 응답하게 만들기 (선택)

Dockerfile 만들기:

FROM nginx
RUN echo "Hello from NGINX $(hostname)" > /usr/share/nginx/html/index.html

이렇게 하면 각 Pod가 다른 hostname을 띄우니 curl 요청마다 다른 응답이 보여 → 부하분산 확인 가능! 😄




이 YAML 파일에서 정의된 두 개의 Pod(mypod3와 mypod4)는 부하 분산을 구현하지 않습니다.

 단순히 두 개의 Pod가 각각 동일한 nginx 이미지를 사용하는 것뿐

이 두 Pod를 연결하는 **서비스(Service)**가 없기 때문

 

부하 분산을 하려면, Service를 사용하여 여러 Pod를 하나의 네트워크 엔드포인트로 묶어야 합니다.

서비스는 클러스터 내에서 여러 Pod를 자동으로 라운드로빈 방식으로 분산시켜줍니다.

apiVersion: v1
kind: Namespace
metadata:
  name: myns2
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod3
  namespace : myns2
spec:
  containers:
  - image: nginx
    name: mycon
    ports:
      - containerPort: 80
        protocol: TCP
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod4
  namespace : myns2
spec:
  containers:
  - image: nginx
    name: mycon
    ports:
      - containerPort: 80
        protocol: TCP

 

별도 서비스 생성

부하분산을 구현하는 방법:

  1. Service 생성:
apiVersion: v1
kind: Service
metadata:
  name: mynginx-service
  namespace: myns2
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  1. Pod에 라벨 추가:

Pod에 app: nginx 라벨을 추가하여 서비스와 연동될 수 있도록 해야 합니다.

apiVersion: v1
kind: Pod
metadata:
  name: mypod3
  namespace: myns2
  labels:
    app: nginx
spec:
  containers:
  - image: nginx
    name: mycon
    ports:
      - containerPort: 80
        protocol: TCP
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod4
  namespace: myns2
  labels:
    app: nginx
spec:
  containers:
  - image: nginx
    name: mycon
    ports:
      - containerPort: 80
        protocol: TCP

설명:

  • Service는 app: nginx 라벨을 가진 모든 Pod를 선택하여, 외부에서 하나의 IP와 포트로 접근할 수 있게 해줍니다.
  • 서비스는 클러스터 내부에서 해당 Pod들로 트래픽을 분산시킵니다.

결과:

이렇게 하면, mypod3와 mypod4에 대한 트래픽이 mynginx-service를 통해 부하 분산됩니다. 이 서비스의 IP와 포트(예: mynginx-service:80)를 통해 두 Pod로 트래픽이 분배됩니다.

추가적으로 kubectl expose 명령어를 사용하여 서비스로 외부 접근을 설정할 수도 있습니다.

파드 내로 접속하는 방법

  1. 파드 이름 확인
    kubectl get pods
    
    
  2. 먼저, kubectl get pods 명령으로 파드 목록을 확인합니다. 여기서 접속하려는 파드의 이름을 확인합니다.
  3. kubectl exec 명령을 사용하여 파드 내로 접속
    kubectl exec -it mypod -- /bin/bash
    
    
    • it: 인터랙티브 모드로 접속하도록 지정.
    • mypod: 접속할 파드의 이름.
    • /bin/bash: bash 셸을 사용하여 접속.
    이 명령은 해당 파드의 첫 번째 컨테이너에 접속합니다. 만약 여러 개의 컨테이너가 있는 파드라면, -c 옵션을 사용하여 특정 컨테이너에 접속할 수 있습니다:
  4. kubectl exec -it mypod -c mycon1 -- /bin/bash
  5. 접속할 파드 이름을 확인한 후, kubectl exec 명령을 사용하여 파드 내로 접속할 수 있습니다. 예를 들어, mypod라는 이름의 파드에 접속하려면 다음과 같이 명령을 실행합니다:
  6. 파일 수정 및 명령 실행
    echo "Hello from NGINX $(hostname)" > /usr/share/nginx/html/index.html
    
    
  7. 파드에 접속한 후, 컨테이너 내에서 원하는 파일을 수정하거나 필요한 명령을 실행할 수 있습니다. 예를 들어, index.html 파일을 수정하려면 다음과 같이 할 수 있습니다:

각 Pod에 대해 고유한 ECHO 메시지를 설정하는 방법

각 Pod의 nginx 설정 파일을 수정

각 Pod가 반환하는 내용에 구분 방법

  • nginx.conf 파일 수정
  • ECHO를 각각의 Pod가 다르게 출력
server {
    listen 80;
    server_name localhost;

    location / {
        return 200 "This is Pod: ${HOSTNAME}\\n";
    }
}

위 설정에서 ${HOSTNAME}은 각 Pod의 이름을 출력합니다. Kubernetes에서 HOSTNAME은 해당 Pod의 이름으로 자동 설정됩니다. 따라서, 이 설정을 각 Pod에 적용하면, 클라이언트는 각 Pod의 이름을 출력하는 메시지를 볼 수 있습니다.

  • Pod를 위한 ConfigMap 생성
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-config
      namespace: myns2
    data:
      nginx.conf: |
        server {
            listen 80;
            server_name localhost;
    
            location / {
                return 200 "This is Pod: ${HOSTNAME}\\n";
            }
        }
    
    
  • nginx.conf 파일을 ConfigMap으로 생성하여 Pod에서 참조하게 할 수 있습니다.
  • Pod에서 ConfigMap 사용하기
    yaml
    코드 복사
    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod3
      namespace: myns2
    spec:
      containers:
        - name: mycon
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - name: nginx-conf
              mountPath: /etc/nginx/nginx.conf
              subPath: nginx.conf
      volumes:
        - name: nginx-conf
          configMap:
            name: nginx-config
    
    
  • Pod에 nginx.conf를 ConfigMap으로 마운트하여 nginx가 이를 읽고 사용하도록 설정합니다.

1. Dockerfile에서 hostname을 포함한 메시지 작성 (단 한번만 설정)

이 방법은 컨테이너를 실행할 때 hostname을 동적으로 반영할 수 없습니다. 이미지를 빌드할 때 hostname이 고정됩니다.


FROM nginx
RUN echo "Hello from NGINX $(hostname)" > /usr/share/nginx/html/index.html

이 방법은 nginx 서버가 시작될 때마다 변경된 호스트 이름을 반영할 수 없습니다.

대신, 컨테이너가 시작될 때마다 실행되는 스크립트를 사용해야 합니다.

2. 컨테이너가 실행될 때마다 hostname을 동적으로 반영하려면

컨테이너가 시작될 때마다 nginx의 index.html 파일을 동적으로 갱신하려면, entrypoint나 CMD를 사용하여 시작 시 스크립트를 실행해야 합니다. 이를 통해 실행 시마다 hostname을 반영하도록 할 수 있습니다.

예시) Dockerfile (동적으로 hostname을 반영하는 방법)

FROM nginx

# /etc/nginx/conf.d/default.conf 또는 다른 설정 파일을 수정할 수 있음
COPY ./default.conf /etc/nginx/conf.d/default.conf

# entrypoint를 사용해 컨테이너가 실행될 때마다 index.html을 동적으로 변경
ENTRYPOINT ["/bin/sh", "-c", "echo 'Hello from NGINX $(hostname)' > /usr/share/nginx/html/index.html && exec nginx -g 'daemon off;'"]

3. 설명

  • ENTRYPOINT를 사용하여 컨테이너가 시작될 때마다 hostname을 동적으로 index.html에 반영하게 합니다.
  • exec nginx -g 'daemon off;' 명령은 nginx를 포그라운드 모드로 실행하여 계속 작동하도록 합니다.

4. 추가 옵션: Nginx를 위한 환경 변수 활용

만약 nginx를 설정 파일을 통해 동적으로 수정하고 싶다면, 환경 변수를 사용하여 설정 파일에서 hostname을 반영할 수 있습니다. 예를 들어 nginx.conf에서 환경 변수를 참조하는 방법입니다.

FROM nginx

# 동적으로 환경 변수를 삽입하기 위해 envsubst 사용
RUN apt-get update && apt-get install -y gettext-base

# 환경 변수로 'hostname'을 사용하여 NGINX 설정 파일 동적 처리
COPY ./default.conf.template /etc/nginx/conf.d/default.conf.template

ENTRYPOINT ["/bin/sh", "-c", "envsubst < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"]

그리고 default.conf.template 파일을 다음과 같이 작성할 수 있습니다:


server {
    listen 80;

    location / {
        root   /usr/share/nginx/html;
        index  index.html;

        # 환경 변수로 호스트명을 삽입
        add_header X-Hostname ${HOSTNAME};
    }
}

envsubst 명령은 환경 변수를 사용하여 템플릿 파일을 처리하고, 결과를 실제 nginx 설정 파일로 적용합니다.

이 방법은 컨테이너가 실행될 때마다 hostname을 자동으로 반영하게 합니다.

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

K8S Controller  (0) 2025.05.26
초기화/인프라 컨테이너  (0) 2025.05.25
K8S 실습  (1) 2025.05.23
K8S POD 생성  (0) 2025.05.22
DOCKER NAMESPACE/STATEFULSET  (0) 2025.05.22