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.

Docker image container

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:

/path/to/mongo_db/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.

In the case of MongoDB, the maintainers of MongoDB have provided a base image that will definitely work. When you are trying create other images, you may have to take your best guess, and then just try the base image out to see if it works.

For example, in trying to get a base image for PostgreSQL I started by searching on "Docker postgresql" and Google returned several links include this one: Docker Hub: postgres. In the screen shot below, you can see that I clicked on the Tags link:

dockerhub postgres

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:

/path/to/postgres/Dockerfile
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:

/path/to/mongo_db/create_image.sh
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:

/path/to/mongo_db/create_container.sh
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
You can see from the listing using the -a switch, which image was used to create each container and when that container was created. You can also see the CONTAINER ID, which is the id you need to use to remove that container. So, if mongo_cont was not running and you wanted to remove it, you could do this:

$ docker container rm c46899468839

In case you accidentally remove the container this way, you can run your create_container.sh script to recreate it.

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.