One of the biggest challenges for implementing cloud native technologies is learning the fundamentals—especially when you need to fit your learning into 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.
In the last lesson, we learned how to create container images from Dockerfiles. This time, we’ll practice using a public container registry to store and share our container images.
Table of Contents
- What is a Container?
- Creating, Observing, and Deleting Containers
- Build Image from Dockerfile
- Using an Image Registry←You are here
- 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
Digging deeper into registries
Here’s a secret: we’ve been quietly using an image registry all along. Whenever we’ve built on top of container images like
alpine, the Docker engine has downloaded those images from Docker Hub, a public container registry managed by Docker, Inc. It can seem like magic—the software we want appears almost as quickly as we can summon it by name!
But what do we mean, exactly, when we say that Docker Hub is a public image registry? In short, it’s a repository (or collection of repositories) that anyone can access to download or upload container images.
In our first lesson, we noted that Docker Hub isn’t the only container image registry. There are public registries managed by other entities, and it is also possible for organizations to create private registries using tools like Mirantis Secure Registry. Anyone who needs to establish a secure software supply chain will need to be able to trust the provenance and contents of their container images, and should therefore use a private registry of some form.
The swiftness, accessibility, and built-in nature of Docker Hub make it a natural choice for learners, but it’s a good idea to cultivate security-consciousness and other best practices from the outset. One way to do this is to investigate images you intend to use through Docker Hub’s web interface at https://hub.docker.com/. There are several labels here that can help you to identify vetted images.
Let’s take a look at
alpine, for example, at https://hub.docker.com/_/alpine.
This has the Official Image label, meaning it is part of a set of images curated and published by Docker. These are very commonly used images that most beginners will want to use—verified as the upstream official version and exemplifying container best practices in design and documentation. Many are OS base images like
ubuntu, but there are also images for popular languages like Python, Go, or Node; data stores like MySQL or Redis; web servers like Nginx; and much more.
The Docker registry also provides another label for a Verified Publisher. Docker has confirmed that images with this label are published and maintained by the entities that produced them. For example, users of Amazon Web Services (AWS) can download a container image for their command-line interface (CLI) that is confirmed to come from Amazon.
There is no such thing as perfect security—by accident or malice, vulnerabilities can creep into even official images—but as you get started using containers, develop a habit of asking questions about the provenance of your images and seeking out validated sources. The catalog of Docker images that are either designated Official Images or from Verified Publishers is a good place to start.
Exercise: Uploading our first container
If you haven’t done so already, you’ll need to sign up for a Docker ID, which will serve as your credentials for Docker Hub. If you’re using Docker Desktop on macOS or Windows, this is the same ID you created to log in. (If you don’t have an ID yet, you can sign up for one at https://hub.docker.com/.)
On the command line, type:
You’ll be prompted for your username and password. Once you’ve successfully entered your credentials, you’re ready to get started.
First, we’ll create a new container based on the official Python image and enter an interactive session with a bash shell:
docker run -it python bash
Now we should be working in a bash shell within our new container. Here, let’s use the apt package manager to download the nano command line text editor.
apt install nano
Now we’re going to write a simple Python program within our container. Use nano to create and open a new Python file:
In this file, we’re going to write a simple Python program that produces a random integer between 1 and 6, inclusive. In other words, we’re writing a program that rolls a virtual die! Don’t worry if you’re unfamiliar with Python—you can simply copy and paste the code below into your file:
#import module from random import randint #assign a random integer between 1 and 6, inclusive, to a variable roll = randint(1, 6) #print the variable print(roll)
Press CTRL-O to write to the file, enter to confirm, and then CTRL-X to exit nano. You may wish to test our new program by running:
In your container’s bash shell, you’ll receive a randomized result from 1 to 6.
Without exiting the container, open another command line session on your host machine. (In Terminal on macOS, for example, this is a simple matter of pressing command-T to open another tab.) Your Python container should still be running, so you can enter…
docker container ls…to retrieve its container ID.
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
python "bash" 1 hour ago Up 4 minutes
Now we’re going to commit the current state of our container to a new image—including the Python program we just wrote.
docker commit -m “First commit”
Let’s take a moment to walk through this commit step by step. The -m flag enables us to append a short descriptive message; this is a good practice for recording the headline changes made within a commit, whether you’re working on a team or leaving breadcrumbs for yourself or others in the future.
Next, you’re specifying the container ID that forms the basis of your commit.
Finally, you’re assigning the image name—in this case, “d6”—and tagging it with a version number (here, that’s 1.0).
The commit has created a new image on our local machine. We can see it on our system with…
docker image ls
You should see the new image name at the top of the listing, with output something like this:
REPOSITORY TAG IMAGE ID CREATED SIZE d6 1.0
1 hour ago 939MB
Let’s take that one step further and upload our new image to Docker Hub. We’ll start by tagging our image for upload, and then push it online:
docker tag d6:1.0
The command line output will show you each of the layers being pushed:
The push refers to repository [docker.io/
/d6] e06d6e649287: Pushed 51a0aba3d0a4: Mounted from library/python e14403cd4d18: Mounted from library/python 8a8d6e9f7282: Mounted from library/python ...
Now your containerized die-rolling app is available for anyone to download as an image through the Docker registry. You should see it when you navigate to:
In this lesson, we’ve created a very simple “static” app—it produces output, but doesn’t have to store any data for later use. Next time, we’ll explore how to handle persistent data stores with containers.