| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64netavark-1.17.2-1.el10.x86_64 |
| Applies to | Any Linux host with Podman installed |
| Privilege | Rootful examples on the lab host; rootless pod notes where behavior differs |
| Scope | Pod-specific networking — shared namespace, IP inspection, localhost communication, port collisions, pod-level -p publishing, immutable mappings, user-defined networks, aliases, hostname, DNS options, static IP, multi-network pods, and pod-level --userns. Does not cover generic -p syntax depth, full Aardvark DNS, pod lifecycle, or Quadlet .pod units. |
| Related guides | Podman networking modes |
Pod networking changes the rules. Every member of a pod shares one network namespace — one IP, one localhost, and one port space. That is what makes app-plus-sidecar layouts work, and it is also what blocks you from publishing ports on individual members after the fact.
This guide assumes you already know what a pod is from Podman pods. Here we focus on what the shared namespace means for IPs, ports, DNS, and user namespaces.
How Podman pod networking works
Pod network namespace
│
├── one IP/interface set
├── one loopback interface
└── one TCP/UDP port space
│
┌──────┴──────┐
▼ ▼
Container A Container B
app:8080 sidecarAll containers that join a pod's network namespace share:
- the same network interfaces
- the same IP addresses
- the same routing table
- the same
localhost - the same TCP and UDP port namespace
That is fundamentally different from two ordinary containers on a user-defined bridge, where each container gets its own IP and its own loopback.
Inspect the pod IP address
Create a pod and start it before adding members:
podman pod create --name pod-network-demoPodman prints the pod ID. Start the pod:
podman pod start pod-network-demoAdd two member containers. Start with the first:
podman run -d --pod pod-network-demo --name net-a registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Join a second member to the same pod:
podman run -d --pod pod-network-demo --name net-b registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Inspect the first member's address:
podman inspect net-a --format 'IP: {{.NetworkSettings.IPAddress}}'Sample output:
IP: 10.88.2.166Check the second member:
podman inspect net-b --format 'IP: {{.NetworkSettings.IPAddress}}'Sample output:
IP: 10.88.2.166Both containers report the same address because they share the pod network namespace. The MAC address and network aliases in full inspect output also match across members.
Containers in a pod communicate over localhost
A service bound to 127.0.0.1:8080 inside one member is reachable from every other member at the same address.
Create a pod with a web server and a client container:
podman pod create --name localhost-podBring the empty pod to running state:
podman pod start localhost-podAdd the web server member:
podman run -d --pod localhost-pod --name loc-web registry.access.redhat.com/ubi9/httpd-24The UBI httpd-24 image listens on port 8080 inside the container namespace.
podman run -d --pod localhost-pod --name loc-client registry.access.redhat.com/ubi9/ubi-minimal sleep 3600From the client member, request the service on shared localhost:
podman exec loc-client curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/Sample output:
403HTTP 403 confirms the TCP connection succeeded — loc-client reached loc-web over shared localhost. A connection failure would print 000.
No container-name DNS is required for this pattern. Both processes share the same loopback interface.
Two pod containers cannot bind the same port
The pod namespace has one port space, like a single Linux host.
Start a pod and run the first httpd member:
podman pod create --name collision-podStart the pod before adding members:
podman pod start collision-podRun the first httpd member so it binds port 8080:
podman run -d --pod collision-pod --name coll-a registry.access.redhat.com/ubi9/httpd-24Try to start a second httpd in the same pod:
podman run -d --pod collision-pod --name coll-b registry.access.redhat.com/ubi9/httpd-24The second container exits. Read its logs:
podman logs coll-bSample output (trimmed):
(98)Address already in use: AH00072: make_sock: could not bind to address [::]:8080
(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:8080
no listening sockets available, shutting downcoll-a already owns port 8080 in the shared namespace, so coll-b cannot bind the same port.
On separate containers attached to a user-defined network, each could listen on container port 8080 independently because they have different network namespaces and IPs.
Publish ports when creating the pod
Host port mappings belong to the pod, not to individual members. Create the pod with -p:
podman pod create --name web-pod -p 18080:8080The mapping forwards host port 18080 to port 8080 in the pod namespace. The UBI httpd-24 image listens on 8080, not 80.
Start the pod and add the application:
podman pod start web-podAttach the application container to the running pod:
podman run -d --pod web-pod --name web-app registry.access.redhat.com/ubi9/httpd-24Test from the host:
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:18080/Sample output:
403The application only needs to listen on :8080 inside the shared namespace. Podman forwards host traffic through the pod-level mapping.
Inspect published ports on the infra container:
podman port web-pod-infraSample output:
8080/tcp -> 0.0.0.0:18080Use the infra container name (PODID-infra) with podman port when the pod name alone is not accepted. General -p syntax and protocol options live in Podman port mapping.
Do not publish ports on individual pod members
Creating a pod without port publication and then trying -p on a joining container fails.
With web-pod already running, attempt:
podman run -d --pod web-pod -p 9090:8080 registry.access.redhat.com/ubi9/httpd-24Sample output:
Error: invalid config provided: published or exposed ports must be defined when the pod is created: network cannot be configured when it is shared with a podA member container does not receive its own independent network namespace where new mappings can be added. Publish ports on podman pod create instead.
Pod port mappings cannot be added after creation
Podman does not support adding or changing port publications on an existing pod. If you create a pod without the -p flags you need, the fix is to recreate the pod with the correct mappings and reattach your containers.
pod create without -p
↓
later need host port 18080
↓
recreate pod with -p 18080:8080Do not edit internal Netavark firewall rules to work around this — plan host ports at pod creation time.
Publish multiple pod ports
Pass multiple -p flags at pod creation:
podman pod create --name multi-port-pod -p 18081:8080 -p 18443:443Start the pod and add a member:
podman pod start multi-port-podAdd a member that listens on the mapped ports inside the pod:
podman run -d --pod multi-port-pod --name mp-app registry.access.redhat.com/ubi9/httpd-24List mappings through the infra container:
podman port multi-port-pod-infraSample output:
8080/tcp -> 0.0.0.0:18081
443/tcp -> 0.0.0.0:18443The 443 mapping is ready when a process inside the pod listens on that port. TCP/UDP and port-range syntax are covered in Podman port mapping.
Rootless pod port mapping
Rootless pods follow the same rule: publish on podman pod create -p. For rootless pods, private networking typically uses pasta. If the pod is attached to a rootless bridge network, published ports use rootlessport by default unless rootless_port_forwarder="pasta" is configured.
A rootless pod with -p 8080:80 can publish a high host port normally. Host ports below the unprivileged threshold (typically 1024) face the same restrictions as ordinary rootless containers. See Rootless Podman privileged ports for fixes — this article does not repeat those workarounds.
Pod network mode is chosen at pod creation
Attach a pod to a user-defined network at creation:
podman network create pod-app-network --subnet 10.20.0.0/24Create the pod on that network:
podman pod create --network pod-app-network --name app-podMember containers inherit the pod's network attachment. They cannot independently choose --network frontend or --network backend after joining. Decide pod topology before you run podman run --pod.
Pod on a user-defined network
Inspect which network the pod uses:
podman pod inspect app-pod --format '{{json .InfraConfig.Networks}}'Sample output:
["pod-app-network"]The pod — not each member individually — holds the network attachment. Every container you add with --pod app-pod sees the same interface and IP from that network.
Pod-level DNS and Aardvark
On a DNS-enabled Podman user-defined network, Aardvark resolves network-scoped names. The pod's network endpoint can carry aliases; all members share that endpoint's resolver configuration.
Inside the pod, tightly coupled workloads normally use localhost:PORT rather than resolving each member as a separate DNS name. Member containers do not each get unique network IPs on the shared namespace.
Full Aardvark behavior and standalone container DNS belong in Podman container DNS.
Configure a pod network alias
Create a network and a pod with an alias:
podman network create alias-net --subnet 10.30.0.0/24Create the pod with a network alias:
podman pod create --network alias-net --network-alias webapp --name web-alias-podPodman documents --network-alias for pod-wide aliases on the attached network. For multi-network pods, use --network NET:alias=NAME when the alias should apply only to one network.
Start the pod, then run a separate container on the same network:
podman pod start web-alias-podThe client container sits on alias-net but outside the pod:
podman run -d --network alias-net --name alias-client registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Resolve the alias from outside the pod:
podman exec alias-client getent hosts webappSample output:
10.30.0.2 webapp.dns.podmanThe alias resolves to the pod's shared network IP (10.30.0.2), not to a per-member address.
Pod hostname
UTS namespace is shared by default, so set hostname at pod creation:
podman pod create --hostname application --name hostname-podStart the pod and add two members:
podman pod start hostname-podAdd the first member:
podman run -d --pod hostname-pod --name hn-a registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Add a second member to confirm UTS is shared:
podman run -d --pod hostname-pod --name hn-b registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Both members report the same hostname:
podman exec hn-a cat /etc/hostnameSample output:
applicationCheck the second member reports the same hostname:
podman exec hn-b cat /etc/hostnameSample output:
applicationCustom pod DNS servers
Pass resolver options at pod creation:
podman pod create --dns 10.0.0.53 --name dns-podVerify the setting on the pod:
podman pod inspect dns-pod --format '{{json .InfraConfig.DNSServer}}'Sample output:
["10.0.0.53"]Pod-level --dns, --dns-search, and --dns-option apply to members through the shared pod networking environment. Resolver semantics for standalone containers are covered in Podman container DNS.
Static pod IP address
Request a fixed address on a user-defined network when creating the pod:
podman pod create --network pod-app-network --ip 10.20.0.50 --name static-podStart the pod and add a member:
podman pod start static-podAdd a member and confirm it inherits the static address:
podman run -d --pod static-pod --name static-c registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Confirm the address on the member:
podman inspect static-c --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{"\n"}}{{end}}'Sample output:
pod-app-network 10.20.0.50Pick an address inside the network subnet you created (10.20.0.0/24 here). The standalone --ip option applies only when the pod joins one network — see the multi-network section for per-network static addresses.
Multiple networks on one pod
Podman 5.8.2 can attach a pod to more than one network at creation:
podman network create frontend --subnet 10.40.0.0/24Create the backend network on a separate subnet:
podman network create backend --subnet 10.41.0.0/24Attach the pod to both networks at creation:
podman pod create --network frontend --network backend --name multi-net-podIf you need static addresses on a multi-network pod, set ip= on each --network entry; the standalone --ip option is limited to single-network pods:
podman pod create \
--network frontend:ip=10.40.0.10 \
--network backend:ip=10.41.0.10 \
--name multi-net-podEvery member shares all pod network interfaces. Add one member:
podman run -d --pod multi-net-pod --name mn-c registry.access.redhat.com/ubi9/ubi-minimal sleep 3600List every interface the member inherited:
podman inspect mn-c --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{"\n"}}{{end}}'Sample output:
backend 10.41.0.2
frontend 10.40.0.2Both interfaces appear on the same container because the pod namespace includes every network the pod was created with. Individual members cannot pick a subset after they join.
User namespace is a pod-level decision
Per-container --userns is ignored when joining a pod with an infra container. Attempting to set it on a member fails:
podman pod create --name userns-podStart the pod, then try to override user namespace on a member:
podman pod start userns-podPodman rejects per-member --userns when an infra container owns the pod namespace:
podman run -d --pod userns-pod --userns=keep-id --name userns-member registry.access.redhat.com/ubi9/ubi-minimal sleep 3600Sample output:
Error: cannot set user namespace mode when joining pod with infra container: invalid argumentConfigure user namespaces when creating the pod:
podman pod create --userns=keep-id --name userns-pod2That member starts without the error. Mapping details live in Podman user namespaces.
Why podman exec is not needed for pod networking
To reach another service in the same pod, connect to localhost:PORT. Use podman exec when you need a separate process or shell inside a member — not as a network hop to another container's service.
Inside pod: curl http://127.0.0.1:8080
Not needed: podman exec other-container curl ...Pod vs separate containers on a user network
| Topic | Pod | Separate containers on user network |
|---|---|---|
| IP address | shared across members | one IP per container |
| localhost | shared loopback | private per container |
| Port namespace | one shared space | same container port can repeat |
| App to sidecar | localhost:PORT |
DNS name such as sidecar:PORT |
| Host port publish | on podman pod create |
on each podman run |
| Network choice | fixed at pod creation | per container |
Use a pod when localhost coupling and joint port space are intentional. Use separate networked containers when each service needs its own IP and DNS endpoint.
Common pod networking errors
| Symptom | Likely cause | Fix |
|---|---|---|
-p rejected on podman run --pod |
Ports must be set on the pod | Add -p to podman pod create |
Address already in use in pod logs |
Two members bind the same port | Use different listen ports or run one listener |
| Host cannot reach service after pod create | No -p at pod creation |
Recreate pod with correct -p mapping |
| Member name does not resolve inside pod | Shared namespace — no per-member DNS IP | Use localhost:PORT |
--userns ignored or rejected on member |
Pod infra owns the namespace | Set --userns on podman pod create |
| Wrong network subnet or no route | Pod attached to wrong network | podman pod inspect; recreate on correct network |
References
- podman-pod-create(1) — Podman documentation
- podman-port(1) — Podman documentation
- Netavark network driver
Summary
Podman pod networking gives every member one shared namespace: one IP, one localhost, and one port space. On the lab host, two members of pod-network-demo both showed 10.88.2.166, and loc-client reached httpd on 127.0.0.1:8080 without container-name DNS.
That sharing has consequences. A second httpd in the same pod failed with Address already in use on port 8080. Host port mappings must be declared on podman pod create — podman run -p inside an existing pod is rejected, and mappings cannot be added later.
Network design is also pod-scoped: user-defined networks, aliases, static IPs, DNS servers, and --userns are set when the pod is created. Use localhost for member-to-member traffic; use network aliases when another container on the same user-defined network must resolve the pod as a single endpoint.
For pod creation and namespace defaults beyond networking, see Podman pods. For per-container publish syntax and rootless forwarding detail, see Podman port mapping.

