diff --git a/release/docker/Dockerfile b/release/docker/Dockerfile index f45486c7582e526d8c0137867b12d077c9b95c0e..615496cbfb44c5c0fe625efd342dcb37f19b24d0 100644 --- a/release/docker/Dockerfile +++ b/release/docker/Dockerfile @@ -17,17 +17,16 @@ RUN apk update && \ WORKDIR /duniter -# copy source tree -COPY ./ ./ - # install latest stable rust RUN curl https://sh.rustup.rs -sSf | sh -s -- -y +# copy source tree +COPY ./ ./ + # build duniter RUN PATH=${HOME}/.cargo/bin:${PATH} \ RUSTFLAGS="-C target-feature=-crt-static" \ make -C release ADD_DEBUG=N server-gui clean \ - && cp release/docker/duniter.sh work/docker.sh \ && rm -rf work/extra # ------------------------------------------------------------------------------ @@ -36,18 +35,22 @@ RUN PATH=${HOME}/.cargo/bin:${PATH} \ FROM node:10-alpine +# install jq +RUN apk add jq + # create group and user duniter RUN addgroup -S -g 1111 duniter && \ adduser -SD -h /duniter -G duniter -u 1111 duniter RUN mkdir -p /var/lib/duniter /etc/duniter && chown duniter:duniter /var/lib/duniter /etc/duniter # copy the build artifact from the build stage -COPY --from=build --chown=duniter:duniter /duniter/work /duniter/duniter +COPY --from=build --chown=duniter:duniter /duniter/work /duniter -# copy bootstrap script -RUN cp /duniter/duniter/docker.sh /usr/bin/duniter && \ - chmod +x /usr/bin/duniter && \ - chown duniter:duniter /usr/bin/duniter +# copy wrappers +COPY release/docker/duniter.sh /usr/bin/duniter + +# copy entrypoint +COPY release/docker/docker-entrypoint.sh / # create volumes VOLUME /var/lib/duniter @@ -58,7 +61,7 @@ EXPOSE 9220 10901 20901 # use duniter user USER duniter -WORKDIR /duniter +WORKDIR /var/lib/duniter -ENTRYPOINT ["/usr/bin/duniter"] +ENTRYPOINT ["/docker-entrypoint.sh"] CMD [] diff --git a/release/docker/docker-entrypoint.sh b/release/docker/docker-entrypoint.sh new file mode 100755 index 0000000000000000000000000000000000000000..3e95b35bb9162234d640f5ad19091e927072c227 --- /dev/null +++ b/release/docker/docker-entrypoint.sh @@ -0,0 +1,138 @@ +#!/bin/sh +set -uo pipefail + +boolean () { + echo "$1" | sed -E 's/^(true|yes|1)$/true/i' +} +big_fat_warning='\033[01;31m**WARNING**:\033[0m' + +DEBUG_ENTRYPOINT="$(boolean "${DEBUG_ENTRYPOINT:-false}")" +if [ "$DEBUG_ENTRYPOINT" = true ]; then + set -x +fi + +# Initialize vars +home=/var/lib/duniter +profile_default=$home/duniter_default +manual_config="$(boolean "${DUNITER_MANUAL_CONFIG:-false}")" +auto_sync="$(boolean "${DUNITER_AUTO_SYNC:-false}")" +DUNITER_PEER_HOST="${DUNITER_PEER_HOST:-${DUNITER_SYNC_HOST:-}}" +if ! echo "${NODE_OPTIONS:-}" | grep '\--max-old-space-size'; then + NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--max-old-space-size=${DUNITER_MAX_OLD_SPACE_SIZE:-6144}" + export NODE_OPTIONS +fi + +# Create default profile path +mkdir -p "$home/duniter_default" + +# Manual config when enabled +if [ "$manual_config" = true ]; then + # Do not start until a configuration file was initialized + while ! [ -f "$profile_default/conf.json.orig" ]; do + echo "Waiting for initial configuration file... Please copy your configuration file to '$profile_default/conf.json.orig'" + sleep 10 + done + echo "Configuration file found. Continuing..." + # Use new conf.json.orig when changed + md5_file="$profile_default/conf.json.orig.md5" + if ! md5sum -c "$md5_file"; then + if [ -f "$profile_default/conf.json" ]; then + echo "Backing up old configuration file to '$profile_default/conf.json.old'..." + mv $profile_default/conf.json $profile_default/conf.json.old + fi + echo "Installing new configuration file..." + cp "$profile_default/conf.json.orig" "$profile_default/conf.json" + md5sum "$profile_default/conf.json.orig" >"$md5_file" + fi + # Log differences between initial, old and current conf file + jq --sort-keys -r . "$profile_default/conf.json.orig" >"$profile_default/conf.json.orig.sorted" + jq --sort-keys -r . "$profile_default/conf.json" >"$profile_default/conf.json.sorted" + if [ -f "$profile_default/conf.json.old" ]; then + jq --sort-keys -r . "$profile_default/conf.json.old" >"$profile_default/conf.json.old.sorted" + if ! diff -q "$profile_default/conf.json.old.sorted" "$profile_default/conf.json.orig.sorted"; then + diff -u "$profile_default/conf.json.old.sorted" "$profile_default/conf.json.orig.sorted" + fi + fi + if ! diff -q "$profile_default/conf.json.orig.sorted" "$profile_default/conf.json.sorted"; then + diff -u "$profile_default/conf.json.orig.sorted" "$profile_default/conf.json.sorted" + fi +fi + +# If conf.json doesn't exist and we have DUNITER_PEER_HOST, then initialise it with +# the currency parameters +host_regex='[a-zA-Z0-9](([a-zA-Z0-9]|-)*[a-zA-Z0-9]+)?(\.[a-zA-Z0-9](([a-zA-Z0-9]|-)*[a-zA-Z0-9]+)?)*' +ipv6_regex='((([0–9A-Fa-f]{1,4}:){7}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){6}:[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){5}:([0–9A-Fa-f]{1,4}:)?[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){4}:([0–9A-Fa-f]{1,4}:){0,2}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){3}:([0–9A-Fa-f]{1,4}:){0,3}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){2}:([0–9A-Fa-f]{1,4}:){0,4}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){6}((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|(([0–9A-Fa-f]{1,4}:){0,5}:((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|(::([0–9A-Fa-f]{1,4}:){0,5}((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|([0–9A-Fa-f]{1,4}::([0–9A-Fa-f]{1,4}:){0,5}[0–9A-Fa-f]{1,4})|(::([0–9A-Fa-f]{1,4}:){0,6}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){1,7}:))' + +if ! [ -f "$profile_default/conf.json" ] && echo "${DUNITER_PEER_HOST}" | grep -E "^($host_regex|$ipv6_regex)(:[0-9]+)?$"; then + echo "No config file - Initializing currency from '$DUNITER_PEER_HOST'..." + port="${DUNITER_PEER_HOST#*:}" + if [ "${port:-443}" = 443 ]; then + scheme=https:// + else + scheme=http:// + fi + if wget -q -O- "$scheme$DUNITER_PEER_HOST/blockchain/parameters" >"$profile_default/conf.json.new"; then + mv "$profile_default/conf.json.new" "$profile_default/conf.json" + else + echo -e "$big_fat_warning Failed." + fi + + # If peers.db is missing and DUNITER_PEER_HOST is set, bootstrap it using + # 'sync --only-peers' + # Working into a temporary Duniter home to avoid side effects on the current + # database + if ! [ -f "$profile_default/peers.db" ] && [ -n "${DUNITER_PEER_HOST:-}" ]; then + echo "No peers database - Initializing from '$DUNITER_PEER_HOST'..." + rm -fr /tmp/duniter-bootstrap + ( + if /usr/bin/duniter --home /tmp/duniter-bootstrap sync "$DUNITER_PEER_HOST" --nointeractive --onlypeers; then + mv /tmp/duniter-bootstrap/duniter_default/peers.db "$profile_default/" + else + echo -e "$big_fat_warning Failed." + fi + ) + rm -fr /tmp/duniter-bootstrap + fi +fi + +# Auto start synchronization when enabled and starting from scratch +if [ "$auto_sync" = true ]; then + if ! [ -d "$profile_default/data" ]; then + echo "No 'data' folder. " + if [ -z "$DUNITER_SYNC_HOST:-" ]; then + echo "DUNITER_SYNC_HOST undefined. Can't start synchronization!" + else + echo "Starting synchronization..." + /usr/bin/duniter sync "$DUNITER_SYNC_HOST" --nointeractive + fi + fi +fi + +# Without parameters, start with web interface +if [ $# = 0 ]; then + set -- direct_webstart +fi + +# Network interface to listen to +set -- --webmhost 0.0.0.0 "$@" + +# Key file found +if [ -f /etc/duniter/keyring.yml ]; then + set -- --keyfile /etc/duniter/keys.yml "$@" +fi + +# Terminate gracefully on SIGTERM by propagating it to the 'node' process +sigterm () { + echo "Received SIGTERM. Terminating..." >&2 + pkill node + wait %1 +} +trap 'sigterm' TERM + +# Start duniter +# Launch in background and wait +# This way we can catch SIGTERM +echo Starting duniter with: +echo /usr/bin/duniter "$@" +/usr/bin/duniter "$@" & +wait %1 diff --git a/release/docker/duniter.sh b/release/docker/duniter.sh old mode 100644 new mode 100755 index 270d084bbf80834941b6d941221b9e10b53fa64d..cbb338b7165e6ca5a8c42e7c74a607f54fe941fd --- a/release/docker/duniter.sh +++ b/release/docker/duniter.sh @@ -1,21 +1,9 @@ #!/bin/sh -# Without parameters, start with web interface -if [[ -z ${1} ]]; then - set -- direct_webstart +# Main +cd /duniter +if [ "$1" != --home ]; then + set -- --home /var/lib/duniter "$@" fi -# Options -DUNITER_OPTS= -DUNITER_OPTS="${DUNITER_OPTS} --webmhost 0.0.0.0" -DUNITER_OPTS="${DUNITER_OPTS} --home /var/lib/duniter" -DUNITER_OPTS="${DUNITER_OPTS} --mdb duniter_default" - -# Key file found -if [[ -f /etc/duniter/key.yml ]]; then - DUNITER_OPTS="${DUNITER_OPTS} --keyfile /etc/duniter/keys.yml" -fi - -# Start duniter -cd /duniter/duniter/ -bin/duniter ${DUNITER_OPTS} "$@" +exec bin/duniter "$@"