18

So I am deploying django, postgress and nginx containers via docker-compose and I have an issue that I can't seem to figure out.

In order to resolve the following error in my Django app, I knew I just had to run a Django migration.

docker@postgres ERROR:  relation "accounts_myprofile" does not exist

In an attempt to run migrations, I tried:

docker-compose run web python manage.py makemigrations 
docker-compose run web python manage.py migrate

which returned the following:

Migrations for 'accounts':
  accounts/migrations/0001_initial.py:
    - Create model Entry
    - Create model MyProfile

Running migrations:
  No migrations to apply.

I was only able to successfully migrate from within the Django container, example:

docker exec -i -t 6dc97c6a305c /bin/bash
python manage.py makemigrations
python manage.py migrate

Although I have resolved the issue, I still don't understand why running the migrate via docker-compose run does not actually migrate anything. I'm hoping someone can maybe point me in the right direction on this.

Also, I don't know if this is a related issue or not, but when I run those docker-compose run web commands, they seem to be creating new containers that won't shutdown unless I manually stop them, docker-compose stop doesn't remove them.

CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                          PORTS                    NAMES
a7bb3c7106d1        accounts_web            "python manage.py che"   4 hours ago         Restarting (0) 41 minutes ago   8000/tcp                 accounts_web_run_62
ee19ca6cdf49        accounts_web            "python manage.py mig"   4 hours ago         Restarting (0) 43 minutes ago   8000/tcp                 accounts_web_run_60
2d87ee35de3a        accounts_web            "python manage.py mak"   4 hours ago         Restarting (0) 43 minutes ago   8000/tcp                 accounts_web_run_59
1c6143c13097        accounts_web            "python manage.py mig"   4 hours ago         Restarting (1) 44 minutes ago   8000/tcp                 accounts_web_run_58
6dc97c6a305c        b1cb7debb103              "python manage.py run"   3 days ago          Up 4 hours                      8000/tcp                 accounts_web_1

Note: Docker-compose stop will properly stop the container at the bottom (as it should), but the other container that were created by docker-compose run web python manage.py migrate, will need to be manually stopped.

my docker-compose

web:    
  restart: always
  build: ./web
  expose:
    - "8000"
  links:
    - postgres:postgres

  volumes:
    - /usr/src/app
    - /usr/src/app/static

  env_file: .env
  environment:
    DEBUG: 'true'
  command: python manage.py runserver 0.0.0.0:8000


postgres:
  restart: always
  image: kartoza/postgis:9.4-2.1
  ports:
    - "5432:5432"
  volumes:
    - pgdata:/var/lib/postgresql/data/
david
  • 6,303
  • 16
  • 54
  • 91

5 Answers5

46

docker-compose run creates new containers

You have already noticed the problem. When you use docker-compose run, a new container is created.

When you ran the first command (makemigrations), a new container was created, makemigrations ran, and the migration files were written to the (new) container's filesystem.

When you ran the second command (migrate), another new container was created. The migration ran, but it had nothing to do. That's because the migration files were not available - they were written in a different container than this new one.

You can solve this in a couple of ways.

Using docker-compose exec

First, you can do what you already did, but use docker-compose exec instead of run.

docker-compose exec web python manage.py makemigrations 
docker-compose exec web python manage.py migrate

exec will use the already-running container, rather than creating new containers.

Using an entrypoint script

Another option is to use an entrypoint script and run the migration there, before the server is started. This is the way to go if you'd prefer things to be more automatic.

Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

entrypoint.sh:

#!/bin/sh
python manage.py makemigrations
python manage.py migrate
exec "$@"

docker-compose.yml (under 'web'):

entrypoint: /entrypoint.sh

In this scenario, when the container starts, the entrypoint script will run, handle your migration, then hand off to the command (which in this case is Django runserver).

The new containers loop forever

As you noticed, the new containers stay running. That is normally unexpected, because you overrode the command with one that should exit (rather than stay running). However, in docker-compose.yml, you specified restart: always. So they will run the migration commands over and over, restarting each time the command exits.

Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
  • 2
    But I don't think it's a good idea to run the migrations automatically (e.g. sometimes Django asks whether you've renamed a model or not, which might break the automation) – Afshin Mehrabani Apr 28 '17 at 09:59
  • 1
    But if you use an entrypoint.sh file how can you do things like python manage.py createsuperuser, these commands are ignored – Jesus Almaral - Hackaprende Jul 15 '17 at 18:35
  • @JesusAlmaral You can do that in the entrypoint script too. But in that case you have to do it different from normal, because that command will expect input. See [this answer](https://stackoverflow.com/a/26091252/2449905) which might help with that task. – Dan Lowe Jul 15 '17 at 18:38
  • You can make the creation of the superuser a part of your migrations by writing a Data Migration, see [here](https://stackoverflow.com/questions/30027203/create-django-super-user-in-a-docker-container-without-inputting-password/53261943#53261943) @JesusAlmaral – Hendrik F Nov 30 '18 at 09:58
  • Are there any changes for 2019? I'm looking to do the same thing and am curious whether the answer might change. – Brian Jun 13 '19 at 15:43
3

Dan Lowe gave a very nice answer, but the entrypoint script was not working for me. The problem is that some "makemigrations" expect your input, for instance "yes"/"no".

You can complement Dan Lowe answer with:

python manage.py makemigrations --noinput

instead of

python manage.py makemigrations

(This works at least for simple "yes"/"no" questions)

Rexcirus
  • 2,459
  • 3
  • 22
  • 42
2

This awnser is a complement to Dan Lowe and Rexcirus responses.

To work well during de CodeBuild e Fargate I did some changes:

Dockefile:

COPY ./docker/entrypoint.sh /usr/local/bin/
COPY ./docker/entrypoint.sh /${projectName}/
# backwards compat
RUN ln -s usr/local/bin/entrypoint.sh /

ENTRYPOINT ["entrypoint.sh"]
CMD ["entrypoint.sh"]

./docker/entrypoint.sh

#!/bin/sh
python manage.py makemigrations --noinput
python manage.py migrate
python manage.py runserver 0.0.0.0:8000

Now everything is running OK.

0
python manage.py makemigrations

python manage.py migrate

#Crear usuario root

DJANGO_SUPERUSER_PASSWORD=*your-passwd* python manage.py createsuperuser --username *root* --email *youremail@gamil.com* --noinput
Syscall
  • 19,327
  • 10
  • 37
  • 52
0

I have resolved this bu changing directory "myProject" path in docker-compose.yml and DockerFile

in Docket File

Pull base image

FROM python:3.7

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set work directory
WORKDIR /myProject

# Install dependencies
COPY Pipfile Pipfile.lock /myProject/
RUN pip install pipenv && pipenv install --system

Copy project

COPY . /myProject/

in docker-compose.yml file

version: '3.7'

services:
  web:
    build: .
    command: python /myProject/manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/myProject
    ports:
      - 8000:8000