diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/CGroupBasedTargetMemoryControl.sln b/CGroupBasedTargetMemoryControl.sln new file mode 100644 index 0000000..83d53c8 --- /dev/null +++ b/CGroupBasedTargetMemoryControl.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35931.197 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CGroupBasedTargetMemoryControl", "CGroupBasedTargetMemoryControl\CGroupBasedTargetMemoryControl.csproj", "{1B4E87CC-BAF7-4DD4-9897-251C0D5A73E4}" +EndProject +Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{81DDED9D-158B-E303-5F62-77A2896D2A5A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CGroupEncapsulation", "CGroupEncapsulation\CGroupEncapsulation.vcxproj", "{A14E9FB5-F238-4083-8BE5-E9905427177F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B4E87CC-BAF7-4DD4-9897-251C0D5A73E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B4E87CC-BAF7-4DD4-9897-251C0D5A73E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B4E87CC-BAF7-4DD4-9897-251C0D5A73E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B4E87CC-BAF7-4DD4-9897-251C0D5A73E4}.Release|Any CPU.Build.0 = Release|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.Build.0 = Release|Any CPU + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Debug|Any CPU.Build.0 = Debug|x64 + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Debug|Any CPU.Deploy.0 = Debug|x64 + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Release|Any CPU.ActiveCfg = Release|x64 + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Release|Any CPU.Build.0 = Release|x64 + {A14E9FB5-F238-4083-8BE5-E9905427177F}.Release|Any CPU.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AD088330-C779-4E80-8FC9-9D91C58F45A8} + EndGlobalSection +EndGlobal diff --git a/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj b/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj new file mode 100644 index 0000000..e9a3d02 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + 521050c6-2bf2-48f6-8642-54756dfac976 + Linux + ..\docker-compose.dcproj + true + + + + + + + + + + True + + + + diff --git a/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.http b/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.http new file mode 100644 index 0000000..4b1b3cd --- /dev/null +++ b/CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.http @@ -0,0 +1,6 @@ +@CGroupBasedTargetMemoryControl_HostAddress = http://localhost:5091 + +GET {{CGroupBasedTargetMemoryControl_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/CGroupBasedTargetMemoryControl/Controller/TestController.cs b/CGroupBasedTargetMemoryControl/Controller/TestController.cs new file mode 100644 index 0000000..f927ad5 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Controller/TestController.cs @@ -0,0 +1,22 @@ +using CGroupBasedTargetMemoryControl.Service; +using Microsoft.AspNetCore.Mvc; + +namespace CGroupBasedTargetMemoryControl.Controller +{ + [ApiController] + [Route("[controller]")] + public class TestController : ControllerBase + { + private readonly CGroupService _cGroupService; + public TestController(CGroupService cGroupService) { + _cGroupService = cGroupService; + } + + [HttpGet(Name ="TestApi")] + public IActionResult Test() + { + _cGroupService.Test(); + return Ok(); + } + } +} diff --git a/CGroupBasedTargetMemoryControl/Dockerfile b/CGroupBasedTargetMemoryControl/Dockerfile new file mode 100644 index 0000000..055a683 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Dockerfile @@ -0,0 +1,32 @@ +# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。 + +# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER root +RUN apt-get update && apt-get install -y libcgroup-dev && rm -rf /var/lib/apt/lists/* +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +# 此阶段用于生成服务项目 +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +USER root +RUN apt-get update && apt-get install -y libcgroup-dev && rm -rf /var/lib/apt/lists/* +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj", "CGroupBasedTargetMemoryControl/"] +RUN dotnet restore "./CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj" +COPY . . +WORKDIR "/src/CGroupBasedTargetMemoryControl" +RUN dotnet build "./CGroupBasedTargetMemoryControl.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# 此阶段用于发布要复制到最终阶段的服务项目 +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./CGroupBasedTargetMemoryControl.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "CGroupBasedTargetMemoryControl.dll"] \ No newline at end of file diff --git a/CGroupBasedTargetMemoryControl/Dockerfile.original b/CGroupBasedTargetMemoryControl/Dockerfile.original new file mode 100644 index 0000000..7df2970 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Dockerfile.original @@ -0,0 +1,34 @@ +# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。 + +# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER root +RUN apt-get update && apt-get install -y libcgroup-dev && rm -rf /var/lib/apt/lists/* +USER $APP_UID +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + + +# 此阶段用于生成服务项目 +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +USER root +RUN apt-get update && apt-get install -y libcgroup-dev && rm -rf /var/lib/apt/lists/* +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj", "CGroupBasedTargetMemoryControl/"] +RUN dotnet restore "./CGroupBasedTargetMemoryControl/CGroupBasedTargetMemoryControl.csproj" +COPY . . +WORKDIR "/src/CGroupBasedTargetMemoryControl" +RUN dotnet build "./CGroupBasedTargetMemoryControl.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# 此阶段用于发布要复制到最终阶段的服务项目 +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./CGroupBasedTargetMemoryControl.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "CGroupBasedTargetMemoryControl.dll"] \ No newline at end of file diff --git a/CGroupBasedTargetMemoryControl/Extension/IServiceCollectionExtension.cs b/CGroupBasedTargetMemoryControl/Extension/IServiceCollectionExtension.cs new file mode 100644 index 0000000..93fba33 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Extension/IServiceCollectionExtension.cs @@ -0,0 +1,13 @@ +using CGroupBasedTargetMemoryControl.Service; + +namespace CGroupBasedTargetMemoryControl.Extension +{ + public static class IServiceCollectionExtension + { + public static IServiceCollection AddCGroupService(this IServiceCollection services) + { + return services.AddSingleton(); + } + + } +} diff --git a/CGroupBasedTargetMemoryControl/Program.cs b/CGroupBasedTargetMemoryControl/Program.cs new file mode 100644 index 0000000..27742b3 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Program.cs @@ -0,0 +1,29 @@ +using CGroupBasedTargetMemoryControl.Extension; +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +builder.Services.AddCGroupService(); + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/CGroupBasedTargetMemoryControl/Properties/launchSettings.json b/CGroupBasedTargetMemoryControl/Properties/launchSettings.json new file mode 100644 index 0000000..c523125 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Properties/launchSettings.json @@ -0,0 +1,62 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5091" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7296;http://localhost:5091" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "8081", + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": true + }, + "WSL": { + "commandName": "WSL2", + "launchBrowser": true, + "launchUrl": "https://localhost:7296/swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "https://localhost:7296;http://localhost:5091" + }, + "distributionName": "" + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:18923", + "sslPort": 44380 + } + } +} \ No newline at end of file diff --git a/CGroupBasedTargetMemoryControl/Service/CGroupService.cs b/CGroupBasedTargetMemoryControl/Service/CGroupService.cs new file mode 100644 index 0000000..9903ac8 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Service/CGroupService.cs @@ -0,0 +1,47 @@ +using System.Runtime.InteropServices; +using CGroupBasedTargetMemoryControl.Util; + +namespace CGroupBasedTargetMemoryControl.Service +{ + public class CGroupService + { + private readonly int ECGEOF = 50023; + + public int Test() + { + unsafe + { + int size; + int ret; + + IntPtr pidsPtr; + int i; + + ret = LibCGroup.cgroup_init(); + if (ret != 0) + { + Console.WriteLine( + "FAIL: cgroup_init failed with %s\n" + LibCGroup.GetErrorString(ret) + ); + return 3; + } + + ret = LibCGroup.cgroup_get_procs("a", "memory", out pidsPtr, out size); + if (ret != 0) + { + Console.WriteLine( + "FAIL: cgroup_get_procs failed with %s\n" + LibCGroup.GetErrorString(ret) + ); + return 3; + } + int[] pids = new int[size]; + Marshal.Copy(pidsPtr, pids, 0, size); + for (i = 0; i < size; i++) + Console.WriteLine(pids[i]); + + // 释放pidsPtr内存(如果libcgroup要求你负责释放,需查阅文档) + } + return 0; + } + } +} diff --git a/CGroupBasedTargetMemoryControl/Util/CGroupUtil.cs b/CGroupBasedTargetMemoryControl/Util/CGroupUtil.cs new file mode 100644 index 0000000..c5c01b3 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/Util/CGroupUtil.cs @@ -0,0 +1,75 @@ +using System; +using System.Runtime.InteropServices; + +namespace CGroupBasedTargetMemoryControl.Util +{ + public static class LibCGroup + { + [DllImport("libcgroup.so.2")] + public static extern int cgroup_init(); + + [DllImport("libcgroup.so.2")] + public static extern nint cgroup_new_cgroup(string name); + + [DllImport("libcgroup.so.2")] + public static extern nint cgroup_add_controller(nint cgroup, string controller); + + [DllImport("libcgroup.so.2")] + public static extern int cgroup_set_value_string( + nint controller, + string name, + string value + ); + + [DllImport("libcgroup.so.2")] + public static extern int cgroup_create_cgroup(nint cgroup, int ignore_ownership); + + [DllImport("libcgroup.so.2")] + public static extern int cgroup_attach_task(nint cgroup); + + [DllImport("libcgroup.so.2")] + public static extern void cgroup_free(nint cgroup); + + [DllImport("libcgroup.so.2")] + public static extern unsafe int cgroup_get_all_controller_begin( + void** handle, + ref controller_data info + ); + + [DllImport("libcgroup.so.2")] + public static extern unsafe int cgroup_get_all_controller_next( + void** handle, + ref controller_data info + ); + + [DllImport("libcgroup.so.2")] + public static extern unsafe int cgroup_get_all_controller_end(void** handle); + + [DllImport("libcgroup.so.2", CharSet = CharSet.Ansi)] + public static extern IntPtr cgroup_strerror(int code); + + [DllImport("libcgroup.so.2", CharSet = CharSet.Ansi)] + public static extern unsafe int cgroup_get_procs( + string name, + string controller, + out IntPtr pids, // pid_t** -> IntPtr(指向pid_t数组的指针) + out int size // int* -> out int + ); + + public static string GetErrorString(int code) + { + IntPtr ptr = cgroup_strerror(code); + return Marshal.PtrToStringAnsi(ptr)!; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct controller_data + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string name; + public int hierarchy; + public int num_cgroups; + public int enabled; + } +} diff --git a/CGroupBasedTargetMemoryControl/appsettings.Development.json b/CGroupBasedTargetMemoryControl/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/CGroupBasedTargetMemoryControl/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/CGroupBasedTargetMemoryControl/appsettings.json b/CGroupBasedTargetMemoryControl/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/CGroupBasedTargetMemoryControl/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/CGroupEncapsulation/CGroupEncapsulation.vcxproj b/CGroupEncapsulation/CGroupEncapsulation.vcxproj new file mode 100644 index 0000000..83dab75 --- /dev/null +++ b/CGroupEncapsulation/CGroupEncapsulation.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + + {a14e9fb5-f238-4083-8be5-e9905427177f} + Linux + CGroupEncapsulation + 15.0 + Linux + 1.0 + Generic + {2238F9CD-F817-4ECC-BD14-2524D2669B35} + + + + true + + + false + + + true + + + false + + + true + DynamicLibrary + WSL2_1_0 + + + false + + + false + + + true + + + + + + + + \\wsl.localhost\Ubuntu-24.04\usr\include;$(IncludePath) + \\wsl.localhost\Ubuntu-24.04\usr\lib\x86_64-linux-gnu;$(LibraryPath) + + + + + + + %(AdditionalDependencies) + cgroup + + + + + \ No newline at end of file diff --git a/CGroupEncapsulation/main.cpp b/CGroupEncapsulation/main.cpp new file mode 100644 index 0000000..0a16604 --- /dev/null +++ b/CGroupEncapsulation/main.cpp @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-2.1-only +#include + +#include +#include + +int main(void) +{ + struct controller_data info; + void* handle; + int error; + + error = cgroup_init(); + + if (error) { + printf("cgroup_init failed with %s\n", cgroup_strerror(error)); + exit(1); + } + + error = cgroup_get_all_controller_begin(&handle, &info); + + while (error != ECGEOF) { + printf("Controller %10s %5d %5d %5d\n", info.name, + info.hierarchy, info.num_cgroups, info.enabled); + error = cgroup_get_all_controller_next(&handle, &info); + if (error && error != ECGEOF) { + printf("cgroup_get_controller_next failed with %s\n", + cgroup_strerror(error)); + exit(1); + } + } + + error = cgroup_get_all_controller_end(&handle); + + return 0; +} diff --git a/docker-compose.dcproj b/docker-compose.dcproj new file mode 100644 index 0000000..b74e5fd --- /dev/null +++ b/docker-compose.dcproj @@ -0,0 +1,19 @@ + + + + 2.1 + Linux + False + 81dded9d-158b-e303-5f62-77a2896d2a5a + LaunchBrowser + {Scheme}://localhost:{ServicePort}/swagger + cgroupbasedtargetmemorycontrol + + + + docker-compose.yml + + + + + \ No newline at end of file diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..88169d1 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,14 @@ +services: + cgroupbasedtargetmemorycontrol: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_HTTP_PORTS=8080 + - ASPNETCORE_HTTPS_PORTS=8081 + ports: + - "8080" + - "8081" + volumes: + - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro + - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro + - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro + - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..de54715 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + cgroupbasedtargetmemorycontrol: + image: ${DOCKER_REGISTRY-}cgroupbasedtargetmemorycontrol + build: + context: . + dockerfile: CGroupBasedTargetMemoryControl/Dockerfile + privileged: true diff --git a/launchSettings.json b/launchSettings.json new file mode 100644 index 0000000..5f43418 --- /dev/null +++ b/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "Docker Compose": { + "commandName": "DockerCompose", + "commandVersion": "1.0", + "serviceActions": { + "cgroupbasedtargetmemorycontrol": "StartDebugging" + } + } + } +} \ No newline at end of file