Kubernetes 환경 TCP 및 UDP 서비스 포트 노출 방법 종합 가이드
Ingress-NGINX를 사용한 TCP 및 UDP 서비스 노출
Kubernetes의 Ingress 리소스는 기본적으로 외부 HTTP(S) 트래픽을 내부 서비스로 라우팅하는 데 사용됩니다. 그러나 Ingress-NGINX는 이를 확장하여 HTTP가 아닌 TCP/UDP 프로토콜을 통해서도 외부 트래픽을 내부 서비스로 라우팅할 수 있습니다. 이를 위해 ConfigMap을 사용하여 특정 포트에 대해 TCP/UDP 포트 매핑을 설정할 수 있습니다.
1. TCP/UDP 서비스 노출을 위한 기본 구성
ConfigMap을 사용하여 TCP/UDP 서비스를 노출할 수 있습니다. 이때 ConfigMap의 키는 외부에서 사용할 포트 번호이고, 값은 내부 서비스로의 라우팅 정보를 나타냅니다. 포맷은 다음과 같습니다:
<external-port>:<namespace/service-name>:<service-port>:[PROXY]:[PROXY]
<external-port>
: 외부에서 노출할 포트 번호<namespace/service-name>
: 서비스가 위치한 네임스페이스와 서비스 이름<service-port>
: 내부 서비스에서 사용할 포트 번호[PROXY]
: 선택적으로 Proxy Protocol을 디코딩 및 인코딩할 수 있습니다. 첫 번째PROXY
는 디코딩을, 두 번째PROXY
는 인코딩을 제어합니다.
예시 1: TCP 서비스 노출
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
namespace: ingress-nginx
data:
9000: "default/example-go:8080"
위 설정은 default
네임스페이스의 example-go
서비스를 외부 포트 9000
에서 8080
포트로 라우팅합니다.
예시 2: UDP 서비스 노출
apiVersion: v1
kind: ConfigMap
metadata:
name: udp-services
namespace: ingress-nginx
data:
53: "kube-system/kube-dns:53"
이 설정은 kube-system
네임스페이스의 kube-dns
서비스를 외부 포트 53
에서 53
포트로 라우팅합니다.
2. Ingress-NGINX 컨트롤러 설정
TCP/UDP 서비스를 사용하려면 Ingress-NGINX 컨트롤러에 --tcp-services-configmap
및 --udp-services-configmap
플래그를 추가하여 올바른 ConfigMap을 참조하도록 설정해야 합니다.
Ingress-NGINX 컨트롤러의 설정 업데이트 (Helm 또는 수동 방식)
args:
- /nginx-ingress-controller
- --tcp-services-configmap=ingress-nginx/tcp-services
- --udp-services-configmap=ingress-nginx/udp-services
이렇게 설정하면 Ingress-NGINX 컨트롤러가 해당 ConfigMap을 참조하여 TCP/UDP 트래픽을 처리합니다.
3. NGINX 서버에 포트 추가
NGINX가 TCP/UDP 포트를 처리할 수 있도록 NGINX 서버 설정에 해당 포트를 추가해야 합니다. 이를 위해 nginx-configuration
ConfigMap 또는 NGINX 설정 파일을 사용하여 포트를 정의합니다.
예시: 포트 추가
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
- name: https
port: 443
targetPort: 443
protocol: TCP
- name: proxied-tcp-9000
port: 9000
targetPort: 9000
protocol: TCP
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
위 설정은 9000
포트를 NGINX 서버에서 리스닝하도록 추가합니다.
4. ConfigMap 변경 시 반영
ConfigMap을 변경하면 Ingress-NGINX 컨트롤러가 자동으로 변경 사항을 감지하고 새로운 설정을 적용합니다. 다만, 경우에 따라 변경 사항이 즉시 반영되지 않는다면 컨트롤러를 재시작하여 반영할 수 있습니다.
5. 종합적으로 설정 및 확인 사항
- ConfigMap 설정: TCP/UDP 서비스에 대해 올바르게 설정되었는지 확인합니다.
- Ingress-NGINX 컨트롤러 설정:
--tcp-services-configmap
및--udp-services-configmap
플래그가 올바르게 추가되었는지 확인합니다. - NGINX 서버 포트 설정: NGINX 서버가 올바른 포트를 리스닝하도록 설정되었는지 확인합니다.
- 포트 열림 확인: 설정한 포트가 호스트 노드에서 열렸는지 확인합니다 (
netstat
등 사용). - 설정 반영 확인: ConfigMap 변경 사항이 반영되었는지 로그를 통해 확인하고 필요 시 컨트롤러를 재시작합니다.
위 가이드를 통해 Ingress-NGINX를 사용하여 Kubernetes에서 TCP/UDP 서비스를 안정적으로 노출할 수 있습니다. Minikube에서 Ingress-NGINX를 사용하여 TCP 포트를 노출하기 위해 ConfigMap을 올바르게 설정했는데도 호스트 노드에서 해당 포트가 열리지 않는 경우, 몇 가지 추가적인 설정과 확인이 필요할 수 있습니다.
1. Ingress Controller 설정 확인
Ingress-NGINX가 TCP/UDP 포트를 올바르게 처리하도록 하기 위해서는 Ingress Controller에 해당 ConfigMap을 참조하도록 설정해야 합니다. 기본적으로 Ingress-NGINX는 TCP/UDP 포트를 처리하지 않으므로, 해당 설정을 추가해야 합니다.
Ingress-NGINX 설치 시, Helm Chart를 사용하는 경우 다음과 같은 추가 설정을 통해 TCP/UDP 서비스를 활성화할 수 있습니다.
2. Helm Chart를 사용한 Ingress-NGINX 설정 (TCP/UDP 지원)
Ingress-NGINX를 설치할 때 Helm Chart를 사용하는 경우, 다음과 같이 tcp-services-configmap
값을 추가하여 TCP 포트를 노출할 수 있습니다.
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx \
--set controller.extraArgs.tcp-services-configmap="ingress-nginx/tcp-services"
이 명령어는 Ingress Controller에 TCP 서비스용 ConfigMap을 참조하도록 설정합니다. tcp-services-configmap
은 TCP 서비스에 대한 설정을 지정하는 옵션입니다.
3. ConfigMap 재확인
ConfigMap이 올바르게 생성되었는지 확인하세요:
kubectl get configmap tcp-services -n ingress-nginx -o yaml
이 명령어로 ConfigMap의 내용이 정확한지 확인할 수 있습니다.
4. Pod 로그 확인
Ingress-NGINX 컨트롤러의 로그를 확인하여 TCP 포트가 제대로 설정되었는지 확인해보세요:
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
로그에서 TCP/UDP 서비스가 로드되었는지 확인할 수 있습니다. 오류가 발생했다면 그 원인을 파악할 수 있습니다.
5. NodePort 사용을 고려
혹시라도 Ingress-NGINX 설정에서 문제가 있는 경우, NodePort를 사용하여 특정 포트를 노출하는 방법을 고려해볼 수 있습니다. (자세한 내용 아래에 설명)
6. 직접 포트 확인
Minikube VM 내부에서 포트가 제대로 열렸는지 확인하기 위해 Minikube VM에 접속하여 포트 상태를 확인할 수 있습니다:
minikube ssh
sudo netstat -tuln | grep 9000
이 명령어로 Minikube VM 내에서 포트가 제대로 열려 있는지 확인할 수 있습니다.
7. 기타 네트워크 정책 확인
만약 네트워크 정책(NetworkPolicy)이나 방화벽 설정이 있어서 포트 접근이 제한될 수 있습니다. 이러한 설정도 확인해보세요. 위의 과정을 통해 설정을 다시 점검하고 문제를 해결할 수 있습니다. 필요한 경우, Minikube를 재시작하여 설정을 재적용해보는 것도 도움이 될 수 있습니다.
Kubernetes에서 NodePort는 여러 워커 노드가 있을 때, 각각의 노드에서 특정 포트를 리스닝하고 그 포트가 외부에 노출되는 방식을 의미합니다. NodePort 서비스는 클러스터 외부의 트래픽을 클러스터 내부의 서비스로 라우팅할 수 있도록 합니다.
NodePort의 동작 방식
- NodePort 서비스 생성
- NodePort 서비스를 생성하면 Kubernetes는 각 노드의 특정 포트를 열어줍니다. 이 포트는
30000
에서32767
사이의 포트 번호로 지정됩니다.
- NodePort 서비스를 생성하면 Kubernetes는 각 노드의 특정 포트를 열어줍니다. 이 포트는
- 포트 리스닝
- 클러스터의 각 노드는 지정된 NodePort를 리스닝하게 됩니다. 예를 들어, NodePort가
31000
으로 설정되었다면, 클러스터 내 모든 노드가31000
포트를 리스닝하게 됩니다.
- 클러스터의 각 노드는 지정된 NodePort를 리스닝하게 됩니다. 예를 들어, NodePort가
- 외부 트래픽 수신
- 외부 트래픽이 노드의 NodePort로 들어오면, Kubernetes는 해당 트래픽을 내부 클러스터의 해당 서비스로 라우팅합니다.
- 서비스로 라우팅
- NodePort로 들어온 트래픽은 해당 서비스의 클러스터 IP로 전달되고, 서비스는 적절한 파드로 트래픽을 분배합니다.
예를 들어, 다음과 같이 NodePort 서비스를 정의할 수 있습니다.
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 31000
이 경우, 클러스터 내 모든 노드는 31000
포트를 리스닝하게 되고, 해당 포트로 들어오는 트래픽은 my-app
레이블을 가진 파드의 8080
포트로 전달됩니다.
NodePort를 사용할 때 몇 가지 보안 사항을 고려해야 합니다.
- 노출된 포트 보호: NodePort 포트는 외부에 노출되므로, 방화벽 규칙을 통해 접근을 제한하는 것이 중요합니다.
- 인증 및 인가: 노출된 서비스에 대한 인증 및 인가를 설정하여 불필요한 접근을 방지합니다.
- 모니터링: 외부에서의 접근을 모니터링하고, 이상 트래픽이 감지되면 신속히 대응할 수 있도록 합니다.
이러한 방식으로 NodePort를 이해하고 활용할 수 있습니다. NodePort와 ClusterIP의 차이점과 접근 방식은 다음과 같이 이해할 수 있습니다.
NodePort
- 노출 방식: 각 워커 노드의 지정된 포트를 외부에 노출합니다. 예를 들어,
31000
포트로 설정된 NodePort 서비스를 사용하면 클러스터의 모든 노드에서31000
포트로 접근할 수 있습니다. - 접근 방식: 외부 클라이언트는 클러스터 노드의 IP와 NodePort를 통해 직접 접근할 수 있습니다.
- 주요 사용 사례: 클러스터 외부에서 클러스터 내부의 서비스를 직접 접근해야 할 때 사용됩니다. 로드 밸런서를 사용하지 않는 경우에 유용합니다.
ClusterIP
- 노출 방식: 클러스터 내에서만 접근 가능한 내부 IP 주소를 할당합니다. 외부에서 직접 접근할 수 없습니다.
- 접근 방식: 클러스터 내부의 다른 파드나 서비스에서만 접근 가능합니다. 외부 트래픽을 처리하려면 Ingress나 LoadBalancer와 같은 다른 리소스를 사용해야 합니다.
- 주요 사용 사례: 클러스터 내부의 마이크로서비스들 간의 통신에 사용됩니다. 외부에서 직접 접근할 필요가 없는 경우에 적합합니다.
Ingress
- 역할: 클러스터 외부에서 클러스터 내부의 서비스로 HTTP/HTTPS 트래픽을 라우팅하는 역할을 합니다. Ingress는 클러스터 내부의 여러 서비스에 대해 단일 진입점을 제공합니다.
- 구성 요소: Ingress 리소스는 특정 경로 또는 도메인에 대한 트래픽을 특정 서비스로 라우팅합니다.
- 보안: TLS 설정을 통해 HTTPS 트래픽을 처리할 수 있으며, 호스트 및 경로 기반 라우팅을 지원하여 다양한 서비스에 대한 접근을 세밀하게 제어할 수 있습니다.
정리하면
- NodePort: 외부 클라이언트가 클러스터의 특정 노드와 포트로 직접 접근할 수 있도록 노출합니다. 외부 접근이 필요할 때 유용하지만 보안상의 고려가 필요합니다.
- ClusterIP: 클러스터 내부에서만 접근할 수 있는 서비스입니다. 외부 접근이 불가능하며 내부 마이크로서비스 간의 통신에 적합합니다.
- Ingress: 외부에서 클러스터 내부의 서비스로 트래픽을 라우팅하는 방법으로, 도메인 및 경로 기반의 트래픽 관리를 제공합니다. HTTPS를 통해 보안 트래픽을 처리할 수 있습니다.
예시 구성
ClusterIP 서비스 예시
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
Ingress 리소스 예시
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-clusterip-service
port:
number: 80
이렇게 구성하면 외부 클라이언트는 my-app.example.com
을 통해 Ingress를 거쳐 ClusterIP 서비스에 접근하게 됩니다. Kubernetes에서 서비스 포트로 내부에서 접근할 때 사용하는 호스트네임은 다음과 같은 형식을 따릅니다.
<service_name>.<namespace>.svc.cluster.local
- Service Name: 서비스의 이름
- Namespace: 서비스가 속한 네임스페이스
- svc: 서비스 도메인을 나타내는 부분
- cluster.local: 기본 클러스터 도메인 (이는 클러스터 설정에 따라 다를 수 있습니다)
예를 들어, 네임스페이스가 default
이고 서비스 이름이 my-service
인 경우
- 전체 FQDN (Fully Qualified Domain Name)은
my-service.default.svc.cluster.local
이 됩니다. - 동일 네임스페이스에서 접근할 경우,
my-service
로도 접근할 수 있습니다.
파드 접근 호스트네임
파드에 직접 접근할 때는 다음과 같은 형식을 사용합니다. <pod_name>.<namespace>.svc.cluster.local
하지만 일반적으로 파드 이름을 사용하여 직접 접근하기보다는 서비스 이름을 사용하는 것이 더 일반적입니다. 서비스는 파드의 복수 개체를 로드 밸런싱하고, 파드의 수명 주기 동안 이름이 변하지 않기 때문입니다.
서비스 예시
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
이 서비스를 통해 접근하려면
- 동일 네임스페이스에서:
http://my-service
- 다른 네임스페이스에서:
http://my-service.default
- 전체 FQDN으로:
http://my-service.default.svc.cluster.local
파드 예시
apiVersion: v1
kind: Pod
metadata:
name: my-pod
namespace: default
spec:
containers:
- name: my-container
image: my-image
파드에 직접 접근하려면
my-pod.default.svc.cluster.local
하지만 일반적으로 서비스명을 통해 접근하는 것이 권장됩니다.
참고 사항
- DNS Resolution: Kubernetes 클러스터 내에서 DNS를 통해 이러한 호스트네임을 자동으로 해석합니다.
- Headless Service: Headless Service (
ClusterIP: None
)를 사용하면 파드에 직접 접근하는 방식도 가능합니다. 이 경우, 각 파드는 자신만의 DNS 레코드를 가집니다.
이와 같이 Kubernetes에서는 서비스와 파드 접근을 위한 네이밍 규칙이 정해져 있으며, 이를 통해 내부 네트워크에서 쉽게 접근할 수 있습니다. Kubernetes에서 서로 다른 네임스페이스는 기본적으로 논리적으로 격리되어 있지만, 네트워크 격리는 기본 설정이 아닙니다. 따라서 기본적으로는 다음과 같은 점을 고려해야 합니다.
네임스페이스 간 통신
- 서비스 이름을 통한 접근
- 네임스페이스 간에 서비스 이름으로 접근할 때는 완전한 도메인 이름을 사용해야 합니다. 예를 들어,
my-service.default.svc.cluster.local
형식입니다. - 네임스페이스 간 통신을 제한하고 싶다면 네트워크 정책을 통해 제어해야 합니다.
- 네임스페이스 간에 서비스 이름으로 접근할 때는 완전한 도메인 이름을 사용해야 합니다. 예를 들어,
- 파드 IP를 통한 직접 접근
- 기본적으로 동일한 클러스터 내에서는 네임스페이스와 상관없이 파드의 IP 주소를 통해 직접 통신이 가능합니다.
- 이는 네트워크 플러그인(CNI, 예: Calico, Weave, Flannel 등)에 따라 달라질 수 있습니다. 기본적인 Kubernetes 네트워크 모델은 네임스페이스 간의 통신을 제한하지 않습니다.
네임스페이스 간 통신 제한 방법
네트워크 정책(Network Policy)을 사용하면 네임스페이스 간의 통신을 제어하고 제한할 수 있습니다. 이를 통해 특정 네임스페이스 또는 파드 간의 통신을 허용하거나 차단할 수 있습니다.
네트워크 정책 예시
default
네임스페이스의 모든 인바운드 트래픽을 차단하고 특정 네임스페이스에서 오는 트래픽만 허용하는 정책은 다음과 같이 작성할 수 있습니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-except-from-allowed-ns
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: allowed-namespace
위 정책은 allowed-namespace
네임스페이스에서 오는 트래픽만 default
네임스페이스의 파드에 접근할 수 있도록 합니다.
네트워크 정책 적용 예시
다음은 모든 인바운드 트래픽을 기본적으로 차단하는 정책입니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
이 정책은 default
네임스페이스의 모든 파드에 대해 인바운드 트래픽을 차단합니다.
요약해보면,
- 기본 설정에서는 네임스페이스 간의 IP 기반 통신이 가능합니다.
- 네임스페이스 간의 통신을 제한하려면 네트워크 정책을 사용해야 합니다.
- 서비스 이름을 통한 접근은 네임스페이스를 명시해야 하며, 기본적으로 네임스페이스 간의 논리적 격리는 네트워크 정책을 통해 보완할 수 있습니다.
이와 같은 방식을 통해 네임스페이스 간 통신을 보다 세밀하게 제어할 수 있습니다.
네트워크 정책(Network Policy)을 사용하면 네임스페이스 간의 통신을 포함하여 IP를 통한 직접 접근도 제한할 수 있습니다. 네트워크 정책은 Kubernetes 클러스터 내의 파드 간 트래픽을 제어하기 위해 사용되며, 특정 파드나 네임스페이스에서 오는 트래픽을 허용하거나 차단하는 규칙을 정의할 수 있습니다.
네트워크 정책으로 IP 기반 접근 제한하기
네트워크 정책은 네트워크 플러그인(CNI, 예: Calico, Weave, Flannel 등)에 의해 구현되며, 올바르게 설정된 경우 IP를 통한 직접 접근도 포함하여 모든 형태의 네트워크 트래픽을 제어할 수 있습니다.
네트워크 정책 예시
- 기본적으로 모든 인바운드 트래픽 차단
이 정책은 네임스페이스의 모든 파드에 대해 기본적으로 모든 인바운드 트래픽을 차단합니다.apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress namespace: default spec: podSelector: {} policyTypes: - Ingress
- 특정 네임스페이스에서 오는 트래픽만 허용
이 정책은allowed-namespace
네임스페이스에서 오는 트래픽만default
네임스페이스의 파드로 허용합니다.apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-specific-namespace namespace: default spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: name: allowed-namespace
- 특정 파드에서 오는 트래픽만 허용
이 정책은 특정 레이블을 가진 파드에서 오는 트래픽만 허용합니다.apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-specific-pod namespace: default spec: podSelector: {} policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: allowed-app
- 네트워크 정책을 사용하면 네임스페이스 간의 통신을 제한할 수 있습니다.
- 네임스페이스뿐만 아니라 특정 파드 또는 IP를 통한 접근도 제한할 수 있습니다.
- 올바르게 설정된 네트워크 정책은 IP 기반 접근도 효과적으로 차단합니다.
따라서 네임스페이스 간 통신을 제한하는 네트워크 정책을 적절히 설정하면 IP를 알고 있더라도 접근을 제한할 수 있습니다. 네트워크 정책을 사용하여 원하는 보안 요구사항을 충족시킬 수 있습니다.
containerPort
는 Kubernetes 파드 정의에서 사용되는 필드로, 파드 내의 컨테이너가 리스닝하는 포트를 지정합니다. 이 값은 주로 정보 제공의 역할을 하며, Kubernetes가 파드의 네트워크 트래픽을 처리하는 데 도움이 됩니다. 그러나 몇 가지 활용 사례가 있습니다.
containerPort의 활용 사례
- 정보 제공
containerPort
는 파드 정의에서 컨테이너가 리스닝하는 포트를 명시적으로 나타냅니다. 이는 사람이 읽을 수 있도록 도와주고, 다른 개발자나 운영자가 파드가 어떤 포트에서 서비스를 제공하는지 쉽게 이해할 수 있도록 합니다.
- 네트워크 정책
- 일부 네트워크 정책이나 툴은
containerPort
정보를 사용하여 특정 포트에 대한 트래픽을 제어할 수 있습니다.
- 일부 네트워크 정책이나 툴은
- 서비스와의 매핑
- 서비스 정의에서
targetPort
로containerPort
를 지정할 수 있습니다. 이는 서비스가 트래픽을 파드의 올바른 포트로 라우팅하는 데 사용됩니다.
- 서비스 정의에서
- 호스트 포트와의 매핑
hostPort
와 함께 사용할 경우,containerPort
는 호스트 포트와 매핑됩니다. 이는 특정 노드의 특정 포트를 컨테이너의 포트로 매핑하여 외부에서 직접 접근할 수 있게 합니다.
요약해보면,
- 정보 제공:
containerPort
는 컨테이너가 리스닝하는 포트를 명시적으로 보여줌으로써 파드 정의를 이해하기 쉽게 만듭니다. - 네트워크 정책: 네트워크 정책이나 툴이 특정 포트에 대한 트래픽을 제어하는 데 사용될 수 있습니다.
- 서비스와의 매핑: 서비스 정의에서
targetPort
로 사용되어 서비스가 트래픽을 올바른 포트로 라우팅할 수 있게 합니다. - 호스트 포트와의 매핑:
hostPort
와 함께 사용될 경우, 호스트의 특정 포트를 컨테이너 포트로 매핑하여 외부에서 직접 접근할 수 있게 합니다.
따라서, containerPort
는 단순히 정보 제공 이상의 역할을 하며, Kubernetes 네트워크 설정에서 중요한 역할을 할 수 있습니다.
hostPort
와 containerPort
를 함께 사용하여 포트 매핑을 설정하면 특정 노드의 특정 포트를 컨테이너의 포트로 매핑할 수 있습니다. 이는 NodePort
와 유사한 방식으로 외부에서 접근할 수 있게 하지만, 몇 가지 중요한 차이점이 있습니다.
hostPort vs NodePort
공통점
- 외부 접근 가능: 둘 다 외부에서 클러스터 내부의 서비스를 접근할 수 있게 합니다.
차이점
- 단일 노드에만 적용
hostPort
: 특정 노드의 특정 포트를 컨테이너의 포트로 매핑합니다. 이 설정은 해당 노드에서만 유효합니다. 따라서, 여러 노드에 동일한 서비스를 배포하려면 각 노드마다 별도로 설정해야 합니다.NodePort
: 클러스터의 모든 노드에서 동일한 포트를 열어줍니다. 클러스터의 어느 노드로 접근해도 서비스가 가능하게 됩니다.
- 로드 밸런싱
hostPort
: 기본적으로 로드 밸런싱이 제공되지 않습니다. 특정 노드의 특정 포트에만 접근할 수 있으므로, 클러스터 내의 다른 노드로의 트래픽 분산이 어렵습니다.NodePort
: Kubernetes 서비스는 자동으로 로드 밸런싱을 제공하여 클러스터의 모든 노드에서 트래픽을 적절히 분산시킵니다.
- 포트 충돌
hostPort
: 여러 파드가 동일한 호스트 포트를 사용할 경우 포트 충돌이 발생할 수 있습니다. 이는 포트 관리가 복잡해질 수 있습니다.NodePort
: Kubernetes가 포트 번호를 관리하므로 포트 충돌의 위험이 적습니다.
hostPort 예시
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: my-image
ports:
- containerPort: 80
hostPort: 8080
이 설정에서는 특정 노드의 8080
포트가 컨테이너의 80
포트로 매핑됩니다. 외부에서 해당 노드의 8080
포트로 접근할 수 있습니다.
NodePort 예시
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30080
이 설정에서는 클러스터의 모든 노드에서 30080
포트가 열리며, 해당 포트로 들어오는 트래픽은 컨테이너의 8080
포트로 전달됩니다.
요약해보면,
hostPort
: 특정 노드에서만 유효하며, 포트 충돌이 발생할 수 있고, 기본적으로 로드 밸런싱이 제공되지 않습니다.NodePort
: 클러스터의 모든 노드에서 동일한 포트를 열어주며, Kubernetes가 로드 밸런싱을 제공하여 더 안정적인 서비스 접근을 보장합니다.
따라서, hostPort
와 NodePort
는 외부 접근을 가능하게 한다는 점에서는 유사하지만, 사용 방식과 제공하는 기능에는 차이가 있습니다. 클러스터 내에서 외부 접근과 로드 밸런싱이 중요한 경우에는 NodePort
를 사용하는 것이 더 적합합니다.
NodePort를 사용하면 해당 서비스가 클러스터의 모든 노드에서 지정된 포트를 열어주며, 이로 인해 서비스 파드가 특정 노드에 없더라도 통신이 가능합니다. NodePort 서비스는 Kubernetes 클러스터 전체에 걸쳐 트래픽을 분산시키기 위한 로드 밸런싱을 자동으로 처리합니다.
NodePort의 동작 방식
- NodePort 서비스 생성
- NodePort 서비스는 클러스터의 모든 노드에서 지정된 포트를 열어줍니다. 예를 들어, NodePort가 30080으로 설정되었다면, 클러스터의 모든 노드는 30080 포트를 리스닝합니다.
- 트래픽 분배
- 외부에서 클러스터의 어느 노드로 접근하더라도 해당 노드의 NodePort로 들어온 트래픽은 Kubernetes 서비스가 파드로 라우팅합니다.
- 서비스는 클러스터의 어느 노드로 들어오는 트래픽이든 적절한 파드로 트래픽을 전달합니다. 이 과정에서 파드는 해당 노드에 있을 필요가 없습니다.
- kube-proxy
- Kubernetes의 kube-proxy는 클러스터 내의 네트워크 트래픽을 처리하고, NodePort를 통해 들어오는 트래픽을 적절한 파드로 전달하는 역할을 합니다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30080
이 설정에서는
- 모든 노드는 30080 포트를 리스닝합니다.
- 클러스터 내의 어느 노드로든 30080 포트로 들어오는 트래픽은
my-app
레이블이 붙은 파드의 8080 포트로 전달됩니다.
통신 흐름
- 외부 트래픽 수신
- 외부 클라이언트가 클러스터의 특정 노드 IP와 NodePort(30080)로 트래픽을 보냅니다.
- 트래픽 라우팅
- kube-proxy가 트래픽을 받아, 해당 트래픽을 적절한 파드로 라우팅합니다.
- 이 때, 파드는 동일한 노드에 있지 않아도 됩니다. kube-proxy는 클러스터 내에서 적절한 파드를 찾아 트래픽을 전달합니다.
NodePort를 사용하면 해당 서비스 파드가 없는 노드에서도 해당 포트로 유입된 트래픽을 적절한 파드로 전달할 수 있게 됩니다. NodePort가 기본적으로 로드 밸런싱을 제공하는지에 대한 부분을 정확하게 확인해보면, NodePort 서비스는 클러스터의 모든 노드에서 지정된 포트를 열어줍니다. 이를 통해 클러스터 외부에서 해당 포트로 접근할 수 있게 됩니다.
- 포트 노출
- NodePort 서비스는 클러스터의 모든 노드에서 지정된 포트를 열어줍니다. 예를 들어,
NodePort: 30080
으로 설정하면 클러스터 내 모든 노드에서30080
포트를 통해 접근할 수 있습니다.
- NodePort 서비스는 클러스터의 모든 노드에서 지정된 포트를 열어줍니다. 예를 들어,
- 트래픽 라우팅
- 외부에서 어느 노드로 접근하든지 kube-proxy가 해당 트래픽을 받아서 서비스로 전달합니다.
- 서비스는 클러스터 내의 파드 중 하나로 트래픽을 라우팅합니다.
- 로드 밸런싱
- NodePort 서비스는 자체적으로 로드 밸런싱을 하지 않지만, Kubernetes 서비스가 이를 지원합니다. 이는 클러스터의 모든 노드에서 동일한 NodePort로 들어오는 트래픽을 서비스의 모든 파드로 분배하는 기능을 의미합니다.
- kube-proxy는 라운드 로빈 방식 또는 IP 해시 기반으로 트래픽을 분배합니다.
따라서, NodePort 서비스는 외부에서 어느 노드로 접근하든지 전체 클러스터 내의 서비스 파드로 트래픽을 분배하여 처리할 수 있게 합니다. 이는 결과적으로 로드 밸런싱 효과를 제공한다고 볼 수 있습니다. NodePort와 LoadBalancer 서비스의 동작 방식 및 사용 사례에는 차이점이 있습니다. 다음은 각 방법의 주요 차이점과 특징을 설명합니다.
NodePort
- 동작 방식
- 모든 클러스터 노드에서 지정된 포트를 열어줍니다.
- 외부 클라이언트는 클러스터의 어느 노드의 IP와 지정된 포트로 접근할 수 있습니다.
- kube-proxy가 트래픽을 받아 적절한 파드로 라우팅합니다.
- 특징
- Kubernetes 클러스터 내부에서만 로드 밸런싱이 이루어집니다.
- 외부 클라이언트가 클러스터의 각 노드 IP를 알고 있어야 합니다.
- 주로 개발 및 테스트 환경에서 사용됩니다.
LoadBalancer
- 동작 방식
- 클라우드 제공자가 관리하는 로드 밸런서를 생성합니다 (예: AWS ELB, GCP GLB, Azure LB).
- 로드 밸런서가 클러스터의 모든 노드에 트래픽을 분배합니다.
- 클러스터 외부에서 로드 밸런서의 IP 또는 DNS 이름을 통해 접근할 수 있습니다.
- 특징
- 클라우드 환경에서 사용되며, 클라우드 제공자가 관리하는 로드 밸런서를 통해 외부 트래픽을 처리합니다.
- 외부 클라이언트는 로드 밸런서의 IP 또는 DNS 이름만 알면 됩니다.
- 고가용성 및 자동 확장 기능을 제공합니다.
주요 차이점
- 트래픽 접근 방식
- NodePort: 외부 클라이언트가 클러스터의 모든 노드 IP와 NodePort를 알아야 합니다.
- LoadBalancer: 외부 클라이언트는 로드 밸런서의 IP 또는 DNS 이름만 알면 됩니다.
- 로드 밸런싱 수준
- NodePort: 클러스터 내부에서만 로드 밸런싱이 이루어집니다.
- LoadBalancer: 클라우드 제공자가 관리하는 로드 밸런서가 트래픽을 분산시킵니다.
- 환경
- NodePort: 주로 온프레미스 환경이나 개발, 테스트 환경에서 사용됩니다.
- LoadBalancer: 주로 클라우드 환경에서 사용됩니다.
- 복잡성 및 관리
- NodePort: 설정이 간단하지만, 노드 IP를 관리하고 알아야 하는 번거로움이 있습니다.
- LoadBalancer: 클라우드 제공자가 관리하므로 설정이 더 간단하고 외부 접근이 용이합니다.
NodePort와 LoadBalancer는 외부 트래픽을 클러스터 내부의 서비스로 라우팅하는 방법이지만, 사용 사례와 환경에 따라 적합한 선택이 달라집니다. NodePort는 모든 노드에서 포트를 열어 외부 접근을 가능하게 하지만, 클러스터 내부의 로드 밸런싱만 제공합니다. 반면 LoadBalancer는 클라우드 제공자가 관리하는 로드 밸런서를 통해 외부 트래픽을 더 효과적으로 처리하고 분산시킵니다.
kubectl port-forward
명령어를 사용하여 Kubernetes 클러스터 내부의 포트를 로컬 머신으로 포워딩할 수 있습니다. 이 방법을 사용하면 Minikube 노드에 사설 IP가 할당되어 있어도 외부에서 접근 가능한 공인 IP를 가진 서버에서 포트를 포워딩할 수 있습니다. 그러나 kubectl port-forward
는 기본적으로 로컬 머신의 루프백 인터페이스(127.0.0.1
)로만 바인딩됩니다. 이를 0.0.0.0
으로 바인딩하여 모든 네트워크 인터페이스에서 접근할 수 있도록 할 수 있습니다.
kubectl port-forward 명령어를 외부 접근 가능하게 설정하기
아래는 kubectl port-forward
를 통해 Minikube의 서비스 포트를 외부에서 접근 가능하도록 설정하는 방법입니다.
kubectl port-forward -n <namespace> service/<service-name> <local-port>:<target-port> --address=0.0.0.0
<namespace>
: Wazuh 서비스가 위치한 네임스페이스입니다.<service-name>
: Wazuh 서비스의 이름입니다.<local-port>
: 외부에서 접근할 때 사용할 로컬 머신의 포트입니다.<target-port>
: Kubernetes 서비스의 포트입니다.
kubectl port-forward
명령어를 사용하여 Minikube 내부의 Wazuh 서비스 포트를 외부로 포워딩할 수 있으며, --address=0.0.0.0
옵션을 사용하여 공인 IP를 포함한 모든 네트워크 인터페이스에서 접근할 수 있도록 설정할 수 있습니다. 이 방법은 간단하면서도 효과적으로 Minikube 내부 서비스를 외부에 노출할 수 있는 방법입니다.