Docker.DotNet 库的使用(一)

缘起:平台开发过程中有个需求,需从一个容器(运行时管理器)中动态创建和管理其他容器(运行实例),并且这些容器处于同个网桥,以便他们能够通过IP或容器名称进行通信。

 一、创建运行时管理器

  创建运行时管理器 webpai项目,引用 Docker.DotNet 包

     

     初始化客户端:我是windows系统连接本机 docker daemon 使用以下方式,更多的连接方式可以参考dotnet/Docker.DotNet: :whale: .NET (C#) Client Library for Docker API (github.com)

builder.Services.AddSingleton<IDockerClient>(provider =>
{
    return new DockerClientConfiguration().CreateClient();
});

先写一个镜像查询api测试一下

using Docker.DotNet;
using Docker.DotNet.Models;
using Microsoft.AspNetCore.Mvc;

namespace RuntimeManager.Controllers;

[ApiController]
[Route("[controller]")]
public class DockerController : ControllerBase
{

    private readonly IDockerClient _client;

    public DockerController(IDockerClient client)
    {
        _client = client;
    }

    [HttpGet(Name = "GetImages")]
    public async Task<IEnumerable<ImagesListResponse>> GetImages()
    {
        IList<ImagesListResponse>? images = await _client.Images.ListImagesAsync(
                    new ImagesListParameters())
                .ConfigureAwait(false);
        return images;
    }
}

我本地 docker 镜像

 

swagger 测试结果 可以看到 成功到连接本地 docker  并且可以查询到镜像信息 

二、创建运行时实例项目

  创建运行时实例项目,这个项目将发布成镜像,运行时管理器,根据这个镜像动态创建容器并与之通信。

  

  创建一个http api 用作内部通信测试,api内容如下:

  

using Microsoft.AspNetCore.Mvc;

namespace RuntimeManager.RuntimeInstance.Controllers;

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{

    [HttpGet]
    public IActionResult Get(string testValue)
    {
        return this.Content($" hello {testValue} ");
    }
}

  appsettings.json 固定端口:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://+:42286",
        "Protocols": "Http1AndHttp2"
      }
    }
  }
}

  创建Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0 
WORKDIR /app
EXPOSE 42286

COPY . .
ENTRYPOINT ["dotnet", "RuntimeManager.RuntimeInstance.dll"]

  程序发布制作docker镜像,镜像名称 runtime-instance,供后续运行时管理器使用,docker 命令:

docker build -t runtime-instance .

制作好镜像,我们再回到运行时管理器开发中。

三、docker 运行时功能编写

首先我们创建DockerRuntime.cs 他继承了BackgroundService, 它主要功能为 创建docker容器,返回运行时实例对象,初始化运行时管理网络。

以下代码作用是启动容器后,创建自定义网络,将运行时管理容器加入网络中。


    protected async override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var containerShortId = Environment.MachineName;
        var containerId = (await _dockerClient.Containers.InspectContainerAsync(containerShortId, stoppingToken)).ID;
        var response = null as NetworkResponse;
        try
        {
            response = await _dockerClient.Networks.InspectNetworkAsync(_options.Network, stoppingToken);
        }
        catch (DockerNetworkNotFoundException)
        {
            await _dockerClient.Networks.CreateNetworkAsync(new() { Name = _options.Network }, stoppingToken);
        }
        finally
        {
            if (response == null || !response!.Containers.ContainsKey(containerId))
                await _dockerClient.Networks.ConnectNetworkAsync(_options.Network, new NetworkConnectParameters() { Container = containerId }, stoppingToken);
        }
    }

我们再看一下创建容器代码

public async override Task<IRuntimeInstace> CreateProcessAsync(RuntimeInstance instance, CancellationToken cancellationToken = default)
    {
        if (instance == null)
            throw new ArgumentNullException(nameof(instance));
        var containerConfig = new Config();

        containerConfig.Env.Add($"RUNTIME_INSTANCEID={instance.Id}");

        var createContainerParameters = new CreateContainerParameters(containerConfig)
        {
            Image = instance.Image,
            Name = instance.Name
        };
        var createContainerResult = await _dockerClient.Containers.CreateContainerAsync(createContainerParameters, cancellationToken);
        await _dockerClient.Networks.ConnectNetworkAsync(_options.Network, new NetworkConnectParameters() { Container = createContainerResult.ID }, cancellationToken);
        foreach (var warning in createContainerResult.Warnings)
        {
            this.Logger.LogWarning(warning);
        }
        return new DockerInstance(createContainerResult.ID, _dockerClient);
    }

传入运行时实例,根据运行时实例创建容器,创建成功后将容器加入网络中,返回docker实例对象,以便对这个容器进行操作。

其中还将运行时实例id写入环境变量,对应容器根据这个环境变量启动以区分不同的运行时实例。

 

posted @ 2023-07-05 23:08  YR20210311  阅读(592)  评论(0)    收藏  举报