Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 715. Windows - WSL 2 환경의 Docker Desktop 네트워크 [링크 복사], [링크+제목 복사],
조회: 7107
글쓴 사람
정성태 (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

비밀번호

댓글 작성자
 




1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13827정성태11/25/20244080Windows: 273. Windows 환경의 파일 압축 방법 (tar, Compress-Archive)
13826정성태11/21/20244278닷넷: 2313. C# - (비밀번호 등의) Console로부터 입력받을 때 문자열 출력 숨기기(echo 끄기)파일 다운로드1
13825정성태11/21/20244251Linux: 110. eBPF / bpf2go - BPF_RINGBUF_OUTPUT / BPF_MAP_TYPE_RINGBUF 사용법
13824정성태11/20/20244196Linux: 109. eBPF / bpf2go - BPF_PERF_OUTPUT / BPF_MAP_TYPE_PERF_EVENT_ARRAY 사용법
13823정성태11/20/20244160개발 환경 구성: 734. Ubuntu에 docker, kubernetes (k3s) 설치
13822정성태11/20/20243975개발 환경 구성: 733. Windbg - VirtualBox VM의 커널 디버거 연결 시 COM 포트가 없는 경우
13821정성태11/18/20243860Linux: 108. Linux와 Windows의 프로세스/스레드 ID 관리 방식
13820정성태11/18/20243892VS.NET IDE: 195. Visual C++ - C# 프로젝트처럼 CopyToOutputDirectory 항목을 추가하는 방법
13819정성태11/15/20244064Linux: 107. eBPF - libbpf CO-RE의 CONFIG_DEBUG_INFO_BTF 빌드 여부에 대한 의존성
13818정성태11/15/20244254Windows: 272. Windows 11 24H2 - sudo 추가
13817정성태11/14/20244156Linux: 106. eBPF / bpf2go - (BPF_MAP_TYPE_HASH) Map을 이용한 전역 변수 구현
13816정성태11/14/20244364닷넷: 2312. C#, C++ - Windows / Linux 환경의 Thread Name 설정파일 다운로드1
13815정성태11/13/20244245Linux: 105. eBPF - bpf2go에서 전역 변수 설정 방법
13814정성태11/13/20244409닷넷: 2311. C# - Windows / Linux 환경에서 Native Thread ID 가져오기파일 다운로드1
13813정성태11/12/20244133닷넷: 2310. .NET의 Rune 타입과 emoji 표현파일 다운로드1
13812정성태11/11/20244320오류 유형: 933. Active Directory - The forest functional level is not supported.
13811정성태11/11/20244164Linux: 104. Linux - COLUMNS 환경변수가 언제나 80으로 설정되는 환경
13810정성태11/10/20244409Linux: 103. eBPF (bpf2go) - Tracepoint를 이용한 트레이스 (BPF_PROG_TYPE_TRACEPOINT)
13809정성태11/10/20244452Windows: 271. 윈도우 서버 2025 마이그레이션
13808정성태11/9/20244274오류 유형: 932. Linux - 커널 업그레이드 후 "error: bad shim signature" 오류 발생
13807정성태11/9/20244577Linux: 102. Linux - 커널 이미지 파일 서명 (Ubuntu 환경)
13806정성태11/8/20244263Windows: 270. 어댑터 상세 정보(Network Connection Details) 창의 내용이 비어 있는 경우
13805정성태11/8/20244220오류 유형: 931. Active Directory의 adprep 또는 복제가 안 되는 경우
13804정성태11/7/20244395Linux: 101. eBPF 함수의 인자를 다루는 방법
13803정성태11/7/20244595닷넷: 2309. C# - .NET Core에서 바뀐 DateTime.Ticks의 정밀도
13802정성태11/6/20244952Windows: 269. GetSystemTimeAsFileTime과 GetSystemTimePreciseAsFileTime의 차이점파일 다운로드1
1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...