One of the biggest challenges for implementing cloud native technologies is learning the fundamentals — especially when you need to fit your learning in a busy schedule.
In this series, we’ll break down core cloud native concepts, challenges, and best practices into short, manageable exercises and explainers, so you can learn five minutes at a time. These lessons assume a basic familiarity with the Linux command line and a Unix-like operating system — beyond that, you don’t need any special preparation to get started.
Table of Contents
- What is a Container?
- Creating, Observing, and Deleting Containers←You are here
- Build Image from Dockerfile
- Using an Image Registry
- Volumes and Persistent Storage
- Container Networking and Opening Container Ports
- Running a Containerized App
- Multi-Container Apps on User-Defined Networks
- Docker Compose and Next Steps
docker container run alpine echo Hello World
This command will call up Docker Engine and ask it to create a new container with
We’re telling it to use a container image (more about those in our next lesson) called
alpine which gives our container the binaries and libraries of a very lightweight Linux distribution as its foundation.
The next parameters specify a process to run within our new container: the system command
echo which outputs strings.
“Hello World” is an argument passed to
echo — the string we would like to output.
When we run this command, Docker should download the alpine image and then run the process, producing terminal output like this:
Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Already exists Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest Hello World
Those using Docker Desktop may open the application and find the new container represented (with a randomly generated name) in the graphical user interface.
Now let’s get a little more advanced and create a container with a continuously running process. We’ll use the same basic command structure as before, but this time we’ll run the ping command inside our container:
docker container run alpine ping localhost
We’ll notice a few differences this time. First, we already had the
alpine image on our machine, so the container started immediately. Second, the command doesn’t finish the way
echo did. The ping process is ongoing, continuously checking network connectivity. We can stop the process by pressing CTRL+C.
After stopping the process, let’s take a look at the containers on our system using the terminal. We can already see this in Docker Desktop if we’re on Mac or Windows, but it’s useful to be able to bring up this information quickly in the terminal.
docker container ls -a
Since we used the
-a flag, this will list all of our containers, whether they are running or not — we should see both our
echo and our
ping containers, along with some useful information such as their names and container IDs. Make a note of the
ping container’s ID. Mine, for example, is
Now let’s restart our ping container. Using the start command will run the process separately from our current shell, so we can enter other commands while the container process runs. You’ll replace
5480aa85d1c5 below with the ID of your container.
docker container start 5480aa85d1c5
The terminal will return the container ID to let us know that it’s running. We can also use the ls command without the
docker container ls
This shows us only running containers. Our
ping container should be listed here, but not the
Before we finish up, let’s inspect our container a little more closely in order to better understand what’s happening under the hood. If we use the top command with a running container ID, we’ll get information about the processes running within the container from the perspective of the host system:
docker container top 5480aa85d1c5
This gives us output looking something like this:
UID PID PPID C STIME TTY TIME CMD root 3509 3481 0 16:17 ? 00:00:00 ping localhost
The second column, PID, indicates the process identifier number for our containerized ping. This is the number the host machine’s operating system kernel is using to keep track of processes running on the machine, and in my case we can see that it is one of thousands. So we see that the ping process is using the host OS kernel, and we see how the kernel perceives the process: number 3509 in a long list.
But we said before that one way containers isolate themselves is through kernel namespaces: the way processes signify themselves relative to the kernel within the container. Metaphorically, we can think of this as the way the process sees itself versus the way the wider world sees it. Let’s take a look at the container from its own perspective:
docker container exec 5480aa85d1c5 ps
This gives us information on the processes running within the container from its perspective. In the container’s kernel namespaces, the ping process is PID 1. We’ll also see a listing for the
ps command we just ran within the container. And that’s it!
The ping running as PID 1 within the container is the very same process as the one signified by PID 3509 on the wider system, but because the container has its own isolated kernel namespaces, its system doesn’t see the wider world outside.
Now let’s clean up. We can stop our running container (again, replacing the numeric ID with your own) using:
docker container stop 5480aa85d1c5
Now we can clean up using:
docker container rm 5480aa85d1c5
It’s an important piece of system hygiene to remove unused containers. Make sure you remember to remove the echo container as well — you can use the
ls command with the
-a flag to retrieve its id.
In the next lesson, we’ll take a closer look at container images.