Skip to content

Commit

Permalink
Database creation now happens inside docker entrypoint
Browse files Browse the repository at this point in the history
  • Loading branch information
francesco-ballarin committed Feb 12, 2024
1 parent 6d3d0e4 commit a3ced1e
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 93 deletions.
2 changes: 0 additions & 2 deletions .dockerignore

This file was deleted.

3 changes: 1 addition & 2 deletions docker/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.docker_container_id
.docker_postgres_data_directory
.docker_django_secret_key
.docker_postgres_password
.docker_secret_key
.docker_volume_id
23 changes: 15 additions & 8 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,27 @@ FROM debian:12
# also in the shell scripts stored in this directory.
MAINTAINER Francesco Ballarin <[email protected]>

ARG SECRET_KEY
ARG DJANGO_SECRET_KEY
ARG POSTGRES_PASSWORD

WORKDIR /root

RUN apt update -y -q && \
apt install -y -qq curl net-tools python3-pip sudo unzip vim wget

COPY . .

# Part 1: turing and its runtime dependencies
COPY patches patches
COPY turing turing

RUN apt install -y -qq postgresql postgresql-client postgresql-contrib && \
echo "$POSTGRES_PASSWORD\n$POSTGRES_PASSWORD" | passwd postgres

RUN bash patches/turing/apply_patches.sh && \
python3 -m pip install --break-system-packages -r turing/requirements.txt

RUN cat <<EOF >> /root/turing/Turing/settings.ini
RUN cat <<EOF > /root/turing/Turing/settings.ini
[settings]
SECRET_KEY=$SECRET_KEY
SECRET_KEY=$DJANGO_SECRET_KEY
DEBUG=False
DEV_MODE=False
ALLOWED_HOSTS=*
Expand All @@ -42,7 +43,7 @@ EOF
RUN cd turing && \
python3 manage.py collectstatic

# Part 2: test dependencies
# Part 2: turing and its test dependencies
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
apt update -y -q && \
Expand All @@ -56,5 +57,11 @@ RUN LATEST_STABLE_RELEASE=$(curl -sS https://googlechromelabs.github.io/chrome-f

RUN python3 -m pip install --break-system-packages -r turing/requirements-dev.txt

# The end: run server on docker container start
CMD service postgresql start && cd turing && python3 manage.py runserver 0.0.0.0:8080
# Part 3: mathrace-interaction
COPY mathrace_interaction mathrace_interaction

# Part 4: set up entrypoint that:
# * creates and initialize databases on first run,
# * starts the server
COPY docker/entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
21 changes: 8 additions & 13 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,19 @@ git clone --recurse-submodules https://github.com/dmf-unicatt/turing-dmf.git
```
cd turing-dmf/docker
```
2. Create a docker volume that will contain the database:
2. Create a secret key for `django` and a password for `postgresql`:
```
bash docker_create_volume.sh
bash docker_create_secrets.sh
```
3. Create a secret key for `django` and a password for `postgresql`:
3. Create a docker volume that will contain the database:
```
bash docker_create_secrets.sh
bash docker_create_volume.sh
```
4. Create a `turing-dmf:latest` docker image based on the current **Turing @ DMF** repository:
```
bash docker_create_image.sh
```
5. Create a database for **Turing**:
```
bash docker_create_database.sh
```
6. Create a docker container based on the current `turing-dmf:latest` docker image:
5. Create a docker container based on the current `turing-dmf:latest` docker image:
```
bash docker_create_container.sh
```
Expand All @@ -47,7 +43,7 @@ cd turing-dmf/docker
```
bash docker_start.sh
```
**Turing** will be available at `https://host-server:8080`.
**Turing** will be available at `https://host-server:8080`. The database will be initialized upon the first run.
3. Attach a terminal to the running docker container
```
bash docker_terminal.sh
Expand Down Expand Up @@ -75,7 +71,8 @@ bash docker_destroy_container.sh
```
Note that:
- the container must not be running in order to destroy it.
- the database will be preserved upon destroying the container.
- secrets will be preserved upon destroying the container, and must not be regenarated.
- database volume (including the database itself) will be preserved upon the destroying the container, and must not be regenerated.
3. Refresh the `turing-dmf:latest` docker image based on the updated **Turing @ DMF** repository:
```
bash docker_create_image.sh
Expand All @@ -84,5 +81,3 @@ bash docker_create_image.sh
```
bash docker_create_container.sh
```

Note that one must not run the command to create the docker volume containing the database, nor the command to create the database itself, since they are preserved upon destroying the former container.
5 changes: 1 addition & 4 deletions docker/docker_create_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ set -e
VOLUME_ID_FILE=".docker_volume_id"
VOLUME_ID=$(cat "${VOLUME_ID_FILE}")

POSTGRES_DATA_DIRECTORY_FILE=".docker_postgres_data_directory"
POSTGRES_DATA_DIRECTORY=$(cat "${POSTGRES_DATA_DIRECTORY_FILE}")

CONTAINER_ID_FILE=".docker_container_id"
if [[ -f "${CONTAINER_ID_FILE}" ]]; then
echo "A container already exists!"
Expand All @@ -25,6 +22,6 @@ else
docker network create --subnet=10.200.1.0/24 turing-dmf-network
# Start docker container on a fixed IP address. The corresponding mac address is generated following
# https://maclookup.app/faq/how-do-i-identify-the-mac-address-of-a-docker-container-interface
CONTAINER_ID=$(docker create --net turing-dmf-network --ip 10.200.1.23 --mac-address 02:42:0a:c8:01:17 -p 8080:8080 -v /tmp/shared-turing-dmf:/tmp/shared-turing-dmf -v ${VOLUME_ID}:${POSTGRES_DATA_DIRECTORY} -e DOCKERHOSTNAME=$(cat /etc/hostname) turing-dmf:latest)
CONTAINER_ID=$(docker create --net turing-dmf-network --ip 10.200.1.23 --mac-address 02:42:0a:c8:01:17 -p 8080:8080 -v /tmp/shared-turing-dmf:/tmp/shared-turing-dmf -v ${VOLUME_ID}:/mnt/postgres_data_directory -e DOCKERHOSTNAME=$(cat /etc/hostname) turing-dmf:latest)
echo ${CONTAINER_ID} > ${CONTAINER_ID_FILE}
fi
54 changes: 0 additions & 54 deletions docker/docker_create_database.sh

This file was deleted.

8 changes: 5 additions & 3 deletions docker/docker_create_image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ set -e
# Do not run any further if we are not connected to the internet
wget -q --spider https://www.google.com

SECRET_KEY_FILE=".docker_secret_key"
SECRET_KEY=$(cat "${SECRET_KEY_FILE}")
# Read in secrets
DJANGO_SECRET_KEY_FILE=".docker_django_secret_key"
DJANGO_SECRET_KEY=$(cat "${DJANGO_SECRET_KEY_FILE}")

POSTGRES_PASSWORD_FILE=".docker_postgres_password"
POSTGRES_PASSWORD=$(cat "${POSTGRES_PASSWORD_FILE}")

docker build --pull --build-arg SECRET_KEY=${SECRET_KEY} --build-arg POSTGRES_PASSWORD=${POSTGRES_PASSWORD} -t turing-dmf:latest -f Dockerfile ..
# Build image
docker build --pull --build-arg DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY} --build-arg POSTGRES_PASSWORD=${POSTGRES_PASSWORD} -t turing-dmf:latest -f Dockerfile ..
12 changes: 6 additions & 6 deletions docker/docker_create_secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

set -e

SECRET_KEY_FILE=".docker_secret_key"
if [[ -f "${SECRET_KEY_FILE}" ]]; then
echo "A secret key already exists!"
echo "If you want to destroy it and create a new one, please remove the ${SECRET_KEY_FILE} file"
DJANGO_SECRET_KEY_FILE=".docker_django_secret_key"
if [[ -f "${DJANGO_SECRET_KEY_FILE}" ]]; then
echo "A django secret key already exists!"
echo "If you want to destroy it and create a new one, please remove the ${DJANGO_SECRET_KEY_FILE} file"
exit 1
else
SECRET_KEY=$(cat /dev/urandom | tr -dc 'abcdefghijklmnopqrstuvwxyz0123456789!@#$^&*-_=+' | head -c 50; echo)
echo ${SECRET_KEY} > ${SECRET_KEY_FILE}
DJANGO_SECRET_KEY=$(cat /dev/urandom | tr -dc 'abcdefghijklmnopqrstuvwxyz0123456789!@#$^&*-_=+' | head -c 50; echo)
echo ${DJANGO_SECRET_KEY} > ${DJANGO_SECRET_KEY_FILE}
fi

POSTGRES_PASSWORD_FILE=".docker_postgres_password"
Expand Down
3 changes: 3 additions & 0 deletions docker/docker_start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ if [ "$( docker container inspect -f '{{.State.Running}}' ${CONTAINER_ID} )" ==
exit 1
else
docker start ${CONTAINER_ID}
# Entrypoint outputs are not reported to stdout, but logged: fetch them and print them to stdout, after waiting
# a reasonable amount of time for the entrypoint to be done
sleep 5 && docker logs --since "6s" --timestamps ${CONTAINER_ID}
fi
87 changes: 87 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/bash
# Copyright (C) 2024 by the Turing @ DMF authors
#
# This file is part of Turing @ DMF.
#
# SPDX-License-Identifier: AGPL-3.0-or-later

set -e

# Installed postgres version
POSTGRES_VERSION=15

# Get the value of docker build args from the settings file
POSTGRES_DATABASE_NAME=$(sed -n -e "s/^RDS_DB_NAME=//p" /root/turing/Turing/settings.ini)
if [[ "${POSTGRES_DATABASE_NAME}" != *"-db" ]]; then
echo "Expected database name ${POSTGRES_DATABASE_NAME} to end with -db"
exit 1
fi
POSTGRES_PASSWORD=$(sed -n -e "s/^RDS_PASSWORD=//p" /root/turing/Turing/settings.ini)

# Hardcode values of docker create args
POSTGRES_CLUSTER_NAME=${POSTGRES_DATABASE_NAME/-db/-cluster}
if [[ "${POSTGRES_CLUSTER_NAME}" != *"-cluster" ]]; then
echo "Expected cluster name ${POSTGRES_CLUSTER_NAME} to end with -cluster"
exit 1
fi
POSTGRES_CLUSTER_DATA_DIRECTORY=/mnt/postgres_data_directory

# Create a new postgres cluster with data directory that matches the volume mounted in docker_create_container.sh,
# if not already done previously
# Note that the marker file .postgres_cluster_created cannot be put in ${POSTGRES_CLUSTER_DATA_DIRECTORY},
# because the cluster needs to be re-created in every container. This is safe upon container destruction because
# postgres data direcory will not be cleared out when creating the cluster in a new container.
POSTGRES_CLUSTER_CREATED_FILE=/root/turing/.postgres_cluster_created
if [[ ! -f ${POSTGRES_CLUSTER_CREATED_FILE} ]]; then
echo "Creating a new postgres cluster"
pg_dropcluster ${POSTGRES_VERSION} main
pg_createcluster ${POSTGRES_VERSION} --datadir=${POSTGRES_CLUSTER_DATA_DIRECTORY} ${POSTGRES_CLUSTER_NAME} -- -E UTF8 --locale=C.utf8 --lc-messages=C
cp /etc/postgresql/${POSTGRES_VERSION}/${POSTGRES_CLUSTER_NAME}/*.conf ${POSTGRES_CLUSTER_DATA_DIRECTORY}/
touch ${POSTGRES_CLUSTER_CREATED_FILE}
else
echo "Reusing existing postgres cluster"
fi

# Start postgresql service
echo "Starting postgresql service"
service postgresql start

# Initialize an empty postgres database, if not already done previously
POSTGRES_DATABASE_INITIALIZED_FILE=${POSTGRES_CLUSTER_DATA_DIRECTORY}/.postgres_database_initialized
if [[ ! -f ${POSTGRES_DATABASE_INITIALIZED_FILE} ]]; then
echo "Initializing an empty postgres database"
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '${POSTGRES_PASSWORD}';"
sudo -u postgres createdb ${POSTGRES_DATABASE_NAME}
touch ${POSTGRES_DATABASE_INITIALIZED_FILE}
else
echo "Reusing existing postgres database"
fi

# Ask turing to initialize the django database, if not already done previously
DJANGO_DATABASE_MIGRATED_FILE=${POSTGRES_CLUSTER_DATA_DIRECTORY}/.django_database_migrated
if [[ ! -f ${DJANGO_DATABASE_MIGRATED_FILE} ]]; then
echo "Initializing django database"
cd /root/turing
python3 manage.py makemigrations
python3 manage.py makemigrations engine
python3 manage.py migrate
touch ${DJANGO_DATABASE_MIGRATED_FILE}
else
echo "Not initializing again django database"
fi

# Add a default administration user to the django database, if not already done previously
DJANGO_ADMIN_INITIALIZED_FILE=${POSTGRES_CLUSTER_DATA_DIRECTORY}/.django_admin_initialized
if [[ ! -f ${DJANGO_ADMIN_INITIALIZED_FILE} ]]; then
echo "Initialize the default django administrator user with username admin and password admin. Make sure to change both the username and the password as soon as possible!"
cd /root/turing
[email protected] DJANGO_SUPERUSER_USERNAME=admin DJANGO_SUPERUSER_PASSWORD=admin python3 manage.py createsuperuser --no-input
touch ${DJANGO_ADMIN_INITIALIZED_FILE}
else
echo "Not initializing again default django administrator"
fi

# Start the server
echo "Starting the server"
cd /root/turing
python3 manage.py runserver 0.0.0.0:8080
2 changes: 1 addition & 1 deletion patches/turing/apply_patches.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

set -e

if [[ ! -e "mathrace_interaction" || ! -e "patches" || ! -e "turing" ]]; then
if [[ ! -e "patches" || ! -e "turing" ]]; then
echo "This script must be run as 'bash patches/turing/apply_patches.sh' from the top level directory of the repository"
exit 1
fi
Expand Down

0 comments on commit a3ced1e

Please sign in to comment.