Switch to multi-stage builder

pull/28/head
Christophe Romain 6 years ago
parent f96a6da3ae
commit a1fd44d938

@ -1,3 +1,32 @@
FROM ejabberd/mix as builder
ARG VERSION
ENV VERSION=${VERSION:-latest} \
MIX_ENV=prod
LABEL maintainer="ProcessOne <contact@process-one.net>" \
product="Ejabberd Community Server builder"
# Get ejabberd sources, dependencies, configuration
RUN git clone https://github.com/processone/ejabberd.git
WORKDIR /ejabberd
COPY vars.config .
COPY rel/*exs rel/
RUN git checkout ${VERSION/latest/HEAD} \
&& mix deps.get
# Compile
RUN mix do compile, release.init, release --env=prod
# Prepare runtime environment
RUN mkdir runtime \
&& tar -C runtime -zxf _build/prod/rel/ejabberd/releases/*/ejabberd.tar.gz \
&& cd runtime \
&& cp releases/*/start.boot bin \
&& echo 'beam_lib:strip_files(filelib:wildcard("lib/*/ebin/*beam")), init:stop().' | erts*/bin/erl -boot start_clean >/dev/null \
&& mv erts*/bin/* bin \
&& rm -rf releases erts* bin/*src bin/dialyzer bin/typer \
&& rm bin/ejabberd bin/ejabberd.bat bin/ejabberd_loader.sh
# Runtime container
FROM alpine:3.7
ARG VERSION
ENV TERM=xterm \
@ -14,37 +43,32 @@ LABEL maintainer="ProcessOne <contact@process-one.net>" \
# Create directory structure and user for ejabberd
RUN addgroup ejabberd -g 9000 \
&& adduser -s /bin/sh -D -G ejabberd ejabberd -u 9000 \
&& mkdir -p /home/ejabberd/config /home/ejabberd/db /home/ejabberd/log \
&& mkdir -p /home/ejabberd/conf /home/ejabberd/database /home/ejabberd/logs \
&& chown -R ejabberd:ejabberd /home/ejabberd
# Install required dependencies
RUN apk upgrade --update musl \
&& apk add \
bash \
ca-certificates \
curl \
expat \
libstdc++ \
ncurses-libs \
openssl \
sqlite \
uthash \
yaml \
zlib \
&& rm -rf /var/cache/apk/* \
&& update-ca-certificates
&& rm -rf /var/cache/apk/*
# Install ejabberd
ADD ejabberd-$VERSION.tar.gz $HOME
COPY ejabberd-api ejabberdctl $HOME/bin/
COPY --chown=ejabberd:ejabberd config/* $HOME/config/
COPY docker-entrypoint.sh /
WORKDIR $HOME
COPY --from=builder /ejabberd/runtime .
COPY bin/* bin/
COPY --chown=ejabberd:ejabberd conf conf/
ADD --chown=ejabberd:ejabberd https://curl.haxx.se/ca/cacert.pem conf/cacert.pem
# Setup runtime environment
USER ejabberd
WORKDIR $HOME
VOLUME ["$HOME/db","$HOME/config","$HOME/log"]
VOLUME ["$HOME/database","$HOME/conf","$HOME/logs"]
EXPOSE 5222 5269 5280
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["ejabberd"]
ENTRYPOINT ["/home/ejabberd/bin/ejabberdctl"]
CMD ["foreground"]

@ -1,4 +1,4 @@
## ejabberd Community Edition - Base
## ejabberd Community Server - Base
This ejabberd Docker image allows you to run a single node ejabberd instance in a Docker container.
@ -28,20 +28,26 @@ docker restart ejabberd
### Creating admin user
When the container is running (and thus ejabberd), you can exec commands inside the container. The ejabberd-api command-line tool can be used to exercise the API directly from the container, even if the API is not exposed to the outside world.
When the container is running (and thus ejabberd), you can exec commands inside the container. The api command-line tool can be used to exercise the API directly from the container, even if the API is not exposed to the outside world. Note: ejabberd configuration must allow api calls from loopback interface.
To create an admin user (or any other user), you can use the following command:
```bash
docker exec -it ejabberd /home/ejabberd/bin/ejabberd-api register --endpoint=http://127.0.0.1:5280/ --jid=admin@localhost --password=passw0rd
docker exec -it ejabberd bin/ejabberdapi register --endpoint=http://127.0.0.1:5280/ --jid=admin@localhost --password=passw0rd
```
It's also possible to fallback to ejabberdctl commands:
```bash
docker exec -it ejabberd bin/ejabberdctl register admin localhost passw0rd
```
### Running ejabberd with Erlang console attached
If you would like to run it with console attached you can use the `console` command:
If you would like to run it with Erlang console attached you can use the `live` command:
```bash
docker run -it -p 5222:5222 ejabberd/ecs console
docker run -it -p 5222:5222 ejabberd/ecs live
```
This command will use default configuration file and XMPP domain "localhost".
@ -51,16 +57,32 @@ This command will use default configuration file and XMPP domain "localhost".
The following command will pass config file using Docker volume feature and share local directory to store database:
```bash
mkdir db
docker run -d --name ejabberd -v $(pwd)/ejabberd.yml:/home/ejabberd/cfg/ejabberd.yml -v $(pwd)/db:/home/ejabberd/db -p 5222:5222 ejabberd/ecs
mkdir database
docker run -d --name ejabberd -v $(pwd)/ejabberd.yml:/home/ejabberd/conf/ejabberd.yml -v $(pwd)/database:/home/ejabberd/database -p 5222:5222 ejabberd/ecs
```
### Checking ejabberd log files
You can execute a Docker command to check the content of the log files from inside to container, even if you do not put it on a shared persistent drive:
```bash
docker exec -it ejabberd tail -f logs/ejabberd.log
```
### Checking ejabberd log file
### Open ejabberd debug console
You can execute a Docker command to check the content of the log file from inside to container, even if you do not put it on a shared persistent drive:
You can open a live debug Erlang console attached to a running container:
```bash
docker exec -it ejabberd /usr/bin/tail -f /home/ejabberd/log/ejabberd.log
docker exec -it ejabberd bin/ejabberdctl debug
```
### Execute ejabberdctl command
You can run anu ejabberdctl command inside running container. Example:
```bash
docker exec -it ejabberd bin/ejabberdctl status
```
## Docker image advanced configuration
@ -80,9 +102,9 @@ This is the kind of data you probably want to store on a persistent or local dri
Here are the volume you may want to map:
- /home/ejabberd/log/: Directory containing log files
- /home/ejabberd/db/: Directory containing Mnesia database. You should backup or export the content of the directory to persistent storage (host storage, local storage, any storage plugin)
- /home/ejabberd/config/: Directory containing configuration and certificates
- /home/ejabberd/logs/: Directory containing log files
- /home/ejabberd/database/: Directory containing Mnesia database. You should backup or export the content of the directory to persistent storage (host storage, local storage, any storage plugin)
- /home/ejabberd/conf/: Directory containing configuration and certificates
## Generating ejabberd release
@ -94,16 +116,22 @@ The configuration of ejabberd Erlang/OTP release is customized with:
- rel/config.exs: Customize ejabberd release
- rel/dev.exs: ejabberd environment configuration for development release
- rel/docker.exs: ejabberd environment configuration for production Docker release
- config/ejabberd.yml: ejabberd default config file
- rel/prod.exs: ejabberd environment configuration for production Docker release
- vars.config: ejabberd compilation configuration options
- conf/ejabberd.yml: ejabberd default config file
Build ejabberd Community Server base image from ejabberd master on Github:
```bash
docker build -t ejabberd/ecs .
```
Run the build script to generate ejabberd Community Server base image from ejabberd master on Github:
Build ejabberd Community Server base image for a given ejabberd version:
```bash
./build.sh
docker build --build-arg VERSION=18.01 -t ejabberd/ecs:18.01 .
```
### TODO
- Embed command-line tool for ejabberd API to be able to create admin user for ejabberd.
- Rebuild last version of ejabberd-api tool when creating container.
- Rebuild last version of bin/ejabberdapi tool when creating container.

@ -9,26 +9,27 @@ ERL_MAX_ETS_TABLES=1400
FIREWALL_WINDOW="4370-4379"
INET_DIST_INTERFACE=""
ERLANG_NODE=ejabberd@$(hostname -s)
EJABBERD_BYPASS_WARNINGS=true
# define default environment variables
ROOT_DIR="/home/ejabberd"
HOME_DIR="$ROOT_DIR"
ERL="$ROOT_DIR"/erts-9.1.5/bin/erl
IEX="$ROOT_DIR"/erts-9.1.5/bin/iex
EPMD="$ROOT_DIR"/erts-9.1.5/bin/epmd
ERL="$ROOT_DIR"/bin/erl
IEX="$ROOT_DIR"/bin/iex
EPMD="$ROOT_DIR"/bin/epmd
INSTALLUSER=ejabberd
# check the proper system user is used
case $(id -un) in
"$INSTALLUSER")
EXEC_CMD="as_current_user"
[ -e "$HOME"/config/ejabberd.yml ] && HOME_DIR="$HOME"
[ -e "$HOME"/conf/ejabberd.yml ] && HOME_DIR="$HOME"
;;
root)
if [ -n "$INSTALLUSER" ] ; then
EXEC_CMD="as_install_user"
HOME=$(su - ejabberd -c pwd)
[ -e "$HOME"/config/ejabberd.yml ] && HOME_DIR="$HOME"
[ -e "$HOME"/conf/ejabberd.yml ] && HOME_DIR="$HOME"
else
EXEC_CMD="as_current_user"
echo "WARNING: This is not recommended to run ejabberd as root" >&2
@ -61,15 +62,15 @@ for arg; do
done
# define ejabberd variables if not already defined from the command line
: "${ETC_DIR:="$HOME_DIR/config"}"
: "${LOGS_DIR:="$HOME_DIR/log"}"
: "${SPOOL_DIR:="$HOME_DIR/db"}"
: "${ETC_DIR:="$HOME_DIR/conf"}"
: "${LOGS_DIR:="$HOME_DIR/logs"}"
: "${EJABBERD_CONFIG_PATH:="$ETC_DIR/ejabberd.yml"}"
: "${EJABBERDCTL_CONFIG_PATH:="$ETC_DIR/ejabberdctl.cfg"}"
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
: "${EJABBERD_LOG_PATH:="$LOGS_DIR/ejabberd.log"}"
: "${SPOOL_DIR:="$HOME_DIR/database/$ERLANG_NODE"}"
# define erl parameters
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
@ -289,11 +290,13 @@ case $1 in
;;
debug)
debugwarning
exec_erl "$(uid debug)" -hidden -remsh "$ERLANG_NODE"
exec_erl "$(uid debug)" -hidden -remsh "$ERLANG_NODE" \
-boot start_clean
;;
etop)
exec_erl "$(uid top)" -hidden -node "$ERLANG_NODE" -s etop \
-s erlang halt -output text
-s erlang halt -output text \
-boot start_clean
;;
iexdebug)
debugwarning
@ -308,7 +311,8 @@ case $1 in
[ "$PEER" = "${PEER%.*}" ] && PS="-s"
exec_cmd "$ERL" ${PS:--}name "$(uid ping "$(hostname $PS)")" $ERLANG_OPTS \
-noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"'$PEER'"')])' \
-s erlang halt -output text
-s erlang halt -output text \
-boot start_clean
;;
started)
wait_status 0 30 2 # wait 30x2s before timeout
@ -317,8 +321,8 @@ case $1 in
wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout
;;
*)
exec_erl "$(uid ctl)" -hidden -noinput -s ejabberd_ctl \
-extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
exec_erl "$(uid ctl)" -hidden -noinput -boot start_clean \
-s ejabberd_ctl -extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
result=$?
case $result in
2|3) help;;

@ -0,0 +1,12 @@
#!/bin/sh
set -e
ROOTDIR=/home/ejabberd
BINDIR=$ROOTDIR/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\\///'`
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
exec "$BINDIR/erlexec" ${1+"$@"}

@ -1,50 +0,0 @@
#!/bin/bash
VERSION=${1:-HEAD}
REF=$VERSION
[ "$VERSION" = "HEAD" ] && VERSION=latest
ARCHIVE=ejabberd-${VERSION}.tar.gz
GREEN='\033[0;32m'
NC='\033[0m' # No Color]]'
docker images | grep -q "ejabberd/mix" || {
echo -e "${GREEN}Pulling ejabberd build Docker image${NC}"
docker pull ejabberd/mix
}
if [ ! -d ejbuild ]; then
echo -e "${GREEN}Cloning ejabberd${NC}"
git clone https://github.com/processone/ejabberd.git ejbuild
else
echo -e "${GREEN}Fetch ejabberd${NC}"
(cd ejbuild; git checkout master && git pull)
fi
cat > ejbuild/vars.config <<EOF
{mysql, true}.
{pgsql, true}.
{sqlite, true}.
{zlib, true}.
{redis, true}.
{elixir, true}.
{iconv, true}.
EOF
if [ ! -e ${ARCHIVE} ]; then
echo -e "${GREEN}Checkout ejabberd ${REF}${NC}"
(cd ejbuild; git checkout $REF)
echo -e "${GREEN}Building ejabberd release${NC}"
# Copy release configuration
cp rel/*.exs ejbuild/rel/
# Force clock resync ?
#docker run -it --rm --privileged --entrypoint="/sbin/hwclock" ejabberd/mix -s
# Build ejabberd and generate release
docker run -it -v $(pwd)/ejbuild:$(pwd)/ejbuild -w $(pwd)/ejbuild -e "MIX_ENV=prod" ejabberd/mix do clean, deps.get, deps.compile, compile, release.init, release --env=prod
# Copy generated ejabberd release archive
relvsn=$(grep version ejbuild/mix.exs | cut -d'"' -f2)
cp ejbuild/_build/prod/rel/ejabberd/releases/$relvsn/ejabberd.tar.gz ${ARCHIVE}
fi
# Build ejabberd base container
echo -e "${GREEN}Building ejabberd Community Edition container${NC}"
docker build --build-arg VERSION=${VERSION} -t ejabberd/ecs:${VERSION} .

@ -111,29 +111,33 @@ hosts:
## automatically by ejabberd.
##
certfiles:
- "/home/ejabberd/config/server.pem"
- "/home/ejabberd/conf/server.pem"
## - "/etc/letsencrypt/live/example.org/*.pem"
## - "/etc/letsencrypt/live/example.com/*.pem"
ca_file: "/home/ejabberd/config/cacert.pem"
ca_file: "/home/ejabberd/conf/cacert.pem"
###. =================
###' TLS configuration
define_macro:
'TLS_CIPHERS': "HIGH:!aNULL:!eNULL:!3DES:@STRENGTH"
'TLS_OPTIONS':
- "no_sslv3"
- "cipher_server_preference"
- "no_compression"
'DH_FILE': "/home/ejabberd/config/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048
c2s_dhfile: 'DH_FILE'
s2s_dhfile: 'DH_FILE'
c2s_ciphers: 'TLS_CIPHERS'
s2s_ciphers: 'TLS_CIPHERS'
c2s_protocol_options: 'TLS_OPTIONS'
s2s_protocol_options: 'TLS_OPTIONS'
## Note that the following configuration is the default
## configuration of the TLS driver, so you don't need to
## uncomment it.
##
## define_macro:
## 'TLS_CIPHERS': "HIGH:!aNULL:!eNULL:!3DES:@STRENGTH"
## 'TLS_OPTIONS':
## - "no_sslv3"
## - "cipher_server_preference"
## - "no_compression"
## 'DH_FILE': "/home/ejabberd/conf/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048
##
## c2s_dhfile: 'DH_FILE'
## s2s_dhfile: 'DH_FILE'
## c2s_ciphers: 'TLS_CIPHERS'
## s2s_ciphers: 'TLS_CIPHERS'
## c2s_protocol_options: 'TLS_OPTIONS'
## s2s_protocol_options: 'TLS_OPTIONS'
###. ===============
###' LISTENING PORTS
@ -647,7 +651,7 @@ language: "en"
##
## Full path to a script that generates the image.
##
## captcha_cmd: "/home/ejabberd/lib/ejabberd-17.12/priv/bin/captcha.sh"
## captcha_cmd: "/home/ejabberd/lib/ejabberd-xx.yy/priv/bin/captcha.sh"
##
## Host for the URL and port where ejabberd listens for CAPTCHA requests.
@ -712,7 +716,7 @@ modules:
mod_bosh: {}
## mod_http_fileserver:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
## accesslog: "/home/ejabberd/logs/access.log"
## mod_http_upload:
## # docroot: "@HOME@/upload"
## put_url: "https://@HOST@:5444"

@ -0,0 +1,3 @@
{lookup,["file","native"]}.
{host,{127,0,0,1}, ["localhost","@@HOSTNAME@@"]}.
{file, resolv, "/etc/resolv.conf"}.

File diff suppressed because it is too large Load Diff

@ -1,12 +0,0 @@
#!/bin/sh
set -e
if [ "${1:0:1}" = '-' ]; then
set -- ejabberd "$@"
fi
case "$1" in
'ejabberd') exec $HOME/bin/ejabberd foreground ;;
'console') exec $HOME/bin/ejabberd console ;;
*) exit ;;
esac

@ -23,7 +23,7 @@ end
environment :prod do
set include_erts: true
set include_src: false
set config: "rel/docker.exs"
set config: "rel/prod.exs"
set cookie: :"HmewW_sUao={>LXTD8,g;xBu`.i]tq7Dz.m2?ZqO<g1Iz}?L(36T%w,Zz,)gHp$^"
end

@ -2,9 +2,9 @@ use Mix.Config
# This is standard path in the context of ejabberd release
config :ejabberd,
file: "/home/p1/ejabberd/config/ejabberd.yml",
log_path: '/home/p1/ejabberd/log/ejabberd.log'
file: "/home/ejabberd/conf/ejabberd.yml",
log_path: '/home/ejabberd/logs/ejabberd.log'
# Customize Mnesia directory:
config :mnesia,
dir: '/home/p1/ejabberd/database/'
dir: '/home/ejabberd/database/'

@ -2,9 +2,9 @@ use Mix.Config
# This is standard path in the context of ejabberd release
config :ejabberd,
file: "/home/p1/ejabberd/config/ejabberd.yml",
log_path: '/home/p1/ejabberd/log/ejabberd.log'
file: "/home/ejabberd/conf/ejabberd.yml",
log_path: '/home/ejabberd/logs/ejabberd.log'
# Customize Mnesia directory:
config :mnesia,
dir: '/home/p1/ejabberd/database/'
dir: '/home/ejabberd/database/'

@ -0,0 +1,5 @@
{mysql, true}.
{pgsql, true}.
{sqlite, true}.
{zlib, true}.
{elixir, true}.

@ -10,13 +10,14 @@ You can build ejabberd from source with all dependencies, with the following com
```bash
git clone https://github.com/processone/ejabberd.git
cd ejabberd
docker run --rm -v $(pwd):$(pwd) -w $(pwd) ejabberd/mix do deps.get, deps.compile, compile
```
Alternatively if you do not have Git installed, you can do:
```bash
wget https://github.com/processone/ejabberd/archive/master.zip
unzip ejabberd-master
unzip master.zip
cd ejabberd-master
docker run --rm -v $(pwd):$(pwd) -w $(pwd) ejabberd/mix do deps.get, deps.compile, compile
```

Loading…
Cancel
Save