dockerize (work in progress)
Docker support was initially worked on in 2bbb7a5e7e
, but it never really worked.
This extends f7d7434012800c3572049af82a501743d4aed583 which was an old branch for docker work.
This commit is contained in:
parent
ce17c12ca2
commit
299a5c6355
|
@ -0,0 +1,47 @@
|
|||
# Mail-in-a-Box Dockerfile
|
||||
###########################
|
||||
#
|
||||
# This file lets Mail-in-a-Box run inside of Docker (https://docker.io),
|
||||
# a virtualization/containerization manager.
|
||||
#
|
||||
# Run:
|
||||
# $ containers/docker/run.sh
|
||||
# to build the image, launch a storage container, and launch a Mail-in-a-Box
|
||||
# container.
|
||||
#
|
||||
###########################################
|
||||
|
||||
# We need a better starting image than docker's ubuntu image because that
|
||||
# base image doesn't provide enough to run most Ubuntu services. See
|
||||
# http://phusion.github.io/baseimage-docker/ for an explanation.
|
||||
|
||||
FROM phusion/baseimage:0.9.15
|
||||
|
||||
# Dockerfile metadata.
|
||||
MAINTAINER Joshua Tauberer (http://razor.occams.info)
|
||||
EXPOSE 22 25 53 80 443 587 993
|
||||
|
||||
# Docker has a beautiful way to cache images after each step. The next few
|
||||
# steps of installing system packages are very intensive, so we take care
|
||||
# of them early and let docker cache the image after that, before doing
|
||||
# any Mail-in-a-Box specific system configuration. That makes rebuilds
|
||||
# of the image extremely fast.
|
||||
|
||||
# Update system packages.
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
|
||||
|
||||
# Install packages needed by Mail-in-a-Box.
|
||||
ADD containers/docker/apt_package_list.txt /tmp/mailinabox_apt_package_list.txt
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y $(cat /tmp/mailinabox_apt_package_list.txt)
|
||||
RUN rm -f /tmp/mailinabox_apt_package_list.txt
|
||||
|
||||
# Now add Mail-in-a-Box to the system.
|
||||
ADD . /usr/local/mailinabox
|
||||
|
||||
# We can't know things like the IP address where the container will eventually
|
||||
# be deployed until the container is started. We also don't want to create any
|
||||
# private keys during the creation of the image --- that should wait until the
|
||||
# container is started too. So our whole setup process is deferred until the
|
||||
# container is started.
|
||||
ENTRYPOINT ["/usr/local/mailinabox/containers/docker/container_start.sh"]
|
|
@ -0,0 +1,86 @@
|
|||
bc
|
||||
bind9
|
||||
ca-certificates
|
||||
coreutils
|
||||
cron
|
||||
curl
|
||||
dbconfig-common
|
||||
dovecot-antispam
|
||||
dovecot-core
|
||||
dovecot-imapd
|
||||
dovecot-lmtpd
|
||||
dovecot-lucene
|
||||
dovecot-managesieved
|
||||
dovecot-pop3d
|
||||
dovecot-sieve
|
||||
dovecot-sqlite
|
||||
duplicity
|
||||
fail2ban
|
||||
git
|
||||
haveged
|
||||
ldnsutils
|
||||
libapr1
|
||||
libawl-php
|
||||
libcurl4-openssl-dev
|
||||
libjs-jquery
|
||||
libjs-jquery-mousewheel
|
||||
libmagic1
|
||||
libtool
|
||||
libyaml-dev
|
||||
links
|
||||
memcached
|
||||
munin
|
||||
munin-node
|
||||
nginx
|
||||
nsd
|
||||
ntp
|
||||
opendkim
|
||||
opendkim-tools
|
||||
opendmarc
|
||||
openssh-client
|
||||
openssl
|
||||
php-apc
|
||||
php-auth
|
||||
php-crypt-gpg
|
||||
php-mail-mime
|
||||
php-net-sieve
|
||||
php-net-smtp
|
||||
php-net-socket
|
||||
php-pear
|
||||
php-soap
|
||||
php-xml-parser
|
||||
php5
|
||||
php5-cli
|
||||
php5-common
|
||||
php5-curl
|
||||
php5-dev
|
||||
php5-fpm
|
||||
php5-gd
|
||||
php5-imap
|
||||
php5-intl
|
||||
php5-json
|
||||
php5-mcrypt
|
||||
php5-memcache
|
||||
php5-pspell
|
||||
php5-sqlite
|
||||
php5-xsl
|
||||
postfix
|
||||
postfix-pcre
|
||||
postgrey
|
||||
python3
|
||||
python3-dateutil
|
||||
python3-dev
|
||||
python3-dnspython
|
||||
python3-flask
|
||||
python3-pip
|
||||
pyzor
|
||||
razor
|
||||
resolvconf
|
||||
spampd
|
||||
sqlite3
|
||||
sudo
|
||||
tinymce
|
||||
ufw
|
||||
unattended-upgrades
|
||||
unzip
|
||||
wget
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script is used within containers to turn it into a Mail-in-a-Box.
|
||||
# It is referenced by the Dockerfile. You should not run it directly.
|
||||
########################################################################
|
||||
|
||||
# Local configuration details were not known at the time the Docker
|
||||
# image was created, so all setup is defered until the container
|
||||
# is started. That's when this script runs.
|
||||
|
||||
# If we're not in an interactive shell, set defaults.
|
||||
if [ ! -t 0 ]; then
|
||||
export PUBLIC_IP=auto
|
||||
export PUBLIC_IPV6=auto
|
||||
export PRIMARY_HOSTNAME=auto
|
||||
export CSR_COUNTRY=US
|
||||
export NONINTERACTIVE=1
|
||||
fi
|
||||
|
||||
# Start configuration.
|
||||
cd /usr/local/mailinabox
|
||||
export IS_DOCKER=1
|
||||
export DISABLE_FIREWALL=1
|
||||
source setup/start.sh # using 'source' means an exit from inside also exits this script and terminates container
|
||||
|
||||
# Once the configuration is complete, start the Unix init process
|
||||
# provided by the base image. We're running as process 0, and
|
||||
# /sbin/my_init needs to run as process 0, so use 'exec' to replace
|
||||
# this shell process and not fork a new one. Nifty right?
|
||||
exec /sbin/my_init -- bash
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
# Use this script to launch Mail-in-a-Box within a docker container.
|
||||
# ==================================================================
|
||||
#
|
||||
# A base image is created first. The base image installs Ubuntu
|
||||
# packages and pulls in the Mail-in-a-Box source code. This is
|
||||
# defined in Dockerfile at the root of this repository.
|
||||
#
|
||||
# A mailinabox-userdata container is started next. This container
|
||||
# contains nothing but a shared volume for storing user data.
|
||||
# It is segregated from the rest of the live system to make backups
|
||||
# easier.
|
||||
#
|
||||
# The mailinabox-services container is started last. It is the
|
||||
# real thing: it runs the mailinabox image. This container will
|
||||
# initialize itself and will initialize the mailinabox-userdata
|
||||
# volume if the volume is new.
|
||||
|
||||
|
||||
DOCKER=docker.io
|
||||
|
||||
# Build or rebuild the image.
|
||||
# Rebuilds are very fast.
|
||||
$DOCKER build -q -t mailinabox .
|
||||
|
||||
# Start the user-data containerw which is merely to create
|
||||
# a container that maintains a reference to a volume so that
|
||||
# we can destroy the main container without losing user data.
|
||||
if ! $DOCKER ps -a | grep mailinabox-userdata > /dev/null; then
|
||||
echo Starting user-data volume container...
|
||||
$DOCKER run -d \
|
||||
--name mailinabox-userdata \
|
||||
-v /home/user-data \
|
||||
scratch bash
|
||||
fi
|
||||
|
||||
# End a running container.
|
||||
if $DOCKER ps -a | grep mailinabox-services > /dev/null; then
|
||||
echo Deleting container...
|
||||
$DOCKER rm mailinabox-services
|
||||
fi
|
||||
|
||||
# Start container.
|
||||
echo Starting new container...
|
||||
$DOCKER run \
|
||||
-p 25 -p 53 -p 80 -p 443 -p 587 -p 993 \
|
||||
--volumes-from mailinabox-userdata \
|
||||
--name mailinabox-services \
|
||||
-t -i \
|
||||
mailinabox
|
|
@ -72,12 +72,20 @@ function get_default_hostname {
|
|||
# Guess the machine's hostname. It should be a fully qualified
|
||||
# domain name suitable for DNS. None of these calls may provide
|
||||
# the right value, but it's the best guess we can make.
|
||||
set -- $(hostname --fqdn 2>/dev/null ||
|
||||
hostname --all-fqdns 2>/dev/null ||
|
||||
hostname 2>/dev/null)
|
||||
set -- $(
|
||||
get_hostname_from_reversedns ||
|
||||
hostname --fqdn 2>/dev/null ||
|
||||
hostname --all-fqdns 2>/dev/null ||
|
||||
hostname 2>/dev/null)
|
||||
printf '%s\n' "$1" # return this value
|
||||
}
|
||||
|
||||
function get_hostname_from_reversedns {
|
||||
# Do a reverse DNS lookup on our public IPv4 address. The output of
|
||||
# `host` is complex -- use sed to get the FDQN.
|
||||
host $(get_publicip_from_web_service 4) | sed "s/.*pointer \(.*\)\./\1/"
|
||||
}
|
||||
|
||||
function get_publicip_from_web_service {
|
||||
# This seems to be the most reliable way to determine the
|
||||
# machine's public IP address: asking a very nice web API
|
||||
|
@ -153,7 +161,25 @@ function ufw_allow {
|
|||
}
|
||||
|
||||
function restart_service {
|
||||
hide_output service $1 restart
|
||||
# Restart a service quietly.
|
||||
if [ ! "$IS_DOCKER" ]; then
|
||||
# The normal way to restart a service.
|
||||
hide_output service $1 restart
|
||||
else
|
||||
# On docker, sysvinit is not present. Our base image provides
|
||||
# a weird way to manage running services. But we're not going
|
||||
# to use it. Just execute the init.d script directly.
|
||||
|
||||
if [ "$1" == "dovecot" ]; then
|
||||
# Dovecot does not provide an init.d script. It just provides
|
||||
# an upstart init configuration. But Docker doesn't provide
|
||||
# upstart. Start Dovecot specially.
|
||||
killall dovecot
|
||||
dovecot -c /etc/dovecot/dovecot.conf
|
||||
else
|
||||
hide_output /etc/init.d/$1 restart
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
## Dialog Functions ##
|
||||
|
|
|
@ -4,7 +4,7 @@ if [[ $EUID -ne 0 ]]; then
|
|||
echo
|
||||
echo "sudo $0"
|
||||
echo
|
||||
exit
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that we are running on Ubuntu 14.04 LTS (or 14.04.xx).
|
||||
|
@ -14,7 +14,7 @@ if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/14\.04\.[0-9]/14.04/' `" != "U
|
|||
lsb_release -d | sed 's/.*:\s*//'
|
||||
echo
|
||||
echo "We can't write scripts that run on every possible setup, sorry."
|
||||
exit
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that we have enough memory.
|
||||
|
@ -30,6 +30,6 @@ if [ ! -d /vagrant ]; then
|
|||
echo "Your Mail-in-a-Box needs more memory (RAM) to function properly."
|
||||
echo "Please provision a machine with at least 768 MB, 1 GB recommended."
|
||||
echo "This machine has $TOTAL_PHYSICAL_MEM MB memory."
|
||||
exit
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os.path, glob, re
|
||||
|
||||
packages = set()
|
||||
|
||||
def add(line):
|
||||
global packages
|
||||
if line.endswith("\\"): line = line[:-1]
|
||||
packages |= set(p for p in line.split(" ") if p not in("", "apt_install"))
|
||||
|
||||
for fn in glob.glob(os.path.join(os.path.dirname(__file__), "../setup/*.sh")):
|
||||
with open(fn) as f:
|
||||
in_apt_install = False
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("apt_install "):
|
||||
in_apt_install = True
|
||||
if in_apt_install:
|
||||
add(line)
|
||||
in_apt_install = in_apt_install and line.endswith("\\")
|
||||
|
||||
print("\n".join(sorted(packages)))
|
Loading…
Reference in New Issue