Skip to content

Commit

Permalink
Start Docker support (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankoegl committed Oct 9, 2014
1 parent 26386b4 commit 7cc9b96
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 19 deletions.
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.git
htdocs/media/logo
mygpo/settings_prod.py
*.pyc
*/*.pyc
*/*/*.pyc
*/*/*/*.pyc
41 changes: 41 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
FROM ubuntu:14.04
MAINTAINER Stefan Kögl <stefan@skoegl.net>

# use bash instead of built-in sh, because it does not support "source" during build
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

# install all packaged dependencies
RUN apt-get update && apt-get install -y \
git \
python2.7 \
python2.7-dev \
python-virtualenv \
libpq-dev \
libjpeg-dev \
zlib1g-dev \
libwebp-dev

# create log directories
RUN mkdir -p /var/log/gunicorn

# copy source
COPY . /srv/mygpo
WORKDIR /srv/mygpo

# run everything in a virtualenv
RUN virtualenv venv
RUN source venv/bin/activate

# install all runtime dependencies
RUN pip install \
-r /srv/mygpo/requirements.txt \
-r /srv/mygpo/requirements-setup.txt

# set up missing environment variables
ENTRYPOINT ["/srv/mygpo/bin/docker-env.sh"]

# default launch command
CMD ["gunicorn", "mygpo.wsgi:application", "-c", "gunicorn.conf.py"]

# HTTP port
EXPOSE 8000
17 changes: 17 additions & 0 deletions bin/docker-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
# Docker doesn't have a great way to set environment variables at startup.
# This scripts will set up some defaults.

# if a DATABSE_URL is provided from outside, use it
if [[ -z "$DATABASE_URL" ]]; then
# otherwise construct one using a linked "db" container
export DATABASE_URL="postgres://mygpo:mygpo@${DB_PORT_5432_TCP_ADDR}:5432/mygpo"
fi

# if not SECRET_KEY is provided from outside, create a random one
if [[ -z "$SECRET_KEY" ]]; then
export SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
fi

# Execute the commands passed to this script
exec "$@"
9 changes: 9 additions & 0 deletions contrib/init-db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE USER mygpo WITH PASSWORD 'mygpo';
ALTER USER mygpo CREATEDB; -- required for creating test database
CREATE DATABASE mygpo;
CREATE DATABASE test_mygpo;
GRANT ALL PRIVILEGES ON DATABASE mygpo to mygpo;
GRANT ALL PRIVILEGES ON DATABASE test_mygpo to mygpo;
ALTER DATABASE mygpo OWNER TO mygpo;
ALTER DATABASE test_mygpo OWNER TO mygpo;
ALTER ROLE mygpo SET statement_timeout = 5000;
14 changes: 3 additions & 11 deletions doc/dev/postgres-setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ PostgreSQL Setup

Use the following to set up a local PostgreSQL.

.. code-block:: sql
CREATE USER mygpo WITH PASSWORD 'mygpo';
ALTER USER mygpo CREATEDB; -- required for creating test database
CREATE DATABASE mygpo;
CREATE DATABASE test_mygpo;
GRANT ALL PRIVILEGES ON DATABASE mygpo to mygpo;
GRANT ALL PRIVILEGES ON DATABASE test_mygpo to mygpo;
ALTER DATABASE mygpo OWNER TO mygpo;
ALTER DATABASE test_mygpo OWNER TO mygpo;
ALTER ROLE mygpo SET statement_timeout = 5000;
.. literalinclude:: ../../contrib/init-db.sql
:language: sql
:linenos:
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Contents
publisher/index
api/index
dev/index
ops/index
Translator Documentation <http://wiki.gpodder.org/wiki/Translations>


Expand Down
106 changes: 106 additions & 0 deletions doc/ops/configuration.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
Configuration
=============

Configuration can be done through the following environment variables.

``DEBUG``
---------
Debug mode shows error pages, enables debug output, etc.


``DATABASE_URL``
----------------
DB connection string in the form of ``postgres://USER:PASSWORD@HOST:PORT/NAME``


``ACCOUNT_ACTIVATION_DAYS``
---------------------------
Number of days that newly registered users have time to activate their account.


``DEFAULT_FROM_EMAIL``
----------------------
Default sender address for outgoing emails. See `Django documentation
<https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DEFAULT_FROM_EMAIL>`__.


``SECRET_KEY``
--------------
See `Django documentation
<https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY>`__.


``GOOGLE_ANALYTICS_PROPERTY_ID``
--------------------------------
Setting a Google Analytics Property ID activates GA integration.


``DIRECTORY_EXCLUDED_TAGS``
---------------------------
A comma-separated list of tags that are excluded from the directory.


``FLICKR_API_KEY``
------------------
Setting a Flickr API key activates Flickr integration.


``MAINTENANCE``
---------------
Switches the site into a maintenance mode.


* ``PODCAST_SLUG_SUBSCRIBER_LIMIT``

* ``MIN_SUBSCRIBERS_CATEGORY``: minimum number of subscribers that a podcast
needs to "push" one of its categories to the top

* ``API_ACTIONS_MAX_NONBG``: maximum number of episode actions that the API
processes immediatelly before returning the response. Larger requests will
be handled in background.

* ``ADSENSE_CLIENT``

* ``ADSENSE_SLOT_BOTTOM``

* ``STAFF_TOKEN``: enabled access to staff-only areas with ?staff=<STAFF_TOKEN>

* ``FLATTR_KEY``

* ``FLATTR_SECRET``

* ``FLATTR_MYGPO_THING``: Flattr thing of the webservice. Will be flattr'd
when a user sets the "Auto-Flattr gpodder.net" option

* ``USER_AGENT``: The User-Agent string used for outgoing HTTP requests

* ``DEFAULT_BASE_URL``: Base URL of the website that is used if the actually
used parameters is not available. Request handlers, for example, can access
the requested domain. Code that runs in background can not do this, and
therefore requires a default value. This should be set to something like
``http://example.com``

* ``BROKER_URL`` Celery Broker URL

* ``CELERY_RESULT_BACKEND``

* ``CELERY_SEND_TASK_ERROR_EMAILS``

* ``SERVER_EMAIL``

* ``GOOGLE_CLIENT_ID``

* ``GOOGLE_CLIENT_SECRET``

* ``SUPPORT_URL``: URL where users of the site can get support

* ``ELASTICSEARCH_SERVER``

* ``ELASTICSEARCH_INDEX``

* ``ELASTICSEARCH_TIMEOUT``

* ``ACTIVATION_VALID_DAYS`` time for how long an activation is valid; after
that, an unactivated user will be deleted

* ``INTERNAL_IPS``
40 changes: 40 additions & 0 deletions doc/ops/docker.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Using Docker
============

mygpo can be run using `Docker <https://docker.com/>`_.


Database
--------

The image requires a PostgreSQL server, specified either via

* a `linked container <https://docs.docker.com/userguide/dockerlinks/>`_
called ``db`` containing a server with a database called ``mygpo``, a user
called ``mygpo`` with a password ``mygpo``.
* A ``DATABASE_URL`` environment variable (eg
``postgres://USER:PASSWORD@HOST:PORT/NAME``)


Elasticsearch
-------------


Redis
-----


Web Frontend
------------

The image exposes the web interface on port 8000.


Celery Worker
-------------


Celery Heartbeat
----------------


9 changes: 9 additions & 0 deletions doc/ops/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Operation Documentation
=======================


.. toctree::
:maxdepth: 1

configuration
docker
5 changes: 5 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ coverage:
clean:
find -name "*.pyc" -exec rm '{}' \;

docker-build:
sudo docker build -t="mygpo/web" .

docker-run:
sudo docker run --rm -p 8000:8000 --name web --link db:db -e SECRET_KEY=asdf mygpo/web

.PHONY: all help test clean unittest coverage

43 changes: 35 additions & 8 deletions mygpo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,28 @@
import os.path
import dj_database_url

def parse_bool(s):
""" parses a boolean setting """
if isinstance(s, bool):
return s
s = s.lower.strip()
return s not in ('n', 'no', 'false', '0', 'off')


def parse_int(s):
return int(str(s))


def parse_strlist(s):
return [item.strip() for item in s.split(',')]


BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#ChangedthewayURLpathsaredetermined
FORCE_SCRIPT_NAME=""

DEBUG = True
DEBUG = parse_bool(os.getenv('DEBUG', True))
TEMPLATE_DEBUG = DEBUG

ADMINS = ()
Expand Down Expand Up @@ -146,9 +162,12 @@
'couchdbkit',
)


TEST_RUNNER='mygpo.test.MygpoTestSuiteRunner'

ACCOUNT_ACTIVATION_DAYS = 7

ACCOUNT_ACTIVATION_DAYS = parse_int(os.getenv('ACCOUNT_ACTIVATION_DAYS', 7))


AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
Expand Down Expand Up @@ -187,14 +206,22 @@
CSRF_FAILURE_VIEW='mygpo.web.views.security.csrf_failure'


# The following entries should be set in settings_prod.py
DEFAULT_FROM_EMAIL = ''
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', '')


SECRET_KEY = os.getenv('SECRET_KEY', '')
GOOGLE_ANALYTICS_PROPERTY_ID=''
DIRECTORY_EXCLUDED_TAGS = ()
FLICKR_API_KEY = ''

MAINTENANCE = os.path.exists(os.path.join(BASE_DIR, 'MAINTENANCE'))

GOOGLE_ANALYTICS_PROPERTY_ID = os.getenv('GOOGLE_ANALYTICS_PROPERTY_ID', '')


DIRECTORY_EXCLUDED_TAGS = parse_strlist(os.getenv('DIRECTORY_EXCLUDED_TAGS', ''))


FLICKR_API_KEY = os.getenv('FLICKR_API_KEY', '')


MAINTENANCE = parse_bool(os.getenv('MAINTENANCE', False))


LOGGING = {
Expand Down

0 comments on commit 7cc9b96

Please sign in to comment.