ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

WSL 容器 C API 实战:深入解析 Microsoft.WSL.Containers 的 Session 会话管理类

WSL 容器 C API 实战:深入解析 Microsoft.WSL.Containers 的 Session 会话管理类 WSL 容器 C# API 实战深入解析 Microsoft.WSL.Containers 的 Session 会话管理类【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL本指南以Microsoft.WSL.ContainersC# API 的核心类Session为主线系统讲解如何创建、启动、终止一个 WSL 容器主机会话以及如何在会话内完成容器创建、镜像拉取/导入/加载/推送/删除/打标签、VHD 卷管理与注册表认证等完整操作。读完本文你将掌握 WSL 容器会话生命周期管理、带进度回调的异步镜像操作以及底层 WinRT 封装与原生 SDK 的调用关系可直接据此编写可运行的容器编排程序。Session 类总览Session是 WSL 容器编程模型中的核心入口它表示一个由 WSL 支撑的容器主机会话WSL-backed container host session。所有容器和镜像操作都以会话为宿主展开镜像必须先被拉取到会话中容器必须由会话创建会话本身则对应着一个独立运行的 WSL 虚拟机。public sealed class Session : IDisposable { public Session(SessionSettings settings); public event SessionTerminationHandler Terminated; public event ProcessCrashHandler ProcessCrashed; public void Start(); public void Terminate(); public Container CreateContainer(ContainerSettings containerSettings); public void PullImage(PullImageOptions options); public IAsyncActionWithProgressImageProgress PullImageAsync(PullImageOptions options); public void ImportImage(string path, string imageName); public IAsyncActionWithProgressImageProgress ImportImageAsync(string path, string imageName); public void LoadImage(string path); public IAsyncActionWithProgressImageProgress LoadImageAsync(string path); public void PushImage(PushImageOptions options); public IAsyncActionWithProgressImageProgress PushImageAsync(PushImageOptions options); public void DeleteImage(string nameOrId); public void TagImage(TagImageOptions options); public void CreateVhdVolume(VhdOptions options); public void DeleteVhdVolume(string name); public string Authenticate(Uri serverAddress, string username, string password); public IReadOnlyListImageInfo GetImages(); public void Dispose(); }从类型特征上看Session是sealed的不可继承、实现了IDisposable需要显式释放底层资源。从官方 API 概览可知这套公开的 C# 表面镜像自 WinRT 表面其真实实现位于src/windows/WslcSDK/winrt/下的Session.h/Session.cpp封装层。当前仓库中 C# 投影的占位实现位于 src/windows/WslcSDK/csharp/Projection.cs实际能力由 WinRT 层与原生Wslc*SDK 函数提供。创建会话构造函数与 SessionSettings会话只能通过构造参数创建没有无参构造函数var session new Session(sessionSettings);SessionSettings负责在Start()之前完成会话的全部配置其定义见 settings-classes/sessionsettings.mdpublic sealed class SessionSettings { public SessionSettings(string name, string storagePath); public string Name { get; set; } public string StoragePath { get; set; } public uint? CpuCount { get; set; } public uint? MemorySizeInMB { get; set; } public TimeSpan? Timeout { get; set; } public VhdOptions VhdRequirements { get; set; } public bool EnableGpu { get; set; } }各字段的语义与注意事项Name会话的显示名称同时也是机器级的标识键。会话名对机器上所有用户可见还包括创建者 SID 和创建进程 PID因此切勿把凭据或敏感信息放进会话名。若同名会话已存在创建会失败并返回ERROR_ALREADY_EXISTS。StoragePath会话存储写入路径如果路径不存在会被自动创建。CpuCount、MemorySizeInMB、Timeout均可选的 nullable 值。其中Timeout必须为正数且数值必须能放进 uint32 毫秒计数即不能超过约 49.7 天。VhdRequirements会话级存储需求描述可选这里不允许设置OwnerOwner专用于命名卷创建见后文 VHD 卷小节。EnableGpu是否启用 GPU 加速。一个完整的配置示例var sessionSettings new SessionSettings(demo-session, C:\WslcData) { CpuCount 4, MemorySizeInMB 4096, Timeout TimeSpan.FromMinutes(5), EnableGpu true };启动与终止Start() / Terminate()Session.Start()启动会话 VM并注册内部终止等待termination waitsession.Start();从 WinRT 实现 src/windows/WslcSDK/winrt/Session.cpp 可以看到Start()内部其实完成了三件事调用原生WslcCreateSession创建底层会话句柄失败时抛出带错误消息的异常成功后会释放m_settings设置仅在Start()之前保留。调用WslcGetSessionTerminationEvent取得会话终止事件句柄并通过CreateThreadpoolWaitSetThreadpoolWait注册一个线程池等待一旦终止事件被触发就回调Session::OnTerminated——这正是Terminated事件的底层来源。调用WslcRegisterSessionCrashDumpCallback注册崩溃转储回调对应ProcessCrashed事件。Session.Terminate()终止会话session.Terminate();底层直接调用WslcTerminateSession完成见 Session.cpp。需要特别说明的是Start()与Terminate()之外的绝大多数方法都受EnsureStarted()保护如果会话尚未启动会抛出hresult_illegal_method_callSession has not been started重复调用Start()则会抛出 Session has already been started。因此任何镜像、容器、卷操作都必须放在Start()之后。会话事件Terminated 与 ProcessCrashed会话暴露两个事件均以标准 C# 事件形式消费WinRT 委托投影为普通 C# 委托详见 delegates-and-events.md。Terminated 事件当会话终止事件被触发时引发session.Terminated reason Console.WriteLine($Session terminated: {reason});委托签名public delegate void SessionTerminationHandler(SessionTerminationReason reason);其中SessionTerminationReason枚举定义了会话终止的原因分类见 enumerations/sessionterminationreason.md。事件底层由线程池等待Session::OnTerminated回调驱动。ProcessCrashed 事件当上报进程崩溃转储时引发session.ProcessCrashed information Console.WriteLine($Process crashed: {information.ProcessName} ({information.Pid}));委托签名public delegate void ProcessCrashHandler(ProcessCrashInformation information);ProcessCrashInformation数据类携带进程名、PID 等崩溃信息见>Container container session.CreateContainer(containerSettings);ContainerSettings至少需要指定镜像如new ContainerSettings(alpine:latest)还可配置容器名称、初始化进程InitProcess、网络模式、端口映射、卷挂载等详见 core-classes/container.md 与 settings-classes/containersettings.md。创建出的Container可进一步执行Start()、Stop(Signal, TimeSpan)、Delete(...)等生命周期操作其核心使用方式可参考 end-to-end-example.md。镜像管理拉取、导入、加载、推送、删除与打标签Session是镜像操作的统一入口所有方法都成对提供「同步版」与「带进度回调的异步版」。拉取镜像PullImage / PullImageAsync同步拉取session.PullImage(new PullImageOptions(docker.io/library/alpine:latest));带进度的异步拉取var pull session.PullImageAsync(new PullImageOptions(docker.io/library/alpine:latest)); pull.Progress (op, progress) Console.WriteLine($pull: {progress.Status} {progress.Id} {progress.CurrentBytes}/{progress.TotalBytes}); await pull;PullImageOptions的定义见 settings-classes/pullimageoptions.mdpublic sealed class PullImageOptions { public PullImageOptions(string uri); public string Uri { get; set; } public string RegistryAuth { get; set; } }Uri为完整镜像引用如docker.io/library/alpine:latestRegistryAuth为注册表认证令牌公共注册表可留空var pullOptions new PullImageOptions(docker.io/library/alpine:latest) { RegistryAuth string.Empty // optional for public registries };导入镜像ImportImage / ImportImageAsync从文件路径同步导入镜像 tarballsession.ImportImage(C:\images\demo.tar, demo:imported);异步导入var importOp session.ImportImageAsync(C:\images\demo.tar, demo:imported); importOp.Progress (op, progress) Console.WriteLine($import: {progress.Status} {progress.Id}); await importOp;第二个参数imageName指定导入后的镜像名称含标签如demo:imported。加载镜像LoadImage / LoadImageAsync从磁盘加载镜像归档适用于docker save产生的 tar 文件session.LoadImage(C:\images\docker-save.tar);异步加载var loadOp session.LoadImageAsync(C:\images\docker-save.tar); loadOp.Progress (op, progress) Console.WriteLine($load: {progress.Status} {progress.Id}); await loadOp;推送镜像PushImage / PushImageAsync同步推送到注册表session.PushImage(new PushImageOptions(registry.example.com/demo:latest, authToken));异步推送var pushOp session.PushImageAsync(new PushImageOptions(registry.example.com/demo:latest, authToken)); pushOp.Progress (op, progress) Console.WriteLine($push: {progress.Status} {progress.Id}); await pushOp;PushImageOptions见 settings-classes/pushimageoptions.mdpublic sealed class PushImageOptions { public PushImageOptions(string image, string registryAuth); public string Image { get; set; } public string RegistryAuth { get; set; } }删除镜像DeleteImage()按名称或 ID 删除镜像session.DeleteImage(demo:old);镜像打标签TagImage()为已有镜像附加新的仓库/标签session.TagImage(new TagImageOptions(alpine:latest, registry.example.com/alpine, v1));TagImageOptions见 settings-classes/tagimageoptions.md由三个必填参数构成Image源镜像、Repository目标仓库、Tag目标标签。镜像操作进度与结果数据所有异步镜像操作统一通过IAsyncActionWithProgressImageProgress上报进度。ImageProgress见>public sealed class ImageProgress { public string Id { get; } public ImageProgressStatus Status { get; } public ulong CurrentBytes { get; } public ulong TotalBytes { get; } }其中Status为ImageProgressStatus枚举见 enumerations/imageprogressstatus.mdCurrentBytes/TotalBytes用于计算传输进度void PrintImageProgress(ImageProgress progress) Console.WriteLine(${progress.Status,-12} {progress.Id} {progress.CurrentBytes}/{progress.TotalBytes});查询镜像列表GetImages()返回会话已知镜像的快照foreach (var image in session.GetImages()) { Console.WriteLine(image.Name); }返回项为ImageInfo见>using Windows.Storage.Streams; public sealed class ImageInfo { public string Name { get; } public IBuffer Sha256 { get; } public ulong Size { get; } public DateTimeOffset CreatedTimestamp { get; } }一个更实用的格式化输出foreach (var image in session.GetImages()) { Console.WriteLine(${image.Name} ({image.Size / 1024 / 1024} MB)); }注册表认证Authenticate()向注册表服务器认证并返回身份令牌字符串string token session.Authenticate( new Uri(https://registry.example.com), user1, password);Authenticate接收服务器地址Uri、用户名与密码。底层对应WslcSessionAuthenticate调用见 Session.cpp需要说明的是在 WinRT 原生层该接口返回的是AuthenticateResult类型见 src/windows/WslcSDK/winrt/Session.h而 C# 投影中简化为直接返回字符串形式的身份令牌。获取到的令牌可继续用于PullImageOptions.RegistryAuth、PushImageOptions.RegistryAuth等私有注册表操作。VHD 卷管理CreateVhdVolume / DeleteVhdVolume会话还支持管理命名的会话 VHD 卷。创建var vhd new VhdOptions(cache, 2UL * 1024 * 1024 * 1024, VhdType.Dynamic) { Owner new VhdOwner { Uid 1000, Gid 1000 } }; session.CreateVhdVolume(vhd);删除session.DeleteVhdVolume(cache);VhdOptions见 settings-classes/vhdoptions.md同时承担两种职责public sealed class VhdOptions { public VhdOptions(string name, ulong size, VhdType type); public string Name { get; set; } public ulong Size { get; set; } public VhdType Type { get; set; } public VhdOwner? Owner { get; set; } }使用要点会话级存储需求通过SessionSettings.VhdRequirements指定此时不允许设置Owner命名会话卷通过Session.CreateVhdVolume(...)创建此时可设置Owner其中VhdOwner携带Uid/Gid以表达卷内文件属主VhdType枚举见 enumerations/vhdtype.md决定卷类型示例中使用的是VhdType.Dynamic动态扩展。释放资源Dispose()Session实现IDisposableDispose()用于释放底层 WinRT 会话对象session.Dispose();从 WinRT 封装看会话句柄由wil::unique_anyWslcSession, WslcReleaseSession持有见 src/windows/WslcSDK/winrt/Session.h句柄释放时会经由WslcReleaseSession归还给原生 SDK。最佳实践是结合using语句或try/finally保证会话资源被及时回收并在程序退出前调用session.Terminate()干净地关闭会话 VM。端到端示例完整容器生命周期下面的完整程序来源end-to-end-example.md串联了本文全部核心概念——检查前置条件、创建会话、拉取镜像、创建并启动容器、等待初始化进程退出、清理并终止会话using Microsoft.WSL.Containers; using System; using System.Text; using System.Threading.Tasks; class Program { static async Taskint Main() { // 0. Check prerequisites var missing WslcService.GetMissingComponents(); if (missing.Count 0) { Console.WriteLine(WSL components are missing. Run: wsl --install); return 1; } var ver WslcService.GetVersion(); Console.WriteLine($WSL version: {ver.Major}.{ver.Minor}.{ver.Revision}); // 1. Create a session var sessionSettings new SessionSettings(MyApp, C:\WslcData) { CpuCount 4, MemorySizeInMB 4096 }; var session new Session(sessionSettings); session.Start(); // 2. Pull an image var pullOp session.PullImageAsync(new PullImageOptions(docker.io/library/alpine:latest)); pullOp.Progress (op, progress) Console.WriteLine($Pull: {progress.Status} {progress.CurrentBytes}/{progress.TotalBytes}); await pullOp; // 3. Configure an init process var initProcSettings new ProcessSettings { CommandLine new[] { /bin/echo, Hello from WSL Container! }, OutputMode ProcessOutputMode.Event }; // 4. Configure and create a container var containerSettings new ContainerSettings(alpine:latest) { Name hello-container, InitProcess initProcSettings }; var container session.CreateContainer(containerSettings); // 5. Subscribe to init process events before starting var exited new TaskCompletionSourceint(TaskCreationOptions.RunContinuationsAsynchronously); container.InitProcess.OutputReceived data Console.Write(Encoding.UTF8.GetString(data)); container.InitProcess.Exited code exited.TrySetResult(code); // 6. Start the container container.Start(); // 7. Wait for the init process to exit (30-second timeout) var completed await Task.WhenAny(exited.Task, Task.Delay(TimeSpan.FromSeconds(30))); int exitCode completed exited.Task ? exited.Task.Result : -1; Console.WriteLine($Process exited with code: {exitCode}); // 8. Clean up if (container.State ContainerState.Running) { container.Stop(Signal.SIGTERM, TimeSpan.FromSeconds(10)); } container.Delete(DeleteContainerOption.None); session.Terminate(); return exitCode; } }示例中值得注意的细节前置检查通过WslcService.GetMissingComponents()完成见 service-class/wslcservice.md组件缺失时提示运行wsl --install初始化进程通过ProcessSettings配置事件订阅OutputReceived/Exited必须在container.Start()之前完成避免漏掉早期输出或退出事件退出等待使用了 30 秒超时保护避免进程异常时程序永久挂起清理顺序为停止容器 → 删除容器 → 终止会话。深入实现Session 的底层调用链从前文各方法中已经可以勾勒出Session的完整实现层次这里做一个汇总C#/WinRT 公开方法底层原生 SDK 调用说明Start()WslcCreateSessionWslcGetSessionTerminationEventWslcRegisterSessionCrashDumpCallback创建会话、注册终止等待与崩溃回调Terminate()WslcTerminateSession终止会话CreateContainer()底层会话句柄派生容器对象容器归属当前会话PullImage()/PullImageAsync()会话句柄派生的镜像操作异步版本携带ImageProgress进度ImportImage()/LoadImage()会话句柄派生的导入/加载分别对应 tarball 与归档文件PushImage()会话句柄派生的推送需要RegistryAuthAuthenticate()WslcSessionAuthenticate返回身份令牌DeleteImage()/TagImage()会话句柄派生的镜像管理按 name/Id 删除、附加 tag所有 WinRT 方法定义与签名均可对照 src/windows/WslcSDK/winrt/Session.h 查看其完整实现位于 src/windows/WslcSDK/winrt/Session.cpp共 400 余行WinRT 接口契约wslcsdk.idl则定义了这些类型的投影规则。会话对象本身通过wil::unique_any持有原生句柄Dispose()/析构路径会调用WslcReleaseSession释放实现 RAII 式资源管理。小结与进一步阅读Session是 WSL 容器 C# 开发模型中的「总控台」先用SessionSettings描述资源需求并构造Start()拉起会话 VM之后所有镜像、容器、卷操作都以它为宿主执行最后通过Terminate()与Dispose()完成清理。掌握Session的同步/异步双轨 API 与事件模型是编写健壮 WSL 容器应用的第一步。进一步阅读容器对象操作core-classes/container.md、core-classes/process.md相关配置类settings-classes/sessionsettings.md、settings-classes/containersettings.md相关数据与枚举data-classes/imageinfo.md、data-classes/imageprogress.md、enumerations/sessionterminationreason.md委托与事件模型delegates-and-events.md完整生命周期示例end-to-end-example.md服务级入口与已知限制service-class/wslcservice.md、known-gaps.md【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表