I am new to docker and I was trying to create an Image for my Django application.
I have created the image using the following Dockerfile
FROM python:3.6-slim-buster
WORKDIR /app
COPY . /app
RUN pip install -r Requirements.txt
EXPOSE 8000
ENTRYPOINT ["python", "manage.py"]
CMD ["runserver", '0.0.0.0:8000']
The problem is when I run the image using
docker run -p 8000:8000 <image-tag>
I am unable to access the app in my localhost:8000
But if I run the container using the command
docker run -p 8000:8000 <image-tag> runserver 0.0.0.0:8000
I can see my app in localhost:8000
I think that you can use only Entrypoint command.
Try with:
FROM python:3.6-slim-buster
WORKDIR /app
COPY . /app
RUN pip install -r Requirements.txt
EXPOSE 8000
ENTRYPOINT ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Or you can write script file (entrypoint.sh) with the line. And maybe you can run makemigrations and migrations in the same file.
You need to change the single quotes to double quotes in your CMD line.
Let's play with this simplified Dockerfile:
FROM alpine
ENTRYPOINT ["echo", "python", "manage.py"]
CMD ["runserver", '0.0.0.0:8000']
Now build it and run it:
$ docker build .
...
Successfully built 24d598ae4182
$ docker run --rm 24d598ae4182
python manage.py /bin/sh -c ["runserver", '0.0.0.0:8000']
Docker is pretty picky on the JSON-array form of the CMD, ENTRYPOINT, and RUN commands. If something doesn't parse as a JSON array, it will silently fall back to treating it as a plain command, which will get implicitly wrapped in a /bin/sh -c '...' invocation. That's what you're seeing here.
If you edit my Dockerfile to have double quotes in the CMD line and rebuild the image, then you'll see
$ docker run --rm 58114fa1fdb4
python manage.py runserver 0.0.0.0:8000
and if you actually COPY code in, use a Python base image, and delete that debugging echo, that's the command you want to execute.
Related
I have simple django project with one html page and I try to deploy it with docker. My Dockerfile you can see below:
FROM python:3.10.9
ENV PYTHONUNBUFFERED 1
RUN mkdir /app
WORKDIR /app
COPY requirements.txt /app/
RUN pip install -r requirements.txt
COPY . /app/
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
I run my image with next command:
docker run -p 8000:8000 --rm 751aa7a2d66f
But when I open my browser the localhost with API 127.0.0.1:8000 doesn't work.
In the same time I run command docker ps and it shows the following:
docker ps result
What's the problem?
Thanks in advance for your help.
For your information I work on windows 7.
I tried to run docker run -p 127.0.0.1:8000:8000 --rm 751aa7a2d66f but it didn't help.
I also tried to change port of my local machine to 8001 with the same result.
You can run django with docker-compose.yml below:
version: '3'
services:
my_django_service:
build:
context: .
dockerfile: Dockerfile
command: 'python manage.py runserver 0.0.0.0:8000'
ports:
- 8000:8000
I would like to have Django's runserver command running when I call docker-compose up
Here is what I tried, firstly, my image is starting from a Python image customized following this dockerfile:
# Dockerfile
FROM python:3.8
MAINTAINER geoffroy
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Ports exposure
EXPOSE 8000
VOLUME /data
# Install dependancies
RUN apt-get update && apt-get install -y \
vim \
git \
&& rm -rf /var/lib/apt/lists/*
# Setup python dependancies
RUN git clone https://github.com/blondelg/auto.git
WORKDIR /auto
RUN cd /auto
RUN pip install --no-cache-dir -r requirements.txt
# Build the secret key generator
RUN echo "import random" > generate_key.py
RUN echo "print(''.join(random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789!#$^&*(-_=+)') for i in range(50)))" >> generate_key.py
# Setup environment configuration
RUN cp auto/config_sample.ini auto/config.ini
RUN sed -i "s/SECRET_KEY_PATTERN/$(python generate_key.py)/gI" auto/config.ini
RUN sed -i "s/django.db.backends.sqlite3/django.db.backends.mysql/gI" auto/config.ini
RUN sed -i 's|{BASE_DIR}/db.sqlite3|autodb|gI' auto/config.ini
RUN sed -i "s/USER_PATTERN/root/gI" auto/config.ini
RUN sed -i "s/PASSWORD_PATTERN/root/gI" auto/config.ini
RUN sed -i "s/HOST_PATTERN/database/gI" auto/config.ini
RUN sed -i "s/PORT_PATTERN/3306/gI" auto/config.ini
Then, I have my docker-compose.yml designed as follow:
# docker-compose.yml
version: "3"
services:
database:
image: mariadb
container_name: database
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=autodb
hostname: 'database'
runserver:
build: .
command: python /auto/manage.py runserver 0.0.0.0:8000
container_name: runserver
ports:
- "8000:8000"
depends_on:
- database
Then I run
docker-compose up --build -d
My two containers (runserver + database) are up but going to http://127.0.0.1:8000 returns an error page whereas I should have the Django start page.
Also, when I go into the container (docker exec -ti runserver bash) and when I run python manage.py runserver 0.0.0.0:8000, I can access to the Django start page through http://127.0.0.1:8000.
What could be wrong here?
In your Dockerfile, there is this line WORKDIR /auto. It means that you are already in the /auto folder. So, in your docker-compose file, you should say
python manage.py runserver 0.0.0.0:8000
Instead of /auto/manage.py.
Following this documentation https://docs.docker.com/compose/django/, Ifixed the way I was declaring volume in my docker-compose.yaml
volumes:
- .:/auto
I have been running an app without docker and have just added in Dockerfile and docker-compose.
The issue I am having is that after I successfuly build the app, runserver produces the below error when I run either that or migrate.
➜ app git:(master) sudo docker-compose run app sh -c "python manage.py runserver"
Error loading shared library libpython3.8.so.1.0: No such file or directory (needed by /usr/local/bin/python)
Error relocating /usr/local/bin/python: Py_BytesMain: symbol not found
failed to resize tty, using default size
%
➜ app git:(master) sudo docker-compose run app sh -c "python manage.py migrate"
Error loading shared library libpython3.8.so.1.0: No such file or directory (needed by /usr/local/bin/python)
Error relocating /usr/local/bin/python: Py_BytesMain: symbol not found
Dockerfile
FROM python:3.8-alpine
MAINTAINER realize-sec
ENV PYTHONUNBUFFERED 1
COPY requirements.txt /requirements.txt
RUN pip install -r requirements.txt
RUN mkdir /app
WORKDIR /app
COPY ./app /app
RUN adduser -D user
USER user
docker-compose.yml
version: "3"
services:
app:
build:
context: ""
ports:
- "8000:8000"
volumes:
- ./app:/app
command: >
sh -c "python manage.py runserver 0.0.0.0:8000"
What am I doing wrong that is causing this?
When I run without docker using python3 manage.py runserver it works fine.
Because I haven’t tested the build, I don’t know whether any of these things will help you to ultimately build your containers, however here are some observations to hopefully set you on the right path.
Your context is a null string and is usually a dot (.)
You typically finish the Dockerfile with the following command:
CMD [ "python3", "manage.py", "runserver", "0.0.0.0:8000" ]
So you can remove that from your compose file.
Other than that, on a more general note, although Alpine images are small, they are prone to breaking because of the additional dependencies and packages that you need to add/remove. You’re probably better off with going for the slim version overall. The original build will take a bit longer but it will be more manageable.
Also, if you’re running a modern version of Docker on your machine, then you can move the syntax version of the compose file to version 3.7 or 3.8, depending upon your version of Docker.
I've been trying to find the best method to handle setting up a Django project with Docker. But I'm somewhat confused as to how CMD and ENTRYPOINT function in relation to the compose commands.
When I first set the project up, I need to run createsuperuser and migrate for the database. I've tried using a script to run the commands as the entrypoint in my Dockerfile but it didn't seem to work consistently. I switched to the configuration shown below, where I overwrite the Dockerfile CMD with commands in my compose file where it is told to run makemigrations, migrate, and createsuperuser.
The issue I'm having is exactly how to set it up so that it does what I need. If I set a command (shown as commented out in the code) in my compose file it should overwrite the CMD in my Dockerfile from what I understand.
What I'm unsure of is whether or not I need to use ENTRYPOINT or CMD in my Dockerfile to achieve this? Since CMD is overwritten by my compose file and ENTRYPOINT isn't, wouldn't it cause problems if it was set to ENTRYPOINT, since it would try to run gunicorn a second time after the compose command is executed?
Would there be any drawbacks in this approach compared to using an entrypoint script?
Lastly, is there a general best practice approach to handling Django's setup commands when deploying a dockerized Django application? Or am I already doing what is typically done?
Here is my Dockerfile:
FROM python:3.6
LABEL maintainer x#x.com
ARG requirements=requirements/production.txt
ENV DJANGO_SETTINGS_MODULE=site.settings.production_test
WORKDIR /app
COPY manage.py /app/
COPY requirements/ /app/requirements/
RUN pip install -r $requirements
COPY config config
COPY site site
COPY templates templates
COPY logs logs
COPY scripts scripts
EXPOSE 8001
CMD ["/usr/local/bin/gunicorn", "--config", "config/gunicorn.conf", "--log-config", "config/logging.conf", "-e", "DJANGO_SETTINGS_MODULE=site.settings.production_test", "-w", "4", "-b", "0.0.0.0:8001", "site.wsgi:application"]
And my compose file (omitted the nginx and postgres sections as they are unnecessary to illustrate the issue):
version: "3.2"
services:
app:
restart: always
build:
context: .
dockerfile: Dockerfile.prodtest
args:
requirements: requirements/production.txt
#command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn --config gunicorn.conf --log-config loggigng.conf -e DJANGO_SETTINGS_MODULE=site.settings.production_test -W 4 -b 0.0.0.0:8000 site.wsgi"
container_name: dj01
environment:
- DJANGO_SETTINGS_MODULE=site.settings.production_test
- PYTHONDONTWRITEBYTECODE=1
volumes:
- ./:/app
- /static:/static
- /media:/media
networks:
- main
depends_on:
- db
I have the following entrypoint script that will attempt to do the migrate automatically on my Django project:
#!/bin/bash -x
python manage.py migrate --noinput || exit 1
exec "$#"
The only change that would need to happen to your Dockerfile is to ADD it and specify the ENTRYPOINT. I usually put these lines directly about the CMD instruction:
ADD docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod a+x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
(please note that the chmod is only necessary if the docker-entrypoint.sh file on in your build environment is not executable already)
I add || exit 1 so that the script will stop the container should the migrate fail for any reason. When starting your project via docker-compose, it's possible that the database may not be 100% ready to accept connections when this migrate command runs. Between the exit on error approach and the restart: always that you have in your docker-compose.yml already, this will handle that race condition properly.
Note that the -x option I specify for bash echoes out what bash is doing, which I find helpful for debugging my scripts. It can be omitted if you want less verbosity in the container logs.
Dockerfile:
...
ENTRYPOINT ["entrypoint.sh"]
CMD ["start"]
entrypoint.sh will be executed all the time whilst CMD will be the default argument for it (docs)
entrypoint.sh:
if ["$1" = "start"]
then
/usr/local/bin/gunicorn --config config/gunicorn.conf \
--log-config config/logging.conf ...
elif ["$1" = "migrate"]
# whatever
python manage.py migrate
fi
now it is possible to do something like
version: "3.2"
services:
app:
restart: always
build:
...
command: migrate # if needed
or
docker exec -it <container> bash -c entrypoint.sh migrate
Using Docker to install gunicorn, I am unable to to use the gunicorn command.
To start Django, I have this line in my docker-compose.yaml:
command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn myproject.wsgi -b 0.0.0.0:8000"
This results in bash: gunicorn: command not found
When I build the Docker images it says gunicorn has been successfully installed.
My Dockerfile looks like:
FROM python:3.5
ENV PYTHONUNBUFFERED 1
RUN mkdir /config
ADD requirements.txt /config/
RUN pip install -r /config/requirements.txt
RUN mkdir /src;
WORKDIR /src
I've been using this http://ruddra.com/2016/08/14/docker-django-nginx-postgres/ as a guide.
If you are finding that gunicorn doesn't exist it could be because
docker image may use a cached layer of the requirements.txt which doesn't have gunicorn in it as a dependency.
Therefore it will result in not installing gunicorn meanwhile specifying pip install gunicorn in a seperate RUN command will work.
Solution:
Build docker image without caching when edits have been made to requirements.txt
docker build --no-cache .