-
[Kubernetes] Pod 관련 Host Network 옵션과 동작원리Infra/Kubernetes 2023. 5. 4. 00:41
얼마전 보안 스터디 멤버의 질문으로 확인하게된 내용을 포스팅하려고한다.
멤버의 궁금증 덕분에 또하나 알게된 것 같다^^ 스터디의 순기능이다!!(Thanks to Malatto)
Kubernetes의 Pod의 spec 하위에 존재하는 옵션들에 대한 내용을 분석한 내용이며 kubernetes 공식페이지에서는 정말 필요한 것이아니면 해당설정을 사용하지 않기를 권고하고 있으니 참고하길 바라며 나의 경우, 필요해서 적용하기보단 단순히 궁금증으로 확인해봤다.
- hostNetwork: false 예시
apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - name: nginx image: nginx ports: - name: nginx-port hostIP: [Node IP] hostPort: 30123 containerPort: 8888 volumeMounts: - mountPath: /etc/nginx/conf.d/default.conf name: nginx-conf volumes: - name: nginx-conf hostPath: path: /root/default.conf type: File
=> 해당 내용으로 Pod 배포 시, 해당 Pod가 배포된 Node의 IP + NodePort로 해당 서비스에 접근이 가능해진다. 위의 yaml file로 예를 들자면 curl [hostIP]:[hostPort]로 nginx 웹서버의 정상적인 응답을 받을 수 있게 된다(마지막 영상참고)
- hostNetwork: true 예시
apiVersion: v1 kind: Pod metadata: name: danger-pod spec: hostNetwork: true containers: - name: nginx image: nginx ports: - name: nginx-port hostPort: 8888 containerPort: 8888 volumeMounts: - mountPath: /etc/nginx/conf.d/default.conf name: nginx-conf volumes: - name: nginx-conf hostPath: path: /root/default.conf type: File
=> hostNetwork를 true로 설정하게되면 Pod가 자신이 배포된 node의 IP를 가지는 것을 확인할 수 있다. host의 Network를 사용하기 때문에 containerPort와 hostPort를 동일하게 설정해야한다. 그렇지않으면 에러가 발생할 것이다. 이 역시 해당 node에 curl을 통해 정상적인 응답을 받을 수 있다(curl 192.7.176.10:8888)
- 사용법 참고
=> 위와같은 yaml file로 Pod를 배포할 경우, 마치 service object의 NodePort type처럼 동작하는 것이 가능하다. 하지만 host의 network를 사용하는 것이기 때문에 보안적인 관점에서 추천하는 방법은 아니다. 처음에도 말했지만 공식홈페이지에서도 반드시 필요한 경우가 아니라면 hostNetwork, hostPort 대신 Service의 NodePort 사용을 되도록 권고하고 있다. 또한 host관련 옵션을 사용하는 경우 hostIP, hostPort, Protocol 옵션의 값이 고유해야하기 때문에 Pod를 스케줄링하는 위치의 제약이 따른다는 단점도 존재한다. 또한 hostIP와 protocol을 명시적으로 지정하지 않으면 Kubernetes는 0.0.0.0을 기본 hostIP로 사용하고 TCP를 기본 프로토콜로 사용한다.
해당 옵션을 사용할 시, 고려할 점
* spec.hostNetwork
true와 false 두가지 옵션이 존재한다(미 설정시, Default: false). 해당 값을 true로 설정 시, Pod의 IP가 Pod가 배포된 Node의 IP로 설정된다.
* spec.containers[].ports[].containerPort
해당 설정을 명시한다고해서 해당 container의 Port가 open되는 것은 아니다. 해당 옵션을 원하는 Port로 사용하기 위해서는 반드시 해당 container에 원하는 Port를 사용하는 서비스 등이 동작중이여야한다. 즉, container가 자체적으로 Port를 사용하고 있어야한다.
* spec.containers[].ports[].hostIP
아무 IP나 사용하면안되고 Node 중 하나의 IP를 사용하여야한다.
* spec.containers[].ports[].hostPort
0 < port < 65536 중에서 Port를 사용하면 된다. 만약 hostNetwork 값을 true로 사용할 시, containerPort와 같은 값을 지정해야한다. 역시나 해당 설정을 한다고해서 해당 Pod가 배포된 Node의 Port가 Open 되는 것은 아니다.
- Demo 영상
=> 나의 경우 nginx의 서비스 Port를 8888로 수정해주었으며 hostPort를 30123으로 지정해주었다. 때문에 해당 Pod가 배포된 node에 curl [node ip]:[node port] 명령을 통해 정상적인 응답을 받을 수 있게 되었다.
=> 이러한 동작이 가능한 이유는 다음과 같다.1. 실제 확인해보면 pod가 배포된 node의 port는 실제로 열려있지 않음을 알 수 있다(영상에서 확인가능)
2. 해당 node에서 tcpdump를 통해 확인해보면 ip가 SNAT되는 것과 port가 바뀌는 것을 확인할 수 있다.
3. 이게 가능한 이유는 해당 yaml file로 pod 생성 시, host관련 옵션의 내용을 kube-proxy가 iptables rule로 생성하였기 때문이다.
결론적으로 대충 봤을때는 마치 Pod가 배포된 Node의 Port가 open되어서 이런게 가능한 것으로 보여질 수 있으나 실제로는 iptables rule에 의해 동작한다는 것을 알 수 있었다(참고로 service nodePort도 iptables로 동작한다)
반응형'Infra > Kubernetes' 카테고리의 다른 글
[Kubernetes] Kubestronaut 후기 (4) 2024.09.27 [Openshift] OCP구축하기(feat. Assisted Installer) (0) 2023.08.12 [k8s] Probe 란? (0) 2021.08.17 [k8s] Volume (0) 2021.07.13 댓글