From f053135f686b873de90539343c1c3b1ccfe98e61 Mon Sep 17 00:00:00 2001 From: Slava <20563034+veaceslavdoina@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:46:49 +0300 Subject: [PATCH] feat: add docker auto-builds (#461) https://github.com/codex-storage/nim-codex/issues/412 --- .github/workflows/docker.yml | 231 ++++++++++++++++++++--------------- docker/README.md | 93 ++++++-------- docker/codex.Dockerfile | 39 ++++-- docker/docker-compose.yaml | 64 ++++++---- docker/docker-entrypoint.sh | 5 + docker/startCodex.sh | 150 ----------------------- 6 files changed, 243 insertions(+), 339 deletions(-) create mode 100644 docker/docker-entrypoint.sh delete mode 100644 docker/startCodex.sh diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ad31c3c6..5ab109be 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,125 +1,154 @@ -name: docker +name: Docker + on: push: branches: - - "main" + - master tags: - "v*.*.*" + paths-ignore: + - '**/*.md' + - '.gitignore' + - '.github/**' + - '!.github/workflows/docker.yml' + - 'docker/**' + - '!docker/codex.Dockerfile' + - '!docker/docker-entrypoint.sh' workflow_dispatch: + +env: + DOCKER_FILE: docker/codex.Dockerfile + DOCKER_REPO: codexstorage/nim-codex + MAKE_PARALLEL: 4 + + jobs: - docker-amd64: + # Build platform specific image + build: + strategy: + fail-fast: true + matrix: + target: + - os: linux + arch: amd64 + - os: linux + arch: arm64 + include: + - target: + os: linux + arch: amd64 + builder: ubuntu-22.04 + - target: + os: linux + arch: arm64 + builder: buildjet-4vcpu-ubuntu-2204-arm + + name: Build ${{ matrix.target.os }}/${{ matrix.target.arch }} + runs-on: ${{ matrix.builder }} + outputs: + tags-linux-amd64: ${{ steps.tags.outputs.tags-linux-amd64 }} + tags-linux-arm64: ${{ steps.tags.outputs.tags-linux-arm64 }} + env: + PLATFORM: ${{ format('{0}/{1}', 'linux', matrix.target.arch) }} + SUFFIX: ${{ format('{0}-{1}', 'linux', matrix.target.arch) }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Docker - Meta + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.DOCKER_REPO }} + flavor: | + latest=false + tags: | + type=semver,pattern={{version}},suffix=-${{ env.SUFFIX }} + type=sha,suffix=-${{ env.SUFFIX }},enable=${{ !startsWith(github.ref, 'refs/tags/') }} + + - name: Docker - Set tags output + id: tags + run: | + if [[ '${{ matrix.target.os }}' == 'linux' && '${{ matrix.target.arch }}' == 'amd64' ]]; then + echo "tags-linux-amd64=${{ steps.meta.outputs.tags }}" >> "$GITHUB_OUTPUT" + elif [[ '${{ matrix.target.os }}' == 'linux' && '${{ matrix.target.arch }}' == 'arm64' ]]; then + echo "tags-linux-arm64=${{ steps.meta.outputs.tags }}" >> "$GITHUB_OUTPUT" + fi + + - name: Docker - Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker - Build and export to Docker + uses: docker/build-push-action@v4 + with: + context: . + file: ${{ env.DOCKER_FILE }} + platforms: ${{ env.PLATFORM }} + build-args: | + MAKE_PARALLEL=${{ env.MAKE_PARALLEL }} + load: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Docker - Minify image + uses: kitabisa/docker-slim-action@v1 + id: slim + env: + DSLIM_HTTP_PROBE: false + with: + target: ${{ steps.meta.outputs.tags }} + overwrite: true + + - name: Docker - Show slim report + run: echo "${REPORT}" | jq -r + env: + REPORT: ${{ steps.slim.outputs.report }} + + - name: Docker - Push to Docker registry + uses: docker/build-push-action@v4 + with: + context: . + file: ${{ env.DOCKER_FILE }} + platforms: ${{ env.PLATFORM }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # Publish single image + publish: + name: Push single image runs-on: ubuntu-latest + needs: build steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Docker meta + - name: Docker - Meta id: meta uses: docker/metadata-action@v4 with: - images: thatbenbierens/nim-codex-amd64 + images: ${{ env.DOCKER_REPO }} tags: | type=semver,pattern={{version}} - type=sha + type=sha,enable=${{ !startsWith(github.ref, 'refs/tags/') }} - - name: Login to Docker Hub - if: github.event_name != 'pull_request' + - name: Docker - Set tags + run: | + # Transform multi-line tags in to the comma-seperated + TAGS=$(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ',' | awk '{gsub(/,$/,"");}1') + echo "TAGS=${TAGS}" >>$GITHUB_ENV + + - name: Docker - Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and export to Docker - id: build - uses: docker/build-push-action@v4 + - name: Docker - Create and push manifest images + uses: Noelware/docker-manifest-action@master with: - context: . - file: docker/codex.Dockerfile - platforms: linux/amd64 - load: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Minify docker image - uses: kitabisa/docker-slim-action@v1 - env: - DSLIM_HTTP_PROBE: false - with: - target: ${{ steps.meta.outputs.tags }} - overwrite: true - - - name: Show slim report - run: echo "${{ steps.slim.outputs.report }}" - - - name: Push to Docker registry - if: github.event_name != 'pull_request' - id: push - uses: docker/build-push-action@v4 - with: - context: . - file: docker/codex.Dockerfile - platforms: linux/amd64 + inputs: ${{ env.TAGS }} + images: ${{ needs.build.outputs.tags-linux-amd64 }},${{ needs.build.outputs.tags-linux-arm64 }} push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - docker-arm64: - runs-on: buildjet-4vcpu-ubuntu-2204-arm - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - with: - images: thatbenbierens/nim-codex-arm64 - tags: | - type=semver,pattern={{version}} - type=sha - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Login to Docker Hub - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and export to Docker - id: build - uses: docker/build-push-action@v4 - with: - context: . - file: docker/codex.Dockerfile - platforms: linux/arm64 - load: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Minify docker image - uses: kitabisa/docker-slim-action@v1 - env: - DSLIM_HTTP_PROBE: false - with: - target: ${{ steps.meta.outputs.tags }} - overwrite: true - - - name: Show slim report - run: echo "${{ steps.slim.outputs.report }}" - - - name: Push to Docker registry - if: github.event_name != 'pull_request' - id: push - uses: docker/build-push-action@v4 - with: - context: . - file: docker/codex.Dockerfile - platforms: linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/docker/README.md b/docker/README.md index 603c6e39..3366328e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,64 +1,51 @@ # Codex Docker Image -Build and run using the example docker-compose file: -`docker-compose up -d` + Codex provides pre-built docker images and they are stored in the [codexstorage/nim-codex](https://hub.docker.com/repository/docker/codexstorage/nim-codex) repository. -Stop and retain image and volume data: -`docker-compose down` -Stop and delete image and volume data: -`docker-compose down --rmi all -v` -`rm -R hostdatadir` +## Run -# Environment variables -Codex docker image supports the following environment variables: -- LISTEN_ADDRS(*) -- API_BINDADDR(*) -- DATA_DIR(*) -- LOG_LEVEL -- METRICS_ADDR -- METRICS_PORT -- NAT_IP -- API_PORT -- DISC_IP -- DISC_PORT -- NET_PRIVKEY -- BOOTSTRAP_SPR -- MAX_PEERS -- AGENT_STRING -- STORAGE_QUOTA -- BLOCK_TTL -- CACHE_SIZE -- ETH_PROVIDER -- ETH_ACCOUNT -- ETH_DEPLOYMENT -- SIMULATE_PROOF_FAILURES -- VALIDATOR -- PERSISTENCE -- CODEX_NODENAME(†) + We can run Codex Docker image using CLI + ```shell + # Default run + docker run --rm codexstorage/nim-codex -(*) These variables have default values in the docker image that are different from Codex's standard default values. + # Mount local datadir + docker run -v ./datadir:/datadir --rm codexstorage/nim-codex codex --data-dir=/datadir + ``` -(†) CODEX_NODENAME is used for logging purposes only in the docker image + And Docker Compose + ```shell + # Run in detached mode + docker-compose up -d + ``` -All environment variables are optional and will default to Codex's CLI default values. -# Constants -Codex CLI arguments 'data-dir', 'listen-addrs', and 'api-bindaddr' cannot be configured. They are set to values required for docker in case of bind addresses. In the case of 'data-dir', the value is set to `/datadir`. It is important that you map this folder to a host volume in your container configuration. See docker-compose.yaml for examples. +## Arguments -# Useful -Connect nodes with the `/connect` endpoint. -To get the IP address of a container within a network: -Find container Id: `docker ps` -Open terminal in container: `docker exec -it sh` -Get IP addresses: `ifconfig` + Docker image is based on the [codex.Dockerfile](codex.Dockerfile) and there is + ``` + ENTRYPOINT ["/docker-entrypoint.sh"] + CMD ["codex"] + ``` -# Slim -1. Build the image using `docker build -t status-im/codexsetup:latest -f codex.Dockerfile ..` -2. The docker image can then be minifed using [slim](https://github.com/slimtoolkit/slim). Install slim on your path and then run: -```shell -slim # brings up interactive prompt ->>> build --target status-im/codexsetup --http-probe-off true -``` -3. This should output an image with name `status-im/codexsetup.slim` -4. We can then bring up the image using `docker-compose up -d`. \ No newline at end of file + It means that at the image run it will just run `codex` application without any arguments and we can pass them as a regular arguments, by overriding command + ```shell + docker run codexstorage/nim-codex codex --api-bindaddr=0.0.0.0 + ``` + + +## Environment variables + + We can configure Codex using [Environment variables](../README#environment-variables) and [docker-compose.yaml](docker-compose.yaml) file can be useful as an example. + + +## Slim + 1. Build the image using `docker build -t status-im/codexsetup:latest -f codex.Dockerfile ..` + 2. The docker image can then be minified using [slim](https://github.com/slimtoolkit/slim). Install slim on your path and then run: + ```shell + slim # brings up interactive prompt + >>> build --target status-im/codexsetup --http-probe-off true + ``` + 3. This should output an image with name `status-im/codexsetup.slim` + 4. We can then bring up the image using `docker-compose up -d`. diff --git a/docker/codex.Dockerfile b/docker/codex.Dockerfile index 1c93d615..bd8b3bcf 100644 --- a/docker/codex.Dockerfile +++ b/docker/codex.Dockerfile @@ -1,18 +1,35 @@ -FROM ubuntu:lunar-20230415 AS builder +# Variables +ARG BUILDER=ubuntu:lunar-20230415 +ARG IMAGE=${BUILDER} +ARG BUILD_HOME=/src +ARG MAKE_PARALLEL=${MAKE_PARALLEL:-4} +ARG MAKE_PARAMS=${MAKE_PARAMS:-NIM_PARAMS="-d:disableMarchNative"} +ARG APP_HOME=/codex + +# Build +FROM ${BUILDER} AS builder +ARG BUILD_HOME +ARG MAKE_PARALLEL +ARG MAKE_PARAMS + RUN apt-get update && apt-get install -y git cmake curl make bash lcov build-essential nim RUN echo 'export NIMBLE_DIR="${HOME}/.nimble"' >> "${HOME}/.bash_env" RUN echo 'export PATH="${NIMBLE_DIR}/bin:${PATH}"' >> "${HOME}/.bash_env" -WORKDIR /src +WORKDIR ${BUILD_HOME} COPY . . RUN make clean -RUN make -j4 update -RUN make -j4 NIM_PARAMS="-d:disableMarchNative -d:codex_enable_api_debug_peers=true" +RUN make -j ${MAKE_PARALLEL} update +RUN make -j ${MAKE_PARALLEL} ${MAKE_PARAMS} -FROM ubuntu:lunar-20230415 -WORKDIR /root -RUN apt-get update && apt-get install -y libgomp1 bash net-tools -COPY --from=builder /src/build/codex ./ -COPY --from=builder /src/docker/startCodex.sh ./ -RUN chmod +x ./startCodex.sh -CMD ["/bin/bash", "-l", "-c", "./startCodex.sh"] +# Create +FROM ${IMAGE} +ARG BUILD_HOME +ARG APP_HOME + +WORKDIR ${APP_HOME} +COPY --from=builder ${BUILD_HOME}/build/codex /usr/local/bin +COPY --chmod=0755 docker/docker-entrypoint.sh / +RUN apt-get update && apt-get install -y libgomp1 bash && rm -rf /var/lib/apt/lists/* +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["codex"] diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 643682a2..4ddf120c 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -1,27 +1,43 @@ services: codex-node1: - image: status-im/codexsetup.slim:latest - ports: - - 8080:8080 - # Available environment variables: + image: codexstorage/nim-codex:sha-82b0399 environment: - - LOG_LEVEL=TRACE - - METRICS_ADDR=0.0.0.0 - - METRICS_PORT=9090 - - NAT_IP=2.3.4.5 - - API_PORT=8080 - - DISC_IP=3.4.5.6 - - DISC_PORT=8765 - - NET_PRIVKEY=privkey - - BOOTSTRAP_SPR=bootstrap_record - - MAX_PEERS=123 - - AGENT_STRING=agent_string - - STORAGE_QUOTA=123456789 - - BLOCK_TTL=23456 - - CACHE_SIZE=6543 - - ETH_PROVIDER=eth - - ETH_ACCOUNT=account - - ETH_MARKETPLACE_ADDRESS=0x59b670e9fA9D0A427751Af201D676719a970857b - - SIMULATE_PROOF_FAILURES=2 - - + - CODEX_LOG_LEVEL=${CODEX_LOG_LEVEL:-TRACE} + - CODEX_METRICS=${CODEX_METRICS:-false} + - CODEX_METRICS_ADDRESS=${CODEX_METRICS_ADDRESS:-0.0.0.0} + - CODEX_METRICS_PORT=${CODEX_METRICS_PORT:-8008} + - CODEX_DATA_DIR=${CODEX_DATA_DIR:-/datadir} + - CODEX_LISTEN_ADDRS=${CODEX_LISTEN_ADDRS:-/ip4/0.0.0.0/tcp/2345} + - CODEX_NAT=${CODEX_NAT:-10.0.0.10} + - CODEX_DISC_IP=${CODEX_DISC_IP:-0.0.0.0} + - CODEX_DISC_PORT=${CODEX_DISC_PORT:-8090} + - CODEX_NET_PRIVKEY=${CODEX_NET_PRIVKEY:-key} + # - CODEX_BOOTSTRAP_NODE=${CODEX_BOOTSTRAP_NODE} + - CODEX_MAX_PEERS=${CODEX_MAX_PEERS:-160} + - CODEX_AGENT_STRING=${CODEX_AGENT_STRING:-Codex} + - CODEX_API_BINDADDR=${CODEX_API_BINDADDR:-127.0.0.1} + - CODEX_API_PORT=${CODEX_API_PORT:-8080} + - CODEX_REPO_KIND=${CODEX_REPO_KIND:-fs} + - CODEX_STORAGE_QUOTA=${CODEX_STORAGE_QUOTA:-8589934592} + - CODEX_BLOCK_TTL=${CODEX_BLOCK_TTL:-0} + # - CODEX_BLOCK_MI=${CODEX_BLOCK_MI} + - CODEX_BLOCK_MN=${CODEX_BLOCK_MN:-1000} + - CODEX_CACHE_SIZE=${CODEX_CACHE_SIZE:-0} + - CODEX_PERSISTENCE=${CODEX_PERSISTENCE:-false} + - CODEX_ETH_PROVIDER=${CODEX_ETH_PROVIDER:-ws://localhost:8545} + # - CODEX_ETH_ACCOUNT=${CODEX_ETH_ACCOUNT} + # - CODEX_MARKETPLACE_ADDRESS=${CODEX_MARKETPLACE_ADDRESS:-0x59b670e9fA9D0A427751Af201D676719a970857b} + - CODEX_VALIDATOR=${CODEX_VALIDATOR:-false} + - CODEX_VALIDATOR_MAX_SLOTS=${CODEX_VALIDATOR_MAX_SLOTS:-1000} + ports: + - 8080:8080/tcp # REST API + - 8008:8008/tcp # Metrics + - 2345:2345/tcp # libp2p + - 8090:8090/udp # DHT discovery + volumes: + - /datadir:/datadir + networks: + - codex +networks: + codex: + driver: bridge diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100644 index 00000000..83560b80 --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +# Run +echo "Run Codex node" +exec "$@" diff --git a/docker/startCodex.sh b/docker/startCodex.sh deleted file mode 100644 index b3b7b472..00000000 --- a/docker/startCodex.sh +++ /dev/null @@ -1,150 +0,0 @@ -NAME="" -if [ -n "$CODEX_NODENAME" ]; then - NAME=" '$CODEX_NODENAME'" -fi -echo "Starting Codex node$NAME" - -args="" - -## Using local ip as NAT -nat_addr=$(ifconfig eth0 | awk '/inet/ {gsub("addr:", "", $2); print $2}') -echo "Local IP: $nat_addr" - -# Required arguments -if [ -n "$LISTEN_ADDRS" ]; then - echo "Listen address: $LISTEN_ADDRS" - args="$args --listen-addrs=$LISTEN_ADDRS" -else - args="$args --listen-addrs=/ip4/0.0.0.0/tcp/8071" -fi - -if [ -n "$API_BINDADDR" ]; then - echo "API bind address: $API_BINDADDR" - args="$args --api-bindaddr=$API_BINDADDR" -else - args="$args --api-bindaddr=0.0.0.0" -fi - -if [ -n "$DATA_DIR" ]; then - echo "Data dir: $DATA_DIR" - args="$args --data-dir=$DATA_DIR" -else - args="$args --data-dir=/datadir" -fi - -# Optional arguments -# Log level -if [ -n "$LOG_LEVEL" ]; then - echo "Log level: $LOG_LEVEL" - args="$args --log-level=\"$LOG_LEVEL\"" -fi - -# Metrics -if [ -n "$METRICS_ADDR" ] && [ -n "$METRICS_PORT" ]; then - echo "Metrics enabled" - args="$args --metrics=true" - args="$args --metrics-address=$METRICS_ADDR" - args="$args --metrics-port=$METRICS_PORT" -fi - -# NAT -echo "NAT: $nat_addr" -args="$args --nat=$nat_addr" - -# Discovery IP -if [ -n "$DISC_IP" ]; then - echo "Discovery IP: $DISC_IP" - args="$args --disc-ip=$DISC_IP" -fi - -# Discovery Port -if [ -n "$DISC_PORT" ]; then - echo "Discovery Port: $DISC_PORT" - args="$args --disc-port=$DISC_PORT" -fi - -# Net private key -if [ -n "$NET_PRIVKEY" ]; then - echo "Network Private Key path: $NET_PRIVKEY" - args="$args --net-privkey=$NET_PRIVKEY" -fi - -# Bootstrap SPR -if [ -n "$BOOTSTRAP_SPR" ]; then - echo "Bootstrap SPR: $BOOTSTRAP_SPR" - args="$args --bootstrap-node=$BOOTSTRAP_SPR" -fi - -# Max peers -if [ -n "$MAX_PEERS" ]; then - echo "Max peers: $MAX_PEERS" - args="$args --max-peers=$MAX_PEERS" -fi - -# Agent string -if [ -n "$AGENT_STRING" ]; then - echo "Agent string: $AGENT_STRING" - args="$args --agent-string=$AGENT_STRING" -fi - -# API port -if [ -n "$API_PORT" ]; then - echo "API port: $API_PORT" - args="$args --api-port=$API_PORT" -fi - -# Storage quota -if [ -n "$STORAGE_QUOTA" ]; then - echo "Storage quote: $STORAGE_QUOTA" - args="$args --storage-quota=$STORAGE_QUOTA" -fi - -# Block TTL -if [ -n "$BLOCK_TTL" ]; then - echo "Block TTL: $BLOCK_TTL" - args="$args --block-ttl=$BLOCK_TTL" -fi - -# Cache size -if [ -n "$CACHE_SIZE" ]; then - echo "Cache size: $CACHE_SIZE" - args="$args --cache-size=$CACHE_SIZE" -fi - -# Ethereum persistence -if [ -n "$ETH_PROVIDER" ]; then - echo "Provider: $ETH_PROVIDER" - args="$args --eth-provider=$ETH_PROVIDER" -fi - -if [ -n "$ETH_ACCOUNT" ]; then - echo "Ethereum account: $ETH_ACCOUNT" - args="$args --eth-account=$ETH_ACCOUNT" -fi - -if [ -n "$ETH_MARKETPLACE_ADDRESS" ]; then - echo "Marketplace address: $ETH_MARKETPLACE_ADDRESS" - args="$args --marketplace-address=$ETH_MARKETPLACE_ADDRESS" -fi - -if [ -n "$SIMULATE_PROOF_FAILURES" ]; then - echo "Simulate proof failures: $SIMULATE_PROOF_FAILURES" - args="$args --simulate-proof-failures=$SIMULATE_PROOF_FAILURES" -fi - -if [ "$PERSISTENCE" = "true" ] || [ "$PERSISTENCE" = "1" ]; then - echo "Persistence enabled" - args="$args --persistence" -else - echo "Persistence disabled" -fi - -if [ "$VALIDATOR" = "true" ] || [ "$VALIDATOR" = "1" ]; then - echo "Validator enabled" - args="$args --validator" -else - echo "Validator disabled" -fi - -echo "./codex $args" -/bin/bash -l -c "./codex $args"