Docker
TOPICS
August 2020
Everytime I run docker ps
to list my containers, I find hard to understand where does the list start and where it ends:
What the! ... the port, which one? ... I almost feel like I'm seeing the matrix
I have to say, after some time your eyes get used to and begin to do weird movements but at the end you begin to understand the output, of course it shouldn't be this way, so I found there are server ways to improve the command output, let's take a look.
Use —format
Use the option --format
, using this we can choose from a list of fields (see the table below) and display them in a ordered layout using the following syntax table {{.FieldName}}\t
. The format option uses Go templates underneath, hey that looks familiar to me1.
table
print the field name and \t
adds space between columns.
Example using --format
docker ps --format 'table {{.Names}}\t
{{.Status}} : {{.RunningFor}}\t
{{.ID}}\t
{{.Image}}'
And we got this :
Definitely a better command output so much easy to read and understand
Taking advantage of Go Templates
We can get creative with Go Templates and lets query our containers to get network information including ports (a clean output would be to show every port in his own line but only if ports are used):
Network information
docker ps --format 'table {{.Names}}
\t{{.Status}}
\t{{.Networks}}
\n{{.ID}}
{{if .Ports}}
{{with $p := split .Ports ", "}}
{{range $p}}\t\t{{println .}}{{end}}
{{end}}
{{else}}
\t\t{{println "No Ports"}}
{{end}}'
Here you have, we can get all network data in a more readable way
All containers docker ps –a
Using the option ps -a
will list all containers in any state. So it would be nice to add the disk space, a summary of the network use and the image from where the container derives.
All containers list
docker ps -a -q --format 'table {{.Names}}\t
{{.Status}}\t
{{.Size}}\n
{{.ID}}\t
{{.Image}}
{{if .Ports}}
{{with $p := split .Ports ", "}}\t
{{len $p}} port(s) on {{end}}{{- .Networks}}
{{else}}\tNo Ports on {{ .Networks }}
{{end}}\n'
Look at this! An easier way to spot information about all containers.
Create a function to reuse the commands
Finally we can create a function to reuse these commands (if you are using WSL or Linux) inside our .bash_aliases file
Create a bash function that allows parameters
# Docker PS Prettify Function
function dock() {
if [[ "$@" == "ps" ]]; then
command docker ps --format 'table {{.Names}}\t{{.Status}} : {{.RunningFor}}\t{{.ID}}\t{{.Image}}'
elif [[ "$@" == "psa" ]]; then
# docker ps -a includes all containers
command docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Size}}\n{{.ID}}\t{{.Image}}{{if .Ports}}{{with $p := split .Ports ", "}}\t{{len $p}} port(s) on {{end}}{{- .Networks}}{{else}}\tNo Ports on {{ .Networks }}{{end}}\n'
elif [[ "$@" == "psnet" ]]; then
# docker ps with network information
command docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Networks}}\n{{.ID}}{{if .Ports}}{{with $p := split .Ports ", "}}{{range $p}}\t\t{{println .}}{{end}}{{end}}{{else}}\t\t{{println "No Ports"}}{{end}}'
else
command docker "$@"
fi
}
To use the function just type:
- dock ps
- List running containers and its image name
- dock psa
- List all containers no matter what state and includes disk space and network information
- dock psnet
- List running containers with detailed network information
Available fields in docker
- .ID
- Container ID
- .Image
- Image ID
- .Command
- Quoted command
- .CreatedAt
- Time when the container was created.
- .RunningFor
- Elapsed time since the container was started.
- .Ports
- Exposed ports.
- .Status
- Container status.
- .Size
- Container disk size.
- .Names
- Container names.
- .Labels
- All labels assigned to the container.
- .Label
- Value of a specific label for this container. For example ‘{{.Label “com.docker.swarm.cpu”}}’
- .Mounts
- Names of the volumes mounted in this container.
- .Networks
- Names of the networks attached to this container.
March 2020
The Issue
I was working on my Linux server, and I had to restart it. The docker instance was empty when the server came back, and it didn't show any container. I was in shock, and I thought I had lost my images and containers. After reviewing the system's health couldn't found a root cause, so I did a second restart 😅 and that's it the containers were back. Great! But when I tried to start
my containers …
ERROR: network xxxx is ambiguous (2 matches found based on name)
The Whys
I found that docker allows repeating network names 👻; my hunch here is that when the system restarted something (maybe my container disk didn't mount properly), docker recreated the network configuration. As you can see in the following table, it duplicated every network and driver
docker network list
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
27b6c27fdc2b bridge bridge local
33f2a0c04878 bridge bridge local
c4247d693521 host host local
9b95be563bf7 host host local
590102262bb5 none null local
25e1bf9dc86 none null local
So the solution appeared to be, just to delete one of the duplicate networks by his ID.
I tried to execute the following command docker network rm [ID]
Error : bridge is a pre-defined network and cannot be removed
What the … this was more tricky than what I initially thought, at some forum, I found some arbitrary advice:
- The docker service must be stopped
- There shouldn't be a container using the network
- And another workaround is not to have containers (delete them)
If you need to see which containers are using which network use:
Inspect network ID of a container
# Note that in this scenario since bridge is repeated you'll need to do it by Id:
docker network inspect [id || name]
"Internal": false,
{ "Network": "" },
"ConfigOnly": false,
"Containers": {},
So, at this point option one and two didn't work and I couldn't afford to delete all my containers which there were already configured with his own volumes and startup scripts.
Workaround and Solution
-
Create a new network. Use the parameter
-d
to specify the driverdocker network create -d bridge [new-network-name]
-
Disconnect the container(s) from the ambiguous network
docker network disconnect bridge [container-name]
-
Connect the container(s) to the new network
docker network connect [new-network-name] [container-name]
-
Optional. Purge our network and get rid off of the unused networks
docker network rm $(docker network ls -q)
And that's all, now we should be able to start our containers.
docker start my-happy-container