Working with Docker Containers

Follow Us

Our Communities

Chapter 2: Working with Docker Containers

Welcome to Chapter 2 of our Docker tutorial series. In this chapter, we’ll delve deeper into Docker and explore Docker Containers, which are central to Docker’s functionality. A Docker container is a standalone, executable software package that includes everything needed to run an application, including the code, a runtime, libraries, environment variables, and config files.

Our discussion will start with an introduction to Docker Containers, followed by detailed steps on how to create, manage, and interact with them. We will also discuss Docker Container Networking, providing an overview of network drivers and explaining how to create, connect, and inspect Docker networks.

The latter part of this chapter will focus on Docker Volumes, which offer a mechanism to persist data and share data among containers. This section will detail the process of creating, using, and managing Docker Volumes.

By the end of this chapter, you will have gained a comprehensive understanding of Docker Containers, and you’ll be equipped with the knowledge and skills necessary to create, manage, and interact with containers effectively. You’ll also learn how to set up container networking and manage data persistence using Docker Volumes.

Now, let’s dive in and start exploring the world of Docker Containers!

What is a Docker Container?

A Docker container is a lightweight, standalone, executable package that includes everything needed to run a piece of software. But what does this really mean? Let’s break it down:

Lightweight: Docker containers are designed to be minimalist, carrying only what’s necessary for the application they house to run. This approach is a significant departure from traditional virtualization, which involves bundling a complete operating system with each application. Docker containers share the host system’s kernel, making them much lighter than virtual machines.

Standalone: Each Docker container runs in isolation, meaning it doesn’t interfere with other containers or the host system. This separation is made possible by Docker’s use of namespaces and cgroups, Linux features that isolate resources per process (or group of processes).

Executable Package: Docker containers are runnable instances of Docker images. Think of an image as a class in object-oriented programming, while a container is an instance of that class. Once a Docker image is created, it can be used to spawn one or more containers. Each container can be started, stopped, moved, or deleted independently of other containers and the image it was created from.

Everything Needed to Run: Docker containers encapsulate everything required to run an application. This includes the application’s code, runtime, system tools, libraries, and environment variables. The benefit here is the guarantee that the application will always run the same, regardless of the environment it’s running in.

Understanding Docker containers is a key part of grasping the Docker ecosystem. It’s essential to remember that a container runs an application with its entire runtime environment. The isolation and security allow you to run many containers simultaneously on your host machine. The lightweight nature means you can get more value from your hardware by dramatically increasing the number of applications you can run on the same hardware.

In a nutshell, Docker containers have revolutionized software delivery, offering an innovative platform that enables applications to be constructed from layered Docker images, orchestrated and scheduled effectively, scaled out, and more.

Creating Docker Containers

Once you understand what a Docker container is, the next logical step is to learn how to create one. Docker containers are created from Docker images, which are templates that contain the application code, dependencies, libraries, and other resources needed to run the application. To create a container, you’ll primarily use the docker run command, followed by the name of the Docker image.

The docker run Command

The basic syntax for creating a container is: docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...].

Let’s break this down:

    • docker run: This is the command used to create and start a new Docker container.
    • OPTIONS: These are optional and can be used to modify the behavior of the Docker run command. Some common options include -d (detached mode), -it (interactive mode with terminal), and -p (port mapping).
    • IMAGE[:TAG|@DIGEST]: This is the name of the Docker image that the container will be based on. The image can be on your local machine, or it can be in a remote repository like Docker Hub. Optionally, you can specify a tag or a digest to use a specific version of the image.
    • COMMAND: This is optional and specifies a command that will be run when the container starts. If no command is specified, the default command defined in the image will be used.
    • ARG...: These are optional and represent arguments that will be passed to the command.

Running a Docker Container

For example, if you wanted to create and run a new container using the latest official Ubuntu image from Docker Hub, you would use the following command:

docker run -it ubuntu bash

Let’s analyze this command:

    • docker run: As explained above, this command is used to create and start a new Docker container.
    • -it: This option tells Docker to allocate a pseudo-TTY connected to the container’s stdin and run the container in interactive mode. Essentially, this allows you to input commands into the container directly from your terminal.
    • ubuntu: This is the name of the Docker image that the container will be based on. Docker will first look for this image on your local machine. If it can’t find it, it will then attempt to pull it from a remote repository (in this case, Docker Hub).
    • bash: This is the command that will be run when the container starts. In this case, it’s opening a bash shell in the container.

Docker Run in Detached Mode

Docker also allows you to run containers in the background (i.e., detached mode) by using the -d option. For instance, you could start an Nginx server in the background with the following command:

docker run -d -p 8080:80 nginx

The -p 8080:80 option is mapping port 80 in the container to port 8080 on the host machine. This means you could access the Nginx server by navigating to localhost:8080 in your web browser.

Creating Docker containers is a fundamental aspect of working with Docker. The ability to create and run containers swiftly, irrespective of the host operating system, is part of what makes Docker such a powerful tool for software development and distribution. In the next sections, we’ll delve into managing and interacting with these containers, deepening our understanding and capabilities with Docker.

Managing Docker Containers

After creating Docker containers, it’s important to understand how to manage them. Docker provides several commands to manage the lifecycle of a container. Below, we’ll discuss some of the most commonly used commands for managing Docker containers:

Listing Docker Containers

The docker ps command is used to list all running Docker containers. If you want to see all containers, including both running and stopped containers, use the docker ps -a command.

Starting and Stopping Docker Containers

Docker containers can be started and stopped using the docker start and docker stop commands, respectively. These commands require the name or ID of the container you want to start or stop. For example, to stop a running container, you can use docker stop my_container, where ‘my_container’ is the name of your Docker container.

Removing Docker Containers

When you no longer need a Docker container, you can remove it using the docker rm command. Like the start and stop commands, the docker rm command requires the name or ID of the container you want to remove. It’s important to note that the container must be stopped before it can be removed. If you want to remove a running container, you can use the -f option to forcibly remove it: docker rm -f my_container.

Inspecting Docker Containers

To view detailed information about a Docker container, use the docker inspect command. This command provides low-level information about the container in JSON format, such as its configuration, state, network settings, and more.

Viewing Logs of Docker Containers

Docker provides the docker logs command to view the logs of a Docker container. This command is useful for debugging purposes. For instance, if your application is crashing, you can use the docker logs my_container command to view the application’s output and error messages.

Executing Commands in Docker Containers

Sometimes, you may need to execute commands in a running Docker container. The docker exec command allows you to do this. For instance, if you want to get a shell in a running container, you can use the docker exec -it my_container bash command.

By understanding and using these Docker commands, you’ll be able to efficiently manage your Docker containers, leading to smoother development workflows and better control over your Docker environment. Remember, good container management is key to leveraging Docker’s full potential. In the next sections, we’ll dive deeper into interacting with Docker containers and understanding their internal workings.

Interacting with Docker Containers

Interaction with Docker containers is a crucial aspect of working with Docker. Whether you’re debugging an application, monitoring runtime behavior, or managing data within containers, knowing how to interact with your containers effectively will improve your Docker experience.

Executing Commands in a Running Container

The docker exec command allows you to run commands in a running Docker container. The basic syntax of the docker exec command is docker exec [OPTIONS] CONTAINER COMMAND [ARG...].

For instance, to start a bash shell in a running container named ‘my_container’, you would use the following command:

docker exec -it my_container bash

In this command, -it instructs Docker to allocate a pseudo-TTY connected to the container’s stdin, creating an interactive bash shell in the container.

Attaching to a Running Container

The docker attach command can be used to attach your terminal’s input, output, and error streams to a running container, using its ID or name. This can be useful for debugging or if you wish to see the real-time output from your container.

For example, to attach to a running container named ‘my_container’, you would use the following command:

docker attach my_container

Please note that you can detach from the container and leave it running using the CTRL-p CTRL-q sequence.

Copying Files to/from a Docker Container

Docker provides the docker cp command to copy files to and from Docker containers, similar to the cp command in Linux. This can be useful for tasks like debugging a running application or updating the configuration files inside a container.

The basic syntax for copying files from the host to a container is: docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH. For example:

docker cp myfile.txt my_container:/tmp/myfile.txt

And to copy files from a container to the host, you would use the command like this: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH. For example:

docker cp my_container:/tmp/myfile.txt ./myfile.txt

Interacting with Docker containers is an essential aspect of managing the lifecycle of an application running inside a container. The above commands make it easy for developers to connect to and interact with a running Docker container, enhancing their control over the applications and their runtime environment. In the next sections, we’ll look at Docker container networking and how Docker handles data persistence.

Docker Container Networking

Networking is a fundamental part of Docker. Docker’s networking capabilities allow containers to communicate with each other and with other systems over a network. Docker accomplishes this through the use of network drivers and by setting up complex network configurations.

Docker Network Drivers

Docker comes with several network drivers that allow you to apply different networking configurations to your containers:

    • Bridge: This is the default network driver for a container. When you create a new container without specifying a network, Docker automatically attaches it to a default bridge network.
    • Host: Removes the network isolation between the Docker host and the Docker containers to use the host’s networking directly.
    • Overlay: Allows multiple Docker daemons to communicate with each other. This network driver is used when creating a Docker Swarm.
    • Macvlan: Assigns a MAC address to a container, making it appear as a physical device on your network.
    • None: Disables all networking.

Creating a Docker Network

You can create a custom network in Docker using the docker network create command. For example, to create a new bridge network, you would use the following command:

docker network create --driver bridge my_network

This command creates a new bridge network named ‘my_network’.

Connecting a Docker Container to a Network

You can connect a Docker container to a network when you start the container using the docker run command and the --network option:

docker run -d --name my_container --network my_network my_image

You can also connect a running Docker container to a network using the docker network connect command:

docker network connect my_network my_container

Inspecting Docker Networks

To view information about a Docker network, use the docker network inspect command:

docker network inspect my_network

This command displays detailed information about the ‘my_network’ network in JSON format.

Docker’s networking capabilities provide a robust system for containers to communicate. By understanding Docker networking, you can control how your containers communicate with each other and other networks, giving you the flexibility to create complex, interlinked applications that can span multiple hosts. In the next sections, we’ll explore more complex Docker topics, like data persistence and Docker use cases.

Inspecting Docker Containers

Inspecting Docker containers allows you to view detailed information about a container’s configuration, state, and more. This information can be incredibly useful for debugging or when you need to know specific details about a running container, such as its IP address or its mounted volumes.

Docker provides the docker inspect command to inspect Docker objects like containers, images, volumes, and networks. For the purpose of this topic, we’ll focus on using it to inspect Docker containers.

The docker inspect Command

The basic syntax for the docker inspect command is docker inspect [OPTIONS] NAME|ID [NAME|ID...].

The docker inspect command can be used to retrieve low-level information about a Docker object, in this case, a container. The command accepts the name or ID of the container you wish to inspect and outputs the information in JSON format.

For instance, to inspect a container named ‘my_container’, you would use the following command:

docker inspect my_container

This command will output a large amount of JSON data about the container.

Filtering docker inspect Output

Given the large amount of information the docker inspect command returns, it can be difficult to find the specific information you need. Docker provides a way to filter this output using the -f or --format option and a Go language template.

For instance, if you only wanted to know the IP address of a running container, you could use the following command:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my_container

This command would return only the IP address of the ‘my_container’ container.

The docker inspect command is a powerful tool for understanding the internals of your Docker containers. Whether you’re debugging an issue or simply want to know more about a container’s configuration or state, docker inspect provides you with a deep look into your Docker containers. In the next sections, we’ll delve deeper into Docker, discussing more advanced topics like Docker images and Dockerfile.

Working with Docker Container Volumes

One of the challenges when working with Docker containers is persisting data. By default, any data that is created inside a Docker container is lost when the container is removed. Docker Volumes provide a way to persist data generated by and used by Docker containers.

What are Docker Volumes?

Docker Volumes are the preferred way of handling persistent data created by and used by Docker containers. They are completely managed by Docker and can be shared among multiple containers. Volumes work on both Linux and Windows containers and are a better alternative to bind mounts because of their improved performance and support for Docker CLI commands.

Creating Docker Volumes

You can create a Docker Volume using the docker volume create command. For example, to create a volume named ‘my_volume’, you would use the following command:

docker volume create my_volume

Using Docker Volumes with Docker Containers

Once you’ve created a volume, you can use it with a Docker container by specifying the -v or --volume option in the docker run command.

For instance, to start a new container and mount the ‘my_volume’ volume to the ‘/app’ directory inside the container, you would use the following command:

docker run -d --name my_container -v my_volume:/app my_image

Listing and Inspecting Docker Volumes

To list all Docker volumes, use the docker volume ls command. If you want to view detailed information about a specific volume, use the docker volume inspect command. For example:

docker volume inspect my_volume

Removing Docker Volumes

To remove a Docker volume, use the docker volume rm command. Keep in mind that you cannot remove a volume that is in use by a container. If you want to remove all unused volumes, you can use the docker volume prune command.

Docker Volumes are an essential tool for any Docker user. They provide a way to persist data and can be shared among multiple containers, making them an excellent solution for many common Docker use cases. In the next sections, we’ll discuss other important Docker topics, such as Docker Networking and Docker Images.

Exercise & Labs

Exercise 1: Creating and Managing Docker Containers

Create a Docker container using the alpine image. The container should run in detached mode and print “Hello, Docker!” when it starts.

List all running Docker containers and note the CONTAINER ID of your new container.

Execute the ls command in the running container from step 1.

Stop the Docker container from step 1.

Start the Docker container from step 1.

Remove the Docker container from step 1.

Exercise 2: Interacting with Docker Containers

Create a Docker container using the ubuntu image. The container should run in detached mode.

Execute an interactive bash shell in the running container from step 1.

Create a new text file in the running container from step 1. The text file should contain some sample text.

Copy the text file from the running container to your local machine.

Exercise 3: Docker Container Networking

Create a new Docker bridge network.

Create two Docker containers that are connected to the new network. They should run in detached mode using the alpine image.

Execute an interactive shell in one of the containers and ping the other container using its container name.

Exercise 4: Inspecting Docker Containers

Create a Docker container using the nginx image. The container should run in detached mode.

Inspect the Docker container and find its IP address and MAC address.

Exercise 5: Working with Docker Container Volumes

Create a new Docker volume.

Create a Docker container using the alpine image. The container should run in detached mode and mount the volume from step 1 to the ‘/data’ directory.

Write some data to the ‘/data’ directory in the running container.

Inspect the volume from step 1 and find its Mountpoint.

These exercises will help students practice the key tasks associated with managing Docker containers, networking, and volumes. They also provide practical examples of how to use the docker exec, docker cp, docker network, docker inspect, and docker volume commands.

Docker Introduction & Installation

UP NEXT

Working with Docker Images