Comments
Patch
new file mode 100644
@@ -0,0 +1,23 @@
+FROM debian:wheezy
+
+ENV DEBIAN_FRONTEND noninteractive
+ENV WSGI_PROCESSES 4
+ENV WSGI_THREADS 1
+ENV WSGI_MAX_REQUESTS 100000
+
+EXPOSE 80
+VOLUME ["/var/hg/htdocs", "/var/hg/repos"]
+
+RUN apt-get update && apt-get -y install libapache2-mod-wsgi python-dev vim
+
+# Install our own Apache site.
+RUN a2dissite 000-default
+ADD vhost.conf /etc/apache2/sites-available/hg
+RUN a2ensite hg
+
+ADD hgwebconfig /defaulthgwebconfig
+
+ADD entrypoint.sh /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
+
+CMD ["/usr/sbin/apache2", "-DFOREGROUND"]
new file mode 100644
@@ -0,0 +1,144 @@
+====================
+Apache Docker Server
+====================
+
+This directory contains code for running a Mercurial hgweb server via
+mod_wsgi with the Apache HTTP Server inside a Docker container.
+
+.. important::
+
+ This container is intended for testing purposes only: it is
+ **not** meant to be suitable for production use.
+
+Building Image
+==============
+
+The first step is to build a Docker image containing Apache and mod_wsgi::
+
+ $ docker build -t hg-apache .
+
+.. important::
+
+ You should rebuild the image whenever the content of this directory
+ changes. Rebuilding after pulling or when you haven't run the container
+ in a while is typically a good idea.
+
+Running the Server
+==================
+
+To run the container, you'll execute something like::
+
+ $ docker run --rm -it -v `pwd`/../..:/var/hg/source -p 8000:80 hg-apache
+
+If you aren't a Docker expert:
+
+* ``--rm`` will remove the container when it stops (so it doesn't clutter
+ your system)
+* ``-i`` will launch the container in interactive mode so stdin is attached
+* ``-t`` will allocate a psudo TTY
+* ``-v src:dst`` will mount the host filesystem at ``src`` into ``dst``
+ in the container. In our example, we assume you are running from this
+ directory and use the source code a few directories up.
+* ``-p 8000:80`` will publish port ``80`` on the container to port ``8000``
+ on the host, allowing you to access the HTTP server on the host interface.
+* ``hg-apache`` is the container image to run. This should correspond to what
+ we build with ``docker build``.
+
+.. important::
+
+ The container **requires** that ``/var/hg/source`` contain the Mercurial
+ source code.
+
+ Upon start, the container will attempt an install of the source in that
+ directory. If the architecture of the host machine doesn't match that of
+ the Docker host (e.g. when running Boot2Docker under OS X), Mercurial's
+ Python C extensions will fail to run. Be sure to ``make clean`` your
+ host's source tree before mounting it in the container to avoid this.
+
+When starting the container, you should see some start-up actions (including
+a Mercurial install) and some output saying Apache has started::
+
+Now if you load ``http://localhost:8000/`` (or whatever interface Docker
+is using), you should see hgweb running!
+
+For your convenience, we've created an empty repository available at
+``/repo``. Feel free to populate it with ``hg push``.
+
+Customizing the Server
+======================
+
+By default, the Docker container installs a basic hgweb config and an
+empty dummy repository. It also uses some reasonable defaults for
+mod_wsgi.
+
+Customizing the WSGI Dispatcher And Mercurial Config
+----------------------------------------------------
+
+By default, the Docker environment installs a custom ``hgweb.wsgi``
+file (based on the example in ``contrib/hgweb.wsgi``). The file
+is installed into ``/var/hg/htdocs/hgweb.wsgi``.
+
+A default hgweb configuration file is also installed. The ``hgwebconfig``
+file from this directory is installed into ``/var/hg/htdocs/config``.
+
+You have a few options for customizing these files.
+
+The simplest is to hack up ``hgwebconfig`` and ``entrypoint.sh`` in
+this directory and to rebuild the Docker image. This has the downside
+that the Mercurial working copy is modified and you may accidentally
+commit unwanted changes.
+
+The next simplest is to copy this directory somewhere, make your changes,
+then rebuild the image. No working copy changes involved.
+
+The preferred solution is to mount a host file into the container and
+overwrite the built-in defaults.
+
+For example, say we create a custom hgweb config file in ``~/hgweb``. We
+can start the container like so to install our custom config file::
+
+ $ docker run -v ~/hgweb:/var/hg/htdocs/config ...
+
+You can do something similar to install a custom WSGI dispatcher::
+
+ $ docker run -v ~/hgweb.wsgi:/var/hg/htdocs/hgweb.wsgi ...
+
+Managing Repositories
+---------------------
+
+Repositories are served from ``/var/hg/repos`` by default. This directory
+is configured as a Docker volume. This means you can mount an existing
+data volume container in the container so repository data is persisted
+across container invocations. See
+https://docs.docker.com/userguide/dockervolumes/ for more.
+
+Alternatively, if you just want to perform lightweight repository
+manipulation, open a shell in the container::
+
+ $ docker exec -it <container> /bin/bash
+
+Then run ``hg init``, etc to manipulate the repositories in ``/var/hg/repos``.
+
+mod_wsgi Configuration Settings
+-------------------------------
+
+mod_wsgi settings can be controlled with the following environment
+variables.
+
+WSGI_PROCESSES
+ Number of WSGI processes to run.
+WSGI_THREADS
+ Number of threads to run in each WSGI process
+WSGI_MAX_REQUESTS
+ Maximum number of requests each WSGI process may serve before it is
+ reaped.
+
+See https://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIDaemonProcess
+for more on these settings.
+
+.. note::
+
+ The default is to use 1 thread per process. The reason is that Mercurial
+ doesn't perform well in multi-threaded mode due to the GIL. Most people
+ run a single thread per process in production for this reason, so that's
+ what we default to.
new file mode 100755
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+# This script gets executed on container start. Its job is to set up
+# the Mercurial environment and invoke the server.
+
+# Mercurial can be started in two modes.
+# If the MERCURIAL_SOURCE environment variable is set and it points to a
+# Mercurial source directory, we will install Mercurial from that directory.
+# Otherwise, we download the Mercurial source and install it manually.
+
+set -e
+
+SOURCE_DIR=/var/hg/source
+INSTALL_DIR=/var/hg/install
+REPOS_DIR=/var/hg/repos
+HTDOCS_DIR=/var/hg/htdocs
+
+if [ ! -d ${SOURCE_DIR} ]; then
+ echo "Mercurial source not available at ${SOURCE_DIR}"
+ echo "You need to mount a volume containing the Mercurial source code"
+ echo "when running the container. For example:"
+ echo ""
+ echo " $ docker run -v ~/src/hg:/${SOURCE_DIR} hg-apache"
+ echo ""
+ echo "This container will now stop running."
+ exit 1
+fi
+
+echo "Installing Mercurial from ${SOURCE_DIR} into ${INSTALL_DIR}"
+pushd ${SOURCE_DIR}
+/usr/bin/python2.7 setup.py install --root=/ --prefix=${INSTALL_DIR} --force
+popd
+
+mkdir -p ${HTDOCS_DIR}
+
+# Provide a default config if the user hasn't supplied one.
+if [ ! -f ${HTDOCS_DIR}/config ]; then
+ cp /defaulthgwebconfig ${HTDOCS_DIR}/config
+fi
+
+if [ ! -f ${HTDOCS_DIR}/hgweb.wsgi ]; then
+ cat >> ${HTDOCS_DIR}/hgweb.wsgi << EOF
+config = '${HTDOCS_DIR}/config'
+
+import sys
+sys.path.insert(0, '${INSTALL_DIR}/lib/python2.7/site-packages')
+
+from mercurial import demandimport
+demandimport.enable()
+
+from mercurial.hgweb import hgweb
+application = hgweb(config)
+EOF
+fi
+
+mkdir -p ${REPOS_DIR}
+
+if [ ! -d ${REPOS_DIR}/repo ]; then
+ ${INSTALL_DIR}/bin/hg init ${REPOS_DIR}/repo
+ chown -R www-data:www-data ${REPOS_DIR}/repo
+fi
+
+# This is necessary to make debuginstall happy.
+if [ ! -f ~/.hgrc ]; then
+ cat >> ~/.hgrc << EOF
+[ui]
+username = Dummy User <nobody@example.com>
+EOF
+fi
+
+echo "Verifying Mercurial installation looks happy"
+${INSTALL_DIR}/bin/hg debuginstall
+
+. /etc/apache2/envvars
+
+echo "Starting Apache HTTP Server on port 80"
+echo "We hope you remembered to publish this port when running the container!"
+echo "If this is an interactive container, simply CTRL^C to stop."
+
+exec "$@"
new file mode 100644
@@ -0,0 +1,6 @@
+[paths]
+/ = /var/hg/repos/*
+
+[web]
+allow_push = *
+push_ssl = False
new file mode 100644
@@ -0,0 +1,24 @@
+# Apache won't be able to resolve its own hostname, so we sneak this
+# into the global context to silence a confusing-to-user warning on
+# server start.
+ServerName hg
+
+<VirtualHost *:80>
+ DocumentRoot /var/hg/htdocs
+ <Directory />
+ Options FollowSymLinks
+ AllowOverride None
+ </Directory>
+
+ SetEnv HGENCODING UTF-8
+ SetEnv LC_TYPE UTF-8
+
+ WSGIDaemonProcess hg processes=${WSGI_PROCESSES} threads=${WSGI_THREADS} maximum-requests=${WSGI_MAX_REQUESTS} user=www-data group=www-data display-name=hg-wsgi
+ WSGIProcessGroup hg
+
+ WSGIScriptAliasMatch ^(.*) /var/hg/htdocs/hgweb.wsgi$1
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ LogLevel warn
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+</VirtualHost>