This week, I wanted to poke around the Docker command line interface (CLI) to see how it can help me troubleshoot something or accomplish a goal. A few weeks ago as I was reading the very awesome book Docker Up & Running: Shipping Reliable Containers in Production by Sean P. Kane and Karl Matthias, I scribbled down a note next to a command. The scribble was, "What does --rm do?".
If you've already created a docker container and you want to manually remove it from your host, you can use the command
docker rm <containername>.
But if what you want to do is use a single command to instruct the docker daemon to do three things—
1) pull an image,
2) create and run a container from that image, AND
3) remove the container right after
—then you can use
docker run --rm.
Last week, I ran
docker run ubuntu, which pulled the
ubuntu:latest image, ran an instance (container) of that image with the command
/bin/bash, and exited the container afterwards. Recall that this happens because Ubuntu is not an application or process but rather a base operating system image, so by design the ensuing container doesn't have any process running inside and is therefore terminated fractions of a second after it runs. But we were still able to double-check that the container indeed ran by typing
docker ps -a.
However, let's see what happens if we use an alternative command with the --rm option:
docker run --rm ubuntu
What does this do? Let's find out by using Docker's insanely helpful --help option in the CLI.
If we type
docker run --help, the inline Docker manual tells us that the
--rm flag will "automatically remove the container when it exits".
We can check for this because neither
docker ps nor
docker ps -a will list any container. But this begs the question: how can we tell the difference between "never having run any containers" and "having run containers that have since been deleted (or automatically removed)"?
Let's see if
docker --help can give us such clues.
First, try running
docker --help in your CLI. That will print the following:
$ docker --help Usage: docker [OPTIONS] COMMAND A self-sufficient runtime for containers Options: --config string Location of client config files (default "/root/.docker") -c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use") -D, --debug Enable debug mode -H, --host list Daemon socket(s) to connect to -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem") --tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem") --tlskey string Path to TLS key file (default "/root/.docker/key.pem") --tlsverify Use TLS and verify the remote -v, --version Print version information and quit Management Commands: app* Docker Application (Docker Inc., v0.8.0) builder Manage builds checkpoint Manage checkpoints config Manage Docker configs container Manage containers context Manage contexts engine Manage the docker engine image Manage images manifest Manage Docker image manifests and manifest lists network Manage networks node Manage Swarm nodes plugin Manage plugins secret Manage Docker secrets service Manage services stack Manage Docker stacks swarm Manage Swarm system Manage Docker trust Manage trust on Docker images volume Manage volumes Commands: attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container deploy Deploy a new stack or update an existing stack diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes
Our goal is to figure out if there's a command in Docker that will show us a historical record of any containers that we previously ran, even if they were eventually deleted. So what we want to do is look for clues in the
--help printout as to which command may help us display such a record.
Unfortunately for us, none of the Options in the list seem relevant to this quest. But in the Management Commands section,
container looks promising.
So let's run
docker container --help to drill down on what the
container command does. Here's the output:
$ docker container --help Usage: docker container COMMAND Manage containers Commands: attach Attach local standard input, output, and error streams to a running container commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem exec Run a command in a running container export Export a container's filesystem as a tar archive inspect Display detailed information on one or more containers kill Kill one or more running containers logs Fetch the logs of a container ls List containers pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container prune Remove all stopped containers rename Rename a container restart Restart one or more containers rm Remove one or more containers run Run a command in a new container start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers wait Block until one or more containers stop, then print their exit codes
container command is used to manage containers, which we can do by using all the commands listed just above. Among them, the
logs commands initially appear to have potential. Sadly, they won't help either: we don't actually know the name or container ID of a container to refer these commands to. Alone,
docker container inspect and
docker container logs won't actually turn up anything. Neither will
docker container ls, since there are no containers running.
In the main list of commands above, I discovered a command I hadn't used before:
docker info. In addition to running
docker ps -a, we can use
docker info to confirm that no containers are running. It will list, among much else, the following:
$ docker info [...] Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 1 [...]
So yea. We have one image (i.e., ubuntu:latest) running, but zero containers. With zero containers running, and no containers that ran but have not yet been deleted, we can't retrieve a container ID, which is necessary to use the
We are at a dead end.
What we need is a list of activity that will display the container ID of the container that was created and exited when we first ran
docker run --rm ubuntu above. However, none of the commands explored above, or found through the --help option, seem to do that.
At this point, one has to wonder if our assumption is even correct: does Docker even keep a log of containers that ran in the past (or during the current session) but no longer exist? On the one hand, this would be useful, to be able to distinguish "containers that happened" yet are no longer visible from "containers that never happened". If the daemon doesn't know the difference, then neither can we.
Being at this impasse, if I Google, "how to list the last docker container that ran", I only find two things that offer clues as to possible next steps:
- Some folks who wished to restore an accidentally deleted container have been able to do so by navigating to the directory
/var/lib/docker/volumes/<containerIDfolder>/_data. I don't know how to do that yet, though.
- Docker's documentation describes the interplay between the local storage area of a running container and the
/datadirectory on a Docker host
But alas, we are once again out of time for this week's post. This has been a great way to get to know the Docker CLI and how to leverage
docker --help to quickly read the manual when attempting to solve a basic problem.
Great learning exercise! :)
I'm back on my Q&A grind. Here are a few questions I answered this week.
Q: How can I deploy AI models using Kubernetes?
Here's my answer:
For this question, you might find inspiration in some of the work being done to run ML models as microservices using a combination of Python, Flask, Docker, IBM’s Data Asset Exchange (DAX) network for open source data sets, IBM’s Model Asset Exchange (MAX) for open source deep learning models, and cloud-based Functions-as-a-Service (FaaS) platforms such as IBM’s own OpenWhisk.
What Docker does in this context is provide the containers and container runtime engine within which to perform certain aspects of training and using your models. If you have a need to run multiple, interacting containers, you might then use a container orchestrator such as Kubernetes. But the details will vary by your use case.
(The reason I say inspiration above is that there may be other approaches to doing something similar for what you want. Whereas the IBM approach is obviously targeted at enterprise uses of AI models, perhaps what you have in mind isn’t aimed at enterprise use cases. Nonetheless, the approach may offer you clues as to how you can go about doing what you’d like to do with containers).
Check out the following resources to see if there’s something helpful there:
- Leverage deep learning in IBM Cloud Functions
- IBM Data Asset eXchange
- IBM Model Asset eXchange
- Deploy deep learning models as a web microservice in minutes - Silicon Valley Code Camp (October 19-20 2019)
And here’s the recording of the presentation in the last link above (the lecture slides are in the comments of the video - see “Session Materials”):
Q: Would you put the frontend and the backend of a web app in different docker containers?
Here's my answer:
Ideally and in many scenarios, yes. One of the software design practices that Docker is suited to (and subtly enforces) is the isolation of processes in an application stack. This helps with long-term scalability, especially if you anticipate your app being used in a way that requires running thousands of containers or more. Since a Docker container is a single, short-lived instance of a single task, process, or application, then it might make more sense to separate the front-end component from the back-end one(s). For example:
- NodeJS in one container, with a MySQL database in another
- PHP running in one container, nginx running in a second container, and MariaDB running in a third
- A container with your front-end, another container with a cache service like Redis, and a database like MongoDB or CouchDB in yet another
In all of these scenarios involving multiple containers that are all necessary for your app to work, you’ll likely need a container orchestrator such as Docker Compose, Mesos, or Kubernetes.
Hope that helps.
Q: Do you see Windows containers as the next step in the evolution in virtualization or is it something that may fade away?
Here's my answer:
I’ll answer this more generally. With technology, it’s so hard to make predictions. Sure bets don’t always work out, and relative unknowns can become dominant forces over time. Within the span of 24–36 months, certain technologies and products can go from low adoption rates to rapid growth and eventually scale. So looking at the current state doesn’t help us much in anticipating the future; nobody can say for certain if Windows containers or Windows container runtime engines will or won’t experience rapid adoption in the future or become the go-to technology for OS-level virtualization. Just because something like 99% of the container ecosystem today is Linux-based doesn’t mean that this can’t change.
However, from what I’ve learned about containers and the container ecosystem—and I’m still at the very early stages of my learning—a few things are worth noting:
- Technologies that experience rapid adoption usually benefit from a lot of work that came before it. This is true in every tech space, but here are two examples involving containers.
- Docker has been a very successful container runtime engine, but its success came after lot of work by a lot of companies had been done on Linux kernels and containers. Perhaps there is foundational work being done today on Windows containers and Windows container runtime engines that isn’t visible to the mainstream but that will someday be looked upon as an example of why Windows containers became wildly successful.
- Kubernetes has gained immense popularity as a Linux container orchestrator, but Google was working on Kubernetes for many years and was running millions of containers with it before it open-sourced the project. Years later (today), Kubernetes seems like the container orchestrator. But perhaps Titus (Netflix’s orchestrator) will be the go-to orchestrator for tomorrow. Who’s to say that an orchestrator natively based on Windows containers won’t become the Kubernetes or Titus of tomorrow?
- Communities and network effects are wonderful, interesting drivers of product adoption. For instance, Facebook launched in 2004. It’s just fifteen years old. In a mere five 36-month timespans, it’s become the #6 most valuable company in the world and one of the most valuable companies of all time. It became that valuable this quickly due to its rapid adoption, the nature of networks and communities, and other just-in-time factors such as a rise in mobile phones, the reduced cost of telecommunications infrastructure, and new trends in how we consume media
- By analogy, Docker and Kubernetes have enjoyed relatively rapid adoption cycles within their user communities. This is in part because Docker and Kubernetes solved a problem for a large addressable market of developers, engineers, and businesses. It’s likely also the case that these two technologies have benefited from good timing, emerging at a time when variables external to them have nevertheless positively impacted their adoption curves. If Windows container and container runtime tools emerge under analogous circumstances, then who knows what will happen
In summary, it isn’t inconceivable to imagine that in the next 5–10 years, a useful Windows container technology could emerge just as the market is ready for it. I’m not saying that it will happen, but I’m saying that it’s unrealistic to think that it can’t. Businesses tend to respond to the behaviors and expectations of their consumers. Technologies tend towards addressing the needs and requirements that arise because of this. So the evolution of containers—be that with respect to Linux, Windows, or anything else—will likely be influenced by the interplay between these two factors.
Q: Where does Kubernetes pull images from?
Here's my answer:
Since Kubernetes is a container orchestrator and containers are built from container images (such as a Docker image), the images pulled by Kubernetes are also stored in a public or private container image registry. The technical documentation for Kubernetes says that you “can create your Docker image and push it to a registry before referring to it in a Kubernetes pod”.
Examples of image registries include Docker Hub, Docker Registry, Docker Trusted Registry (DTR) for enterprise, Google Container Registry, Amazon Elastic Container Registry (Amazon ECR), and many others. These all work with Kubernetes, so you can refer your images to your Kubernetes pods accordingly, pulling from a private registry if necessary.
Q: How do I push an image to Docker Hub?
Here's my answer:
This is typically accomplished from the Docker client with the following command:
docker push. What this command does, per Docker’s technical documentation, is to “push an image or a repository to a registry”. You can push an image to a public image repository such as Docker Hub, or to a private registry (see here for another answer of mine which references several public and private image repos).
Q: If you work in programming, should you learn Kubernetes?
Here's my answer:
This really depends on what you’d like to accomplish and if your programming work will require deploying containerized applications. If that’s the case, then learning about Docker may be a good investment of time, as that’s by far the most popular container runtime engine today. Docker is also heavily architected into Kubernetes. However, working with Kubernetes is a highly specialized skill and will likely take time to learn. If you do go in that direction, consider this resource.
I do hear that being able to debug and test your code in production with containers is a valuable skill to master, so if you plan to use Linux containers as part of your application stacks, then investing in learning Docker is likely a great idea.
These may be of service to you:
- I must say, one of the best Docker presentations I've seen thus far is Jerome Petazzoni's 2015 talk, Cgroups, namespaces, and beyond: what are containers made from?
- I've also started watching a much longer talk of Jerome's, his three-hour Introduction to Docker and Containers from PyCon 2016. It's accompanied by an INSANE resource at https://container.training/, with videos, previous workshops and presentations, and lecture slides for self-paced review. Enjoy!
And that about does it for this week's
docker learn. Thanks for spending some of your time with me, my learning, and my series! Have an awesome weekend, everyone!
My Educative team runs a pretty awesome blog. Not only do we interview amazing Educative Authors like C# legend Eric Lippert, but also sometimes we have guest blog posts on topics that—you guessed it—relate to container technologies. Two of our guest articles have been by Microsoft Developer Advocate and Docker Captain Scott Coulton. The two pieces are about Kubernetes, and since this week I answered a few K8s-related Docker questions, go ahead and also read Scott's Educative posts if you so fancy 😎👉🏾:
- Deploying my first service on Kubernetes: Demystifying ingress
- Pods, services, deployments... what do I use when?
Hit the heart button, share this DEV article with someone you care about, and see ya soon! <3