Why & How: ASP.NET Core + Docker + Heroku + Postgres

  • Published on April 8, 2017

This website is powered by ASP.NET Core and Postgres running inside a Docker container hosted on Heroku as of this writing. Below are the why's and how's.


Why ASP.NET Core

In short: cross-platform & lightweight development.

I can code on my Linux desktop and my Windows surface. It's certainly a lot more cross-platform than the Ruby community. Heck, half the gems can't even be installed on Windows.

I was able to write all the components for this website using just Sublime Text and the command line:

  • A .NET Core friendly ORM (don't ask why)
  • The core logic contained in a .DLL project
  • The MVC controllers and views

Why Docker

Docker allows me to have a local environment that's (mostly) identical to the production environment.

Why Heroku

Easy deployment, cheap (enough).

Why Postgres

Cross-platform, the defacto supported database on Heroku, cheap (enough).


Developing ASP.NET Core with Docker

What I do is basically spin up a Docker node with:

  • A database container
  • A web container, with the /opt/app folder mapped to my source code folder.
  • Configure all this with a docker-compose.yml file (see below).
  • Run docker-compose run web bash. This puts me on the bash command line of the web container. From there, I can do my regular dotnet restore and dotnet watch run.
  • From the web container, I can reach the database container via "postgres://db"--you get the idea.
  • In the docker-compose file, I mapped port 5000 from the web container and ported 5432 to the same ports on my local machine. This means I can browse the web page I'm developing at "http://localhost:5000" and connect to Postgres via "localhost:5432".
  • By default, ASP.NET Core listens at "localhost:{PORT}". This means the web host can only be reached from within the machine or container it runs on. We want to change it to "{PORT}". That can be accomplished by setting the ASPNETCORE_URLS environment variable, or call UseUrl when setting up the web host.

Packaging as a Docker image

Microsoft has a comprehensive guide to packaging your .NET Core application using the runtime image (which is significantly smaller than the SDK image). In short:

  1. Configure your Dockerfile similar the Dockerfile below.
  2. Run dotnet restore then dotnet publish -c Release -o out to build your binaries.
  3. Run docker build -t <your-image-name> . to build the docker image with the binary output.

Pushing YOUR Docker image to Heroku

Heroku also has an official guide to deploy existing Docker images to its infrastructure. Follow the guide to install the Heroku CLI and sign into the container registry from the command line. These two final steps will get your container onto Heroku:

  • docker tag <your-image-name> registry.heroku.com/<heroky-app-name>/web
  • docker push registry.heroku.com/<heroky-app-name>/web

If your .NET Core application is a background/command line application, change the last part of the registry to "worker" instead of web.

Note: The first time pushing your docker image to Heroku might take a little while, since it's pushing the whole OS, the .NET Runtime, then your code, etc. Subsequent pushes will only push your code to the registry. The other layers (OS, .NET) are cached on Heroku.