diff --git a/image/base/Dockerfile b/image/base/Dockerfile index ec4efc7..cda8ae4 100644 --- a/image/base/Dockerfile +++ b/image/base/Dockerfile @@ -1,9 +1,11 @@ -# lastet phusion baseimage as of 2016.11, based on ubuntu 16.04 +# Lastet phusion baseimage as of 2016.11, based on ubuntu 16.04 +# See https://hub.docker.com/r/phusion/baseimage/tags/ FROM phusion/baseimage:0.9.19 -ENV UPDATED_AT 20161110 +ENV UPDATED_AT=20161110 \ + DEBIAN_FRONTEND=noninteractive -RUN apt-get update -qq && apt-get -qq -y install memcached sqlite3 nginx \ +RUN apt-get update -qq && apt-get -qq -y install memcached sqlite3 mariadb-server nginx \ python2.7-dev python-imaging python-ldap python-mysqldb # Utility tools @@ -28,4 +30,13 @@ RUN mkdir -p /etc/service/nginx && \ mv /services/nginx.conf /etc/nginx/nginx.conf && \ mv /services/nginx.sh /etc/service/nginx/run +RUN mkdir -p /etc/service/mysql && \ + mv /services/mysql.sh /etc/service/mysql/run + +RUN mkdir -p /etc/my_init.d && rm -f /etc/my_init.d/00_regen_ssh_host_keys.sh +ADD my_init.d/99_mysql_setup.sh /etc/my_init.d/ + CMD ["/sbin/my_init", "--", "bash", "-l"] + +# TODO: clean up & squash layers with docker-squash +# See https://github.com/jwilder/docker-squash diff --git a/image/base/my_init.d/99_mysql_setup.sh b/image/base/my_init.d/99_mysql_setup.sh new file mode 100755 index 0000000..83b10ee --- /dev/null +++ b/image/base/my_init.d/99_mysql_setup.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Init mysql data dir. +# Borrowed from https://github.com/fideloper/docker-mysql/blob/master/etc/my_init.d/99_mysql_setup.sh + +if [[ ! -d /var/lib/mysql/mysql ]]; then + echo 'Rebuilding mysql data dir' + + chown -R mysql.mysql /var/lib/mysql + mysql_install_db > /dev/null + + rm -rf /var/run/mysqld/* + + echo 'Starting mysqld' + # The sleep 1 is there to make sure that inotifywait starts up before the socket is created + mysqld_safe & + + echo 'Waiting for mysqld to come online' + while [[ ! -x /var/run/mysqld/mysqld.sock ]]; do + sleep 1 + done + + echo 'Setting root password to root' + /usr/bin/mysqladmin -u root password '' + + # if [ -d /var/lib/mysql/setup ]; then + # echo 'Found /var/lib/mysql/setup - scanning for SQL scripts' + # for sql in $(ls /var/lib/mysql/setup/*.sql 2>/dev/null | sort); do + # echo 'Running script:' $sql + # mysql -uroot -proot -e "\. $sql" + # mv $sql $sql.processed + # done + # else + # echo 'No setup directory with extra sql scripts to run' + # fi + + echo 'Shutting down mysqld' + mysqladmin -uroot shutdown +fi diff --git a/image/base/services/mysql.sh b/image/base/services/mysql.sh new file mode 100755 index 0000000..c6a6649 --- /dev/null +++ b/image/base/services/mysql.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +shutdown_mysql() { + if [[ -d /var/run/mysqld/mysqld.sock ]]; then + mysqladmin -u root shutdown + fi +} + +trap shutdown_mysql EXIT + +mkdir -p /var/run/mysqld +chown mysql:mysql /var/run/mysqld + +/sbin/setuser mysql /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306 >&1 >/var/log/mysql.log 2>&1 diff --git a/image/seafile/Dockerfile b/image/seafile/Dockerfile index 71e3271..add3cbb 100644 --- a/image/seafile/Dockerfile +++ b/image/seafile/Dockerfile @@ -5,8 +5,7 @@ ENV SEAFILE_VERSION=6.0.5 RUN mkdir -p /opt/seafile/ && \ curl -sSL -o - https://bintray.com/artifact/download/seafile-org/seafile/seafile-server_6.0.5_x86-64.tar.gz \ - | tar xzf - -C /opt/seafile/ && \ - ln -sf /opt/seafile/seafile-server-${SEAFILE_VERSION} /opt/seafile/seafile-server-latest + | tar xzf - -C /opt/seafile/ RUN mkdir -p /etc/my_init.d ADD create_data_links.sh /etc/my_init.d/create_data_links.sh diff --git a/image/seafile/create_data_links.sh b/image/seafile/create_data_links.sh index 386e517..5623fba 100755 --- a/image/seafile/create_data_links.sh +++ b/image/seafile/create_data_links.sh @@ -26,4 +26,8 @@ if [[ -e /shared/logs/seafile ]]; then ln -sf /shared/logs/seafile/ /opt/seafile/logs fi +if [[ ! -e /opt/seafile/seafile-server-latest ]]; then + ln -sf /opt/seafile/seafile-server-$SEAFILE_VERSION /opt/seafile/seafile-server-latest +fi + # TODO: create avatars link diff --git a/launcher b/launcher index be87f50..95ab25e 100755 --- a/launcher +++ b/launcher @@ -23,7 +23,7 @@ err_and_quit () { } init_shared() { - mkdir -p $sharedir/seafile/ + mkdir -p $sharedir/{seafile,db} mkdir -p $sharedir/logs/{seafile,var-log} mkdir -p $sharedir/logs/var-log/nginx @@ -42,6 +42,7 @@ set_volumes() { mounts=( $sharedir:/shared $sharedir/logs/var-log:/var/log + $sharedir/db:/var/lib/mysql $dockerdir/bootstrap:/bootstrap:ro $dockerdir/scripts:/scripts:ro $dockerdir/scripts/tmp/check_init_admin.py:$installdir/check_init_admin.py:ro @@ -60,7 +61,7 @@ bootstrap() { err_and_quit "The file $bootstrap_conf doesn't exist. Have you run seafile-server-setup?" fi set_volumes - docker run --rm -it -e SEAFILE_BOOTSRAP=1 $volumes $image /scripts/bootstrap.py + docker run --rm -it -e SEAFILE_BOOTSRAP=1 $volumes $image /sbin/my_init -- /scripts/bootstrap.py } start() { diff --git a/samples/server-mysql.conf b/samples/server-mysql.conf new file mode 100644 index 0000000..097c19d --- /dev/null +++ b/samples/server-mysql.conf @@ -0,0 +1,5 @@ +[server] +server.hostname = seafile.example.com +admin.email = me@example.com +admin.password = asecret +db.type = mysql \ No newline at end of file diff --git a/samples/server-sqlite3.conf b/samples/server-sqlite3.conf index bf66497..e3d32ae 100644 --- a/samples/server-sqlite3.conf +++ b/samples/server-sqlite3.conf @@ -1,4 +1,5 @@ [server] server.hostname = seafile.example.com admin.email = me@example.com -admin.password = asecret \ No newline at end of file +admin.password = asecret +db.type = sqlite3 \ No newline at end of file diff --git a/scripts/bootstrap.py b/scripts/bootstrap.py index 659d35a..2ac2088 100755 --- a/scripts/bootstrap.py +++ b/scripts/bootstrap.py @@ -11,6 +11,7 @@ import os from os.path import abspath, basename, exists, dirname, join, isdir import shutil import sys +import uuid from utils import call, get_conf, get_install_dir, get_script @@ -21,12 +22,34 @@ shared_seafiledir = '/shared/seafile' def main(): if not exists(shared_seafiledir): os.mkdir(shared_seafiledir) + db_type = get_conf('db.type', 'mysql') env = { 'SERVER_NAME': 'seafile', - 'SERVER_IP': get_conf("server.hostname"), + 'SERVER_IP': get_conf('server.hostname'), } - call('{} auto'.format(get_script('setup-seafile.sh')), env=env) - for fn in ('conf', 'ccnet', 'seafile-data', 'seahub-data', 'seahub.db'): + + if db_type == 'sqlite3': + setup_script = get_script('setup-seafile.sh') + else: + setup_script = get_script('setup-seafile-mysql.sh') + env.update({ + 'MYSQL_USER': 'seafile', + 'MYSQL_USER_PASSWD': str(uuid.uuid4()), + 'MYSQL_USER_HOST': '127.0.0.1', + # Default MariaDB root user has empty password and can only connect from localhost. + 'MYSQL_ROOT_PASSWD': '', + }) + # Change the script to allow mysql root password to be empty + call('''sed -i -e 's/if not mysql_root_passwd/if not mysql_root_passwd and "MYSQL_ROOT_PASSWD" not in os.environ/g' {}''' + .format(get_script('setup-seafile-mysql.py')), check_call=True) + + call('{} auto -n seafile'.format(setup_script), env=env) + + files_to_copy = ['conf', 'ccnet', 'seafile-data', 'seahub-data',] + if db_type in ('sqlite', 'sqlite3'): + files_to_copy += ['seahub.db'] + + for fn in files_to_copy: src = join(topdir, fn) dst = join(shared_seafiledir, fn) if not exists(dst) and exists(src): diff --git a/scripts/start.py b/scripts/start.py index 94a58cd..ad4fed0 100755 --- a/scripts/start.py +++ b/scripts/start.py @@ -46,7 +46,12 @@ def main(): if exists(password_file): os.unlink(password_file) - watch_controller() + print 'seafile server is running now.' + try: + watch_controller() + except KeyboardInterrupt: + print 'Stopping seafile server.' + sys.exit(0) if __name__ == '__main__': main() diff --git a/scripts/utils/__init__.py b/scripts/utils/__init__.py index 9391ee3..77f3150 100644 --- a/scripts/utils/__init__.py +++ b/scripts/utils/__init__.py @@ -213,9 +213,10 @@ def get_script(script): _config = None -def get_conf(key): +def get_conf(key, default=None): global _config if _config is None: _config = ConfigParser() _config.read("/bootstrap/bootstrap.conf") - return _config.get("server", key) + return _config.get("server", key) if _config.has_option("server", key) \ + else default