Init django app with docker-compose - python

I'm newbie in docker-compose and I have a docker with my django instance and a mysql database. I would like to create a self autoconfigured container which run a command only on the first docker run. In this command I would like to do the following tasks:
make initial database migrations
create the admin superuser
import a mysql backup into the database
After this the system should continue launching the django test webserver.
Are there any way to tell docker-compose to run a command just on it first run or are there any alternative in django to control if the system is already configured and updated?
In order to clarify here are my dockfile and docker-compose.yml:
FROM python:3.4
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
####################
version: '2'
services:
db:
image: "mysql:5.6"
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: xxxxxx
MYSQL_DATABASE: xxxxxx
MYSQL_USER: xxxxx
MYSQL_PASSWORD: xxxxxxx
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
Thanks.

Following the comments of #cricket_007, finally I have found a tricky solution to solve the problem. I have created a sh script for the database service and for my web service. Additionally I have created two version files in my folder, web_local.version and web_server.version.
The web_local.version has been added to my .gitignore because this file is used to storage the current app version.
The start_web.sh script is a simple script that compare if the folder contains a web_local.version file. In that case the project has been configured in the past and the script checks if the current app version is updated compared with the server version. In the case all is up to date simply run a webserver otherwise run a migrate to update the models and then run the webserver.
Here is the web_start.sh script for references:
#!/bin/bash
FILE="web_local.version"
if [ -f "$FILE" ];
then
echo "File $FILE exist."
if diff ./web_server.version ./web_local.version > /dev/null;
then
echo "model version up to date :)"
else
echo "model updated!!"
python manage.py migrate
cp ./web_server.version ./$FILE
fi
else
echo "File $FILE does not exist"
sleep 10 #added because the first time db take a long time to init and the script doesn't wait until db is finished
cp ./web_server.version ./$FILE
python manage.py migrate
fi
python manage.py runserver 0.0.0.0:8000
I suppose that there are more formal solutions but this solutions is functional for my case because it allows our team to maintain the same mock database and same models synced through git and we have a zero time configuration environment running just with one command.

Related

Dockerized Django app and MySQL with docker-compose using .env

I would to run my Django project into a Docker container with its Database on another Docker container inside a Bebian
When i run my docker container, I have some errors. Like : Lost connection to MySQL server during query ([Errno 104] Connection reset by peer).
This command mysql > SET GLOBAL log_bin_trust_function_creators = 1 is very important because database's Django user create trigger.
Morever, I use a .env file used same for create DB image to store DB user and password. This path is settings/.env.
My code:
docker-compose.yml:
version: '3.3'
services:
db:
image: mysql:8.0.29
container_name: db_mysql_container
environment:
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USER
MYSQL_PASSWORD: $DB_PASSWORD
MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
command: ["--log_bin_trust_function_creators=1"]
ports:
- '3306:3306'
expose:
- '3306'
api:
build: .
container_name: django_container
command: bash -c "pip install -q -r requirements.txt &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/app
ports:
- '8000:8000'
depends_on:
- db
Dockerfile :
# syntax=docker/dockerfile:1
FROM python:3.9.14-buster
ENV PYTHONUNBUFFERED=1
RUN mkdir /app
WORKDIR /app
COPY requirements.txt /app/
RUN pip install -r requirements.txt
ADD . /app/
How to start my Django project ? Is possible to start only the DB container ?
What command i need execute and what changes i need to make, I'm novice with Docker ! So if you help me, please explains your commands and actions !
You can find this project on my GitHub
Thank !
To run dockerized django project.
Simply you can run below command:
docker-compose run projectname bash -c "python manage.py createsuperuser"
Above command is used for to create superuser

Dockerize a Django app with a MySQL container

I have an app developed in Django (2.2.7) with python (3.8.0), Docker (19.03.5) and docker-compose (1.25.2) running in Windows 10 pro. I want to Dockerize it with changing the sqlite3 database for a MySQL database. I've already write this Dockerfile:
FROM python:3.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD . /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
RUN pip install mysqlclient
COPY . /code/
And this docker-compose.yml file:
version: '3'
services:
db:
image: mysql:5.7
ports:
- '3306:3306'
environment:
MYSQL_DATABASE: 'my-app-db'
MYSQL_USER: 'root'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
volumes:
- .setup.sql:/docker-entrypoint-initbd.d/setup.sql
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
links:
- db
Also I have change the default database configurations in settings.py for this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'my-app-db',
'USER': 'root',
'PASSWORD': 'password',
'HOST': 'db',
'PORT': 3306,
}
}
After all of this the docker compose works and the app starts, but the problem is that the tables in the database are not created. I've tried with these How do I add a table in MySQL using docker-compose, Seeding a MySQL DB for a Dockerized Django App or this Seeding a MySQL DB for a Dockerized Django App but I couldn't fix it yet.
How can I create the required tables in the MySQL db container while runing the docker-compose? Must I add every single table by hand or there is a way to do it from the django app automatically?
Thanks
Hi i think this answer helps you
##1.- Reset all your migrations
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete
##2.- See and apply your migrations again
python manage.py showmigrations
python manage.py makemigrations
python manage.py migrate
You should not reset your migrations unless you want to wipe all of the data completely and start over. Your migrations should exist beforehand. So if you dont mind about old migrations you can delete them and use python manage.py makemigrations and then proceed to following steps:
So if your applications starts at the moment, we need to update your docker-compose file in a way that it uses entrypoint.sh. An ENTRYPOINT allows you to configure a container that will run as an executable.
First things first, create your entrypoint.sh file on the same level as docker-compose.yaml.
Next, don't forget to add chmod +x entrypoint.sh so entrypoint can be executed
entrypoint.sh file:
#!/bin/bash
set -e
echo "${0}: running migrations."
python manage.py migrate --noinput
echo "${0}: collecting statics."
python manage.py collectstatic --noinput
python manage.py runserver 0.0.0.0:8000
Afterwards update your docker-compose.yaml file. Change your command line to:
command:
- /bin/sh
- '-c'
- '/code/entrypoint.sh'
Additionally you should store all of your pip requirements in requirements.txt file and in your Dockerfile you should run pip install -r requirements.txt
You can dump your pip requirements with a command pip freeze > requirements.txt

How to initialize a postgres container with data using .dump instead of .sql?

i've seen in the docs and many solution to initialize a postgres container with a database using an init.sql as mentioned in this question:
COPY init.sql /docker-entrypoint-initdb.d/10-init.sql
The problem is that my database data in .sql is to large(8GB). This makes the dump process to long and the file to heavy. I was trying to make something similar to this approach generating a .dump file with (540mb).
I have 2 containers to run my django project. A Dockerfile for my python environment and postgres image. My docker files are shown in the end of this question. So far i've managed to run the dump in my container with these steps:
I add my .dump file to my container in docker-compose
build my containers
Go inside my postgres container and execute a pg_restore command
to dump my database.
Then go to my python/django container to execute a migrate command.
And finally run server.
This works but its not automated. How can i automate this problem in my docker files so i don't need to execute these commands manually?
Bellow are my files and the commands i required to run my .dump file on postgres container:
generate and add ./project-dump/latest.dump to my project
docker-compose up -d web db #build containers
docker-compose exec db bash # go in my postgres container
pg_restore --verbose --clean --no-acl --no-owner -h {pg_container_name} -U postgres -d database_dev
exit # exit postgres container
docker-compose exec web bash # go in my python/django project container
./manage.py migrate # migrate database
./manage.py runserver 0.0.0.0:3000 #run server
Dockerfile:
FROM python:3.7.3-stretch
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
COPY init.sql /docker-entrypoint-initdb.d/10-init.sql
RUN python manage.py migrate
EXPOSE 3000
docker-compose.yaml
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_DB: database_dev
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
volumes:
- ./project-dump/:/var/www/html
web:
build: .
command: python3 manage.py runserver 0.0.0.0:3000
volumes:
- .:/django-docker
ports:
- "3000:3000"
depends_on:
- db
init.sql
CREATE DATABASE database_dev;
GRANT ALL PRIVILEGES ON DATABASE database_dev TO postgres;

docker-compose: Why is my python application being invoked here?

I've been scratching my head for a while with this. I have the following Dockerfile for my python application:
# Use an official Python runtime as a parent image
FROM frankwolf/rpi-python3
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
RUN chmod 777 docker-entrypoint.sh
# Install any needed packages specified in requirements.txt
RUN pip3 install --trusted-host pypi.python.org -r requirements.txt
# Run __main__.py when the container launches
CMD ["sudo", "python3", "__main__.py", "-debug"] # Not sure if I need sudo here
docker-compose file:
version: "3"
services:
mongoDB:
restart: unless-stopped
volumes:
- "/data/db:/data/db"
ports:
- "27017:27017"
- "28017:28017"
image: "andresvidal/rpi3-mongodb3:latest"
mosquitto:
restart: unless-stopped
ports:
- "1883:1883"
image: "mjenz/rpi-mosquitto"
FG:
privileged: true
network_mode: "host"
depends_on:
- "mosquitto"
- "mongoDB"
volumes:
- "/home/pi:/home/pi"
#image: "arkfreestyle/fg:v1.8"
image: "test:latest"
entrypoint: /app/docker-entrypoint.sh
restart: unless-stopped
And this what docker-entrypoint.sh looks like:
#!/bin/sh
if [ ! -f /home/pi/.initialized ]; then
echo "Initializing..."
echo "Creating .initialized"
# Create .initialized hidden file
touch /home/pi/.initialized
else
echo "Initialized already!"
sudo python3 __main__.py -debug
fi
Here's what I am trying to do:
(This stuff already works)
1) I need a docker image which runs my python application when I run it in a container. (this works)
2) I need a docker-compose file which runs 2 services + my python application, BUT before running my python application I need to do some initialization work, for this I created a shell script which is docker-entrypoint.sh. I want to do this initialization work ONLY ONCE when I deploy my application on a machine for the first time. So I'm creating a .initialized hidden file which I'm using as a check in my shell script.
I read that using entrypoint in a docker-compose file overwrites any old entrypoint/cmd given to the Dockerfile. So that's why in the else portion of my shell script I'm manually running my code using "sudo python3 main.py -debug", this else portion works fine.
(This is the main question)
In the if portion, I do not run my application in the shell script. I've tested the shell script itself separately, both if and else statements work as I expect, but when I run "sudo docker-compose up", the first time when my shell script hits the if portion it echoes the two statements, creates the hidden file and THEN RUNS MY APPLICATION. The console output appears in purple/pink/mauve for the application, while the other two services print their logs out in yellow and cyan. I'm not sure if the colors matter, but in the normal condition my application logs are always green, in fact the first two echoes "Initializing" and "Creating .initialized" are also green! so I thought I'd mention this detail. After those two echoes, my application mysteriously begins and logs console output in purple...
Why/how is my application being invoked in the if statement of the shell script?
(This is only happens if I run through docker-compose, not if I just run the shell script with sh docker-entrypoint.sh)
Problem 1
Using ENTRYPOINT and CMD at the same time has some strange effects.
Problem 2
This happens to your container:
It is started the first time. The .initialized file does not exist.
The if case is executed. The file is created.
The script and therefore the container ends.
The restart: unless-stopped option restarts the container.
The .initialized file exists now, the else case is run.
python3 __main__.py -debug is executed.
BTW the USER command in the Dockerfile or the user option in Docker Compose are better options than sudo.

Adding docker to django project: no such file or directory

I am trying to add docker support to an already existing django project. I have a Dockerfile, a docker-compose, and a gunicorn.sh which I use as a script to launch the whole things. That script works fine when I run it from my shell.
When I run:
docker-compose -f docker-compose.yml up
I get this error:
ERROR: for intranet_django_1 Cannot start service django: oci runtime error: container_linux.go:247: starting container process caused "exec: \"/srv/gunicorn.sh\": stat /srv/gunicorn.sh: no such file or directory"
What the hell am I doing wrong?
I am very much a docker n00b so any explanation would be most welcome.
The Dockerfile looks like so:
FROM python:3
ENV PYTHONUNBUFFERED 1
ENV DB_NAME unstable_intranet_django
ENV DB_USER django
ENV DB_PASSWORD ookookEEK
ENV DB_HOST db
ENV DB_PORT 3306
RUN groupadd -r django
RUN useradd -r -g django django
COPY ./requirements/requierments.txt /srv/
RUN pip install -U pip
RUN pip install -r /srv/requierments.txt
COPY ./intranet_site/ /srv
RUN chmod a+rx /srv/gunicorn.sh
RUN chown -R django:django /srv/
USER django
WORKDIR /srv
I am well aware that the passwords should not be set here and that a permanent volume with a file containing them is probably the best way to deal with it. However, I kinda want something working instead of spending hours fiddling with things and not being able to see anything run…
The docker-compose.yml looks like:
version: '3'
services:
db:
image: mariadb
environment:
- MYSQL_ROOT_PASSWORD=fubar
- MYSQL_USER=django
- MYSQL_PASSWORD=ookookEEK
- MYSQL_DATABASE=unstable_intranet_django
django:
build: .
command: /srv/gunicorn.sh
volumes:
- .:/srv
ports:
- "8000:8000"
depends_on:
- db
Finally, the gunicorn.sh file is:
#!/bin/bash
# -*- coding: utf-8 -*-
# Check if the database is alive or not.
python << END
from MySQLdb import Error
from MySQLdb import connect
from sys import exit
from time import sleep
retry=0
while True:
try:
conn = connect(db="$DB_NAME",
user="$DB_USER",
password="$DB_PASSWORD",
host="$DB_HOST",
port=$DB_PORT)
print("✔ DB $DB_NAME on $DB_HOST:$DB_PORT is up.")
break
except Error as err:
snooze = retry / 10.0
print("✖ DB $DB_NAME on $DB_HOST:$DB_PORT is unavailable "
"→ sleeping for {}…".format(snooze))
sleep(snooze)
retry += 1
exit(0)
END
# Set up log file.
log="./gunicorn.log"
date > ${log}
# Collectstatic
echo "Collecting static files." | tee -a ${log}
python manage.py collectstatic -v 3 --noinput >> ${log}
# Migrate database
echo "Doing database migration." | tee -a ${log}
python manage.py migrate -v 3 >> ${log}
# New shiny modern hip way:
echo "Running Gunicorn on ${HOSTNAME} …" | tee -a ${log}
gunicorn -b ${HOSTNAME}:8000 -w 2 intranet_site.wsgi | tee -a ${log}
To make things stranger:
; docker run -it intranet_web /bin/bash
django#ce7f641cc1c7:/srv$ ls -l gunicorn.sh
-rwxrwxr-x. 1 django django 1677 Jun 2 07:51 gunicorn.sh
django#ce7f641cc1c7:/srv$ ./gunicorn.sh
✖ DB unstable_intranet_django on 127.0.0.1:3306 is unavailable → sleeping for 0.0…
So running the script from the containers seems to work just fine…
I think you should have:
ADD . /srv/ instead of COPY ./intranet_site/ /srv
because ADD . /srv/ adds all the content of the directory in which you have the Dockerfile to the srv folder from container. So the COPY/ADD command should be used in the folder that contains the Dockerfile. And I suppose your Dockerfile is in this root directory of the project (alongside docker-compose.yml and gunicorn.sh).
You could also use COPY . /srv/ with the same effect.
Suspect the path shouldn't have a leading .:
command: /srv/gunicorn.sh

Categories