When to run a command in docker compose and when in dockerfile?

Viewed 259

I am somehow newbie in docker, so bear with me for a potentially stupid question.

From what I understood, if I want to have a running container and not an executable, you end it up with a "command". Okey.

So if what I want is a container serving a django app, I have to add something like:

python manage.py runserver 0.0.0.0:8000

Now the question is: Do we add this at the end of the dockerfile that defines the image?

Or do I add this command in the docker compose that uses the image, like this?

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
[...]
2 Answers

If something makes sense to put in a Dockerfile, then you should put it there (but not everything will make sense). Think about other ways you could run this container (docker run; putting it in a Kubernetes manifest) and similarly other environments you could run it in (where the database is maintained on a different host, for example). If something will basically always be the same every time you run the container, put it in the Dockerfile.

In the example you give, the image you're building is for a Django application. Whenever you run the image, regardless of context, you're probably always going to want to run the Django application, and with exactly that command line. So put in the Dockerfile

CMD ./manage.py runserver 0.0.0.0:8000

and do not supply a Compose command:, docker run command, Kubernetes command:, or other deploy-time setting.

Conversely, your underlying database storage will be different in each environment. So it makes sense to specify the database location using an environment variable or other setting, and include this in your deployment configuration.

# in a host development environment
export PGHOST=localhost
pipenv run ./manage.py runserver
# docker-compose.yml
version: '3.8'
services:
  db:
    image: postgres
  app:
    build: .
    environment:
      - PGHOST=db # (not a Dockerfile ENV)
    ports:
      - '8000:8000'

The one notable exception around command: is if you have an image that can do two things. Combining Django and Celery is a good example of this: both halves will share most of the same code base, so to run the Celery worker specifically you need to run the same image but with a different command.

version: '3.8'
services:
  redis:
    image: redis
  app:
    build: .
    environment: [REDIS_HOST=redis]
    ports: ['8000:8000']
  worker:
    build: .
    environment: [REDIS_HOST=redis]
    command: celery worker ...

You can create a sh file and trigger it from Dockerfile

boot-strap.sh

python manage.py runserver 0.0.0.0:8007

in Dockerfile:

...
ENTRYPOINT ["sh",".../boot-strap.sh"]

with this way, you can add other commands(e.g., python manage.py migrate ..)

Related