Chapter 27Lesson 01~185 minutes

Containers, Kubernetes, Ephemeral Injectors, and Infrastructure Automation: Core Concepts and Mental Model

Chapter 26 proved that an injector is part of the experiment: CPU, heap/GC, sockets, disk and network headroom determine whether configured load becomes achieved load. Containers solve a different problem. They package a known Java/JMeter/userspace environment and make injectors disposable, but they also add image provenance, mount, namespace, resource-quota, virtual-network, DNS, filesystem and exit-state boundaries that can invalidate a test if they are implicit.

Image provenanceEphemeral injectorRead-only inputsPersistent artifactsContainer/Kubernetes network

Learning objectives

  • Separate container/orchestrator lifecycle from JMeter thread lifecycle.
  • Explain pinned Java + JMeter + plugins + JMX/data → image/runtime → target → persistent evidence.
  • Define image tag/digest, layer, bind mount, writable artifact volume, container network, resource limit and exit state.
  • Inspect image/runtime/mount/network/resource/artifact state before execution.
  • Recognize that container localhost belongs to that container's network namespace.
  • Preserve Chapter 26 generator-capacity and Chapter 25 load-math contracts inside ephemeral infrastructure.

1. The practical problem: “works in my shell” is not an injector specification

A workstation has JMeter 5.6.3, one developer plugin, an untracked Java update, a CSV beside the JMX and a writable home directory. The same test is started in CI from an image called jmeter:latest. It cannot find the CSV, writes JTL into the container layer, has half the CPU quota and resolves localhost to itself rather than the target. Containerization did not create reproducibility because the important state was never specified.

Mandatory chapter boundary: all executable traffic remains disposable/local. Docker target lives only on a private user-defined network; native proof uses 127.0.0.1:8027. Each required run is 5 threads ×20 loops = 100 samples, 100 ms pacing, 2 KiB synthetic response, ≤15 seconds. No real credentials, cloud cluster, public target, privileged container, host Docker socket mount, RMI service, or OS/JVM global tuning is required. Never substitute a public/shared/production endpoint.

2. Mental model: package, runtime, execution and evidence are separate

Ephemeral injector lifecycle and evidence flow

Containerization changes how the injector is packaged, started, networked, limited, and cleaned up; it does not change JMeter thread semantics. The image/runtime lifecycle and the test-plan lifecycle must therefore be measured and evidenced separately.

flowchart TD
A[Pinned Java base + verified JMeter binary + optional plugins] --> I[Injector image]
J[JMX + properties + synthetic data] --> M[Read-only mounted inputs]
I --> C[Ephemeral container / Job Pod]
M --> C
Q[CPU / memory / PID / filesystem / network limits] --> C
C --> E[JMeter CLI engine]
E --> H[HTTP protocol/session]
H --> T[Private target service]
E --> R[JTL + jmeter.log]
E --> X[Process exit status]
R --> P[Persistent host volume / collected artifact]
X --> P
T --> S[Target telemetry/events]
S --> P
K[Container/Kubernetes lifecycle] --> C

The image packages Java/JMeter binaries and any deliberately baked plugins. Versioned JMX/data/config are separate inputs mounted into the running injector. Docker/Kubernetes creates an ephemeral process environment with CPU/memory/filesystem/network constraints. JMeter still creates the same Thread Groups and protocol sessions as outside a container. The target sees traffic from the container/pod network. JTL/jmeter.log and exit state must leave the ephemeral filesystem before cleanup. Deleting a container/Pod is an infrastructure lifecycle event; it does not redefine what a JMeter thread, loop or sample means.

3. New infrastructure terms

Term Meaning in this chapter
Image Immutable layered filesystem/config used to create a container. An image ID/digest identifies content more strongly than a human tag.
Tag Mutable human-readable reference such as 5.6.3-p27; never assume latest stays the same.
Registry digest / image ID Content-addressed identity recorded for provenance. A local build has an image ID; pushed/pulled images can have RepoDigests.
Bind mount Host path exposed inside a container. Inputs are mounted read-only; results get a separate writable mount.
Read-only root filesystem Container image filesystem cannot be modified at runtime; explicit writable locations such as /tmp//artifacts are provided.
User-defined Docker network Private virtual network with container-name DNS, e.g. p27-fixture.
Resource request/limit Kubernetes scheduling request and enforced container CPU/memory ceiling; Docker has analogous runtime limits.
Job Kubernetes run-to-completion controller that creates one or more Pods and records success/failure.
Ephemeral injector Short-lived generator instance created for one test/run and then removed after evidence collection.

4. Apache JMeter distribution versus a container image

Apache publishes JMeter binaries and integrity material. The mandatory path builds a custom container from that verified Apache tarball; it does not claim any community JMeter image is maintained by Apache. The Java base is the Docker Official Image for Eclipse Temurin at a version-specific Java 17.0.20+8 tag. Record its resolved digest before building.

The resulting local JMeter image has two provenance anchors: the base image's resolved registry digest and the Apache JMeter tarball's published SHA-512.

5. Container lifetime is not thread lifetime

One container can run one JMeter process containing 5 threads; two Kubernetes Pods each running that plan configure 10 total threads, not five. A Job retry can run the program again and create additional target work. Therefore:

  • container count/Job parallelism belongs in configured-load math;
  • JMeter Thread Group threads/loops still belong inside each process;
  • orchestrator retries/deadlines/evictions belong in infrastructure validity;
  • target counts and per-injector labels prove achieved work.

6. Mount JMX/data/config read-only

Docker bind mounts are read-write by default, so use the readonly/ro option for plans/data/config. This prevents a compromised/mistaken sampler/script from modifying the source assets through the container. Artifacts get a separate write mount.

7. Ephemeral filesystems and evidence

If JMeter writes /work/results.jtl only inside the container, deleting the container can delete the experiment. The required pattern is:

  • inputs: immutable/read-only;
  • /tmp: disposable scratch;
  • /artifacts: host bind mount/PVC/explicit artifact collection;
  • JTL and matching jmeter.log: always outside the ephemeral layer before cleanup;
  • target events/telemetry and container exit state: retained with the run manifest.

8. Container localhost is not host/sibling localhost

Inside the JMeter container, 127.0.0.1 points to the JMeter container itself. A sibling fixture is reached by its service/container name on the private network, e.g. p27-fixture:8027. Kubernetes uses Service/DNS names similarly. This is namespace semantics, not a JMeter DNS bug.

9. Resource limits are part of generator sizing

Chapter 26 measured usable generator capacity. A Docker --cpus/--memory or Kubernetes CPU/memory limit can move that capacity ceiling even when the physical host is idle. Record the container limit and keep Java heap below the memory limit with enough native/metaspace/thread/socket headroom.

10. State checklist before an ephemeral run

State Read-only question
Image/runtime Exact base tag + resolved digest, JMeter SHA/version, final image ID, Docker/kind/kubectl versions?
JMeter/thread Threads/loops/timers/CLI/properties and total count across containers/Pods?
Components/plugins Stock Apache tarball or exact added plugin/JAR hashes?
Inputs Which JMX/data/config are mounted; read-only; hashes match native run?
Protocol/session Target hostname inside namespace, keep-alive/TLS/DNS behavior, service identity?
Resources CPU/memory/PID/read-only root/tmp limits and Chapter 26 generator headroom?
Artifacts Where JTL/log/target events go; are they persistent before deletion?
Credentials/trust No secret in Dockerfile/layer/tag/log; runtime secret source and scope if needed?
Exit state Container/Job exit code, OOMKilled/restarts/deadline, achieved target count?
Validity Configured load equals sum of injectors and evidence proves achieved work without generator/container saturation?

11. Read-only inspection first

PowerShell / portable Docker commands:

docker version
docker info --format "{{json .SecurityOptions}}"

docker pull eclipse-temurin:17.0.20_8-jre-jammy
docker image inspect eclipse-temurin:17.0.20_8-jre-jammy `
  --format "{{json .RepoDigests}}"

docker image ls --digests
docker network ls
docker ps -a

kind version
kubectl version --client
kubectl config current-context

If the current Kubernetes context is not the disposable local cluster you intended, stop. Do not apply a teaching Job to a shared/production cluster.

12. DevOps connection

Ephemeral injectors improve repeatability only when the artifact has a supply chain and the runtime has a contract. Image provenance, immutable inputs, network target identity, resource quotas, secrets, exit status and evidence retention are as important as the JMX itself.

Knowledge check

Does two Pods running a 5-thread JMX mean five or ten configured threads?

Why mount JMX/data read-only?

Why is a tag weaker provenance than a digest/image ID?

Why can a container memory limit invalidate a JMeter test?

Why does 127.0.0.1 fail for a sibling container target?

Next lesson

Build and run the pinned local injector

Lesson 2 verifies Apache JMeter integrity during image build, mounts inputs read-only, persists artifacts, inspects resource/exit state, and proves the identical JMX natively and in Docker.

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.