Remove 3.7
> 3.7 goes out of any kind of support on October 1st. There will be one more security patch release of 3.7.x, after that, we can basically assume the 3.7 flavour of this image won't have any upstream releases to benefit from. > Honestly, the attack 3.7.28 will address is local, requires elevated privileges and is Windows-specific. So this image isn't really affected. - Michael Klishin
This commit is contained in:
parent
d2c116b97e
commit
13daa516eb
|
|
@ -1,250 +0,0 @@
|
||||||
# Alpine Linux is not officially supported by the RabbitMQ team -- use at your own risk!
|
|
||||||
FROM alpine:3.12
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
# grab su-exec for easy step-down from root
|
|
||||||
'su-exec>=0.2' \
|
|
||||||
# bash for docker-entrypoint.sh
|
|
||||||
bash \
|
|
||||||
# "ps" for "rabbitmqctl wait" (https://github.com/docker-library/rabbitmq/issues/162)
|
|
||||||
procps
|
|
||||||
|
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
|
||||||
ENV OPENSSL_VERSION 1.1.1g
|
|
||||||
ENV OPENSSL_SOURCE_SHA256="ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46"
|
|
||||||
# https://www.openssl.org/community/omc.html
|
|
||||||
ENV OPENSSL_PGP_KEY_IDS="0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D"
|
|
||||||
|
|
||||||
# Use the latest stable Erlang/OTP release (https://github.com/erlang/otp/tags)
|
|
||||||
ENV OTP_VERSION 22.3.4.4
|
|
||||||
# TODO add PGP checking when the feature will be added to Erlang/OTP's build system
|
|
||||||
# http://erlang.org/pipermail/erlang-questions/2019-January/097067.html
|
|
||||||
ENV OTP_SOURCE_SHA256="8dd1f21eadf5973f3278a4035a629f538bfbe3664679b45fe1d94b65f2f4a716"
|
|
||||||
|
|
||||||
# Install dependencies required to build Erlang/OTP from source
|
|
||||||
# http://erlang.org/doc/installation_guide/INSTALL.html
|
|
||||||
# autoconf: Required to configure Erlang/OTP before compiling
|
|
||||||
# dpkg-dev: Required to set up host & build type when compiling Erlang/OTP
|
|
||||||
# gnupg: Required to verify OpenSSL artefacts
|
|
||||||
# libncurses5-dev: Required for Erlang/OTP new shell & observer_cli - https://github.com/zhongwencool/observer_cli
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
apk add --no-cache --virtual .build-deps \
|
|
||||||
autoconf \
|
|
||||||
dpkg-dev dpkg \
|
|
||||||
gcc \
|
|
||||||
gnupg \
|
|
||||||
libc-dev \
|
|
||||||
linux-headers \
|
|
||||||
make \
|
|
||||||
ncurses-dev \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
OPENSSL_SOURCE_URL="https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"; \
|
|
||||||
OPENSSL_PATH="/usr/local/src/openssl-$OPENSSL_VERSION"; \
|
|
||||||
OPENSSL_CONFIG_DIR=/usr/local/etc/ssl; \
|
|
||||||
\
|
|
||||||
# /usr/local/src doesn't exist in Alpine by default
|
|
||||||
mkdir /usr/local/src; \
|
|
||||||
\
|
|
||||||
# Required by the crypto & ssl Erlang/OTP applications
|
|
||||||
wget --output-document "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_SOURCE_URL.asc"; \
|
|
||||||
wget --output-document "$OPENSSL_PATH.tar.gz" "$OPENSSL_SOURCE_URL"; \
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
for key in $OPENSSL_PGP_KEY_IDS; do \
|
|
||||||
gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$key"; \
|
|
||||||
done; \
|
|
||||||
gpg --batch --verify "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_PATH.tar.gz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
echo "$OPENSSL_SOURCE_SHA256 *$OPENSSL_PATH.tar.gz" | sha256sum -c -; \
|
|
||||||
mkdir -p "$OPENSSL_PATH"; \
|
|
||||||
tar --extract --file "$OPENSSL_PATH.tar.gz" --directory "$OPENSSL_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure OpenSSL for compilation
|
|
||||||
cd "$OPENSSL_PATH"; \
|
|
||||||
# OpenSSL's "config" script uses a lot of "uname"-based target detection...
|
|
||||||
MACHINE="$(dpkg-architecture --query DEB_BUILD_GNU_CPU)" \
|
|
||||||
RELEASE="4.x.y-z" \
|
|
||||||
SYSTEM='Linux' \
|
|
||||||
BUILD='???' \
|
|
||||||
./config \
|
|
||||||
--openssldir="$OPENSSL_CONFIG_DIR" \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
-Wl,-rpath=/usr/local/lib \
|
|
||||||
; \
|
|
||||||
# Compile, install OpenSSL, verify that the command-line works & development headers are present
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)"; \
|
|
||||||
make install_sw install_ssldirs; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf "$OPENSSL_PATH"*; \
|
|
||||||
# use Alpine's CA certificates
|
|
||||||
rmdir "$OPENSSL_CONFIG_DIR/certs" "$OPENSSL_CONFIG_DIR/private"; \
|
|
||||||
ln -sf /etc/ssl/certs /etc/ssl/private "$OPENSSL_CONFIG_DIR"; \
|
|
||||||
# smoke test
|
|
||||||
openssl version; \
|
|
||||||
\
|
|
||||||
OTP_SOURCE_URL="https://github.com/erlang/otp/archive/OTP-$OTP_VERSION.tar.gz"; \
|
|
||||||
OTP_PATH="/usr/local/src/otp-$OTP_VERSION"; \
|
|
||||||
\
|
|
||||||
# Download, verify & extract OTP_SOURCE
|
|
||||||
mkdir -p "$OTP_PATH"; \
|
|
||||||
wget --output-document "$OTP_PATH.tar.gz" "$OTP_SOURCE_URL"; \
|
|
||||||
echo "$OTP_SOURCE_SHA256 *$OTP_PATH.tar.gz" | sha256sum -c -; \
|
|
||||||
tar --extract --file "$OTP_PATH.tar.gz" --directory "$OTP_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure Erlang/OTP for compilation, disable unused features & applications
|
|
||||||
# http://erlang.org/doc/applications.html
|
|
||||||
# ERL_TOP is required for Erlang/OTP makefiles to find the absolute path for the installation
|
|
||||||
cd "$OTP_PATH"; \
|
|
||||||
export ERL_TOP="$OTP_PATH"; \
|
|
||||||
./otp_build autoconf; \
|
|
||||||
export CFLAGS='-g -O2'; \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
export CFLAGS="$CFLAGS -Wl,-rpath=/usr/local/lib"; \
|
|
||||||
hostArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"; \
|
|
||||||
buildArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
|
|
||||||
dpkgArch="$(dpkg --print-architecture)"; dpkgArch="${dpkgArch##*-}"; \
|
|
||||||
./configure \
|
|
||||||
--host="$hostArch" \
|
|
||||||
--build="$buildArch" \
|
|
||||||
--disable-dynamic-ssl-lib \
|
|
||||||
--disable-hipe \
|
|
||||||
--disable-sctp \
|
|
||||||
--disable-silent-rules \
|
|
||||||
--enable-clock-gettime \
|
|
||||||
--enable-hybrid-heap \
|
|
||||||
--enable-kernel-poll \
|
|
||||||
--enable-shared-zlib \
|
|
||||||
--enable-smp-support \
|
|
||||||
--enable-threads \
|
|
||||||
--with-microstate-accounting=extra \
|
|
||||||
--without-common_test \
|
|
||||||
--without-debugger \
|
|
||||||
--without-dialyzer \
|
|
||||||
--without-diameter \
|
|
||||||
--without-edoc \
|
|
||||||
--without-erl_docgen \
|
|
||||||
--without-erl_interface \
|
|
||||||
--without-et \
|
|
||||||
--without-eunit \
|
|
||||||
--without-ftp \
|
|
||||||
--without-hipe \
|
|
||||||
--without-jinterface \
|
|
||||||
--without-megaco \
|
|
||||||
--without-observer \
|
|
||||||
--without-odbc \
|
|
||||||
--without-reltool \
|
|
||||||
--without-ssh \
|
|
||||||
--without-tftp \
|
|
||||||
--without-wx \
|
|
||||||
; \
|
|
||||||
# Compile & install Erlang/OTP
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)" GEN_OPT_FLGS="-O2 -fno-strict-aliasing"; \
|
|
||||||
make install; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf \
|
|
||||||
"$OTP_PATH"* \
|
|
||||||
/usr/local/lib/erlang/lib/*/examples \
|
|
||||||
/usr/local/lib/erlang/lib/*/src \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
runDeps="$( \
|
|
||||||
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
|
|
||||||
| tr ',' '\n' \
|
|
||||||
| sort -u \
|
|
||||||
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
|
||||||
)"; \
|
|
||||||
apk add --no-cache --virtual .otp-run-deps $runDeps; \
|
|
||||||
apk del --no-network .build-deps; \
|
|
||||||
\
|
|
||||||
# Check that OpenSSL still works after purging build dependencies
|
|
||||||
openssl version; \
|
|
||||||
# Check that Erlang/OTP crypto & ssl were compiled against OpenSSL correctly
|
|
||||||
erl -noshell -eval 'io:format("~p~n~n~p~n~n", [crypto:supports(), ssl:versions()]), init:stop().'
|
|
||||||
|
|
||||||
ENV RABBITMQ_DATA_DIR=/var/lib/rabbitmq
|
|
||||||
# Create rabbitmq system user & group, fix permissions & allow root user to connect to the RabbitMQ Erlang VM
|
|
||||||
RUN set -eux; \
|
|
||||||
addgroup -g 101 -S rabbitmq; \
|
|
||||||
adduser -u 100 -S -h "$RABBITMQ_DATA_DIR" -G rabbitmq rabbitmq; \
|
|
||||||
mkdir -p "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chown -fR rabbitmq:rabbitmq "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chmod 777 "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
ln -sf "$RABBITMQ_DATA_DIR/.erlang.cookie" /root/.erlang.cookie
|
|
||||||
|
|
||||||
# Use the latest stable RabbitMQ release (https://www.rabbitmq.com/download.html)
|
|
||||||
ENV RABBITMQ_VERSION 3.7.27-rc.1
|
|
||||||
# https://www.rabbitmq.com/signatures.html#importing-gpg
|
|
||||||
ENV RABBITMQ_PGP_KEY_ID="0x0A9AF2115F4687BD29803A206B73A36E6026DFCA"
|
|
||||||
ENV RABBITMQ_HOME=/opt/rabbitmq
|
|
||||||
|
|
||||||
# Add RabbitMQ to PATH, send all logs to TTY
|
|
||||||
ENV PATH=$RABBITMQ_HOME/sbin:$PATH \
|
|
||||||
RABBITMQ_LOGS=-
|
|
||||||
|
|
||||||
# Install RabbitMQ
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
apk add --no-cache --virtual .build-deps \
|
|
||||||
gnupg \
|
|
||||||
xz \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
RABBITMQ_SOURCE_URL="https://github.com/rabbitmq/rabbitmq-server/releases/download/v$RABBITMQ_VERSION/rabbitmq-server-generic-unix-latest-toolchain-$RABBITMQ_VERSION.tar.xz"; \
|
|
||||||
RABBITMQ_PATH="/usr/local/src/rabbitmq-$RABBITMQ_VERSION"; \
|
|
||||||
\
|
|
||||||
wget --output-document "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_SOURCE_URL.asc"; \
|
|
||||||
wget --output-document "$RABBITMQ_PATH.tar.xz" "$RABBITMQ_SOURCE_URL"; \
|
|
||||||
\
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$RABBITMQ_PGP_KEY_ID"; \
|
|
||||||
gpg --batch --verify "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_PATH.tar.xz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
\
|
|
||||||
mkdir -p "$RABBITMQ_HOME"; \
|
|
||||||
tar --extract --file "$RABBITMQ_PATH.tar.xz" --directory "$RABBITMQ_HOME" --strip-components 1; \
|
|
||||||
rm -rf "$RABBITMQ_PATH"*; \
|
|
||||||
# Do not default SYS_PREFIX to RABBITMQ_HOME, leave it empty
|
|
||||||
grep -qE '^SYS_PREFIX=\$\{RABBITMQ_HOME\}$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
sed -i 's/^SYS_PREFIX=.*$/SYS_PREFIX=/' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
grep -qE '^SYS_PREFIX=$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
chown -R rabbitmq:rabbitmq "$RABBITMQ_HOME"; \
|
|
||||||
\
|
|
||||||
apk del .build-deps; \
|
|
||||||
\
|
|
||||||
# verify assumption of no stale cookies
|
|
||||||
[ ! -e "$RABBITMQ_DATA_DIR/.erlang.cookie" ]; \
|
|
||||||
# Ensure RabbitMQ was installed correctly by running a few commands that do not depend on a running server, as the rabbitmq user
|
|
||||||
# If they all succeed, it's safe to assume that things have been set up correctly
|
|
||||||
su-exec rabbitmq rabbitmqctl help; \
|
|
||||||
su-exec rabbitmq rabbitmqctl list_ciphers; \
|
|
||||||
su-exec rabbitmq rabbitmq-plugins list; \
|
|
||||||
# no stale cookies
|
|
||||||
rm "$RABBITMQ_DATA_DIR/.erlang.cookie"
|
|
||||||
|
|
||||||
# Added for backwards compatibility - users can simply COPY custom plugins to /plugins
|
|
||||||
RUN ln -sf /opt/rabbitmq/plugins /plugins
|
|
||||||
|
|
||||||
# set home so that any `--user` knows where to put the erlang cookie
|
|
||||||
ENV HOME $RABBITMQ_DATA_DIR
|
|
||||||
# Hint that the data (a.k.a. home dir) dir should be separate volume
|
|
||||||
VOLUME $RABBITMQ_DATA_DIR
|
|
||||||
|
|
||||||
# warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
|
|
||||||
# Setting all environment variables that control language preferences, behaviour differs - https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
|
|
||||||
# https://docs.docker.com/samples/library/ubuntu/#locales
|
|
||||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
|
|
||||||
EXPOSE 4369 5671 5672 25672
|
|
||||||
CMD ["rabbitmq-server"]
|
|
||||||
|
|
@ -1,415 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# usage: file_env VAR [DEFAULT]
|
|
||||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
|
||||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
|
||||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
|
||||||
file_env() {
|
|
||||||
local var="$1"
|
|
||||||
local fileVar="${var}_FILE"
|
|
||||||
local def="${2:-}"
|
|
||||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
||||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local val="$def"
|
|
||||||
if [ "${!var:-}" ]; then
|
|
||||||
val="${!var}"
|
|
||||||
elif [ "${!fileVar:-}" ]; then
|
|
||||||
val="$(< "${!fileVar}")"
|
|
||||||
fi
|
|
||||||
export "$var"="$val"
|
|
||||||
unset "$fileVar"
|
|
||||||
}
|
|
||||||
|
|
||||||
# backwards compatibility for old environment variables
|
|
||||||
: "${RABBITMQ_SSL_CERTFILE:=${RABBITMQ_SSL_CERT_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_KEYFILE:=${RABBITMQ_SSL_KEY_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_CACERTFILE:=${RABBITMQ_SSL_CA_FILE:-}}"
|
|
||||||
|
|
||||||
# "management" SSL config should default to using the same certs
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CACERTFILE:=$RABBITMQ_SSL_CACERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CERTFILE:=$RABBITMQ_SSL_CERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_KEYFILE:=$RABBITMQ_SSL_KEYFILE}"
|
|
||||||
|
|
||||||
# Allowed env vars that will be read from mounted files (i.e. Docker Secrets):
|
|
||||||
fileEnvKeys=(
|
|
||||||
default_user
|
|
||||||
default_pass
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://www.rabbitmq.com/configure.html
|
|
||||||
sslConfigKeys=(
|
|
||||||
cacertfile
|
|
||||||
certfile
|
|
||||||
depth
|
|
||||||
fail_if_no_peer_cert
|
|
||||||
keyfile
|
|
||||||
verify
|
|
||||||
)
|
|
||||||
managementConfigKeys=(
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
rabbitConfigKeys=(
|
|
||||||
default_pass
|
|
||||||
default_user
|
|
||||||
default_vhost
|
|
||||||
vm_memory_high_watermark
|
|
||||||
)
|
|
||||||
fileConfigKeys=(
|
|
||||||
management_ssl_cacertfile
|
|
||||||
management_ssl_certfile
|
|
||||||
management_ssl_keyfile
|
|
||||||
ssl_cacertfile
|
|
||||||
ssl_certfile
|
|
||||||
ssl_keyfile
|
|
||||||
)
|
|
||||||
allConfigKeys=(
|
|
||||||
"${managementConfigKeys[@]/#/management_}"
|
|
||||||
"${rabbitConfigKeys[@]}"
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -A configDefaults=(
|
|
||||||
[management_ssl_fail_if_no_peer_cert]='false'
|
|
||||||
[management_ssl_verify]='verify_none'
|
|
||||||
|
|
||||||
[ssl_fail_if_no_peer_cert]='true'
|
|
||||||
[ssl_verify]='verify_peer'
|
|
||||||
)
|
|
||||||
|
|
||||||
# allow the container to be started with `--user`
|
|
||||||
if [[ "$1" == rabbitmq* ]] && [ "$(id -u)" = '0' ]; then
|
|
||||||
# this needs to happen late enough that we have the SSL config
|
|
||||||
# https://github.com/docker-library/rabbitmq/issues/283
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
[ -n "$val" ] || continue
|
|
||||||
case "$conf" in
|
|
||||||
*_ssl_*file | ssl_*file )
|
|
||||||
if [ -f "$val" ] && ! su-exec rabbitmq test -r "$val"; then
|
|
||||||
newFile="/tmp/rabbitmq-ssl/$conf.pem"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$val' ($var) is not readable by rabbitmq ($(id rabbitmq)); copying to '$newFile'"
|
|
||||||
echo >&2
|
|
||||||
cat "$val" > "$newFile"
|
|
||||||
chown rabbitmq "$newFile"
|
|
||||||
chmod 0400 "$newFile"
|
|
||||||
eval 'export '$var'="$newFile"'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ]; then
|
|
||||||
find /var/lib/rabbitmq \! -user rabbitmq -exec chown rabbitmq '{}' +
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec su-exec rabbitmq "$BASH_SOURCE" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
haveConfig=
|
|
||||||
haveSslConfig=
|
|
||||||
haveManagementSslConfig=
|
|
||||||
for fileEnvKey in "${fileEnvKeys[@]}"; do file_env "RABBITMQ_${fileEnvKey^^}"; done
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
if [ "$val" ]; then
|
|
||||||
if [ "${configDefaults[$conf]:-}" ] && [ "${configDefaults[$conf]}" = "$val" ]; then
|
|
||||||
# if the value set is the same as the default, treat it as if it isn't set
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
haveConfig=1
|
|
||||||
case "$conf" in
|
|
||||||
ssl_*) haveSslConfig=1 ;;
|
|
||||||
management_ssl_*) haveManagementSslConfig=1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
missing=()
|
|
||||||
for sslConf in cacertfile certfile keyfile; do
|
|
||||||
var="RABBITMQ_SSL_${sslConf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ -z "$val" ]; then
|
|
||||||
missing+=( "$var" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missing[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: SSL requested, but missing required configuration'
|
|
||||||
for miss in "${missing[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
missingFiles=()
|
|
||||||
for conf in "${fileConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ "$val" ] && [ ! -f "$val" ]; then
|
|
||||||
missingFiles+=( "$val ($var)" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missingFiles[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: files specified, but missing'
|
|
||||||
for miss in "${missingFiles[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set defaults for missing values (but only after we're done with all our checking so we don't throw any of that off)
|
|
||||||
for conf in "${!configDefaults[@]}"; do
|
|
||||||
default="${configDefaults[$conf]}"
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
[ -z "${!var:-}" ] || continue
|
|
||||||
eval "export $var=\"\$default\""
|
|
||||||
done
|
|
||||||
|
|
||||||
# if long and short hostnames are not the same, use long hostnames
|
|
||||||
if [ "$(hostname)" != "$(hostname -s)" ]; then
|
|
||||||
: "${RABBITMQ_USE_LONGNAME:=true}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${RABBITMQ_ERLANG_COOKIE:-}" ]; then
|
|
||||||
cookieFile='/var/lib/rabbitmq/.erlang.cookie'
|
|
||||||
if [ -e "$cookieFile" ]; then
|
|
||||||
if [ "$(cat "$cookieFile" 2>/dev/null)" != "$RABBITMQ_ERLANG_COOKIE" ]; then
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "warning: $cookieFile contents do not match RABBITMQ_ERLANG_COOKIE"
|
|
||||||
echo >&2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$RABBITMQ_ERLANG_COOKIE" > "$cookieFile"
|
|
||||||
fi
|
|
||||||
chmod 600 "$cookieFile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
configBase="${RABBITMQ_CONFIG_FILE:-/etc/rabbitmq/rabbitmq}"
|
|
||||||
oldConfigFile="$configBase.config"
|
|
||||||
newConfigFile="$configBase.conf"
|
|
||||||
|
|
||||||
shouldWriteConfig="$haveConfig"
|
|
||||||
if [ -n "$shouldWriteConfig" ] && ! touch "$newConfigFile"; then
|
|
||||||
# config file exists but it isn't writeable (likely read-only mount, such as Kubernetes configMap)
|
|
||||||
export RABBITMQ_CONFIG_FILE='/tmp/rabbitmq.conf'
|
|
||||||
cp "$newConfigFile" "$RABBITMQ_CONFIG_FILE"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$newConfigFile' is not writable, but environment variables have been provided which request that we write to it"
|
|
||||||
echo >&2 " We have copied it to '$RABBITMQ_CONFIG_FILE' so it can be amended to work around the problem, but it is recommended that the read-only source file should be modified and the environment variables removed instead."
|
|
||||||
echo >&2
|
|
||||||
newConfigFile="$RABBITMQ_CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$shouldWriteConfig" ] && [ -f "$oldConfigFile" ]; then
|
|
||||||
{
|
|
||||||
echo "error: Docker configuration environment variables specified, but old-style (Erlang syntax) configuration file '$oldConfigFile' exists"
|
|
||||||
echo " Suggested fixes: (choose one)"
|
|
||||||
echo " - remove '$oldConfigFile'"
|
|
||||||
echo " - remove any Docker-specific 'RABBITMQ_...' environment variables"
|
|
||||||
echo " - convert '$oldConfigFile' to the newer sysctl format ('$newConfigFile'); see https://www.rabbitmq.com/configure.html#config-file"
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$shouldWriteConfig" ] && [ ! -f "$oldConfigFile" ] && [ ! -f "$newConfigFile" ]; then
|
|
||||||
# no config files, we should write one
|
|
||||||
shouldWriteConfig=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# http://stackoverflow.com/a/2705678/433558
|
|
||||||
sed_escape_lhs() {
|
|
||||||
echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g'
|
|
||||||
}
|
|
||||||
sed_escape_rhs() {
|
|
||||||
echo "$@" | sed -e 's/[\/&]/\\&/g'
|
|
||||||
}
|
|
||||||
rabbit_set_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
local val="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
local sedVal="$(sed_escape_rhs "$val")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*)\S.*\$/\1${sedVal}/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
if ! grep -qE "^${sedKey}[[:space:]]*=" "$newConfigFile"; then
|
|
||||||
echo "$key = $val" >> "$newConfigFile"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
rabbit_comment_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*#?[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*\S.*)\$/# \1/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
}
|
|
||||||
rabbit_env_config() {
|
|
||||||
local prefix="$1"; shift
|
|
||||||
|
|
||||||
local conf
|
|
||||||
for conf; do
|
|
||||||
local var="rabbitmq${prefix:+_$prefix}_$conf"
|
|
||||||
var="${var^^}"
|
|
||||||
|
|
||||||
local key="$conf"
|
|
||||||
case "$prefix" in
|
|
||||||
ssl) key="ssl_options.$key" ;;
|
|
||||||
management_ssl) key="management.ssl.$key" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
local val="${!var:-}"
|
|
||||||
local rawVal="$val"
|
|
||||||
case "$conf" in
|
|
||||||
fail_if_no_peer_cert)
|
|
||||||
case "${val,,}" in
|
|
||||||
false|no|0|'') rawVal='false' ;;
|
|
||||||
true|yes|1|*) rawVal='true' ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
|
|
||||||
vm_memory_high_watermark) continue ;; # handled separately
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$rawVal" ]; then
|
|
||||||
rabbit_set_config "$key" "$rawVal"
|
|
||||||
else
|
|
||||||
rabbit_comment_config "$key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ] && [ "$shouldWriteConfig" ]; then
|
|
||||||
rabbit_set_config 'loopback_users.guest' 'false'
|
|
||||||
|
|
||||||
# determine whether to set "vm_memory_high_watermark" (based on cgroups)
|
|
||||||
memTotalKb=
|
|
||||||
if [ -r /proc/meminfo ]; then
|
|
||||||
memTotalKb="$(awk -F ':? +' '$1 == "MemTotal" { print $2; exit }' /proc/meminfo)"
|
|
||||||
fi
|
|
||||||
memLimitB=
|
|
||||||
if [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
|
||||||
# "18446744073709551615" is a valid value for "memory.limit_in_bytes", which is too big for Bash math to handle
|
|
||||||
# "$(( 18446744073709551615 / 1024 ))" = 0; "$(( 18446744073709551615 * 40 / 100 ))" = 0
|
|
||||||
memLimitB="$(awk -v totKb="$memTotalKb" '{
|
|
||||||
limB = $0;
|
|
||||||
limKb = limB / 1024;
|
|
||||||
if (!totKb || limKb < totKb) {
|
|
||||||
printf "%.0f\n", limB;
|
|
||||||
}
|
|
||||||
}' /sys/fs/cgroup/memory/memory.limit_in_bytes)"
|
|
||||||
fi
|
|
||||||
if [ -n "$memLimitB" ]; then
|
|
||||||
# if we have a cgroup memory limit, let's inform RabbitMQ of what it is (so it can calculate vm_memory_high_watermark properly)
|
|
||||||
# https://github.com/rabbitmq/rabbitmq-server/pull/1234
|
|
||||||
rabbit_set_config 'total_memory_available_override_value' "$memLimitB"
|
|
||||||
fi
|
|
||||||
# https://www.rabbitmq.com/memory.html#memsup-usage
|
|
||||||
if [ "${RABBITMQ_VM_MEMORY_HIGH_WATERMARK:-}" ]; then
|
|
||||||
# https://github.com/docker-library/rabbitmq/pull/105#issuecomment-242165822
|
|
||||||
vmMemoryHighWatermark="$(
|
|
||||||
echo "$RABBITMQ_VM_MEMORY_HIGH_WATERMARK" | awk '
|
|
||||||
/^[0-9]*[.][0-9]+$|^[0-9]+([.][0-9]+)?%$/ {
|
|
||||||
perc = $0;
|
|
||||||
if (perc ~ /%$/) {
|
|
||||||
gsub(/%$/, "", perc);
|
|
||||||
perc = perc / 100;
|
|
||||||
}
|
|
||||||
if (perc > 1.0 || perc < 0.0) {
|
|
||||||
printf "error: invalid percentage for vm_memory_high_watermark: %s (must be >= 0%%, <= 100%%)\n", $0 > "/dev/stderr";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
printf "vm_memory_high_watermark.relative %0.03f\n", perc;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+([.][0-9]+)?[a-zA-Z]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
printf "error: unexpected input for vm_memory_high_watermark: %s\n", $0;
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
'
|
|
||||||
)"
|
|
||||||
if [ "$vmMemoryHighWatermark" ]; then
|
|
||||||
vmMemoryHighWatermarkKey="${vmMemoryHighWatermark%% *}"
|
|
||||||
vmMemoryHighWatermarkVal="${vmMemoryHighWatermark#$vmMemoryHighWatermarkKey }"
|
|
||||||
rabbit_set_config "$vmMemoryHighWatermarkKey" "$vmMemoryHighWatermarkVal"
|
|
||||||
case "$vmMemoryHighWatermarkKey" in
|
|
||||||
# make sure we only set one or the other
|
|
||||||
'vm_memory_high_watermark.absolute') rabbit_comment_config 'vm_memory_high_watermark.relative' ;;
|
|
||||||
'vm_memory_high_watermark.relative') rabbit_comment_config 'vm_memory_high_watermark.absolute' ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
rabbit_set_config 'listeners.ssl.default' 5671
|
|
||||||
rabbit_env_config 'ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'listeners.tcp.default' 5672
|
|
||||||
fi
|
|
||||||
|
|
||||||
rabbit_env_config '' "${rabbitConfigKeys[@]}"
|
|
||||||
|
|
||||||
# if management plugin is installed, generate config for it
|
|
||||||
# https://www.rabbitmq.com/management.html#configuration
|
|
||||||
if [ "$(rabbitmq-plugins list -q -m -e rabbitmq_management)" ]; then
|
|
||||||
if [ "$haveManagementSslConfig" ]; then
|
|
||||||
rabbit_set_config 'management.ssl.port' 15671
|
|
||||||
rabbit_env_config 'management_ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'management.tcp.port' 15672
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if definitions file exists, then load it
|
|
||||||
# https://www.rabbitmq.com/management.html#load-definitions
|
|
||||||
managementDefinitionsFile='/etc/rabbitmq/definitions.json'
|
|
||||||
if [ -f "$managementDefinitionsFile" ]; then
|
|
||||||
# see also https://github.com/docker-library/rabbitmq/pull/112#issuecomment-271485550
|
|
||||||
rabbit_set_config 'management.load_definitions' "$managementDefinitionsFile"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
combinedSsl='/tmp/rabbitmq-ssl/combined.pem'
|
|
||||||
if [ "$haveSslConfig" ] && [[ "$1" == rabbitmq* ]] && [ ! -f "$combinedSsl" ]; then
|
|
||||||
# Create combined cert
|
|
||||||
{
|
|
||||||
cat "$RABBITMQ_SSL_CERTFILE"
|
|
||||||
echo # https://github.com/docker-library/rabbitmq/issues/357#issuecomment-517755647
|
|
||||||
cat "$RABBITMQ_SSL_KEYFILE"
|
|
||||||
} > "$combinedSsl"
|
|
||||||
chmod 0400 "$combinedSsl"
|
|
||||||
fi
|
|
||||||
if [ "$haveSslConfig" ] && [ -f "$combinedSsl" ]; then
|
|
||||||
# More ENV vars for make clustering happiness
|
|
||||||
# we don't handle clustering in this script, but these args should ensure
|
|
||||||
# clustered SSL-enabled members will talk nicely
|
|
||||||
export ERL_SSL_PATH="$(erl -eval 'io:format("~p", [code:lib_dir(ssl, ebin)]),halt().' -noshell)"
|
|
||||||
sslErlArgs="-pa $ERL_SSL_PATH -proto_dist inet_tls -ssl_dist_opt server_certfile $combinedSsl -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
|
|
||||||
export RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
export RABBITMQ_CTL_ERL_ARGS="${RABBITMQ_CTL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
FROM rabbitmq:3.7-rc-alpine
|
|
||||||
|
|
||||||
RUN rabbitmq-plugins enable --offline rabbitmq_management
|
|
||||||
|
|
||||||
# extract "rabbitmqadmin" from inside the "rabbitmq_management-X.Y.Z.ez" plugin zipfile
|
|
||||||
# see https://github.com/docker-library/rabbitmq/issues/207
|
|
||||||
RUN set -eux; \
|
|
||||||
erl -noinput -eval ' \
|
|
||||||
{ ok, AdminBin } = zip:foldl(fun(FileInArchive, GetInfo, GetBin, Acc) -> \
|
|
||||||
case Acc of \
|
|
||||||
"" -> \
|
|
||||||
case lists:suffix("/rabbitmqadmin", FileInArchive) of \
|
|
||||||
true -> GetBin(); \
|
|
||||||
false -> Acc \
|
|
||||||
end; \
|
|
||||||
_ -> Acc \
|
|
||||||
end \
|
|
||||||
end, "", init:get_plain_arguments()), \
|
|
||||||
io:format("~s", [ AdminBin ]), \
|
|
||||||
init:stop(). \
|
|
||||||
' -- /plugins/rabbitmq_management-*.ez > /usr/local/bin/rabbitmqadmin; \
|
|
||||||
[ -s /usr/local/bin/rabbitmqadmin ]; \
|
|
||||||
chmod +x /usr/local/bin/rabbitmqadmin; \
|
|
||||||
apk add --no-cache python3; \
|
|
||||||
rabbitmqadmin --version
|
|
||||||
|
|
||||||
EXPOSE 15671 15672
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
# The official Canonical Ubuntu Bionic image is ideal from a security perspective,
|
|
||||||
# especially for the enterprises that we, the RabbitMQ team, have to deal with
|
|
||||||
FROM ubuntu:18.04
|
|
||||||
|
|
||||||
RUN set -eux; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
# grab gosu for easy step-down from root
|
|
||||||
gosu \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
# verify that the "gosu" binary works
|
|
||||||
gosu nobody true
|
|
||||||
|
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
|
||||||
ENV OPENSSL_VERSION 1.1.1g
|
|
||||||
ENV OPENSSL_SOURCE_SHA256="ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46"
|
|
||||||
# https://www.openssl.org/community/omc.html
|
|
||||||
ENV OPENSSL_PGP_KEY_IDS="0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D"
|
|
||||||
|
|
||||||
# Use the latest stable Erlang/OTP release (https://github.com/erlang/otp/tags)
|
|
||||||
ENV OTP_VERSION 22.3.4.4
|
|
||||||
# TODO add PGP checking when the feature will be added to Erlang/OTP's build system
|
|
||||||
# http://erlang.org/pipermail/erlang-questions/2019-January/097067.html
|
|
||||||
ENV OTP_SOURCE_SHA256="8dd1f21eadf5973f3278a4035a629f538bfbe3664679b45fe1d94b65f2f4a716"
|
|
||||||
|
|
||||||
# Install dependencies required to build Erlang/OTP from source
|
|
||||||
# http://erlang.org/doc/installation_guide/INSTALL.html
|
|
||||||
# autoconf: Required to configure Erlang/OTP before compiling
|
|
||||||
# dpkg-dev: Required to set up host & build type when compiling Erlang/OTP
|
|
||||||
# gnupg: Required to verify OpenSSL artefacts
|
|
||||||
# libncurses5-dev: Required for Erlang/OTP new shell & observer_cli - https://github.com/zhongwencool/observer_cli
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
savedAptMark="$(apt-mark showmanual)"; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install --yes --no-install-recommends \
|
|
||||||
autoconf \
|
|
||||||
ca-certificates \
|
|
||||||
dpkg-dev \
|
|
||||||
gcc \
|
|
||||||
gnupg \
|
|
||||||
libncurses5-dev \
|
|
||||||
make \
|
|
||||||
wget \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
\
|
|
||||||
OPENSSL_SOURCE_URL="https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"; \
|
|
||||||
OPENSSL_PATH="/usr/local/src/openssl-$OPENSSL_VERSION"; \
|
|
||||||
OPENSSL_CONFIG_DIR=/usr/local/etc/ssl; \
|
|
||||||
\
|
|
||||||
# Required by the crypto & ssl Erlang/OTP applications
|
|
||||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_SOURCE_URL.asc"; \
|
|
||||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz" "$OPENSSL_SOURCE_URL"; \
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
for key in $OPENSSL_PGP_KEY_IDS; do \
|
|
||||||
gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$key"; \
|
|
||||||
done; \
|
|
||||||
gpg --batch --verify "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_PATH.tar.gz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
echo "$OPENSSL_SOURCE_SHA256 *$OPENSSL_PATH.tar.gz" | sha256sum --check --strict -; \
|
|
||||||
mkdir -p "$OPENSSL_PATH"; \
|
|
||||||
tar --extract --file "$OPENSSL_PATH.tar.gz" --directory "$OPENSSL_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure OpenSSL for compilation
|
|
||||||
cd "$OPENSSL_PATH"; \
|
|
||||||
# without specifying "--libdir", Erlang will fail during "crypto:supports()" looking for a "pthread_atfork" function that doesn't exist (but only on arm32v7/armhf??)
|
|
||||||
debMultiarch="$(dpkg-architecture --query DEB_HOST_MULTIARCH)"; \
|
|
||||||
# OpenSSL's "config" script uses a lot of "uname"-based target detection...
|
|
||||||
MACHINE="$(dpkg-architecture --query DEB_BUILD_GNU_CPU)" \
|
|
||||||
RELEASE="4.x.y-z" \
|
|
||||||
SYSTEM='Linux' \
|
|
||||||
BUILD='???' \
|
|
||||||
./config \
|
|
||||||
--openssldir="$OPENSSL_CONFIG_DIR" \
|
|
||||||
--libdir="lib/$debMultiarch" \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
-Wl,-rpath=/usr/local/lib \
|
|
||||||
; \
|
|
||||||
# Compile, install OpenSSL, verify that the command-line works & development headers are present
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)"; \
|
|
||||||
make install_sw install_ssldirs; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf "$OPENSSL_PATH"*; \
|
|
||||||
ldconfig; \
|
|
||||||
# use Debian's CA certificates
|
|
||||||
rmdir "$OPENSSL_CONFIG_DIR/certs" "$OPENSSL_CONFIG_DIR/private"; \
|
|
||||||
ln -sf /etc/ssl/certs /etc/ssl/private "$OPENSSL_CONFIG_DIR"; \
|
|
||||||
# smoke test
|
|
||||||
openssl version; \
|
|
||||||
\
|
|
||||||
OTP_SOURCE_URL="https://github.com/erlang/otp/archive/OTP-$OTP_VERSION.tar.gz"; \
|
|
||||||
OTP_PATH="/usr/local/src/otp-$OTP_VERSION"; \
|
|
||||||
\
|
|
||||||
# Download, verify & extract OTP_SOURCE
|
|
||||||
mkdir -p "$OTP_PATH"; \
|
|
||||||
wget --progress dot:giga --output-document "$OTP_PATH.tar.gz" "$OTP_SOURCE_URL"; \
|
|
||||||
echo "$OTP_SOURCE_SHA256 *$OTP_PATH.tar.gz" | sha256sum --check --strict -; \
|
|
||||||
tar --extract --file "$OTP_PATH.tar.gz" --directory "$OTP_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure Erlang/OTP for compilation, disable unused features & applications
|
|
||||||
# http://erlang.org/doc/applications.html
|
|
||||||
# ERL_TOP is required for Erlang/OTP makefiles to find the absolute path for the installation
|
|
||||||
cd "$OTP_PATH"; \
|
|
||||||
export ERL_TOP="$OTP_PATH"; \
|
|
||||||
./otp_build autoconf; \
|
|
||||||
CFLAGS="$(dpkg-buildflags --get CFLAGS)"; export CFLAGS; \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
export CFLAGS="$CFLAGS -Wl,-rpath=/usr/local/lib"; \
|
|
||||||
hostArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"; \
|
|
||||||
buildArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
|
|
||||||
dpkgArch="$(dpkg --print-architecture)"; dpkgArch="${dpkgArch##*-}"; \
|
|
||||||
./configure \
|
|
||||||
--host="$hostArch" \
|
|
||||||
--build="$buildArch" \
|
|
||||||
--disable-dynamic-ssl-lib \
|
|
||||||
--disable-hipe \
|
|
||||||
--disable-sctp \
|
|
||||||
--disable-silent-rules \
|
|
||||||
--enable-clock-gettime \
|
|
||||||
--enable-hybrid-heap \
|
|
||||||
--enable-kernel-poll \
|
|
||||||
--enable-shared-zlib \
|
|
||||||
--enable-smp-support \
|
|
||||||
--enable-threads \
|
|
||||||
--with-microstate-accounting=extra \
|
|
||||||
--without-common_test \
|
|
||||||
--without-debugger \
|
|
||||||
--without-dialyzer \
|
|
||||||
--without-diameter \
|
|
||||||
--without-edoc \
|
|
||||||
--without-erl_docgen \
|
|
||||||
--without-erl_interface \
|
|
||||||
--without-et \
|
|
||||||
--without-eunit \
|
|
||||||
--without-ftp \
|
|
||||||
--without-hipe \
|
|
||||||
--without-jinterface \
|
|
||||||
--without-megaco \
|
|
||||||
--without-observer \
|
|
||||||
--without-odbc \
|
|
||||||
--without-reltool \
|
|
||||||
--without-ssh \
|
|
||||||
--without-tftp \
|
|
||||||
--without-wx \
|
|
||||||
; \
|
|
||||||
# Compile & install Erlang/OTP
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)" GEN_OPT_FLGS="-O2 -fno-strict-aliasing"; \
|
|
||||||
make install; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf \
|
|
||||||
"$OTP_PATH"* \
|
|
||||||
/usr/local/lib/erlang/lib/*/examples \
|
|
||||||
/usr/local/lib/erlang/lib/*/src \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
|
||||||
apt-mark auto '.*' > /dev/null; \
|
|
||||||
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
|
|
||||||
find /usr/local -type f -executable -exec ldd '{}' ';' \
|
|
||||||
| awk '/=>/ { print $(NF-1) }' \
|
|
||||||
| sort -u \
|
|
||||||
| xargs -r dpkg-query --search \
|
|
||||||
| cut -d: -f1 \
|
|
||||||
| sort -u \
|
|
||||||
| xargs -r apt-mark manual \
|
|
||||||
; \
|
|
||||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
|
||||||
\
|
|
||||||
# Check that OpenSSL still works after purging build dependencies
|
|
||||||
openssl version; \
|
|
||||||
# Check that Erlang/OTP crypto & ssl were compiled against OpenSSL correctly
|
|
||||||
erl -noshell -eval 'io:format("~p~n~n~p~n~n", [crypto:supports(), ssl:versions()]), init:stop().'
|
|
||||||
|
|
||||||
ENV RABBITMQ_DATA_DIR=/var/lib/rabbitmq
|
|
||||||
# Create rabbitmq system user & group, fix permissions & allow root user to connect to the RabbitMQ Erlang VM
|
|
||||||
RUN set -eux; \
|
|
||||||
groupadd --gid 999 --system rabbitmq; \
|
|
||||||
useradd --uid 999 --system --home-dir "$RABBITMQ_DATA_DIR" --gid rabbitmq rabbitmq; \
|
|
||||||
mkdir -p "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chown -fR rabbitmq:rabbitmq "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chmod 777 "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
ln -sf "$RABBITMQ_DATA_DIR/.erlang.cookie" /root/.erlang.cookie
|
|
||||||
|
|
||||||
# Use the latest stable RabbitMQ release (https://www.rabbitmq.com/download.html)
|
|
||||||
ENV RABBITMQ_VERSION 3.7.27-rc.1
|
|
||||||
# https://www.rabbitmq.com/signatures.html#importing-gpg
|
|
||||||
ENV RABBITMQ_PGP_KEY_ID="0x0A9AF2115F4687BD29803A206B73A36E6026DFCA"
|
|
||||||
ENV RABBITMQ_HOME=/opt/rabbitmq
|
|
||||||
|
|
||||||
# Add RabbitMQ to PATH, send all logs to TTY
|
|
||||||
ENV PATH=$RABBITMQ_HOME/sbin:$PATH \
|
|
||||||
RABBITMQ_LOGS=-
|
|
||||||
|
|
||||||
# Install RabbitMQ
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
savedAptMark="$(apt-mark showmanual)"; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install --yes --no-install-recommends \
|
|
||||||
ca-certificates \
|
|
||||||
gnupg \
|
|
||||||
wget \
|
|
||||||
xz-utils \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
\
|
|
||||||
RABBITMQ_SOURCE_URL="https://github.com/rabbitmq/rabbitmq-server/releases/download/v$RABBITMQ_VERSION/rabbitmq-server-generic-unix-latest-toolchain-$RABBITMQ_VERSION.tar.xz"; \
|
|
||||||
RABBITMQ_PATH="/usr/local/src/rabbitmq-$RABBITMQ_VERSION"; \
|
|
||||||
\
|
|
||||||
wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_SOURCE_URL.asc"; \
|
|
||||||
wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar.xz" "$RABBITMQ_SOURCE_URL"; \
|
|
||||||
\
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$RABBITMQ_PGP_KEY_ID"; \
|
|
||||||
gpg --batch --verify "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_PATH.tar.xz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
\
|
|
||||||
mkdir -p "$RABBITMQ_HOME"; \
|
|
||||||
tar --extract --file "$RABBITMQ_PATH.tar.xz" --directory "$RABBITMQ_HOME" --strip-components 1; \
|
|
||||||
rm -rf "$RABBITMQ_PATH"*; \
|
|
||||||
# Do not default SYS_PREFIX to RABBITMQ_HOME, leave it empty
|
|
||||||
grep -qE '^SYS_PREFIX=\$\{RABBITMQ_HOME\}$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
sed -i 's/^SYS_PREFIX=.*$/SYS_PREFIX=/' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
grep -qE '^SYS_PREFIX=$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
chown -R rabbitmq:rabbitmq "$RABBITMQ_HOME"; \
|
|
||||||
\
|
|
||||||
apt-mark auto '.*' > /dev/null; \
|
|
||||||
apt-mark manual $savedAptMark; \
|
|
||||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
|
||||||
\
|
|
||||||
# verify assumption of no stale cookies
|
|
||||||
[ ! -e "$RABBITMQ_DATA_DIR/.erlang.cookie" ]; \
|
|
||||||
# Ensure RabbitMQ was installed correctly by running a few commands that do not depend on a running server, as the rabbitmq user
|
|
||||||
# If they all succeed, it's safe to assume that things have been set up correctly
|
|
||||||
gosu rabbitmq rabbitmqctl help; \
|
|
||||||
gosu rabbitmq rabbitmqctl list_ciphers; \
|
|
||||||
gosu rabbitmq rabbitmq-plugins list; \
|
|
||||||
# no stale cookies
|
|
||||||
rm "$RABBITMQ_DATA_DIR/.erlang.cookie"
|
|
||||||
|
|
||||||
# Added for backwards compatibility - users can simply COPY custom plugins to /plugins
|
|
||||||
RUN ln -sf /opt/rabbitmq/plugins /plugins
|
|
||||||
|
|
||||||
# set home so that any `--user` knows where to put the erlang cookie
|
|
||||||
ENV HOME $RABBITMQ_DATA_DIR
|
|
||||||
# Hint that the data (a.k.a. home dir) dir should be separate volume
|
|
||||||
VOLUME $RABBITMQ_DATA_DIR
|
|
||||||
|
|
||||||
# warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
|
|
||||||
# Setting all environment variables that control language preferences, behaviour differs - https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
|
|
||||||
# https://docs.docker.com/samples/library/ubuntu/#locales
|
|
||||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
|
|
||||||
EXPOSE 4369 5671 5672 25672
|
|
||||||
CMD ["rabbitmq-server"]
|
|
||||||
|
|
@ -1,415 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# usage: file_env VAR [DEFAULT]
|
|
||||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
|
||||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
|
||||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
|
||||||
file_env() {
|
|
||||||
local var="$1"
|
|
||||||
local fileVar="${var}_FILE"
|
|
||||||
local def="${2:-}"
|
|
||||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
||||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local val="$def"
|
|
||||||
if [ "${!var:-}" ]; then
|
|
||||||
val="${!var}"
|
|
||||||
elif [ "${!fileVar:-}" ]; then
|
|
||||||
val="$(< "${!fileVar}")"
|
|
||||||
fi
|
|
||||||
export "$var"="$val"
|
|
||||||
unset "$fileVar"
|
|
||||||
}
|
|
||||||
|
|
||||||
# backwards compatibility for old environment variables
|
|
||||||
: "${RABBITMQ_SSL_CERTFILE:=${RABBITMQ_SSL_CERT_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_KEYFILE:=${RABBITMQ_SSL_KEY_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_CACERTFILE:=${RABBITMQ_SSL_CA_FILE:-}}"
|
|
||||||
|
|
||||||
# "management" SSL config should default to using the same certs
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CACERTFILE:=$RABBITMQ_SSL_CACERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CERTFILE:=$RABBITMQ_SSL_CERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_KEYFILE:=$RABBITMQ_SSL_KEYFILE}"
|
|
||||||
|
|
||||||
# Allowed env vars that will be read from mounted files (i.e. Docker Secrets):
|
|
||||||
fileEnvKeys=(
|
|
||||||
default_user
|
|
||||||
default_pass
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://www.rabbitmq.com/configure.html
|
|
||||||
sslConfigKeys=(
|
|
||||||
cacertfile
|
|
||||||
certfile
|
|
||||||
depth
|
|
||||||
fail_if_no_peer_cert
|
|
||||||
keyfile
|
|
||||||
verify
|
|
||||||
)
|
|
||||||
managementConfigKeys=(
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
rabbitConfigKeys=(
|
|
||||||
default_pass
|
|
||||||
default_user
|
|
||||||
default_vhost
|
|
||||||
vm_memory_high_watermark
|
|
||||||
)
|
|
||||||
fileConfigKeys=(
|
|
||||||
management_ssl_cacertfile
|
|
||||||
management_ssl_certfile
|
|
||||||
management_ssl_keyfile
|
|
||||||
ssl_cacertfile
|
|
||||||
ssl_certfile
|
|
||||||
ssl_keyfile
|
|
||||||
)
|
|
||||||
allConfigKeys=(
|
|
||||||
"${managementConfigKeys[@]/#/management_}"
|
|
||||||
"${rabbitConfigKeys[@]}"
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -A configDefaults=(
|
|
||||||
[management_ssl_fail_if_no_peer_cert]='false'
|
|
||||||
[management_ssl_verify]='verify_none'
|
|
||||||
|
|
||||||
[ssl_fail_if_no_peer_cert]='true'
|
|
||||||
[ssl_verify]='verify_peer'
|
|
||||||
)
|
|
||||||
|
|
||||||
# allow the container to be started with `--user`
|
|
||||||
if [[ "$1" == rabbitmq* ]] && [ "$(id -u)" = '0' ]; then
|
|
||||||
# this needs to happen late enough that we have the SSL config
|
|
||||||
# https://github.com/docker-library/rabbitmq/issues/283
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
[ -n "$val" ] || continue
|
|
||||||
case "$conf" in
|
|
||||||
*_ssl_*file | ssl_*file )
|
|
||||||
if [ -f "$val" ] && ! gosu rabbitmq test -r "$val"; then
|
|
||||||
newFile="/tmp/rabbitmq-ssl/$conf.pem"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$val' ($var) is not readable by rabbitmq ($(id rabbitmq)); copying to '$newFile'"
|
|
||||||
echo >&2
|
|
||||||
cat "$val" > "$newFile"
|
|
||||||
chown rabbitmq "$newFile"
|
|
||||||
chmod 0400 "$newFile"
|
|
||||||
eval 'export '$var'="$newFile"'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ]; then
|
|
||||||
find /var/lib/rabbitmq \! -user rabbitmq -exec chown rabbitmq '{}' +
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec gosu rabbitmq "$BASH_SOURCE" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
haveConfig=
|
|
||||||
haveSslConfig=
|
|
||||||
haveManagementSslConfig=
|
|
||||||
for fileEnvKey in "${fileEnvKeys[@]}"; do file_env "RABBITMQ_${fileEnvKey^^}"; done
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
if [ "$val" ]; then
|
|
||||||
if [ "${configDefaults[$conf]:-}" ] && [ "${configDefaults[$conf]}" = "$val" ]; then
|
|
||||||
# if the value set is the same as the default, treat it as if it isn't set
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
haveConfig=1
|
|
||||||
case "$conf" in
|
|
||||||
ssl_*) haveSslConfig=1 ;;
|
|
||||||
management_ssl_*) haveManagementSslConfig=1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
missing=()
|
|
||||||
for sslConf in cacertfile certfile keyfile; do
|
|
||||||
var="RABBITMQ_SSL_${sslConf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ -z "$val" ]; then
|
|
||||||
missing+=( "$var" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missing[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: SSL requested, but missing required configuration'
|
|
||||||
for miss in "${missing[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
missingFiles=()
|
|
||||||
for conf in "${fileConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ "$val" ] && [ ! -f "$val" ]; then
|
|
||||||
missingFiles+=( "$val ($var)" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missingFiles[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: files specified, but missing'
|
|
||||||
for miss in "${missingFiles[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set defaults for missing values (but only after we're done with all our checking so we don't throw any of that off)
|
|
||||||
for conf in "${!configDefaults[@]}"; do
|
|
||||||
default="${configDefaults[$conf]}"
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
[ -z "${!var:-}" ] || continue
|
|
||||||
eval "export $var=\"\$default\""
|
|
||||||
done
|
|
||||||
|
|
||||||
# if long and short hostnames are not the same, use long hostnames
|
|
||||||
if [ "$(hostname)" != "$(hostname -s)" ]; then
|
|
||||||
: "${RABBITMQ_USE_LONGNAME:=true}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${RABBITMQ_ERLANG_COOKIE:-}" ]; then
|
|
||||||
cookieFile='/var/lib/rabbitmq/.erlang.cookie'
|
|
||||||
if [ -e "$cookieFile" ]; then
|
|
||||||
if [ "$(cat "$cookieFile" 2>/dev/null)" != "$RABBITMQ_ERLANG_COOKIE" ]; then
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "warning: $cookieFile contents do not match RABBITMQ_ERLANG_COOKIE"
|
|
||||||
echo >&2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$RABBITMQ_ERLANG_COOKIE" > "$cookieFile"
|
|
||||||
fi
|
|
||||||
chmod 600 "$cookieFile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
configBase="${RABBITMQ_CONFIG_FILE:-/etc/rabbitmq/rabbitmq}"
|
|
||||||
oldConfigFile="$configBase.config"
|
|
||||||
newConfigFile="$configBase.conf"
|
|
||||||
|
|
||||||
shouldWriteConfig="$haveConfig"
|
|
||||||
if [ -n "$shouldWriteConfig" ] && ! touch "$newConfigFile"; then
|
|
||||||
# config file exists but it isn't writeable (likely read-only mount, such as Kubernetes configMap)
|
|
||||||
export RABBITMQ_CONFIG_FILE='/tmp/rabbitmq.conf'
|
|
||||||
cp "$newConfigFile" "$RABBITMQ_CONFIG_FILE"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$newConfigFile' is not writable, but environment variables have been provided which request that we write to it"
|
|
||||||
echo >&2 " We have copied it to '$RABBITMQ_CONFIG_FILE' so it can be amended to work around the problem, but it is recommended that the read-only source file should be modified and the environment variables removed instead."
|
|
||||||
echo >&2
|
|
||||||
newConfigFile="$RABBITMQ_CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$shouldWriteConfig" ] && [ -f "$oldConfigFile" ]; then
|
|
||||||
{
|
|
||||||
echo "error: Docker configuration environment variables specified, but old-style (Erlang syntax) configuration file '$oldConfigFile' exists"
|
|
||||||
echo " Suggested fixes: (choose one)"
|
|
||||||
echo " - remove '$oldConfigFile'"
|
|
||||||
echo " - remove any Docker-specific 'RABBITMQ_...' environment variables"
|
|
||||||
echo " - convert '$oldConfigFile' to the newer sysctl format ('$newConfigFile'); see https://www.rabbitmq.com/configure.html#config-file"
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$shouldWriteConfig" ] && [ ! -f "$oldConfigFile" ] && [ ! -f "$newConfigFile" ]; then
|
|
||||||
# no config files, we should write one
|
|
||||||
shouldWriteConfig=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# http://stackoverflow.com/a/2705678/433558
|
|
||||||
sed_escape_lhs() {
|
|
||||||
echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g'
|
|
||||||
}
|
|
||||||
sed_escape_rhs() {
|
|
||||||
echo "$@" | sed -e 's/[\/&]/\\&/g'
|
|
||||||
}
|
|
||||||
rabbit_set_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
local val="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
local sedVal="$(sed_escape_rhs "$val")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*)\S.*\$/\1${sedVal}/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
if ! grep -qE "^${sedKey}[[:space:]]*=" "$newConfigFile"; then
|
|
||||||
echo "$key = $val" >> "$newConfigFile"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
rabbit_comment_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*#?[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*\S.*)\$/# \1/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
}
|
|
||||||
rabbit_env_config() {
|
|
||||||
local prefix="$1"; shift
|
|
||||||
|
|
||||||
local conf
|
|
||||||
for conf; do
|
|
||||||
local var="rabbitmq${prefix:+_$prefix}_$conf"
|
|
||||||
var="${var^^}"
|
|
||||||
|
|
||||||
local key="$conf"
|
|
||||||
case "$prefix" in
|
|
||||||
ssl) key="ssl_options.$key" ;;
|
|
||||||
management_ssl) key="management.ssl.$key" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
local val="${!var:-}"
|
|
||||||
local rawVal="$val"
|
|
||||||
case "$conf" in
|
|
||||||
fail_if_no_peer_cert)
|
|
||||||
case "${val,,}" in
|
|
||||||
false|no|0|'') rawVal='false' ;;
|
|
||||||
true|yes|1|*) rawVal='true' ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
|
|
||||||
vm_memory_high_watermark) continue ;; # handled separately
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$rawVal" ]; then
|
|
||||||
rabbit_set_config "$key" "$rawVal"
|
|
||||||
else
|
|
||||||
rabbit_comment_config "$key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ] && [ "$shouldWriteConfig" ]; then
|
|
||||||
rabbit_set_config 'loopback_users.guest' 'false'
|
|
||||||
|
|
||||||
# determine whether to set "vm_memory_high_watermark" (based on cgroups)
|
|
||||||
memTotalKb=
|
|
||||||
if [ -r /proc/meminfo ]; then
|
|
||||||
memTotalKb="$(awk -F ':? +' '$1 == "MemTotal" { print $2; exit }' /proc/meminfo)"
|
|
||||||
fi
|
|
||||||
memLimitB=
|
|
||||||
if [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
|
||||||
# "18446744073709551615" is a valid value for "memory.limit_in_bytes", which is too big for Bash math to handle
|
|
||||||
# "$(( 18446744073709551615 / 1024 ))" = 0; "$(( 18446744073709551615 * 40 / 100 ))" = 0
|
|
||||||
memLimitB="$(awk -v totKb="$memTotalKb" '{
|
|
||||||
limB = $0;
|
|
||||||
limKb = limB / 1024;
|
|
||||||
if (!totKb || limKb < totKb) {
|
|
||||||
printf "%.0f\n", limB;
|
|
||||||
}
|
|
||||||
}' /sys/fs/cgroup/memory/memory.limit_in_bytes)"
|
|
||||||
fi
|
|
||||||
if [ -n "$memLimitB" ]; then
|
|
||||||
# if we have a cgroup memory limit, let's inform RabbitMQ of what it is (so it can calculate vm_memory_high_watermark properly)
|
|
||||||
# https://github.com/rabbitmq/rabbitmq-server/pull/1234
|
|
||||||
rabbit_set_config 'total_memory_available_override_value' "$memLimitB"
|
|
||||||
fi
|
|
||||||
# https://www.rabbitmq.com/memory.html#memsup-usage
|
|
||||||
if [ "${RABBITMQ_VM_MEMORY_HIGH_WATERMARK:-}" ]; then
|
|
||||||
# https://github.com/docker-library/rabbitmq/pull/105#issuecomment-242165822
|
|
||||||
vmMemoryHighWatermark="$(
|
|
||||||
echo "$RABBITMQ_VM_MEMORY_HIGH_WATERMARK" | awk '
|
|
||||||
/^[0-9]*[.][0-9]+$|^[0-9]+([.][0-9]+)?%$/ {
|
|
||||||
perc = $0;
|
|
||||||
if (perc ~ /%$/) {
|
|
||||||
gsub(/%$/, "", perc);
|
|
||||||
perc = perc / 100;
|
|
||||||
}
|
|
||||||
if (perc > 1.0 || perc < 0.0) {
|
|
||||||
printf "error: invalid percentage for vm_memory_high_watermark: %s (must be >= 0%%, <= 100%%)\n", $0 > "/dev/stderr";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
printf "vm_memory_high_watermark.relative %0.03f\n", perc;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+([.][0-9]+)?[a-zA-Z]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
printf "error: unexpected input for vm_memory_high_watermark: %s\n", $0;
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
'
|
|
||||||
)"
|
|
||||||
if [ "$vmMemoryHighWatermark" ]; then
|
|
||||||
vmMemoryHighWatermarkKey="${vmMemoryHighWatermark%% *}"
|
|
||||||
vmMemoryHighWatermarkVal="${vmMemoryHighWatermark#$vmMemoryHighWatermarkKey }"
|
|
||||||
rabbit_set_config "$vmMemoryHighWatermarkKey" "$vmMemoryHighWatermarkVal"
|
|
||||||
case "$vmMemoryHighWatermarkKey" in
|
|
||||||
# make sure we only set one or the other
|
|
||||||
'vm_memory_high_watermark.absolute') rabbit_comment_config 'vm_memory_high_watermark.relative' ;;
|
|
||||||
'vm_memory_high_watermark.relative') rabbit_comment_config 'vm_memory_high_watermark.absolute' ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
rabbit_set_config 'listeners.ssl.default' 5671
|
|
||||||
rabbit_env_config 'ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'listeners.tcp.default' 5672
|
|
||||||
fi
|
|
||||||
|
|
||||||
rabbit_env_config '' "${rabbitConfigKeys[@]}"
|
|
||||||
|
|
||||||
# if management plugin is installed, generate config for it
|
|
||||||
# https://www.rabbitmq.com/management.html#configuration
|
|
||||||
if [ "$(rabbitmq-plugins list -q -m -e rabbitmq_management)" ]; then
|
|
||||||
if [ "$haveManagementSslConfig" ]; then
|
|
||||||
rabbit_set_config 'management.ssl.port' 15671
|
|
||||||
rabbit_env_config 'management_ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'management.tcp.port' 15672
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if definitions file exists, then load it
|
|
||||||
# https://www.rabbitmq.com/management.html#load-definitions
|
|
||||||
managementDefinitionsFile='/etc/rabbitmq/definitions.json'
|
|
||||||
if [ -f "$managementDefinitionsFile" ]; then
|
|
||||||
# see also https://github.com/docker-library/rabbitmq/pull/112#issuecomment-271485550
|
|
||||||
rabbit_set_config 'management.load_definitions' "$managementDefinitionsFile"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
combinedSsl='/tmp/rabbitmq-ssl/combined.pem'
|
|
||||||
if [ "$haveSslConfig" ] && [[ "$1" == rabbitmq* ]] && [ ! -f "$combinedSsl" ]; then
|
|
||||||
# Create combined cert
|
|
||||||
{
|
|
||||||
cat "$RABBITMQ_SSL_CERTFILE"
|
|
||||||
echo # https://github.com/docker-library/rabbitmq/issues/357#issuecomment-517755647
|
|
||||||
cat "$RABBITMQ_SSL_KEYFILE"
|
|
||||||
} > "$combinedSsl"
|
|
||||||
chmod 0400 "$combinedSsl"
|
|
||||||
fi
|
|
||||||
if [ "$haveSslConfig" ] && [ -f "$combinedSsl" ]; then
|
|
||||||
# More ENV vars for make clustering happiness
|
|
||||||
# we don't handle clustering in this script, but these args should ensure
|
|
||||||
# clustered SSL-enabled members will talk nicely
|
|
||||||
export ERL_SSL_PATH="$(erl -eval 'io:format("~p", [code:lib_dir(ssl, ebin)]),halt().' -noshell)"
|
|
||||||
sslErlArgs="-pa $ERL_SSL_PATH -proto_dist inet_tls -ssl_dist_opt server_certfile $combinedSsl -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
|
|
||||||
export RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
export RABBITMQ_CTL_ERL_ARGS="${RABBITMQ_CTL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
FROM rabbitmq:3.7-rc
|
|
||||||
|
|
||||||
RUN rabbitmq-plugins enable --offline rabbitmq_management
|
|
||||||
|
|
||||||
# extract "rabbitmqadmin" from inside the "rabbitmq_management-X.Y.Z.ez" plugin zipfile
|
|
||||||
# see https://github.com/docker-library/rabbitmq/issues/207
|
|
||||||
RUN set -eux; \
|
|
||||||
erl -noinput -eval ' \
|
|
||||||
{ ok, AdminBin } = zip:foldl(fun(FileInArchive, GetInfo, GetBin, Acc) -> \
|
|
||||||
case Acc of \
|
|
||||||
"" -> \
|
|
||||||
case lists:suffix("/rabbitmqadmin", FileInArchive) of \
|
|
||||||
true -> GetBin(); \
|
|
||||||
false -> Acc \
|
|
||||||
end; \
|
|
||||||
_ -> Acc \
|
|
||||||
end \
|
|
||||||
end, "", init:get_plain_arguments()), \
|
|
||||||
io:format("~s", [ AdminBin ]), \
|
|
||||||
init:stop(). \
|
|
||||||
' -- /plugins/rabbitmq_management-*.ez > /usr/local/bin/rabbitmqadmin; \
|
|
||||||
[ -s /usr/local/bin/rabbitmqadmin ]; \
|
|
||||||
chmod +x /usr/local/bin/rabbitmqadmin; \
|
|
||||||
apt-get update; apt-get install -y --no-install-recommends python3; rm -rf /var/lib/apt/lists/*; \
|
|
||||||
rabbitmqadmin --version
|
|
||||||
|
|
||||||
EXPOSE 15671 15672
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
# Alpine Linux is not officially supported by the RabbitMQ team -- use at your own risk!
|
|
||||||
FROM alpine:3.12
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
# grab su-exec for easy step-down from root
|
|
||||||
'su-exec>=0.2' \
|
|
||||||
# bash for docker-entrypoint.sh
|
|
||||||
bash \
|
|
||||||
# "ps" for "rabbitmqctl wait" (https://github.com/docker-library/rabbitmq/issues/162)
|
|
||||||
procps
|
|
||||||
|
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
|
||||||
ENV OPENSSL_VERSION 1.1.1g
|
|
||||||
ENV OPENSSL_SOURCE_SHA256="ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46"
|
|
||||||
# https://www.openssl.org/community/omc.html
|
|
||||||
ENV OPENSSL_PGP_KEY_IDS="0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D"
|
|
||||||
|
|
||||||
# Use the latest stable Erlang/OTP release (https://github.com/erlang/otp/tags)
|
|
||||||
ENV OTP_VERSION 22.3.4.7
|
|
||||||
# TODO add PGP checking when the feature will be added to Erlang/OTP's build system
|
|
||||||
# http://erlang.org/pipermail/erlang-questions/2019-January/097067.html
|
|
||||||
ENV OTP_SOURCE_SHA256="9bafa7a6040ecd18a0b0b05ed014bd186722ef4bf8925b70e9661d3eb5886e66"
|
|
||||||
|
|
||||||
# Install dependencies required to build Erlang/OTP from source
|
|
||||||
# http://erlang.org/doc/installation_guide/INSTALL.html
|
|
||||||
# autoconf: Required to configure Erlang/OTP before compiling
|
|
||||||
# dpkg-dev: Required to set up host & build type when compiling Erlang/OTP
|
|
||||||
# gnupg: Required to verify OpenSSL artefacts
|
|
||||||
# libncurses5-dev: Required for Erlang/OTP new shell & observer_cli - https://github.com/zhongwencool/observer_cli
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
apk add --no-cache --virtual .build-deps \
|
|
||||||
autoconf \
|
|
||||||
dpkg-dev dpkg \
|
|
||||||
gcc \
|
|
||||||
gnupg \
|
|
||||||
libc-dev \
|
|
||||||
linux-headers \
|
|
||||||
make \
|
|
||||||
ncurses-dev \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
OPENSSL_SOURCE_URL="https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"; \
|
|
||||||
OPENSSL_PATH="/usr/local/src/openssl-$OPENSSL_VERSION"; \
|
|
||||||
OPENSSL_CONFIG_DIR=/usr/local/etc/ssl; \
|
|
||||||
\
|
|
||||||
# /usr/local/src doesn't exist in Alpine by default
|
|
||||||
mkdir /usr/local/src; \
|
|
||||||
\
|
|
||||||
# Required by the crypto & ssl Erlang/OTP applications
|
|
||||||
wget --output-document "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_SOURCE_URL.asc"; \
|
|
||||||
wget --output-document "$OPENSSL_PATH.tar.gz" "$OPENSSL_SOURCE_URL"; \
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
for key in $OPENSSL_PGP_KEY_IDS; do \
|
|
||||||
gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$key"; \
|
|
||||||
done; \
|
|
||||||
gpg --batch --verify "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_PATH.tar.gz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
echo "$OPENSSL_SOURCE_SHA256 *$OPENSSL_PATH.tar.gz" | sha256sum -c -; \
|
|
||||||
mkdir -p "$OPENSSL_PATH"; \
|
|
||||||
tar --extract --file "$OPENSSL_PATH.tar.gz" --directory "$OPENSSL_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure OpenSSL for compilation
|
|
||||||
cd "$OPENSSL_PATH"; \
|
|
||||||
# OpenSSL's "config" script uses a lot of "uname"-based target detection...
|
|
||||||
MACHINE="$(dpkg-architecture --query DEB_BUILD_GNU_CPU)" \
|
|
||||||
RELEASE="4.x.y-z" \
|
|
||||||
SYSTEM='Linux' \
|
|
||||||
BUILD='???' \
|
|
||||||
./config \
|
|
||||||
--openssldir="$OPENSSL_CONFIG_DIR" \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
-Wl,-rpath=/usr/local/lib \
|
|
||||||
; \
|
|
||||||
# Compile, install OpenSSL, verify that the command-line works & development headers are present
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)"; \
|
|
||||||
make install_sw install_ssldirs; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf "$OPENSSL_PATH"*; \
|
|
||||||
# use Alpine's CA certificates
|
|
||||||
rmdir "$OPENSSL_CONFIG_DIR/certs" "$OPENSSL_CONFIG_DIR/private"; \
|
|
||||||
ln -sf /etc/ssl/certs /etc/ssl/private "$OPENSSL_CONFIG_DIR"; \
|
|
||||||
# smoke test
|
|
||||||
openssl version; \
|
|
||||||
\
|
|
||||||
OTP_SOURCE_URL="https://github.com/erlang/otp/archive/OTP-$OTP_VERSION.tar.gz"; \
|
|
||||||
OTP_PATH="/usr/local/src/otp-$OTP_VERSION"; \
|
|
||||||
\
|
|
||||||
# Download, verify & extract OTP_SOURCE
|
|
||||||
mkdir -p "$OTP_PATH"; \
|
|
||||||
wget --output-document "$OTP_PATH.tar.gz" "$OTP_SOURCE_URL"; \
|
|
||||||
echo "$OTP_SOURCE_SHA256 *$OTP_PATH.tar.gz" | sha256sum -c -; \
|
|
||||||
tar --extract --file "$OTP_PATH.tar.gz" --directory "$OTP_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure Erlang/OTP for compilation, disable unused features & applications
|
|
||||||
# http://erlang.org/doc/applications.html
|
|
||||||
# ERL_TOP is required for Erlang/OTP makefiles to find the absolute path for the installation
|
|
||||||
cd "$OTP_PATH"; \
|
|
||||||
export ERL_TOP="$OTP_PATH"; \
|
|
||||||
./otp_build autoconf; \
|
|
||||||
export CFLAGS='-g -O2'; \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
export CFLAGS="$CFLAGS -Wl,-rpath=/usr/local/lib"; \
|
|
||||||
hostArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"; \
|
|
||||||
buildArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
|
|
||||||
dpkgArch="$(dpkg --print-architecture)"; dpkgArch="${dpkgArch##*-}"; \
|
|
||||||
./configure \
|
|
||||||
--host="$hostArch" \
|
|
||||||
--build="$buildArch" \
|
|
||||||
--disable-dynamic-ssl-lib \
|
|
||||||
--disable-hipe \
|
|
||||||
--disable-sctp \
|
|
||||||
--disable-silent-rules \
|
|
||||||
--enable-clock-gettime \
|
|
||||||
--enable-hybrid-heap \
|
|
||||||
--enable-kernel-poll \
|
|
||||||
--enable-shared-zlib \
|
|
||||||
--enable-smp-support \
|
|
||||||
--enable-threads \
|
|
||||||
--with-microstate-accounting=extra \
|
|
||||||
--without-common_test \
|
|
||||||
--without-debugger \
|
|
||||||
--without-dialyzer \
|
|
||||||
--without-diameter \
|
|
||||||
--without-edoc \
|
|
||||||
--without-erl_docgen \
|
|
||||||
--without-erl_interface \
|
|
||||||
--without-et \
|
|
||||||
--without-eunit \
|
|
||||||
--without-ftp \
|
|
||||||
--without-hipe \
|
|
||||||
--without-jinterface \
|
|
||||||
--without-megaco \
|
|
||||||
--without-observer \
|
|
||||||
--without-odbc \
|
|
||||||
--without-reltool \
|
|
||||||
--without-ssh \
|
|
||||||
--without-tftp \
|
|
||||||
--without-wx \
|
|
||||||
; \
|
|
||||||
# Compile & install Erlang/OTP
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)" GEN_OPT_FLGS="-O2 -fno-strict-aliasing"; \
|
|
||||||
make install; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf \
|
|
||||||
"$OTP_PATH"* \
|
|
||||||
/usr/local/lib/erlang/lib/*/examples \
|
|
||||||
/usr/local/lib/erlang/lib/*/src \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
runDeps="$( \
|
|
||||||
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
|
|
||||||
| tr ',' '\n' \
|
|
||||||
| sort -u \
|
|
||||||
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
|
||||||
)"; \
|
|
||||||
apk add --no-cache --virtual .otp-run-deps $runDeps; \
|
|
||||||
apk del --no-network .build-deps; \
|
|
||||||
\
|
|
||||||
# Check that OpenSSL still works after purging build dependencies
|
|
||||||
openssl version; \
|
|
||||||
# Check that Erlang/OTP crypto & ssl were compiled against OpenSSL correctly
|
|
||||||
erl -noshell -eval 'io:format("~p~n~n~p~n~n", [crypto:supports(), ssl:versions()]), init:stop().'
|
|
||||||
|
|
||||||
ENV RABBITMQ_DATA_DIR=/var/lib/rabbitmq
|
|
||||||
# Create rabbitmq system user & group, fix permissions & allow root user to connect to the RabbitMQ Erlang VM
|
|
||||||
RUN set -eux; \
|
|
||||||
addgroup -g 101 -S rabbitmq; \
|
|
||||||
adduser -u 100 -S -h "$RABBITMQ_DATA_DIR" -G rabbitmq rabbitmq; \
|
|
||||||
mkdir -p "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chown -fR rabbitmq:rabbitmq "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chmod 777 "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
ln -sf "$RABBITMQ_DATA_DIR/.erlang.cookie" /root/.erlang.cookie
|
|
||||||
|
|
||||||
# Use the latest stable RabbitMQ release (https://www.rabbitmq.com/download.html)
|
|
||||||
ENV RABBITMQ_VERSION 3.7.28
|
|
||||||
# https://www.rabbitmq.com/signatures.html#importing-gpg
|
|
||||||
ENV RABBITMQ_PGP_KEY_ID="0x0A9AF2115F4687BD29803A206B73A36E6026DFCA"
|
|
||||||
ENV RABBITMQ_HOME=/opt/rabbitmq
|
|
||||||
|
|
||||||
# Add RabbitMQ to PATH, send all logs to TTY
|
|
||||||
ENV PATH=$RABBITMQ_HOME/sbin:$PATH \
|
|
||||||
RABBITMQ_LOGS=-
|
|
||||||
|
|
||||||
# Install RabbitMQ
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
apk add --no-cache --virtual .build-deps \
|
|
||||||
gnupg \
|
|
||||||
xz \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
RABBITMQ_SOURCE_URL="https://github.com/rabbitmq/rabbitmq-server/releases/download/v$RABBITMQ_VERSION/rabbitmq-server-generic-unix-latest-toolchain-$RABBITMQ_VERSION.tar.xz"; \
|
|
||||||
RABBITMQ_PATH="/usr/local/src/rabbitmq-$RABBITMQ_VERSION"; \
|
|
||||||
\
|
|
||||||
wget --output-document "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_SOURCE_URL.asc"; \
|
|
||||||
wget --output-document "$RABBITMQ_PATH.tar.xz" "$RABBITMQ_SOURCE_URL"; \
|
|
||||||
\
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$RABBITMQ_PGP_KEY_ID"; \
|
|
||||||
gpg --batch --verify "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_PATH.tar.xz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
\
|
|
||||||
mkdir -p "$RABBITMQ_HOME"; \
|
|
||||||
tar --extract --file "$RABBITMQ_PATH.tar.xz" --directory "$RABBITMQ_HOME" --strip-components 1; \
|
|
||||||
rm -rf "$RABBITMQ_PATH"*; \
|
|
||||||
# Do not default SYS_PREFIX to RABBITMQ_HOME, leave it empty
|
|
||||||
grep -qE '^SYS_PREFIX=\$\{RABBITMQ_HOME\}$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
sed -i 's/^SYS_PREFIX=.*$/SYS_PREFIX=/' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
grep -qE '^SYS_PREFIX=$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
chown -R rabbitmq:rabbitmq "$RABBITMQ_HOME"; \
|
|
||||||
\
|
|
||||||
apk del .build-deps; \
|
|
||||||
\
|
|
||||||
# verify assumption of no stale cookies
|
|
||||||
[ ! -e "$RABBITMQ_DATA_DIR/.erlang.cookie" ]; \
|
|
||||||
# Ensure RabbitMQ was installed correctly by running a few commands that do not depend on a running server, as the rabbitmq user
|
|
||||||
# If they all succeed, it's safe to assume that things have been set up correctly
|
|
||||||
su-exec rabbitmq rabbitmqctl help; \
|
|
||||||
su-exec rabbitmq rabbitmqctl list_ciphers; \
|
|
||||||
su-exec rabbitmq rabbitmq-plugins list; \
|
|
||||||
# no stale cookies
|
|
||||||
rm "$RABBITMQ_DATA_DIR/.erlang.cookie"
|
|
||||||
|
|
||||||
# Added for backwards compatibility - users can simply COPY custom plugins to /plugins
|
|
||||||
RUN ln -sf /opt/rabbitmq/plugins /plugins
|
|
||||||
|
|
||||||
# set home so that any `--user` knows where to put the erlang cookie
|
|
||||||
ENV HOME $RABBITMQ_DATA_DIR
|
|
||||||
# Hint that the data (a.k.a. home dir) dir should be separate volume
|
|
||||||
VOLUME $RABBITMQ_DATA_DIR
|
|
||||||
|
|
||||||
# warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
|
|
||||||
# Setting all environment variables that control language preferences, behaviour differs - https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
|
|
||||||
# https://docs.docker.com/samples/library/ubuntu/#locales
|
|
||||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
|
|
||||||
EXPOSE 4369 5671 5672 25672
|
|
||||||
CMD ["rabbitmq-server"]
|
|
||||||
|
|
@ -1,415 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# usage: file_env VAR [DEFAULT]
|
|
||||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
|
||||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
|
||||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
|
||||||
file_env() {
|
|
||||||
local var="$1"
|
|
||||||
local fileVar="${var}_FILE"
|
|
||||||
local def="${2:-}"
|
|
||||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
||||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local val="$def"
|
|
||||||
if [ "${!var:-}" ]; then
|
|
||||||
val="${!var}"
|
|
||||||
elif [ "${!fileVar:-}" ]; then
|
|
||||||
val="$(< "${!fileVar}")"
|
|
||||||
fi
|
|
||||||
export "$var"="$val"
|
|
||||||
unset "$fileVar"
|
|
||||||
}
|
|
||||||
|
|
||||||
# backwards compatibility for old environment variables
|
|
||||||
: "${RABBITMQ_SSL_CERTFILE:=${RABBITMQ_SSL_CERT_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_KEYFILE:=${RABBITMQ_SSL_KEY_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_CACERTFILE:=${RABBITMQ_SSL_CA_FILE:-}}"
|
|
||||||
|
|
||||||
# "management" SSL config should default to using the same certs
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CACERTFILE:=$RABBITMQ_SSL_CACERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CERTFILE:=$RABBITMQ_SSL_CERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_KEYFILE:=$RABBITMQ_SSL_KEYFILE}"
|
|
||||||
|
|
||||||
# Allowed env vars that will be read from mounted files (i.e. Docker Secrets):
|
|
||||||
fileEnvKeys=(
|
|
||||||
default_user
|
|
||||||
default_pass
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://www.rabbitmq.com/configure.html
|
|
||||||
sslConfigKeys=(
|
|
||||||
cacertfile
|
|
||||||
certfile
|
|
||||||
depth
|
|
||||||
fail_if_no_peer_cert
|
|
||||||
keyfile
|
|
||||||
verify
|
|
||||||
)
|
|
||||||
managementConfigKeys=(
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
rabbitConfigKeys=(
|
|
||||||
default_pass
|
|
||||||
default_user
|
|
||||||
default_vhost
|
|
||||||
vm_memory_high_watermark
|
|
||||||
)
|
|
||||||
fileConfigKeys=(
|
|
||||||
management_ssl_cacertfile
|
|
||||||
management_ssl_certfile
|
|
||||||
management_ssl_keyfile
|
|
||||||
ssl_cacertfile
|
|
||||||
ssl_certfile
|
|
||||||
ssl_keyfile
|
|
||||||
)
|
|
||||||
allConfigKeys=(
|
|
||||||
"${managementConfigKeys[@]/#/management_}"
|
|
||||||
"${rabbitConfigKeys[@]}"
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -A configDefaults=(
|
|
||||||
[management_ssl_fail_if_no_peer_cert]='false'
|
|
||||||
[management_ssl_verify]='verify_none'
|
|
||||||
|
|
||||||
[ssl_fail_if_no_peer_cert]='true'
|
|
||||||
[ssl_verify]='verify_peer'
|
|
||||||
)
|
|
||||||
|
|
||||||
# allow the container to be started with `--user`
|
|
||||||
if [[ "$1" == rabbitmq* ]] && [ "$(id -u)" = '0' ]; then
|
|
||||||
# this needs to happen late enough that we have the SSL config
|
|
||||||
# https://github.com/docker-library/rabbitmq/issues/283
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
[ -n "$val" ] || continue
|
|
||||||
case "$conf" in
|
|
||||||
*_ssl_*file | ssl_*file )
|
|
||||||
if [ -f "$val" ] && ! su-exec rabbitmq test -r "$val"; then
|
|
||||||
newFile="/tmp/rabbitmq-ssl/$conf.pem"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$val' ($var) is not readable by rabbitmq ($(id rabbitmq)); copying to '$newFile'"
|
|
||||||
echo >&2
|
|
||||||
cat "$val" > "$newFile"
|
|
||||||
chown rabbitmq "$newFile"
|
|
||||||
chmod 0400 "$newFile"
|
|
||||||
eval 'export '$var'="$newFile"'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ]; then
|
|
||||||
find /var/lib/rabbitmq \! -user rabbitmq -exec chown rabbitmq '{}' +
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec su-exec rabbitmq "$BASH_SOURCE" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
haveConfig=
|
|
||||||
haveSslConfig=
|
|
||||||
haveManagementSslConfig=
|
|
||||||
for fileEnvKey in "${fileEnvKeys[@]}"; do file_env "RABBITMQ_${fileEnvKey^^}"; done
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
if [ "$val" ]; then
|
|
||||||
if [ "${configDefaults[$conf]:-}" ] && [ "${configDefaults[$conf]}" = "$val" ]; then
|
|
||||||
# if the value set is the same as the default, treat it as if it isn't set
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
haveConfig=1
|
|
||||||
case "$conf" in
|
|
||||||
ssl_*) haveSslConfig=1 ;;
|
|
||||||
management_ssl_*) haveManagementSslConfig=1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
missing=()
|
|
||||||
for sslConf in cacertfile certfile keyfile; do
|
|
||||||
var="RABBITMQ_SSL_${sslConf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ -z "$val" ]; then
|
|
||||||
missing+=( "$var" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missing[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: SSL requested, but missing required configuration'
|
|
||||||
for miss in "${missing[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
missingFiles=()
|
|
||||||
for conf in "${fileConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ "$val" ] && [ ! -f "$val" ]; then
|
|
||||||
missingFiles+=( "$val ($var)" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missingFiles[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: files specified, but missing'
|
|
||||||
for miss in "${missingFiles[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set defaults for missing values (but only after we're done with all our checking so we don't throw any of that off)
|
|
||||||
for conf in "${!configDefaults[@]}"; do
|
|
||||||
default="${configDefaults[$conf]}"
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
[ -z "${!var:-}" ] || continue
|
|
||||||
eval "export $var=\"\$default\""
|
|
||||||
done
|
|
||||||
|
|
||||||
# if long and short hostnames are not the same, use long hostnames
|
|
||||||
if [ "$(hostname)" != "$(hostname -s)" ]; then
|
|
||||||
: "${RABBITMQ_USE_LONGNAME:=true}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${RABBITMQ_ERLANG_COOKIE:-}" ]; then
|
|
||||||
cookieFile='/var/lib/rabbitmq/.erlang.cookie'
|
|
||||||
if [ -e "$cookieFile" ]; then
|
|
||||||
if [ "$(cat "$cookieFile" 2>/dev/null)" != "$RABBITMQ_ERLANG_COOKIE" ]; then
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "warning: $cookieFile contents do not match RABBITMQ_ERLANG_COOKIE"
|
|
||||||
echo >&2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$RABBITMQ_ERLANG_COOKIE" > "$cookieFile"
|
|
||||||
fi
|
|
||||||
chmod 600 "$cookieFile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
configBase="${RABBITMQ_CONFIG_FILE:-/etc/rabbitmq/rabbitmq}"
|
|
||||||
oldConfigFile="$configBase.config"
|
|
||||||
newConfigFile="$configBase.conf"
|
|
||||||
|
|
||||||
shouldWriteConfig="$haveConfig"
|
|
||||||
if [ -n "$shouldWriteConfig" ] && ! touch "$newConfigFile"; then
|
|
||||||
# config file exists but it isn't writeable (likely read-only mount, such as Kubernetes configMap)
|
|
||||||
export RABBITMQ_CONFIG_FILE='/tmp/rabbitmq.conf'
|
|
||||||
cp "$newConfigFile" "$RABBITMQ_CONFIG_FILE"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$newConfigFile' is not writable, but environment variables have been provided which request that we write to it"
|
|
||||||
echo >&2 " We have copied it to '$RABBITMQ_CONFIG_FILE' so it can be amended to work around the problem, but it is recommended that the read-only source file should be modified and the environment variables removed instead."
|
|
||||||
echo >&2
|
|
||||||
newConfigFile="$RABBITMQ_CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$shouldWriteConfig" ] && [ -f "$oldConfigFile" ]; then
|
|
||||||
{
|
|
||||||
echo "error: Docker configuration environment variables specified, but old-style (Erlang syntax) configuration file '$oldConfigFile' exists"
|
|
||||||
echo " Suggested fixes: (choose one)"
|
|
||||||
echo " - remove '$oldConfigFile'"
|
|
||||||
echo " - remove any Docker-specific 'RABBITMQ_...' environment variables"
|
|
||||||
echo " - convert '$oldConfigFile' to the newer sysctl format ('$newConfigFile'); see https://www.rabbitmq.com/configure.html#config-file"
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$shouldWriteConfig" ] && [ ! -f "$oldConfigFile" ] && [ ! -f "$newConfigFile" ]; then
|
|
||||||
# no config files, we should write one
|
|
||||||
shouldWriteConfig=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# http://stackoverflow.com/a/2705678/433558
|
|
||||||
sed_escape_lhs() {
|
|
||||||
echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g'
|
|
||||||
}
|
|
||||||
sed_escape_rhs() {
|
|
||||||
echo "$@" | sed -e 's/[\/&]/\\&/g'
|
|
||||||
}
|
|
||||||
rabbit_set_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
local val="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
local sedVal="$(sed_escape_rhs "$val")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*)\S.*\$/\1${sedVal}/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
if ! grep -qE "^${sedKey}[[:space:]]*=" "$newConfigFile"; then
|
|
||||||
echo "$key = $val" >> "$newConfigFile"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
rabbit_comment_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*#?[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*\S.*)\$/# \1/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
}
|
|
||||||
rabbit_env_config() {
|
|
||||||
local prefix="$1"; shift
|
|
||||||
|
|
||||||
local conf
|
|
||||||
for conf; do
|
|
||||||
local var="rabbitmq${prefix:+_$prefix}_$conf"
|
|
||||||
var="${var^^}"
|
|
||||||
|
|
||||||
local key="$conf"
|
|
||||||
case "$prefix" in
|
|
||||||
ssl) key="ssl_options.$key" ;;
|
|
||||||
management_ssl) key="management.ssl.$key" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
local val="${!var:-}"
|
|
||||||
local rawVal="$val"
|
|
||||||
case "$conf" in
|
|
||||||
fail_if_no_peer_cert)
|
|
||||||
case "${val,,}" in
|
|
||||||
false|no|0|'') rawVal='false' ;;
|
|
||||||
true|yes|1|*) rawVal='true' ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
|
|
||||||
vm_memory_high_watermark) continue ;; # handled separately
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$rawVal" ]; then
|
|
||||||
rabbit_set_config "$key" "$rawVal"
|
|
||||||
else
|
|
||||||
rabbit_comment_config "$key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ] && [ "$shouldWriteConfig" ]; then
|
|
||||||
rabbit_set_config 'loopback_users.guest' 'false'
|
|
||||||
|
|
||||||
# determine whether to set "vm_memory_high_watermark" (based on cgroups)
|
|
||||||
memTotalKb=
|
|
||||||
if [ -r /proc/meminfo ]; then
|
|
||||||
memTotalKb="$(awk -F ':? +' '$1 == "MemTotal" { print $2; exit }' /proc/meminfo)"
|
|
||||||
fi
|
|
||||||
memLimitB=
|
|
||||||
if [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
|
||||||
# "18446744073709551615" is a valid value for "memory.limit_in_bytes", which is too big for Bash math to handle
|
|
||||||
# "$(( 18446744073709551615 / 1024 ))" = 0; "$(( 18446744073709551615 * 40 / 100 ))" = 0
|
|
||||||
memLimitB="$(awk -v totKb="$memTotalKb" '{
|
|
||||||
limB = $0;
|
|
||||||
limKb = limB / 1024;
|
|
||||||
if (!totKb || limKb < totKb) {
|
|
||||||
printf "%.0f\n", limB;
|
|
||||||
}
|
|
||||||
}' /sys/fs/cgroup/memory/memory.limit_in_bytes)"
|
|
||||||
fi
|
|
||||||
if [ -n "$memLimitB" ]; then
|
|
||||||
# if we have a cgroup memory limit, let's inform RabbitMQ of what it is (so it can calculate vm_memory_high_watermark properly)
|
|
||||||
# https://github.com/rabbitmq/rabbitmq-server/pull/1234
|
|
||||||
rabbit_set_config 'total_memory_available_override_value' "$memLimitB"
|
|
||||||
fi
|
|
||||||
# https://www.rabbitmq.com/memory.html#memsup-usage
|
|
||||||
if [ "${RABBITMQ_VM_MEMORY_HIGH_WATERMARK:-}" ]; then
|
|
||||||
# https://github.com/docker-library/rabbitmq/pull/105#issuecomment-242165822
|
|
||||||
vmMemoryHighWatermark="$(
|
|
||||||
echo "$RABBITMQ_VM_MEMORY_HIGH_WATERMARK" | awk '
|
|
||||||
/^[0-9]*[.][0-9]+$|^[0-9]+([.][0-9]+)?%$/ {
|
|
||||||
perc = $0;
|
|
||||||
if (perc ~ /%$/) {
|
|
||||||
gsub(/%$/, "", perc);
|
|
||||||
perc = perc / 100;
|
|
||||||
}
|
|
||||||
if (perc > 1.0 || perc < 0.0) {
|
|
||||||
printf "error: invalid percentage for vm_memory_high_watermark: %s (must be >= 0%%, <= 100%%)\n", $0 > "/dev/stderr";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
printf "vm_memory_high_watermark.relative %0.03f\n", perc;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+([.][0-9]+)?[a-zA-Z]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
printf "error: unexpected input for vm_memory_high_watermark: %s\n", $0;
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
'
|
|
||||||
)"
|
|
||||||
if [ "$vmMemoryHighWatermark" ]; then
|
|
||||||
vmMemoryHighWatermarkKey="${vmMemoryHighWatermark%% *}"
|
|
||||||
vmMemoryHighWatermarkVal="${vmMemoryHighWatermark#$vmMemoryHighWatermarkKey }"
|
|
||||||
rabbit_set_config "$vmMemoryHighWatermarkKey" "$vmMemoryHighWatermarkVal"
|
|
||||||
case "$vmMemoryHighWatermarkKey" in
|
|
||||||
# make sure we only set one or the other
|
|
||||||
'vm_memory_high_watermark.absolute') rabbit_comment_config 'vm_memory_high_watermark.relative' ;;
|
|
||||||
'vm_memory_high_watermark.relative') rabbit_comment_config 'vm_memory_high_watermark.absolute' ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
rabbit_set_config 'listeners.ssl.default' 5671
|
|
||||||
rabbit_env_config 'ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'listeners.tcp.default' 5672
|
|
||||||
fi
|
|
||||||
|
|
||||||
rabbit_env_config '' "${rabbitConfigKeys[@]}"
|
|
||||||
|
|
||||||
# if management plugin is installed, generate config for it
|
|
||||||
# https://www.rabbitmq.com/management.html#configuration
|
|
||||||
if [ "$(rabbitmq-plugins list -q -m -e rabbitmq_management)" ]; then
|
|
||||||
if [ "$haveManagementSslConfig" ]; then
|
|
||||||
rabbit_set_config 'management.ssl.port' 15671
|
|
||||||
rabbit_env_config 'management_ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'management.tcp.port' 15672
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if definitions file exists, then load it
|
|
||||||
# https://www.rabbitmq.com/management.html#load-definitions
|
|
||||||
managementDefinitionsFile='/etc/rabbitmq/definitions.json'
|
|
||||||
if [ -f "$managementDefinitionsFile" ]; then
|
|
||||||
# see also https://github.com/docker-library/rabbitmq/pull/112#issuecomment-271485550
|
|
||||||
rabbit_set_config 'management.load_definitions' "$managementDefinitionsFile"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
combinedSsl='/tmp/rabbitmq-ssl/combined.pem'
|
|
||||||
if [ "$haveSslConfig" ] && [[ "$1" == rabbitmq* ]] && [ ! -f "$combinedSsl" ]; then
|
|
||||||
# Create combined cert
|
|
||||||
{
|
|
||||||
cat "$RABBITMQ_SSL_CERTFILE"
|
|
||||||
echo # https://github.com/docker-library/rabbitmq/issues/357#issuecomment-517755647
|
|
||||||
cat "$RABBITMQ_SSL_KEYFILE"
|
|
||||||
} > "$combinedSsl"
|
|
||||||
chmod 0400 "$combinedSsl"
|
|
||||||
fi
|
|
||||||
if [ "$haveSslConfig" ] && [ -f "$combinedSsl" ]; then
|
|
||||||
# More ENV vars for make clustering happiness
|
|
||||||
# we don't handle clustering in this script, but these args should ensure
|
|
||||||
# clustered SSL-enabled members will talk nicely
|
|
||||||
export ERL_SSL_PATH="$(erl -eval 'io:format("~p", [code:lib_dir(ssl, ebin)]),halt().' -noshell)"
|
|
||||||
sslErlArgs="-pa $ERL_SSL_PATH -proto_dist inet_tls -ssl_dist_opt server_certfile $combinedSsl -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
|
|
||||||
export RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
export RABBITMQ_CTL_ERL_ARGS="${RABBITMQ_CTL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
FROM rabbitmq:3.7-alpine
|
|
||||||
|
|
||||||
RUN rabbitmq-plugins enable --offline rabbitmq_management
|
|
||||||
|
|
||||||
# extract "rabbitmqadmin" from inside the "rabbitmq_management-X.Y.Z.ez" plugin zipfile
|
|
||||||
# see https://github.com/docker-library/rabbitmq/issues/207
|
|
||||||
RUN set -eux; \
|
|
||||||
erl -noinput -eval ' \
|
|
||||||
{ ok, AdminBin } = zip:foldl(fun(FileInArchive, GetInfo, GetBin, Acc) -> \
|
|
||||||
case Acc of \
|
|
||||||
"" -> \
|
|
||||||
case lists:suffix("/rabbitmqadmin", FileInArchive) of \
|
|
||||||
true -> GetBin(); \
|
|
||||||
false -> Acc \
|
|
||||||
end; \
|
|
||||||
_ -> Acc \
|
|
||||||
end \
|
|
||||||
end, "", init:get_plain_arguments()), \
|
|
||||||
io:format("~s", [ AdminBin ]), \
|
|
||||||
init:stop(). \
|
|
||||||
' -- /plugins/rabbitmq_management-*.ez > /usr/local/bin/rabbitmqadmin; \
|
|
||||||
[ -s /usr/local/bin/rabbitmqadmin ]; \
|
|
||||||
chmod +x /usr/local/bin/rabbitmqadmin; \
|
|
||||||
apk add --no-cache python3; \
|
|
||||||
rabbitmqadmin --version
|
|
||||||
|
|
||||||
EXPOSE 15671 15672
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
# The official Canonical Ubuntu Bionic image is ideal from a security perspective,
|
|
||||||
# especially for the enterprises that we, the RabbitMQ team, have to deal with
|
|
||||||
FROM ubuntu:18.04
|
|
||||||
|
|
||||||
RUN set -eux; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
# grab gosu for easy step-down from root
|
|
||||||
gosu \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
# verify that the "gosu" binary works
|
|
||||||
gosu nobody true
|
|
||||||
|
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
|
||||||
ENV OPENSSL_VERSION 1.1.1g
|
|
||||||
ENV OPENSSL_SOURCE_SHA256="ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46"
|
|
||||||
# https://www.openssl.org/community/omc.html
|
|
||||||
ENV OPENSSL_PGP_KEY_IDS="0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D"
|
|
||||||
|
|
||||||
# Use the latest stable Erlang/OTP release (https://github.com/erlang/otp/tags)
|
|
||||||
ENV OTP_VERSION 22.3.4.7
|
|
||||||
# TODO add PGP checking when the feature will be added to Erlang/OTP's build system
|
|
||||||
# http://erlang.org/pipermail/erlang-questions/2019-January/097067.html
|
|
||||||
ENV OTP_SOURCE_SHA256="9bafa7a6040ecd18a0b0b05ed014bd186722ef4bf8925b70e9661d3eb5886e66"
|
|
||||||
|
|
||||||
# Install dependencies required to build Erlang/OTP from source
|
|
||||||
# http://erlang.org/doc/installation_guide/INSTALL.html
|
|
||||||
# autoconf: Required to configure Erlang/OTP before compiling
|
|
||||||
# dpkg-dev: Required to set up host & build type when compiling Erlang/OTP
|
|
||||||
# gnupg: Required to verify OpenSSL artefacts
|
|
||||||
# libncurses5-dev: Required for Erlang/OTP new shell & observer_cli - https://github.com/zhongwencool/observer_cli
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
savedAptMark="$(apt-mark showmanual)"; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install --yes --no-install-recommends \
|
|
||||||
autoconf \
|
|
||||||
ca-certificates \
|
|
||||||
dpkg-dev \
|
|
||||||
gcc \
|
|
||||||
gnupg \
|
|
||||||
libncurses5-dev \
|
|
||||||
make \
|
|
||||||
wget \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
\
|
|
||||||
OPENSSL_SOURCE_URL="https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"; \
|
|
||||||
OPENSSL_PATH="/usr/local/src/openssl-$OPENSSL_VERSION"; \
|
|
||||||
OPENSSL_CONFIG_DIR=/usr/local/etc/ssl; \
|
|
||||||
\
|
|
||||||
# Required by the crypto & ssl Erlang/OTP applications
|
|
||||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_SOURCE_URL.asc"; \
|
|
||||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz" "$OPENSSL_SOURCE_URL"; \
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
for key in $OPENSSL_PGP_KEY_IDS; do \
|
|
||||||
gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$key"; \
|
|
||||||
done; \
|
|
||||||
gpg --batch --verify "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_PATH.tar.gz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
echo "$OPENSSL_SOURCE_SHA256 *$OPENSSL_PATH.tar.gz" | sha256sum --check --strict -; \
|
|
||||||
mkdir -p "$OPENSSL_PATH"; \
|
|
||||||
tar --extract --file "$OPENSSL_PATH.tar.gz" --directory "$OPENSSL_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure OpenSSL for compilation
|
|
||||||
cd "$OPENSSL_PATH"; \
|
|
||||||
# without specifying "--libdir", Erlang will fail during "crypto:supports()" looking for a "pthread_atfork" function that doesn't exist (but only on arm32v7/armhf??)
|
|
||||||
debMultiarch="$(dpkg-architecture --query DEB_HOST_MULTIARCH)"; \
|
|
||||||
# OpenSSL's "config" script uses a lot of "uname"-based target detection...
|
|
||||||
MACHINE="$(dpkg-architecture --query DEB_BUILD_GNU_CPU)" \
|
|
||||||
RELEASE="4.x.y-z" \
|
|
||||||
SYSTEM='Linux' \
|
|
||||||
BUILD='???' \
|
|
||||||
./config \
|
|
||||||
--openssldir="$OPENSSL_CONFIG_DIR" \
|
|
||||||
--libdir="lib/$debMultiarch" \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
-Wl,-rpath=/usr/local/lib \
|
|
||||||
; \
|
|
||||||
# Compile, install OpenSSL, verify that the command-line works & development headers are present
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)"; \
|
|
||||||
make install_sw install_ssldirs; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf "$OPENSSL_PATH"*; \
|
|
||||||
ldconfig; \
|
|
||||||
# use Debian's CA certificates
|
|
||||||
rmdir "$OPENSSL_CONFIG_DIR/certs" "$OPENSSL_CONFIG_DIR/private"; \
|
|
||||||
ln -sf /etc/ssl/certs /etc/ssl/private "$OPENSSL_CONFIG_DIR"; \
|
|
||||||
# smoke test
|
|
||||||
openssl version; \
|
|
||||||
\
|
|
||||||
OTP_SOURCE_URL="https://github.com/erlang/otp/archive/OTP-$OTP_VERSION.tar.gz"; \
|
|
||||||
OTP_PATH="/usr/local/src/otp-$OTP_VERSION"; \
|
|
||||||
\
|
|
||||||
# Download, verify & extract OTP_SOURCE
|
|
||||||
mkdir -p "$OTP_PATH"; \
|
|
||||||
wget --progress dot:giga --output-document "$OTP_PATH.tar.gz" "$OTP_SOURCE_URL"; \
|
|
||||||
echo "$OTP_SOURCE_SHA256 *$OTP_PATH.tar.gz" | sha256sum --check --strict -; \
|
|
||||||
tar --extract --file "$OTP_PATH.tar.gz" --directory "$OTP_PATH" --strip-components 1; \
|
|
||||||
\
|
|
||||||
# Configure Erlang/OTP for compilation, disable unused features & applications
|
|
||||||
# http://erlang.org/doc/applications.html
|
|
||||||
# ERL_TOP is required for Erlang/OTP makefiles to find the absolute path for the installation
|
|
||||||
cd "$OTP_PATH"; \
|
|
||||||
export ERL_TOP="$OTP_PATH"; \
|
|
||||||
./otp_build autoconf; \
|
|
||||||
CFLAGS="$(dpkg-buildflags --get CFLAGS)"; export CFLAGS; \
|
|
||||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
|
||||||
export CFLAGS="$CFLAGS -Wl,-rpath=/usr/local/lib"; \
|
|
||||||
hostArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"; \
|
|
||||||
buildArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
|
|
||||||
dpkgArch="$(dpkg --print-architecture)"; dpkgArch="${dpkgArch##*-}"; \
|
|
||||||
./configure \
|
|
||||||
--host="$hostArch" \
|
|
||||||
--build="$buildArch" \
|
|
||||||
--disable-dynamic-ssl-lib \
|
|
||||||
--disable-hipe \
|
|
||||||
--disable-sctp \
|
|
||||||
--disable-silent-rules \
|
|
||||||
--enable-clock-gettime \
|
|
||||||
--enable-hybrid-heap \
|
|
||||||
--enable-kernel-poll \
|
|
||||||
--enable-shared-zlib \
|
|
||||||
--enable-smp-support \
|
|
||||||
--enable-threads \
|
|
||||||
--with-microstate-accounting=extra \
|
|
||||||
--without-common_test \
|
|
||||||
--without-debugger \
|
|
||||||
--without-dialyzer \
|
|
||||||
--without-diameter \
|
|
||||||
--without-edoc \
|
|
||||||
--without-erl_docgen \
|
|
||||||
--without-erl_interface \
|
|
||||||
--without-et \
|
|
||||||
--without-eunit \
|
|
||||||
--without-ftp \
|
|
||||||
--without-hipe \
|
|
||||||
--without-jinterface \
|
|
||||||
--without-megaco \
|
|
||||||
--without-observer \
|
|
||||||
--without-odbc \
|
|
||||||
--without-reltool \
|
|
||||||
--without-ssh \
|
|
||||||
--without-tftp \
|
|
||||||
--without-wx \
|
|
||||||
; \
|
|
||||||
# Compile & install Erlang/OTP
|
|
||||||
make -j "$(getconf _NPROCESSORS_ONLN)" GEN_OPT_FLGS="-O2 -fno-strict-aliasing"; \
|
|
||||||
make install; \
|
|
||||||
cd ..; \
|
|
||||||
rm -rf \
|
|
||||||
"$OTP_PATH"* \
|
|
||||||
/usr/local/lib/erlang/lib/*/examples \
|
|
||||||
/usr/local/lib/erlang/lib/*/src \
|
|
||||||
; \
|
|
||||||
\
|
|
||||||
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
|
||||||
apt-mark auto '.*' > /dev/null; \
|
|
||||||
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
|
|
||||||
find /usr/local -type f -executable -exec ldd '{}' ';' \
|
|
||||||
| awk '/=>/ { print $(NF-1) }' \
|
|
||||||
| sort -u \
|
|
||||||
| xargs -r dpkg-query --search \
|
|
||||||
| cut -d: -f1 \
|
|
||||||
| sort -u \
|
|
||||||
| xargs -r apt-mark manual \
|
|
||||||
; \
|
|
||||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
|
||||||
\
|
|
||||||
# Check that OpenSSL still works after purging build dependencies
|
|
||||||
openssl version; \
|
|
||||||
# Check that Erlang/OTP crypto & ssl were compiled against OpenSSL correctly
|
|
||||||
erl -noshell -eval 'io:format("~p~n~n~p~n~n", [crypto:supports(), ssl:versions()]), init:stop().'
|
|
||||||
|
|
||||||
ENV RABBITMQ_DATA_DIR=/var/lib/rabbitmq
|
|
||||||
# Create rabbitmq system user & group, fix permissions & allow root user to connect to the RabbitMQ Erlang VM
|
|
||||||
RUN set -eux; \
|
|
||||||
groupadd --gid 999 --system rabbitmq; \
|
|
||||||
useradd --uid 999 --system --home-dir "$RABBITMQ_DATA_DIR" --gid rabbitmq rabbitmq; \
|
|
||||||
mkdir -p "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chown -fR rabbitmq:rabbitmq "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
chmod 777 "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
|
||||||
ln -sf "$RABBITMQ_DATA_DIR/.erlang.cookie" /root/.erlang.cookie
|
|
||||||
|
|
||||||
# Use the latest stable RabbitMQ release (https://www.rabbitmq.com/download.html)
|
|
||||||
ENV RABBITMQ_VERSION 3.7.28
|
|
||||||
# https://www.rabbitmq.com/signatures.html#importing-gpg
|
|
||||||
ENV RABBITMQ_PGP_KEY_ID="0x0A9AF2115F4687BD29803A206B73A36E6026DFCA"
|
|
||||||
ENV RABBITMQ_HOME=/opt/rabbitmq
|
|
||||||
|
|
||||||
# Add RabbitMQ to PATH, send all logs to TTY
|
|
||||||
ENV PATH=$RABBITMQ_HOME/sbin:$PATH \
|
|
||||||
RABBITMQ_LOGS=-
|
|
||||||
|
|
||||||
# Install RabbitMQ
|
|
||||||
RUN set -eux; \
|
|
||||||
\
|
|
||||||
savedAptMark="$(apt-mark showmanual)"; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install --yes --no-install-recommends \
|
|
||||||
ca-certificates \
|
|
||||||
gnupg \
|
|
||||||
wget \
|
|
||||||
xz-utils \
|
|
||||||
; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
\
|
|
||||||
RABBITMQ_SOURCE_URL="https://github.com/rabbitmq/rabbitmq-server/releases/download/v$RABBITMQ_VERSION/rabbitmq-server-generic-unix-latest-toolchain-$RABBITMQ_VERSION.tar.xz"; \
|
|
||||||
RABBITMQ_PATH="/usr/local/src/rabbitmq-$RABBITMQ_VERSION"; \
|
|
||||||
\
|
|
||||||
wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_SOURCE_URL.asc"; \
|
|
||||||
wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar.xz" "$RABBITMQ_SOURCE_URL"; \
|
|
||||||
\
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$RABBITMQ_PGP_KEY_ID"; \
|
|
||||||
gpg --batch --verify "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_PATH.tar.xz"; \
|
|
||||||
gpgconf --kill all; \
|
|
||||||
rm -rf "$GNUPGHOME"; \
|
|
||||||
\
|
|
||||||
mkdir -p "$RABBITMQ_HOME"; \
|
|
||||||
tar --extract --file "$RABBITMQ_PATH.tar.xz" --directory "$RABBITMQ_HOME" --strip-components 1; \
|
|
||||||
rm -rf "$RABBITMQ_PATH"*; \
|
|
||||||
# Do not default SYS_PREFIX to RABBITMQ_HOME, leave it empty
|
|
||||||
grep -qE '^SYS_PREFIX=\$\{RABBITMQ_HOME\}$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
sed -i 's/^SYS_PREFIX=.*$/SYS_PREFIX=/' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
grep -qE '^SYS_PREFIX=$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
|
||||||
chown -R rabbitmq:rabbitmq "$RABBITMQ_HOME"; \
|
|
||||||
\
|
|
||||||
apt-mark auto '.*' > /dev/null; \
|
|
||||||
apt-mark manual $savedAptMark; \
|
|
||||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
|
||||||
\
|
|
||||||
# verify assumption of no stale cookies
|
|
||||||
[ ! -e "$RABBITMQ_DATA_DIR/.erlang.cookie" ]; \
|
|
||||||
# Ensure RabbitMQ was installed correctly by running a few commands that do not depend on a running server, as the rabbitmq user
|
|
||||||
# If they all succeed, it's safe to assume that things have been set up correctly
|
|
||||||
gosu rabbitmq rabbitmqctl help; \
|
|
||||||
gosu rabbitmq rabbitmqctl list_ciphers; \
|
|
||||||
gosu rabbitmq rabbitmq-plugins list; \
|
|
||||||
# no stale cookies
|
|
||||||
rm "$RABBITMQ_DATA_DIR/.erlang.cookie"
|
|
||||||
|
|
||||||
# Added for backwards compatibility - users can simply COPY custom plugins to /plugins
|
|
||||||
RUN ln -sf /opt/rabbitmq/plugins /plugins
|
|
||||||
|
|
||||||
# set home so that any `--user` knows where to put the erlang cookie
|
|
||||||
ENV HOME $RABBITMQ_DATA_DIR
|
|
||||||
# Hint that the data (a.k.a. home dir) dir should be separate volume
|
|
||||||
VOLUME $RABBITMQ_DATA_DIR
|
|
||||||
|
|
||||||
# warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
|
|
||||||
# Setting all environment variables that control language preferences, behaviour differs - https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
|
|
||||||
# https://docs.docker.com/samples/library/ubuntu/#locales
|
|
||||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
|
|
||||||
EXPOSE 4369 5671 5672 25672
|
|
||||||
CMD ["rabbitmq-server"]
|
|
||||||
|
|
@ -1,415 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# usage: file_env VAR [DEFAULT]
|
|
||||||
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
|
||||||
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
|
||||||
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
|
||||||
file_env() {
|
|
||||||
local var="$1"
|
|
||||||
local fileVar="${var}_FILE"
|
|
||||||
local def="${2:-}"
|
|
||||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
||||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local val="$def"
|
|
||||||
if [ "${!var:-}" ]; then
|
|
||||||
val="${!var}"
|
|
||||||
elif [ "${!fileVar:-}" ]; then
|
|
||||||
val="$(< "${!fileVar}")"
|
|
||||||
fi
|
|
||||||
export "$var"="$val"
|
|
||||||
unset "$fileVar"
|
|
||||||
}
|
|
||||||
|
|
||||||
# backwards compatibility for old environment variables
|
|
||||||
: "${RABBITMQ_SSL_CERTFILE:=${RABBITMQ_SSL_CERT_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_KEYFILE:=${RABBITMQ_SSL_KEY_FILE:-}}"
|
|
||||||
: "${RABBITMQ_SSL_CACERTFILE:=${RABBITMQ_SSL_CA_FILE:-}}"
|
|
||||||
|
|
||||||
# "management" SSL config should default to using the same certs
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CACERTFILE:=$RABBITMQ_SSL_CACERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_CERTFILE:=$RABBITMQ_SSL_CERTFILE}"
|
|
||||||
: "${RABBITMQ_MANAGEMENT_SSL_KEYFILE:=$RABBITMQ_SSL_KEYFILE}"
|
|
||||||
|
|
||||||
# Allowed env vars that will be read from mounted files (i.e. Docker Secrets):
|
|
||||||
fileEnvKeys=(
|
|
||||||
default_user
|
|
||||||
default_pass
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://www.rabbitmq.com/configure.html
|
|
||||||
sslConfigKeys=(
|
|
||||||
cacertfile
|
|
||||||
certfile
|
|
||||||
depth
|
|
||||||
fail_if_no_peer_cert
|
|
||||||
keyfile
|
|
||||||
verify
|
|
||||||
)
|
|
||||||
managementConfigKeys=(
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
rabbitConfigKeys=(
|
|
||||||
default_pass
|
|
||||||
default_user
|
|
||||||
default_vhost
|
|
||||||
vm_memory_high_watermark
|
|
||||||
)
|
|
||||||
fileConfigKeys=(
|
|
||||||
management_ssl_cacertfile
|
|
||||||
management_ssl_certfile
|
|
||||||
management_ssl_keyfile
|
|
||||||
ssl_cacertfile
|
|
||||||
ssl_certfile
|
|
||||||
ssl_keyfile
|
|
||||||
)
|
|
||||||
allConfigKeys=(
|
|
||||||
"${managementConfigKeys[@]/#/management_}"
|
|
||||||
"${rabbitConfigKeys[@]}"
|
|
||||||
"${sslConfigKeys[@]/#/ssl_}"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -A configDefaults=(
|
|
||||||
[management_ssl_fail_if_no_peer_cert]='false'
|
|
||||||
[management_ssl_verify]='verify_none'
|
|
||||||
|
|
||||||
[ssl_fail_if_no_peer_cert]='true'
|
|
||||||
[ssl_verify]='verify_peer'
|
|
||||||
)
|
|
||||||
|
|
||||||
# allow the container to be started with `--user`
|
|
||||||
if [[ "$1" == rabbitmq* ]] && [ "$(id -u)" = '0' ]; then
|
|
||||||
# this needs to happen late enough that we have the SSL config
|
|
||||||
# https://github.com/docker-library/rabbitmq/issues/283
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
[ -n "$val" ] || continue
|
|
||||||
case "$conf" in
|
|
||||||
*_ssl_*file | ssl_*file )
|
|
||||||
if [ -f "$val" ] && ! gosu rabbitmq test -r "$val"; then
|
|
||||||
newFile="/tmp/rabbitmq-ssl/$conf.pem"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$val' ($var) is not readable by rabbitmq ($(id rabbitmq)); copying to '$newFile'"
|
|
||||||
echo >&2
|
|
||||||
cat "$val" > "$newFile"
|
|
||||||
chown rabbitmq "$newFile"
|
|
||||||
chmod 0400 "$newFile"
|
|
||||||
eval 'export '$var'="$newFile"'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ]; then
|
|
||||||
find /var/lib/rabbitmq \! -user rabbitmq -exec chown rabbitmq '{}' +
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec gosu rabbitmq "$BASH_SOURCE" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
haveConfig=
|
|
||||||
haveSslConfig=
|
|
||||||
haveManagementSslConfig=
|
|
||||||
for fileEnvKey in "${fileEnvKeys[@]}"; do file_env "RABBITMQ_${fileEnvKey^^}"; done
|
|
||||||
for conf in "${allConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var:-}"
|
|
||||||
if [ "$val" ]; then
|
|
||||||
if [ "${configDefaults[$conf]:-}" ] && [ "${configDefaults[$conf]}" = "$val" ]; then
|
|
||||||
# if the value set is the same as the default, treat it as if it isn't set
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
haveConfig=1
|
|
||||||
case "$conf" in
|
|
||||||
ssl_*) haveSslConfig=1 ;;
|
|
||||||
management_ssl_*) haveManagementSslConfig=1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
missing=()
|
|
||||||
for sslConf in cacertfile certfile keyfile; do
|
|
||||||
var="RABBITMQ_SSL_${sslConf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ -z "$val" ]; then
|
|
||||||
missing+=( "$var" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missing[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: SSL requested, but missing required configuration'
|
|
||||||
for miss in "${missing[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
missingFiles=()
|
|
||||||
for conf in "${fileConfigKeys[@]}"; do
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
val="${!var}"
|
|
||||||
if [ "$val" ] && [ ! -f "$val" ]; then
|
|
||||||
missingFiles+=( "$val ($var)" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missingFiles[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo 'error: files specified, but missing'
|
|
||||||
for miss in "${missingFiles[@]}"; do
|
|
||||||
echo " - $miss"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set defaults for missing values (but only after we're done with all our checking so we don't throw any of that off)
|
|
||||||
for conf in "${!configDefaults[@]}"; do
|
|
||||||
default="${configDefaults[$conf]}"
|
|
||||||
var="RABBITMQ_${conf^^}"
|
|
||||||
[ -z "${!var:-}" ] || continue
|
|
||||||
eval "export $var=\"\$default\""
|
|
||||||
done
|
|
||||||
|
|
||||||
# if long and short hostnames are not the same, use long hostnames
|
|
||||||
if [ "$(hostname)" != "$(hostname -s)" ]; then
|
|
||||||
: "${RABBITMQ_USE_LONGNAME:=true}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${RABBITMQ_ERLANG_COOKIE:-}" ]; then
|
|
||||||
cookieFile='/var/lib/rabbitmq/.erlang.cookie'
|
|
||||||
if [ -e "$cookieFile" ]; then
|
|
||||||
if [ "$(cat "$cookieFile" 2>/dev/null)" != "$RABBITMQ_ERLANG_COOKIE" ]; then
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "warning: $cookieFile contents do not match RABBITMQ_ERLANG_COOKIE"
|
|
||||||
echo >&2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$RABBITMQ_ERLANG_COOKIE" > "$cookieFile"
|
|
||||||
fi
|
|
||||||
chmod 600 "$cookieFile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
configBase="${RABBITMQ_CONFIG_FILE:-/etc/rabbitmq/rabbitmq}"
|
|
||||||
oldConfigFile="$configBase.config"
|
|
||||||
newConfigFile="$configBase.conf"
|
|
||||||
|
|
||||||
shouldWriteConfig="$haveConfig"
|
|
||||||
if [ -n "$shouldWriteConfig" ] && ! touch "$newConfigFile"; then
|
|
||||||
# config file exists but it isn't writeable (likely read-only mount, such as Kubernetes configMap)
|
|
||||||
export RABBITMQ_CONFIG_FILE='/tmp/rabbitmq.conf'
|
|
||||||
cp "$newConfigFile" "$RABBITMQ_CONFIG_FILE"
|
|
||||||
echo >&2
|
|
||||||
echo >&2 "WARNING: '$newConfigFile' is not writable, but environment variables have been provided which request that we write to it"
|
|
||||||
echo >&2 " We have copied it to '$RABBITMQ_CONFIG_FILE' so it can be amended to work around the problem, but it is recommended that the read-only source file should be modified and the environment variables removed instead."
|
|
||||||
echo >&2
|
|
||||||
newConfigFile="$RABBITMQ_CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$shouldWriteConfig" ] && [ -f "$oldConfigFile" ]; then
|
|
||||||
{
|
|
||||||
echo "error: Docker configuration environment variables specified, but old-style (Erlang syntax) configuration file '$oldConfigFile' exists"
|
|
||||||
echo " Suggested fixes: (choose one)"
|
|
||||||
echo " - remove '$oldConfigFile'"
|
|
||||||
echo " - remove any Docker-specific 'RABBITMQ_...' environment variables"
|
|
||||||
echo " - convert '$oldConfigFile' to the newer sysctl format ('$newConfigFile'); see https://www.rabbitmq.com/configure.html#config-file"
|
|
||||||
} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$shouldWriteConfig" ] && [ ! -f "$oldConfigFile" ] && [ ! -f "$newConfigFile" ]; then
|
|
||||||
# no config files, we should write one
|
|
||||||
shouldWriteConfig=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# http://stackoverflow.com/a/2705678/433558
|
|
||||||
sed_escape_lhs() {
|
|
||||||
echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g'
|
|
||||||
}
|
|
||||||
sed_escape_rhs() {
|
|
||||||
echo "$@" | sed -e 's/[\/&]/\\&/g'
|
|
||||||
}
|
|
||||||
rabbit_set_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
local val="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
local sedVal="$(sed_escape_rhs "$val")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*)\S.*\$/\1${sedVal}/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
if ! grep -qE "^${sedKey}[[:space:]]*=" "$newConfigFile"; then
|
|
||||||
echo "$key = $val" >> "$newConfigFile"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
rabbit_comment_config() {
|
|
||||||
local key="$1"; shift
|
|
||||||
|
|
||||||
[ -e "$newConfigFile" ] || touch "$newConfigFile"
|
|
||||||
|
|
||||||
local sedKey="$(sed_escape_lhs "$key")"
|
|
||||||
sed -ri \
|
|
||||||
"s/^[[:space:]]*#?[[:space:]]*(${sedKey}[[:space:]]*=[[:space:]]*\S.*)\$/# \1/" \
|
|
||||||
"$newConfigFile"
|
|
||||||
}
|
|
||||||
rabbit_env_config() {
|
|
||||||
local prefix="$1"; shift
|
|
||||||
|
|
||||||
local conf
|
|
||||||
for conf; do
|
|
||||||
local var="rabbitmq${prefix:+_$prefix}_$conf"
|
|
||||||
var="${var^^}"
|
|
||||||
|
|
||||||
local key="$conf"
|
|
||||||
case "$prefix" in
|
|
||||||
ssl) key="ssl_options.$key" ;;
|
|
||||||
management_ssl) key="management.ssl.$key" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
local val="${!var:-}"
|
|
||||||
local rawVal="$val"
|
|
||||||
case "$conf" in
|
|
||||||
fail_if_no_peer_cert)
|
|
||||||
case "${val,,}" in
|
|
||||||
false|no|0|'') rawVal='false' ;;
|
|
||||||
true|yes|1|*) rawVal='true' ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
|
|
||||||
vm_memory_high_watermark) continue ;; # handled separately
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$rawVal" ]; then
|
|
||||||
rabbit_set_config "$key" "$rawVal"
|
|
||||||
else
|
|
||||||
rabbit_comment_config "$key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$1" = 'rabbitmq-server' ] && [ "$shouldWriteConfig" ]; then
|
|
||||||
rabbit_set_config 'loopback_users.guest' 'false'
|
|
||||||
|
|
||||||
# determine whether to set "vm_memory_high_watermark" (based on cgroups)
|
|
||||||
memTotalKb=
|
|
||||||
if [ -r /proc/meminfo ]; then
|
|
||||||
memTotalKb="$(awk -F ':? +' '$1 == "MemTotal" { print $2; exit }' /proc/meminfo)"
|
|
||||||
fi
|
|
||||||
memLimitB=
|
|
||||||
if [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
|
||||||
# "18446744073709551615" is a valid value for "memory.limit_in_bytes", which is too big for Bash math to handle
|
|
||||||
# "$(( 18446744073709551615 / 1024 ))" = 0; "$(( 18446744073709551615 * 40 / 100 ))" = 0
|
|
||||||
memLimitB="$(awk -v totKb="$memTotalKb" '{
|
|
||||||
limB = $0;
|
|
||||||
limKb = limB / 1024;
|
|
||||||
if (!totKb || limKb < totKb) {
|
|
||||||
printf "%.0f\n", limB;
|
|
||||||
}
|
|
||||||
}' /sys/fs/cgroup/memory/memory.limit_in_bytes)"
|
|
||||||
fi
|
|
||||||
if [ -n "$memLimitB" ]; then
|
|
||||||
# if we have a cgroup memory limit, let's inform RabbitMQ of what it is (so it can calculate vm_memory_high_watermark properly)
|
|
||||||
# https://github.com/rabbitmq/rabbitmq-server/pull/1234
|
|
||||||
rabbit_set_config 'total_memory_available_override_value' "$memLimitB"
|
|
||||||
fi
|
|
||||||
# https://www.rabbitmq.com/memory.html#memsup-usage
|
|
||||||
if [ "${RABBITMQ_VM_MEMORY_HIGH_WATERMARK:-}" ]; then
|
|
||||||
# https://github.com/docker-library/rabbitmq/pull/105#issuecomment-242165822
|
|
||||||
vmMemoryHighWatermark="$(
|
|
||||||
echo "$RABBITMQ_VM_MEMORY_HIGH_WATERMARK" | awk '
|
|
||||||
/^[0-9]*[.][0-9]+$|^[0-9]+([.][0-9]+)?%$/ {
|
|
||||||
perc = $0;
|
|
||||||
if (perc ~ /%$/) {
|
|
||||||
gsub(/%$/, "", perc);
|
|
||||||
perc = perc / 100;
|
|
||||||
}
|
|
||||||
if (perc > 1.0 || perc < 0.0) {
|
|
||||||
printf "error: invalid percentage for vm_memory_high_watermark: %s (must be >= 0%%, <= 100%%)\n", $0 > "/dev/stderr";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
printf "vm_memory_high_watermark.relative %0.03f\n", perc;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
/^[0-9]+([.][0-9]+)?[a-zA-Z]+$/ {
|
|
||||||
printf "vm_memory_high_watermark.absolute %s\n", $0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
printf "error: unexpected input for vm_memory_high_watermark: %s\n", $0;
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
'
|
|
||||||
)"
|
|
||||||
if [ "$vmMemoryHighWatermark" ]; then
|
|
||||||
vmMemoryHighWatermarkKey="${vmMemoryHighWatermark%% *}"
|
|
||||||
vmMemoryHighWatermarkVal="${vmMemoryHighWatermark#$vmMemoryHighWatermarkKey }"
|
|
||||||
rabbit_set_config "$vmMemoryHighWatermarkKey" "$vmMemoryHighWatermarkVal"
|
|
||||||
case "$vmMemoryHighWatermarkKey" in
|
|
||||||
# make sure we only set one or the other
|
|
||||||
'vm_memory_high_watermark.absolute') rabbit_comment_config 'vm_memory_high_watermark.relative' ;;
|
|
||||||
'vm_memory_high_watermark.relative') rabbit_comment_config 'vm_memory_high_watermark.absolute' ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$haveSslConfig" ]; then
|
|
||||||
rabbit_set_config 'listeners.ssl.default' 5671
|
|
||||||
rabbit_env_config 'ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'listeners.tcp.default' 5672
|
|
||||||
fi
|
|
||||||
|
|
||||||
rabbit_env_config '' "${rabbitConfigKeys[@]}"
|
|
||||||
|
|
||||||
# if management plugin is installed, generate config for it
|
|
||||||
# https://www.rabbitmq.com/management.html#configuration
|
|
||||||
if [ "$(rabbitmq-plugins list -q -m -e rabbitmq_management)" ]; then
|
|
||||||
if [ "$haveManagementSslConfig" ]; then
|
|
||||||
rabbit_set_config 'management.ssl.port' 15671
|
|
||||||
rabbit_env_config 'management_ssl' "${sslConfigKeys[@]}"
|
|
||||||
else
|
|
||||||
rabbit_set_config 'management.tcp.port' 15672
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if definitions file exists, then load it
|
|
||||||
# https://www.rabbitmq.com/management.html#load-definitions
|
|
||||||
managementDefinitionsFile='/etc/rabbitmq/definitions.json'
|
|
||||||
if [ -f "$managementDefinitionsFile" ]; then
|
|
||||||
# see also https://github.com/docker-library/rabbitmq/pull/112#issuecomment-271485550
|
|
||||||
rabbit_set_config 'management.load_definitions' "$managementDefinitionsFile"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
combinedSsl='/tmp/rabbitmq-ssl/combined.pem'
|
|
||||||
if [ "$haveSslConfig" ] && [[ "$1" == rabbitmq* ]] && [ ! -f "$combinedSsl" ]; then
|
|
||||||
# Create combined cert
|
|
||||||
{
|
|
||||||
cat "$RABBITMQ_SSL_CERTFILE"
|
|
||||||
echo # https://github.com/docker-library/rabbitmq/issues/357#issuecomment-517755647
|
|
||||||
cat "$RABBITMQ_SSL_KEYFILE"
|
|
||||||
} > "$combinedSsl"
|
|
||||||
chmod 0400 "$combinedSsl"
|
|
||||||
fi
|
|
||||||
if [ "$haveSslConfig" ] && [ -f "$combinedSsl" ]; then
|
|
||||||
# More ENV vars for make clustering happiness
|
|
||||||
# we don't handle clustering in this script, but these args should ensure
|
|
||||||
# clustered SSL-enabled members will talk nicely
|
|
||||||
export ERL_SSL_PATH="$(erl -eval 'io:format("~p", [code:lib_dir(ssl, ebin)]),halt().' -noshell)"
|
|
||||||
sslErlArgs="-pa $ERL_SSL_PATH -proto_dist inet_tls -ssl_dist_opt server_certfile $combinedSsl -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
|
|
||||||
export RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
export RABBITMQ_CTL_ERL_ARGS="${RABBITMQ_CTL_ERL_ARGS:-} $sslErlArgs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
FROM rabbitmq:3.7
|
|
||||||
|
|
||||||
RUN rabbitmq-plugins enable --offline rabbitmq_management
|
|
||||||
|
|
||||||
# extract "rabbitmqadmin" from inside the "rabbitmq_management-X.Y.Z.ez" plugin zipfile
|
|
||||||
# see https://github.com/docker-library/rabbitmq/issues/207
|
|
||||||
RUN set -eux; \
|
|
||||||
erl -noinput -eval ' \
|
|
||||||
{ ok, AdminBin } = zip:foldl(fun(FileInArchive, GetInfo, GetBin, Acc) -> \
|
|
||||||
case Acc of \
|
|
||||||
"" -> \
|
|
||||||
case lists:suffix("/rabbitmqadmin", FileInArchive) of \
|
|
||||||
true -> GetBin(); \
|
|
||||||
false -> Acc \
|
|
||||||
end; \
|
|
||||||
_ -> Acc \
|
|
||||||
end \
|
|
||||||
end, "", init:get_plain_arguments()), \
|
|
||||||
io:format("~s", [ AdminBin ]), \
|
|
||||||
init:stop(). \
|
|
||||||
' -- /plugins/rabbitmq_management-*.ez > /usr/local/bin/rabbitmqadmin; \
|
|
||||||
[ -s /usr/local/bin/rabbitmqadmin ]; \
|
|
||||||
chmod +x /usr/local/bin/rabbitmqadmin; \
|
|
||||||
apt-get update; apt-get install -y --no-install-recommends python3; rm -rf /var/lib/apt/lists/*; \
|
|
||||||
rabbitmqadmin --version
|
|
||||||
|
|
||||||
EXPOSE 15671 15672
|
|
||||||
|
|
@ -12,7 +12,7 @@ RUN apk add --no-cache \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ RUN set -eux; \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ RUN apk add --no-cache \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ RUN set -eux; \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ RUN apk add --no-cache \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ RUN set -eux; \
|
||||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.8 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.8/ubuntu
|
||||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||||
|
|
||||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ versions=( "${versions[@]%/}" )
|
||||||
|
|
||||||
# https://www.rabbitmq.com/which-erlang.html ("Maximum supported Erlang/OTP")
|
# https://www.rabbitmq.com/which-erlang.html ("Maximum supported Erlang/OTP")
|
||||||
declare -A otpMajors=(
|
declare -A otpMajors=(
|
||||||
[3.7]='22'
|
|
||||||
[3.8]='23'
|
[3.8]='23'
|
||||||
)
|
)
|
||||||
declare -A otpHashCache=()
|
declare -A otpHashCache=()
|
||||||
|
|
@ -19,7 +18,6 @@ declare -A otpHashCache=()
|
||||||
# https://www.openssl.org/policies/releasestrat.html
|
# https://www.openssl.org/policies/releasestrat.html
|
||||||
# https://www.openssl.org/source/
|
# https://www.openssl.org/source/
|
||||||
declare -A opensslMajors=(
|
declare -A opensslMajors=(
|
||||||
[3.7]='1.1'
|
|
||||||
[3.8]='1.1'
|
[3.8]='1.1'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue