Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 715. Windows - WSL 2 환경의 Docker Desktop 네트워크 [링크 복사], [링크+제목 복사],
조회: 7891
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 7개 있습니다.)
개발 환경 구성: 713. "WSL --debug-shell"로 살펴보는 WSL 2 VM의 리눅스 환경
; https://www.sysnet.pe.kr/2/0/13650

개발 환경 구성: 715. Windows - WSL 2 환경의 Docker Desktop 네트워크
; https://www.sysnet.pe.kr/2/0/13659

Linux: 88. WSL 2 리눅스 배포본 내에서의 pid 네임스페이스 구성
; https://www.sysnet.pe.kr/2/0/13771

Linux: 89. pid 네임스페이스 구성으로 본 WSL 2 배포본의 계층 관계
; https://www.sysnet.pe.kr/2/0/13772

Linux: 90. pid 네임스페이스 구성으로 본 WSL 2 + docker-desktop
; https://www.sysnet.pe.kr/2/0/13773

Linux: 91. Container 환경에서 출력하는 eBPF bpf_get_current_pid_tgid의 pid가 존재하지 않는 이유
; https://www.sysnet.pe.kr/2/0/13774

개발 환경 구성: 729. WSL 2 - Mariner VM 커널 이미지 업데이트 방법
; https://www.sysnet.pe.kr/2/0/13779




Windows - WSL 2 환경의 Docker Desktop 네트워크

지난 글에서 다뤘듯이,

"WSL --debug-shell"로 살펴보는 WSL 2 VM의 리눅스 환경
; https://www.sysnet.pe.kr/2/0/13650

WSL 2 VM에서 네임스페이스를 분리시켜 실행한 "docker-desktop" 컨테이너가 있고, 다시 그것에서 분리해 "LinuxKit" 컨테이너를 실행하고, 다시 분리해 docker 관련 컨테이너들이 실행되는 것입니다.

따라서 실질적인 docker 데몬이 시작한 환경은 "LinuxKit"이고, 그 환경을 조사하고 싶다면, 예전 DockerDesktopVM에 대해서 썼던 바로 그 방식과 유사하게 진입할 수 있습니다.

// Getting a Shell in the Docker for Windows Moby VM
// https://www.bretfisher.com/getting-a-shell-in-the-docker-for-windows-vm/

c:\temp> docker run -it --rm --privileged --pid=host justincormack/nsenter1
~ # ps a | grep docker
   59 root      0:00 /usr/bin/runc run --preserve-fds=3 01-docker
   71 root      0:00 /usr/libexec/docker/docker-init /usr/bin/entrypoint.sh
  143 root      1:05 /usr/local/bin/dockerd --config-file /run/config/docker/daemon.json --containerd /run/containerd/containerd.sock --pidfile /run/desktop/docker.pid --swarm-default-advertise-addr=192.168.65.3 --host-gateway-ip 192.168.65.254
...[생략]...
16183 root      0:00 grep docker




LinuxKit 컨테이너의 네트워크 환경을 살펴볼까요? ^^

우선 그 전에 VM의 네트워크 환경이 있을 것입니다. 해당 VM은 Hyper-V의 "vEthernet (WSL (Hyper-V firewall))" 가상 어댑터로 "vSwitch (WSL (Hyper-V firewall))" 가상 스위치에 연결됩니다. 이후, 그 위에서 생성되는 리눅스 배포본들은 그 환경을 그대로 이어받아 사용하는데요, 그래서 VM의 ifconfig 결과docker-desktop 배포본의 ifconfig 결과는 같습니다.

하지만, LinuxKit 컨테이너 레벨에서는 달라지는데요, 우선, docker는 자신이 사용할 내부 가상 네트워크를 임의로 생성하는 것이 가능합니다. 실졔로 Docker Desktop을 설치하면 기본적으로 3개의 네트워크를 가지는데요,

C:\Windows\System32> docker network ls
NETWORK ID     NAME                       DRIVER    SCOPE
39115851b938   bridge                     bridge    local
29b1107e441f   host                       host      local
1650344b2376   none                       null      local

각각의 네트워크 구성을 "docker network inspect" 명령어로 정리하면 이렇게 나옵니다.

[bridge]
"Driver": "bridge",
"EnableIPv6": false,
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"

[host]
"Driver": "host"
(null)

[none]
"Driver": "null"
(null)

그리고 bridge 네트워크로 연결해 실행한 컨테이너에서 ifconfig 명령어를 수행하면 다음과 같이 나옵니다.

// docker에서 생성한 임의의 컨테이너에서 ifconfig 출력

# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ...[생략]...

이와 함께 LinuxKit 컨테이너에서 ifconfig 명령어를 수행하면 이런 결과가 나옵니다.

// LinuxKit 컨테이너에서 실행한 ifconfig 출력 정리

[cni0] inet addr:10.1.0.1  Bcast:10.1.255.255  Mask:255.255.0.0
[docker0] inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
[eth0] inet addr:192.168.65.3  Bcast:192.168.65.255  Mask:255.255.255.0
[lo] inet addr:127.0.0.1  Mask:255.0.0.0
[services1] inet addr:192.168.65.6  Bcast:0.0.0.0  Mask:255.255.255.255

하나씩 볼까요? ^^ 우선 "[cni0]"는 k8s를 함께 설치했을 때 나오는 것입니다.

그다음 "[docker0] inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0" 항목은 낯이 익은 IP 대역인데요, 바로 docker가 기본 구성한 가상 네트워크인 bridge입니다. 다시 말해, Windows Command Shell에서 "docker network create" 명령어를 수행하면 (윈도우가 아닌) LinuxKit 컨테이너 환경 내에서 가상 네트워크를 생성하는 것입니다. (참고로 bridge 네트워크를 추가하면 기본적으로는 172.18.0.1/16, 172.19.0.1/16 등으로 순차 생성됩니다.)

마지막으로 [eth0] 196.168.65.0/24 네트워크가 재미있는데요, 이 구성은 Docker Desktop for Windows의 "Resources" / "Network" 메뉴로 바꿀 수 있습니다. 그러니까, 그것의 기본값이 Docker subnet == "192.168.65.0/24"인 것이고, 해당 네트워크에서 "LinuxKit 컨테이너"의 가상 IP는 "192.168.65.3"이 됩니다.

또한, 위의 환경에서 host.docker.internal, gateway.docker.internal은 ping을 해보면 각각 다음과 같이 나옵니다.

host.docker.internal 192.168.65.254
gateway.docker.internal 192.168.65.1

문서에 따르면, 192.168.65.0/24 네트워크는 (순수) 리눅스 운영체제에서 docker를 호스팅하는 경우에는 만들지 않는다고 합니다. 그런 의미에서, 아마도 192.168.65.0/24는 컨테이너에서 (VM을 건너뛰고) 호스트 네트워크와 연결하기 위한 보조 수단으로써 제공하는 듯합니다. 사실, Docker Desktop은 개발자 친화적으로 만들어진 응용 프로그램이고, 개발자가 주로 머무르는 환경이 (docker를 띄우기 위해 필요한 VM이 아닌) 호스트 운영체제가 되기 때문에 그것과 좀 더 부드럽게 연동하기 위한 네트워크로써 필요했을 것입니다. 실제로 192.168.65.0/24 네트워크는 거의 사용 용도가 없는데요, 제가 찾은 유일한 용도는 docker container 내부에서 "host.docker.internal (192.168.65.254)" 주소가 윈도우 호스트로 연결된다는 점입니다.

// 윈도우 호스트 측에 IIS 서비스를 설치했다면, docker run으로 띄운 컨테이너에서 IIS 80 테스트 가능

C:\temp> docker run -it --rm ubuntil
root@8091c139af60:/# curl host.docker.internal
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...[생략]...
<body>
<div id="container">
<a href="http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409"><img src="iisstart.png" alt="IIS" width="960" height="600" /></a>
</div>
</body>

// 위의 "ubuntil" 이미지는 아래의 dockerfile 구성으로 "docker build -t ubuntil ." 명령을 실행해 생성한 이미지라고 가정.
// FROM ubuntu:latest
// RUN apt-get -y update && apt-get -y install net-tools

재미있는 점은, 윈도우의 VM으로 인해 필요하게 된 네트워크이고, host.docker.internal이 윈도우 호스트 측에 매핑된 것인데 그 과정이 필요 없는 리눅스 환경의 docker에서도 해당 DNS를 쓰고 싶다는 요청이 역으로 발생한 듯합니다. 그래서 리눅스의 경우에는 "--add-host=host.docker.internal:host-gateway" 옵션을 적용해 컨테이너를 실행했을 때 host.docker.internal에 대한 이름 풀이가 호스트 측으로 가능해집니다.

혹시 위의 설명 외에 192.168.65.0/24 네트워크에 대한 구체적인 용도를 아시는 분은 덧글 부탁드립니다. ^^




참고로 지난 글에서,

Visual Studio로 개발 시 기본 등록하는 dev tag 이미지로 Docker Desktop k8s에서 실행하는 방법
; https://www.sysnet.pe.kr/2/0/13645

hostPath를 "/run/desktop/mnt/host/c/temp/WebApplication1" 같은 식으로 지정했었는데, 실제로 이 경로는 "LinuxKit 컨테이너"에서 확인할 수 있습니다.

// LinuxKit 컨테이너 내부에서 실행
// docker run -it --rm --privileged --pid=host justincormack/nsenter1

# ls -l /run/desktop/mnt/host
total 0
drwxrwxrwx    1 root     root          4096 Jun 11 23:02 c
drwxrwxrwx    1 root     root          4096 Jun  9 01:52 d
drwxrwxrwt    5 root     root           120 Jun 12 23:26 wsl
drwxrwxrwt    7 root     root           300 Jun 13 15:03 wslg

그런데, 사실 /mnt/host 경로도 존재하긴 합니다. 예상과는 달리 서로 link로 연결되지도 않았는데요,

# ls -l /mnt/host
total 0
drwxrwxrwx    1 root     root          4096 Jun 11 23:02 c
drwxrwxrwx    1 root     root          4096 Jun  9 01:52 d
drwxrwxrwt    5 root     root           120 Jun 12 23:26 wsl
drwxrwxrwt    7 root     root           300 Jun 13 15:03 wslg

반면 권한까지도 완전히 똑같은데, 왜? k8s의 hostPath에는 "/mnt/host"로는 연결이 안 되고 반드시 "/run/desktop"으로만 정상적으로 동작하는 걸까요? (혹시 아시는 분은 덧글 부탁드립니다. ^^)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/2/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 46  47  48  [49]  50  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12712정성태7/15/202116107개발 환경 구성: 579. Azure - 리눅스 호스팅의 Site Extension 제작 방법
12711정성태7/15/202116127개발 환경 구성: 578. Azure - Java Web App Service를 위한 Site Extension 제작 방법
12710정성태7/15/202118750개발 환경 구성: 577. MQTT - emqx.io 서비스 소개
12709정성태7/14/202114284Linux: 42. 실행 중인 docker 컨테이너에 대한 구동 시점의 docker run 명령어를 확인하는 방법
12708정성태7/14/202118489Linux: 41. 리눅스 환경에서 디스크 용량 부족 시 원인 분석 방법
12707정성태7/14/202185727오류 유형: 734. MySQL - Authentication method 'caching_sha2_password' not supported by any of the available plugins.
12706정성태7/14/202116910.NET Framework: 1076. C# - AsyncLocal 기능을 CallContext만으로 구현하는 방법 [2]파일 다운로드1
12705정성태7/13/202117290VS.NET IDE: 168. x64 DLL 프로젝트의 컨트롤이 Visual Studio의 Designer에서 보이지 않는 문제 - 두 번째 이야기
12704정성태7/12/202116085개발 환경 구성: 576. Azure VM의 서비스를 Azure Web App Service에서만 접근하도록 NSG 설정을 제한하는 방법
12703정성태7/11/202121465개발 환경 구성: 575. Azure VM에 (ICMP) ping을 허용하는 방법
12702정성태7/11/202117170오류 유형: 733. TaskScheduler에 등록된 wacs.exe의 Let's Encrypt 인증서 업데이트 문제
12701정성태7/9/202116717.NET Framework: 1075. C# - ThreadPool의 스레드는 반환 시 ThreadStatic과 AsyncLocal 값이 초기화 될까요?파일 다운로드1
12700정성태7/8/202117158.NET Framework: 1074. RuntimeType의 메모리 누수? [1]
12699정성태7/8/202115693VS.NET IDE: 167. Visual Studio 디버깅 중 GC Heap 상태를 보여주는 "Show Diagnostic Tools" 메뉴 사용법
12698정성태7/7/202119941오류 유형: 732. Windows 11 업데이트 시 3% 또는 0%에서 다운로드가 멈춘 경우
12697정성태7/7/202115011개발 환경 구성: 574. Windows 11 (Insider Preview) 설치하는 방법
12696정성태7/6/202115967VC++: 146. 운영체제의 스레드 문맥 교환(Context Switch)을 유사하게 구현하는 방법파일 다운로드2
12695정성태7/3/202115993VC++: 145. C 언어의 setjmp/longjmp 기능을 Thread Context를 이용해 유사하게 구현하는 방법파일 다운로드1
12694정성태7/2/202117932Java: 24. Azure - Spring Boot 앱을 Java SE(Embedded Web Server)로 호스팅 시 로그 파일 남기는 방법 [1]
12693정성태6/30/202114878오류 유형: 731. Azure Web App Site Extension - Failed to install web app extension [...]. {1}
12692정성태6/30/202115354디버깅 기술: 180. Azure - Web App의 비정상 종료 시 남겨지는 로그 확인
12691정성태6/30/202115614개발 환경 구성: 573. 테스트 용도이지만 테스트에 적합하지 않은 Azure D1 공유(shared) 요금제
12690정성태6/28/202116628Java: 23. Azure - 자바(Java)로 만드는 Web App Service - Tomcat 호스팅
12689정성태6/25/202118329오류 유형: 730. Windows Forms 디자이너 - The class Form1 can be designed, but is not the first class in the file. [1]
12688정성태6/24/202117653.NET Framework: 1073. C# - JSON 역/직렬화 시 리플렉션 손실을 없애는 JsonSrcGen [2]파일 다운로드1
12687정성태6/22/202114969오류 유형: 729. Invalid data: Invalid artifact, java se app service only supports .jar artifact
... 46  47  48  [49]  50  51  52  53  54  55  56  57  58  59  60  ...