Skip to content

Commit 3b9430e

Browse files
committed
Add Dockerfile and docker-compose files.
- Still need to make a custom image for Caddy with our static assets in it.
1 parent ff3f506 commit 3b9430e

12 files changed

+344
-4
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.docker-data/

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ ENV/
103103
.idea/
104104

105105
config/settings/local.py
106+
caddy.env
106107
nerd_herder.env
107108
postgres.env
108109
.docker-data/

Caddyfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pspython.com {
2+
tls {$TLS_EMAIL}
3+
gzip
4+
root /var/www/nerd_herder/static
5+
proxy / nerd_herder:8080 {
6+
transparent
7+
}
8+
}

Caddyfile.dev

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
localhost:8080 {
2+
tls self_signed
3+
gzip
4+
root /var/www/nerd_herder/static
5+
proxy / nerd_herder:8080 {
6+
transparent
7+
}
8+
}

Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM python:3.6-slim
2+
3+
ENV PYTHONUNBUFFERED 1
4+
5+
WORKDIR /usr/src/nerd_herder
6+
7+
COPY requirements.txt .
8+
RUN pip install --no-cache-dir -r requirements.txt
9+
10+
COPY config ./config
11+
COPY manage.py .
12+
COPY nerd_herder ./nerd_herder
13+
COPY wait-for-it.sh .
14+
RUN python manage.py collectstatic --no-input
15+
EXPOSE 8080
16+
ENV DJANGO_SETTINGS_MODULE config.settings.docker
17+
18+
CMD [ "gunicorn", "config.wsgi", "-b", "0.0.0.0:8080" ]

config/settings/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
'django.contrib.sessions',
3838
'django.contrib.messages',
3939
'django.contrib.staticfiles',
40-
'debug_toolbar',
40+
'rest_framework',
4141
'nerd_herder',
4242
'nerd_herder.users',
4343
'nerd_herder.speakers',
@@ -54,7 +54,6 @@
5454
'django.contrib.auth.middleware.AuthenticationMiddleware',
5555
'django.contrib.messages.middleware.MessageMiddleware',
5656
'django.middleware.clickjacking.XFrameOptionsMiddleware',
57-
'debug_toolbar.middleware.DebugToolbarMiddleware',
5857
]
5958

6059
ROOT_URLCONF = 'config.urls'
@@ -135,5 +134,5 @@
135134
# Static files (CSS, JavaScript, Images)
136135
# https://docs.djangoproject.com/en/2.0/howto/static-files/
137136

138-
STATIC_ROOT = os.path.join(BASE_DIR, 'nerd_herder', 'static')
137+
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
139138
STATIC_URL = '/static/'

config/settings/docker.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from .base import *
2+
3+
DEBUG = False
4+
ALLOWED_HOSTS = ['*']
5+
6+
POSTGRES_HOST = os.environ.get('POSTGRES_HOST', 'postgres')
7+
POSTGRES_PORT = os.environ.get('POSTGRES_PORT', '5432')
8+
POSTGRES_USER = os.environ.get('POSTGRES_USER', 'postgres')
9+
POSTGRES_PASSWORD = os.environ.get('POSTGRES_PASSWORD')
10+
POSTGRES_DB = os.environ.get('POSTGRES_DB', 'nerd_herder')
11+
12+
DATABASES = {
13+
'default': {
14+
'ENGINE': 'django.db.backends.postgresql',
15+
'NAME': POSTGRES_DB,
16+
'USER': POSTGRES_USER,
17+
'PASSWORD': POSTGRES_PASSWORD,
18+
'HOST': POSTGRES_HOST,
19+
'PORT': POSTGRES_PORT,
20+
},
21+
}
22+
23+
REDIS_HOST = os.environ.get('REDIS_HOST', 'redis')
24+
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
25+
26+
CACHES = {
27+
'default': {
28+
'BACKEND': 'django_redis.cache.RedisCache',
29+
'LOCATION': f'redis://{REDIS_HOST}:{REDIS_PORT}/0',
30+
'OPTIONS': {
31+
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
32+
},
33+
},
34+
}

docker-compose.override.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3'
2+
services:
3+
postgres:
4+
environment:
5+
- POSTGRES_PASSWORD=nerd_herder
6+
volumes:
7+
- './.docker-data/postgresql/data:/var/lib/postgresql/data/'
8+
redis:
9+
image: 'redis:alpine'
10+
nerd_herder:
11+
build: .
12+
command: ['./wait-for-it.sh', 'postgres:5432', '--', 'python', 'manage.py', 'runserver',
13+
'0.0.0.0:8080']
14+
environment:
15+
- POSTGRES_USER=nerd_herder
16+
- POSTGRES_PASSWORD=nerd_herder
17+
volumes:
18+
- ./nerd_herder:/usr/src/nerd_herder/nerd_herder
19+
- ./config/:/usr/src/config
20+
depends_on:
21+
- redis
22+
- postgres
23+
links:
24+
- redis
25+
- postgres
26+
# TODO: Add service for react build. Probably don't need caddy that way though.
27+
reverse-proxy:
28+
image: abiosoft/caddy:0.11.0-no-stats
29+
restart: always
30+
depends_on:
31+
- nerd_herder
32+
links:
33+
- nerd_herder
34+
volumes:
35+
- './.docker-data/caddy:/root/.caddy'
36+
- './Caddyfile.dev:/etc/Caddyfile'
37+
ports:
38+
- '8080:8080'

docker-compose.prod.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
version: '3'
2+
services:
3+
postgres:
4+
env_file:
5+
- postgres.env
6+
volumes:
7+
- '/var/lib/postgresql/data:/var/lib/postgresql/data/'
8+
redis:
9+
image: 'redis:alpine'
10+
nerd_herder:
11+
image: 'path/to/nerd_herder/gitlab/image'
12+
command: python manage.py runserver 0.0.0.0:8080
13+
env_file:
14+
- nerd_herder.env
15+
links:
16+
- redis
17+
- postgres
18+
reverse-proxy:
19+
# TODO: make an image for caddy that uses the nerd_herder image as an intermediary to copy
20+
# static assets from. Should also copy static assets from frontend build.
21+
# nerd_herder static assets are stored in /usr/src/nerd_herder/static after collectstatic runs.
22+
image: abiosoft/caddy:0.11.0-no-stats
23+
restart: always
24+
env_file:
25+
- caddy.env
26+
links:
27+
- nerd_herder
28+
depends_on:
29+
- nerd_herder
30+
volumes:
31+
- '/var/lib/caddy:/root/.caddy'
32+
- './Caddyfile:/etc/Caddyfile'
33+
ports:
34+
- '80:80'
35+
- '443:443'

docker-compose.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: '3'
2+
services:
3+
postgres:
4+
image: postgres:latest
5+
restart: always
6+
environment:
7+
- POSTGRES_USER=nerd_herder
8+
- POSTGRES_DATABASE=nerd_herder
9+
- PGDATA=/var/lib/postgresql/data/pgdata
10+
redis:
11+
image: redis:alpine
12+
restart: always
13+
nerd_herder:
14+
build: .
15+
restart: always
16+
links:
17+
- redis
18+
- postgres

requirements.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
Django==2.0.1
2-
psycopg2==2.7.3.2
2+
django-redis==4.9.0
3+
djangorestframework==3.7.7
4+
gunicorn==19.8.1
5+
psycopg2-binary==2.7.4
36
pytest==3.3.2

wait-for-it.sh

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env bash
2+
# Use this script to test if a given TCP host/port are available
3+
4+
cmdname=$(basename $0)
5+
6+
echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
7+
8+
usage()
9+
{
10+
cat << USAGE >&2
11+
Usage:
12+
$cmdname host:port [-s] [-t timeout] [-- command args]
13+
-h HOST | --host=HOST Host or IP under test
14+
-p PORT | --port=PORT TCP port under test
15+
Alternatively, you specify the host and port as host:port
16+
-s | --strict Only execute subcommand if the test succeeds
17+
-q | --quiet Don't output any status messages
18+
-t TIMEOUT | --timeout=TIMEOUT
19+
Timeout in seconds, zero for no timeout
20+
-- COMMAND ARGS Execute command with args after the test finishes
21+
USAGE
22+
exit 1
23+
}
24+
25+
wait_for()
26+
{
27+
if [[ $TIMEOUT -gt 0 ]]; then
28+
echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
29+
else
30+
echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
31+
fi
32+
start_ts=$(date +%s)
33+
while :
34+
do
35+
if [[ $ISBUSY -eq 1 ]]; then
36+
nc -z $HOST $PORT
37+
result=$?
38+
else
39+
(echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
40+
result=$?
41+
fi
42+
if [[ $result -eq 0 ]]; then
43+
end_ts=$(date +%s)
44+
echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
45+
break
46+
fi
47+
sleep 1
48+
done
49+
return $result
50+
}
51+
52+
wait_for_wrapper()
53+
{
54+
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
55+
if [[ $QUIET -eq 1 ]]; then
56+
timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
57+
else
58+
timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
59+
fi
60+
PID=$!
61+
trap "kill -INT -$PID" INT
62+
wait $PID
63+
RESULT=$?
64+
if [[ $RESULT -ne 0 ]]; then
65+
echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
66+
fi
67+
return $RESULT
68+
}
69+
70+
# process arguments
71+
while [[ $# -gt 0 ]]
72+
do
73+
case "$1" in
74+
*:* )
75+
hostport=(${1//:/ })
76+
HOST=${hostport[0]}
77+
PORT=${hostport[1]}
78+
shift 1
79+
;;
80+
--child)
81+
CHILD=1
82+
shift 1
83+
;;
84+
-q | --quiet)
85+
QUIET=1
86+
shift 1
87+
;;
88+
-s | --strict)
89+
STRICT=1
90+
shift 1
91+
;;
92+
-h)
93+
HOST="$2"
94+
if [[ $HOST == "" ]]; then break; fi
95+
shift 2
96+
;;
97+
--host=*)
98+
HOST="${1#*=}"
99+
shift 1
100+
;;
101+
-p)
102+
PORT="$2"
103+
if [[ $PORT == "" ]]; then break; fi
104+
shift 2
105+
;;
106+
--port=*)
107+
PORT="${1#*=}"
108+
shift 1
109+
;;
110+
-t)
111+
TIMEOUT="$2"
112+
if [[ $TIMEOUT == "" ]]; then break; fi
113+
shift 2
114+
;;
115+
--timeout=*)
116+
TIMEOUT="${1#*=}"
117+
shift 1
118+
;;
119+
--)
120+
shift
121+
CLI=("$@")
122+
break
123+
;;
124+
--help)
125+
usage
126+
;;
127+
*)
128+
echoerr "Unknown argument: $1"
129+
usage
130+
;;
131+
esac
132+
done
133+
134+
if [[ "$HOST" == "" || "$PORT" == "" ]]; then
135+
echoerr "Error: you need to provide a host and port to test."
136+
usage
137+
fi
138+
139+
TIMEOUT=${TIMEOUT:-15}
140+
STRICT=${STRICT:-0}
141+
CHILD=${CHILD:-0}
142+
QUIET=${QUIET:-0}
143+
144+
# check to see if timeout is from busybox?
145+
# check to see if timeout is from busybox?
146+
TIMEOUT_PATH=$(realpath $(which timeout))
147+
if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
148+
ISBUSY=1
149+
BUSYTIMEFLAG="-t"
150+
else
151+
ISBUSY=0
152+
BUSYTIMEFLAG=""
153+
fi
154+
155+
if [[ $CHILD -gt 0 ]]; then
156+
wait_for
157+
RESULT=$?
158+
exit $RESULT
159+
else
160+
if [[ $TIMEOUT -gt 0 ]]; then
161+
wait_for_wrapper
162+
RESULT=$?
163+
else
164+
wait_for
165+
RESULT=$?
166+
fi
167+
fi
168+
169+
if [[ $CLI != "" ]]; then
170+
if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
171+
echoerr "$cmdname: strict mode, refusing to execute subprocess"
172+
exit $RESULT
173+
fi
174+
exec "${CLI[@]}"
175+
else
176+
exit $RESULT
177+
fi

0 commit comments

Comments
 (0)