diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index b21668241..cfcde7fc1 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -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 ------------------------------------------- -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 .. _attach: https://aws.amazon.com/blogs/security/easily-replace-or-attach-an-iam-role-to-an-existing-ec2-instance-by-using-the-ec2-console/ diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 08b25f3bc..10217f661 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -87,31 +87,24 @@ This is the excerpt from your project's ``local.yml``: :: # ... postgres: - build: - context: . - dockerfile: ./compose/production/postgres/Dockerfile - volumes: - - local_postgres_data:/var/lib/postgresql/data - - local_postgres_data_backups:/backups + # ... 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 - ├── .local - │   ├── .django - │   └── .postgres - └── .production - ├── .caddy - ├── .django - └── .postgres + ├── .caddy + ├── .django + ├── .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 # ------------------------------------------------------------------------------ @@ -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. -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 @@ -184,6 +177,6 @@ Prerequisites: * ``use_docker`` 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 diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst index 60453b870..6fcdce661 100644 --- a/docs/project-generation-options.rst +++ b/docs/project-generation-options.rst @@ -91,7 +91,7 @@ use_travisci: Indicates whether the project should be configured to use `Travis CI`_. 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 is strongly encouraged). diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 9118f6c93..83159be56 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -54,7 +54,7 @@ def remove_pycharm_files(): def remove_docker_files(): - shutil.rmtree("compose") + shutil.rmtree("docker") file_names = ["local.yml", "production.yml", ".dockerignore"] for file_name in file_names: @@ -223,10 +223,10 @@ def set_flags_in_envs( celery_flower_user, debug=False, ): - local_django_envs_path = os.path.join(".envs", ".local", ".django") - production_django_envs_path = os.path.join(".envs", ".production", ".django") - local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres") - production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres") + local_django_envs_path = os.path.join(".envs", ".django.local") + production_django_envs_path = os.path.join(".envs", ".django") + local_postgres_envs_path = os.path.join(".envs", ".postgres.local") + production_postgres_envs_path = os.path.join(".envs", ".postgres") set_django_secret_key(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") -def remove_celery_compose_dirs(): - shutil.rmtree(os.path.join("compose", "local", "django", "celery")) - shutil.rmtree(os.path.join("compose", "production", "django", "celery")) +def remove_django_celery_docker_scripts(): + file_names = [ + "celerybeat", + "celeryworker", + "flower" + ] + for file_name in file_names: + os.remove(os.path.join("docker", "django", "scripts", file_name)) def main(): @@ -296,7 +301,7 @@ def main(): append_to_gitignore_file(".env") append_to_gitignore_file(".envs/*") 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": remove_gulp_files() @@ -320,7 +325,7 @@ def main(): if "{{ cookiecutter.use_celery }}".lower() == "n": remove_celery_app() if "{{ cookiecutter.use_docker }}".lower() == "y": - remove_celery_compose_dirs() + remove_django_celery_docker_scripts() if "{{ cookiecutter.use_travisci }}".lower() == "n": remove_dottravisyml_file() diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.caddy b/{{cookiecutter.project_slug}}/.envs/.caddy similarity index 100% rename from {{cookiecutter.project_slug}}/.envs/.production/.caddy rename to {{cookiecutter.project_slug}}/.envs/.caddy diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.django b/{{cookiecutter.project_slug}}/.envs/.django similarity index 100% rename from {{cookiecutter.project_slug}}/.envs/.production/.django rename to {{cookiecutter.project_slug}}/.envs/.django diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.django b/{{cookiecutter.project_slug}}/.envs/.django.local similarity index 100% rename from {{cookiecutter.project_slug}}/.envs/.local/.django rename to {{cookiecutter.project_slug}}/.envs/.django.local diff --git a/{{cookiecutter.project_slug}}/.envs/.local/.postgres b/{{cookiecutter.project_slug}}/.envs/.postgres similarity index 100% rename from {{cookiecutter.project_slug}}/.envs/.local/.postgres rename to {{cookiecutter.project_slug}}/.envs/.postgres diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.postgres b/{{cookiecutter.project_slug}}/.envs/.postgres.local similarity index 100% rename from {{cookiecutter.project_slug}}/.envs/.production/.postgres rename to {{cookiecutter.project_slug}}/.envs/.postgres.local diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile deleted file mode 100644 index e2e9e5f3c..000000000 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ /dev/null @@ -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"] diff --git a/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start b/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start deleted file mode 100644 index 4e2493f3b..000000000 --- a/{{cookiecutter.project_slug}}/compose/local/django/celery/beat/start +++ /dev/null @@ -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 diff --git a/{{cookiecutter.project_slug}}/compose/local/django/celery/flower/start b/{{cookiecutter.project_slug}}/compose/local/django/celery/flower/start deleted file mode 100644 index f0abae7ef..000000000 --- a/{{cookiecutter.project_slug}}/compose/local/django/celery/flower/start +++ /dev/null @@ -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}" diff --git a/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start b/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start deleted file mode 100644 index c8bc31d3a..000000000 --- a/{{cookiecutter.project_slug}}/compose/local/django/celery/worker/start +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o nounset - - -celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO diff --git a/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile deleted file mode 100644 index c32efb3ee..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM abiosoft/caddy:0.11.0 - -COPY ./compose/production/caddy/Caddyfile /etc/Caddyfile diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile deleted file mode 100644 index 68d72327f..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ /dev/null @@ -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"] diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start deleted file mode 100644 index def83076c..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o pipefail -set -o nounset - - -celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/flower/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/flower/start deleted file mode 100644 index f0abae7ef..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/flower/start +++ /dev/null @@ -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}" diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start deleted file mode 100644 index 10f0d20c5..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o pipefail -set -o nounset - - -celery -A {{cookiecutter.project_slug}}.taskapp worker -l INFO diff --git a/{{cookiecutter.project_slug}}/compose/production/django/start b/{{cookiecutter.project_slug}}/compose/production/django/start deleted file mode 100644 index 0ad39dfae..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/django/start +++ /dev/null @@ -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 diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile deleted file mode 100644 index eca29bada..000000000 --- a/{{cookiecutter.project_slug}}/compose/production/postgres/Dockerfile +++ /dev/null @@ -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 diff --git a/{{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile b/{{cookiecutter.project_slug}}/docker/caddy/Caddyfile similarity index 85% rename from {{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile rename to {{cookiecutter.project_slug}}/docker/caddy/Caddyfile index d36632e4b..6e95b5188 100644 --- a/{{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile +++ b/{{cookiecutter.project_slug}}/docker/caddy/Caddyfile @@ -1,5 +1,5 @@ www.{% raw %}{$DOMAIN_NAME}{% endraw %} { - redir https://{{cookiecutter.domain_name}} + redir https://{{ cookiecutter.domain_name }} } {% raw %}{$DOMAIN_NAME}{% endraw %} { diff --git a/{{cookiecutter.project_slug}}/docker/caddy/Dockerfile b/{{cookiecutter.project_slug}}/docker/caddy/Dockerfile new file mode 100644 index 000000000..fe2423a5d --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/caddy/Dockerfile @@ -0,0 +1,3 @@ +FROM abiosoft/caddy:0.11.0 + +COPY ./Caddyfile /etc/Caddyfile diff --git a/{{cookiecutter.project_slug}}/docker/django/Dockerfile b/{{cookiecutter.project_slug}}/docker/django/Dockerfile new file mode 100644 index 000000000..9075e4143 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/Dockerfile @@ -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} diff --git a/{{cookiecutter.project_slug}}/docker/django/scripts/celerybeat b/{{cookiecutter.project_slug}}/docker/django/scripts/celerybeat new file mode 100644 index 000000000..6c330a1fc --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/celerybeat @@ -0,0 +1,9 @@ +#!/bin/sh + +set -o errexit +set -o nounset + + +celery beat \ + --app={{ cookiecutter.project_slug }}.taskapp \ + --loglevel=INFO diff --git a/{{cookiecutter.project_slug}}/docker/django/scripts/celeryworker b/{{cookiecutter.project_slug}}/docker/django/scripts/celeryworker new file mode 100644 index 000000000..95b3d3a4a --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/celeryworker @@ -0,0 +1,9 @@ +#!/bin/sh + +set -o errexit +set -o nounset + + +celery worker \ + --app={{ cookiecutter.project_slug }}.taskapp \ + --loglevel=INFO diff --git a/{{cookiecutter.project_slug}}/docker/django/scripts/django b/{{cookiecutter.project_slug}}/docker/django/scripts/django new file mode 100644 index 000000000..9ce0e7995 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/django @@ -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 diff --git a/{{cookiecutter.project_slug}}/compose/local/django/start b/{{cookiecutter.project_slug}}/docker/django/scripts/django.local similarity index 87% rename from {{cookiecutter.project_slug}}/compose/local/django/start rename to {{cookiecutter.project_slug}}/docker/django/scripts/django.local index 921604dcb..3d6596d2f 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/start +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/django.local @@ -1,7 +1,6 @@ #!/bin/sh set -o errexit -set -o pipefail set -o nounset diff --git a/{{cookiecutter.project_slug}}/docker/django/scripts/entrypoint b/{{cookiecutter.project_slug}}/docker/django/scripts/entrypoint new file mode 100644 index 000000000..fc04a6299 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/entrypoint @@ -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 "$@" diff --git a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint b/{{cookiecutter.project_slug}}/docker/django/scripts/entrypoint.local similarity index 97% rename from {{cookiecutter.project_slug}}/compose/production/django/entrypoint rename to {{cookiecutter.project_slug}}/docker/django/scripts/entrypoint.local index 4845e343b..999f2d4e5 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/entrypoint +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/entrypoint.local @@ -1,7 +1,6 @@ #!/bin/sh set -o errexit -set -o pipefail set -o nounset @@ -17,9 +16,7 @@ export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES postgres_ready() { python << END import sys - import psycopg2 - try: psycopg2.connect( dbname="${POSTGRES_DB}", @@ -31,7 +28,6 @@ try: except psycopg2.OperationalError: sys.exit(-1) sys.exit(0) - END } until postgres_ready; do diff --git a/{{cookiecutter.project_slug}}/docker/django/scripts/flower b/{{cookiecutter.project_slug}}/docker/django/scripts/flower new file mode 100644 index 000000000..e18f2d5bc --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/django/scripts/flower @@ -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 diff --git a/{{cookiecutter.project_slug}}/docker/mailhog/Dockerfile b/{{cookiecutter.project_slug}}/docker/mailhog/Dockerfile new file mode 100644 index 000000000..cc9696659 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/mailhog/Dockerfile @@ -0,0 +1 @@ +FROM mailhog/mailhog:v1.0.0 diff --git a/{{cookiecutter.project_slug}}/docker/postgres/Dockerfile b/{{cookiecutter.project_slug}}/docker/postgres/Dockerfile new file mode 100644 index 000000000..e1cec0512 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/postgres/Dockerfile @@ -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/ diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh b/{{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/constants.sh similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/constants.sh rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/constants.sh diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh b/{{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/countdown.sh similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/countdown.sh rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/countdown.sh diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh b/{{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/messages.sh similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/messages.sh rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/messages.sh diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh b/{{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/yes_no.sh similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/_sourced/yes_no.sh rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/_sourced/yes_no.sh diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup b/{{cookiecutter.project_slug}}/docker/postgres/scripts/backup similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backup rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/backup diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups b/{{cookiecutter.project_slug}}/docker/postgres/scripts/backups similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/backups rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/backups diff --git a/{{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore b/{{cookiecutter.project_slug}}/docker/postgres/scripts/restore similarity index 100% rename from {{cookiecutter.project_slug}}/compose/production/postgres/maintenance/restore rename to {{cookiecutter.project_slug}}/docker/postgres/scripts/restore diff --git a/{{cookiecutter.project_slug}}/docker/redis/Dockerfile b/{{cookiecutter.project_slug}}/docker/redis/Dockerfile new file mode 100644 index 000000000..1717d54a8 --- /dev/null +++ b/{{cookiecutter.project_slug}}/docker/redis/Dockerfile @@ -0,0 +1 @@ +FROM redis:3.2 diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 366389320..2f07855aa 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -3,12 +3,16 @@ version: '3' volumes: local_postgres_data: {} local_postgres_data_backups: {} + local_redis_data: {} services: django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} build: context: . - dockerfile: ./compose/local/django/Dockerfile + dockerfile: ./docker/django/Dockerfile + args: + environment: local + cmd: /django.local image: {{ cookiecutter.project_slug }}_local_django depends_on: - postgres @@ -18,35 +22,14 @@ services: volumes: - .:/app env_file: - - ./.envs/.local/.django - - ./.envs/.local/.postgres + - ./.envs/.django.local + - ./.envs/.postgres.local ports: - "8000:8000" - command: /start - - 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 %} + entrypoint: /entrypoint.local + command: /django.local {%- if cookiecutter.use_celery == 'y' %} - redis: - image: redis:3.2 - celeryworker: <<: *django image: {{ cookiecutter.project_slug }}_local_celeryworker @@ -57,7 +40,7 @@ services: - mailhog {%- endif %} ports: [] - command: /start-celeryworker + command: /celeryworker celerybeat: <<: *django @@ -69,13 +52,34 @@ services: - mailhog {%- endif %} ports: [] - command: /start-celerybeat + command: /celerybeat flower: <<: *django image: {{ cookiecutter.project_slug }}_local_flower ports: - "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 %} diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index fd8388acb..5e557059e 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -3,67 +3,87 @@ version: '3' volumes: production_postgres_data: {} production_postgres_data_backups: {} + production_redis_data: {} production_caddy: {} services: django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} build: context: . - dockerfile: ./compose/production/django/Dockerfile + dockerfile: ./docker/django/Dockerfile + args: + environment: production + cmd: /django image: {{ cookiecutter.project_slug }}_production_django depends_on: - postgres - redis env_file: - - ./.envs/.production/.django - - ./.envs/.production/.postgres - command: /start + - ./.envs/.django + - ./.envs/.postgres + command: /django + {%- if cookiecutter.use_celery == 'y' %} - postgres: + celeryworker: + <<: *django build: 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 volumes: - production_postgres_data:/var/lib/postgresql/data - production_postgres_data_backups:/backups env_file: - - ./.envs/.production/.postgres + - ./.envs/.postgres + + redis: + build: ./docker/redis/ + volumes: + - production_redis_data:/data caddy: - build: - context: . - dockerfile: ./compose/production/caddy/Dockerfile + build: ./docker/caddy/ image: {{ cookiecutter.project_slug }}_production_caddy depends_on: - django volumes: - production_caddy:/root/.caddy env_file: - - ./.envs/.production/.caddy + - ./.envs/.caddy ports: - "0.0.0.0:80:80" - "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 %}