Running Postgres in Project Tye on Windows
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.