kopia lustrzana https://github.com/wagtail/bakerydemo
Add Dockerfile, docker-compose.yml, S3 uploaded media settings (configurable via the environment), Docker instructions, and a .travis.yml to build/test the Docker image.
rodzic
6eefd5f991
commit
6652c42d09
|
@ -0,0 +1,4 @@
|
|||
Dockerfile
|
||||
docker-compose.yml
|
||||
Procfile
|
||||
Vagrantfile
|
|
@ -12,7 +12,6 @@ bakerydemo/media/*
|
|||
bakerydemo/settings/local.py
|
||||
bakerydemodb
|
||||
__pycache__
|
||||
.*
|
||||
.vagrant/
|
||||
/.vagrant/
|
||||
/Vagrantfile.local
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- GREP_TIMEOUT=360
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -qy -o Dpkg::Options::="--force-confold" docker-engine coreutils
|
||||
|
||||
script:
|
||||
# Bring up the postgres, redis, and app containers
|
||||
- docker-compose up --build -d
|
||||
|
||||
- timeout $GREP_TIMEOUT grep -m 1 'Running migrations' <(docker-compose logs --follow app 2>&1)
|
||||
- timeout $GREP_TIMEOUT grep -m 1 'spawned uWSGI http 1' <(docker-compose logs --follow app 2>&1)
|
||||
- docker-compose run app /venv/bin/python /code/manage.py check
|
||||
|
||||
after_script:
|
||||
- docker-compose logs
|
||||
- docker images
|
|
@ -0,0 +1,44 @@
|
|||
FROM python:3.5-alpine
|
||||
|
||||
ADD requirements/ /requirements/
|
||||
RUN set -ex \
|
||||
&& apk add --no-cache --virtual .build-deps \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
libc-dev \
|
||||
musl-dev \
|
||||
linux-headers \
|
||||
pcre-dev \
|
||||
postgresql-dev \
|
||||
libjpeg-turbo-dev \
|
||||
&& pyvenv /venv \
|
||||
&& /venv/bin/pip install -U pip \
|
||||
&& LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "/venv/bin/pip install -r /requirements/production.txt" \
|
||||
&& runDeps="$( \
|
||||
scanelf --needed --nobanner --recursive /venv \
|
||||
| awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
|
||||
| sort -u \
|
||||
| xargs -r apk info --installed \
|
||||
| sort -u \
|
||||
)" \
|
||||
&& apk add --virtual .python-rundeps $runDeps \
|
||||
&& apk del .build-deps
|
||||
RUN apk add --no-cache postgresql-client
|
||||
RUN mkdir /code/
|
||||
WORKDIR /code/
|
||||
ADD . /code/
|
||||
EXPOSE 8000
|
||||
|
||||
# Add custom environment variables needed by Django or your settings file here:
|
||||
ENV DJANGO_SETTINGS_MODULE=bakerydemo.settings.production DJANGO_DEBUG=off
|
||||
|
||||
# uWSGI configuration (customize as needed):
|
||||
ENV UWSGI_VIRTUALENV=/venv UWSGI_WSGI_FILE=bakerydemo/wsgi_production.py UWSGI_HTTP=:8000 UWSGI_MASTER=1 UWSGI_WORKERS=2 UWSGI_THREADS=8 UWSGI_UID=1000 UWSGI_GID=2000
|
||||
|
||||
# Call collectstatic with dummy environment variables:
|
||||
RUN DATABASE_URL=postgres://none REDIS_URL=none /venv/bin/python manage.py collectstatic --noinput
|
||||
|
||||
# start uWSGI, using a wrapper script to allow us to easily add more commands to container startup:
|
||||
ENTRYPOINT ["/code/docker-entrypoint.sh"]
|
||||
CMD ["/venv/bin/uwsgi", "--http-auto-chunked", "--http-keepalive"]
|
2
Procfile
2
Procfile
|
@ -1,2 +1,2 @@
|
|||
release: yes "yes" | python manage.py migrate
|
||||
web: gunicorn bakerydemo.heroku_wsgi --log-file -
|
||||
web: uwsgi --http-socket=:$PORT --master --workers=2 --threads=8 --die-on-term --wsgi-file=bakerydemo/wsgi_production.py
|
||||
|
|
4
app.json
4
app.json
|
@ -4,7 +4,9 @@
|
|||
"repository": "https://github.com/wagtail/bakerydemo",
|
||||
"keywords": ["wagtail", "django"],
|
||||
"env": {
|
||||
"DJANGO_SETTINGS_MODULE": "bakerydemo.settings.heroku"
|
||||
"DJANGO_DEBUG": "off",
|
||||
"DJANGO_SETTINGS_MODULE": "bakerydemo.settings.production",
|
||||
"DJANGO_SECURE_SSL_REDIRECT": "on"
|
||||
},
|
||||
"scripts": {
|
||||
"postdeploy": "django-admin.py migrate && django-admin.py load_initial_data && echo 'from wagtail.wagtailimages.models import Rendition; Rendition.objects.all().delete()' | django-admin.py shell"
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import dj_database_url
|
||||
|
||||
from .base import *
|
||||
|
||||
|
||||
# Accept all hostnames, since we don't know in advance which hostname will be used for any given Heroku instance.
|
||||
# IMPORTANT: Set this to a real hostname when using this in production!
|
||||
# See https://docs.djangoproject.com/en/1.10/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = ['*', ]
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
# BASE_URL required for notification emails
|
||||
BASE_URL = 'http://localhost:8000'
|
||||
|
||||
db_from_env = dj_database_url.config(conn_max_age=500)
|
||||
DATABASES['default'].update(db_from_env)
|
||||
|
||||
# Simplified static file serving.
|
||||
# https://warehouse.python.org/project/whitenoise/
|
||||
|
||||
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
|
|
@ -0,0 +1,68 @@
|
|||
import os
|
||||
import dj_database_url
|
||||
import random
|
||||
import string
|
||||
|
||||
from .base import *
|
||||
|
||||
DEBUG = os.getenv('DJANGO_DEBUG', 'off') == 'on'
|
||||
|
||||
# DJANGO_SECRET_KEY *should* be specified in the environment. If it's not, generate an ephemeral key.
|
||||
if 'DJANGO_SECRET_KEY' in os.environ:
|
||||
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
|
||||
else:
|
||||
# Use if/else rather than a default value to avoid calculating this if we don't need it
|
||||
print("WARNING: DJANGO_SECRET_KEY not found in os.environ. Generating ephemeral SECRET_KEY.")
|
||||
SECRET_KEY = ''.join([random.SystemRandom().choice(string.printable) for i in range(50)])
|
||||
|
||||
# Make sure Django can detect a secure connection properly on Heroku:
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
# Redirect all requests to HTTPS
|
||||
SECURE_SSL_REDIRECT = os.getenv('DJANGO_SECURE_SSL_REDIRECT', 'off') == 'on'
|
||||
|
||||
# Accept all hostnames, since we don't know in advance which hostname will be used for any given Heroku instance.
|
||||
# IMPORTANT: Set this to a real hostname when using this in production!
|
||||
# See https://docs.djangoproject.com/en/1.10/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '*').split(';')
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
# BASE_URL required for notification emails
|
||||
BASE_URL = 'http://localhost:8000'
|
||||
|
||||
db_from_env = dj_database_url.config(conn_max_age=500)
|
||||
DATABASES['default'].update(db_from_env)
|
||||
|
||||
# Simplified static file serving.
|
||||
# https://warehouse.python.org/project/whitenoise/
|
||||
|
||||
MIDDLEWARE.append('whitenoise.middleware.WhiteNoiseMiddleware')
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
|
||||
if 'AWS_STORAGE_BUCKET_NAME' in os.environ:
|
||||
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
|
||||
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID', '')
|
||||
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY', '')
|
||||
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
|
||||
AWS_AUTO_CREATE_BUCKET = True
|
||||
|
||||
INSTALLED_APPS.append('storages')
|
||||
MEDIA_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers': ['console'],
|
||||
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
version: '2'
|
||||
|
||||
services:
|
||||
db:
|
||||
environment:
|
||||
POSTGRES_DB: app_db
|
||||
POSTGRES_USER: app_user
|
||||
POSTGRES_PASSWORD: changeme
|
||||
restart: always
|
||||
image: postgres:9.6
|
||||
expose:
|
||||
- "5432"
|
||||
redis:
|
||||
restart: always
|
||||
image: redis:3.0
|
||||
expose:
|
||||
- "6379"
|
||||
app:
|
||||
environment:
|
||||
DJANGO_SECRET_KEY: changeme
|
||||
DATABASE_URL: postgres://app_user:changeme@db/app_db
|
||||
REDIS_URL: redis://redis
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
links:
|
||||
- db:db
|
||||
- redis:redis
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
until psql $DATABASE_URL -c '\l'; do
|
||||
>&2 echo "Postgres is unavailable - sleeping"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
>&2 echo "Postgres is up - continuing"
|
||||
|
||||
if [ "$1" = '/venv/bin/uwsgi' ]; then
|
||||
/venv/bin/python manage.py migrate --noinput
|
||||
fi
|
||||
|
||||
if [ "x$DJANGO_LOAD_INITIAL_DATA" = 'xon' ]; then
|
||||
/venv/bin/python manage.py load_initial_data
|
||||
fi
|
||||
|
||||
exec "$@"
|
83
readme.md
83
readme.md
|
@ -26,7 +26,7 @@ Run the following commands:
|
|||
|
||||
```bash
|
||||
git clone git@github.com:wagtail/bakerydemo.git
|
||||
cd wagtaildemo
|
||||
cd bakerydemo
|
||||
vagrant up
|
||||
vagrant ssh
|
||||
# then, within the SSH session:
|
||||
|
@ -38,9 +38,39 @@ interface at [http://localhost:8000/admin/](http://localhost:8000/admin/).
|
|||
|
||||
Log into the admin with the credentials ``admin / changeme``.
|
||||
|
||||
Setup without Vagrant
|
||||
-----
|
||||
Don't want to set up a whole VM to try out Wagtail? No problem.
|
||||
Setup with Docker
|
||||
-----------------
|
||||
|
||||
### Dependencies
|
||||
* [Docker](https://docs.docker.com/engine/installation/)
|
||||
|
||||
### Installation
|
||||
Run the following commands:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:wagtail/bakerydemo.git
|
||||
cd bakerydemo
|
||||
docker-compose up --build -d
|
||||
docker-compose run app /venv/bin/python manage.py load_initial_data
|
||||
```
|
||||
|
||||
The demo site will now be accessible at [http://localhost:8000/](http://localhost:8000/) and the Wagtail admin
|
||||
interface at [http://localhost:8000/admin/](http://localhost:8000/admin/).
|
||||
|
||||
Log into the admin with the credentials ``admin / changeme``.
|
||||
|
||||
**Important:** This `docker-compose.yml` is configured for local testing only, and is not intended for production use.
|
||||
|
||||
### Debugging
|
||||
To tail the logs from the Docker containers in realtime, run:
|
||||
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
Local Setup
|
||||
-----------
|
||||
Don't want to set up a whole VM nor use Docker to try out Wagtail? No problem.
|
||||
|
||||
### Dependencies
|
||||
* [PIP](https://github.com/pypa/pip)
|
||||
|
@ -89,53 +119,40 @@ update in the browser. Once finished, click `View` to see the public site.
|
|||
|
||||
Log into the admin with the credentials ``admin / changeme``.
|
||||
|
||||
To prevent the demo site from regenerating a new Django `SECRET_KEY` each time Heroku restarts your site, you should set
|
||||
a `DJANGO_SECRET_KEY` environment variable in Heroku using the web interace or the [CLI](https://devcenter.heroku.com/articles/heroku-cli). If using the CLI, you can set a `SECRET_KEY` like so:
|
||||
|
||||
heroku config:set DJANGO_SECRET_KEY=changeme
|
||||
|
||||
To learn more about Heroku, read [Deploying Python and Django Apps on Heroku](https://devcenter.heroku.com/articles/deploying-python).
|
||||
|
||||
### Storing Wagtail Media Files on AWS S3
|
||||
|
||||
If you have deployed the demo site to Heroku, you may want to perform some additional setup. Heroku uses an
|
||||
[ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem). In laymen's terms, this means
|
||||
that uploaded images will disappear at a minimum of once per day, and on each application deployment. To mitigate this,
|
||||
you can host your media on S3.
|
||||
If you have deployed the demo site to Heroku or via Docker, you may want to perform some additional setup. Heroku uses an
|
||||
[ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem), and Docker-based hosting
|
||||
environments typically work in the same manner. In laymen's terms, this means that uploaded images will disappear at a
|
||||
minimum of once per day, and on each application deployment. To mitigate this, you can host your media on S3.
|
||||
|
||||
This documentation assumes that you have an AWS account, an IAM user, and a properly configured S3 bucket. These topics
|
||||
are outside of the scope of this documentation; the following [blog post](https://wagtail.io/blog/amazon-s3-for-media-files/)
|
||||
will walk you through those steps.
|
||||
|
||||
Next, you will need to add `django-storages` and `boto3` to `requirements/heroku.txt`.
|
||||
|
||||
Then you will need to edit `settings/heroku.py`:
|
||||
|
||||
INSTALLED_APPS.append('storages')
|
||||
|
||||
You will also need to add the S3 bucket and access credentials for the IAM user that you created.
|
||||
|
||||
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME', 'changeme')
|
||||
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID', 'changeme')
|
||||
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY', 'changeme')
|
||||
AWS_S3_CUSTOM_DOMAIN = '{}.s3.amazonaws.com'.format(AWS_STORAGE_BUCKET_NAME)
|
||||
|
||||
Next, you will need to set these values in the Heroku environment. The next steps assume that you have
|
||||
the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) installed and configured. You will
|
||||
execute the following commands to set the aforementioned environment variables:
|
||||
This demo site comes preconfigured with a production settings file that will enable S3 for uploaded media storage if
|
||||
``AWS_STORAGE_BUCKET_NAME`` is defined in the shell environment. All you need to do is set the following environment
|
||||
variables. If using Heroku, you will first need to install and configure the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli). Then, execute the following commands to set the aforementioned environment variables:
|
||||
|
||||
heroku config:set AWS_STORAGE_BUCKET_NAME=changeme
|
||||
heroku config:set AWS_ACCESS_KEY_ID=changeme
|
||||
heroku config:set AWS_SECRET_ACCESS_KEY=changeme
|
||||
|
||||
Do not forget to replace the `changeme` with the actual values for your AWS account.
|
||||
Do not forget to replace the `changeme` with the actual values for your AWS account. If you're using a different hosting
|
||||
environment, set the same environment variables there using the method appropriate for your environment.
|
||||
|
||||
Finally, we need to configure the `MEDIA_URL` as well as inform Django that we want to use `boto3` for the storage
|
||||
backend:
|
||||
|
||||
MEDIA_URL = 'https://{}/'.format(AWS_S3_CUSTOM_DOMAIN)'
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
||||
|
||||
Commit these changes and push to Heroku and you should now have persistent media storage!
|
||||
Once Heroku restarts your application or your Docker container is refreshed, you should have persistent media storage!
|
||||
|
||||
### Sending email from the contact form
|
||||
|
||||
The following setting in `base.py` and `heroku.py` ensures that live email is not sent by the demo contact form.
|
||||
The following setting in `base.py` and `production.py` ensures that live email is not sent by the demo contact form.
|
||||
|
||||
`EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'`
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
-r requirements/heroku.txt
|
||||
-r requirements/production.txt
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
-r base.txt
|
||||
# Additional dependencies for Heroku deployment
|
||||
dj-database-url==0.4.1
|
||||
gunicorn==19.6.0
|
||||
uwsgi==2.0.14
|
||||
psycopg2==2.6.2
|
||||
whitenoise==3.2.2
|
||||
boto==2.45.0
|
||||
django-storages==1.5.2
|
Ładowanie…
Reference in New Issue