Development of Docker Server Agent with .NET

KUMAR BISHOJITKUMAR BISHOJIT
5 min read

OVERVIEW & PURPOSE

The majority of developers find it challenging to utilize Docker on Linux server systems due to a lack of expertise. Deploying applications built with technologies like .NET, Next.js, Python, and Java can be particularly complex. This server agent provides a comprehensive API solution, simplifying the deployment process for developers.

REQUIREMENTS

  1. Software Development Knowledge (.NET).

  2. Docker Basic Knowledge

  3. Linux Server Knowledge

STEP-01: Create a new ASP.NET Core Web API Project

Open up your terminal and run the following code to create your project. Feel free to personalize the project name instead of using “DockerInfoApi”.

dotnet new webapi -n DockerInfoApi
cd DockerInfoApi

STEP-02: Add Docker .NET NuGet Package

  • To communicate between the Docker environment and this project, the Docker.DotNet NuGet Package is required.

  • The Swashbuckle.AspNetCore NuGet Package is necessary for API management and provides an interactive API testing UI.

dotnet add package Docker.DotNet
dotnet add package Swashbuckle.AspNetCore
dotnet add package NuGet.Protocol

STEP-03: Project Setup

Here is a basic Project.csproj file that you can modify to meet your business requirements. The build and publish configurations are also included.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>

    <!-- Add these configurations -->
    <OutputType>Exe</OutputType>
    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
    <SelfContained>true</SelfContained>
    <PublishSingleFile>true</PublishSingleFile>
    <PublishTrimmed>false</PublishTrimmed>
    <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Docker.DotNet" Version="3.125.15" />
    <!-- Microsoft.AspNetCore.OpenApi is included in .NET 9.0 SDK - you can remove this explicit reference -->
    <PackageReference Include="NuGet.Protocol" Version="6.13.2" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
  </ItemGroup>

</Project>

STEP-04: Update Program.cs & Configure for Docker

Here is a sample file named Program.cs. You can add custom code to meet your business needs.

using Docker.DotNet;

var builder = WebApplication.CreateBuilder(args);

// Configure Docker client
var dockerUri = Environment.OSVersion.Platform == PlatformID.Unix 
    ? "unix:///var/run/docker.sock" 
    : "npipe://./pipe/docker_engine";
builder.Services.AddSingleton<IDockerClient>(new DockerClientConfiguration(new Uri(dockerUri)).CreateClient());

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

STEP-05: Create ContainersController.cs (With APIs)

Here is the first API for accessing the Docker environment. The controller provides four APIs listed below:

  1. GET: /containers - Retrieve a list of all containers.

  2. POST: /containers - Create a new container.

  3. POST: /containers/:id/start - Start the specified container.

  4. POST: /containers/:id/stop - Stop the specified container.

  5. DELETE: /containers/:id - Remove the specified container.

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

namespace DockerInfoApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ContainersController : ControllerBase
    {
        private readonly IDockerClient _dockerClient;

        public ContainersController(IDockerClient dockerClient)
        {
            _dockerClient = dockerClient;
        }

        // List all containers
        [HttpGet]
        public async Task<IActionResult> GetContainers()
        {
            try
            {
                // List all containers
                var contListParams = new ContainersListParameters
                {
                    All = true
                };

                // Get the list of containers
                var containers = await _dockerClient.Containers.ListContainersAsync(contListParams);

                return Ok(containers);
            }
            catch (DockerApiException ex)
            {
                // Handle Docker API exceptions
                var message = $"Error retrieving containers: {ex.Message}";
                return StatusCode((int)ex.StatusCode, message);
            }
            catch (Exception ex)
            {
                // Handle other exceptions
                var message = $"Error retrieving containers: {ex.Message}";
                return BadRequest(message);
            }
        }

        // Create a new container
        //[HttpPost]
        // Coming Soon...

        // Start a container
        [HttpPost("{id}/start")]
        public async Task<IActionResult> StartContainer(string id)
        {
            try
            {
                // Start the container
                var contStartParams = new ContainerStartParameters { };
                var success = await _dockerClient.Containers.StartContainerAsync(id, contStartParams);

                return Ok($"Container {id} started successfully.");
            }
            catch (DockerContainerNotFoundException ex)
            {
                // Handle container not found exception
                var message = $"Container not found: {ex.Message}";
                return NotFound(message);
            }
            catch (Exception ex)
            {
                // Handle other exceptions
                var message = $"Error starting container: {ex.Message}";
                return BadRequest(message);
            }
        }

        // Stop a container
        [HttpPost("{id}/stop")]
        public async Task<IActionResult> StopContainer(string id)
        {
            try
            {
                // Stop the container
                var stopParams = new ContainerStopParameters
                {
                    WaitBeforeKillSeconds = 10
                };
                await _dockerClient.Containers.StopContainerAsync(id, stopParams);

                return Ok($"Container {id} stopped successfully.");
            }
            catch (DockerContainerNotFoundException ex)
            {
                // Handle container not found exception
                var message = $"Container not found: {ex.Message}";
                return NotFound(message);
            }
            catch (Exception ex)
            {
                // Handle other exceptions
                var message = $"Error stopping container: {ex.Message}";
                return BadRequest(message);
            }
        }

        // Remove a container
        [HttpDelete("{id}")]
        public async Task<IActionResult> RemoveContainer(string id)
        {
            try
            {
                // Remove the container
                var removeParams = new ContainerRemoveParameters
                {
                    Force = true,
                    RemoveVolumes = true
                };
                await _dockerClient.Containers.RemoveContainerAsync(id, removeParams);

                return Ok($"Container {id} removed successfully.");
            }
            catch (DockerContainerNotFoundException ex)
            {
                // Handle container not found exception
                var message = $"Container not found: {ex.Message}";
                return NotFound(message);
            }
            catch (Exception ex)
            {
                // Handle other exceptions
                var message = $"Error removing container: {ex.Message}";
                return BadRequest(message);
            }
        }
    }
}

STEP-06: Build and Publish the Project

Run the Project

dotnet run .

# A http://loclhost:5000 link will be generated after successful installation
# Browse URL: http://loclhost:5000/containers

After a successful run of the project, publish the project

dotnet publish -c Release

STEP-07: Prepare your Docker Environment to Test the APIs

Please check if your Docker is running on the OS.

# This command works on Windows, Linux, and macOS.
docker info > /dev/null 2>&1 && echo "Docker is running" || echo "Docker is not running"

Note: If Docker is not running, then install and run it. Docker Install

Creating a test container:

docker pull ubuntu
docker run -it ubuntu /bin/bash

# Test
# It returns the list of containers
docker ps

CONCLUSION:

The development of a Docker Server Agent with .NET simplifies the deployment process for developers who may find using Docker on Linux servers challenging. By following the outlined steps, developers can create a robust API to manage Docker containers efficiently. This guide provides a comprehensive approach, from setting up an ASP.NET Core Web API project to integrating necessary NuGet packages and configuring the Docker environment. By implementing these steps, developers can enhance their deployment capabilities, streamline container management, and leverage the full potential of Docker in their development workflows.

CONTACT:

I’m Kumar Bishojit Paul, the Founder and CEO of BIKIRAN. If you need further assistance, please leave a comment. I’m interested in helping you.

1
Subscribe to my newsletter

Read articles from KUMAR BISHOJIT directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

KUMAR BISHOJIT
KUMAR BISHOJIT