From 7da5e4aa0b856215d73bb71302f25135987c17fd Mon Sep 17 00:00:00 2001 From: Phillip Mienk Date: Sun, 5 Jan 2025 01:40:30 -0800 Subject: [PATCH 1/2] Update developer_setup.sh to support dockerization, add docker image build script. --- docker/{bs.Dockerfile => bs-linux.Dockerfile} | 0 docker/bs-linux.sh | 172 ++++++++++++++++++ templates/gsl.developer_setup.sh | 34 ++-- 3 files changed, 191 insertions(+), 15 deletions(-) rename docker/{bs.Dockerfile => bs-linux.Dockerfile} (100%) create mode 100755 docker/bs-linux.sh diff --git a/docker/bs.Dockerfile b/docker/bs-linux.Dockerfile similarity index 100% rename from docker/bs.Dockerfile rename to docker/bs-linux.Dockerfile diff --git a/docker/bs-linux.sh b/docker/bs-linux.sh new file mode 100755 index 0000000..b8bd07f --- /dev/null +++ b/docker/bs-linux.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +set -e + +display_message() +{ + printf "%s\n" "$@" +} + +display_error() +{ + >&2 printf "%s\n" "$@" +} + +display_help() +{ + display_message "Usage: ./bs-linux.sh [OPTION]..." + display_message "Manage the generation of a docker image of bitcoin-server (bs)." + display_message "Script options:" + display_message " --build-dir= Directory for building docker image" + display_message " --source= xml file for gsl generation." + display_message " --tag= git tag to utilize with source instructions." + display_message "" +} + +fatal_error() +{ + display_error "$@" + display_error "" + display_help + exit 1 +} + +display_state() +{ + display_message "Parameters:" + display_message " DIR_BUILD : ${DIR_BUILD}" + display_message " SOURCE : ${SOURCE}" + display_message " TAG : ${TAG}" + display_message "Deduced:" + display_message " DIR_BUILD_PROJ : ${DIR_BUILD_PROJ}" + display_message " VERSION : ${VERSION}" +} + +dispatch_help() +{ + if [[ ${DISPLAY_HELP} ]]; then + display_help + exit 0 + fi +} + +initialize_environment() +{ + # https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script + local DIR_SCRIPT=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + + # initialize DIR_BUILD_PROJ + pushd "${DIR_SCRIPT}/.." + DIR_BUILD_PROJ="$(pwd)" + popd + + if [ -f ${DIR_BUILD_PROJ}/${SOURCE} ]; then + SOURCE_VERSION=$(grep ' must be a valid filename in the expected path." + fi + + # rationalize intended version + if [ -z ${TAG} ]; then + VERSION="${SOURCE_VERSION}" + else + if [[ "${TAG}" =~ ^v.* ]]; then + VERSION=$(echo "${TAG}" | sed -n s/v//p) + else + VERSION="${TAG}" + fi + fi + + # cleanup build directory + if [ -d ${DIR_BUILD} ]; then + display_message "Directory '${DIR_BUILD}' found, emptying..." + pushd ${DIR_BUILD} + rm -rf Dockerfile developer_setup.sh src/ + mkdir -p "${DIR_BUILD}/src" + popd + else + display_message "Directory '${DIR_BUILD}' not found, building..." + mkdir -p "${DIR_BUILD}/src" + fi +} + +validate_parameterization() +{ + if [ -z ${DIR_BUILD} ]; then + fatal_error " --build-dir= required." + fi + + if [ -z ${SOURCE} ]; then + fatal_error " --source= required." + fi +} + +parse_command_line_options() +{ + for OPTION in "$@"; do + case ${OPTION} in + # Specific + (--build-dir=*) DIR_BUILD="${OPTION#*=}";; + (--source=*) SOURCE="${OPTION#*=}";; + (--tag=*) TAG="${OPTION#*=}";; + + # Standard + (--help) DISPLAY_HELP="yes";; + esac + done +} + +generate_instructions() +{ + display_message "Generate developer_setup.sh..." + + # create developer_setup.sh + pushd ${DIR_BUILD_PROJ} + eval gsl -q -script:templates/gsl.developer_setup.sh ${SOURCE} + chmod +x output/libbitcoin-*/developer_setup.sh + popd +} + +initialize_build_directory() +{ + display_message "Initialize build directory contents..." + cp ${DIR_BUILD_PROJ}/output/libbitcoin-server/developer_setup.sh ${DIR_BUILD} + + pushd ${DIR_BUILD} + + local BUILD_TAG_PARAM="" + if [ -z ${TAG} ]; then + BUILD_TAG_PARAM="" + else + BUILD_TAG_PARAM="--build-tag=${TAG}" + fi + + ./developer_setup.sh ${BUILD_TAG_PARAM} \ + --build-sync-only \ + --build-src-dir="${DIR_BUILD}/src" \ + --build-target=all + + popd +} + +dockerize() +{ + pushd ${DIR_BUILD} + display_message "----------------------------------------------------------------------" + display_message "docker build : libbitcoin/bitcoin-server:${VERSION}" + display_message "----------------------------------------------------------------------" + docker build -t libbitcoin/bitcoin-server:${VERSION} -f ${DIR_BUILD_PROJ}/docker/bs-linux.Dockerfile . + popd +} + +parse_command_line_options "$@" +dispatch_help +validate_parameterization +initialize_environment +display_state +generate_instructions +initialize_build_directory +dockerize diff --git a/templates/gsl.developer_setup.sh b/templates/gsl.developer_setup.sh index 64781df..976195b 100644 --- a/templates/gsl.developer_setup.sh +++ b/templates/gsl.developer_setup.sh @@ -106,9 +106,8 @@ BUILD_TARGET="unknown" . heading2("Process script specific options.") handle_custom_options() { - if [[ ($BUILD_MODE != "sync") && ($BUILD_MODE != "configure") && ($BUILD_MODE != "build") ]]; then - display_error "Unsupported build-mode: $BUILD_MODE" - display_error "Supported values are: sync, configure, build" + if [[ ! ($BUILD_SRC_DIR) ]]; then + display_error "Missing build-src-dir required." display_error "" display_help exit 1 @@ -122,18 +121,21 @@ handle_custom_options() exit 1 fi - if [[ ! ($BUILD_SRC_DIR) ]]; then - display_error "Missing build-src-dir required." - display_error "" - display_help - exit 1 - fi + if [[ ! ($SYNC_ONLY) ]]; then + if [[ ($BUILD_MODE != "sync") && ($BUILD_MODE != "configure") && ($BUILD_MODE != "build") ]]; then + display_error "Unsupported build-mode: $BUILD_MODE" + display_error "Supported values are: sync, configure, build" + display_error "" + display_help + exit 1 + fi - if [[ ! ($BUILD_OBJ_DIR) ]]; then - display_error "Missing build-obj-dir required." - display_error "" - display_help - exit 1 + if [[ ! ($BUILD_OBJ_DIR) ]]; then + display_error "Missing build-obj-dir required." + display_error "" + display_help + exit 1 + fi fi if [[ $BUILD_TAG ]]; then @@ -498,7 +500,9 @@ else display_configuration push_directory "$BUILD_SRC_DIR" initialize_git - initialize_object_directory + if [[ ! ($SYNC_ONLY) ]]; then + initialize_object_directory + fi create_local_copies if [[ $SYNC_ONLY ]]; then display_message "Skipping build due to --sync-only." From 6c393c7ff3580c3d48ee263f42e7e465d609e7bd Mon Sep 17 00:00:00 2001 From: Phillip Mienk Date: Mon, 6 Jan 2025 20:59:49 -0800 Subject: [PATCH 2/2] Extend docker container. --- docker/README.md | 45 ++++++++++++++ docker/bs-linux-startup.sh | 72 ++++++++++++++++++++++ docker/bs-linux.Dockerfile | 13 ++-- docker/bs-linux.env.in | 4 ++ docker/bs-linux.sh | 118 +++++++++++++++++++++++-------------- docker/bs-linux.yml | 25 ++++++++ 6 files changed, 229 insertions(+), 48 deletions(-) create mode 100644 docker/README.md create mode 100755 docker/bs-linux-startup.sh create mode 100644 docker/bs-linux.env.in create mode 100644 docker/bs-linux.yml diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..27fae1e --- /dev/null +++ b/docker/README.md @@ -0,0 +1,45 @@ +# dockerized libbitcoin + +## bitcoin server + +A linux image can be generated with the script below. Currently, this is only tested against the `version3` branch with or without the `v3.8.0` tag. + +### linux + +The following outlines usage of the `bs-linux` artifacts. +It is of note that the generated image includes a `startup.sh` script which conditionally initializes the blockchain database if not found. + +#### Initialization + +The following populates a provided image build directory: + +``` +./bs-linux.sh --build-dir= --source= --init-only +``` + +The reader then needs to edit the generated `bs-linux.env` to provide storage paths for volume mounting. +Additionally, the `STORAGE_BITCOIN_CONF` path should contain a `bs.cfg` containing a `directory` field for `[database]` which has some depth from the volume mount point, due to `bs` implementation attempts to create the blockchain containing directory. + +#### Image construction + +The image construction can then continue via an other invocatio with the following parameters: + +``` +./bs-linux.sh --build-dir= --source= --build-only +``` + +#### Container management + +The file `bs-linux.yml` is provided in the image build directory in order to allow `docker compose` to control container construction and destruction. +The reader is free to translate this file and the `bs-linux.env` into `docker` commands derived from the declative `yaml`. +The timeout parameter should be noted: `bs` has been known to take an extended period of time to write memory to disk and `SIGKILL` will likely corrupt the database. + +##### Instantiating container +``` +docker compose --env-file bs-linux.env --file bs-linux.yml up -t 3600 -d +``` + +##### Terminating container +``` +docker compose --env-file bs-linux.env --file bs-linux.yml down -t 3600 -v +``` diff --git a/docker/bs-linux-startup.sh b/docker/bs-linux-startup.sh new file mode 100755 index 0000000..2c0603b --- /dev/null +++ b/docker/bs-linux-startup.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +set -ex + +SCRIPT_IDENTITY=$(basename "$0") + +display_message() +{ + printf "%s\n" "$@" +} + +display_error() +{ + >&2 printf "%s\n" "$@" +} + +display_help() +{ + display_message "Usage: ./${SCRIPT_IDENTITY} [OPTION]..." + display_message "Docker instance startup script." + display_message "Script options:" + display_message " --unconditional-init Force database reset." + display_message "" +} + +fatal_error() +{ + display_error "$@" + display_error "" + display_help + exit 1 +} + +dispatch_help() +{ + if [[ ${DISPLAY_HELP} ]]; then + display_help + exit 0 + fi +} + +parse_command_line_options() +{ + for OPTION in "$@"; do + case ${OPTION} in + # Specific + (--unconditional-init) INIT_UNCONDITIONAL="yes";; + + # Standard + (--help) DISPLAY_HELP="yes";; + esac + done +} + +initialize() +{ + if [[ -z "$( ls -A blockchain )" ]]; then + ./bs -c conf/bs.cfg --initchain + elif [[ $INIT_UNCONDITIONAL ]]; then + ./bs -c conf/bs.cfg --initchain + fi +} + +execute_service() +{ + ./bs -c conf/bs.cfg +} + +parse_command_line_options "$@" +dispatch_help +initialize +execute_service diff --git a/docker/bs-linux.Dockerfile b/docker/bs-linux.Dockerfile index d9390c5..5fc323e 100644 --- a/docker/bs-linux.Dockerfile +++ b/docker/bs-linux.Dockerfile @@ -30,8 +30,13 @@ RUN /build/developer_setup.sh \ FROM alpine:latest AS runtime -COPY --from=build /build/prefix/bin/bs /bitcoin +ENV BUILD_DEPS="build-base linux-headers gcc make autoconf automake libtool pkgconf git wget bash" + +RUN apk update && \ + apk add --update ${BUILD_DEPS} +COPY --from=build /build/prefix/bin/bs /bitcoin/bs +COPY bs-linux-startup.sh /bitcoin/startup.sh # Bitcoin P2P EXPOSE 8333/tcp EXPOSE 8333/udp @@ -52,6 +57,6 @@ EXPOSE 9093/tcp EXPOSE 9084/tcp EXPOSE 9094/tcp -VOLUME ["/bitcoin/data", "/bitcoin/conf"] -ENTRYPOINT ["/bitcoin/bs"] -CMD ["-c", "/bitcoin/conf/bs.cfg", "-i", "/bitcoin/data"] +WORKDIR /bitcoin +VOLUME ["/bitcoin/blockchain", "/bitcoin/conf"] +CMD [ "/bitcoin/startup.sh" ] diff --git a/docker/bs-linux.env.in b/docker/bs-linux.env.in new file mode 100644 index 0000000..3501995 --- /dev/null +++ b/docker/bs-linux.env.in @@ -0,0 +1,4 @@ +COMPOSE_PROJECT_NAME=bitcoin +VERSION_BITCOIN_SERVER=%version% +STORAGE_BITCOIN_CONF=%SET_ME% +STORAGE_BITCOIN_DATA=%SET_ME% diff --git a/docker/bs-linux.sh b/docker/bs-linux.sh index b8bd07f..f8a694c 100755 --- a/docker/bs-linux.sh +++ b/docker/bs-linux.sh @@ -2,6 +2,8 @@ set -e +SCRIPT_IDENTITY=$(basename "$0") + display_message() { printf "%s\n" "$@" @@ -12,23 +14,41 @@ display_error() >&2 printf "%s\n" "$@" } +fatal_error() +{ + display_error "$@" + display_error "" + display_help + exit 1 +} + display_help() { - display_message "Usage: ./bs-linux.sh [OPTION]..." + display_message "Usage: ./${SCRIPT_IDENTITY} [OPTION]..." display_message "Manage the generation of a docker image of bitcoin-server (bs)." display_message "Script options:" display_message " --build-dir= Directory for building docker image" display_message " --source= xml file for gsl generation." display_message " --tag= git tag to utilize with source instructions." + display_message " --build-only docker build without reinitializing build-dir." + display_message " --init-only Initialize build-dir for docker image building." display_message "" } -fatal_error() +parse_command_line_options() { - display_error "$@" - display_error "" - display_help - exit 1 + for OPTION in "$@"; do + case ${OPTION} in + # Specific + (--build-dir=*) DIR_BUILD="${OPTION#*=}";; + (--source=*) SOURCE="${OPTION#*=}";; + (--tag=*) TAG="${OPTION#*=}";; + (--build-only) BUILD_ONLY="yes";; + (--init-only) INIT_ONLY="yes";; + # Standard + (--help) DISPLAY_HELP="yes";; + esac + done } display_state() @@ -37,6 +57,8 @@ display_state() display_message " DIR_BUILD : ${DIR_BUILD}" display_message " SOURCE : ${SOURCE}" display_message " TAG : ${TAG}" + display_message " BUILD_ONLY : ${BUILD_ONLY}" + display_message " INIT_ONLY : ${INIT_ONLY}" display_message "Deduced:" display_message " DIR_BUILD_PROJ : ${DIR_BUILD_PROJ}" display_message " VERSION : ${VERSION}" @@ -50,6 +72,17 @@ dispatch_help() fi } +validate_parameterization() +{ + if [ -z ${DIR_BUILD} ]; then + fatal_error " --build-dir= required." + fi + + if [ -z ${SOURCE} ]; then + fatal_error " --source= required." + fi +} + initialize_environment() { # https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script @@ -79,12 +112,33 @@ initialize_environment() VERSION="${TAG}" fi fi +} +generate_instructions() +{ + display_message "Generate developer_setup.sh..." + + # create developer_setup.sh + pushd ${DIR_BUILD_PROJ} + eval gsl -q -script:templates/gsl.developer_setup.sh ${SOURCE} + chmod +x output/libbitcoin-*/developer_setup.sh + popd +} + +emit_compose() +{ + cp ${DIR_BUILD_PROJ}/docker/bs-linux.yml ${DIR_BUILD}/bs-linux.yml + sed "s/%version%/${VERSION}/" \ + ${DIR_BUILD_PROJ}/docker/bs-linux.env.in > ${DIR_BUILD}/bs-linux.env +} + +clean_build_directory() +{ # cleanup build directory if [ -d ${DIR_BUILD} ]; then display_message "Directory '${DIR_BUILD}' found, emptying..." pushd ${DIR_BUILD} - rm -rf Dockerfile developer_setup.sh src/ + rm -rf bs-linux-startup.sh developer_setup.sh src/ mkdir -p "${DIR_BUILD}/src" popd else @@ -93,47 +147,18 @@ initialize_environment() fi } -validate_parameterization() +initialize_build_directory() { - if [ -z ${DIR_BUILD} ]; then - fatal_error " --build-dir= required." + if [[ $BUILD_ONLY ]]; then + return 0 fi - if [ -z ${SOURCE} ]; then - fatal_error " --source= required." - fi -} - -parse_command_line_options() -{ - for OPTION in "$@"; do - case ${OPTION} in - # Specific - (--build-dir=*) DIR_BUILD="${OPTION#*=}";; - (--source=*) SOURCE="${OPTION#*=}";; - (--tag=*) TAG="${OPTION#*=}";; - - # Standard - (--help) DISPLAY_HELP="yes";; - esac - done -} - -generate_instructions() -{ - display_message "Generate developer_setup.sh..." + clean_build_directory + generate_instructions - # create developer_setup.sh - pushd ${DIR_BUILD_PROJ} - eval gsl -q -script:templates/gsl.developer_setup.sh ${SOURCE} - chmod +x output/libbitcoin-*/developer_setup.sh - popd -} - -initialize_build_directory() -{ display_message "Initialize build directory contents..." cp ${DIR_BUILD_PROJ}/output/libbitcoin-server/developer_setup.sh ${DIR_BUILD} + cp ${DIR_BUILD_PROJ}/docker/bs-linux-startup.sh ${DIR_BUILD} pushd ${DIR_BUILD} @@ -150,10 +175,16 @@ initialize_build_directory() --build-target=all popd + + emit_compose } dockerize() { + if [[ $INIT_ONLY ]]; then + return 0 + fi + pushd ${DIR_BUILD} display_message "----------------------------------------------------------------------" display_message "docker build : libbitcoin/bitcoin-server:${VERSION}" @@ -166,7 +197,6 @@ parse_command_line_options "$@" dispatch_help validate_parameterization initialize_environment -display_state -generate_instructions initialize_build_directory +display_state dockerize diff --git a/docker/bs-linux.yml b/docker/bs-linux.yml new file mode 100644 index 0000000..b1ab8aa --- /dev/null +++ b/docker/bs-linux.yml @@ -0,0 +1,25 @@ +networks: + net: + +services: + bitcoin-server: + container_name: bitcoin-server + hostname: bitcoin-server + image: libbitcoin/bitcoin-server:${VERSION_BITCOIN_SERVER} + # restart: unless-stopped + ports: + - 8333:8333/tcp + - 8333:8333/udp + - 9081:9081/tcp + - 9082:9082/tcp + - 9083:9083/tcp + - 9084:9084/tcp + - 9091:9091/tcp + - 9092:9092/tcp + - 9093:9093/tcp + - 9094:9094/tcp + volumes: + - ${STORAGE_BITCOIN_DATA}:/bitcoin/blockchain + - ${STORAGE_BITCOIN_CONF}:/bitcoin/conf + networks: + - net