In this post, let's have a look at WSL Containers, which is now
available for public preview, and see how we can programmatically start a
container on WSL using the
Microsoft.WSL.Containers
SDK.
WSL now has native container support to build, pull, and run Linux
containers directly on WSL, without Docker Desktop. It ships with a new CLI,
wslc, and a set of SDKs for C, C++, and C#.
1. Install the WSL preview and check the version
WSL Containers is only available in the pre-release version for now. Let's
update WSL to the pre-release.
wsl --update --pre-release
Once that's done, make sure the version is 2.9.3.0 or later (latest
as of today, it will change).
wsl --version WSL version: 2.9.3.0 Kernel version: 6.18.35.2-1 ...
2. wslc
Once you are on 2.9.3.0 or later, you get a new CLI, wslc,
which feels very much like the Docker CLI.
You can pull images, run containers, list them, and so on.
|
|
| wslc |
wslc pull alpine:latest wslc run alpine:latest cat /etc/alpine-release wslc images wslc list || wslc container list
3. Starting a container from code with Microsoft.WSL.Containers
Now let's see how we can do this programmatically. Let's create a console application and add the Microsoft.WSL.Containers NuGet package (2.9.3, latest as of today).
One thing to note is the target framework. The package is a C#/WinRT projection, so the project needs to target a Windows flavored framework. The package itself targets net8.0-windows10.0.19041.0, so anything from .NET 8 upwards works. I am using .NET 11 here, which gives me net11.0-windows10.0.19041.0. A plain net11.0 (without the Windows part) will not work.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net11.0-windows10.0.19041.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.WSL.Containers" Version="2.9.3" /> </ItemGroup> </Project>
And here is the code. It starts a Session (a lightweight VM), pulls
an image into it, creates and starts a Container, execs a command,
and prints its output.
using Microsoft.WSL.Containers; const string image = "alpine:latest"; var storage = Path.Combine(AppContext.BaseDirectory, "WslcStorage"); // 1. Start a container session (its own lightweight VM). Console.WriteLine("[wslc] Starting session..."); using var session = new Session(new SessionSettings("HelloWorld", storage)); session.Start(); // 2. Pull an image into the session. session.PullImage(new PullImageOptions(image)); // 3. Create container. using Container container = session.CreateContainer(new ContainerSettings(image) { InitProcess = new ProcessSettings { CommandLine = ["/bin/sleep", "infinity"] }, EnableAutoRemove = true, }); // 4. Start the container. container.Start(); // 5. Exec a command and print its output. using var slim = new ManualResetEventSlim(); using Stream stdout = Console.OpenStandardOutput(); using Process process = container.CreateProcess(new ProcessSettings { CommandLine = [ "/bin/sh", "-c", "echo \"Hello from a WSL container running Alpine $(cat /etc/alpine-release)\"" ], OutputMode = ProcessOutputMode.Event, }); process.OutputReceived += data => stdout.Write(data, 0, data.Length); process.Exited += _ => slim.Set(); process.Start(); slim.Wait(); // 6. Terminate session. Console.WriteLine("[wslc] Terminating session..."); session.Terminate(); Console.WriteLine("[wslc] Done.");
One thing to note here: the image you pull and the container you create from
code live in their own session, which is separate from the session the
wslc CLI uses. So after running the above, you won't see the Alpine
image under wslc images or the container under wslc list (microsoft/WSL/issues/40966).
Definitely not anytime soon. The neat part is that we can now pull and run standard OCI container images (what most of us call Docker images) from any OCI registry, be it Docker Hub, GitHub Container Registry, Azure Container Registry, or others, without having Docker Desktop installed or running at all. So, will this replace Docker? Definitely not anytime soon, but it's handy, and being able to drive it from C# opens up some nice possibilities.
Definitely not anytime soon. The neat part is that we can now pull and run standard OCI container images (what most of us call Docker images) from any OCI registry, be it Docker Hub, GitHub Container Registry, Azure Container Registry, or others, without having Docker Desktop installed or running at all. So, will this replace Docker? Definitely not anytime soon, but it's handy, and being able to drive it from C# opens up some nice possibilities.
Hope this helps.
Happy Coding.
Regards,
Jaliya
No comments:
Post a Comment