Chapter 27Lesson 03~220 minutes

Containers, Kubernetes, Ephemeral Injectors, and Infrastructure Automation: Configuration, Design Patterns, and Trade-Offs

Containerizing JMeter introduces design choices that look operational but change measurement validity. Baking a plugin into an image improves binary consistency but requires a new image digest; mounting a JMX improves test portability but requires asset hashes; multiple Pods increase load exactly like multiple remote engines; remote telemetry survives Pod deletion but costs network/CPU and does not replace forensic JTL.

Custom vs communityBaked vs mountedCompose vs JobOne vs many injectorsArtifact vs telemetry

Learning objectives

  • Choose a custom Apache-binary image or vetted community image using provenance evidence.
  • Choose baked versus mounted JMX/data/plugins intentionally.
  • Choose Docker/Compose or Kubernetes Job based on local/orchestration needs.
  • Calculate aggregate load for multiple containers/Pods.
  • Choose persistent artifacts and/or remote telemetry without losing raw evidence.
  • Separate JMeter/JVM/OS/SUT/plugin/CI/container configuration layers.

1. Custom Apache-binary image versus community JMeter image

Custom image from Apache binary Vetted community image
You control Java base, Apache URL/checksum and added JARs. Faster adoption but maintainer/release/update process is external to Apache JMeter.
Easy to prove no hidden third-party plugin was added by your Dockerfile. Must inspect Dockerfile/source/SBOM/signatures/tags/digests and verify actual JMeter/Java inside.
You own patch/rebuild responsibility for base OS/Java. Community may publish updates quickly, but tag semantics/support vary.
Mandatory path here because provenance is directly teachable. Acceptable after organizational vetting; never call it 'official Apache' unless Apache actually publishes it.

2. Baked assets versus mounted versioned assets

Baked into image Mounted at runtime
Image digest fully identifies JMeter + plugin + JMX/data if everything is copied. One runtime image can execute many JMX/data revisions.
Excellent immutable release bundle; every test change rebuilds image. Requires separate SHA/manifests and mount/path discipline.
Do not bake secrets; image layers/history can retain them. Secrets can be injected separately at runtime; test assets mounted read-only.
Large/private datasets make image distribution expensive. Host/PVC/object-store staging can keep data separate.

Mandatory lab: JMeter runtime is baked; JMX/config/synthetic CSV are mounted and hashed. Plugins would normally be baked and versioned because plugin binary drift changes execution semantics.

3. Docker Compose versus Kubernetes Job

Docker / Compose Kubernetes Job
Best local single-host teaching and reproducible dev/CI service topology. Best when a Kubernetes cluster is already an intentional injector platform.
Simple bind mounts and user-defined network. ConfigMaps/Secrets/volumes, Pod DNS, requests/limits and Job retry/deadline semantics.
Container exit + host artifact directory easy to inspect. Job can create/retry multiple Pods; artifacts must survive/leave Pods before deletion.
No cloud/control plane needed. kind/minikube keeps learning local; managed Kubernetes is optional only.

4. One large injector versus multiple injectors

Chapter 26 says measure one injector's usable capacity; Chapter 25 says distributed configured load is the sum of full plans. Containers do not change either rule.

Example: one Pod at 20 threads may hit its 500m CPU limit; two Pods at 10 threads each configure the same 20 total threads but have two independent JVMs, two DNS/socket pools and two resource limits. Compare generator overhead and target source/network behavior—do not assume they are equivalent.

5. Kubernetes Job load math and retries

The optional checkpoint Job uses completions=2, parallelism=2. Each Pod executes 5 threads ×20 loops =100 samples, so configured total =200. It also uses backoffLimit=0 and a 90-second active deadline to avoid automatic workload retries in the teaching run.

Kubernetes documentation warns Jobs can recreate Pods after failures. For real destructive/non-idempotent targets, retry semantics must be included in safety/load math. Target count remains the final achieved-work check.

6. Artifact volume versus remote telemetry

Persistent/local artifacts Remote telemetry
Raw JTL/jmeter.log survive backend/dashboard changes and allow forensic reruns. Live fleet visibility survives short-lived Pods if backend is reachable.
Requires storage/collection path sized for results. Adds backend client/network/cardinality/security cost—Chapter 24 applies.
Kubernetes emptyDir is only Pod-lifetime storage; copy before Pod/Job deletion. Not a lossless replacement for raw per-sample JTL unless deliberately designed.
PVC can persist but storage class/performance/permissions become infrastructure state. Useful for many injectors if engine_id/run_id tags remain bounded.

7. Compose pattern

Compose is useful when the fixture and injector should be described in one local file. Preserve the same rules: exact image tags/IDs, private network, read-only inputs, writable artifacts, explicit CPU/memory, no latest, and a health/preflight gate. depends_on ordering alone is not evidence that the target is ready.

8. Resource limits versus JVM heap

A container memory limit is broader than Java heap: metaspace, direct buffers, thread stacks, native libraries and kernel/socket state also consume resources. Set -Xmx comfortably below the container limit and profile Chapter 26 metrics inside that cgroup/quota. CPU limits can throttle JMeter even when host CPU is low.

9. Non-root image versus bind-mount ownership

Running the injector as non-root reduces container privilege, but Linux bind-mounted result directories must be writable by the container UID/GID or by an intentional override such as --user "$(id -u):$(id -g)". Do not “fix” every permission issue with chmod 777 or root.

10. Namespace/service DNS versus host network

User-defined Docker networks and Kubernetes Services make target identity explicit. Host networking may reduce namespace translation on some Linux setups, but it weakens isolation/port separation and is not portable to Docker Desktop in the same way. Mandatory path stays bridge/Service DNS and measures the resulting environment.

11. Configuration-layer boundaries

Layer Examples Do not confuse with
JMeter core/test plan Thread Groups, properties, CSV, assertions, listeners container CPU/memory/DNS namespace.
Java/JVM 17.0.20+8, heap/GC/system properties Kubernetes memory limit.
OS/network host kernel/NIC/filesystem/Docker daemon container namespace/resource quota.
SUT target service/database/cache fixture/Service DNS or injector OOM.
Plugin/driver extra lib/ext JARs and versions base Java/JMeter image provenance.
CI provider runner disk, artifact upload, secret store, job timeout Kubernetes Job retry semantics.
Container/orchestrator image, mounts, UID, network, resources, Job/Pod lifecycle JMeter threads/loops.

12. Worked scenario

You need 1,000 total configured threads. Chapter 26 proved one container under 1 CPU/768 MiB is valid only to 120 threads. Should one Kubernetes Pod be set to 1,000 threads because the node has enough total CPU?

No. The measured injector/JVM quota is the relevant capacity. Use a bounded number of measured injectors and calculate the sum—for example eight ×120 =960 plus a separately justified remainder—while accounting for additional JVM/network/result overhead. Do not let horizontal scaling bypass target authorization.

13. Decision table

Need Preferred choice Evidence
Maximum provenance control Custom Apache-binary JMeter image base RepoDigest + Apache SHA + final image ID + runtime -v.
Many test revisions, stable runtime Mounted hashed JMX/data input manifest + read-only mount inspection.
Local single-host reproducibility Docker/Compose image/mount/network/resource/exit/JTL evidence.
Existing local Kubernetes learning kind/minikube Job manifest + image load/digest + Pod resources/status + collected artifacts.
Many injectors live visibility Backend Listener + per-injector low-cardinality tag Chapter24 overhead/cardinality + raw JTL retention.
Secret-bearing auth Runtime secret mechanism, never image layer secret reference/permissions; redact logs/artifacts.

14. Configured versus achieved load

Configured load = sum of every running injector's Thread Group workload plus any orchestrator retries/restarts that actually rerun the process. Achieved load = target-observed and JTL-observed samples under valid generator/container headroom. Preserve image/input identities, resource limits, Pod/container count and exit/restart state before making target-capacity claims.

Knowledge check

When is baking the JMX into the image preferable?

Why can two 10-thread Pods differ from one 20-thread Pod?

Why is emptyDir not long-term evidence storage?

Why is backoffLimit part of load safety?

Why must container CPU/memory be included in Chapter 26 capacity evidence?

Next lesson

Diagnose ephemeral infrastructure failures causally

Lesson 4 covers unofficial/floating images, baked secrets, lost JTL, localhost confusion, uncontrolled Job scaling and non-root permission failures.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current primary documentation on 2026-09-05. The course baseline remains Apache JMeter 5.6.3, requiring Java 8+; this chapter uses Eclipse Temurin 17.0.20+8 JRE (Jammy) as the version-specific Java base and records its resolved registry digest locally. The JMeter layer is built from Apache's binary tarball and verifies Apache's published SHA-512: 5978a1a35edb5a7d428e270564ff49d2b1b257a65e17a759d259a9283fc17093e522fe46f474a043864aea6910683486340706d745fcdf3db1505fd71e689083. Apache JMeter does not need a third-party plugin for the mandatory lab. Docker bind mounts are writable by default, so the JMX/data/config inputs are explicitly readonly; only the artifact mount is writable. The optional Kubernetes path uses current batch/v1 Job semantics with restartPolicy: Never, backoffLimit: 0, activeDeadlineSeconds, resource requests/limits, and no cloud requirement. The local cluster example assumes kind v0.32.0; a current minikube installation is an optional equivalent.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.