Search code examples
djangodockerdocker-composeseedingdocker-entrypoint

How do I prevent my script from being run every time a Docker container is brought up?


I would to run a script (populate my MySql Docker container) only when my docker containers are built. I'm running the following docker-compose.yml file, which contains a Django container.

version: '3'

services:
  mysql:
    restart: always
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: 'maps_data'
      # So you don't have to use root, but you can if you like
      MYSQL_USER: 'chicommons'
      # You can use whatever password you like
      MYSQL_PASSWORD: 'password'
      # Password for root access
      MYSQL_ROOT_PASSWORD: 'password'
    ports:
      - "3406:3406"
    volumes:
      - my-db:/var/lib/mysql

  web:
    restart: always
    build: ./web
    ports:           # to access the container from outside
      - "8000:8000"
    env_file: .env
    environment:
      DEBUG: 'true'
    command: /usr/local/bin/gunicorn maps.wsgi:application -w 2 -b :8000
    depends_on:
      - mysql

  apache:
    restart: always
    build: ./apache/
    ports:
      - "80:80"
    #volumes:
    #  - web-static:/www/static
    links:
      - web:web

volumes:
  my-db:

I have this web/Dockerfile

FROM python:3.7-slim

RUN apt-get update && apt-get install

RUN apt-get install -y libmariadb-dev-compat libmariadb-dev
RUN apt-get update \
    && apt-get install -y --no-install-recommends gcc \
    && rm -rf /var/lib/apt/lists/*

RUN python -m pip install --upgrade pip
RUN mkdir -p /app/

WORKDIR /app/

COPY requirements.txt requirements.txt
RUN python -m pip install -r requirements.txt

COPY entrypoint.sh /app/
COPY . /app/
RUN ["chmod", "+x", "/app/entrypoint.sh"]

ENTRYPOINT ["/app/entrypoint.sh"]

and these are the contents of my entrypoint.sh file

#!/bin/bash
set -e

python manage.py migrate maps
python manage.py loaddata maps/fixtures/country_data.yaml
python manage.py loaddata maps/fixtures/seed_data.yaml

exec "$@"

The issue is, when I repeatedly run "docker-compose up," the entrypoint.sh script is getting run with its commands. I would prefer the commands only get run when the docker container is first built but they seem to always get run when the container is restored. Is there any way to adjust what I have to achieve this?


Solution

  • An approach that I've used before is to wrap your loaddata calls in your own management command, which first checks if there's any data in the database, and if there is, doesn't do anything. Something like this:

    # your_app/management/commands/maybe_init_data.py
    
    from django.core.management import call_command
    from django.core.management.base import BaseCommand
    
    from address.models import Country
    
    class Command(BaseCommand):
    
        def handle(self, *args, **options):
            if not Country.objects.exists():
                self.stdout.write('Seeding initial data')
                call_command('loaddata', 'maps/fixtures/country_data.yaml')
                call_command('loaddata', 'maps/fixtures/seed_data.yaml')
    

    And then change your entrypoint script to:

    python manage.py migrate
    python manage.py maybe_init_data
    

    (Assumption here that you have a Country model - replace with a model that you do actually have in your fixtures.)