Search code examples
djangodockerheroku

Release phase with container registry on heroku runs container


I created simple project in Django with docker. According to heroku's documentation about release phase with container registry (https://devcenter.heroku.com/articles/container-registry-and-runtime#release-phase) I created a new app with postgres addon. To deploy app with docker I executed following commands:

heroku container:push web
heroku container:push release
heroku container:release web release

But after last command my terminal is blocked and it looks like release phase actually run a container.

Releasing images web,release to teleagh... done
Running release command...
[2019-12-30 21:22:00 +0000] [17] [INFO] Starting gunicorn 19.9.0
[2019-12-30 21:22:00 +0000] [17] [INFO] Listening at: http://0.0.0.0:5519 (17)
[2019-12-30 21:22:00 +0000] [17] [INFO] Using worker: sync
[2019-12-30 21:22:00 +0000] [27] [INFO] Booting worker with pid: 27

My goal is tu run django migrations before release. I would really apreciate any help.

Procfile:

release: python manage.py migrate

Dockerfile:

FROM python:3.7-slim

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PORT=8000
WORKDIR /app
ADD requirements.txt .
RUN pip install -r requirements.txt
RUN apt-get update && apt-get install -y curl
ADD . ./
RUN python manage.py collectstatic --noinput
CMD gunicorn --bind 0.0.0.0:$PORT teleagh.wsgi 

Solution

  • Procfile does not make effect when container deploy is used in heroku. If you want to set release phase command I can suggest two options that I have tested a lot:

    1. Create dedicated Dockerfile for each phase with extensions matching the phase name.

    Dockerfile.web

    FROM python:3.7-slim
    
    ENV PYTHONDONTWRITEBYTECODE 1
    ENV PYTHONUNBUFFERED 1
    ENV PORT=8000
    WORKDIR /app
    ADD requirements.txt .
    RUN pip install -r requirements.txt
    RUN apt-get update && apt-get install -y curl
    ADD . ./
    RUN python manage.py collectstatic --noinput
    CMD gunicorn --bind 0.0.0.0:$PORT teleagh.wsgi 
    

    Dockerfile.release

    FROM python:3.7-slim
    
    ENV PYTHONDONTWRITEBYTECODE 1
    ENV PYTHONUNBUFFERED 1
    ENV PORT=8000
    WORKDIR /app
    ADD requirements.txt .
    RUN pip install -r requirements.txt
    RUN apt-get update && apt-get install -y curl
    ADD . ./
    RUN python manage.py collectstatic --noinput
    CMD python manage.py migrate
    

    The deploying process will be looking the same like yours with one exception — push command must have additional argument --recursive. Moreover it is possible to push all containers in one command:

    heroku container:push web release --recursive
    heroku container:release web release
    

    2. Create a bash script to detect what phase is running in the container at the moment.

    start.sh

    #!/bin/bash
    
    if [ -z "$SSH_CLIENT" ] && [ -n "$HEROKU_EXEC_URL" ];
    then
        source <(curl --fail --retry 3 -sSL "$HEROKU_EXEC_URL")
    fi
    
    if [[ "$DYNO" =~ ^release.* ]];
    then
        set -e
        python3 manage.py migrate
    else
        exec gunicorn teleagh.wsgi  -b 0.0.0.0:${PORT} --reload --access-logfile -
    fi
    
    

    Then the only Dockerfile will be looking like:

    FROM python:3.7-slim
    
    ENV PYTHONDONTWRITEBYTECODE 1
    ENV PYTHONUNBUFFERED 1
    ENV PORT=8000
    WORKDIR /app
    ADD requirements.txt .
    RUN pip install -r requirements.txt
    RUN apt-get update && apt-get install -y curl
    ADD . ./
    RUN python manage.py collectstatic --noinput
    CMD ./start.sh 
    

    Hope this will be helpful