Docker Containers - The Heart of Navigation 💙
Welcome back to Docking the Ship: Navigating Docker for Developers! In this installment, we’ll explore the cornerstone of Docker: containers. Containers have revolutionized the way we build, ship, and run applications. In this post, we’ll dive deep into what containers are, how they work, and why they’re so efficient.
What Are Docker Containers?
At its core, a Docker container is a lightweight, standalone, and executable package that includes everything needed to run an application: code, runtime, libraries, and dependencies. Containers are built on top of Docker images and provide an isolated environment for running applications.
How Containers Differ from Virtual Machines
While both containers and virtual machines (VMs) provide isolation, they do so in fundamentally different ways:
Feature | Containers | Virtual Machines |
---|---|---|
Isolation Level | Process-level | Full operating system-level |
Size | Lightweight (megabytes) | Heavy (gigabytes) |
Startup Time | Fast (seconds) | Slower (minutes) |
Efficiency | Shares the host OS kernel | Requires a full guest OS |
Containers achieve their efficiency by sharing the host operating system’s kernel, unlike VMs that require a full OS for each instance.
The Lifecycle of a Docker Container
Understanding the container lifecycle is key to managing them effectively. Here’s a breakdown:
- Create
A container is created from a Docker image using thedocker create
command. At this stage, the container exists but isn’t running.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$ docker create vishalanarase/navigating-docker:v1.0.0 Unable to find image 'vishalanarase/navigating-docker:v1.0.0' locally v1.0.0: Pulling from vishalanarase/navigating-docker cb8611c9fe51: Already exists bd9615f269cd: Already exists 39f8f326b044: Already exists 859344cb3f85: Already exists 4f4fb700ef54: Already exists 2a927826cb18: Already exists bd2ff5f12cf5: Already exists 9bcbe2868212: Already exists d2a3aa0d6430: Already exists eac0338a0e1d: Already exists Digest: sha256:902c518d2dd4d89e565ca96c9d20cc09faeca663486c2bb6683e3befad37fc06 Status: Downloaded newer image for vishalanarase/navigating-docker:v1.0.0 8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930
Verify container called
demo
is created1 2 3
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8674b559fc16 vishalanarase/navigating-docker:v1.0.0 "./webserver" 8 seconds ago Created demo
Start
The container is started with thedocker start
command, executing the process defined in the image.1 2
$ docker start demo demo
Run
Alternatively, you can create and start a container in one step usingdocker run
.1 2
$ docker run --name test -d vishalanarase/navigating-docker:v1.0.0 82576266d26c8e68b4815a6a3628473fa0a1c94f5b3047134e58d44fa97071ec
Verify container called
test
is created1 2 3 4
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82576266d26c vishalanarase/navigating-docker:v1.0.0 "./webserver" 36 seconds ago Up 35 seconds 8081/tcp test 8674b559fc16 vishalanarase/navigating-docker:v1.0.0 "./webserver" 3 minutes ago Up 2 minutes 8081/tcp demo
Pause/Unpause
Temporarily halt a container’s processes withdocker pause
and resume withdocker unpause
.1 2
$ docker pause test test
1 2
$ docker unpause test test
Stop
Gracefully stop a running container usingdocker stop
.1 2
$ docker stop test test
1 2
$ docker start test test
Kill
Forcefully terminate a container withdocker kill
.1 2
$ docker kill test test
Remove
Delete a container usingdocker rm
. This action is final, so ensure you no longer need the container.1 2
$ docker rm test test
Managing Docker Containers
Here are some essential commands for container management:
- List Running Containers:
1
$ docker ps
1 2 3
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8674b559fc16 vishalanarase/navigating-docker:v1.0.0 "./webserver" 6 minutes ago Up 5 minutes 8081/tcp demo
- List All Containers (Including Stopped):
1
$ docker ps -a
1 2 3
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8674b559fc16 vishalanarase/navigating-docker:v1.0.0 "./webserver" 6 minutes ago Up 5 minutes 8081/tcp demo
- Inspect a Container:
View detailed information about a container:1
$ docker inspect <container_id>
1
$ docker inspect demo
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
[ { "Id": "8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930", "Created": "2025-01-09T15:44:13.915347501Z", "Path": "./webserver", "Args": [], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 2285, "ExitCode": 0, "Error": "", "StartedAt": "2025-01-09T15:45:17.811367795Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:4e87789a83fc40d5144f6d5454acdc19cfb72a7072dece5497c0542c11222b85", "ResolvConfPath": "/var/lib/docker/containers/8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930/resolv.conf", "HostnamePath": "/var/lib/docker/containers/8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930/hostname", "HostsPath": "/var/lib/docker/containers/8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930/hosts", "LogPath": "/var/lib/docker/containers/8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930/8674b559fc163fd2b107055d49bfa988e03965348548e349ec24d56aacc38930-json.log", "Name": "/demo", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "bridge", "PortBindings": {}, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "ConsoleSize": [ 45, 158 ], "CapAdd": null, "CapDrop": null, "CgroupnsMode": "private", "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": [], "BlkioDeviceWriteBps": [], "BlkioDeviceReadIOps": [], "BlkioDeviceWriteIOps": [], "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": null, "PidsLimit": null, "Ulimits": [], "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware", "/sys/devices/virtual/powercap" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f-init/diff:/var/lib/docker/overlay2/rm08hgeeg2n1ull9sed0wg5lu/diff:/var/lib/docker/overlay2/qrs7mot5dzkubio5rzs7z7tuv/diff:/var/lib/docker/overlay2/xozzhsefrjwllxluwquhmw2cb/diff:/var/lib/docker/overlay2/4bdxfte72y7eakcz0a4eyplqb/diff:/var/lib/docker/overlay2/u3szopca12lfiy6yz42x6apzv/diff:/var/lib/docker/overlay2/df2496f5b13e01178dcfed8252695846450576f79b7831b70f44aac1fe8671d6/diff:/var/lib/docker/overlay2/feb7d81e23ee2e778286f5f5cb0d481569272894b928ed4fb338105c2f0e4434/diff:/var/lib/docker/overlay2/72a21c9133ef6499d8896650a1f3b6b37b3d410a8245392ffcd0cdbe366232df/diff:/var/lib/docker/overlay2/0bdd117f93f07c849f18ab3fb7d41f0bdf8c384857f9406fade4f9979e8a50a3/diff:/var/lib/docker/overlay2/faf20fcf861221030dc28e6d4874643ce562ff532ef2955423edc03f808c3a08/diff", "MergedDir": "/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f/merged", "UpperDir": "/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f/diff", "WorkDir": "/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "8674b559fc16", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "ExposedPorts": { "8081/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOLANG_VERSION=1.23.4", "GOTOOLCHAIN=local", "GOPATH=/go" ], "Cmd": [ "./webserver" ], "Image": "vishalanarase/navigating-docker:v1.0.0", "Volumes": null, "WorkingDir": "/app", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "d8026809d87b8497945c50f86c6c2deab829682b4505f44594085294f538a9c4", "SandboxKey": "/var/run/docker/netns/d8026809d87b", "Ports": { "8081/tcp": null }, "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "b106aff81c7a40396cd964c37e844e0b7bd3c1cd8fd380116eeb193a4a4949f2", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null, "NetworkID": "12a23966fbbc258ec83b3b7abc6123d1e2f56212a55847466118f25f5889e686", "EndpointID": "b106aff81c7a40396cd964c37e844e0b7bd3c1cd8fd380116eeb193a4a4949f2", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "DNSNames": null } } } } ]
- View Logs:
Check logs for debugging:1
docker logs <container_id/name>
1 2
$ docker logs demo Starting server on :8081
- Access a Running Container:
Enter a container’s shell for troubleshooting:1
docker exec -it <container_id/name> /bin/bash
1
$ docker exec -it demo sh
Run some basic commands
1
/app # ifconfig
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:65535 Metric:1 RX packets:9 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1046 (1.0 KiB) TX bytes:0 (0.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
1 2 3 4 5
/app # ps aux PID USER TIME COMMAND 1 root 0:00 ./webserver 29 root 0:00 sh 36 root 0:00 ps aux
1 2
/app # hostname 8674b559fc16
1 2
/app # hostname -i 172.17.0.2
1
/app # mount
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/HJQ4PREEC2VKRCRTWEE75HSGCO:/var/lib/docker/overlay2/l/HAOXCKJQQKOHWM3BGG5YFUJ4X2:/var/lib/docker/overlay2/l/MVHX6WQSHAH5PKDE5VZ2YCWTLF:/var/lib/docker/overlay2/l/NBWXKYGBX6SY5MBUK6P2F7RKSQ:/var/lib/docker/overlay2/l/FXGSLQPK4GC6J4PCKSQT2ND4YR:/var/lib/docker/overlay2/l/T6YVWOBNC3RAKZHSXD5U2CDIQ6:/var/lib/docker/overlay2/l/FYEZEQJHBEQDGV55QSWJAMNLA3:/var/lib/docker/overlay2/l/UONY7FGWXP6PQJJEYI5ZQ64XGF:/var/lib/docker/overlay2/l/3WEIWPF5D3JNHIEKXLMZ2UQUPM:/var/lib/docker/overlay2/l/WNZY3IY7NPCJYVH2PZDDDNAOEJ:/var/lib/docker/overlay2/l/AUWBKUCGQMNCWX5FFSMQBEXSPW,upperdir=/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f/diff,workdir=/var/lib/docker/overlay2/4a212649d84f2d344c1004df1ac00315e3e6a9034fa9e9bf0b89e51bc95f501f/work) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666) sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime) cgroup on /sys/fs/cgroup type cgroup2 (ro,nosuid,nodev,noexec,relatime) mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime) shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k) /dev/vda1 on /etc/resolv.conf type ext4 (rw,relatime,discard) /dev/vda1 on /etc/hostname type ext4 (rw,relatime,discard) /dev/vda1 on /etc/hosts type ext4 (rw,relatime,discard) proc on /proc/bus type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/fs type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/irq type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/sys type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/sysrq-trigger type proc (ro,nosuid,nodev,noexec,relatime) tmpfs on /proc/kcore type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /proc/keys type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /proc/timer_list type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /proc/scsi type tmpfs (ro,relatime) tmpfs on /sys/firmware type tmpfs (ro,relatime)
1 2 3 4 5 6 7 8 9 10
/app # env HOSTNAME=8674b559fc16 SHLVL=1 HOME=/root GOTOOLCHAIN=local TERM=xterm PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin GOPATH=/go PWD=/app GOLANG_VERSION=1.23.4
1
/app # ip addr
IP Addresses </summary> ```bash 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: tunl0@NONE: mtu 1480 qdisc noop state DOWN qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: gre0@NONE: mtu 1476 qdisc noop state DOWN qlen 1000 link/gre 0.0.0.0 brd 0.0.0.0 4: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 5: erspan0@NONE: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 6: ip_vti0@NONE: mtu 1480 qdisc noop state DOWN qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 7: ip6_vti0@NONE: mtu 1428 qdisc noop state DOWN qlen 1000 link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 8: sit0@NONE: mtu 1480 qdisc noop state DOWN qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0 9: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN qlen 1000 link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 10: ip6gre0@NONE: mtu 1448 qdisc noop state DOWN qlen 1000 link/[823] 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 37: eth0@if38: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 65535 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever ``` </details> ```bash /app # cat /etc/resolv.conf # Generated by Docker Engine. # This file can be edited; Docker Engine will not make further changes once it # has been modified. nameserver 192.168.65.7 # Based on host file: '/etc/resolv.conf' (legacy) # Overrides: [] ``` ```bash /app # ls Dockerfile LICENSE README.md go.mod go.sum main.go webserver ``` ```bash Try running binary again i.e. ./webserver /app # ./webserver Starting server on :8081 Error starting server: listen tcp :8081: bind: address already in use ``` ---
Container Isolation: Security and Efficiency
Docker containers provide isolation through the following mechanisms:
Namespaces
Namespaces ensure each container has its own isolated view of system resources (e.g., process IDs, file systems, and network interfaces).Control Groups (cgroups)
Cgroups limit the resources (CPU, memory, disk I/O) a container can use, ensuring fair resource allocation.Union File System (UnionFS)
UnionFS enables efficient storage by layering file systems. Changes made in a container are written to a new layer without modifying the base image.
Why Docker Containers Are So Efficient
Resource Sharing
Containers share the host OS kernel, reducing overhead and improving startup times.Portability
Containers encapsulate all dependencies, ensuring consistent behavior across environments.Scalability
Containers are lightweight, making it easy to scale applications horizontally by spinning up multiple instances.Rapid Development and Deployment
With containers, developers can focus on writing code without worrying about environmental inconsistencies.
Conclusion
Docker containers are the heartbeat of modern application development. They provide a lightweight, efficient, and portable way to package and run applications. By mastering container lifecycles, management, and isolation, you’ll be well-equipped to harness their full potential.
In the next post, we’ll explore Docker Volumes : Persisting Data to understand how to manage persistent data and connect containers. Stay tuned, and happy docking! 🚢
Have questions or feedback? Drop them in the comments or connect with me. Let’s navigate the Docker seas together! 🌊