Docker

[도커 알아가기] 4. 도커 네트워크

begong 2025. 3. 11. 11:47
반응형

관련 글 목록

1. 컨테이너 기술

2. 도커와 Docker engine

3. 도커 네트워크

4. 도커 포트포워딩 시 서버 폭파 문제해결

 

그동안 컨테이너 기술, 도커, 도커네트워크에 관하여 알아보았습니다.

현재 프로젝트에서 사용중인 bridge 네트워크의 구조에 대해서 알아보았으니, 문제가 될 만한 부분을 추측하고 원인을 찾아 해결해 보겠습니다.

그렇다면 포트포워딩 설정을 많이했을 때 왜 서버가 터졌는가?

원인 추측

  • 많은 proxy 프로세스로 인한 과부하
    • 포트매핑 별로 docker-proxy 프로세스가 생기기 떄문에 과부하가 발생할 수 있다.

테스트

  • 테스트 환경
    • M1 맥북에 우분투 18버전을 설치하여 최대한 클라우드 환경과 비슷하게 세팅하였습니다.
      • CPU 2코어, 메모리 4GB (클라우드 메모리는 8GB)
    • 컨테이너 실행을 위해 NGINX이미지를 이용
      • 컨테이너 포트포워딩에 대한 테스트이기 때문에 별도의 설정은 하지 않았습니다.
    • 모니터링 도구로 htop 활용
  • idle 상태
  • 포트 포워딩 없이 컨테이너 실행
    • docker run -d --name my1 nginx
  • 포트 한개만 포워딩
    • docker run -d --name my1 -p 40000:40000 nginx
    • process가 2개 생성된다.
    • 메모리 사용량 1mb 증가
  • 포트 500개 포트포워딩
    • docker run -d --name my1 -p 40001-40500:40001-40500 nginx
    • process가 1000개 생성
    • 메모리 사용량 1GB 가까이 증가
    • cpu 사용량도 10퍼센트 이상 증가
  • 포트 10000개 포트포워딩
    • docker run -d --name my1 -p 40001-50000:40001-50000 nginx
    • 서버가 터진 모습
    • 모니터링 프로세스가 터진 모습
    • 10000개 포트매핑 실행 영상
    • 메모리 overflow가 나면서 시스템이 멈춰버린다.

테스트 결과

  • docker의 userland proxy로 인하여 포트포워딩 하나 당 docker-proxy 프로세스가 2개씩 생성됩니다.
    • 생성되는 docker-proxy의 종류
      • IPv4 포워딩
      • /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 40478 -container-ip 172.17.0.2 -container-port 40478
      • IPv6 포워딩
      • /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 40478 -container-ip 172.17.0.2 -container-port 40478
  • 포트포워딩 500개 당 메모리 약 900mb 할당
  • 포트포워딩 설정 약 2000개 쯤, 메모리 overflow로 인하여 시스템이 터져버립니다.

결론

  • 10000개의 포트포워딩을 했을 때 서버가 터지던 이유는 많은 프로세스가 생성되어 메모리 OVERFLOW가 발생 했기 때문입니다.

그렇다면 어떻게 해결할 것인가?

  • STUN/TURN 서버의 경우 ICE CHECK를 할 경우 이용할 수 있지만, 미디어 패킷통신을 하려면 포트가 필요하므로 해결책이 될 수 없습니다.
  • ipvlan, macvlan 네트워크 모드의 경우 클라우드 환경에서 IP 할당의 어려움과 시스템 아키텍쳐를 수정해야 하므로 해결방법에서 제외 하였습니다.

해결방안

  1. Userland Proxy 설정 해제
  2. Docker host 모드

1. Userland Proxy 설정 해제

  • userland Proxy 사용 설정을 해제할 경우 docker-proxy 프로세스가 생성되지 않습니다.
  • docker-proxy가 없으면 iptables에서 포트포워딩을 전담합니다
    • docker daemon 설정파일 생성(수정)
    • { "userland-proxy": false, }
    • sudo vi /etc/docker/daemon.json
    • docker 재시작
      • systemctl restart 로 재실행 시, docker.socket때문에 완전 종료되지 않아 설정값이 적용안됨.
      • sudo systemctl stop docker sudo systemctl stop docker.socket sudo systemctl start docker
  • Userland Proxy 설정 해제 방법 (docker 24.0.7v)

userland proxy 설정 후 실행 테스트

  • 도커 미실행 시
    • iptables에 포워딩 관련 정보 없음
  • 포트 포워딩1개
    • userland proxy 사용 해제 시 iptables 만으로 동작
    • docker-proxy 프로세스가 생기지 않는 것을 볼 수 있다.

  • 포트포워딩 5000개
    • 10000개하니 실행시간이 너무 오래걸려 5000개로 테스트 하였음
    • 컨테이너 실행에 약 4분 소요
    • 실행 시간이 길어질 수록 포트매핑속도가 줄어든다.
      • (10000개 매핑시 10분이상 소요 예상)
    • iptables에 설정된 정보

결과

  • docker-proxy 프로세스 미실행으로 메모리 overflow가 발생하지 않아, 정상적으로 컨테이너를 실행 할 수 있었습니다.
  • 포트매핑 설정 중 이미 사용중인 포트가 있으면, 종료되어 처음부터 다시 실행해야 했습니다.
  • 포트 매핑 개수가 많아질 수록 컨테이너 실행 시간이 오래걸린다 (포트 포워딩 갯수를 2배 늘리면 세팅 시간은 그보다 더 늘어남)

해당 방법의 추가적인 단점

  • docker 네트워크 간 통신 및 로컬 프로세스(loopback)의 접근 불가
    • iptables와 NAT만으로는 위의 두 상황에서 통신이 불가능 합니다.
    • 위의 상황에서 userland proxy가 TCP/UDP 프로세스를 실행하여 컨테이너와 호스트 시스템 간의 네트워크 트래픽을 중계해 줍니다.

2. Host 모드 사용

  • 도커 공식문서에도 성능최적화, 컨테이너가 다양한 포트를 처리해야하는 상황에 host모드가 유용할 수 있다고 한다 https://docs.docker.com/engine/network/drivers/host/
  • 호스트의 네트워크를 컨테이너와 공유하기때문에 포트포워딩을 하지 않아도 됩니다.
    • 컨테이너 실행 시 --network host 옵션을 추가한다.
    • Host 모드의 단점
    • 네트워크 격리 부족
      • 호스트의 네트워크를 공유하기 때문에 container에서 보안 문제가 발생했을 경우 host에게 영향을 줄 수 있습니다.
    • 포트 충돌 가능성
    • 선점 포트에 대한 예외처리
      • mediasoup 설정 시 연결 포트를 범위로 지정
      • 연결을 시도하는 포트에대한 이용여부를 판단하는 로직을 미디어 서버에 적용해야 합니다.
  • docker run -d --name my1 --network host nginx
  • Host 모드 실행방법

결론

  • userland-proxy설정을 끄는 방법은 가능하나 실행시간 증가 및 확장 가능성이 저하되는 문제가 발생하였습니다.
  • 따라서 host 네트워크 모드를 활용하여 문제를 해결해보기로 결정하였습니다.

Host 모드로 코드 수정

  • main.ts
    • 0.0.0.0 로 주소를 바인딩해주어야 한다
    • 127.0.0.1은 컨테이너 내부의 네트워크를 가리키기 때문에 설정하지 않는다면 외부에서 접근 불가능하다
  • await app.listen(port, '0.0.0.0');
  • back-media-cd.yml
    • cd과정을 수정해주었습니다.
      • 도커 실행 시 --network host 옵션을 주어 호스트 모드로 실행시킵니다.
  • - name: 🐳 media 컨테이너 실행 run: | docker run -dit --network host --name media ${{secrets.DOCKER_REGISTRY_URL}}/media:${{ github.sha }}

결과

  • 배포 후 정상적으로 호스트모드로 동작하는 것을 확인하였습니다.

참고문서

https://blog.ipspace.net/kb/DockerSvc/40-userland-proxy/

https://www.samsungsds.com/kr/insights/docker.html

https://opencontainers.org/

반응형