From 92b4b64aa623b57866ba04e009afa7f50bbdba8f Mon Sep 17 00:00:00 2001 From: Caian Benedicto Date: Tue, 12 Apr 2022 14:44:03 -0300 Subject: [PATCH] feat(docker): /container-init.d for advanced initialization (#6577) * Add initialization directory support to Docker image * Add sharness test, fix bugs in init script Fixed in init script: - Added some missing quotes around expansions - Fixed INIT_ARGS to not pass any args if IPFS_PROFILE isn't specified - Use printf instead of "echo -e" - Only run scripts in top-level of init dir - Handle filenames correctly when finding init scripts (by using find + xargs) * chore: docker cleanup cleans up containers and images (useful when run on developer machine) * remove container init documentation from README There is already IPFS Docker documentation where this should live: https://docs.ipfs.io/how-to/run-ipfs-inside-docker/ Co-authored-by: Caian Co-authored-by: Marcin Rataj Co-authored-by: Gus Eggert --- Dockerfile | 5 +++++ bin/container_daemon | 19 ++++++++-------- bin/container_init_run | 14 ++++++++++++ test/ipfs-test-lib.sh | 10 +++++++++ test/sharness/t0300-docker-image.sh | 31 +++++++++++++++++++++++++-- test/sharness/t0301-docker-migrate.sh | 2 ++ 6 files changed, 69 insertions(+), 12 deletions(-) create mode 100755 bin/container_init_run diff --git a/Dockerfile b/Dockerfile index 751ba6a9f239..dce35b54c718 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,7 @@ LABEL maintainer="Steven Allen " ENV SRC_DIR /go-ipfs COPY --from=0 $SRC_DIR/cmd/ipfs/ipfs /usr/local/bin/ipfs COPY --from=0 $SRC_DIR/bin/container_daemon /usr/local/bin/start_ipfs +COPY --from=0 $SRC_DIR/bin/container_init_run /usr/local/bin/container_init_run COPY --from=0 /tmp/su-exec/su-exec-static /sbin/su-exec COPY --from=0 /tmp/tini /sbin/tini COPY --from=0 /bin/fusermount /usr/local/bin/fusermount @@ -93,6 +94,10 @@ RUN mkdir -p $IPFS_PATH \ RUN mkdir /ipfs /ipns \ && chown ipfs:users /ipfs /ipns +# Create the init scripts directory +RUN mkdir /container-init.d \ + && chown ipfs:users /container-init.d + # Expose the fs-repo as a volume. # start_ipfs initializes an fs-repo if none is mounted. # Important this happens after the USER directive so permissions are correct. diff --git a/bin/container_daemon b/bin/container_daemon index 8fe429036a73..ae8725be5dba 100755 --- a/bin/container_daemon +++ b/bin/container_daemon @@ -1,9 +1,10 @@ #!/bin/sh set -e + user=ipfs repo="$IPFS_PATH" -if [ `id -u` -eq 0 ]; then +if [ "$(id -u)" -eq 0 ]; then echo "Changing user to $user" # ensure folder is writable su-exec "$user" test -w "$repo" || chown -R -- "$user" "$repo" @@ -14,14 +15,11 @@ fi # 2nd invocation with regular user ipfs version + if [ -e "$repo/config" ]; then echo "Found IPFS fs-repo at $repo" else - case "$IPFS_PROFILE" in - "") INIT_ARGS="" ;; - *) INIT_ARGS="--profile=$IPFS_PROFILE" ;; - esac - ipfs init $INIT_ARGS + ipfs init ${IPFS_PROFILE:+"--profile=$IPFS_PROFILE"} ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001 ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080 @@ -31,9 +29,9 @@ else SWARM_KEY_PERM=0400 # Create a swarm key from a given environment variable - if [ ! -z "$IPFS_SWARM_KEY" ] ; then + if [ -n "$IPFS_SWARM_KEY" ] ; then echo "Copying swarm key from variable..." - echo -e "$IPFS_SWARM_KEY" >"$SWARM_KEY_FILE" || exit 1 + printf "%s\n" "$IPFS_SWARM_KEY" >"$SWARM_KEY_FILE" || exit 1 chmod $SWARM_KEY_PERM "$SWARM_KEY_FILE" fi @@ -43,14 +41,15 @@ else # Check during initialization if a swarm key was provided and # copy it to the ipfs directory with the right permissions # WARNING: This will replace the swarm key if it exists - if [ ! -z "$IPFS_SWARM_KEY_FILE" ] ; then + if [ -n "$IPFS_SWARM_KEY_FILE" ] ; then echo "Copying swarm key from file..." install -m $SWARM_KEY_PERM "$IPFS_SWARM_KEY_FILE" "$SWARM_KEY_FILE" || exit 1 fi # Unset the swarm key file variable unset IPFS_SWARM_KEY_FILE - fi +find /container-init.d -maxdepth 1 -type f -iname '*.sh' -print0 | sort -z | xargs -n 1 -0 -r container_init_run + exec ipfs "$@" diff --git a/bin/container_init_run b/bin/container_init_run new file mode 100755 index 000000000000..9d20660ccfd7 --- /dev/null +++ b/bin/container_init_run @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# used by the container startup script for running initialization scripts + +script="$1" +if [ -x "$script" ] ; then + printf "Executing '%s'...\n" "$script" + "$script" +else + printf "Sourcing '%s'...\n" "$script" + . "$script" +fi diff --git a/test/ipfs-test-lib.sh b/test/ipfs-test-lib.sh index 960cf7caa868..eabf17020d22 100644 --- a/test/ipfs-test-lib.sh +++ b/test/ipfs-test-lib.sh @@ -70,6 +70,16 @@ docker_stop() { docker stop "$1" } +# This takes a docker ID as argument +docker_rm() { + docker rm -f -v "$1" > /dev/null +} + +# This takes a docker image name as argument +docker_rmi() { + docker rmi -f "$1" > /dev/null +} + # Test whether all the expected lines are included in a file. The file # can have extra lines. # diff --git a/test/sharness/t0300-docker-image.sh b/test/sharness/t0300-docker-image.sh index 2a25dd28406a..a3a802b287fb 100755 --- a/test/sharness/t0300-docker-image.sh +++ b/test/sharness/t0300-docker-image.sh @@ -29,7 +29,7 @@ TEST_TESTS_DIR=$(dirname "$TEST_SCRIPTS_DIR") APP_ROOT_DIR=$(dirname "$TEST_TESTS_DIR") test_expect_success "docker image build succeeds" ' - docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" >build-actual || + docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" | tee build-actual || test_fsh echo "TEST_TESTS_DIR: $TEST_TESTS_DIR" || test_fsh echo "APP_ROOT_DIR : $APP_ROOT_DIR" || test_fsh cat build-actual @@ -41,8 +41,18 @@ test_expect_success "docker image build output looks good" ' test_fsh cat build-actual ' +test_expect_success "write init scripts" ' + echo "ipfs config Foo Bar" > 001.sh && + echo "ipfs config Baz Qux" > 002.sh && + chmod +x 002.sh +' + test_expect_success "docker image runs" ' - DOC_ID=$(docker run -d -p 127.0.0.1:5001:5001 -p 127.0.0.1:8080:8080 "$IMAGE_ID") + DOC_ID=$(docker run -d \ + -p 127.0.0.1:5001:5001 -p 127.0.0.1:8080:8080 \ + -v "$PWD/001.sh":/container-init.d/001.sh \ + -v "$PWD/002.sh":/container-init.d/002.sh \ + "$IMAGE_ID") ' test_expect_success "docker container gateway is up" ' @@ -53,6 +63,21 @@ test_expect_success "docker container API is up" ' pollEndpoint -host=/ip4/127.0.0.1/tcp/5001 -http-url http://localhost:5001/version -v -tries 30 -tout 1s ' +test_expect_success "check that init scripts were run correctly and in the correct order" " + echo -e \"Sourcing '/container-init.d/001.sh'...\nExecuting '/container-init.d/002.sh'...\" > expected && + docker logs $DOC_ID 2>/dev/null | grep -e 001.sh -e 002.sh > actual && + test_cmp actual expected +" + +test_expect_success "check that init script configs were applied" ' + echo Bar > expected && + docker exec "$DOC_ID" ipfs config Foo > actual && + test_cmp actual expected && + echo Qux > expected && + docker exec "$DOC_ID" ipfs config Baz > actual && + test_cmp actual expected +' + test_expect_success "simple ipfs add/cat can be run in docker container" ' expected="Hello Worlds" && HASH=$(docker_exec "$DOC_ID" "echo $(cat expected) | ipfs add | cut -d' ' -f2") && @@ -74,5 +99,7 @@ test_expect_success "stop docker container" ' docker_stop "$DOC_ID" ' +docker_rm "$DOC_ID" +docker_rmi "$IMAGE_ID" test_done diff --git a/test/sharness/t0301-docker-migrate.sh b/test/sharness/t0301-docker-migrate.sh index 4fb9ab155e4b..3f7d32f214b1 100755 --- a/test/sharness/t0301-docker-migrate.sh +++ b/test/sharness/t0301-docker-migrate.sh @@ -77,5 +77,7 @@ test_expect_success "correct version was requested" ' grep "/fs-repo-6-to-7/v1.1.1/fs-repo-6-to-7_v1.1.1_linux-amd64.tar.gz" dist_serv_out > /dev/null ' +docker_rm "$DOC_ID" +docker_rmi "$IMAGE_ID" test_done