gepardec logo

Training Containerization

Gepardec who?

That’s us

  • office: vienna / linz

  • size: ~ 40 people

  • we do what we love..

    • custom software solution

    • cloud transformation

    • DevOps automation

team

openshift

rh premium partner

jboss

How we teach

  • Gepardec believes in learning by doing

  • The training is lab driven

  • Work together!

  • Ask questions at any time

Session Logistics

  • 1 days duration

  • Mostly exercises

  • Regular breaks

Assumed knowledge and requirements

Your lab environment

  • You have been given an instance for use in the exercises

  • Ask the instructor for the credentials if you don’t have them already

Training learning objectives

By the end of this training, trainess will be able to

  • Asses the advantages of a containerized software development & deployment

  • Use container engine features necessary for running containerized applications

Virtualization vs Containerization

What we want

Ideal software should

  • be modular and flexible (DEVs)

  • be easy to migrate (DevOps)

  • be easy to scale, monitor and lifecycle (OPS)

  • mitigate vulnerabilities (Security)

  • and run cheap (business)

Virtualization

pre container

Containerization

post container

Rapid development

component upgrade

Containers can be removed and replaced with a minimum of impact on their neighbors, increasing developer choice and speed.

Smooth migration

component migration

Simple scale & maintenance

component scalability

Containers have private system resources, so a compromise in one does not affect the rest.

Secure by default

component isolation

Containers have private system resources, so a compromise in one does not affect the rest.

Application density

component density

Containers save datacenter costs by running many more application instances than virtual machines can on the same physical hosts.

Containerization basics

Learning objectives

By the end of this module, trainees will be able to

  • Explain containers as host processes isolated with namespaces and control groups

  • Verify PID namespace and lifecycle behavior using Docker CLI commands

  • Use key Docker commands to inspect, run, stop, remove, and troubleshoot containers

Containers are processes

Containers are processes sandboxed by

  • Kernel namespaces

  • Control groups

  • Root privilege and syscall restrictions (Linux)

Linux kernel namespaces

  • DEFAULT

    • Process IDs

    • Network stacks

    • Inter-process communications

    • Mount points

    • Hostnames

  • OPTIONAL

    • User IDs

Linux PID kernel namespace

pid tree

Linux isolation features

  • Control groups: limit memory & CPU

  • Root privilege management: allowlist Linux capabilities

  • System call management: allowlist available system calls (seccomp)

  • Linux Security Modules: mandatory filesystem access control

task Instructor demo: Process isolation

See the demo

  • Process isolation

in the exercise book

task Exercise: Container Basics

Work through

  • Running and inspecting a container

  • Interactive containers

  • Detached containers and logging

  • Starting, stopping, inspecting and deleting containers

In the exercise book.

Container lifecycle

container lifecycle

Container logs

  • STDOUT and STDERR for a container process

  • docker container logs <container_name>

  • docker container logs -f --tail 50 <container_name>

PID 1 and graceful shutdown

  • PID 1 receives stop signals sent by the runtime

  • Well-behaved applications should handle SIGTERM and exit cleanly

  • Forced termination (docker container kill) sends SIGKILL immediately

Container basics takeaways

  • Single process constrained by kernel namespaces, control groups and other Linux technologies

  • Private & ephemeral filesystem and data

  • PID 1 lifecycle, logging, and signal handling directly affect operability

Further reading

Container images

Learning objectives

By the end of this module, trainees will be able to:

  • Explain image layers, copy-on-write, and the writable container layer

  • Build reproducible images with Dockerfiles / Containerfiles

  • Use cache-aware build patterns for faster iteration

  • Apply production-ready image practices for security and operability

  • Correctly tag, namespace, and publish images to registries

What are container images?

  • A container image is a packaged filesystem plus metadata

  • Built from a stack of immutable layers

  • Starts from a base image

  • Each build instruction can create a new layer

image layered fs

Sharing layers

image shared layers

The writable container layer

image container layer

Images: copy on write

image copy on write

Linux containers: Union FS

image union fs

Creating images

Three common methods:

  • Build from a Dockerfile / Containerfile (recommended)

  • Commit a running container (docker container commit) for quick experimentation only

  • Import a tarball as a base image (docker image import) for special cases

Committing container changes

  • docker container commit stores current writable layer as a new image layer

  • Pro: quick for interactive exploration

  • Con: difficult to audit, reproduce, and automate

  • Guidance: avoid for production pipelines

Dockerfiles / Containerfiles

  • Machine-readable build recipe

  • Documents image construction step-by-step

  • Enables CI/CD automation and repeatability

  • FROM defines the base image

  • RUN, COPY, ADD, ENV, and others define layers/metadata

# Comments start with '#'
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends wget \
    && rm -rf /var/lib/apt/lists/*
COPY data /myapp/data

task Instructor demo: Creating images

See the demo:

  • Creating images

in the exercise book.

task Exercise: Creating images

Work through:

  • Interactive image creation

  • Creating images with Dockerfiles (1/2)

in the exercise book.

Build cache fundamentals

image build cache

Cache reuse depends on:

  • The instruction itself

  • Build arguments and environment that affect the instruction

  • Files from the build context used by that instruction

  • The parent layer digest

CMD and ENTRYPOINT

  • Every container runs a PID 1 process

  • ENTRYPOINT defines the executable

  • CMD defines default arguments (or default command if no ENTRYPOINT)

  • Runtime command can override CMD

  • --entrypoint can override ENTRYPOINT

SAMPLE

FROM alpine:3.22
RUN apk add --no-cache yq
ENTRYPOINT ["yq"]

Shell vs exec form

# Shell form (runs via /bin/sh -c)
CMD java -jar /app/app.jar

# Exec form (preferred for ENTRYPOINT/CMD in production)
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
CMD ["--server.port=8080"]

task Exercise: Dockerfiles (2/2)

Work through:

  • Creating images with Dockerfiles (2/2)

in the exercise book.

COPY and ADD

COPY is the default choice for local files.

COPY <src> <dest>

Use ADD only when you explicitly need:

  • Auto-extracting local tar archives

  • Fetching from URL sources (if policy allows)

# when app.tar.gz contains index.js and config.json
# with
ADD app.tar.gz /app/
# result would be: /app/index.js and /app/config.json
# with
COPY app.tar.gz /app/
# result would be: /app/app.tar.gz

Build context and .dockerignore

.dockerignore is critical for fast and safe builds.

Benefits:

  • Reduces build context transfer size

  • Prevents accidental inclusion of secrets and local artifacts

  • Improves cache stability

Example:

.git
node_modules
*.log
.env
target
dist

Advanced image construction goals

Build images that are:

  • Lightweight

  • Secure

  • Fast to build

  • Easy to operate and debug

The scratch image

  • Special empty base image

  • Not pulled from a registry

  • Useful for minimal final images

  • Common in multi-stage builds

FROM scratch
COPY hello /hello
ENTRYPOINT ["/hello"]

Multi-stage builds (1/2)

Naive single-stage C build:

FROM alpine:3.20
RUN apk add --no-cache build-base
WORKDIR /app
COPY hello.c /app
RUN gcc -Wall hello.c -o /app/hello
CMD ["/app/hello"]

Multi-stage builds (2/2)

Improved multi-stage build:

# Build stage
FROM alpine:3.20 AS build
RUN apk add --no-cache build-base
WORKDIR /src
COPY hello.c .
RUN gcc -Wall hello.c -o /out/hello

# Runtime stage
FROM alpine:3.20
COPY --from=build /out/hello /app/hello
ENTRYPOINT ["/app/hello"]

Build targets

Use named stages and optional build target selection.

FROM base-image AS base
# ...

FROM toolchain-image AS test
# ...

FROM runtime-image
COPY --from=test /out/app /app/app
# Build final image (last stage)
docker image build -t myapp:1.0 .

# Build an intermediate stage by name
docker image build --target test -t myapp:test .

task Exercise: Multi-stage builds

Work through:

  • Multi-stage builds

in the exercise book.

Security baseline for Dockerfiles

  • Start from trusted, maintained base images

  • Prefer minimal runtime images

  • Run as non-root user (USER)

  • Avoid embedding secrets in image layers

  • Keep package lists/caches out of final image

Example:

FROM node:22-bookworm-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN useradd -r -u 10001 appuser && chown -R appuser:appuser /app
USER appuser
CMD ["node", "server.js"]

HEALTHCHECK and operability

HEALTHCHECK lets orchestrators detect unhealthy containers.

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD wget -qO- http://localhost:8080/health || exit 1

Guidance:

  • Keep checks lightweight

  • Verify critical readiness path

  • Log to stdout/stderr for observability

Development vs production layering

Cache-aware development pattern:

FROM python:3.12-slim
WORKDIR /app
# Copying dependency manifests first avoids re-installing dependencies on every code change.
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]

Updates and patching strategy

  • Rebuild from Dockerfile when dependencies or base image change

  • Avoid layering ad-hoc patch commands over outdated images

  • Prefer immutable references in CI (image@sha256:…​) for reproducibility

Image tags and digests

  • Tags are mutable pointers (myapp:1.2.3, myapp:latest)

  • Digests are immutable content addresses (myapp@sha256:…​)

  • Recommended: publish semantic version tags plus immutable digest references

# Tag examples
docker image build -t myorg/myapp:1.2.3 -t myorg/myapp:latest .

# Pull immutable image by digest
docker image pull myorg/myapp@sha256:abc123...

Dockerfile command roundup

  • FROM: base image

  • RUN: execute build-time commands

  • COPY: copy files into image

  • ADD: specialized copy behavior

  • ENTRYPOINT and CMD: default runtime behavior

  • USER: set runtime user

  • HEALTHCHECK: define container health probe

Image namespaces

Images can be addressed as:

  • Root namespace (nginx, redis) on default registries

  • User/org namespace (myorg/myapp:1.2.3)

  • Fully qualified registry path (registry.example.com/myorg/myapp:1.2.3)

Multi-platform builds (buildx)

Modern teams often publish for multiple architectures.

# Example: build and push amd64 + arm64
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t registry.example.com/myorg/myapp:1.2.3 \
  --push .

Vulnerability scanning in CI/CD

Integrate image scanning before deployment.

Example tools:

  • Docker Scout

  • Trivy

  • Grype

Sharing container images

Typical workflow:

  • Build image locally or in CI

  • Tag with namespace and version

  • Authenticate to registry

  • Push image

  • Deploy by version tag and/or digest

docker image tag myapp:1.2.3 registry.example.com/team/myapp:1.2.3
docker image push registry.example.com/team/myapp:1.2.3

task Exercise: Managing container images

Work through:

  • Managing images

in the exercise book.

Production-ready Dockerfile checklist

  • Use a maintained base image (pin digest when needed)

  • Keep build context small with .dockerignore

  • Use multi-stage builds to remove compilers/SDKs from runtime

  • Run as non-root with USER

  • Keep secrets out of layers (BuildKit secrets)

  • Add HEALTHCHECK when meaningful

  • Scan images in CI/CD

  • Tag consistently (version, git-sha, optional latest)

Container image takeaways

  • Container images are built from read-only layers plus metadata.

  • Dockerfiles provide reproducible, auditable image builds.

  • Layering and cache strategy strongly affect developer feedback cycle.

  • Security and operability practices are required for production images.

  • Tags are mutable references; digests are immutable content addresses.

Further reading

Container Volumes

Learning objectives

By the end of this module, trainees will be able to

  • Define a volume and identify its primary use cases

  • Describe advantages and potential security risks of mounting volumes and host directories

Volume use cases

Volumes provide a R/W path separate from the layered filesystem.

  • Mount data at container startup

  • Persist data when a container is deleted

  • Share data between containers

  • Speed up I/O by circumventing the union filesystem

Basic volumes

  • Named: managed by Docker; filesystem independent; user-specified identifier

  • Anonymous: managed by Docker; filesystem independent; randomly-generated identifier

  • Host mounted: mount a specific path on the host; DIY management

task Instructor demo: Volumes

See the demo

  • Basic Volume Usage

in the exercise book.

Volumes in Containerfile

  • VOLUME instruction creates a mount point

  • Can specify arguments in a JSON array or string

  • Cannot map volumes to host directories

  • Volumes are initialized when the container is executed

FROM nginx:latest
...
# string example
VOLUME /myvolume

# string example with multiple volumes
VOLUME /www/website1 /www/website2

# JSON example
VOLUME ["myvol1", "myvol2"]
...

Volumes and security

  • Point of ingress to the host and other containers

  • Don’t mount things unnecessarily

  • Use the :ro flag whenever possible

  • Linux: in-memory tmpfs mounts available

task Exercise: Volume use cases

Work through

  • Database Volumes

in the exercise book.

Container volumes takeaways

  • Volumes persist data beyond the container lifecycle

  • Volumes bypass the copy-on-write system (better for write-heavy containers)

Further reading

Docker system commands

Learning objectives

By the end of this module, trainees will be able to

  • Execute cleanup commands

  • Locate Docker system information

Cleanup commands

$ docker system df
TYPE           TOTAL    ACTIVE   SIZE        RECLAIMABLE
Images         39       2        9.01 GB     7.269 GB (80%)
Containers     2        2        69.36 MB    0 B
  • docker system prune

more limited…​

  • docker image prune [--filter "foo=bar"]

  • docker container prune [--filter "foo=bar"]

  • docker volume prune [--filter "foo=bar"]

  • docker network prune [--filter "foo=bar"]

Inspect the system

$ docker system info
Containers: 2
 Running: 2
 Paused: 0
 Stopped: 0
Images: 105
Server Version: 17.03.0-ee
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host ipvlan macvlan null overlay
Swarm: active
 NodeID: ybmqksh6fm627armruq0e8id1
 Is Manager: true
 ClusterID: 2rbf1dv6t5ntro2fxbry6ikr3
 Managers: 1
 Nodes: 1
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1

System events

$ docker system events
2017-01-25T16:57:48.553596179-06:00 container create 30eb630790d44052f26c1081...
2017-01-25T16:57:48.556718161-06:00 container attach 30eb630790d44052f26c1081...
2017-01-25T16:57:48.698190608-06:00 network connect de1b2b40f522e69318847ada3...
2017-01-25T16:57:49.062631155-06:00 container start 30eb630790d44052f26c1081d...
2017-01-25T16:57:49.164526268-06:00 container die 30eb630790d44052f26c1081dbf...
2017-01-25T16:57:49.613422740-06:00 network disconnect de1b2b40f522e69318847a...
2017-01-25T16:57:49.815845051-06:00 container destroy 30eb630790d44052f26c108...

Generate events with docker container run --rm alpine echo 'Hello world'

task Exercise: System commands

Work through

  • Cleaning up Docker resources

  • Inspecting commands

in the exercise book.

Discussion

  • What is the origin of dangling container image layers?

  • What are potential pitfalls automating system cleanup, and how can we avoid them?

  • Questions?

Further reading

Containerization fundamentals conclusion: Any app, anywhere

  • Containers are isolated processes

  • Container images provide filesystem for containers

  • Volumes persist data

Wrap up - Quarkus Hello-world

task Exercise instructions

  • Goal: Build a docker image that runs a Java application

  • Find the fat jar hello-world-<version>-runner.jar in the zip you downloaded

  • Run the application with java –jar hello-world-<version>-runner.jar.

  • Try it out via http://localhost:8080/

Considerations:

  • What container image is suitable?

  • Do you need CMD, or ENTRYPOINT, or maybe both?

  • If you run two containers, what do need to take care of?

Solution

Sample Containerfile

FROM alpine/java
WORKDIR /data
EXPOSE 8080
COPY build/libs/hello-world-runner.jar hello-world-runner.jar
CMD ["-jar", "hello-world-runner.jar"]
ENTRYPOINT ["java"]

Solution commands

  • docker build -t hello_world .

  • docker run -d -p 8080:8080 hello_world

Container networking basics

Learning objectives

By the end of this module, trainees will be able to

  • Describe Docker’s container network model and its security implications

  • Describe the basic technologies that underwrite single host networks

  • Understand how Docker manipulates a host’s firewall rules to control container traffic

The container network model

container networking model

Linux: Default single-host network

linux single host network

Linux: Default container networking

linux default container networking

Linux: User-defined bridges & firewalls

linux custom container networking

Exposing container ports

  • Containers have no public IP address by default.

  • Can forward host port → container port

  • Mapping created manually or automatically.

  • Port mappings visible via docker container ls or docker container port

task Instructor demo: Single host networks

See the demo

  • Single host networks

in the exercise book.

task Exercise: Single host networks

Work through

  • Introduction to Container Networking

  • Container Port Mapping

in the exercise book.

Container networking takeaways

  • Single host networks follow the container networking model:

    • Sandbox: Network namespaces

    • Endpoint: veth (Linux)

    • Network: bridge (Linux)

  • Containers resolve each other by DNS lookup when named and attached to custom networks

  • Docker software defined networks are firewalled from each other by default

Further reading

Introduction to container compose

Learning objectives

By the end of this module, trainees will be able to

  • Design scalable Docker services

  • Leverage Docker’s built-in service discovery mechanism

  • Write a compose file describing an application

Distributed application architecture

  • Applications consisting of one or more containers across one or more nodes

  • Docker Compose facilitates multi-container design on a single node

Container services

  • Goal: declare and (re)configure many similar containers all at once

  • Goal: scale apps by adding containers seamlessly

  • A service defines the desired state of a group of identically configured containers

  • Docker provides transparent service discovery for services

Service discovery

service discovery

Services are assigned a Virtual IP which spreads traffic out across the underlying container automatically.

Our application: Dockercoins

dockercoins flow

task Instructor demo: Docker Compose

See the demo

  • Docker Compose

in the exercise book.

task Exercise: Compose apps

Work through

  • Starting a Compose App

  • Scaling a Compose App

in the exercise book.

Container Compose takeaways

  • Docker Compose makes single node orchestration easy

  • Compose services make scaling applications easy

  • Bottleneck identification important

  • Syntactically: compose.yaml (or docker-compose.yml) + API

Further reading

Wrap-up Container Compose - SonarQube

SonarQube

sonarqube

task Exercise: Instructions

  • Set up a SonarQube server that listens on port 9000

  • Connect it to a persistent database

  • Use PostgreSQL and persist its data on the host filesystem using volumes

  • Verify that the data is persistent (create user and delete the container)

  • Hint: use Docker Compose

Solution

version: "3"

services:
  sonarqube:
    image: sonarqube:lts-community
    depends_on:
      - sonar_db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://sonar_db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    ports:
      - "9001:9000"
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_temp:/opt/sonarqube/temp

  sonar_db:
    image: postgres:13
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonar
    volumes:
      - sonar_db:/var/lib/postgresql
      - sonar_db_data:/var/lib/postgresql/data

volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  sonarqube_temp:
  sonar_db:
  sonar_db_data:

Introduction to Kubernetes

Learning objectives

By the end of this module, trainees will be able to

  • Explain what Kubernetes is and when to use it

  • Distinguish between Pods, Deployments, Services, and Secrets

  • Read and apply a basic Kubernetes manifest

  • Deploy and verify a simple application on Kubernetes

Why Kubernetes?

  • Docker Compose is excellent for multi-container apps on one host

  • Kubernetes is for orchestrating containers across a cluster of nodes

  • It adds scheduling, self-healing, service discovery, and rolling updates

Kubernetes basics

  • A cluster consists of control-plane and worker nodes

  • The API server is the central interface

  • Desired state is defined in YAML manifests

  • Controllers continuously reconcile actual state to desired state

Core object: Pod

  • Smallest deployable unit in Kubernetes

  • Usually one main container per Pod

  • All containers in a Pod share network namespace and volumes

Core object: Deployment

  • Manages a ReplicaSet of Pods

  • Defines image, replicas, and rollout strategy

  • Supports rolling updates and easy rollbacks

  • Recreates Pods automatically if they fail

Core object: Service

  • Stable virtual endpoint for a dynamic Pod set

  • Selects Pods by labels

  • Common types:

    • ClusterIP for internal traffic

    • NodePort for quick external access

    • LoadBalancer for cloud-managed ingress

Core object: Secret

  • Stores sensitive values (passwords, tokens, keys)

  • Inject into Pods via environment variables or mounted files

  • Should not be hard-coded in images or plain manifests

task Instructor demo: Kubernetes app deployment

See the demo

  • Kubernetes basics

in the instructor demo book.

Further reading

Containerization Training

Please take our feedback survey

Get in touch: office@gepardec.com

#WECKDENGEPARDENINDIR