From b3c47d23b4a138d5d18517b5a456bb84ea07a3d0 Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Fri, 28 Nov 2025 18:50:53 +0100 Subject: [PATCH 01/16] Add Dockerfile --- Dockerfile | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9287080 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +ARG RUST_IMAGE_VERSION="1.91.1-alpine3.20" +ARG ALPINE_IMAGE_VERSION="3.22.2" +ARG TARGET_PLATFORM="unknowntarget" +ARG USER="shay" +ARG UID="1000" +ARG GID="1000" + +# Because we can't use variable expansion in `RUN --mount=from=`, we use this to alias the image +FROM rust:${RUST_IMAGE_VERSION} AS build_base +RUN apk update && apk add g++ + +#################################################################################################### +FROM build_base AS build +ARG TARGET_PLATFORM +WORKDIR /app + +COPY . . + +# Mounts are complicated. See https://github.com/rust-lang/cargo/issues/2644#issuecomment-570749508 +# We set `id` to separate caches by target platform so we can build for multiple architectures +RUN \ + --mount=type=cache,target=/usr/local/cargo,from=build_base,source=/usr/local/cargo,id=${TARGET_PLATFORM}_cargohome \ + --mount=type=cache,target=/app/target,id=${TARGET_PLATFORM}_target < Date: Fri, 28 Nov 2025 23:59:31 +0100 Subject: [PATCH 02/16] Add default config files to Docker image --- Dockerfile | 3 ++ example-config/global-settings.toml | 48 +++++++++++++++++++ example-config/local-settings/ExampleBot.toml | 41 ++++++++++++++++ example-config/stasis-chambers.yaml | 1 + 4 files changed, 93 insertions(+) create mode 100644 example-config/global-settings.toml create mode 100644 example-config/local-settings/ExampleBot.toml create mode 100644 example-config/stasis-chambers.yaml diff --git a/Dockerfile b/Dockerfile index 9287080..60632b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,9 @@ RUN < Date: Sat, 29 Nov 2025 00:29:23 +0100 Subject: [PATCH 03/16] Separate config files and binary --- Dockerfile | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 60632b6..dcc8746 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN apk update && apk add g++ #################################################################################################### FROM build_base AS build ARG TARGET_PLATFORM -WORKDIR /app +WORKDIR /build COPY . . @@ -20,9 +20,9 @@ COPY . . # We set `id` to separate caches by target platform so we can build for multiple architectures RUN \ --mount=type=cache,target=/usr/local/cargo,from=build_base,source=/usr/local/cargo,id=${TARGET_PLATFORM}_cargohome \ - --mount=type=cache,target=/app/target,id=${TARGET_PLATFORM}_target < Date: Sat, 29 Nov 2025 00:43:49 +0100 Subject: [PATCH 04/16] Remove config files from container --- Dockerfile | 11 +---- example-config/global-settings.toml | 48 ------------------- example-config/local-settings/ExampleBot.toml | 41 ---------------- example-config/stasis-chambers.yaml | 1 - 4 files changed, 2 insertions(+), 99 deletions(-) delete mode 100644 example-config/global-settings.toml delete mode 100644 example-config/local-settings/ExampleBot.toml delete mode 100644 example-config/stasis-chambers.yaml diff --git a/Dockerfile b/Dockerfile index dcc8746..f5f9284 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,12 +46,5 @@ RUN < Date: Sat, 29 Nov 2025 00:49:02 +0100 Subject: [PATCH 05/16] Add `.dockerignore` --- .dockerignore | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dee5bfa --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +# Various config files +.github/ +.gitignore +Makefile.toml +rustfmt.toml + +# Builds +target/ + +# Documentation +compose.example.yaml +LICENSE +README.md + +# Yes, really! +Dockerfile +.dockerignore From 9da5f033f83c8bfc3d9fcc3c652116b1297976d9 Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 00:50:31 +0100 Subject: [PATCH 06/16] Remove extra group initialisation --- Dockerfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index f5f9284..e222650 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ ARG ALPINE_IMAGE_VERSION="3.22.2" ARG TARGET_PLATFORM="unknowntarget" ARG USER="shay" ARG UID="1000" -ARG GID="1000" # Because we can't use variable expansion in `RUN --mount=from=`, we use this to alias the image FROM rust:${RUST_IMAGE_VERSION} AS build_base @@ -33,12 +32,8 @@ ARG GID WORKDIR /config RUN < Date: Sat, 29 Nov 2025 00:54:44 +0100 Subject: [PATCH 07/16] Add example `compose.yaml` --- compose.example.yaml | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 compose.example.yaml diff --git a/compose.example.yaml b/compose.example.yaml new file mode 100644 index 0000000..c14fb7b --- /dev/null +++ b/compose.example.yaml @@ -0,0 +1,50 @@ +services: + bot: + restart: unless-stopped + image: shaysbot:latest # replace with a versioned tag! + volumes: + - ./config:/config # create this directory first! + + + # ZenithProxy (below) is optional -- uncomment to enable it + + # proxy: + # image: ghcr.io/rfresh2/zenithproxy:latest # replace with a versioned tag! + # ports: + # - '25565:25565' + # environment: + # # The port that ZenithProxy will be connectable on. + # ZENITH_PORT: "25565" + + # # The host that ZenithProxy will be bound to. This can be an IP address (eg. 203.0.113.67), a + # # hostname (eg. mc-proxy) or a FQDN (eg. mc.example.com) + # ZENITH_IP: "localhost" + + # # The version of Minecraft Zenith will run. + # # Latest version is usually supported, others are deprecated. + # ZENITH_MC_VERSION: "1.21.4" + + # # The authorization token granted by Discord when configuring a Bot user. + # ZENITH_DISCORD_TOKEN: "" + + # # The ID of the Discord role that should allow users to interact ZenithProxy. + # ZENITH_DISCORD_ROLE_ID: "" + + # # The ID of the Discord channel in which ZenithProxy will look for commands, also referred to + # # as the "Management channel". + # ZENITH_DISCORD_CHANNEL_ID: "" + + # # The ChatRelay is a live feed of chat messages and/or connection messages from the server to + # # a Discord channel. To enable it, set this variable to the ID of the channel you want to use + # # for ChatRelay. This can't be the same as the Management channel. + # # ZENITH_DISCORD_CHAT_RELAY_CHANNEL: "" + + # # Completely disable ZenithProxy's Discord integration. As Discord is the main way most users + # # will interact with ZenithProxy, you probably want to leave this set to `false`. + # # ZENITH_DISCORD_DISABLED: "false" + + # # On Linux, ZenithProxy can be run as a specially optimized binary. On other platforms, it + # # must be run directly via the JVM. The former method is better, and will be chosen + # # automatically by ZenithProxy if the environment supports it. You probably shouldn't override + # # this unless you know what you're doing. + # # ZENITH_PLATFORM: "linux" \ No newline at end of file From 245e000849987da7181a67a74941e05664f393ef Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:01:33 +0100 Subject: [PATCH 08/16] Add documentation to README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 77b2c49..7151e4b 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,17 @@ The first is the log level of the bot, the second is of dependencies. Compiled with [GitHub Actions](.github/workflows/release.yml) using the [**Debug**](#cargo-profiles) profile. +### Docker +Pull from the image `ghcr.io/ShayBox/ShaysBot`. Available tags are listed +[here](#TODO-fix-this-when-ghcr-is-set-up). + +All configuration files are in the container's working directory, `/config`. If using a bind mount +for this directory, make sure `config` mount point on the host has the proper permissions and +ownership set for the application to be able to access it inside the container. + +For an example `compose.yaml` file for use with Docker Compose, see +[`compose.example.yaml`](./compose.example.yaml). + ### Install or Develop Locally Prerequisites: From 89b1e74591b3e9054d7aa556ba20ceb68d3c382c Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:27:56 +0100 Subject: [PATCH 09/16] Add container builds --- .../{release.yml => build-binary.yml} | 4 +- .github/workflows/build-image.yml | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) rename .github/workflows/{release.yml => build-binary.yml} (98%) create mode 100644 .github/workflows/build-image.yml diff --git a/.github/workflows/release.yml b/.github/workflows/build-binary.yml similarity index 98% rename from .github/workflows/release.yml rename to .github/workflows/build-binary.yml index 5f12980..2b86d39 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/build-binary.yml @@ -1,9 +1,11 @@ +name: Build binaries + on: release: types: [ created ] jobs: - release: + build: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml new file mode 100644 index 0000000..635eefb --- /dev/null +++ b/.github/workflows/build-image.yml @@ -0,0 +1,62 @@ +name: Build container images + +on: + push: + branches: ["master"] + tags: ["*"] + pull_request: + branches: ["master"] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.7.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Log in to GHCR + uses: docker/login-action@v3.6.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get Docker metadata + id: meta + uses: docker/metadata-action@v5.10.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Checkout repository + uses: actions/checkout@v6.0.0 + + - name: Build and push + id: build-push + uses: docker/build-push-action@v6.18.0 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3.0.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.build-push.outputs.digest }} + push-to-registry: true From 1d5c61335d2ab7f059a87e2fd18668732734b261 Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 10:09:23 +0100 Subject: [PATCH 10/16] Fix README link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7151e4b..6f46179 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Compiled with [GitHub Actions](.github/workflows/release.yml) using the [**Debug ### Docker Pull from the image `ghcr.io/ShayBox/ShaysBot`. Available tags are listed -[here](#TODO-fix-this-when-ghcr-is-set-up). +[here](https://github.com/ShayBox/ShaysBot/pkgs/container/shaysbot/versions). All configuration files are in the container's working directory, `/config`. If using a bind mount for this directory, make sure `config` mount point on the host has the proper permissions and From 0d82f2be8370b28b6ea17f3a53fe0eb6d6f38b83 Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 16:59:41 +0100 Subject: [PATCH 11/16] Add config for [act](https://nektosact.com/) --- .actrc | 5 +++++ .dockerignore | 1 + .gitignore | 1 + act_event.json | 5 +++++ 4 files changed, 12 insertions(+) create mode 100644 .actrc create mode 100644 act_event.json diff --git a/.actrc b/.actrc new file mode 100644 index 0000000..2e88c33 --- /dev/null +++ b/.actrc @@ -0,0 +1,5 @@ +--secret GITHUB_TOKEN +--artifact-server-path ./.artifacts +--matrix platform:amd64 +--eventpath ./act_event.json +--platform ubuntu-24.04=catthehacker/ubuntu:act-latest \ No newline at end of file diff --git a/.dockerignore b/.dockerignore index dee5bfa..6580db6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,7 @@ rustfmt.toml # Builds target/ +.artifacts/ # Documentation compose.example.yaml diff --git a/.gitignore b/.gitignore index 643d79a..f595fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/ .vscode/ target/ +.artifacts/ diff --git a/act_event.json b/act_event.json new file mode 100644 index 0000000..650cd5d --- /dev/null +++ b/act_event.json @@ -0,0 +1,5 @@ +{ + "repository": { + "name": "ShaysBot" + } +} \ No newline at end of file From 2717b60d6b65c295535a6260be612a320a1fa57f Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sat, 29 Nov 2025 17:00:08 +0100 Subject: [PATCH 12/16] Build Docker image with `cargo chef` --- Dockerfile | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index e222650..e0c279a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,34 @@ ARG RUST_IMAGE_VERSION="1.91.1-alpine3.20" ARG ALPINE_IMAGE_VERSION="3.22.2" -ARG TARGET_PLATFORM="unknowntarget" ARG USER="shay" ARG UID="1000" -# Because we can't use variable expansion in `RUN --mount=from=`, we use this to alias the image +#################################################################################################### + FROM rust:${RUST_IMAGE_VERSION} AS build_base +WORKDIR /build + RUN apk update && apk add g++ +RUN cargo +nightly install cargo-chef --locked --version 0.1.73 #################################################################################################### -FROM build_base AS build -ARG TARGET_PLATFORM -WORKDIR /build +FROM build_base AS build_plan COPY . . +RUN cargo +nightly chef prepare --recipe-path recipe.json -# Mounts are complicated. See https://github.com/rust-lang/cargo/issues/2644#issuecomment-570749508 -# We set `id` to separate caches by target platform so we can build for multiple architectures -RUN \ - --mount=type=cache,target=/usr/local/cargo,from=build_base,source=/usr/local/cargo,id=${TARGET_PLATFORM}_cargohome \ - --mount=type=cache,target=/build/target,id=${TARGET_PLATFORM}_target < Date: Sat, 29 Nov 2025 17:00:41 +0100 Subject: [PATCH 13/16] Rework build to run on platform matrix --- .github/workflows/build-image.yml | 167 +++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 48 deletions(-) diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 635eefb..ded141f 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -10,53 +10,124 @@ on: env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} jobs: - build-and-push: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - attestations: write - id-token: write - - steps: - - name: Set up QEMU - uses: docker/setup-qemu-action@v3.7.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.11.1 - - - name: Log in to GHCR - uses: docker/login-action@v3.6.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Get Docker metadata - id: meta - uses: docker/metadata-action@v5.10.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Checkout repository - uses: actions/checkout@v6.0.0 - - - name: Build and push - id: build-push - uses: docker/build-push-action@v6.18.0 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Generate artifact attestation - uses: actions/attest-build-provenance@v3.0.0 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} - subject-digest: ${{ steps.build-push.outputs.digest }} - push-to-registry: true + meta: + name: Set metadata + runs-on: ubuntu-24.04 + outputs: + image_name: ${{ steps.meta.outputs.image_name }} + + steps: + - name: Set metadata + id: meta + env: + registry: ${{ env.REGISTRY }} + owner: ${{ github.repository_owner }} + repo: ${{ github.event.repository.name }} + run: | + echo "image_name=${registry,,}/${owner,,}/${repo,,}" >> "$GITHUB_OUTPUT" + + build: + needs: + - meta + strategy: + fail-fast: false + matrix: + include: + - platform: amd64 + os: linux + runner: ubuntu-24.04 + - platform: arm64 + os: linux + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.0 + + - name: Set up Docker Buildx + id: setup-buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Log in to registry + uses: docker/login-action@v3.6.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get Docker metadata + id: meta + uses: docker/metadata-action@v5.10.0 + with: + images: ${{ needs.meta.outputs.image_name }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6.18.0 + with: + context: . + platforms: ${{ matrix.os }}/${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + tags: ${{ needs.meta.outputs.image_name }} + outputs: type=registry,push-by-digest=true,name-canonical=true + + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v5.0.0 + with: + name: digests-${{ matrix.os }}-${{ matrix.platform }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + needs: + - meta + - build + runs-on: ubuntu-24.04 + + steps: + - name: Download digests + uses: actions/download-artifact@v6.0.0 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Log in to registry + uses: docker/login-action@v3.6.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Get Docker metadata + id: meta + uses: docker/metadata-action@v5.10.0 + with: + images: ${{ needs.meta.outputs.image_name }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ needs.meta.outputs.image_name }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ needs.meta.outputs.image_name }}:${{ steps.meta.outputs.version }} From 53d6331ecf2ec0193311a12c6ec130b6f224621a Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:18:13 +0100 Subject: [PATCH 14/16] Add caching --- .github/workflows/build-image.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index ded141f..f598087 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -72,6 +72,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} tags: ${{ needs.meta.outputs.image_name }} outputs: type=registry,push-by-digest=true,name-canonical=true + cache-from: type=gha,scope=${{ matrix.platform }}-${{ github.ref_name }} + cache-to: type=gha,mode=max,scope=${{ matrix.platform }}-${{ github.ref_name }} - name: Export digest run: | From a3de9258b24ae7e243188080d00bdd670321f352 Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:37:33 +0100 Subject: [PATCH 15/16] Update readme (this is just to test caching...) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f46179..f68e635 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ My personal Minecraft bot written in Rust built with [Azalea]. Primarily designed to be a pearl bot, allowing for quick travel to different locations with multiple accounts. -Also featuring a Discord bot, an HTTP API for local integrations, and support for [No Chat Reports] encryption. +Also featuring a Discord bot, an HTTP API for local integrations, a Docker image, and support for [No Chat Reports] encryption. ## How to use From d95f7dc6a2acfaf4622f27f619b9091c1a6384cd Mon Sep 17 00:00:00 2001 From: nozx <245411841+nozxmc@users.noreply.github.com> Date: Sun, 30 Nov 2025 02:08:47 +0100 Subject: [PATCH 16/16] Fix container run environment --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index e0c279a..ff8bc4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG RUST_IMAGE_VERSION="1.91.1-alpine3.20" -ARG ALPINE_IMAGE_VERSION="3.22.2" +ARG JAVA_IMAGE_VERSION="25-jre-alpine-3.22" ARG USER="shay" ARG UID="1000" @@ -29,7 +29,7 @@ RUN cargo +nightly build --release --locked --bin shaysbot #################################################################################################### -FROM alpine:${ALPINE_IMAGE_VERSION} AS run +FROM eclipse-temurin:${JAVA_IMAGE_VERSION} AS run ARG USER ARG UID ARG GID @@ -38,7 +38,6 @@ WORKDIR /config RUN <