TL;DR;

If you want your data to stay around: Use named volumes, which Project Tye supports.

The longer version:

Project Tye is a new powerful developer tool currently being developed by Microsoft.

"Tye is a developer tool that makes developing, testing, and deploying microservices and distributed applications easier. Project Tye includes a local orchestrator to make developing microservices easier and the ability to deploy microservices to Kubernetes with minimal configuration."

It basically aims to simplify local development by making it possible to run both containers and your .NET Core projects via a single common tool. Like a combination of a docker-compose file and hitting F5 in Visual Studio. If you haven't tried it out, I really think you should give it a go.

So the great thing is that you can run all of your code and your dependencies within Project Tye. Either as dotnet projects or Docker containers. Starting them is as easy as running a single command: tye run.

The problem

So let's say you have a project that is dependent on Postgres 9.6, and you would like to run both your code and the Postgres container within Project Tye. No problem!

But, running Postgres in Docker on Windows has one little problem. Since database containers by default store their data within the container, and containers usually are ephemeral and will be disposed and recreated, we need a way of storing data outside of the container.

One way of doing this is to simply mount a directory on the host, your computer, and map that to the database containers internal storage directory. This way, all of that data will be stored safely on your computer, and will survive if the container is recreated. This would look something like this in Tye:

  # DON'T DO THIS. WILL NOT WORK. ✌️
  - name: postgres
    image: postgres:9.6
    env:
      - name: POSTGRES_USER
        value: postgres
      - name: POSTGRES_PASSWORD
        value: password
      - name: POSTGRES_DB
        value: postgres
    bindings:
      - port: 5432
    volumes:
      - source: postgres-storage
        target: /var/lib/postgresql/data

The idea here ☝️ is that we mount and map the local folder postgres-storage to the postgres container internal folder var/lib/postgresql/data. But! When we do that, we get the following error:

FATAL:  data directory "/var/lib/postgresql/data" has wrong ownership
HINT:  The server must be started by the user that owns the data directory.

A little bit of Googling shows us that it has to do with how the Postgres docker image works (or doesn't work) on Windows:

https://github.com/docker/for-win/issues/445
https://forums.docker.com/t/trying-to-get-postgres-to-work-on-persistent-windows-mount-two-issues/12456
https://forums.docker.com/t/data-directory-var-lib-postgresql-data-pgdata-has-wrong-ownership/17963/4

The suggested solution is to use Docker volumes instead of mounting a folder directly on your host.

"Volumes are the preferred mechanism for persisting data generated by and used by Docker containers"

So there you have it, I guess that is what we should use then.

If we were running Postgres in docker-compose, our compose file would look something like this:

version: '3'
services:
  postgres:
    image: postgres:9.6
    container_name: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=postgres
    volumes:
      - postgres-storage:/var/lib/postgresql/data
    ports:
      - 5432:5432

volumes:
  postgres-storage:
    external: true

Instead of mounting a directory on our host, we use a named volume (postgres-storage). We'd also have to create that volume first:

docker volume create --name postgres-storage -d local

Buuuuut. We're not using docker-compose anymore, we're using Tye. So what would be the equivalent?

The solution

  - name: postgres
    image: postgres:9.6
    env:
      - name: POSTGRES_USER
        value: postgres
      - name: POSTGRES_PASSWORD
        value: password
      - name: POSTGRES_DB
        value: postgres
    bindings:
      - port: 5432
    volumes:
      - name: postgres-storage
        target: /var/lib/postgresql/data

What's neat is that you don't have to manually create the named volume first, it will be taken care of automatically.

And that's it! I hope you found this post helpful.