Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 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




"WSL --debug-shell"로 살펴보는 WSL 2 VM의 리눅스 환경

지난 글에서도 언급했지만,

Windows - WSL 2의 네트워크 통신 방법 - 세 번째 이야기 (같은 IP를 공유하는 WSL 2 인스턴스)
; https://www.sysnet.pe.kr/2/0/13647

WSL 2는 Hyper-V VM 위에 (다소 특별하게) 올라오는 Full Linux 운영체제입니다. 그리고, 우리가 흔히 알고 있는 Ubuntu 20.04 같은 배포본들은 그 운영체제 위에서 Container의 하나로 실행되는 인스턴스입니다.

그러니까, WSL 2는 하나의 VM 위에서 여러 개의 Container가 운영되는 방식이고, 그 Container 각각이 Ubuntu 20.04, Fedora 33, CentOS 8, Kali Linux 배포본 등이 되는 것입니다.

만약 WSL 2 인스턴스가 하나도 실행 중이지 않다면,

C:\temp> wsl -l -v
  NAME                    STATE           VERSION
* Ubuntu-20.04            Stopped         2
  docker-desktop          Stopped         2
  docker-desktop-data     Stopped         2

해당 리눅스 VM도 띄워놓지 않습니다. 그런 경우, 그 VM 자체의 shell로 진입하려는 명령어는 동작하지 않습니다.

// wsl --debug-shell
// ; https://renenyffenegger.ch/notes/Windows/dirs/Windows/System32/wsl_exe/debug-shell

C:\temp> wsl --debug-shell
The system cannot find the file specified.
Error code: Wsl/DebugShell/ERROR_FILE_NOT_FOUND

하지만, 1개의 WSL 인스턴스라도 실행 중이라면, 설령 그것이 (0-byte /init만 가지고 있다고 표현되는) docker-desktop-data라고 해도,

// "wsl -d docker-desktop-data" 명령어로 구동

c:\temp> wsl -l -v
  NAME                    STATE           VERSION
* Ubuntu-20.04            Stopped         2
  docker-desktop          Stopped         2
  docker-desktop-data     Running         2

작업 관리자에는 다음의 VM 프로세스가 추가로 생성되고,

vmmemWSL
vmwp.exe

shell 진입이 가능합니다.

// Running 상태의 인스턴스가 "docker-desktop-data" 하나라면 잠시 후에 VM이 자동 종료함

c:\temp> wsl --debug-shell

Welcome to CBL-Mariner 2.0.20240112 (x86_64) - Kernel 5.15.153.1-microsoft-standard-WSL2 (hvc1)
TESTPC login: root (automatic login)

# tty
/dev/hvc1

위의 출력에도 나오지만, 이 운영체제의 커널은 마이크로소프트가 커스터마이징한 것이고, 배포본 종류는 CBL-Mariner라고 합니다.

CBL-Mariner
 - an internal Linux distribution for Microsoft's cloud infrastructure and edge products and services.
; https://github.com/microsoft/azurelinux




예를 들어, 이렇게 3개의 WSL Instance가 실행 중이라면,

c:\temp> wsl -l -v
  NAME                    STATE           VERSION
* Ubuntu-20.04            Running         2
  docker-desktop          Running         2
  docker-desktop-data     Running         2

wsl --debug-shell 내부에서는 각각에 대응한 WSLGd 프로세스를 볼 수 있습니다.

# cat /etc/wsl.conf
command=/usr/bin/WSLGd

# ps -oeuser,pid,ppid,cmd -C WSLGd
EUSER      PID  PPID CMD
root       314   298 /usr/bin/WSLGd
root      2306  2297 /usr/bin/WSLGd
root      2350  2341 /usr/bin/WSLGd

해당 프로세스들은 pid=1인 /init이 실행한 또 다른 /init을 부모로 둡니다.

#  ps -oeuser,pid,ppid,cmd --ppid 1
EUSER      PID  PPID CMD
...[생략]...
root       298     1 /init
root      2297     1 /init
root      2341     1 /init

예를 들어, 2297 init을 부모로 프로세스 트리를 쭉 따라가 보면,

2297     1 /init
  2298  2297 /init
    2384  2298 /init
      2385  2384 /init
        2386  2385 wsl-bootstrap run --base-image /c/Program Files/Docker/Docker/resources/docker-desktop.iso --cli-iso /c/Program Files/Docker/Docker/resources/wsl/docker-wsl-cli.iso
          2417  2386 unshare -muinpf --propagation=unchanged --kill-child /usr/local/bin/wsl-bootstrap jump
            2420  2417 /init
              2433  2420 /init services
                2502  2433 /usr/bin/runc run --preserve-fds=3 01-docker
                  3910  2502 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 4e51b5a3b0b8741c27ad94663f5c6cbad139af4ad37eccb7eef8397e235bca96 -address /run/containerd/containerd.sock

저렇게 docker desktop을 구성하는 컨테이너까지 흘러가게 됩니다. 즉, "docker-desktop" (컨테이너로 실행 중인) WSL 2 인스턴스 내부의 프로세스를 볼 수 있습니다.

마찬가지로, (예를 들어) "Ubuntu 20.04" WSL 2 인스턴스를 실행한 다음 거기 실행된 프로세스를 아무거나 하나 열거하고,

// "Ubuntu 20.04" WSL 2 인스턴스에서 실행

$ ps -oeuser,pid,ppid,cmd --pid 333
EUSER      PID  PPID CMD
root       333     1 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers

$ ps -oeuser,pid,ppid,cmd --pid 1
EUSER      PID  PPID CMD
root         1     0 /sbin/init

그에 해당하는 프로세스를 CBL-Mariner에서 추적하면 이런 트리가 구성됩니다.

298     1 /init
  304   298 /sbin/init
    666   304 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers

정말 하나의 컴퓨터(VM)에서 (namespace만 구분돼) 모든 WSL 2 인스턴스가 실행되는 것이 맞죠? ^^

흥미로운 것은, 위의 결과를 보면, "Ubuntu 20.04"보다 "docker-desktop"이 /init에 대한 단계가 더 많습니다. 제가 리알못이지만, 아마도 "docker-desktop"도 일반적인 하나의 WSL 2 배포본으로 동작하지만 단순히 bootstrapper 용도에 불과한 듯합니다. 즉, "docker-desktop"은 일종의 껍데기 WSL 2 배포본이고, 실질적인 docker 서비스는 그것에서 다시 실행한 컨테이너에서 하는 것입니다. 이에 대한 구조를 다음의 그림에서 확인할 수 있습니다.

Introducing the Docker Desktop WSL 2 Backend
; https://www.docker.com/blog/new-docker-desktop-wsl2-backend/

archtecture_wsl2_1.png

그러니까, 위의 그림에 따르면 "wsl --debug-shell"로 진입한 환경은 "WSL 2 Utility VM"의 운영체제에 해당하고, "docker-desktop"은 그 VM 위에서 실행되는 "Bootstrapping distro"이며, 실제 docker 서비스는 다시 그것에서 구성한 "LinuxKit" 컨테이너에서 이뤄지는 것입니다.

CBL-Mariner (마이크로소프트가 제공하는 "WSL 2 Utility VM" 운영체제), "wsl --debug-shell"로 연결 가능
    - 컨테이너로 실행 중인 다른 배포본 (예: Ubuntu-20.04, Kali-Linux), "wsl -d [배포본명]"으로 연결 가능
    - bootstrapping을 위한 배포본 (docker-desktop), "wsl -d docker-desktop"으로 연결 가능
        - (실질적인 docker 기능을 담당하는) LinuxKit 배포본

참고로 LinuxKit도 공개돼 있습니다.

linuxkit/linuxkit
; https://github.com/linuxkit/linuxkit

(혹시, 리눅스 전문가가 계시다면 위의 설명이 맞게 정리된 것인지 덧글 부탁드립니다. ^^)




CBL-Mariner 운영체제로의 진입은 "wsl --debug-shell" 명령어(또는 그보다 좀 더 격리된 wslg 환경으로는 "wsl --system")으로 할 수 있습니다.

당연하겠지만, "컨테이너로 실행 중인 다른 배포본"의 shell에 진입하는 것도 가능합니다. 사실 이것은 우리가 그동안 무심코 해왔던 건데요, 예를 들어, Ubuntu 20.04 배포본을 설치한 후 윈도우의 "시작" 메뉴에 설치된 "Ubuntu 20.04"를 클릭하면 해당 배포본의 Shell로 진입할 수 있었습니다. 혹은, 이 과정을 명령행으로는 "wsl -d" 옵션으로 수행할 수 있습니다.

c:\temp> wsl -d Ubuntu-20.04

물론 "docker-desktop" 배포본에도 위의 명령어를 이용하면 shell 진입이 가능합니다.

c:\temp> wsl -d docker-desktop

# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:15:5D:73:ED:54
          inet addr:172.19.132.144  Bcast:172.19.143.255  Mask:255.255.240.0
          ...[생략]...

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          ...[생략]...

// 또한, docker-desktop은 현재 alpine 리눅스이므로 apk를 이용한 패키지 설치가 가능합니다.
# apk add nano
fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/community/x86_64/APKINDEX.tar.gz
(1/1) Installing nano (7.2-r1)
Executing busybox-1.36.1-r15.trigger
OK: 15 MiB in 54 packages

게다가 보는 바와 같이 해당 환경에서의 IP를 비롯한 시스템 환경이 다른 WSL 2 인스턴스에서의 환경과 유사한 레벨로 구성되었습니다.

참고로, "docker-desktop-data"는 "data store" 역할만 하기 때문에 오류가 발생합니다.

c:\temp> wsl -d docker-desktop-data
...[생략]...
<3>WSL (22) ERROR: CreateProcessEntryCommon:334: getpwuid(0) failed 2
<3>WSL (22) ERROR: CreateProcessEntryCommon:505: execvpe /bin/sh failed 2
<3>WSL (22) ERROR: CreateProcessEntryCommon:508: Create process not expected to return




VM의 CBL-Mariner 운영체제도 하나의 완벽한 리눅스 환경이므로 (소개 페이지에 "Fedora Project"가 언급되는 걸로 봐서) yum으로 추가 패키지를 설치할 수 있습니다.

// "wsl --shutdown" 등으로 VM이 종료되면,
// 이후 다시 "--debug-shell"로 진입했을 때 패키지도 새롭게 설치해야 합니다.

# yum install lsb-release -y
...[생략]...
Installing/Updating: lsb-release-3.1-1.cm2.noarch

# lsb_release -a
LSB Version:    n/a
Distributor ID: Mariner
Description:    CBL-Mariner 2.0.20240112
Release:        2.0.20240112
Codename:       Mariner

# cat /etc/os-release
NAME="Common Base Linux Mariner"
VERSION="2.0.20240112"
ID=mariner
VERSION_ID="2.0"
PRETTY_NAME="CBL-Mariner/Linux"
ANSI_COLOR="1;34"
HOME_URL="https://aka.ms/cbl-mariner"
BUG_REPORT_URL="https://aka.ms/cbl-mariner"
SUPPORT_URL="https://aka.ms/cbl-mariner"

당연히, IP 역시 WSL 2 VM으로써 "vEthernet (WSL)"에 연결돼 최초 할당받은 것이므로 WSL 배포본에서 볼 수 있었던 그 IP와 동일합니다.

# yum install net-tools -y
...[생략]...

# ifconfig

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.132.144  netmask 255.255.240.0  broadcast 172.19.143.255
        ...[생략]...

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        ...[생략]...

어찌 보면, WSL 2가 구성되었다는 것만으로도 여러분은 이미 Linux VM 하나를 소유한 것이나 다름없습니다. ^^




wsl debug shell은 일단 들어가면 나올 수 없습니다. 가령 'exit' 명령어를 입력하면 대부분 'logout'이라고만 나오고 멈출 것입니다. 이후 다른 cmd 창에서 다시 들어가려고 해도 ERROR_PIPE_BUSY 오류가 나올 텐데요,

C:\temp> wsl --debug-shell
All pipe instances are busy.
Error code: Wsl/DebugShell/ERROR_PIPE_BUSY

매끄러운 해결책은 알 수 없었고, 제 경우에는 그냥 "wsl --shutdown"을 해 vmwp.exe 자체를 종료한 후 다시 (WSL 2 인스턴스를 띄우고) 진입했습니다. 관련해서 아래의 이슈를 보면,

wsl --debug-shell not exiting #9535
; https://github.com/microsoft/WSL/issues/9535>

일단 그렇게 동작하는 것은 맞는다고 합니다. 따라서, 이런 불편함이 있으므로 가능하다면 그냥 "--debug-shell"보다는 "--system" 옵션으로 접속해 살펴보는 것이 좋겠습니다. 단지 "--system"은 기본적으로 "wslg" 사용자로 로그인하기 때문에 "root" 권한이 요구되는 작업은 할 수 없는데, 대신 "-u root" 옵션을 추가해 이런 문제를 보완할 수 있습니다. (그 외에도 --debug-shell과 --system에는 차이가 있긴 합니다.)

C:\temp> wsl --system
wslg $ yum install iputils
Error(1601) : Operation not permitted. You have to be root.
$ exit
logout

C:\temp> wsl --system -u root
root $ yum install iputils -y
...[생략]...
Installing/Updating: iputils-20211215-2.cm2.x86_64




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 10/19/2024]

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

비밀번호

댓글 작성자
 




... 136  137  138  139  140  141  142  143  144  145  146  147  148  149  [150]  ...
NoWriterDateCnt.TitleFile(s)
1303정성태6/26/201227404개발 환경 구성: 152. sysnet DB를 SQL Azure 데이터베이스로 마이그레이션
1302정성태6/25/201229455개발 환경 구성: 151. Azure 웹 사이트에 사용자 도메인 네임 연결하는 방법
1301정성태6/20/201225766오류 유형: 156. KB2667402 윈도우 업데이트 실패 및 마이크로소프트 Answers 웹 사이트 대응
1300정성태6/20/201231785.NET Framework: 329. C# - Rabin-Miller 소수 생성방법을 이용하여 RSACryptoServiceProvider의 개인키를 직접 채워보자 [1]파일 다운로드2
1299정성태6/18/201232897제니퍼 .NET: 21. 제니퍼 닷넷 - Ninject DI 프레임워크의 성능 분석 [2]파일 다운로드2
1298정성태6/14/201234411VS.NET IDE: 72. Visual Studio에서 pfx 파일로 서명한 경우, 암호는 어디에 저장될까? [2]
1297정성태6/12/201231056VC++: 63. 다른 프로세스에 환경 변수 설정하는 방법파일 다운로드1
1296정성태6/5/201227699.NET Framework: 328. 해당 DLL이 Managed인지 / Unmanaged인지 확인하는 방법 - 두 번째 이야기 [4]파일 다운로드1
1295정성태6/5/201225085.NET Framework: 327. RSAParameters와 System.Numerics.BigInteger 이야기파일 다운로드1
1294정성태5/27/201248544.NET Framework: 326. 유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리 [7]파일 다운로드2
1293정성태5/24/201229776.NET Framework: 325. System.Drawing.Bitmap 데이터를 Parallel.For로 처리하는 방법 [2]파일 다운로드1
1292정성태5/24/201223755.NET Framework: 324. First-chance exception에 대해 조건에 따라 디버거가 멈추게 할 수는 없을까? [1]파일 다운로드1
1291정성태5/23/201230283VC++: 62. 배열 초기화를 위한 기계어 코드 확인 [2]
1290정성태5/18/201235083.NET Framework: 323. 관리자 권한이 필요한 작업을 COM+에 대행 [7]파일 다운로드1
1289정성태5/17/201239242.NET Framework: 322. regsvcs.exe로 어셈블리 등록 시 시스템 변경 사항 [5]파일 다운로드2
1288정성태5/17/201226467.NET Framework: 321. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (3) - Type Library파일 다운로드1
1287정성태5/17/201229304.NET Framework: 320. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (2) - .NET 4.0 + .NET 2.0 [2]
1286정성태5/17/201238233.NET Framework: 319. regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (1) - .NET 2.0 + x86/x64/AnyCPU [5]
1285정성태5/16/201233267.NET Framework: 318. gacutil.exe로 어셈블리 등록 시 시스템 변경 사항파일 다운로드1
1284정성태5/15/201225704오류 유형: 155. Windows Phone 연결 상태에서 DRIVER POWER STATE FAILURE 블루 스크린 뜨는 현상
1283정성태5/12/201233316.NET Framework: 317. C# 관점에서의 Observer 패턴 구현 [1]파일 다운로드1
1282정성태5/12/201226110Phone: 6. Windows Phone 7 Silverlight에서 Google Map 사용하는 방법 [3]파일 다운로드1
1281정성태5/9/201233197.NET Framework: 316. WPF/Silverlight의 그래픽 단위와 Anti-aliasing 처리를 이해하자 [1]파일 다운로드1
1280정성태5/9/201226159오류 유형: 154. Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, ...'.
1279정성태5/9/201224919.NET Framework: 315. 해당 DLL이 Managed인지 / Unmanaged인지 확인하는 방법 [1]파일 다운로드1
1278정성태5/8/201226151오류 유형: 153. Visual Studio 디버깅 - Unable to break execution. This process is not currently executing the type of code that you selected to debug.
... 136  137  138  139  140  141  142  143  144  145  146  147  148  149  [150]  ...