Skip to content

Commit ec7de68

Browse files
committed
Add .IPAddresses as formatting option on docker ps
This allows showing the IP address for each network that the container is attached to, for example: docker network create foo docker run -d --name foo nginx:alpine docker network connect foo foo container container ls --format 'table {{.ID}}\\t{{join .IPAddresses ", "}}' CONTAINER ID IP ADDRESSES 17e7d1910fc0 bridge:172.17.0.2, foo:172.19.0.2 container container ls --format='{{json .IPAddresses}}' | jq . [ "bridge:172.17.0.2", "foo:172.19.0.2" ] Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 68cad50 commit ec7de68

3 files changed

Lines changed: 88 additions & 24 deletions

File tree

cli/command/formatter/container.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ import (
1616
const (
1717
defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}"
1818

19-
namesHeader = "NAMES"
20-
commandHeader = "COMMAND"
21-
runningForHeader = "CREATED"
22-
mountsHeader = "MOUNTS"
23-
localVolumes = "LOCAL VOLUMES"
24-
networksHeader = "NETWORKS"
19+
namesHeader = "NAMES"
20+
commandHeader = "COMMAND"
21+
runningForHeader = "CREATED"
22+
mountsHeader = "MOUNTS"
23+
localVolumes = "LOCAL VOLUMES"
24+
networksHeader = "NETWORKS"
25+
ipAddressesHeader = "IP ADDRESSES"
2526
)
2627

2728
// NewContainerFormat returns a Format for rendering using a Context
@@ -103,6 +104,7 @@ func NewContainerContext() *ContainerContext {
103104
"Mounts": mountsHeader,
104105
"LocalVolumes": localVolumes,
105106
"Networks": networksHeader,
107+
"IPAddresses": ipAddressesHeader,
106108
}
107109
return &containerCtx
108110
}
@@ -294,6 +296,25 @@ func (c *ContainerContext) Networks() string {
294296
return strings.Join(networks, ",")
295297
}
296298

299+
// IPAddresses returns the list of IP-addresses assigned to the container
300+
// IP-addresses are prefixed with the name of the network, separated with a colon.
301+
// For example: "bridge:192.168.1.10"
302+
func (c *ContainerContext) IPAddresses() []string {
303+
ipAddresses := []string{}
304+
if c.c.NetworkSettings == nil {
305+
return ipAddresses
306+
}
307+
for name, net := range c.c.NetworkSettings.Networks {
308+
if net.IPAddress != "" {
309+
ipAddresses = append(ipAddresses, name+":"+net.IPAddress)
310+
}
311+
if net.GlobalIPv6Address != "" {
312+
ipAddresses = append(ipAddresses, name+":"+net.GlobalIPv6Address)
313+
}
314+
}
315+
return ipAddresses
316+
}
317+
297318
// DisplayablePorts returns formatted string representing open ports of container
298319
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
299320
// it's used by command 'docker ps'

cli/command/formatter/container_test.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/docker/cli/internal/test"
1212
"github.com/docker/docker/api/types"
13+
"github.com/docker/docker/api/types/network"
1314
"github.com/docker/docker/pkg/stringid"
1415
"gotest.tools/v3/assert"
1516
is "gotest.tools/v3/assert/cmp"
@@ -247,7 +248,7 @@ size: 0B
247248
}
248249

249250
containers := []types.Container{
250-
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: "running"},
251+
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: "running", NetworkSettings: &types.SummaryNetworkSettings{}},
251252
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime, State: "running"},
252253
}
253254

@@ -405,6 +406,36 @@ func TestContainerContextWriteJSONField(t *testing.T) {
405406
}
406407
}
407408

409+
func TestContainerContextIPAddresses(t *testing.T) {
410+
containers := []types.Container{
411+
{
412+
ID: "containerID1",
413+
NetworkSettings: &types.SummaryNetworkSettings{
414+
Networks: map[string]*network.EndpointSettings{
415+
"one": {IPAddress: "192.168.1.2"},
416+
"two": {IPAddress: "192.168.178.2"},
417+
},
418+
},
419+
},
420+
{
421+
ID: "containerID2",
422+
NetworkSettings: &types.SummaryNetworkSettings{
423+
Networks: map[string]*network.EndpointSettings{
424+
"one": {IPAddress: "192.168.1.3"},
425+
"two": {IPAddress: "192.168.178.3"},
426+
},
427+
},
428+
},
429+
}
430+
431+
out := bytes.NewBufferString("")
432+
err := ContainerWrite(Context{Format: "{{.IPAddresses}}", Output: out}, containers)
433+
assert.NilError(t, err)
434+
assert.Equal(t, out.String(), `[one:192.168.1.2 two:192.168.178.2]
435+
[one:192.168.1.3 two:192.168.178.3]
436+
`)
437+
}
438+
408439
func TestContainerBackCompat(t *testing.T) {
409440
containers := []types.Container{{ID: "brewhaha"}}
410441
cases := []string{

docs/reference/commandline/ps.md

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -406,22 +406,24 @@ template.
406406

407407
Valid placeholders for the Go template are listed below:
408408

409-
| Placeholder | Description |
410-
|:--------------|:------------------------------------------------------------------------------------------------|
411-
| `.ID` | Container ID |
412-
| `.Image` | Image ID |
413-
| `.Command` | Quoted command |
414-
| `.CreatedAt` | Time when the container was created. |
415-
| `.RunningFor` | Elapsed time since the container was started. |
416-
| `.Ports` | Exposed ports. |
417-
| `.State` | Container status (for example; "created", "running", "exited"). |
418-
| `.Status` | Container status with details about duration and health-status. |
419-
| `.Size` | Container disk size. |
420-
| `.Names` | Container names. |
421-
| `.Labels` | All labels assigned to the container. |
422-
| `.Label` | Value of a specific label for this container. For example `'{{.Label "com.docker.swarm.cpu"}}'` |
423-
| `.Mounts` | Names of the volumes mounted in this container. |
424-
| `.Networks` | Names of the networks attached to this container. |
409+
| Placeholder | Description |
410+
|:---------------|:------------------------------------------------------------------------------------------------|
411+
| `.ID` | Container ID |
412+
| `.Image` | Image ID |
413+
| `.Command` | Quoted command |
414+
| `.CreatedAt` | Time when the container was created. |
415+
| `.RunningFor` | Elapsed time since the container was started. |
416+
| `.Ports` | Exposed ports. |
417+
| `.State` | Container status (for example; "created", "running", "exited"). |
418+
| `.Status` | Container status with details about duration and health-status. |
419+
| `.Size` | Container disk size. |
420+
| `.Names` | Container names. |
421+
| `.Labels` | All labels assigned to the container. |
422+
| `.Label` | Value of a specific label for this container. For example `'{{.Label "com.docker.swarm.cpu"}}'` |
423+
| `.Mounts` | Names of the volumes mounted in this container. |
424+
| `.Networks` | Names of the networks attached to this container. |
425+
| `.IPAddresses` | List of IP-Addresses for each network that the container is attached to. |
426+
425427

426428
When using the `--format` option, the `ps` command will either output the data
427429
exactly as the template declares or, when using the `table` directive, includes
@@ -455,4 +457,14 @@ To list all running containers in JSON format, use the `json` directive:
455457
```console
456458
$ docker ps --format json
457459
{"Command":"\"/docker-entrypoint.…\"","CreatedAt":"2021-03-10 00:15:05 +0100 CET","ID":"a762a2b37a1d","Image":"nginx","Labels":"maintainer=NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e","LocalVolumes":"0","Mounts":"","Names":"boring_keldysh","Networks":"bridge","Ports":"80/tcp","RunningFor":"4 seconds ago","Size":"0B","State":"running","Status":"Up 3 seconds"}
458-
```
460+
```
461+
462+
Show the IP-addresses that containers have:
463+
464+
```console
465+
$ docker ps --format "table {{.ID}}\\t{{join .IPAddresses \", \"}}"
466+
467+
CONTAINER ID IP ADDRESSES
468+
c0cf2877da71 bridge:172.17.0.3
469+
17e7d1910fc0 bridge:172.17.0.2, mynetwork:172.19.0.2
470+
```

0 commit comments

Comments
 (0)