Simple Guide to Docker
A simple guide to using Docker
Using Docker containers
As you can see from A web app using postgresql with Docker, using a Docker container can be a good way to provide some kind of service (like PostgreSQL) without having to install that service in your host operating system. So, this lesson goes into the basic Docker commands so that you can start making use of Docker containers.
Creating a Dockerfile
Using a file named Dockerfile in your working directory is a good way to set up creating a Docker image. You can think of a Docker image as a kind of template that will be used to create a Docker container. The Docker image is sort of like a class in an object-oriented programming language, and the container is like an object created from that image.
So, the Docker image is stored on the host’s drive and the container runs in RAM. If we want information from the Docker container, the container must be running (loaded into RAM).
Here is some documentation on creating a Dockerfile, dockerdocs Dockerfile reference. The most important instruction is the FROM instruction. This is used to pull the base image from the Docker repositories to create the new image.
Here is an example of a simple Dockerfile for a MongoDB Docker container. Assuming the name of the working directory is mongo_db here is the Dockerfile:
FROM mongodb/mongodb-community-server:latest
mongodb/mongodb-community-server:latest is the name of the base image for the MongoDB Community with Docker. If you don’t need any other configuration, the Dockerfile can be just one line like this.
I wound up scrolling down until I found 16, which is the base image called postgres:16. That is simply because I knew that I could install the Debian package: postgresql-16 on my Ubuntu 24.04 machine. So, that would make using the Docker container for the PostgreSQL service and the service on my Ubuntu machine the same version. Of course, if this did not work, I would have to try another base image.
Assuming that my working directory for using a PostgreSQL Docker container is postgres, here is the Dockerfile I used:
FROM postgres:16
RUN apt-get update -y && apt-get install -y nano
Note that in this case I added the instruction RUN which runs the commands specified inside the image. A very important thing to keep in mind is that if you use the RUN command, that you should chain the commands together using the && operator. If there are many commands, use the continuation \ operator. So, this might look something like this:
RUN command1 && command2 && command3 && \
command4 && command5 && command6 && \
command7 && command8
This will ensure that all the commands are run in the same context. If you don’t do this, you might get error messages stating that some command does not exist, even though you just installed it right above that.
Creating the image using the Dockerfile
I always use a simple shell script to create the image from the Dockerfile. This gives me a record to look at if I want to see exactly what I did. For me, this is better on relying on my memory to recall this kind of detail. Also, the next time I want to do something similar, I have a starting point. This is true even if it is years after I last looked at that area.
So, here is the shell script that I used to build the image for MongoDB:
docker build -t mongo_img .
The . at the end for the current directory will cause docker to look for Dockerfile in the current directory. The image that is created will be named mongo_img.
Viewing Docker images
From the command line, you can display the built images using this command:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mongo_img latest a96f2a8a692f 6 days ago 1.34GB
pg_img latest 5145bb1ce1de 2 weeks ago 460MB
You can see that I have two images that have been created. Take note of the IMAGE ID. If you want to remove an image, you first make sure there are no containers that are using that image. Then, you can remove that image using a command like this:
$ docker image rm 5145bb1ce1de
That is, if you wanted to remove the image named pg_img.
Creating a Docker container
Just as with creating an image, I use a simple shell script to create a Docker container. So, for the MongoDB container, I used the following script:
docker container run -d --name=mongo_cont mongo_img
The part of the command docker container run will run a Docker container. The -d switch means to run the container as a daemon in the background. This will keep your terminal from displaying messages from the container, but also get you back to the terminal prompt so you can issue other commands.
The part of the command --name=mongo_cont will name the container mongo_cont. Finally, the mongo_img at the end of the command gives the name of the Docker image to use to create the container.
Stopping and stopping a Docker container
If you ran the shell script, create_container.sh, then the container mongo_cont would be running. To stop the container, this is the command:
$ docker stop mongo_cont
To start/restart the container, you use the following command:
$ docker start mongo_cont
Inspecting a Docker container
To see if there are Docker containers running, you can run the following command:
$ docker container ls
Suppose there are no Docker container running, this is what you would see:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
That is, you will see the headers, but nothing listed.
But, if you modify that command to include the -a switch (to display all), here is what you might see:
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c46899468839 mongo_img "python3 /usr/local/…" 6 days ago Exited (137) 5 days ago mongo_cont
b28549e574c6 pg_img "docker-entrypoint.s…" 2 weeks ago Exited (0) 7 days ago pg_cont
So, my containers mongo_cont and pg_cont listed in the NAMES column are not running. But, they exist and could be started up with a command like this:
$ docker start mongo_cont
With the container running, you can inspect the container’s properties. Here this is shown for the mongo_cont container:
$ docker start mongo_cont
mongo_cont
vern@msi-lianli-build:~/Documents/practicalcompute.cc$ docker inspect mongo_cont
[
{
"Id": "c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2",
"Created": "2025-08-12T20:12:50.707259439Z",
"Path": "python3",
"Args": [
"/usr/local/bin/docker-entrypoint.py",
"mongod"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 180038,
"ExitCode": 0,
"Error": "",
"StartedAt": "2025-08-19T06:15:48.197883728Z",
"FinishedAt": "2025-08-14T03:53:07.023010367Z"
},
"Image": "sha256:a96f2a8a692fd2dffaac39e3c89085b2a4631c46ea6c4397b3f5d18144f2cc94",
"ResolvConfPath": "/var/lib/docker/containers/c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2/hostname",
"HostsPath": "/var/lib/docker/containers/c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2/hosts",
"LogPath": "/var/lib/docker/containers/c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2/c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2-json.log",
"Name": "/mongo_cont",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"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": [
24,
80
],
"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/interrupts",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware",
"/sys/devices/virtual/powercap",
"/sys/devices/system/cpu/cpu0/thermal_throttle",
"/sys/devices/system/cpu/cpu1/thermal_throttle",
"/sys/devices/system/cpu/cpu2/thermal_throttle",
"/sys/devices/system/cpu/cpu3/thermal_throttle",
"/sys/devices/system/cpu/cpu4/thermal_throttle",
"/sys/devices/system/cpu/cpu5/thermal_throttle",
"/sys/devices/system/cpu/cpu6/thermal_throttle",
"/sys/devices/system/cpu/cpu7/thermal_throttle",
"/sys/devices/system/cpu/cpu8/thermal_throttle",
"/sys/devices/system/cpu/cpu9/thermal_throttle",
"/sys/devices/system/cpu/cpu10/thermal_throttle",
"/sys/devices/system/cpu/cpu11/thermal_throttle"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"ID": "c46899468839679bf6aeb10dfbbdf0af4e4e29902f68b87a9d63e877c03de7f2",
"LowerDir": "/var/lib/docker/overlay2/fe46921257a2f7655a1fb33c17535fd827c096ffadf9ae6cc7882e22bffd05dc-init/diff:/var/lib/docker/overlay2/b538a098e7aabb64cb1ed2299e9a9432a58cf71b7a1cff68c16bc418b47cb056/diff:/var/lib/docker/overlay2/a3141dc112cdde2a2942a53fcf6beb7b8d646ef1fa6f3e1609545a9114c18a2c/diff:/var/lib/docker/overlay2/be2b6ab0a7a8a74f4c419cb076efd1f23ee2aead3d9d5f3578b2f29ddd36e84b/diff:/var/lib/docker/overlay2/c5bfda2885e0b2460d3f10d07108782c0bac24f647aba02a47cf19f4a19c578b/diff:/var/lib/docker/overlay2/73aa8c6bd821ac328576baab059bfa7811bf42b03ef1cd13cd9b9bfaa9113f29/diff:/var/lib/docker/overlay2/7de704154b56d42ab59cdd66e564df9b31a2fa5963b177df6a509254047be6d2/diff:/var/lib/docker/overlay2/e3d00c27502c4608c5bb1b474a28bd3913347196c4cc6d5220d3d94a901e1940/diff:/var/lib/docker/overlay2/05c8d226c514e1062b8e96eeea1bca5d49d791b332e0cc157c1f22bf7bb8ac4b/diff:/var/lib/docker/overlay2/d545813276270479221d6849893ccb3fffec7e14fdc758b684f4ba1339191aa0/diff:/var/lib/docker/overlay2/a73c708c19f0c29a552eef078097c6a1fd01555a2afa8afdf49d5783b5c0de0c/diff:/var/lib/docker/overlay2/b0c0bd2e948aef172d034723b006dd9ca0d5b939b82a8f3bcd35f7f235129077/diff:/var/lib/docker/overlay2/491e9c0ebe18b4460af92bf5dce817f15fde7bcc476e3c3d210c404ea32c5f2a/diff",
"MergedDir": "/var/lib/docker/overlay2/fe46921257a2f7655a1fb33c17535fd827c096ffadf9ae6cc7882e22bffd05dc/merged",
"UpperDir": "/var/lib/docker/overlay2/fe46921257a2f7655a1fb33c17535fd827c096ffadf9ae6cc7882e22bffd05dc/diff",
"WorkDir": "/var/lib/docker/overlay2/fe46921257a2f7655a1fb33c17535fd827c096ffadf9ae6cc7882e22bffd05dc/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "volume",
"Name": "67ac450915ab74b1477d469f738938d516233ecbaf26194ebb2a7f37f9b91797",
"Source": "/var/lib/docker/volumes/67ac450915ab74b1477d469f738938d516233ecbaf26194ebb2a7f37f9b91797/_data",
"Destination": "/data/configdb",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "a9c694f59b5e555d74b3de04185bf82947782129737ebf9f42bf0a852e73ed5d",
"Source": "/var/lib/docker/volumes/a9c694f59b5e555d74b3de04185bf82947782129737ebf9f42bf0a852e73ed5d/_data",
"Destination": "/data/db",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "c46899468839",
"Domainname": "",
"User": "mongodb",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"27017/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/data/db"
],
"Cmd": [
"mongod"
],
"Image": "mongo_img",
"Volumes": {
"/data/configdb": {},
"/data/db": {}
},
"WorkingDir": "",
"Entrypoint": [
"python3",
"/usr/local/bin/docker-entrypoint.py"
],
"OnBuild": null,
"Labels": {
"description": "Container configured with a standalone instance of MongoDB",
"maintainer": "support@mongodb.com",
"name": "MongoDB Standalone",
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "22.04",
"summary": "MongoDB Standalone Container",
"vendor": "MongoDB",
"version": "8.0.12"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "b24af5f50e1d6a73600ef1929494cf154def1a1daac9078293d3c9f99a6d351b",
"SandboxKey": "/var/run/docker/netns/b24af5f50e1d",
"Ports": {
"27017/tcp": null
},
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "b785f65cbe90226fc7dd26d4b8c1bfd2c1333ffa842a800a76c0586175de438d",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "ea:99:a2:e9:c8:0f",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "ea:99:a2:e9:c8:0f",
"DriverOpts": null,
"GwPriority": 0,
"NetworkID": "766a87ebbfd26e5565d46dbae493fba95fb72573f6e6f3081632d4f5bf95e322",
"EndpointID": "b785f65cbe90226fc7dd26d4b8c1bfd2c1333ffa842a800a76c0586175de438d",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": null
}
}
}
}
]
This is a lot of information. So, typically, you would use pipe the output to the grep command to view what you want to see more easily.