Merge pull request #142 from rtau-trial/merge-docker

Enable Docker Hub to build image automatically on push
This commit is contained in:
Ji Qu
2019-03-25 19:14:33 +08:00
committed by GitHub
18 changed files with 560 additions and 1 deletions

44
Dockerfile.autobuild Normal file
View File

@@ -0,0 +1,44 @@
# -----------------------------------------------------------------------------
# docker-pinry
#
# Builds a basic docker image that can run Pinry (http://getpinry.com) and serve
# all of it's assets, there are more optimal ways to do this but this is the
# most friendly and has everything contained in a single instance.
#
# Authors: Isaac Bythewood
# Updated: Mar 29th, 2016
# Require: Docker (http://www.docker.io/)
# -----------------------------------------------------------------------------
# Base system is the LTS version of Ubuntu.
FROM python:3.6-stretch
RUN groupadd -g 2300 tmpgroup && usermod -g tmpgroup www-data && groupdel www-data && groupadd -g 1000 www-data && usermod -g www-data www-data && usermod -u 1000 www-data && groupdel tmpgroup
RUN apt-get update
RUN apt-get -y install nginx nginx-extras pwgen
RUN mkdir -p /srv/www/; cd /srv/www/; git clone https://github.com/pinry/pinry.git
RUN mkdir /srv/www/pinry/logs; mkdir /data
RUN cd /srv/www/pinry && pip install pipenv && pipenv install --three --system
RUN pip install gunicorn
# Fix permissions
RUN chown -R www-data:www-data /srv/www
# Load in all of our config files.
ADD docker-contents/nginx/nginx.conf /etc/nginx/nginx.conf
ADD docker-contents/nginx/sites-enabled/default /etc/nginx/sites-enabled/default
# Fix permissions
RUN mkdir /scripts/
ADD docker-contents/scripts/* /scripts/
RUN chown -R www-data:www-data /data
RUN mkdir /var/log/gunicorn
# 80 is for nginx web, /data contains static files and database /start runs it.
expose 80
volume ["/data"]
cmd ["/scripts/start.sh"]

View File

@@ -20,7 +20,7 @@ Feature
Setup Guide for users
--------------------------
Please use docker to install `docker-pinry <https://github.com/pinry/docker-pinry>`_
Please use docker to install `pinry <https://github.com/pinry/pinry>`_
Developers or users who are familiar with python/nginx could setup Pinry with following guide : )

14
docker/CONTRIBUTORS.rst Normal file
View File

@@ -0,0 +1,14 @@
Contributors
============
The core contributors for Pinry have been/currently are:
* Isaac Bythewood <http://isaacbythewood.com/>
* Krzysztof Klimonda
For a full list of contributors check out the `GitHub Contributors Graph`_.
.. Links
.. _GitHub Contributors Graph: https://github.com/pinry/pinry/graphs/contributors

27
docker/LICENSE.rst Normal file
View File

@@ -0,0 +1,27 @@
License (Simplified BSD)
========================
| Copyright (c) Pinry Contributors
| All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

135
docker/README.rst Normal file
View File

@@ -0,0 +1,135 @@
Pinry Docker
============
.. image:: https://travis-ci.org/pinry/docker-pinry.svg?branch=master
:target: https://travis-ci.org/pinry/docker-pinry
A nice and easy way to get a Pinry instance up and running using docker. For
help on getting started with docker see the `official getting started guide`_.
For more information on Pinry and a demo check out it's `website`_.
Getting Pinry Docker
---------------------
Running this will get the latest version of pinry itself::
git clone https://github.com/pinry/pinry
cd pinry
./docker/bootstrap.sh
Now you can start your container by command like this::
# this is where your database and pins localted
mkdir data
# use absolute path for docker to avoid using default data-volume (we use directory instead)
./docker/start_docker.sh `readlink -f data`
Please visit `http://your-ip` to visit your instance and register a new account, enjoy it.
Configuring docker-pinry
------------------------
Enable signups for new users by editing ``pinry/local_settings.py``::
ALLOW_NEW_REGISTRATIONS = True
`Additional pinry configuration settings`_
Building docker-pinry again
---------------------------
Running this will build you a docker image with the latest version of pinry::
./docker/build_docker.sh
Running docker-pinry in manual way
----------------------------------
Running the start command for the first time will setup your production secret
key, database and static files. It is important that you decide what port you
want and what location on the host machine you wish to store your files. If this
is the only thing running on your system and you wish to make it public without
a proxy then you can set ``-p=80:80``. The setting ``-p=10000:80`` assumes you
are wanting to proxy to this instance using something like nginx. Also note that
you must have your host mount directory created first (``mkdir -p /mnt/pinry``)
Then you have two choice to run docker-pinry
Fist one, with automaticlly configured default arguments::
./docker/start_docker.sh /mnt/pinry
Second one, start docker by hand with customized arguments::
SETTINGS_PATH=$(readlink -f docker/pinry/local_settings.py) \
DATA_PATH=$(readlink -f /mnt/pinry) \
sudo docker run -d=true -p=10000:80 \
-v=${DATA_PATH}:/data \
-v=${SETTINGS_PATH}:/srv/www/pinry/pinry/settings/local_settings.py \
pinry/pinry /scripts/start.sh
If it's the first run it'll take a few seconds but it will print out your
container ID which should be used to start and stop the container in the future
using the commands::
sudo docker start <container_id>
sudo docker stop <container_id>
Running docker-pinry with docker-compose
-----------------------------------------
Just config your ``docker-compose.yml`` and then run::
sudo pip install -U docker-compose
sudo docker-compose --project-directory docker up -d
Notes on the run commands
`````````````````````````
* ``-v`` is the volume you are mounting ``-v=host_dir:docker_dir``
* ``pinry/pinry`` is simply what I called my docker build of this image
* ``-d=true`` allows this to run cleanly as a daemon, remove for debugging
* ``-p`` is the port it connects to, ``-p=host_port:docker_port``
* Follow comments in ``local_settings.py`` to understand how the site configured
Using docker-pinry
------------------
Open a browser to ``http://<YOUR-HOSTNAME>:10000`` and register. Replace YOUR-HOSTNAME with the name
of the machine docker is running on, likely localhost.
You can map ``http://localhost:10000`` to your outer nginx for SSL or just change
the default port-mapping to ``80:80`` to serve your site directly, just enjoy!
Why include nginx and not just map to gunicorn directly?
-----------------------------------------------------------
Because gunicorn/django can't serve static files very well and it is unwise to do
so for security reasons. I built this so that people can have a full hosted
solution in a container. If you have a host machine running nginx then of course
there is no point to run nginx in the container as well, you can simply disable
nginx, map gunicorn to a port and then set your host machine's nginx to display
your media and static files since that directory is shared between the container
and host.
Why use sqlite3?
----------------
Because it has a very low resource cost and most pinry websites are small
personal ones. Why have a full on database for that? If you need more power
than you can easily modify the `pinry/local_settings.py` to point to a
stronger database solution.
.. Links
.. _official getting started guide: http://www.docker.io/gettingstarted/
.. _website: http://getpinry.com/
.. _additional pinry configuration settings: https://github.com/pinry/pinry/blob/master/docker/pinry/local_settings.example.py

51
docker/bootstrap.sh Normal file
View File

@@ -0,0 +1,51 @@
#!/bin/bash
script_dir="$( dirname "${0}" )"
# Force users to login before seeing any pins.
if [ "${ALLOW_NEW_REGISTRATIONS}" = "" ]; then
ALLOW_NEW_REGISTRATIONS=true
fi
if [[ "$(docker images -q pinry/pinry 2> /dev/null)" == "" ]]; then
echo "No docker image found, building..." && "${script_dir}/build_docker.sh"
fi
echo "=================================================================================="
echo "Note: Please copy this key and keep it in a secure place."
echo "Then you should manually edit your pinry/local_settings.py"
echo "and replace SECRET_KEY with new secret-key if you had previously generated a"
echo "pinry/local_settings.py."
echo "If no previous pinry/local_settings.py generated, you can have a look and edit it."
echo "If you want to use docker-compose, just edit docker-compose.yml and use 'docker-compose up'"
SECRET_KEY=$(sudo docker run pinry/pinry /scripts/gen_key.sh)
echo ""
echo "Your secret-key is(also saved/overwritten your pinry/production_secret_key.txt):"
echo ""
echo ${SECRET_KEY}
echo "=================================================================================="
local_settings_file="${script_dir}/pinry/local_settings.py"
# Create local_settings.py
if [ ! -f "${local_settings_file}" ];
then
cp "${script_dir}/pinry/local_settings.example.py" "${local_settings_file}"
sed -i "s/secret\_key\_place\_holder/${SECRET_KEY}/" "${local_settings_file}"
# Force users to login before seeing any pins.
if [ "${PRIVATE}" = "true" ]; then
sed -i "s/PUBLIC = True/PUBLIC = False/" "${local_settings_file}"
fi
# Enable people from creating new accounts.
if [ "${ALLOW_NEW_REGISTRATIONS}" = "true" ]; then
sed -i "s/ALLOW_NEW_REGISTRATIONS = False/ALLOW_NEW_REGISTRATIONS = True/" "${local_settings_file}"
fi
fi
# Copy to docker-compose.yml
if [ ! -f "${script_dir}/docker-compose.yml" ];
then
cp "${script_dir}/docker-compose.example.yml" "${script_dir}/docker-compose.yml"
fi

4
docker/build_docker.sh Normal file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
script_dir="$( dirname "${0}" )"
sudo docker build -t pinry/pinry${@} "${script_dir}/../" -f "${script_dir}/../Dockerfile.autobuild"

View File

@@ -0,0 +1,16 @@
version: '3'
services:
web:
build: .
command: >
bash -c "/scripts/start.sh"
ports:
# if you use "127.0.0.1", no one except you can visit it from within
# - "127.0.0.1:10000:8000"
- "80:80"
volumes:
# overwrite local_settings, you can always modify your local_settings file
- ./pinry/local_settings.py:/srv/www/pinry/pinry/settings/local_settings.py
- ./data/:/data/
restart: always

35
docker/nginx/nginx.conf Normal file
View File

@@ -0,0 +1,35 @@
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 1m;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

View File

@@ -0,0 +1,26 @@
server {
listen 80 default;
server_name _;
access_log /srv/www/pinry/logs/access.log;
error_log /srv/www/pinry/logs/error.log;
location /media {
alias /data/static/media;
expires max;
access_log off;
}
location /static {
alias /data/static;
expires max;
access_log off;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://localhost:8000;
}
}

2
docker/pinry/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
local_settings.py
production_secret_key.txt

View File

@@ -0,0 +1,44 @@
import os
# Please don't change following settings unless you know what you are doing
STATIC_ROOT = '/data/static'
MEDIA_ROOT = os.path.join(STATIC_ROOT, 'media')
# SECURITY WARNING: keep the secret key used in production secret!
# Or just write your own secret-key here instead of using a env-variable
SECRET_KEY = "secret_key_place_holder"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
TEMPLATE_DEBUG = DEBUG
# SECURITY WARNING: use your actual domain name in production!
ALLOWED_HOSTS = ['*']
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/data/production.db',
}
}
# Allow users to register by themselves
ALLOW_NEW_REGISTRATIONS = False
# Delete image files once you remove your pin
IMAGE_AUTO_DELETE = True
# thumbnail size control
IMAGE_SIZES = {
'thumbnail': {'size': [240, 0]},
'standard': {'size': [600, 0]},
'square': {'crop': True, 'size': [125, 125]},
}
# Whether people can view pins without login
PUBLIC = True

View File

@@ -0,0 +1,3 @@
#!/bin/bash
gunicorn pinry.wsgi -b 0.0.0.0:8000 -w 4 \
--capture-output --timeout 30 --user www-data --group www-data

13
docker/scripts/gen_key.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Check for secret key if one doesn't exist create.
if [ ! -f /data/production_secret_key.txt ]
then
cd /data
PRODUCTION_SECRET_KEY=`pwgen -c -n -1 65`
echo $PRODUCTION_SECRET_KEY > /data/production_secret_key.txt
else
PRODUCTION_SECRET_KEY=`cat /data/production_secret_key.txt`
fi
echo ${PRODUCTION_SECRET_KEY}

34
docker/scripts/start.sh Normal file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# -----------------------------------------------------------------------------
# docker-pinry /start script
#
# Will setup database and static files if they don't exist already, if they do
# just continues to run docker-pinry.
#
# Authors: Isaac Bythewood
# Updated: Aug 19th, 2014
# -----------------------------------------------------------------------------
# If static files don't exist collect them
if [ ! -d /data/static ]
then
cd /srv/www/pinry
python manage.py collectstatic --noinput
fi
# If database doesn't exist yet create it
if [ ! -f /data/production.db ]
then
cd /srv/www/pinry
python manage.py migrate --noinput --settings=pinry.settings.docker
fi
# Fix all settings after all commands are run
chown -R www-data:www-data /data
# start all process
/usr/sbin/nginx
cd /srv/www/pinry/
/scripts/_start_gunicorn.sh

16
docker/start_docker.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
DATA_PATH=${1}
HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
SETTINGS_PATH="${HERE}/pinry/local_settings.py"
if [ "${DATA_PATH}" = "" ]
then
echo "usage: start_docker.sh /abs/path/to/your/data/store"
exit 1
fi
sudo docker run -d=true -p=80:80 \
-v=${DATA_PATH}:/data \
-v=${SETTINGS_PATH}:/srv/www/pinry/pinry/settings/local_settings.py \
pinry/pinry /scripts/start.sh

View File

@@ -0,0 +1,42 @@
#!/bin/bash
set -e
usage() {
cat <<EOL
USAGE: $(basename $0) url
OPTIONS:
-h, --help
EOL
exit 1
}
main() {
local argc=0
local argv=()
while [ $# -gt 0 ]; do
case $1 in
-h|--help)
usage
;;
*)
argc=`expr $argc + 1`
argv+=($1)
;;
esac
shift
done
if [ $argc -lt 1 ]; then
echo "Too few arguments"
exit 1
fi
url=${argv[0]}
http_status_code=`curl -s -w "%{http_code}" -o /dev/null $url`
echo $http_status_code
}
main $*

53
docker/tests/test.sh Normal file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
set -e
home_url="http://localhost:$HOST_PORT/"
new_registration_url="http://localhost:$HOST_PORT/register/"
admin_login_url="http://localhost:$HOST_PORT/admin/login/"
echo "Starting container."
$TRAVIS_BUILD_DIR/bootstrap.sh
$TRAVIS_BUILD_DIR/start_docker.sh ${MOUNT_DIR}
sleep 10
# Get status codes
status_code_of_home=`$TRAVIS_BUILD_DIR/tests/http_status_code.sh $home_url`
status_code_of_new_registration=`$TRAVIS_BUILD_DIR/tests/http_status_code.sh $new_registration_url`
status_code_of_admin_login=`$TRAVIS_BUILD_DIR/tests/http_status_code.sh $admin_login_url`
exit_error () {
echo ${1}
exit 1
}
assert_equal () {
[ ${1} = ${2} ] || exit_error "${1} != ${2}, exit now"
}
# enable command echo
set -o xtrace
# Check status codes
case $1 in
private)
assert_equal "$status_code_of_home" "302"
assert_equal "$status_code_of_new_registration" "302"
assert_equal "$status_code_of_admin_login" "302"
exit 0
;;
allow_new_registrations)
assert_equal "$status_code_of_home" "200"
assert_equal "$status_code_of_new_registration" "200"
assert_equal "$status_code_of_admin_login" "200"
exit 0
;;
*)
echo "$0 $1: invalid option."
exit 1
esac
exit 1