containers/*
cids/*
bin/*
+image/.build.out
+image/img.tar
+image/squash.tar
image/nsenter/nsenter
image/docker-squash
+image/docker-squash.tar.gz
+image/discourse_dev/postgres.template.yml
+image/discourse_dev/redis.template.yml
.gc-state/*
#### `/image`
-Dockerfile for both the base image `/discourse_base` and discourse image `/discourse`.
+Dockerfiles for Discourse; see [the README](image/README.md) for further details.
-- `/discourse_base` contains all the OS dependencies including runit, postgres, nginx, ruby.
-
-- `/discourse` builds on the base image and configures a discourse user and `/var/www/discourse` directory for the Discourse source.
-
-The Docker repository will always contain the latest built version at: https://index.docker.io/u/samsaffron/discourse/ , you should not need to build the base image.
+The Docker repository will always contain the latest built version at: https://hub.docker.com/r/discourse/discourse/, you should not need to build the base image.
### Launcher
--- /dev/null
+IMAGE_VERSION := 1.3.7
+
+SHELL := /bin/bash
+OS := $(shell uname | tr '[:upper:]' '[:lower:]')
+
+DOCKER_SQUASH_URL := https://github.com/jwilder/docker-squash/releases/download/v0.2.0/docker-squash-${OS}-amd64-v0.2.0.tar.gz
+
+
+# omitting discourse_fast_switch from 'all' as it seems obsolete.
+all: base discourse discourse_dev discourse_test discourse_bench
+.PHONY: all base discourse discourse_dev discourse_test discourse_bench discourse_fast_switch
+
+base: base-deps
+# discourse: discourse-deps
+discourse_dev: discourse_dev-deps
+# discourse_test: discourse_test-deps
+# discourse_bench: discourse_bench-deps
+# discourse_fast_switch: discourse_fast_switch-deps
+
+base:
+ @IMAGE_DIR=$@ IS_BASE=YES ${MAKE} build-image
+
+discourse discourse_fast_switch discourse_dev discourse_test discourse_bench:
+ @IMAGE_DIR=$@ ${MAKE} build-image
+
+
+base-deps: base/phantomjs
+.PHONY: base-deps
+
+base/phantomjs:
+ @echo "Fetching phantomjs..."
+ cd base && ./download_phantomjs
+
+discourse_dev-deps:
+ @echo "Copying postgres and redis templates..."
+ sed -e 's/\(db_name: discourse\)/\1_development/' ../templates/postgres.template.yml > discourse_dev/postgres.template.yml
+ cp ../templates/redis.template.yml discourse_dev/redis.template.yml
+.PHONY: discourse_dev-deps
+
+# docker-squash doesn't seem to work on OSX... there's an error about calling
+# tar with an unsuported "--xattrs" option. If/when that gets fixed, the ifeq
+# can be removed. For now, OSX skips the docker-squash step, so don't push
+# images built on OSX!
+build-image: docker-squash update-dockerfile
+ @echo "----- building image: discourse/${IMAGE_DIR}:${IMAGE_VERSION} -----"
+ifeq ($(OS), darwin)
+ docker build -t discourse/${IMAGE_DIR}:${IMAGE_VERSION} ${IMAGE_DIR}
+else
+ docker build ${IMAGE_DIR} | tee .build.out
+ @echo "squashing $(shell tail -1 .build.out | awk '/^Successfully built / {print $$3}')..."
+ docker save -o img.tar $(shell tail -1 .build.out | awk '/^Successfully built / {print $$3}')
+ ./docker-squash -verbose -i img.tar -o squash.tar $(if $(IS_BASE),-from root) -t discourse/${IMAGE_DIR}:${IMAGE_VERSION}
+ docker load -i squash.tar
+ rm -f squash.tar
+ rm -f img.tar
+ rm -f .build.out
+endif
+.PHONY: build-image
+
+docker-squash:
+ wget ${DOCKER_SQUASH_URL} --output-document=$@.tar.gz
+ tar -xzvf $@.tar.gz
+ rm -f $@.tar.gz
+
+# We want to ensure that the Dockerfiles all have an appropriate header
+# comment, and any FROM line refers to the version we're currently building.
+# Also, if there's a line that echoes into VERSION, replace the value with the
+# current version. (Dockerfiles support environment expansion, but not for
+# FROM or RUN statements.)
+update-dockerfile:
+ @echo "----- updating ${IMAGE_DIR}/Dockerfile for ${IMAGE_VERSION} -----"
+ @sed -i '' -e 's/^\(# NAME:\).*$$/\1 discourse\/${IMAGE_DIR}/' ${IMAGE_DIR}/Dockerfile
+ @sed -i '' -e 's/^\(# VERSION:\).*$$/\1 ${IMAGE_VERSION}/' ${IMAGE_DIR}/Dockerfile
+ @sed -i '' -e 's/^\(FROM discourse\/[^:]*:\).*/\1${IMAGE_VERSION}/' ${IMAGE_DIR}/Dockerfile
+ @sed -i '' -e 's/^\(RUN echo "\)[^"]*\(" > \/VERSION\)$$/\1${IMAGE_VERSION}\2/' ${IMAGE_DIR}/Dockerfile
+.PHONY: update-dockerfile
--- /dev/null
+# Docker images
+
+## Building new images
+
+To build a new set of images, update the `Makefile` with the new version number, and then `make all`. This will automatically update the header comments in the Dockerfiles and update any `FROM` statements to ensure that the image verions remain in lock-step with each other. (The downside is that if you only wanted to tweak a "leaf" image, you'll still be touching/updating _all_ of the images. But reasoning about the images is much easier if they all have the same version.)
+
+> _A note about building on OSX:_ While the `Makefile` has provisions for acquiring an OS-specific version of docker-squash, running the Darwin (OSX) version doesn't work on my machine. To cope, OSX builds simply skip the docker-squash step. Since I'm not going to be pushing images up to Docker Hub, that's okay with me.
+
+The build process will tag the images with the version number, but not with "latest", nor will it push the images up to Docker Hub. Both of those steps must be performed manually.
+
+## More about the images
+
+See both `Makefile` and the respective `Dockerfile`s for details on _how_ all of this happens.
+
+
+### base ([discourse/base](https://hub.docker.com/r/discourse/base/))
+
+All of the dependencies for running Discourse. This includes runit, postgres, nginx, ruby, imagemagick, etc. It also includes the creation of the "discourse" user and `/var/www` directory.
+
+
+### discourse ([discourse/discourse](https://hub.docker.com/r/discourse/discourse/))
+
+Builds on the base image and adds the current (as of image build time) version of Discourse, cloned from GitHub, and also the bundled gems.
+
+
+### discourse_dev ([discourse/discourse_dev](https://hub.docker.com/r/discourse/discourse_dev/))
+
+Adds redis and postgres just like the "standalone" template for Discourse in order to have an all-in-one container for development. Note that you are expected to mount your local discourse source directory to `/src`. See [the README in GitHub's discourse/bin/docker](https://github.com/discourse/discourse/tree/master/bin/docker/) for utilities that help with this.
+
+Note that the discourse user is granted "sudo" permission without asking for a password in the discourse_dev image. This is to facilitate the command-line Docker tools in discourse proper that run commands as the discourse user.
+
+
+### discourse_test ([discourse/discourse_test](https://hub.docker.com/r/discourse/discourse_test/))
+
+Builds on the discourse image and adds testing tools and a default testing entrypoint.
+
+
+### discourse_bench ([discourse/discourse_bench](https://hub.docker.com/r/discourse/discourse_bench/))
+
+Builds on the discourse_test image and adds benchmark testing.
+
+
+### discourse_fast_switch ([discourse/discourse_fast_switch](https://hub.docker.com/r/discourse/discourse_fast_switch/))
+
+Builds on the discourse image and adds the ability to easily switch versions of Ruby.
# NAME: discourse/base
-# VERSION: 1.3.6
-
+# VERSION: 1.3.7
FROM ubuntu:16.04
ENV PG_MAJOR 9.5
MAINTAINER Sam Saffron "https://twitter.com/samsaffron"
-RUN echo "1.3.5" > /VERSION
+RUN echo "1.3.7" > /VERSION
RUN apt-get update && apt-get install -y lsb-release sudo curl
RUN echo "debconf debconf/frontend select Teletype" | debconf-set-selections
ADD cron /etc/service/cron/run
ADD rsyslog /etc/service/rsyslog/run
ADD cron.d_anacron /etc/cron.d/anacron
+
+# Create discourse user and /var/www location for both
+# discourse and dev images.
+RUN useradd discourse -s /bin/bash -m -U &&\
+ mkdir -p /var/www
# Build and install ImageMagick
-wget -O $WDIR/ImageMagick.tar.gz "http://www.imagemagick.org/download/ImageMagick-6.9.5-8.tar.gz"
+wget -O $WDIR/ImageMagick.tar.gz "http://www.imagemagick.org/download/ImageMagick-6.9.5-9.tar.gz"
IMDIR=$WDIR/$(tar tzf $WDIR/ImageMagick.tar.gz --wildcards "ImageMagick-*/configure" |cut -d/ -f1)
tar zxf $WDIR/ImageMagick.tar.gz -C $WDIR
cd $IMDIR
#!/bin/bash
mkdir -p /var/log/nginx
chown -R www-data:www-data /var/log/nginx
-chown www-data:www-data /var/log/nginx
-chown -f syslog:adm /var/log/syslog*
-chown -f syslog:adm /var/log/auth.log*
-chown -f syslog:adm /var/log/kern.log*
+touch /var/log/syslog && chown -f syslog:adm /var/log/syslog*
+touch /var/log/auth.log && chown -f syslog:adm /var/log/auth.log*
+touch /var/log/kern.log && chown -f syslog:adm /var/log/kern.log*
-# Current version 1.3.6
-FROM discourse/base:1.3.6
+# NAME: discourse/discourse
+# VERSION: 1.3.7
+FROM discourse/base:1.3.7
MAINTAINER Sam Saffron "https://twitter.com/samsaffron"
# Discourse specific bits
-RUN useradd discourse -s /bin/bash -m -U &&\
- mkdir -p /var/www && cd /var/www &&\
+RUN cd /var/www &&\
git clone https://github.com/discourse/discourse.git &&\
cd discourse &&\
git remote set-branches --add origin tests-passed &&\
sudo -u discourse bundle install --deployment \
--without test --without development &&\
find /var/www/discourse/vendor/bundle -name tmp -type d -exec rm -rf {} +
-
-FROM samsaffron/discourse_test:latest
+# NAME: discourse/discourse_bench
+# VERSION: 1.3.7
+FROM discourse/discourse_test:1.3.7
MAINTAINER Gerhard Schlager <mail@gerhard-schlager.at>
# reconfigure PostgreSQL template databases to use UTF-8
# otherwise rake db:create fails
-RUN pg_dropcluster --stop 9.3 main &&\
- pg_createcluster --start -e UTF-8 9.3 main
+RUN pg_dropcluster --stop 9.5 main &&\
+ pg_createcluster --start -e UTF-8 9.5 main
# create role "discourse"
RUN /etc/init.d/postgresql start &&\
+ sleep 10 &&\
sudo -u postgres createuser --superuser discourse
ADD run_bench.sh /tmp/run_bench.sh
-FROM samsaffron/discourse_fast_switch:1.0.13
+# NAME: discourse/discourse_dev
+# VERSION: 1.3.7
+FROM discourse/base:1.3.7
MAINTAINER Sam Saffron "https://twitter.com/samsaffron"
-RUN use_22
-RUN rm -fr /usr/local/include/ruby-2.0.0
-
-RUN chown -R discourse:discourse /usr/ruby_22
-
-RUN rm /var/www/discourse/.bundle/config
-
-RUN cd /var/www/discourse && git pull && sudo -u discourse bundle install
-RUN use_22
-
-# CLEANUP
-RUN rm -fr /var/www/discourse/vendor/bundle/ruby
-RUN rm -fr /usr/ruby_20
-
+# Give discourse user no-passwd sudo permissions (for bundle install)
+ADD sudoers.discourse /etc/sudoers.d/discourse
# get redis going
ADD redis.template.yml /pups/redis.yml
ADD postgres.template.yml /pups/postgres.yml
RUN LANG=en_US.UTF-8 /pups/bin/pups /pups/postgres.yml
-# move pg out of the way
+# move default postgres_data out of the way
RUN mv /shared/postgres_data /shared/postgres_data_orig
-# We got gems ... we need no source in the image ...
-RUN rm -fr /var/www/discourse
-
+# re-instantiate data on boot if needed (this will allow it to persist across
+# invocations when used with a mounted volume)
ADD ensure-database /etc/runit/1.d/ensure-database
if [ ! -f /shared/postgres_data/PG_VERSION ]; then
mkdir -p /shared/postgres_data
- cp -R /shared/postgres_data_orig/* /shared/postgres_data
chown -R postgres:postgres /shared/postgres_data
chmod 700 /shared/postgres_data
+ cp -R /shared/postgres_data_orig/* /shared/postgres_data
fi
+++ /dev/null
-params:
- db_synchronous_commit: "off"
- db_shared_buffers: "512MB"
- db_work_mem: "20MB"
- db_default_text_search_config: "pg_catalog.english"
- db_user: discourse
- db_wal_level: minimal
- db_max_wal_senders: 0
- db_checkpoint_segments: 6
- db_logging_collector: off
- db_log_min_duration_statement: 100
-
-hooks:
- before_code:
- - replace:
- filename: /etc/service/unicorn/run
- from: "# postgres"
- to: sv start postgres || exit 1
-
-env:
- LANG: en_US.UTF-8
-
-run:
- - exec: mkdir -p /shared/postgres_run
- - exec: chown postgres:postgres /shared/postgres_run
- - exec: chmod 775 /shared/postgres_run
- - exec: rm -fr /var/run/postgresql
- - exec: ln -s /shared/postgres_run /var/run/postgresql
- - exec: rm -fr /shared/postgres_run/.s*
- - exec: rm -fr /shared/postgres_run/*.pid
- - exec: mkdir -p /shared/postgres_run/9.3-main.pg_stat_tmp
- - exec: chown postgres:postgres /shared/postgres_run/9.3-main.pg_stat_tmp
- - file:
- path: /etc/service/postgres/run
- chmod: "+x"
- contents: |
- #!/bin/sh
- exec 2>&1
- HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/9.3/bin/postmaster -D /etc/postgresql/9.3/main
-
- - file:
- path: /etc/runit/3.d/99-postgres
- chmod: "+x"
- contents: |
- #!/bin/bash
- sv stop postgres
-
- - exec:
- cmd:
- - chown -R root /var/lib/postgresql/9.3/main
- - "[ ! -e /shared/postgres_data ] && install -d -m 0755 -o postgres -g postgres /shared/postgres_data && sudo -E -u postgres LANG=en_US.UTF-8 /usr/lib/postgresql/9.3/bin/initdb --locale=C -E UTF-8 -D /shared/postgres_data || exit 0"
- - chown -R postgres:postgres /shared/postgres_data
- - chown -R postgres:postgres /var/run/postgresql
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: "data_directory = '/var/lib/postgresql/9.3/main'"
- to: "data_directory = '/shared/postgres_data'"
-
- # listen on all interfaces
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?listen_addresses *=.*/
- to: "listen_addresses = '*'"
-
- # sync commit off is faster and less spiky, also marginally less safe
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?synchronous_commit *=.*/
- to: "synchronous_commit = $db_synchronous_commit"
-
- # default is 128MB which is way too small
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?shared_buffers *=.*/
- to: "shared_buffers = $db_shared_buffers"
-
- # default is 1MB which is too small
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?work_mem *=.*/
- to: "work_mem = $db_work_mem"
-
- # allow for other
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?default_text_search_config *=.*/
- to: "default_text_search_config = '$db_default_text_search_config'"
-
- # Necessary to enable backups
- - exec:
- cmd:
- - install -d -m 0755 -o postgres -g postgres /shared/postgres_backup
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?max_wal_senders *=.*/
- to: "max_wal_senders = $db_max_wal_senders"
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?wal_level *=.*/
- to: "wal_level = $db_wal_level"
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?checkpoint_segments *=.*/
- to: "checkpoint_segments = $db_checkpoint_segments"
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?logging_collector *=.*/
- to: "logging_collector = $db_logging_collector"
-
- - replace:
- filename: "/etc/postgresql/9.3/main/postgresql.conf"
- from: /#?log_min_duration_statement *=.*/
- to: "log_min_duration_statement = $db_log_min_duration_statement"
-
- - replace:
- filename: "/etc/postgresql/9.3/main/pg_hba.conf"
- from: /^#local +replication +postgres +peer$/
- to: "local replication postgres peer"
-
- # allow all to connect in with md5 auth
- - replace:
- filename: "/etc/postgresql/9.3/main/pg_hba.conf"
- from: /^host.*all.*all.*127.*$/
- to: "host all all 0.0.0.0/0 md5"
-
- - exec:
- background: true
- # use fast shutdown for pg
- stop_signal: INT
- cmd: HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/9.3/bin/postmaster -D /etc/postgresql/9.3/main
-
- # give db a few secs to start up
- - exec: "sleep 5"
-
- - exec: sudo -E -u postgres LANG=en_US.UTF-8 createdb discourse_development
- - exec: sudo -E -u postgres LANG=en_US.UTF-8 createdb discourse_test
- - exec: su postgres -c 'psql -c "create user $db_user with superuser"'
-
- - exec:
- background: true
- cmd: exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf
-
- - exec: cd /var/www/discourse && sudo -u discourse rake db:migrate
- - exec: cd /var/www/discourse && sudo -u discourse RAILS_ENV=test rake db:migrate
- - exec:
- hook: postgres
- cmd: "echo postgres installed!"
+++ /dev/null
-run:
- - file:
- path: /etc/service/redis/run
- chmod: "+x"
- contents: |
- #!/bin/sh
- exec 2>&1
- exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf
-
- - file:
- path: /etc/runit/3.d/10-redis
- chmod: "+x"
- contents: |
- #!/bin/bash
- sv stop redis
-
- - replace:
- filename: "/etc/redis/redis.conf"
- from: "daemonize yes"
- to: ""
- - replace:
- filename: "/etc/redis/redis.conf"
- from: /^pidfile.*$/
- to: ""
-
- - exec:
- cmd:
- - install -d -m 0755 -o redis -g redis /shared/redis_data
-
- - replace:
- filename: "/etc/redis/redis.conf"
- from: /^logfile.*$/
- to: "logfile \"\""
-
- - replace:
- filename: "/etc/redis/redis.conf"
- from: /^dir .*$/
- to: "dir /shared/redis_data"
-
- - exec:
- cmd: echo redis installed
- hook: redis
-
-# we can not migrate without redis, launch it if needed
-hooks:
- before_code:
- - exec:
- background: true
- cmd: exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf
- after_code:
- - replace:
- filename: /etc/service/unicorn/run
- from: "# redis"
- to: sv start redis || exit 1
--- /dev/null
+discourse ALL = NOPASSWD: ALL
-# Allow to easily switch Ruby version in images that derive off this
+# NAME: discourse/discourse_fast_switch
+# VERSION: 1.3.7
-FROM discourse/discourse:1.0.18
+# Allow to easily switch Ruby version in images that derive off this
+FROM discourse/base:1.3.7
MAINTAINER Sam Saffron "https://twitter.com/samsaffron"
-FROM discourse/discourse:1.3.6
+# NAME: discourse/discourse_test
+# VERSION: 1.3.7
+FROM discourse/discourse:1.3.7
MAINTAINER Sam Saffron "https://twitter.com/samsaffron"