---
layout: docs
page_title: 'Drivers: podman'
description: >-
  The Podman task driver uses podman (https://podman.io/) for containerizing
  tasks.
---

# Podman Task Driver

Name: `podman`

Homepage: https://github.com/hashicorp/nomad-driver-podman

The Podman task driver plugin for Nomad uses the [Pod Manager (podman)][podman]
daemonless container runtime for executing Nomad tasks. Podman supports OCI
containers and its command line tool is meant to be [a drop-in replacement for
Docker's][podman-cli].

Due to Podman's similarity to Docker, the example job created by
[`nomad init -short`][nomad-init] is easily adapted to use Podman instead:

```hcl
job "redis" {
  datacenters = ["dc1"]
  type        = "service"

  group "cache" {
    network {
      port "redis" { to = 6379 }
    }

    task "redis" {
      driver = "podman"

      config {
        image = "docker://redis"
        ports = ["redis"]
      }
    }
  }
}
```

Refer to the project's [homepage][homepage] for details.

## Client Requirements

The Podman task driver is not builtin to Nomad. It must be
[downloaded][downloaded] onto the client host in the configured plugin
directory.

- [Nomad][nomad_download] 0.12.9+
- Linux host with [`podman`][podman] installed
- For rootless containers you need a system supporting cgroup V2 and a few
  other things, follow [this tutorial][rootless_tutorial].

You need a 3.0.x podman binary and a system socket activation unit, refer to
[https://www.redhat.com/sysadmin/podmans-new-rest-api](https://www.redhat.com/sysadmin/podmans-new-rest-api).

Nomad agent, `nomad-driver-podman` and `podman` will reside on the same client,
so you do not have to worry about the `ssh` aspects of the Podman api.

Ensure that Nomad can find the plugin, refer to [`plugin_dir`][plugin_dir].

## Capabilities

The `podman` driver implements the following [capabilities](/docs/internals/plugins/task-drivers#capabilities-capabilities-error).

| Feature              | Implementation          |
| -------------------- | ----------------------- |
| `nomad alloc signal` | true                    |
| `nomad alloc exec`   | false                   |
| filesystem isolation | image                   |
| network isolation    | host, group, task, none |
| volume mounting      | none                    |

## Task Configuration

- `args` - (Optional) A list of arguments to the optional command. If no
  [`command`] is specified, the arguments are passed directly to the container.

  ```hcl
  config {
    args = [
      "arg1",
      "arg2",
    ]
  }
  ```

- `auth` - (Optional) Authenticate to the image registry using a static
  credential.

  ```hcl
  config {
    image = "your.registry.tld/some/image"
    auth {
      username = "someuser"
      password = "sup3rs3creT"
    }
  }
  ```

- `cap_add` - (Optional) A list of Linux capabilities as strings to pass to
  `--cap-add`.

  ```hcl
  config {
    cap_add = [
      "SYS_TIME"
    ]
  }
  ```

- `cap_drop` - (Optional) A list of Linux capabilities as strings to pass to
  `--cap-drop`.

  ```hcl
  config {
    cap_drop = [
      "MKNOD"
    ]
  }
  ```

- `command` - (Optional) The command to run when starting the container.

  ```hcl
  config {
    command = "some-command"
  }
  ```

- `devices` - (Optional) A list of `host-device[:container-device][:permissions]`
  definitions. Each entry adds a host device to the container. Optional
  permissions can be used to specify device permissions, it is a combination of
  `r` for read, `w` for write, and `m` for `mknod(2)`. Refer to Podman's
  documentation for more details.

  ```hcl
  config {
    devices = [
      "/dev/net/tun"
    ]
  }
  ```

- `entrypoint` - (Optional) The entrypoint for the container. Defaults to the
  `entrypoint` set in the image.

  ```hcl
  config {
    entrypoint = "/entrypoint.sh"
  }
  ```

- `force_pull` - (Optional) `true` or `false` (default). Always pull the latest
  image on container start.

  ```hcl
  config {
    force_pull = true
  }
  ```

- `hostname` - (Optional) The hostname to assign to the container. When
  launching more than one of a task (using [`count`]) with this option set,
  every container the task starts will have the same hostname.

- `image` - The image to run. Accepted transports are `docker` (default if
  missing), `oci-archive` and `docker-archive`. Images referenced as
  [short-names] will be treated according to user-configured preferences.

  ```hcl
  config {
    image = "docker://redis"
  }
  ```

- `init` - (Optional) Run an `init` inside the container that forwards signals
  and reaps processes.

  ```hcl
  config {
    init = true
  }
  ```

- `init_path` - (Optional) Path to the `container-init` binary.

  ```hcl
  config {
    init = true
    init_path = "/usr/libexec/podman/catatonit"
  }
  ```

- `labels` - (Optional) Set labels on the container.

  ```hcl
  config {
    labels = {
      "nomad" = "job"
    }
  }
  ```

- `logging` - (Optional) Configure logging. Also refer to the plugin option
  [`disable_log_collection`].

    - `driver = "nomad"` - (Default) Podman redirects its combined
    `stdout/stderr` logstream directly to a Nomad `fifo`. Benefits of this
    mode are: zero overhead, don't have to worry about log rotation at system
    or Podman level. Downside: you cannot easily ship the logstream to a log
    aggregator plus `stdout/stderr` is multiplexed into a single stream.

    ```hcl
    config {
      logging = {
        driver = "nomad"
      }
    }
    ```

    - `driver = "journald"` - The container log is forwarded from Podman to the
    `journald` on your host. Next, it's pulled by the Podman API back from the
    journal into the Nomad `fifo` (controllable by [`disable_log_collection`]).
    Benefits: all containers can log into the host journal, you can ship a
    structured stream including metadata to your log aggregator. No log
    rotation at Podman level. You can add additional tags to the journal.
    Drawbacks: a bit more overhead, depends on Journal (will not work on WSL2).
    You should configure some rotation policy for your Journal. Ensure you're
    running Podman 3.1.0 or higher because of bugs in older versions.

    ```hcl
    config {
      logging = {
        driver = "journald"
        options = [
          {
            "tag" = "redis"
          }
        ]
      }
    }
    ```

- `memory_reservation` - (Optional) Memory soft limit (units = `b` (bytes), `k`
  (kilobytes), `m` (megabytes), or `g` (gigabytes)).

  After setting memory reservation, when the system detects memory contention
  or low memory, containers are forced to restrict their consumption to their
  reservation. So you should always set the value below `--memory`, otherwise
  the hard limit will take precedence. By default, memory reservation will be
  the same as memory limit.

  ```hcl
  config {
    memory_reservation = "100m"
  }
  ```

- `memory_swap` - (Optional) A limit value equal to memory plus swap. The swap
  limit should always be larger than the [memory value][memory-value]. Unit can
  be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you
  don't specify a unit, `b` is used. Set `LIMIT` to `-1` to enable unlimited
  swap.

  ```hcl
  config {
    memory_swap = "180m"
  }
  ```

- `memory_swappiness` - Tune a container's memory swappiness behavior. Accepts
  an integer between `0` and `100`.

  ```hcl
  config {
    memory_swappiness = 60
  }
  ```

- `network_mode` - (Optional) Set the [network mode][network-mode] for the
  container. By default the task uses the network stack defined in the task
  group [`network`][nomad_group_network] stanza. If the groups network behavior
  is also undefined, it will fallback to `bridge` in rootful mode or
  `slirp4netns` for rootless containers.

  - `bridge` - (Default for rootful) Create a network stack on the default
  Podman bridge.
  - `container:id` - Reuse another container's network stack.
  - `host` - Use the Podman host network stack. Note: the host mode gives the
  container full access to local system services such as D-bus and is therefore
  considered insecure.
  - `none` - No networking.
  - `slirp4netns` - (Default for rootless) Use `slirp4netns` to create a user
  network stack. Podman currently does not support this option for rootful
  containers ([issue][slirp-issue]).
  - `task:name-of-other-task`: Join the network of another task in the same
  allocation.

  ```hcl
  config {
    network_mode = "bridge"
  }
  ```

- `ports` - (Optional) Forward and expose ports. Refer to
  [Docker driver configuration][nomad_driver_ports] for details.

- `sysctl` - (Optional) A key-value map of `sysctl` configurations to set to
  the containers on start.

  ```hcl
  config {
    sysctl = {
      "net.core.somaxconn" = "16384"
    }
  }
  ```

- `tmpfs` - (Optional) A list of `/container_path` strings for `tmpfs` mount
  points. Refer to `podman run --tmpfs` options for details.

  ```hcl
  config {
    tmpfs = [
      "/var"
    ]
  }
  ```

- `tty` - (Optional) `true` or `false` (default). Allocate a pseudo-TTY for the
  container.

- `user` - (Optional) Run the command as a specific user/uid within the
  container. Refer to [task configuration][task].

  ```hcl
  config {
    user = "nobody"
  }
  ```

- `volumes` - (Optional) A list of `host_path:container_path` strings to bind
  host paths to container paths. Named volumes are not supported.

  ```hcl
  config {
    volumes = [
      "/some/host/data:/container/data:ro,noexec"
    ]
  }
  ```

- `working_dir` - (Optional) The working directory for the container. Defaults
  to the default set in the image.

  ```hcl
  config {
    working_dir = "/data"
  }
  ```

## Network Configuration

Nomad [lifecycle hooks][nomad_lifecycle_hooks] combined with the drivers
[`network_mode`] allows very flexible network namespace definitions. This
feature does not build upon the native Podman pod structure but simply reuses
the networking namespace of one container for other tasks in the same group.

A typical example is a network server and a metric exporter or log shipping
sidecar. The metric exporter needs access to a private monitoring port which
should not be exposed the the network and thus is usually bound to `localhost`.

The [`nomad-driver-podman` repository][homepage] includes three different
examples jobs for such a setup. All of them will start a
[nats](https://nats.io/) server and a
[prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter)
using different approaches.

You can use `curl` to prove that the job is working correctly and that you can
get Prometheus metrics:

```shell-session
$ curl http://your-machine:7777/metrics
```

### 2 Task setup, server defines the network

Reference [`examples/jobs/nats_simple_pod.nomad`].

Here, the `server` task is started as main workload and the `exporter` runs as
a `poststart` sidecar. Because of that, Nomad guarantees that the server is
started first and thus the exporter can easily join the servers network
namespace via `network_mode = "task:server"`.

Note, that the `server` configuration file binds the `http_port` to
`localhost`.

Be aware that ports must be defined in the parent network namespace, here
`server`.

### 3 Task setup, a pause container defines the network

Reference [`examples/jobs/nats_pod.nomad`].

A slightly different setup is demonstrated in this job. It reassembles more
closesly the idea of a `pod` by starting a `pause` task, named `pod` via a
[`prestart`] sidecar hook.

Next, the main workload, `server` is started and joins the network namespace by
using the `network_mode = "task:pod"` stanza. Finally, Nomad starts the
`poststart` sidecar `exporter` which also joins the network.

Note that all ports must be defined on the `pod` level.

### 2 Task setup, shared Nomad network namespace

Reference [`examples/jobs/nats_group.nomad`].

This example is very different. Both `server` and `exporter` join a network
namespace which is created and managed by Nomad itself. Refer to Nomad's
[`network`] stanza to get started with this generic approach.

## Plugin Options

The Podman plugin has options which may be customized in the agent's
configuration file.

- `disable_log_collection` `(bool: false)` - Setting this to `true` will
  disable Nomad logs collection of Podman tasks. If you don't rely on Nomad log
  capabilities and exclusively use host based log aggregation, you may consider
  this option to disable Nomad log collection overhead. Beware that you also
  lose automatic log rotation.

  ```hcl
  plugin "nomad-driver-podman" {
    config {
      disable_log_collection = false
    }
  }
  ```

- `gc` stanza:

  - `container` - Defaults to `true`. This option can be used to disable Nomad
    from removing a container when the task exits.

  ```hcl
  plugin "nomad-driver-podman" {
    config {
      gc {
        container = false
      }
    }
  }
  ```

- `recover_stopped` - Defaults to `true`. Allows the driver to start and reuse
  a previously stopped container after a Nomad client restart. Consider a
  simple single node system and a complete reboot. All previously managed
  containers will be reused instead of disposed and recreated.

  ```hcl
  plugin "nomad-driver-podman" {
    config {
      recover_stopped = false
    }
  }
  ```

- `socket_path` `(string)` - Defaults to `unix://run/podman/io.podman` when
  running as `root` or a cgroup V1 system, and
  `unix://run/user/<USER_ID>/podman/io.podman` for rootless cgroup V2 systems.

- `volumes` stanza:

  - `enabled` - Defaults to `true`. Allows tasks to bind host paths (volumes)
    inside their container.
  - `selinuxlabel` - Allows the operator to set a SELinux label to the
    allocation and task local bind-mounts to containers. If used with
    `volumes.enabled` set to false, the labels will still be applied to the
    standard binds in the container.

  ```hcl
  plugin "nomad-driver-podman" {
    config {
      volumes {
        enabled      = true
        selinuxlabel = "z"
      }
    }
  }
  ```

[`count`]: /docs/job-specification/group#count
[`disable_log_collection`]: #disable_log_collection
[docker-ports]: /docs/drivers/docker#forwarding-and-exposing-ports
[`examples/jobs/nats_group.nomad`]: https://github.com/hashicorp/nomad-driver-podman/blob/main/examples/jobs/nats_group.nomad
[`examples/jobs/nats_simple_pod.nomad`]: https://github.com/hashicorp/nomad-driver-podman/blob/main/examples/jobs/nats_simple_pod.nomad
[`examples/jobs/nats_pod.nomad`]: https://github.com/hashicorp/nomad-driver-podman/blob/main/examples/jobs/nats_pod.nomad
[homepage]: https://github.com/hashicorp/nomad-driver-podman
[memory-value]: /docs/job-specification/resources#memory
[`network`]: /docs/job-specification/network
[nomad-init]: /docs/commands/job/init
[nomad_download]: /downloads.html
[nomad_driver_ports]: /docs/drivers/docker.html#forwarding-and-exposing-ports
[nomad_group_network]: /docs/job-specification/group#network
[nomad_lifecycle_hooks]: /docs/job-specification/lifecycle
[plugin_dir]: /docs/configuration#plugin_dir
[podman]: https://podman.io/
[podman-cli]: https://podman.io/whatis.html
[`prestart`]: /docs/job-specification/lifecycle#prestart
[releases]: https://releases.hashicorp.com/nomad-driver-podman
[rootless_tutorial]: https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md
[task]: /docs/job-specification/task#user
[`network_mode`]: #network_mode
[network-mode]: http://docs.podman.io/en/latest/markdown/podman-run.1.html#options
[slirp-issue]: https://github.com/containers/libpod/issues/6097
[downloaded]: https://releases.hashicorp.com/nomad-driver-podman
[short-names]: https://github.com/containers/image/blob/master/docs/containers-registries.conf.5.md#short-name-aliasing
[`command`]: #command
