Month: February 2020

Running PostgreSql in a Container on Windows 10

Today at work we were setting up a development environment for a .Net Core project using PostgreSql as it’s datastore. We decided that we set up the database server running in a container in the same way I have been running SQL Server (See recent article: Running Microsoft SQL Server in a Container on Windows 10) for the local development environment. Using the docker-compose file from this article as a basis and referring to the documentation for the postgres docker image on Docker Hub we put together a docker-compose file for PostgreSQL that looked similar to this:

version: "3"
services:
  postgres:
    image: "postgres"
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: "MyUser"
      POSTGRES_PASSWORD: "Password!23"
      POSTGRES_DB: "example"
    volumes: 
      - C:\Docker\PostgreSql\data:/var/lib/postgresql/data

Upon running docker-compose we were greeted with the following output containing an error message:

Creating postgresql_postgres_1 ... done
Attaching to postgresql_postgres_1
postgres_1  | The files belonging to this database system will be owned by user "postgres".
postgres_1  | This user must also own the server process.
postgres_1  |
postgres_1  | The database cluster will be initialized with locale "en_US.utf8".
postgres_1  | The default database encoding has accordingly been set to "UTF8".
postgres_1  | The default text search configuration will be set to "english".
postgres_1  |
postgres_1  | Data page checksums are disabled.
postgres_1  |
postgres_1  | fixing permissions on existing directory /var/lib/postgresql/data ... ok
postgres_1  | creating subdirectories ... ok
postgres_1  | selecting dynamic shared memory implementation ... posix
postgres_1  | selecting default max_connections ... 20
postgres_1  | selecting default shared_buffers ... 400kB
postgres_1  | selecting default time zone ... Etc/UTC
postgres_1  | creating configuration files ... ok
postgres_1  | running bootstrap script ... 2020-02-25 02:38:12.326 UTC [80] FATAL:  data directory "/var/lib/postgresql/data" has wrong ownership
postgres_1  | 2020-02-25 02:38:12.326 UTC [80] HINT:  The server must be started by the user that owns the data directory.
postgres_1  | child process exited with exit code 1
postgres_1  | initdb: removing contents of data directory "/var/lib/postgresql/data"
postgresql_postgres_1 exited with code 1

Notice line 19: “FATAL: data directory “/var/lib/postgresql/data” has wrong ownership”. After reading the error message we noted on line 12 it reads “fixing permissions on existing directory /var/lib/postgresql/data … ok”. Also near the top of the output on line 3 it reads “The files belonging to this database system will be owned by user “postgres”.” followed by “This user must also own the server process.”. Interesting…

So after digging around a bit we found that indeed the user “postgres” must own the files in order for the db system to read them and that the container starts up as root. It appears that line 12 is trying to fix the issue, and from what we found online it will… If the data directory is on a Linux file system. Since we are attempting to mount these files from a Windows file system, it appears that “fixing the permissions” fails. No major surprise there. So what is the work around for us poor developers working on Windows machines?

Named Volumes to the Rescue

In order to get this to work we set up a named volume. In this scenario, Docker takes care of handling the files and where they are actually stored, so we don’t readily have access to the files, but we don’t really care all that much. We just want our data to persist and not get blown away when the container gets deleted.

Here is the new (working) docker-compose file with the named volume:

version: "3"
services:
  postgres:
    image: "postgres"
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: "MyUser"
      POSTGRES_PASSWORD: "Password!23"
      POSTGRES_DB: "example"
    volumes: 
      - psql:/var/lib/postgresql/data

volumes:
  psql:

Using this approach you may want to keep an eye on the named volumes on your system and clean them up when you are no longer using them. To get a list of the volumes on your machine use the following command:

docker volumes ls

That will dump out a list of volumes on your machine that looks something like:

DRIVER              VOLUME NAME
local               600de9fcef37a60b93c410f9e7db6b4b7f9966faf5f6ba067cc6cb55ee851198
local               ae45bfac51d4fb1813bd747cc9af10b7d141cf3affa26d79f46f405ebfa07462
local               b94806ba697f79c7003481f8fd1d65599e532c0e2223800b39a2f90b087d5127
local               d02adf9ab33dfa22e154d25e13c5bb383a5969c19c1dd98cfa2ac8e560d87eb4
local               postgresql_psql

Notice the last entry named “postgresql_psql”? That is the one we just created above. To remove it use the following command (Note: It will not allow you to remove the volume if it is referenced by a container, running or not, so you’ll want to stop and remove the container first):

docker volume rm postgresql_psql

Automatic Binding of Settings Classes to Configuration

I’ve had the idea to do this for a while now. It usually pops back into my head when I start a new project and I have to read configuration information into the application. Microsoft’s IOptions<T> is nice, but there is still a bit of ceremony in having to bind each class to it’s configuration in Startup.cs. It seemed like I should just be able to tell the system in some light-weight, unobtrusive way where to get this configuration from and be done with it.

The Dream

So what is this magical “light-weight, unobtrusive way” you speak of? Well, I’m glad you asked! My thought was to create a NuGet package so that I could just plug it into any project, add an attribute to my settings class(es), and set a single constructor parameter that was the section of the configuration to bind it to. Something like this:

    [AutoBind("Features")]
    public class Features
    {
        public bool IsCoolFeatureEnabled { get; set; }
        public int CoolFeatureCount { get; set; }
        public bool IsUberFeatureEnabled { get; set; }
        public bool IsSecretFeatureEnabled { get; set; }
    }

In my magical world that should automatically bind to a section in my configuration named “Features”.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Features": {
    "IsCoolFeatureEnabled": true,
    "CoolFeatureCount": 4,
    "IsUberFeatureEnabled": true,
    "IsSecretFeatureEnabled": false 
  },
  "AllowedHosts": "*"
}

Then, for example, I could inject an instance of “Features” into a controller and use them to control the availability of features in my application (for example). In this case I’m just going to pass the settings (“Features”) to my view to control the layout of the page like so:

    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly Features _features;

        public HomeController(ILogger<HomeController> logger, Features features)
        {
            _logger = logger??throw new ArgumentNullException(nameof(logger));
            _features = features ?? throw new ArgumentNullException(nameof(features));
        }

        public IActionResult Index()
        {
            return View(_features);
        }

        ...
    }

The Startup Code (“The Glue”)

The only “glue” to hold all this together is a little one-liner in the Startup.cs file’s ConfigureServices method, that you only have to make once. You don’t have to go back to the startup each time you want to configure a new class for configuration settings.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAutoBoundConfigurations(Configuration).FromAssembly(typeof(Program).Assembly);
        services.AddControllersWithViews();
    }

The AddAutoBoundConfigurations(…) method sets up a builder with your configuration root. Each time you call FromAssembly(…) using the fluent API it will scan that assembly for any classes with the AutoBind attribute, create an instance, bind it to your configuration, and configure it as a singleton for dependency injection.

The fluent API also exposes a Services property which will allow you to chain back into the services fluent API to continue your setup if you wish to like this.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAutoBoundConfigurations(Configuration)
                .FromAssembly(typeof(Program).Assembly)
                .Services
                .AddControllersWithViews();
    }

Wrapping it up – Back to the View

I’ve created a view that uses the “Features” settings to enable features (OK, they’re just div tags on the page, but you get the idea.) and to control the number of CoolFeatures that are on the page. Here’s the razor view:

@model AutoBind.Demo.Settings.Features
@{
    ViewData["Title"] = "Home Page";
}
    <div class="row">
        <div class="col-sm-12 mb-5">
            <h1 class="text-4">Features</h1>
        </div>
    </div>
    <div class="row">
    @if (Model.IsCoolFeatureEnabled)
    {
        @for (int index = 1; index <= Model.CoolFeatureCount; index++)
        {
            <div class="col-sm-4">
                <div class="card text-white bg-info mb-3">
                    <div class="card-header">Cool Feature # @index</div>
                    <div class="card-body">
                        <p class="card-text">Here's my cool feature!</p>
                    </div>
                </div>
            </div>
        }
    }
    @if (Model.IsUberFeatureEnabled)
    {
        <div class="col-sm-4">
            <div class="card text-white bg-dark mb-3">
                <div class="card-header">Uber Feature</div>
                <div class="card-body">
                    <p class="card-text">Here's my uber feature!</p>
                </div>
            </div>
        </div>
    }
    @if (Model.IsSecretFeatureEnabled)
    {
        <div class="col-sm-4">
            <div class="card text-white bg-warning mb-3">
                <div class="card-header">Secret Feature</div>
                <div class="card-body">
                    <p class="card-text">Here's my secret feature!</p>
                </div>
            </div>
        </div>
    }
    </div>

Here’s what the rendered page looks like in the browser:

Screenshot

Summary

This is a simple example, but in larger projects with lots of configuration its nice to be able to quickly create and use your configuration settings classes without having to deal with the plumbing.

The package is available on NuGet.org. You can install it in your projects from Visual Studio by searching for the package DotNetNinja.AutoBoundConfiguration or install it from the command line with:

dotnet add package DotNetNinja.AutoBoundConfiguration

The source is available on GitHub @ https://github.com/DotNet-Ninja/DotNetNinja.AutoBoundConfiguration.