Skip to content

added real-world examples for podman#516

Open
ritesh-harihar wants to merge 8 commits into
mainfrom
f-add-examples-for-podman
Open

added real-world examples for podman#516
ritesh-harihar wants to merge 8 commits into
mainfrom
f-add-examples-for-podman

Conversation

@ritesh-harihar

@ritesh-harihar ritesh-harihar commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Issue

Summary

Adds a curated, progressive set of example jobs for the Podman driver that takes a user from a single-container "hello world" all the way to a rootless, hardened deployment. Each example is self-contained: a runnable job spec plus a README that explains what it demonstrates, gives exact run/verify steps, and shows the expected output — so a user can run and adapt each one without external guidance.

Previously the jobs directory held a handful of feature-specific specs with no narrative or learning order. This PR adds a guided learning path on top of them (the older specs remain as additional references).

What's included

A new examples/jobs/<NN-name>/ directory per example, each with a *.nomad spec, a README.md, and any supporting templates/. An index README ties them together as an ordered learning path, and the main README links to it (without duplicating the detail).

# Example What you learn Key options
1 Hello World Minimal runnable job image, ports, resources
2 Persistent Storage Stateful data that survives restarts bind-mount volumes (:U), job variable
3 Sidecar / Shared Network Multiple containers, one namespace network_mode = "task:...", lifecycle
4 Service Discovery & Health Register a service, gate on health service (Nomad provider), check
5 Rootless & Hardened Unprivileged, locked-down containers socket, user, cap_drop, readonly_rootfs, security_opt, tmpfs

Testing

Details
  • All 5 examples deployed and verified end-to-end on rootless Podman 5.4 with Nomad native service discovery :
# Job Result
01 hello-world running — PONG
02 persistent-storage running — row survives alloc restart
03 sidecar-network running — proxy responds, direct app port refused
04 service-health running — / text + /health {"status":"ok"}
05 rootless-hardened running on app1 socket — HTTP/1.1 200 OK, RO rootfs + dropped caps
Screenshot 2026-06-18 at 7 03 50 PM
  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

@ritesh-harihar
ritesh-harihar marked this pull request as ready for review June 18, 2026 13:36
@ritesh-harihar
ritesh-harihar requested a review from a team as a code owner June 18, 2026 13:36
@ritesh-harihar ritesh-harihar self-assigned this Jun 18, 2026
@tehut

tehut commented Jun 18, 2026

Copy link
Copy Markdown

This is pretty cool! I haven't worked my way through all of the examples yet but a thought that occurred to me while troubleshooting example #2 is that we should probably include any required plugin configuration in the readme. You mention that we should have the plugin configured for volumes but since the plugin config is short it would be nice to include it in that section of the readme

@tehut tehut left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worked through the rest of the examples today and I only have a single (but repeated) note on the actual tutorial steps. But I have some pretty big feedback on the way each of the example sections are structured.

All of the commands were correct and worked fine but the structure wasn't written as if someone was going to work through them but just sorta generated.

I think the most impactful change would be to rewrite the Verify sections so that each step follows the usual Instruction -> Action -> Expected Result pattern. I did example 1 for you to demonstrate what I mean and how it varies with what's there now.

Comment thread examples/jobs/01-hello-world/README.md
Comment on lines +29 to +66
```sh
# 1. The allocation should be "running".
nomad job status hello-world

# 2. Podman should show the container.
podman ps --filter name=^redis-

# 3. Talk to Redis through the published port. Read the host:port that Nomad
# assigned, then PING it.
addr=$(nomad alloc status -json $(nomad job allocs -json hello-world \
| jq -r '.[0].ID') | jq -r '.Resources.Networks[0].DynamicPorts[0]
| "\(env.NOMAD_IP // "127.0.0.1"):\(.Value)"')

redis-cli -u "redis://${addr}" PING
```

If you don't have `redis-cli` locally, exec into the container instead:

```sh
podman exec -it $(podman ps -qf name=^redis-) redis-cli PING
```

## Expected output

`nomad job status hello-world` shows one allocation in the `running` state:

```
Allocations
ID Node ID Task Group Version Desired Status Created Modified
xxxxxxxx xxxxxxxx cache 0 run running 10s ago 3s ago
```

`podman ps` lists the container with a `redis-server` command and a published
port, and the `PING` returns:

```
PONG
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworked the first example to conform to the general tutorial pattern of expected action-> expected result. And because we're able to show the expected result directly beneath the input I don't think you need the comments to do that and can instead treat them like bulleted instructions to go along with the expected action -> expected result.

I reworked the section as an example but this applies throughout. If there are sections with a single step I think you can probably just remove the Expected Results header but anything with more than one step should be re-written as single threaded.

Suggested change
```sh
# 1. The allocation should be "running".
nomad job status hello-world
# 2. Podman should show the container.
podman ps --filter name=^redis-
# 3. Talk to Redis through the published port. Read the host:port that Nomad
# assigned, then PING it.
addr=$(nomad alloc status -json $(nomad job allocs -json hello-world \
| jq -r '.[0].ID') | jq -r '.Resources.Networks[0].DynamicPorts[0]
| "\(env.NOMAD_IP // "127.0.0.1"):\(.Value)"')
redis-cli -u "redis://${addr}" PING
```
If you don't have `redis-cli` locally, exec into the container instead:
```sh
podman exec -it $(podman ps -qf name=^redis-) redis-cli PING
```
## Expected output
`nomad job status hello-world` shows one allocation in the `running` state:
```
Allocations
ID Node ID Task Group Version Desired Status Created Modified
xxxxxxxx xxxxxxxx cache 0 run running 10s ago 3s ago
```
`podman ps` lists the container with a `redis-server` command and a published
port, and the `PING` returns:
```
PONG
```

Verify

  1. Use nomad job status to verify the job is running
nomad job status hello-world

Allocations
ID        Node ID   Task Group  Version  Desired  Status   Created  Modified
xxxxxxxx  xxxxxxxx  cache       0        run      running  10s ago  3s ago
  1. List all podman containers matching the filter ^redis-
podman ps --filter name=^redis-
<For the sake of symmetry RUN the above command and paste the results here>
  1. Read the dynamic port that Nomad assigned into a variable and use that to then PING the redis server.
$ addr=$(nomad alloc status -json $(nomad job allocs -json hello-world \
  | jq -r '.[0].ID') | jq -r '.Resources.Networks[0].DynamicPorts[0]
  | "\(env.NOMAD_IP // "127.0.0.1"):\(.Value)"')

$ redis-cli -u "redis://${addr}" PING

PONG

Comment thread examples/jobs/03-sidecar-network/README.md Outdated
Comment thread examples/jobs/05-rootless-hardened/README.md Outdated
@ritesh-harihar
ritesh-harihar requested a review from tehut July 17, 2026 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants