Windows Docker Desktop wsl2 - ghdrako/doc_snipets GitHub Wiki

WSL2 - lightweight VM

WSL 2 uses the Windows Host Compute Service, an API built on Hyper-V and exposed by enabling the Virtual Machine Platform in Windows 10.

WSL 2 defines a lightweight Linux environment through a series of API calls to the Host Compute Service, including attaching virtual file systems and virtual network adapters.

$ lshw  # view the virtual file systems and network adapters in WSL 2

The Linux kernel in WSL 2 is a slightly modified Linux kernel optimized to run in the Hyper-V-based WSL 2 environment.

Enable windows feature

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Enable WSL2

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart
Restart-Computer
wsl --set-default-version 2

Install from powershell (simplified method)

wsl.exe --install # enable WSL 2 by default, update the WSL 2 kernel, and install GUI support on eligible versions of Windows 10.

https://dockr.ly/docker-for-windows.

Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
Install-Package -Name docker -ProviderName DockerMsftProvider
Restart-Computer -Force

Update

Install-Package -Name docker -ProviderName DockerMsftProvider -Update 

wsl.exe --update
wsl.exe --update --status
wsl.exe --update --rollback  # wycofanie updatu
 

Resource setting

Vmmem - proces allocate dynamic cpu and ram to docker desctop. To limit resouce use instruction below:

creating a .wslconfig file in your user profile folder, as described in the docs.

New-Item "$env:USERPROFILE\.wslconfig" -ItemType File -Value "[wsl2]
memory=8GB # Limits VM memory in WSL 2 to 8 GB"
# turn off all wsl instances such as docker-desktop
wsl --shutdown
notepad "$env:USERPROFILE/.wslconfig"

# Edit .wslconfig file with notepad and write down these settings:
[wsl2]
memory=3GB   # Limits VM memory in WSL 2 up to 3GB
processors=4 # Makes the WSL 2 VM use two virtual processors

Save the file and restart the docker-desktop service.WSL-2 setting isn’t just limited to CPU and Memory; there are more other settings you can apply. Read more about it here.


wsl --list --online  # list avaliable distributions
wsl --install -d Ubuntu-16.04 
Set-VMProcessor -VMName "Virtual Machine Name" -ExposeVirtualizationExtensions $true

WSL distros can also be installed directly from a root file system tar file.

Ubuntu publishes rootfs tarballs for WSL on their cloud image server at https://cloud-images.ubuntu.com/ organized by release code name

wsl.exe --import <name for distro> <location to unpack rootfs> <location of rootfs> [optionally: --version <version of WSL to install in>]
wsl.exe --import UbuntuGroovy-2 C:\WSL\Ubuntu-Groovy-2 $HOME\Downloads\groovy-server-cloudimg-amd64-wsl.rootfs.tar.gz --version 2

It is possible to install the same rootfs under different distro names to have multiple distros for different purposes.

Installing a rootfs using wsl.exe --import must launch the distro from PowerShell (no icon in Start Menu):

wsl.exe -d <name for distro>

you launch the distribution as root

adduser akepka
usermod -aG sudo akepka
su akepka
wsl.exe -d <distro name> -u akepka

Running command in distro using wsl

wsl ls ~
wsl cat /etc/issue
wsl -d Ubuntu-20.04 cat /etc/issue # run command in specified distro
wsl whoami
wsl -u akepka whoami

Managing WSL Distros

# List distro
wsl --list --verbose --all
wsl --list --running
# Run distro
wsl                                # lunch default distro
wsl --distribution Ubuntu-20.04    # lunch specific distro
wsl.exe --distribution Ubuntu-20.04 --user root
wsl.exe --distribution Ubuntu-20.04 --user akepka
# Set default distro
wsl.exe --set-default Ubuntu-20.04 # set specific distro as default
# Execute command in distro
wsl.exe --exec <command to run>   # exec command in distribution
wsl.exe --exec echo 'hello world'
wsl.exe --distribution Ubuntu-20.04 --exec cat /etc/os-release
wsl.exe --distribution Ubuntu-20.04 --user root --exec whoami
# Shutdown
wsl.exe --shutdown
# Terminating
wsl.exe –terminate <name of distribution>
wsl.exe --terminate Ubuntu-20.04
# Convert distro to version
wsl.exe --set-version <name of distribution> <version number>
wsl.exe --set-version Ubuntu-20.04 1
wsl.exe --set-version Ubuntu-20.04 2
# Export/Buckup
wsl.exe --export <name of distribution> <filename of exported image>
wsl.exe --export Ubuntu-20.04 C:\WSL\ubuntu-focal-backup.tar.gz
# Import
wsl.exe --import <name of imported distro> <location to store unpacked file system> <filename of exported image> --version <1 or 2>
wsl.exe --import Ubuntu-Groovy C:\WSL\Ubuntu-Groovy\ C:\Users\Hayden\Downloads\groovy-server-cloudimg-amd64-wsl.rootfs.tar.gz --version 2

Duplicate Distros

# 1 Export
wsl.exe --export Ubuntu-20.04 C:\WSL\ubuntu-focal-backup.tar.gz
# 2 Import under a new distro name  - Distros installed via the Store are installed in folders under $env:LOCALAPPDATA\Packages
wsl.exe --import Ubuntu-20.04-2 C:\WSL\Ubuntu-20.04-2\ C:\WSL\ubuntu-focal-backup.tar.gz --version 2

Creating DIstro from container

docker pull mcr.microsoft.com/dotnet/sdk:5.0 # pull image
docker run -it --name dotnet mcr.microsoft.com/dotnet/sdk:5.0 # start with command line to make modification
# useradd -m stuart
# passwd stuart
# echo -e "[user]\ndefault=stuart" > /etc/wsl.conf #  add the /etc/wsl.conf file to tell WSL to use the user
# cat /etc/wsl.conf
# exit
docker ps -a
docker export -o c:\temp\dotnet.tar dotnet
wsl --import dotnet5 C:\wsl-distros\dotnet5 C:\temp\dotnet.tar --version 2
wsl -d dotnet5 bash
# whoami
# dotnet new webapp --name new-web-app
# cd new-web-app/
# dotnet run
# ^C
wsl --unregister dotnet5
Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:5.0
ARG USERNAME
ARG PASSWORD
RUN useradd -m ${USERNAME}
RUN bash -c 'echo -e "${PASSWORD}\n${PASSWORD}\n" | passwd ${USERNAME}'
RUN bash -c 'echo -e "[user]\ndefault=${USERNAME}" > /etc/wsl.conf'
RUN usermod -aG sudo ${USERNAME}
RUN apt-get update && apt-get -y install sudo
docker build -t dotnet-test -f Dockerfile --build-arg USERNAME=stuart --build-arg PASSWORD=ticONUDavE .
docker run --name dotnet-test-instance dotnet-test
docker export -o c:\temp\chapter-08-dotnet.tar dotnet-test-instance
docker rm dotnet-test-instance
wsl --import chapter-08-dotnet c:\wsl-distros\chapter-08-dotnet c:\temp\chapter-08-dotnet.tar

Remove distro from Store (PowerShell)

Get-AppxPackage -Name "*<distroname>*" | Select PackageFamilyName
Get-AppxPackage -Name "*ubuntu*" | Select PackageFullName
Remove-AppxPackage -Package <PackageFullName>
Remove-AppxPackage -Package "CanonicalGroupLimited.UbuntuonWindows_2004.2020.424.0_x64__79rhkp1fndgsc"

Uninstall Distros Installed Using wsl.exe --import

wsl.exe --unregister Ubuntu
rmdir C:\WSL\ubuntu-hirsute

Mounting External Volumes

wsl.exe --mount \\.\PHYSICALDRIVE<disk number> --bare  # –bare flag, the disk was inserted into WSL but not mounted, instead exposing every partition for further use as we want. 
wsl.exe --exec lsblk                                   # check visible

wsl.exe --mount \\.\PHYSICALDRIVE3 --bare
wsl.exe --exec lsblk

wmic diskdrive list brief

wsl.exe --mount \\.\PHYSICALDRIVE0 --partition 2  # mount

Linux Distro Maintenance

sudo apt update
sudo apt -y upgrade
sudo apt install neovim
sudo apt -y install neovim
sudo apt remove neovim
sudo apt autoremove  # remove  unneeded dependencies
apt search <keyword>
apt search lynx
apt search gnome | less
sudo apt -y install aptitude
sudo aptitude

Configuring WSL Distros

  • wsl.conf, which provides a per-distro configuration
  • .wslconfig, which provides global configuration options

Setting Per-Distro Settings - wsl.conf

Per-distro settings are set in /etc/wsl.conf in each respective distro. This file is read on “boot” by WSL. Some distro publishers publishing images for WSL include a wsl.conf file with default settings. But if it is not present in your distro, then you may manually create or edit this file if you want to override the default WSL settings.

# /etc/wsl.conf:
[automount]
enabled = true
root = /mnt/
sudo mkdir /windrives
# /etc/wsl.conf:
[automount]
enabled = true
root = /windrives/
# load it or not /etc/fstab on WSL boot
[automount]
enabled = true
mountFsTab = true
sudo mount -t drvfs C: /mnt/c -o metadata,uid=1000,gid=1000,umask=22,fmask=11
fsutil.exe file queryCaseSensitiveInfo C:\WSLworkspace\ # check CaseSensitive
fsutil.exe file setCaseSensitiveInfo C:\WSLworkspace\ disable # disable CaseSensitive

[automount]
enabled = true
mountFsTab = true
options = "metadata,case=off,umask=22,fmask=11"

Cross-distro mounting enables a space, /mnt/wsl, where any folder mounted by any one distro is visible to all other distros.

[automount]
crossDistro = true

Generate Hosts File [network] generateHosts = true

Generate DNS File

[network]
generateHosts = true
generateResolvConf = true

Set a custom hostname for your WSL instance

[network]
generateHosts = true
generateResolvConf = true
hostname = Biswa96

WSL interoperability includes the ability to run Windows programs from Linux, Linux programs from Windows, and shared environment variables.

[interop]
enabled = true

Tt is also possible to enable or disable this feature in a single session, without altering wsl.conf. To temporarily disable Windows programs in Linux, run

echo 0 > /proc/sys/fs/binfmt_misc/WSLInterop

To reenable Windows programs in Linux, run

echo 1 > /proc/sys/fs/binfmt_misc/WSLInterop

Appending Windows Path

[interop]
enabled = true
appendWindowsPath = true

WSLENV is a special meta environment variable that exists in both Windows and WSL. WSLENV defines which environment variables are shared between Windows and WSL. WSLENV contains a list of these other environment variables, separated by a colon in WSL or a semicolon in Windows, with flags for how each of the environment variables should be interpreted.

export PATHTOPROJECT=~/project
export WSLENV=PATHTOPROJECT/p # add PATHTOPROJECT to WSLENV

WSLENV Flags

  • /p – Translates a path between Windows and WSL paths, as demonstrated earlier
  • /l – Indicates a list of paths
  • /u – Shares the variable only from Windows to WSL
  • /w – Shares the variable only from WSL to Windows
export PROJECTLIST=/opt/project1:/opt/project2/
export WSLENV=PROJECTLIST/l # make this list of path accessible in Windows
[user]
default = root
[boot]
command = apt update && apt upgrade -y

Setting Global Settings - .wslconfig

The settings are global for all WSL 2 distros, unlike /etc/wsl.conf, which are distinct for each WSL distro. If this file does not exist, then the defaults for WSL 2 are applied. - C:\Users<your username>.wslconfig

[wsl2]
memory=4GB
processors=2
localhostForwarding=true
swap=6GB
swapFile=D:\\Temp\\WslSwap.vhdx

There are additional options (such as kernel and kernelCommandLine, which allow you to specify a custom kernel or additional kernel arguments) https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig.

Kernel

WSL 2 ships with a kernel that is stored in Windows 10 at %SystemRoot%\system32\lxss\tools\kernel and is updated through Windows Update automatically or manually with

wsl.exe --update

It is, however, possible to replace this kernel with your own kernel, using kernel= in .wslconfig.

WSL 2 kernel is open source, available at https://​github.​com/​microsoft/​WSL2-Linux-Kernel, and can be easily tailored to your needs, if the default, for example, doesn't contain support for a specific file system or other kernel features. Note that adding kernel drivers to the WSL 2 kernel will not necessarily enable support for that hardware in WSL 2, which is still contained in a lightweight virtualization container.

[wsl2]
kernel=C:\\Users\\Hayden\\bzImage
[wsl2]
kernel=C:\\Users\\Hayden\\bzImage
kernelCommandLine= vsyscall=emulate # Kernel Command Line
processors=4                        # limit the number of cores that WSL 2 utilizes chack in /proc/cpuinfo
memory=12GB
swap=6GB
swapfile=C:\\wslswap.vhdx # default to storing your swap file at %USERPROFILE%\AppData\Local\Temp\swap.vhdx
localhostforwarding=true
nestedVirtualization=true  # allows you to run virtual machines (VMs) inside of WSL 2, most commonly using KVM
debugConsole=true #  provides a window in which kernel messages are printed

After editing .wslconfig, you must shut down the WSL 2 environment for settings to take.

wsl.exe --shutdown

WSL 2 Advanced Networking

The WSL 2 network has its own IP address on a DHCP NAT subnet. So accessing services running in WSL 2 from outside your device requires opening a port in Windows Firewall and then forwarding the port to the WSL 2 environment IP.

sudo apt -y install apache2
sudo service apache2 start
wslview http://localhost #  open the default landing page for Apache running on localhost 
Get-NetIPAddress # Powershell: get ip windows
ip a             # bash get ip ditro
ip addr show eth0 | awk -F'[ /]+' '$2=="inet" {print $3}'
netsh interface portproxy add v4tov4 listenaddress=192.168.4.122 listenport=80 connectaddress=172.28.202.134 connectport=80 # powershell: creating forwarding port proxy
netsh advfirewall firewall add rule name="Open Port 80 for WSL2" dir=in action=allow protocol=TCP localport=80 # powershell: open prot in firewall
# or
New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow -EdgeTraversalPolicy Allow # create firewall rule
 
curl http://<distro ip> --connection-timeout 15 -v


Filesystem Accessing

Accessing Windows files from Linux

By default, WSL automatically mounts your Windows drives inside WSL distributions (distros). These mounts are created in /mnt; for example, your C: drive is mounted as /mnt/c.

#### Accessing Linux files from Windows

Under Windows, file systems are generally case-insensitive. From linux write to wsl.txt and then to WSL.txt cause overwrite the conntent of the first.

# from explorer 
\\wsl$
# from powershell: 
cd \\wsl$\<DistributionName> 
C:\Users\<username>\AppData\Local\Packages\
C:\Users\%USERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\
# conversion of paths between WSL and their Windows equivalents and vice versa
wslpath C:\\Users\\Hayden
/mnt/c/Users/Hayden
wslpath -w /mnt/c/Users/Hayden
C:\Users\Hayden

Mount File Systems in WSL 2

\wsl$ into the address bar in Windows Explorer, it will list any running Linux distributions (distros)

\\wsl$\<distroname>
\\wsl$\Ubuntu-20.04
\wsl$\Ubuntu-20.04\home\stuart\tmp

# From powershel read/write
Get-Content '\\wsl$\ubuntu-20.04\home\stuart\tmp\hello-wsl.txt'

WSL-to-Windows special path \wsl$

sudo mkdir /mnt/z; sudo mount -t drvfs Z: /mnt/z

To remount when WSL restarts, add the following line into /etc/fstab:

Z: /mnt/z drvfs defaults 0 0

Alternativli using UNC

sudo mkdir /mnt/file-share; sudo mount -t drvfs '\\server\share-name' /mnt/file-share

To remount when WSL restarts, add the following line into /etc/fstab:

\\server\share-name /mnt/file-share drvfs defaults 0 0

Piping

# Piping form window to linux
Get-Childitem $env:SystemRoot | ForEach-Object { $_.Name.Substring(0,1).ToUpper() } | wsl sort | wsl uniq -
Get-Childitem $env:SystemRoot | ForEach-Object { $_.Name.Substring(0,1).ToUpper() } | wsl bash -c "sort | uniq -c"

# Piping form linux to window
wsl bash -c "ls /usr/bin | cut -c1-1" | Group-Object

Executing windows aplication in linux

Simply calc.exe execte in Linux becaues wsl Windows Path will map to Linux Path

$ echo $PATH
$ notepad.exe "c:\wsl-book\wsl.txt"
$ notepad.exe c:\\wsl-book\\wsl.txt
$ powershell.exe -C "Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System"
$ powershell.exe -C ./wsl.ps1 -Name Stuart
$ powershell.exe -C "Get-Content ./wsl.ps1" | wc -l
$ MESSAGE="Hello"; powershell.exe -noprofile -C "Write-Host $MESSAGE"
$ echo "Stuart" | powershell.exe -noprofile -c 'Write-Host "Hello $input"'

WSL Tooling

%SystemRoot%\system32\lxss\contains:

  • LxssManager.dll – Services for managing the WSL environment
  • LxssManagerProxyStub.dll – An initial stub for loading LxssManager.dll later in the boot process
  • tools/ – A folder containing several other tools
    • bsdtar – The utility for converting WSL installations to and from tar.gz balls
    • ext4.vhdx.gz – A preformatted blank ext4 file system
    • init – The WSL 2 init process, which operates as PID 1 on WSL 2 containers
    • initrd.img – The initial RAM disk loaded by the WSL 2 kernel as part of the “boot” process
    • kernel – The WSL 2 Linux kernel
    • license – A copy of the GNU General Public License 2 covering the Linux kernel
  • lib/ – A folder containing several libraries
    • wslclient.dll – A new library in builds 19555+ used to consolidate the functionality of wsl.exe, bash.exe, wslhost.exe, wslconfig.exe, and LxssManager.dll into a single library
    • wslhost.exe – A tool used to maintain Windows interoperability for background tasks on WSL 1 compute functionalities.
    • libdxcore.so, libd3d12.so, libd3d12core.so, libdirectml.so, and related libraries provide support for DirectX-powered Direct3D GPU acceleration and DirectML machine learning.

%SystemRoot%\system32\lxss\lib is linked into place inside WSL distros at /usr/lib/wsl/lib/

Set up TLS in communication

$ipAddress = '<vm-ip-address>'

mkdir -p C:\certs\client

docker container run --rm `
 --env SERVER_NAME=$(hostname) `
 --env IP_ADDRESSES=127.0.0.1,$ipAddress `
 --volume 'C:\ProgramData\docker:C:\ProgramData\docker' `
 --volume 'C:\certs\client:C:\Users\ContainerAdministrator\.docker' `
 dockeronwindows/ch01-dockertls:2e

Restart-Service docker

Configured the Docker Engine API to allow only secure remote connections and will also have created the certificates that the client needs to use to connect. Copy these certificates from C:\certs\client on the VM onto the machine where you want to use the Docker client.

On the client machine - set environment variables to point the Docker client to use a remote Docker service.

$ipAddress = '<vm-ip-address>'

$env:DOCKER_HOST='tcp://$($ipAddress):2376'
$env:DOCKER_TLS_VERIFY='1'
$env:DOCKER_CERT_PATH='C:\certs\client'  # cert coping form serwer

Change location docker desktop disk image

The WSL 2 docker-desktop-data vm disk image would normally reside in: %USERPROFILE%\AppData\Local\Docker\wsl\data\ext4.vhdx

wsl --shutdown
wsl --list -v
wsl --export docker-desktop-data "D:\Docker\wsl\data\docker-desktop-data.tar"
wsl --unregister docker-desktop-data  # remove ext4.vhdx in current location
mkdir "D:\Docker\wsl\data"
wsl --import docker-desktop-data "D:\Docker\wsl\data" "D:\Docker\wsl\data\docker-desktop-data.tar" --version 2
wsl --start
del "D:\Docker\wsl\data" "D:\Docker\wsl\data\docker-desktop-data.tar"

Integration VSC with WSL Distro

  1. Ctrl+P, and type ext install remote-wsl and press install button
  2. Ctrl+Shift+P and type: remote-wsl

There are various flavors of the remote extensions:

  • Remote-WSL, which runs the server in WSL
  • Remote-SSH, which allows you to connect to a remote machine over SSH to run the server
  • Remote-Containers, which allows you to use containers to run the server in

Opening a folder with Remote-WSL (Ctrl + Shift + P) Remote-WSL: New Window - open a new Visual Studio Code window, start up the Visual Studio Code server in your default WSL distro and connect to it Remote-WSL: New Window using Distro… option - choose which distro to connect to

Integration VSC with Docker Containers

Remote-Containers extension sits as part of the Remote-Development extension pack alongside Remote-WSL and Remote-SSH. This extensions allow you to separate the user interface aspects from the code interactions, such as loading, running, and debugging your code.

With Remote-Containers, we instruct Visual Studio Code to run these code interactions inside a container that we define in a Dockerfile.

  1. Creating a dev container - To add a dev container to a project, we need to create a .devcontainer folder with two files Dockerfile devcontainer.json - Remote-Containers: Add Development Container Configuration Files… - chooes from predefinition 2 Remote-Containers: Reopen in Container - vsc restart and begin building the container image to run the code server in. 3 View: Toggle Integrated Terminal - gives us a terminal view in Visual Studio Code with the terminal running inside the dev container.

Setting up Docker in the dev container

Open .devcontainer/Dockerfile in Visual Studio Code and add the following:

RUN apt-get update \
     && export
DEBIAN_FRONTEND=noninteractive \"
    # Install docker
    && apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common lsb-release \
    && curl -fsSL https://download.docker.com/linux/$(lsb_release -is | 
tr '[:upper:]' '[:lower:]')/gpg | apt-key add - 2>/dev/null \
    && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable" \
    && apt-get update \
    && apt-get install -y docker-ce-cli \
    # Install docker (END)
    # Install icu-devtools
    && apt-get install -y icu-devtools \
    # Clean up
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

we will reuse the Docker daemon from the host within the dev container. On Linux, the default communication with Docker is via the /var/run/docker.sock socket. When running containers using the docker CLI, you can mount sockets using the --mounts switch (https://docs.docker.com/storage/bind-mounts/). For the dev container, we can specify this using the mounts property in .devcontainer/devcontainer.json:

"mounts": [
    // mount the host docker socket (for Kind and docker builds)
    "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"

Any docker commands that you run will be executed against the Docker Desktop daemon; so, for example, running docker ps to list containers will include the dev container in its output

⚠️ **GitHub.com Fallback** ⚠️