Introduce unified Docker / Docker Compose infrastructure

This commit is contained in:
Nikita P. Shupeyko 2018-06-27 21:12:45 +03:00
parent 3ac9902670
commit 36535770d1
42 changed files with 225 additions and 267 deletions

View File

@ -46,7 +46,7 @@ You will probably also need to setup the Mail backend, for example by adding a `
Optional: Use AWS IAM Role for EC2 instance Optional: Use AWS IAM Role for EC2 instance
------------------------------------------- -------------------------------------------
If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it's safe to remove the ``AWS_ACCESS_KEY_ID`` AND ``AWS_SECRET_ACCESS_KEY`` from ``.envs/.production/.django``. To do it, create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. The role should assume, at minimum, the ``AmazonS3FullAccess`` permission. If you are deploying to AWS, you can use the IAM role to substitute AWS credentials, after which it's safe to remove the ``AWS_ACCESS_KEY_ID`` AND ``AWS_SECRET_ACCESS_KEY`` from ``.envs/.django``. To do it, create an `IAM role`_ and `attach`_ it to the existing EC2 instance or create a new EC2 instance with that role. The role should assume, at minimum, the ``AmazonS3FullAccess`` permission.
.. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html .. _IAM role: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
.. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ .. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/

View File

@ -87,31 +87,24 @@ This is the excerpt from your project's ``local.yml``: ::
# ... # ...
postgres: postgres:
build: # ...
context: .
dockerfile: ./compose/production/postgres/Dockerfile
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
env_file: env_file:
- ./.envs/.local/.postgres - ./.envs/.postgres.local
# ... # ...
The most important thing for us here now is ``env_file`` section enlisting ``./.envs/.local/.postgres``. Generally, the stack's behavior is governed by a number of environment variables (`env(s)`, for short) residing in ``envs/``, for instance, this is what we generate for you: :: The most important thing for us here now is ``env_file`` section enlisting ``./.envs/.postgres.local``. Generally, the stack's behavior is governed by a number of environment variables (`env(s)`, for short) residing in ``envs/``, for instance, this is what we generate for you: ::
.envs .envs
├── .local
│   ├── .django
│   └── .postgres
└── .production
├── .caddy ├── .caddy
├── .django ├── .django
└── .postgres ├── .django.local
├── .postgres
└── .postgres.local
By convention, for any service ``sI`` in environment ``e`` (you know ``someenv`` is an environment when there is a ``someenv.yml`` file in the project root), given ``sI`` requires configuration, a ``.envs/.e/.sI`` `service configuration` file exists. By convention, for any service ``sI`` in environment ``e`` (you know ``someenv`` is an environment when there is a ``someenv.yml`` file in the project root), given ``sI`` requires configuration, a ``.envs/.sI(.e)`` `service configuration` file exists.
Consider the aforementioned ``.envs/.local/.postgres``: :: Consider the aforementioned ``.envs/.postgres.local``: ::
# PostgreSQL # PostgreSQL
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -122,7 +115,7 @@ Consider the aforementioned ``.envs/.local/.postgres``: ::
The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs.
One final touch: should you ever need to merge ``.envs/production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: :: One final touch: should you ever need to merge ``.envs/*`` (except ``.envs/*.local``) in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: ::
$ python merge_production_dotenvs_in_dotenv.py $ python merge_production_dotenvs_in_dotenv.py
@ -184,6 +177,6 @@ Prerequisites:
* ``use_docker`` was set to ``y`` on project initialization; * ``use_docker`` was set to ``y`` on project initialization;
* ``use_celery`` was set to ``y`` on project initialization. * ``use_celery`` was set to ``y`` on project initialization.
By default, it's enabled both in local and production environments (``local.yml`` and ``production.yml`` Docker Compose configs, respectively) through a ``flower`` service. For added security, ``flower`` requires its clients to provide authentication credentials specified as the corresponding environments' ``.envs/.local/.django`` and ``.envs/.production/.django`` ``CELERY_FLOWER_USER`` and ``CELERY_FLOWER_PASSWORD`` environment variables. Check out ``localhost:5555`` and see for yourself. By default, it's enabled both in local and production environments (``local.yml`` and ``production.yml`` Docker Compose configs, respectively) through a ``flower`` service. For added security, ``flower`` requires its clients to provide authentication credentials specified as the corresponding environments' ``.envs/.django.local`` and ``.envs/.production/.django`` ``CELERY_FLOWER_USER`` and ``CELERY_FLOWER_PASSWORD`` environment variables. Check out ``localhost:5555`` and see for yourself.
.. _`Flower`: https://github.com/mher/flower .. _`Flower`: https://github.com/mher/flower

View File

@ -91,7 +91,7 @@ use_travisci:
Indicates whether the project should be configured to use `Travis CI`_. Indicates whether the project should be configured to use `Travis CI`_.
keep_local_envs_in_vcs: keep_local_envs_in_vcs:
Indicates whether the project's ``.envs/.local/`` should be kept in VCS Indicates whether the project's ``.envs/*.local`` should be kept in VCS
(comes in handy when working in teams where local environment reproducibility (comes in handy when working in teams where local environment reproducibility
is strongly encouraged). is strongly encouraged).

View File

@ -54,7 +54,7 @@ def remove_pycharm_files():
def remove_docker_files(): def remove_docker_files():
shutil.rmtree("compose") shutil.rmtree("docker")
file_names = ["local.yml", "production.yml", ".dockerignore"] file_names = ["local.yml", "production.yml", ".dockerignore"]
for file_name in file_names: for file_name in file_names:
@ -223,10 +223,10 @@ def set_flags_in_envs(
celery_flower_user, celery_flower_user,
debug=False, debug=False,
): ):
local_django_envs_path = os.path.join(".envs", ".local", ".django") local_django_envs_path = os.path.join(".envs", ".django.local")
production_django_envs_path = os.path.join(".envs", ".production", ".django") production_django_envs_path = os.path.join(".envs", ".django")
local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres") local_postgres_envs_path = os.path.join(".envs", ".postgres.local")
production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres") production_postgres_envs_path = os.path.join(".envs", ".postgres")
set_django_secret_key(production_django_envs_path) set_django_secret_key(production_django_envs_path)
set_django_admin_url(production_django_envs_path) set_django_admin_url(production_django_envs_path)
@ -252,9 +252,14 @@ def remove_envs_and_associated_files():
os.remove("merge_production_dotenvs_in_dotenv.py") os.remove("merge_production_dotenvs_in_dotenv.py")
def remove_celery_compose_dirs(): def remove_django_celery_docker_scripts():
shutil.rmtree(os.path.join("compose", "local", "django", "celery")) file_names = [
shutil.rmtree(os.path.join("compose", "production", "django", "celery")) "celerybeat",
"celeryworker",
"flower"
]
for file_name in file_names:
os.remove(os.path.join("docker", "django", "scripts", file_name))
def main(): def main():
@ -296,7 +301,7 @@ def main():
append_to_gitignore_file(".env") append_to_gitignore_file(".env")
append_to_gitignore_file(".envs/*") append_to_gitignore_file(".envs/*")
if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y": if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y":
append_to_gitignore_file("!.envs/.local/") append_to_gitignore_file("!.envs/*.local")
if "{{ cookiecutter.js_task_runner}}".lower() == "none": if "{{ cookiecutter.js_task_runner}}".lower() == "none":
remove_gulp_files() remove_gulp_files()
@ -320,7 +325,7 @@ def main():
if "{{ cookiecutter.use_celery }}".lower() == "n": if "{{ cookiecutter.use_celery }}".lower() == "n":
remove_celery_app() remove_celery_app()
if "{{ cookiecutter.use_docker }}".lower() == "y": if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_celery_compose_dirs() remove_django_celery_docker_scripts()
if "{{ cookiecutter.use_travisci }}".lower() == "n": if "{{ cookiecutter.use_travisci }}".lower() == "n":
remove_dottravisyml_file() remove_dottravisyml_file()

View File

@ -1,44 +0,0 @@
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev py-cffi \
# Translations dependencies
&& apk add gettext \
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
&& apk add postgresql-client
# Requirements are installed here to ensure they will be cached.
COPY ./requirements /requirements
RUN pip install -r /requirements/local.txt
COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r//' /entrypoint
RUN chmod +x /entrypoint
COPY ./compose/local/django/start /start
RUN sed -i 's/\r//' /start
RUN chmod +x /start
{% if cookiecutter.use_celery == "y" %}
COPY ./compose/local/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r//' /start-celeryworker
RUN chmod +x /start-celeryworker
COPY ./compose/local/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r//' /start-celerybeat
RUN chmod +x /start-celerybeat
COPY ./compose/local/django/celery/flower/start /start-flower
RUN sed -i 's/\r//' /start-flower
RUN chmod +x /start-flower
{% endif %}
WORKDIR /app
ENTRYPOINT ["/entrypoint"]

View File

@ -1,8 +0,0 @@
#!/bin/sh
set -o errexit
set -o nounset
rm -f './celerybeat.pid'
celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO

View File

@ -1,10 +0,0 @@
#!/bin/sh
set -o errexit
set -o nounset
celery flower \
--app={{cookiecutter.project_slug}}.taskapp \
--broker="${CELERY_BROKER_URL}" \
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"

View File

@ -1,7 +0,0 @@
#!/bin/sh
set -o errexit
set -o nounset
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO

View File

@ -1,3 +0,0 @@
FROM abiosoft/caddy:0.11.0
COPY ./compose/production/caddy/Caddyfile /etc/Caddyfile

View File

@ -1,54 +0,0 @@
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev py-cffi
RUN addgroup -S django \
&& adduser -S -G django django
# Requirements are installed here to ensure they will be cached.
COPY ./requirements /requirements
RUN pip install --no-cache-dir -r /requirements/production.txt \
&& rm -rf /requirements
COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r//' /entrypoint
RUN chmod +x /entrypoint
RUN chown django /entrypoint
COPY ./compose/production/django/start /start
RUN sed -i 's/\r//' /start
RUN chmod +x /start
RUN chown django /start
{% if cookiecutter.use_celery == "y" %}
COPY ./compose/production/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r//' /start-celeryworker
RUN chmod +x /start-celeryworker
RUN chown django /start-celeryworker
COPY ./compose/production/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r//' /start-celerybeat
RUN chmod +x /start-celerybeat
RUN chown django /start-celerybeat
COPY ./compose/production/django/celery/flower/start /start-flower
RUN sed -i 's/\r//' /start-flower
RUN chmod +x /start-flower
{% endif %}
COPY . /app
RUN chown -R django /app
USER django
WORKDIR /app
ENTRYPOINT ["/entrypoint"]

View File

@ -1,8 +0,0 @@
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO

View File

@ -1,10 +0,0 @@
#!/bin/sh
set -o errexit
set -o nounset
celery flower \
--app={{cookiecutter.project_slug}}.taskapp \
--broker="${CELERY_BROKER_URL}" \
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"

View File

@ -1,8 +0,0 @@
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO

View File

@ -1,9 +0,0 @@
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
python /app/manage.py collectstatic --noinput
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app

View File

@ -1,6 +0,0 @@
FROM postgres:{{ cookiecutter.postgresql_version }}
COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
&& rmdir /usr/local/bin/maintenance

View File

@ -0,0 +1,3 @@
FROM abiosoft/caddy:0.11.0
COPY ./Caddyfile /etc/Caddyfile

View File

@ -0,0 +1,46 @@
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
ARG environment
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev py-cffi \
&& [ "${environment}" != 'production' ] && apk add \
# Translations dependencies
gettext \
# and https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
postgresql-client
COPY ./requirements/ /app/requirements/
WORKDIR /app/
RUN [ "${environment}" = 'production' ] && pip --no-cache-dir install -r "./requirements/${environment}.txt" || pip install -r "./requirements/${environment}.txt"
RUN addgroup -S django \
&& adduser -S -g django django
COPY ./docker/django/scripts/ /scripts/
RUN [ "${environment}" = 'production' ] && find /scripts/ -type f -name '*.local' -exec rm -f {} \; || true
RUN chown --recursive django:django /scripts/
RUN find /scripts/ -type f -exec sed -i 's/\r//' {} \;
RUN chmod +x /scripts/*
RUN mv /scripts/* / \
&& rmdir /scripts/
COPY . /app/
RUN chown --recursive django:django /app/
USER django
ENTRYPOINT ["/entrypoint"]
ARG cmd
# See why we need ENV as well: https://stackoverflow.com/a/35562189
ENV cmd ${cmd}
CMD ${cmd}

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -o errexit
set -o nounset
celery beat \
--app={{ cookiecutter.project_slug }}.taskapp \
--loglevel=INFO

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -o errexit
set -o nounset
celery worker \
--app={{ cookiecutter.project_slug }}.taskapp \
--loglevel=INFO

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -o errexit
set -o nounset
python manage.py migrate
# TODO: runs so long that web dyno times out after 60 secs on Heroku
#python manage.py collectstatic --noinput
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app

View File

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
set -o errexit set -o errexit
set -o pipefail
set -o nounset set -o nounset

View File

@ -0,0 +1,12 @@
#!/bin/sh
set -o errexit
set -o nounset
# TODO: ? merge with -local somehow
# N.B. If only .env files supported variable expansion...
export CELERY_BROKER_URL="${REDIS_URL}"
exec "$@"

View File

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
set -o errexit set -o errexit
set -o pipefail
set -o nounset set -o nounset
@ -17,9 +16,7 @@ export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES
postgres_ready() { postgres_ready() {
python << END python << END
import sys import sys
import psycopg2 import psycopg2
try: try:
psycopg2.connect( psycopg2.connect(
dbname="${POSTGRES_DB}", dbname="${POSTGRES_DB}",
@ -31,7 +28,6 @@ try:
except psycopg2.OperationalError: except psycopg2.OperationalError:
sys.exit(-1) sys.exit(-1)
sys.exit(0) sys.exit(0)
END END
} }
until postgres_ready; do until postgres_ready; do

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -o errexit
set -o nounset
celery flower \
--app={{ cookiecutter.project_slug }}.taskapp \
--broker="${CELERY_BROKER_URL}" \
--loglevel=INFO

View File

@ -0,0 +1 @@
FROM mailhog/mailhog:v1.0.0

View File

@ -0,0 +1,7 @@
FROM postgres:{{ cookiecutter.postgresql_version }}
COPY ./scripts/ /usr/local/bin/scripts/
RUN find /usr/local/bin/scripts/ -type f -exec sed -i 's/\r//' {} \;
RUN chmod +x /usr/local/bin/scripts/*
RUN mv /usr/local/bin/scripts/* /usr/local/bin/ \
&& rmdir /usr/local/bin/scripts/

View File

@ -0,0 +1 @@
FROM redis:3.2

View File

@ -3,12 +3,16 @@ version: '3'
volumes: volumes:
local_postgres_data: {} local_postgres_data: {}
local_postgres_data_backups: {} local_postgres_data_backups: {}
local_redis_data: {}
services: services:
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
build: build:
context: . context: .
dockerfile: ./compose/local/django/Dockerfile dockerfile: ./docker/django/Dockerfile
args:
environment: local
cmd: /django.local
image: {{ cookiecutter.project_slug }}_local_django image: {{ cookiecutter.project_slug }}_local_django
depends_on: depends_on:
- postgres - postgres
@ -18,35 +22,14 @@ services:
volumes: volumes:
- .:/app - .:/app
env_file: env_file:
- ./.envs/.local/.django - ./.envs/.django.local
- ./.envs/.local/.postgres - ./.envs/.postgres.local
ports: ports:
- "8000:8000" - "8000:8000"
command: /start entrypoint: /entrypoint.local
command: /django.local
postgres:
build:
context: .
dockerfile: ./compose/production/postgres/Dockerfile
image: {{ cookiecutter.project_slug }}_production_postgres
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
env_file:
- ./.envs/.local/.postgres
{%- if cookiecutter.use_mailhog == 'y' %}
mailhog:
image: mailhog/mailhog:v1.0.0
ports:
- "8025:8025"
{%- endif %}
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
redis:
image: redis:3.2
celeryworker: celeryworker:
<<: *django <<: *django
image: {{ cookiecutter.project_slug }}_local_celeryworker image: {{ cookiecutter.project_slug }}_local_celeryworker
@ -57,7 +40,7 @@ services:
- mailhog - mailhog
{%- endif %} {%- endif %}
ports: [] ports: []
command: /start-celeryworker command: /celeryworker
celerybeat: celerybeat:
<<: *django <<: *django
@ -69,13 +52,34 @@ services:
- mailhog - mailhog
{%- endif %} {%- endif %}
ports: [] ports: []
command: /start-celerybeat command: /celerybeat
flower: flower:
<<: *django <<: *django
image: {{ cookiecutter.project_slug }}_local_flower image: {{ cookiecutter.project_slug }}_local_flower
ports: ports:
- "5555:5555" - "5555:5555"
command: /start-flower command: /flower
redis:
build: ./docker/redis/
volumes:
- local_redis_data:/data
{%- endif %}
postgres:
build: ./docker/postgres/
image: {{ cookiecutter.project_slug }}_production_postgres
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
env_file:
- ./.envs/.postgres.local
{%- if cookiecutter.use_mailhog == 'y' %}
mailhog:
build: ./docker/mailhog/
ports:
- "8025:8025"
{%- endif %} {%- endif %}

View File

@ -3,67 +3,87 @@ version: '3'
volumes: volumes:
production_postgres_data: {} production_postgres_data: {}
production_postgres_data_backups: {} production_postgres_data_backups: {}
production_redis_data: {}
production_caddy: {} production_caddy: {}
services: services:
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
build: build:
context: . context: .
dockerfile: ./compose/production/django/Dockerfile dockerfile: ./docker/django/Dockerfile
args:
environment: production
cmd: /django
image: {{ cookiecutter.project_slug }}_production_django image: {{ cookiecutter.project_slug }}_production_django
depends_on: depends_on:
- postgres - postgres
- redis - redis
env_file: env_file:
- ./.envs/.production/.django - ./.envs/.django
- ./.envs/.production/.postgres - ./.envs/.postgres
command: /start command: /django
{%- if cookiecutter.use_celery == 'y' %}
postgres: celeryworker:
<<: *django
build: build:
context: . context: .
dockerfile: ./compose/production/postgres/Dockerfile dockerfile: ./docker/django/Dockerfile
args:
environment: production
cmd: /celeryworker
image: {{ cookiecutter.project_slug }}_production_celeryworker
ports: []
command: /celeryworker
celerybeat:
<<: *django
build:
context: .
dockerfile: ./docker/django/Dockerfile
args:
environment: production
cmd: /celerybeat
image: {{ cookiecutter.project_slug }}_production_celerybeat
command: /celerybeat
flower:
<<: *django
build:
context: .
dockerfile: ./docker/django/Dockerfile
args:
environment: production
cmd: /flower
image: {{ cookiecutter.project_slug }}_production_flower
ports:
- "5555:5555"
command: /flower
{%- endif %}
postgres:
build: ./docker/postgres/
image: {{ cookiecutter.project_slug }}_production_postgres image: {{ cookiecutter.project_slug }}_production_postgres
volumes: volumes:
- production_postgres_data:/var/lib/postgresql/data - production_postgres_data:/var/lib/postgresql/data
- production_postgres_data_backups:/backups - production_postgres_data_backups:/backups
env_file: env_file:
- ./.envs/.production/.postgres - ./.envs/.postgres
redis:
build: ./docker/redis/
volumes:
- production_redis_data:/data
caddy: caddy:
build: build: ./docker/caddy/
context: .
dockerfile: ./compose/production/caddy/Dockerfile
image: {{ cookiecutter.project_slug }}_production_caddy image: {{ cookiecutter.project_slug }}_production_caddy
depends_on: depends_on:
- django - django
volumes: volumes:
- production_caddy:/root/.caddy - production_caddy:/root/.caddy
env_file: env_file:
- ./.envs/.production/.caddy - ./.envs/.caddy
ports: ports:
- "0.0.0.0:80:80" - "0.0.0.0:80:80"
- "0.0.0.0:443:443" - "0.0.0.0:443:443"
redis:
image: redis:3.2
{%- if cookiecutter.use_celery == 'y' %}
celeryworker:
<<: *django
image: {{ cookiecutter.project_slug }}_production_celeryworker
command: /start-celeryworker
celerybeat:
<<: *django
image: {{ cookiecutter.project_slug }}_production_celerybeat
command: /start-celerybeat
flower:
<<: *django
image: {{ cookiecutter.project_slug }}_production_flower
ports:
- "5555:5555"
command: /start-flower
{%- endif %}