mirror of
https://github.com/itzg/docker-minecraft-server.git
synced 2026-10-26 04:18:54 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6610b4964 | ||
|
|
7c486b27b7 | ||
|
|
b64207b3c9 | ||
|
|
b692386094 | ||
|
|
4cd372a7ef | ||
|
|
151ef70368 | ||
|
|
3cb9486e4a | ||
|
|
bab1e16209 | ||
|
|
b040fb02dd | ||
|
|
625b10ae45 | ||
|
|
057d9c3a74 |
No files matched your search
@@ -94,25 +94,25 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.16.5
|
||||
# Pin version for pre-Java 17
|
||||
mcHelperVersion: 1.51.5-java8
|
||||
mcHelperVersion: 1.51.6-java8
|
||||
# JAVA 11
|
||||
- variant: java11
|
||||
baseImage: adoptopenjdk:11-jre-hotspot
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.16.4
|
||||
# Pin version for pre-Java 17
|
||||
mcHelperVersion: 1.51.5-java8
|
||||
mcHelperVersion: 1.51.6-java8
|
||||
# JAVA 8: NOTE: Unable to go past 8u312 because of Forge dependencies
|
||||
- variant: java8
|
||||
baseImage: eclipse-temurin:8-jre
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.12.2
|
||||
mcHelperVersion: 1.51.5-java8
|
||||
mcHelperVersion: 1.51.6-java8
|
||||
- variant: java8-jdk
|
||||
baseImage: eclipse-temurin:8-jdk
|
||||
platforms: linux/amd64,linux/arm64
|
||||
mcVersion: 1.12.2
|
||||
mcHelperVersion: 1.51.5-java8
|
||||
mcHelperVersion: 1.51.6-java8
|
||||
env:
|
||||
# Assume they line up, but when forked change to your Docker Hub username
|
||||
DOCKER_HUB_ORG: ${{ github.repository_owner }}
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
# For GLIBC_2.34 support
|
||||
knockdRepoOrg: Metalcape/knock
|
||||
# Pin version for Java 8, be sure to also set in build.yml
|
||||
mcHelperVersion: 1.51.5-java8
|
||||
mcHelperVersion: 1.51.6-java8
|
||||
env:
|
||||
IMAGE_TO_TEST: ${{ github.repository_owner }}/minecraft-server:test-${{ matrix.variant }}-${{ github.run_id }}
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
+6
-6
@@ -17,7 +17,7 @@ ARG KNOCKD_REPO_ORG=Metalcape/knock
|
||||
RUN --mount=target=/build,source=build \
|
||||
TARGET=${TARGETARCH}${TARGETVARIANT} \
|
||||
/build/run.sh install-packages
|
||||
COPY --from=tianon/gosu:1.19 /gosu /usr/local/bin/
|
||||
COPY --from=tianon/gosu:1.20 /gosu /usr/local/bin/
|
||||
|
||||
RUN --mount=target=/build,source=build \
|
||||
/build/run.sh setup-user
|
||||
@@ -28,18 +28,18 @@ ARG APPS_REV=1
|
||||
ARG GITHUB_BASEURL=https://github.com
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/easy-add
|
||||
ARG EASY_ADD_VERSION=0.8.18
|
||||
ARG EASY_ADD_VERSION=0.8.19
|
||||
ADD ${GITHUB_BASEURL}/itzg/easy-add/releases/download/${EASY_ADD_VERSION}/easy-add_${TARGETOS}_${TARGETARCH}${TARGETVARIANT} /usr/bin/easy-add
|
||||
RUN chmod +x /usr/bin/easy-add
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/restify
|
||||
ARG RESTIFY_VERSION=1.7.20
|
||||
ARG RESTIFY_VERSION=1.7.21
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${RESTIFY_VERSION} --var app=restify --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/rcon-cli
|
||||
ARG RCON_CLI_VERSION=1.7.8
|
||||
ARG RCON_CLI_VERSION=1.7.9
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${RCON_CLI_VERSION} --var app=rcon-cli --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
@@ -51,13 +51,13 @@ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/mc-server-runner
|
||||
ARG MC_SERVER_RUNNER_VERSION=1.16.1
|
||||
ARG MC_SERVER_RUNNER_VERSION=1.16.2
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${MC_SERVER_RUNNER_VERSION} --var app=mc-server-runner --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/mc-image-helper versioning=loose
|
||||
ARG MC_HELPER_VERSION=1.74.0
|
||||
ARG MC_HELPER_VERSION=1.74.2
|
||||
ARG MC_HELPER_BASE_URL=${GITHUB_BASEURL}/itzg/mc-image-helper/releases/download/${MC_HELPER_VERSION}
|
||||
# used for cache busting local copy of mc-image-helper
|
||||
ARG MC_HELPER_REV=1
|
||||
|
||||
@@ -89,6 +89,33 @@ you can use
|
||||
JVM_DD_OPTS: fml.queryResult=confirm,name=value
|
||||
```
|
||||
|
||||
## Java and JVM Agents
|
||||
|
||||
Java agents, such as [authlib-injector](https://github.com/yushijinhun/authlib-injector), can be loaded into the server by setting `JAVA_AGENTS`, and native JVM agents by setting `JVM_AGENTS`. Like [the `MODS` / `PLUGINS` variables](../mods-and-plugins/index.md#modsplugins-list), both are a comma or newline delimited list of
|
||||
|
||||
- URL of an agent file
|
||||
- container path to an agent file
|
||||
- container path to a directory containing agent jar files for `JAVA_AGENTS`, or `.so` files for `JVM_AGENTS`
|
||||
|
||||
The agents are copied into `/data/agents/java` and `/data/agents/jvm`, and each one is passed to the JVM as `-javaagent:<file>` or `-agentpath:<file>`, in file name order.
|
||||
|
||||
!!! example
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
JAVA_AGENTS: |
|
||||
https://www.example.com/agents/agent.jar
|
||||
/agents
|
||||
```
|
||||
|
||||
!!! note "Auto-removal"
|
||||
|
||||
Entries that are removed from the `JAVA_AGENTS` or `JVM_AGENTS` list will be automatically removed from the agents directory, so they are no longer loaded.
|
||||
|
||||
!!! note "Agent options"
|
||||
|
||||
An agent that needs options, such as `-javaagent:agent.jar=options`, can still be passed with `JVM_OPTS` instead.
|
||||
|
||||
## Enable Remote JMX for Profiling
|
||||
|
||||
To enable remote JMX, such as for profiling with VisualVM or JMC, set the environment variable `ENABLE_JMX` to "true", set `JMX_HOST` to the IP/host running the Docker container, and add a port forwarding of TCP port 7091, such as:
|
||||
|
||||
@@ -21,6 +21,40 @@ docker compose -f compose-dev.yml run --rm -it [-e key=value] mc-dev
|
||||
|
||||
To speed up the development cycle, it is recommended to set `SETUP_ONLY` to `true` as part of the run command above.
|
||||
|
||||
## Testing changes
|
||||
|
||||
Most changes should be covered by a test under `tests/setuponlytests`. Each test scenario needs its own `compose.yml` or `docker-compose.yml`, which defines the container configuration and inputs for that case. These tests run server setup with `SETUP_ONLY=true`, so they can verify configuration, downloads, and generated files without starting Minecraft.
|
||||
|
||||
A scenario can include a `require.sh` to check whether its prerequisites are available in the test environment, such as a required environment variable. It runs before the scenario; a non-zero exit status skips that test. For example, this skips a test when `CF_API_KEY` is not set:
|
||||
|
||||
```bash title="require.sh"
|
||||
[[ -n "${CF_API_KEY:-}" ]] || exit 1
|
||||
```
|
||||
|
||||
Since `require.sh` runs on the host, it sees the variables provided by the CI workflow. These are the ones typically checked:
|
||||
|
||||
- `EXTENDED_TESTS`: opt-in flag for slower or network-heavy scenarios; the CI workflows don't set it, so those scenarios only run when it is exported locally
|
||||
- `CF_API_KEY`: CurseForge API key, which is only available to trusted runs
|
||||
- `MINECRAFT_VERSION`: the Minecraft version of the CI matrix entry, such as `latest` or `1.12.2`
|
||||
- `VARIANT`: the image variant of the CI matrix entry, such as `java21-alpine`
|
||||
- `GH_TOKEN`: GitHub token used for API calls that would otherwise be rate limited
|
||||
|
||||
A `require_inside.sh` works the same way, but runs inside a container of the image under test, which is useful when a test depends on the image's contents or Java variant. Checking for JVM runtime files is a good use of it. For example, this skips a test that needs the JDWP agent, which some Java variants such as GraalVM do not include:
|
||||
|
||||
```bash title="require_inside.sh"
|
||||
[[ -f /opt/java/openjdk/lib/libjdwp.so ]] || exit 1
|
||||
```
|
||||
|
||||
Add a `verify.sh` to assert that setup produced the expected files or contents. It runs only after setup succeeds, with the scenario's `data` directory mounted at `/data`; a non-zero exit status fails the test. See the [`mc-image-helper assert` command documentation](https://github.com/itzg/mc-image-helper#assert) for available assertions. For example, use it to check that setup downloaded an expected mod:
|
||||
|
||||
```bash title="verify.sh"
|
||||
mc-image-helper assert fileExists "/data/mods/ExplorersCompass-1.16.5-1.1.2-forge.jar"
|
||||
```
|
||||
|
||||
Run the test suite with `tests/test.sh`. For a focused setup-only check, run `bash tests/setuponlytests/test.sh <scenario>` from the repository root, where `<scenario>` is the directory name under `tests/setuponlytests` (for example, `defaults`). The pull request workflow runs the suite, so prefer setup-only tests for new scenarios.
|
||||
|
||||
Tests under `tests/fulltests` start Minecraft and wait for the monitor to confirm that the server is healthy. Keep this suite limited to maintained tests that provide essential full-startup coverage; adding every scenario there would increase pull request validation time.
|
||||
|
||||
## Building the image with a new release of a tool
|
||||
|
||||
In this exapmle, let's say that [mc-image-helper](https://github.com/itzg/mc-image-helper) has been [released](https://github.com/itzg/mc-image-helper/releases) at 1.56.0, but the corresponding changes in the image [scripts](https://github.com/itzg/docker-minecraft-server/tree/23205471db9814cff9c6602361dbc6cdd6c4230a/scripts) need to be tested against that version while updating [the Dockerfile](https://github.com/itzg/docker-minecraft-server/blob/23205471db9814cff9c6602361dbc6cdd6c4230a/Dockerfile#L58).
|
||||
|
||||
@@ -4,7 +4,7 @@ deepmerge==3.0.1
|
||||
ghp-import==2.1.0
|
||||
griffe==2.3.2
|
||||
Jinja2==3.1.6
|
||||
Markdown==3.11
|
||||
Markdown==3.11.1
|
||||
MarkupSafe==3.0.4
|
||||
mergedeep==1.3.4
|
||||
mkdocs==1.6.1
|
||||
@@ -14,12 +14,12 @@ mkdocstrings==1.0.7
|
||||
mkdocstrings-python==2.0.9
|
||||
packaging==26.3
|
||||
pathspec==1.1.1
|
||||
platformdirs==4.13.0
|
||||
platformdirs==4.13.4
|
||||
Pygments==2.21.0
|
||||
pymdown-extensions==12.2
|
||||
pymdown-extensions==12.3
|
||||
python-dateutil==2.9.0.post0
|
||||
PyYAML==6.0.3
|
||||
pyyaml_env_tag==1.1
|
||||
six==1.17.0
|
||||
watchdog==6.0.0
|
||||
zensical==0.0.69
|
||||
zensical==0.0.71
|
||||
@@ -147,6 +147,18 @@ alternatively, you can mount: <code>/etc/localtime:/etc/localtime:ro
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>JAVA_AGENTS</code></td>
|
||||
<td>Comma or newline delimited list of Java agent jar URLs, container paths to jars, or container paths to directories of jars, which are loaded with <code>-javaagent</code></td>
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>JVM_AGENTS</code></td>
|
||||
<td>Comma or newline delimited list of native JVM agent URLs, container paths to agents, or container paths to directories of <code>.so</code> agents, which are loaded with <code>-agentpath</code></td>
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>EXTRA_ARGS</code></td>
|
||||
<td>Arguments that would usually be passed to the jar file (those which are written after the filename)</td>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"chunk-animator",
|
||||
"clickable-advancements",
|
||||
"colorwheel",
|
||||
"colorwheel-patcher",
|
||||
"compass-coords",
|
||||
"config-menus-forge",
|
||||
"configured",
|
||||
@@ -59,7 +60,6 @@
|
||||
"entity-texture-features-fabric",
|
||||
"entityculling",
|
||||
"equipment-compare",
|
||||
"essential-mod",
|
||||
"euphoria-patches",
|
||||
"extreme-sound-muffler",
|
||||
"ezzoom",
|
||||
|
||||
@@ -67,7 +67,6 @@ function buildSpigotFromSource {
|
||||
function downloadSpigot {
|
||||
local match
|
||||
local getBukkitBaseUrl="https://getbukkit.org/download/"
|
||||
local getBukkitSpigotUrl="${getBukkitBaseUrl}spigot"
|
||||
case "$TYPE" in
|
||||
*BUKKIT|*bukkit)
|
||||
match="CraftBukkit"
|
||||
@@ -82,8 +81,9 @@ function downloadSpigot {
|
||||
esac
|
||||
|
||||
if [[ ${VERSION^^} = LATEST ]]; then
|
||||
if ! downloadUrl=$(restify "${getBukkitBaseUrl}/${getbukkitFlavor}" --id='downloadr' | jq -r '.[0] | .href '); then
|
||||
logError "Failed to retrieve latest version from ${getBukkitSpigotUrl} -- site might be down"
|
||||
if ! downloadUrl=$(curl -fsSL "https://getbukkit.org/api/jars" \
|
||||
| jq -er --arg f "$getbukkitFlavor" '.[$f][0].downloadUrl | "https://getbukkit.org" + .'); then
|
||||
logError "Failed to retrieve latest version from ${getBukkitBaseUrl}${getbukkitFlavor} -- site might be down"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -125,6 +125,39 @@ elif versionLessThan 1.18.1; then
|
||||
fi
|
||||
fi
|
||||
|
||||
function addAgents() {
|
||||
local agents=$1 outDir=$2 glob=$3 option=$4
|
||||
|
||||
mkdir -p "$outDir"
|
||||
if ! mc-image-helper mcopy \
|
||||
--glob="$glob" \
|
||||
--scope=var-list \
|
||||
--to="$outDir" \
|
||||
"$agents"; then
|
||||
logError "Failed to get agents from $agents"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The manifest lists the files that the list resolved to, also in subdirectories, as for destination<source entries
|
||||
local manifest="$outDir/.var-list-manifest.json"
|
||||
if [ -f "$manifest" ]; then
|
||||
while read -r agent; do
|
||||
JVM_OPTS="${JVM_OPTS} ${option}:${outDir}/${agent}"
|
||||
done < <(jq -r '.files[]' "$manifest" | sort)
|
||||
fi
|
||||
}
|
||||
|
||||
if isFamily NATIVE; then
|
||||
: # Native server, so no JVM to load agents into
|
||||
else
|
||||
if [[ -v JVM_AGENTS ]]; then
|
||||
addAgents "$JVM_AGENTS" /data/agents/jvm '*.so' -agentpath
|
||||
fi
|
||||
if [[ -v JAVA_AGENTS ]]; then
|
||||
addAgents "$JAVA_AGENTS" /data/agents/java '*.jar' -javaagent
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set up log4j2 configuration with templating support
|
||||
LOGFILE="${SERVER_DIR}/log4j2.xml"
|
||||
if isFamily NATIVE; then
|
||||
|
||||
@@ -313,6 +313,10 @@ function handleModrinthProjects() {
|
||||
loader=${HYBRIDTYPE}
|
||||
elif isFamily VANILLA; then
|
||||
loader=datapack
|
||||
elif isType NEOFORGE; then
|
||||
loader=neoforge
|
||||
elif isFamily FORGE; then
|
||||
loader=forge
|
||||
else
|
||||
loader="${TYPE,,}"
|
||||
fi
|
||||
|
||||
@@ -28,8 +28,8 @@ fullMinecraftUpTest(){
|
||||
}
|
||||
|
||||
# go through each folder in fulltests and run fullbuilds
|
||||
files=$(ls */docker-compose.yml)
|
||||
for file in $files; do
|
||||
readarray -t files < <(find . -maxdepth 2 -mindepth 2 \( -name compose.yml -o -name docker-compose.yml \) | sort)
|
||||
for file in "${files[@]}"; do
|
||||
|
||||
echo "Starting Tests on $(dirname "$file")"
|
||||
if ! fullMinecraftUpTest "$file"; then
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
mc:
|
||||
restart: "no"
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
SETUP_ONLY: "TRUE"
|
||||
VERSION: ${MINECRAFT_VERSION:-LATEST}
|
||||
# The image's own directory holds a Java agent among other files
|
||||
JAVA_AGENTS: /image
|
||||
# The JDK's debugger is a native JVM agent
|
||||
JVM_AGENTS: /opt/java/openjdk/lib/libjdwp.so
|
||||
volumes:
|
||||
- ./data:/data
|
||||
+1
@@ -0,0 +1 @@
|
||||
[[ -f /opt/java/openjdk/lib/libjdwp.so ]] || exit 1
|
||||
@@ -0,0 +1,3 @@
|
||||
mc-image-helper assert fileExists agents/java/Log4jPatcher.jar
|
||||
mc-image-helper assert fileNotExists agents/java/server.properties
|
||||
mc-image-helper assert fileExists agents/jvm/libjdwp.so
|
||||
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
mc:
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
environment:
|
||||
EULA: "true"
|
||||
SETUP_ONLY: "true"
|
||||
TYPE: NEOFORGE
|
||||
VERSION: 1.21.1
|
||||
MODRINTH_PROJECTS: storagedrawers
|
||||
volumes:
|
||||
- ./data:/data
|
||||
@@ -0,0 +1 @@
|
||||
mc-image-helper assert fileExists "mods/StorageDrawers-neoforge-*.jar"
|
||||
@@ -41,6 +41,16 @@ setupOnlyMinecraftTest(){
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f require_inside.sh ]; then
|
||||
# require_inside.sh scripts run inside the image under test to check for things like a particular
|
||||
# JVM file or feature. A non-zero exit status indicates the test should be skipped.
|
||||
if ! docker run --rm --entrypoint bash -v "${PWD}/require_inside.sh":/require_inside:ro "${IMAGE_TO_TEST}" -e /require_inside; then
|
||||
echo "${folder} SKIP (require_inside)"
|
||||
cd ..
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# false positive since it's used in delta calculations below
|
||||
# shellcheck disable=SC2034
|
||||
start=$(date +%s)
|
||||
@@ -71,7 +81,7 @@ image=""
|
||||
|
||||
# Go through each folder in setuponly and test setups
|
||||
if (( $# == 0 )); then
|
||||
readarray -t folders < <(find . -maxdepth 2 -mindepth 2 -name docker-compose.yml -exec dirname "{}" \;)
|
||||
readarray -t folders < <(find . -maxdepth 2 -mindepth 2 \( -name compose.yml -o -name docker-compose.yml \) -exec dirname "{}" \; | sort -u)
|
||||
foldersList=("${folders[@]}")
|
||||
image=" using $IMAGE_TO_TEST"
|
||||
fi
|
||||
|
||||
Reference in new issue
Block a user