# On M1 mac $ docker run \ --platform linux/amd64 \ --pull always \ -it \ --rm \ -p 8080:80 \ --name openjdk-playground \ ghcr.io/sureshg/containers:openjdk-latest # Default busybox image should work. $ brew install cdebug $ cdebug exec \ --privileged \ -it \ --rm \ --platform linux/amd64 \ docker://openjdk-playground # Extract a file from the Docker environment and store it locally $ docker run \ --rm \ --entrypoint cat \ busybox:latest \ '/bin/ls' > ls # OR copy files from a container $ docker cp <CONTAINER>:/app/app/jar . # OR $ id=$(docker create ghcr.io/sureshg/containers:openjdk-latest) $ docker cp $id:/app/app.jar - > app.tar $ docker rm -v $id
JVM Ergonomics and Container logs
$ cat << EOF >App.java import static java.lang.System.out; public class App { void main() { var version = "• Java %s running on %s %s".formatted( System.getProperty("java.version"), System.getProperty("os.name"), System.getProperty("os.arch")); out.println(version); long unit = 1024 * 1024L; long heapSize = Runtime.getRuntime().totalMemory(); long heapFreeSize = Runtime.getRuntime().freeMemory(); long heapUsedSize = heapSize-heapFreeSize; long heapMaxSize = Runtime.getRuntime().maxMemory(); out.println("• [CPU] Active Processors: " + Runtime.getRuntime().availableProcessors()); out.println("• [Mem] Current Heap Size (Committed) : " + heapSize/unit + " MiB"); out.println("• [Mem] Current Free memeory in Heap : " + heapFreeSize/unit + " MiB"); out.println("• [Mem] Currently used memory : " + heapUsedSize/unit + " MiB"); out.println("• [Mem] Max Heap Size (-Xmx) : " + heapMaxSize/unit + " MiB"); } } EOF $ docker run \ -it \ --rm \ --cpus=2 \ --memory=512m \ --pull always \ --mount type=bind,source=$(pwd),destination=/app,readonly \ --mount type=bind,source=/,destination=/host,readonly \ --name openjdk \ openjdk:25-slim \ java \ --source 25 --enable-preview \ -XX:+UnlockExperimentalVMOptions \ -XX:+UnlockDiagnosticVMOptions \ -XX:+PrintFlagsFinal \ -XX:MaxRAMPercentage=0.8 \ -XX:-MaxFDLimit \ -Xlog:gc \ /app/App.java \ | grep -e "Use.*GC" -e "Active" -e "Using" -e "Max.*Limit" -e "Container" -e "•"
JVM default GC
# OpenJDK reverts to Serial GC when it detects < 2 CPUs or < 2GB RAM $ docker run -it --rm --cpus=1 --memory=1G openjdk:25-slim java -Xlog:gc --version #[0.007s][info][gc] Using Serial
$ docker run -it --rm --platform=linux/aarch64 alpine uname -m aarch64 $ docker run -it --rm --platform=linux/amd64 alpine uname -m x86_64 $ docker run --rm arm64v8/alpine uname -a $ docker run --rm arm32v7/alpine uname -a $ docker run --rm ppc64le/alpine uname -a $ docker run --rm s390x/alpine uname -a $ docker run --rm tonistiigi/debian:riscv uname -a
Netcat Webserver
FROM alpine ENTRYPOINT while :; do nc -k -l -p $PORT -e sh -c 'echo -e "HTTP/1.1 200 OK\n\n hello, world"'; done # https://github.com/jamesward/hello-netcat # docker build -t hello-netcat . # docker run -p 8080:80 -e PORT=80 -it hello-netcat
Forwards Logs
# forward request and error logs to docker log collector RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # OR output directly to /proc/self/fd/1 (STDOUT) /proc/self/fd/2 (STDERR) # https://docs.docker.com/config/containers/logging/configure/
#!/bin/bash ## Entrypoint script for my-app. This script is to show how to write ## an entrypoint script that actually passes down signals from Docker. ## Load our DB Password into a runtime only Environment Variable if [ -f /run/secrets/password ] then echo "Loading DB password from secrets file" DB_PASS=$(cat /run/secrets/password) export DB_PASS fi ## Run the Application exec my-app