Container Registry and Runtime
Last updated 21 August 2017
Table of Contents
Support for deploying Docker-based apps is in beta. If you have questions or feedback, please file a ticket via Heroku Help.
Make sure you have a working Docker installation (eg.
docker ps) and that you’re logged in to Heroku (
Log in to the Heroku container registry:
$ heroku container:login
Get sample code by cloning an Alpine-based python example:
$ git clone https://github.com/heroku/alpinehelloworld.git
Navigate to the app’s directory and create a Heroku app:
$ heroku create Creating salty-fortress-4191... done, stack is cedar-14 https://salty-fortress-4191.herokuapp.com/ | https://git.heroku.com/salty-fortress-4191.git
Build the image and push to the Heroku container registry:
$ heroku container:push web
Now open the app in your browser:
$ heroku open
Logging in to the registry
Heroku runs a container registry on
If you are using the Heroku CLI, you can log in with:
$ heroku container:login
or directly via the Docker CLI:
$ docker login --username=_ --password=$(heroku auth:token) registry.heroku.com
Pushing an image(s)
Build an image and push
To build an image and push it to the Heroku container registry, make sure that your directory contains a Dockerfile. Then run:
$ heroku container:push <process-type>
Even if a process type is specified, a push to the registry will restart all processes. For example, if you specify
worker processes will also be restarted.
Pushing an existing image
To push an image to Heroku, such as one pulled from Docker Hub, tag it and push it according to this naming template:
$ docker tag <image> registry.heroku.com/<app>/<process-type> $ docker push registry.heroku.com/<app>/<process-type>
After the image has successfully been pushed, open your app:
$ heroku open -a <app>
Pushing multiple images
To push multiple images, rename your Dockerfiles using
$ ls -R ./webapp: Dockerfile.web ./worker: Dockerfile.worker ./image-processor: Dockerfile.image
Then, from the root directory of the project, run:
$ heroku container:push --recursive === Building web === Building worker === Building image === Pushing web === Pushing worker === Pushing image
This will build and push all 3 images. If you only want to push specific images, you can specify the process types:
$ heroku container:push web worker --recursive === Building web === Building worker === Pushing web === Pushing worker
Using a CI/CD platform
If you are using a third party CI/CD platform, you can push images to the registry. First authenticate with the following information:
- Registry URL:
your Heroku email address
your Heroku email address
your Heroku API key
Many CI/CD providers have documentation about how to build and push images to a Docker registry:
Dockerfile commands and runtime
When you push Docker images to the Heroku container registry for an app, those images are immediately released to the Heroku app. Docker images are the functional equivalent of slugs built with buildpacks. Docker images run in dynos the same way that slugs do, and under the same constraints:
- The web process must listen for HTTP traffic on
$PORT, which is set by Heroku.
Dockerfileis not respected, but can be used for local testing. Only HTTP requests are supported.
- Network linking of dynos is not supported.
- The filesystem is ephemeral.
- The working directory is
/. You can set a different directory using
ENV, for setting environment variables, is supported.
- We suggest using
ENVfor runtime variables (e.g.,
heroku configfor credentials, so that sensitive credentials aren’t accidentally checked into source code control.
- We suggest using
ENTRYPOINTis optional. If not set,
/bin/sh -cwill be used
CMDis required. If
CMDis missing, the registry will return an error
We strongly recommend testing images locally as a non-root user, as containers are not run with root privileges on Heroku.
Unsupported Dockerfile commands
VOLUME- Volume mounting is not supported. The filesystem of the dyno is ephemeral.
EXPOSEcan be used for local testing, it is not supported in Heroku’s container runtime. Instead your web process/code should get the $PORT environment variable.
STOPSIGNAL- The dyno manager will request that your processes shut down gracefully by sending them a SIGTERM signal followed by a SIGKILL signal.
STOPSIGNALis not respected.
SHELL- The default shell for Docker images is
/bin/sh, you can override with
HEALTHCHECKis not currently supported, the Heroku Dyno manager automatically checks the health of your running containers.
Testing an image locally
When testing an image locally there are a number of best practices. These best practices are implemented in this example Dockerfile.
Run the image as a non-root user
We strongly recommend testing images locally as a non-root user, as containers are not run with root privileges in Heroku. Immediately before
CMD you can add the following commands to your Dockerfile:
If using Alpine:
RUN adduser -D myuser USER myuser
If using Ubuntu:
RUN useradd -m myuser USER myuser
To confirm that your container is running as a non-root user, attach to a running container and then run the
$ docker exec <container-id> bash $ whoami myuser
When deployed to Heroku, we also run your container as a non-root user (although we do not use the
USER specified in the Dockerfile).
$ heroku run bash $ whoami U7729
Get the port from the environment variable
For testing purposes, we suggest that your
Dockerfile or code read from the $PORT environment variable, for example:
CMD gunicorn --bind 0.0.0.0:$PORT wsgi
When running a Docker container locally, you can set an environment variable using the -e flag:
$ docker run -p 5000:5000 -e PORT=5000 <image-name>
Setting multiple environment variables
When you use heroku locally, you can set config vars in a .env file. When
heroku local is run .env is read and each name/value pair is set in the environment. You can use this same .env file when using Docker:
$ docker run -p 5000:5000 --env-file .env <image-name>
We suggest adding the .env file to your .dockerignore file.
Take advantage of Docker Compose for multi-container applications
If you’ve created a multi-container application you can use Docker Compose to define your local development environment. Learn how to use Docker Compose for local development.
- More information on running a Docker image locally is available in Docker’s official documentation.
- Learn more about using Docker Compose for local development.
Both Cedar-14 and Heroku-16 are available as Docker images. However, you are free to use any base image you want – using a Heroku stack image is not required. If you chose to use a Heroku image we suggest Heroku-16, given it is much smaller than Cedar-14 (465.3 MB).
To use Heroku-16 as the base image in your
Known issues and limitations
- Heroku does not provide a hosted Docker build service; images must be built locally, using Docker Hub or using another hosted Docker build service. This means Heroku GitHub integration and review apps do not work out of the box.
- While Docker images are not subject to size restrictions (unlike slugs), they are subject to the dyno boot time restriction. As layer count/image size grows, so will dyno boot time.
- Promoting an application from staging to production in a Heroku pipeline will fail, yet appear to succeed.
- Release phase is not supported.
heroku forkwill fail. We do not plan on supporting
heroku runwill always use the Docker image of the web process type.