first commit

pull/1/head
Andy 8 years ago
parent 143fd37cfb
commit 5df32939a6
Signed by: arno
GPG Key ID: 368DDA2E9A471EAC

@ -0,0 +1,54 @@
FROM debian:jessie
MAINTAINER "Andrey Arapov <andrey.arapov@nixaid.com>"
# To avoid problems with Dialog and curses wizards
ENV DEBIAN_FRONTEND noninteractive
# OS & Python env deps for taiga-back
RUN apt-get update -qq \
&& apt-get install -y -- build-essential binutils-doc autoconf flex \
bison libjpeg-dev libfreetype6-dev zlib1g-dev libzmq3-dev \
libgdbm-dev libncurses5-dev automake libtool libffi-dev curl git \
tmux gettext python3.4 python3.4-dev python3-pip libxml2-dev \
libxslt-dev libpq-dev virtualenv \
nginx \
&& rm -rf -- /var/lib/apt/lists/*
RUN pip3 install circus gunicorn
# Create taiga user
ENV USER taiga
ENV UID 1000
ENV GROUP www-data
ENV HOME /home/$USER
ENV DATA /usr/local/taiga
RUN useradd -u $UID -m -d $HOME -s /usr/sbin/nologin -g $GROUP $USER
RUN mkdir -p $DATA $DATA/media $DATA/static $DATA/logs /var/log/taiga \
&& chown -Rh $USER:$GROUP $DATA /var/log/taiga
# Install taiga-back
USER $USER
WORKDIR $DATA
RUN git clone -b stable https://github.com/taigaio/taiga-back.git $DATA/taiga-back \
&& virtualenv -p /usr/bin/python3.4 venvtaiga \
&& . venvtaiga/bin/activate \
&& cd $DATA/taiga-back \
&& pip3 install -r requirements.txt \
&& deactivate
# Install taiga-front (compiled)
RUN git clone -b stable https://github.com/taigaio/taiga-front-dist.git $DATA/taiga-front-dist
USER root
# Cleanups
RUN rm -f /etc/nginx/sites-enabled/default
# Copy template seeds
COPY seeds/*.tmpl /tmp/
VOLUME [ "$DATA/static", \
"$DATA/media" ]
COPY launch /
CMD /launch

@ -0,0 +1,200 @@
Taiga in Docker
===============
This container allows you to run [Taiga](https://taiga.io/) in a Docker
container.
What is Taiga?
--------------
Taiga is a project management application that can handle both simple and
complex projects for startups, software developers, and other target teams.
It tracks the progress of a project. Taiga's design is clean and elegant
design—something that is supposed to be "beautiful to look at all day long."
With Taiga, you can use either Kanban or Scrum template, or both. Backlogs are
shown as a running list of all features and User Stories added to the project.
Taiga integrates video conferencing functions with the use of third party
services from Talky.io and Appear.in. Group and private chat is done via HipChat.
Dockerfile
----------
The Dockerfile performs the following steps:
* install the OS & Python dependencies required to run Taiga Django backend.
* install nginx - to serve the content including static assests which Django
app should not be handling.
* install circus - a process & socket manager for the Python web application.
* install gunicorn - a Python Web Server Gateway Interface (WSGI) HTTP Server
to serve dynamic content.
* create taiga user for running circus & gunicorn.
* clone stable branches of the taiga backend and frontend.
* copy templates which will be then processed by the launch script when the
container starts.
Running Taiga
=============
I recommend to use Docker Compose for running the Taiga.
Docker Compose
--------------
Below is a docker compose file as example
docker-compose.yml
```
version: '2'
volumes:
postgres_data: {}
taiga_postgres: {}
taiga_static: {}
taiga_media: {}
networks:
backend: {}
services:
postgres:
# https://hub.docker.com/_/postgres/
image: postgres
networks:
- backend
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db:/docker-entrypoint-initdb.d:ro
env_file:
- ./postgres.env
- ./taiga-db.env
taiga:
# https://hub.docker.com/r/andrey01/taiga
image: andrey01/taiga
# build: .
networks:
- backend
ports:
- 80:80
volumes:
- taiga_static:/usr/local/taiga/static
- taiga_media:/usr/local/taiga/media
env_file:
- ./taiga.env
- ./taiga-db.env
environment:
- TZ=Europe/Amsterdam
depends_on:
- postgres
```
The following file is required so that Postgres will create taiga database that
is used by the Taiga backend.
db/init-taiga-db.sh
```
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE USER $TAIGA_DB_USER;
CREATE DATABASE $TAIGA_DB_NAME;
GRANT ALL PRIVILEGES ON DATABASE $TAIGA_DB_NAME TO $TAIGA_DB_USER;
ALTER USER $TAIGA_DB_USER WITH PASSWORD '$TAIGA_DB_PASSWORD';
EOSQL
```
The environment variables
-------------------------
This file will defines a superuser for Postgres.
postgres.env
```
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin
```
This file defines individual settings for Taiga.
taiga.env
```
GUNICORN_WORKERS=1
SITE_URI=http://taiga.mydomain.com
PUBLIC_REGISTER=true
ADMIN_EMAIL=admin@mydomain.com
NOREPLY_EMAIL=no-reply@mydomain.com
```
This file defines the database settings for Taiga.
taiga-db.env
```
TAIGA_DB_USER=taiga
TAIGA_DB_NAME=taiga
TAIGA_DB_PASSWORD=secretpassword
TAIGA_DB_HOST=postgres
TAIGA_DB_PORT=5432
```
Run the Taiga
```
docker-compose up -d taiga
```
Now you can access Taiga with your favorite Web Browser.
I recommend to run nginx reverse proxy in front of this container, so that
you could use TLS.
[Let's Encrypt](https://letsencrypt.org) project is now able to issue free
SSL/TLS certificates.
Maintenance
===========
Accessing the Taiga Database
----------------------------
You can access it using the docker compose or docker as follows
```
docker-compose run --rm postgres sh -c 'PGPASSWORD=$TAIGA_DB_PASSWORD exec psql -h "$TAIGA_DB_HOST" -U $TAIGA_DB_USER'
```
```
docker run -ti --rm --net taiga_backend --env-file taiga-db.env postgres sh -c 'PGPASSWORD=$TAIGA_DB_PASSWORD exec psql -h "$TAIGA_DB_HOST" -U $TAIGA_DB_USER'
```
Backup the database
-------------------
Below is an example of how you can make the Taiga PostgreSQL database backup
```
docker-compose run --rm postgres sh -c 'PGPASSWORD=$TAIGA_DB_PASSWORD exec pg_dump -h "$TAIGA_DB_HOST" -U $TAIGA_DB_USER $TAIGA_DB_NAME' > taiga-db.backup
```
To restore it
```
docker-compose run --rm postgres sh -c 'PGPASSWORD=$TAIGA_DB_PASSWORD exec psql -h "$TAIGA_DB_HOST" -U $TAIGA_DB_USER $TAIGA_DB_NAME' < taiga-db.backup
```
There are also volumes containing the data you might want to backup externally
```
$ docker volume ls
DRIVER VOLUME NAME
local taiga_taiga_postgres
local taiga_taiga_media
local taiga_taiga_static
local taiga_postgres_data
```
Useful links
------------
* [Docker Compose file reference](https://docs.docker.com/compose/compose-file/)
* [Taiga: Setup production environment](https://taigaio.github.io/taiga-doc/dist/setup-production.html)
* [Read Taiga upgrade notes](https://taigaio.github.io/taiga-doc/dist/upgrades.html)
* [How to upgrade Taiga](https://taigaio.github.io/taiga-doc/dist/upgrades.html)

@ -0,0 +1,8 @@
TODO
====
* make sure Taiga sends emails, e.g. new user registered, password reset,
general Taiga notifications
* enable Async tasks (leverage RabbitMQ, redis and the Taiga-events websocket
server)

@ -0,0 +1,9 @@
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE USER $TAIGA_DB_USER;
CREATE DATABASE $TAIGA_DB_NAME;
GRANT ALL PRIVILEGES ON DATABASE $TAIGA_DB_NAME TO $TAIGA_DB_USER;
ALTER USER $TAIGA_DB_USER WITH PASSWORD '$TAIGA_DB_PASSWORD';
EOSQL

@ -0,0 +1,42 @@
version: '2'
volumes:
postgres_data: {}
taiga_postgres: {}
taiga_static: {}
taiga_media: {}
networks:
backend: {}
services:
postgres:
# https://hub.docker.com/_/postgres/
image: postgres
networks:
- backend
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db:/docker-entrypoint-initdb.d:ro
env_file:
- ./postgres.env
- ./taiga-db.env
taiga:
# https://hub.docker.com/r/andrey01/taiga
image: andrey01/taiga
# build: .
networks:
- backend
ports:
- 80:80
volumes:
- taiga_static:/usr/local/taiga/static
- taiga_media:/usr/local/taiga/media
env_file:
- ./taiga.env
- ./taiga-db.env
environment:
- TZ=Europe/Amsterdam
depends_on:
- postgres

@ -0,0 +1,65 @@
#!/bin/bash
# Debug
# set -x
# Do Not Change these variables unless you know what you are doing
export ESC=$
export DJANGO_SECRET_KEY=$(openssl rand -hex 32)
# Default variables. These shall be overridden :-)
export GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
export SITE_URI=${SITE_URI:-http://example.com}
export SITE_FQDN=$(echo $SITE_URI | sed -e "s/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/")
[ "${SITE_URI::5}" == "https" ] && SITE_SCHEME="https" || SITE_SCHEME="http"
export SITE_SCHEME
[ ${PUBLIC_REGISTER,,} == "false" ] \
&& { PUBLIC_REGISTER="False"; PUBLIC_REGISTER_JS="false"; } \
|| { PUBLIC_REGISTER="True"; PUBLIC_REGISTER_JS="true"; }
export PUBLIC_REGISTER PUBLIC_REGISTER_JS
export ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com}
export NOREPLY_EMAIL=${NOREPLY_EMAIL:-no-reply@example.com}
export TAIGA_DB_HOST=${TAIGA_DB_HOST:-postgres}
export TAIGA_DB_PORT=${TAIGA_DB_PORT:-5432}
export TAIGA_DB_NAME=${TAIGA_DB_NAME:-taiga}
export TAIGA_DB_USER=${TAIGA_DB_USER:-taiga}
export TAIGA_DB_PASSWORD=${TAIGA_DB_PASSWORD:-mysecretpassword}
# Generate configs based on the template seeds
envsubst < /tmp/taiga.tmpl > /etc/nginx/sites-enabled/taiga
envsubst < /tmp/circus.ini.tmpl > $DATA/circus.ini
envsubst < /tmp/conf.json.tmpl > $DATA/taiga-front-dist/dist/conf.json
envsubst < /tmp/local.py.tmpl > $DATA/taiga-back/settings/local.py
# Keep sensitive information out of here
unset DJANGO_SECRET_KEY TAIGA_DB_PASSWORD
# Make sure the data is readable
chown -Rh $USER:$GROUP $DATA
# Allow a little delay on the first run
# to make sure Database is set and ready
[ -e "/tmp/taiga.firstrun" ] || ( sleep 5; touch /tmp/taiga.firstrun )
# Upgrade DB schemas, etc...
# This is important when Taiga's codebase gets updated
su -s /bin/sh $USER -c '. $DATA/venvtaiga/bin/activate
cd $DATA/taiga-back
python3 manage.py migrate --noinput
python3 manage.py compilemessages
python3 manage.py collectstatic --noinput
deactivate'
# (Optional) Create a new user admin with password 123123 and
# fill Taiga with the Sample data
# su -s /bin/sh $USER -c '. $DATA/venvtaiga/bin/activate
# cd $DATA/taiga-back
# python3 manage.py loaddata initial_user
# python3 manage.py loaddata initial_project_templates
# python3 manage.py loaddata initial_role
# python3 manage.py sample_data
# deactivate'
# Launch the backend
service nginx start
su -s /bin/sh $USER -c '/usr/local/bin/circusd "$DATA/circus.ini"'

@ -0,0 +1,2 @@
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin

@ -0,0 +1,31 @@
[circus]
check_delay = 5
endpoint = tcp://127.0.0.1:5555
pubsub_endpoint = tcp://127.0.0.1:5556
statsd = true
[watcher:taiga]
working_dir = ${DATA}/taiga-back
cmd = gunicorn
args = -w ${GUNICORN_WORKERS} -t 60 --pythonpath=. -b 127.0.0.1:8001 taiga.wsgi
uid = taiga
numprocesses = 1
autostart = true
send_hup = true
stdout_stream.class = FileStream
stdout_stream.filename = /var/log/taiga/gunicorn.stdout.log
stdout_stream.max_bytes = 10485760
stdout_stream.backup_count = 4
stderr_stream.class = FileStream
stderr_stream.filename = /var/log/taiga/gunicorn.stderr.log
stderr_stream.max_bytes = 10485760
stderr_stream.backup_count = 4
[env:taiga]
PATH = ${DATA}/venvtaiga/bin:${ESC}PATH
TERM=rxvt-256color
SHELL=/bin/bash
USER=taiga
LANG=en_US.UTF-8
HOME=${DATA}
PYTHONPATH=${DATA}/venvtaiga/lib/python3.4/site-packages

@ -0,0 +1,17 @@
{
"api": "${SITE_URI}/api/v1/",
"eventsUrl": null,
"eventsMaxMissedHeartbeats": 5,
"eventsHeartbeatIntervalTime": 60000,
"debug": true,
"debugInfo": false,
"defaultLanguage": "en",
"themes": ["taiga"],
"defaultTheme": "taiga",
"publicRegisterEnabled": ${PUBLIC_REGISTER_JS},
"feedbackEnabled": true,
"privacyPolicyUrl": null,
"termsOfServiceUrl": null,
"maxUploadFileSize": null,
"contribPlugins": []
}

@ -0,0 +1,42 @@
from .common import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': '${TAIGA_DB_NAME}',
'USER': '${TAIGA_DB_USER}',
'PASSWORD': '${TAIGA_DB_PASSWORD}',
'HOST': '${TAIGA_DB_HOST}',
'PORT': '${TAIGA_DB_PORT}',
}
}
ADMINS = (
("Admin", "${ADMIN_EMAIL}"),
)
# THROTTLING (Anti-flood)
REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = {
"anon": "20/min",
"user": "200/min",
"import-mode": "20/sec",
"import-dump-mode": "10/minute"
}
SECRET_KEY = "${DJANGO_SECRET_KEY}"
MEDIA_ROOT = '${DATA}/media'
STATIC_ROOT = '${DATA}/static'
MEDIA_URL = "${SITE_URI}/media/"
STATIC_URL = "${SITE_URI}/static/"
ADMIN_MEDIA_PREFIX = "${SITE_URI}/static/admin/"
SITES["front"]["scheme"] = "${SITE_SCHEME}"
SITES["front"]["domain"] = "${SITE_FQDN}"
DEBUG = False
TEMPLATE_DEBUG = False
PUBLIC_REGISTER_ENABLED = ${PUBLIC_REGISTER}
DEFAULT_FROM_EMAIL = "${NOREPLY_EMAIL}"
SERVER_EMAIL = DEFAULT_FROM_EMAIL

@ -0,0 +1,49 @@
server {
listen 80 default_server;
server_name _;
large_client_header_buffers 4 32k;
client_max_body_size 50M;
charset utf-8;
access_log /var/log/taiga/nginx.access.log;
error_log /var/log/taiga/nginx.error.log;
# Frontend
location / {
root ${DATA}/taiga-front-dist/dist/;
try_files ${ESC}uri ${ESC}uri/ /index.html;
}
# Backend
location /api {
proxy_set_header Host ${ESC}http_host;
proxy_set_header X-Real-IP ${ESC}remote_addr;
proxy_set_header X-Scheme ${ESC}scheme;
proxy_set_header X-Forwarded-Proto ${ESC}scheme;
proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8001/api;
proxy_redirect off;
}
# Django admin access (/admin/)
location /admin {
proxy_set_header Host ${ESC}http_host;
proxy_set_header X-Real-IP ${ESC}remote_addr;
proxy_set_header X-Scheme ${ESC}scheme;
proxy_set_header X-Forwarded-Proto ${ESC}scheme;
proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8001${ESC}request_uri;
proxy_redirect off;
}
# Static files
location /static {
alias ${DATA}/static;
}
# Media files
location /media {
alias ${DATA}/media;
}
}

@ -0,0 +1,5 @@
TAIGA_DB_USER=taiga
TAIGA_DB_NAME=taiga
TAIGA_DB_PASSWORD=secretpassword
TAIGA_DB_HOST=postgres
TAIGA_DB_PORT=5432

@ -0,0 +1,5 @@
GUNICORN_WORKERS=1
SITE_URI=http://taiga.mydomain.com
PUBLIC_REGISTER=true
ADMIN_EMAIL=admin@mydomain.com
NOREPLY_EMAIL=no-reply@mydomain.com
Loading…
Cancel
Save