Chapter 02Lesson 02~120 minutes

Jenkins LTS Installation, Java 21/25 Runtime Planning, Packages, Containers, and Initial Setup: Guided Hands-On Workflow and Core Operations

Install Jenkins 2.568.3 LTS in a disposable local container, compare native package ownership, capture version/runtime/image/storage evidence, and prove persistent state across replacement.

InstallationJenkins LTSJava 21/25JENKINS_HOMEEvidence-first

Learning objectives

  • Compare a host-package installation with an official-container installation without mixing their state ownership models.
  • Preflight Java, Docker, port availability, storage, and network binding before launching a controller.
  • Run Jenkins 2.568.3 LTS locally with persistent storage and collect version/runtime/image evidence.
  • Complete the setup wizard without retaining the initial admin password and capture the installed plugin baseline safely.
  • Replace the controller container and prove that the named volume preserves configured state.

1. Lab scenario and safety boundary

You are creating a disposable training controller named jenkins-ch02-controller. It must be reachable only from the local machine on port 8080, store state in a named volume called jenkins-ch02-home, run the official Jenkins 2.568.3 LTS Java 21 image, and survive container deletion/recreation.

Lab boundary: do not use a production controller, company credentials, public DNS, a public firewall rule, or a host directory containing unrelated data. The setup password is a secret—read it locally when needed, then do not copy it into the evidence packet.

2. First compare the two common installation ownership models

Concern Native package Official container
Jenkins bytes Package repository/version installed on host Image tag plus resolved digest
Java Host Java installation Java included in selected Jenkins image variant
Service lifecycle systemd / Windows Service Container runtime
Persistent home Host directory, commonly package-defined Explicit volume/bind mount to /var/jenkins_home
Upgrade action Package upgrade with host/service considerations Pull/test new image then replace container against same validated home copy
Rollback Package/version + data compatibility plan Previous image is easy; data rollback is not automatically safe
Best lab fit Changes host package/service state Easy disposal; clearer separation of process vs data

3. Native-package path: inspect before you install

On Debian/Ubuntu, current Jenkins documentation recommends installing Java first, adding the stable Jenkins repository, then installing the jenkins package. These commands are shown for understanding; the mandatory lab continues with Docker so it does not alter your host package database.

java -version
# Current official Debian/Ubuntu baseline uses OpenJDK 21.
sudo apt update
sudo apt install fontconfig openjdk-21-jre

# Stable Jenkins repository key and source (re-check before use):
sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc \
  https://pkg.jenkins.io/debian-stable/jenkins.io-2026.key
echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/" | \
  sudo tee /etc/apt/sources.list.d/jenkins.list >/dev/null
sudo apt update
apt-cache policy jenkins

Notice the final command: inspect the candidate version before mutating the host. If you later install the package, also record the systemd service user, home directory, listener configuration, and package version.

4. Container-lab preflight: prove prerequisites before launch

docker version
docker info --format 'Server={{.ServerVersion}} OS={{.OperatingSystem}}'

# Port 8080 should not already be owned by another service.
# PowerShell: Get-NetTCPConnection -LocalPort 8080 -ErrorAction SilentlyContinue
# Linux:      ss -ltnp | grep ':8080 ' || true

docker pull jenkins/jenkins:2.568.3-jdk21
docker image inspect jenkins/jenkins:2.568.3-jdk21 \
  --format 'Id={{.Id}} RepoDigests={{json .RepoDigests}}'
docker run --rm jenkins/jenkins:2.568.3-jdk21 java -version
Expected: Docker is healthy, port 8080 is available for the lab, the image pull succeeds, RepoDigests is recorded, and the container reports Java 21. Stop here if any prerequisite is not true.

5. Create persistent state and start the controller safely

docker volume create jenkins-ch02-home

docker run --name jenkins-ch02-controller --detach \
  --publish 127.0.0.1:8080:8080 \
  --volume jenkins-ch02-home:/var/jenkins_home \
  jenkins/jenkins:2.568.3-jdk21

docker ps --filter name=jenkins-ch02-controller
docker inspect jenkins-ch02-controller \
  --format 'Image={{.Image}} User={{.Config.User}} Mounts={{json .Mounts}} Ports={{json .HostConfig.PortBindings}}'

Do not publish port 50000 for this chapter. Later agent lessons can choose inbound/WebSocket/SSH connectivity deliberately. Opening extra ports “because tutorials do” obscures the network boundary.

6. Read startup evidence before opening the UI

docker logs --tail 120 jenkins-ch02-controller

# Confirm the controller responds locally.
curl -I http://127.0.0.1:8080/login

Startup logs should show normal initialization and the one-time unlock instructions. Do not copy the generated password into retained logs, issue trackers, screenshots, or course evidence. If you need the password, obtain it directly from the local container and paste it only into the local setup form:

docker exec jenkins-ch02-controller \
  cat /var/jenkins_home/secrets/initialAdminPassword
Secret handling: the command intentionally displays a bootstrap secret on your local terminal. Do not include its output in screenshots or evidence. After creating the real lab administrator, treat the bootstrap value as sensitive historical material.

7. Complete the setup wizard without turning it into an unreviewed plugin baseline

  1. Browse to http://127.0.0.1:8080.
  2. Enter the locally retrieved unlock value.
  3. For this beginner lab, choose Install suggested plugins. This is convenience, not a fixed production baseline.
  4. Create a disposable administrator account with a unique lab password. Do not reuse a real password.
  5. Keep the Jenkins URL local for this exercise.

After setup, go to Manage Jenkins → Plugins → Installed plugins and record plugin names and versions in your notes. The exact suggested set evolves, so the evidence packet records what was actually installed rather than pretending the recommendation is immutable.

8. Verify controller identity and state after setup

docker exec jenkins-ch02-controller java -version
docker inspect jenkins-ch02-controller --format 'Image={{.Image}}'
docker volume inspect jenkins-ch02-home

curl -s -D - -o /dev/null http://127.0.0.1:8080/login | head
Core

In the Jenkins UI, record the exact Jenkins version shown in system/about information; expected 2.568.3.

Java

Record Java 21 from inside the controller container.

Image

Record image ID and pulled RepoDigest.

Storage

Record named volume and mount to /var/jenkins_home.

Exposure

Record host binding 127.0.0.1:8080 only.

Plugins

Record installed plugin names/versions, not credentials or configuration secrets.

9. The proof: replace the process, keep the state

# Stop and remove only the lab container. Keep the named volume.
docker stop jenkins-ch02-controller
docker rm jenkins-ch02-controller

# Recreate a new container using the same exact image tag and volume.
docker run --name jenkins-ch02-controller --detach \
  --publish 127.0.0.1:8080:8080 \
  --volume jenkins-ch02-home:/var/jenkins_home \
  jenkins/jenkins:2.568.3-jdk21

docker logs --tail 80 jenkins-ch02-controller

Reload the UI. Your administrator and completed setup state should still exist because they were stored in the named volume. This is the chapter’s central before/after observation: container identity changed, durable controller state did not.

10. Challenge: choose the failed layer

Suppose a teammate reports “Jenkins disappeared after I upgraded the container.” You inspect Docker and find a brand-new container using the right image, but it was started without the old volume. Which layer failed?

The Jenkins core and Java runtime may be perfectly healthy. The failure is persistent-state attachment. The least destructive correction is to stop the new disposable container and reattach the known correct home volume—after verifying its identity—rather than reinstalling plugins or recreating users.

11. Cleanup options

# Keep the lab for Lesson 3/4 if you want continuity.
# Otherwise remove the container first:
docker stop jenkins-ch02-controller
docker rm jenkins-ch02-controller

# Destructive: remove ONLY the known disposable training volume when you no longer need the state.
docker volume rm jenkins-ch02-home
Destructive step: deleting the volume deletes this lab controller state. Verify the exact name jenkins-ch02-home before removal. Never substitute an ambiguous “latest” volume or wildcard.

12. Summary

  • Preflight Java/runtime, port, storage, and distribution identity before launch.
  • The mandatory lab uses a loopback-only Jenkins 2.568.3/JDK21 controller with an explicit named home volume.
  • Setup credentials stay local; retained evidence records versions and state, not passwords.
  • Plugin recommendations are not a frozen bill of materials—capture the versions actually installed.
  • Container replacement proves process ephemerality and volume persistence independently.
Next lesson

Configuration, Design Choices, and Tradeoffs

Compare LTS versus weekly, package versus container, Java 21 versus 25, direct HTTP versus reverse proxy, and tag versus digest using explicit operational criteria.

Knowledge check

Why inspect RepoDigests immediately after pulling the Jenkins image?

What should remain after docker rm jenkins-ch02-controller if persistence was configured correctly?

Why is “Install suggested plugins” not a reproducible plugin baseline by itself?

Why does the lab publish 127.0.0.1:8080:8080 instead of 8080:8080?

A recreated container shows the setup wizard again. What should you inspect before reconfiguring anything?

Official references and version notes

Version and compatibility note

Version-sensitive statements in this lesson were rechecked on 2026-09-14. The lab baseline is Jenkins 2.568.3 LTS on Java 21; Jenkins 2.568.3 is also tested with Java 25. Current Jenkins LTS releases in this line require Java 21 or 25. The disposable container examples pin the human-readable image tag jenkins/jenkins:2.568.3-jdk21 and require learners to record the locally resolved RepoDigest after pulling it. Re-check the LTS changelog, Java policy, image tags/digests, package signing key, and security advisories when regenerating this lesson.

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.