Linux Foundation Certified System Administrator (LFCS)
Operations Deployment
Create and Manage Containers
Docker containers have become immensely popular due to their portability and ease of management. To illustrate their usefulness, let’s compare a traditional MariaDB database setup with one running inside a Docker container.
Traditionally, to install MariaDB on a Linux system, you would run:
$ sudo apt install mariadb-server
After the installation, you would need to adjust configurations in the /etc/mysql
directory, create databases, configure users, assign privileges, and manage log files. When it comes time to migrate this multi-component setup to a cloud server, the scattered pieces across various directories can make the process cumbersome.
Key Insight
By containerizing your application, such as setting up your MariaDB inside a Docker container, every component—including the daemon, configuration files, logs, and databases—resides within a single container. This makes migration as simple as copying one file.
Imagine moving your entire database within a single container to a cloud server or scaling it across multiple servers effortlessly.
Containers are designed to encapsulate applications, making them highly portable and scalable. Essentially, they are like copying and pasting an entire application setup in one go.
In this article, we will explore practical examples of how to work with Docker by running an Nginx web server within a container.
Using Docker Commands
Before diving into running containers, note that you can often execute Docker commands without sudo
if your Linux user is added to the docker
group. If you encounter permission errors, you can either prepend sudo
to your commands or add your user to the Docker group and then log out and back in.
For example, you might see an error like this:
aaron@kodekloud:~$ docker images
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/1.24/images/json": dial unix /var/run/docker.sock: connect: permission denied
By using sudo
, the command runs successfully:
aaron@kodekloud:~$ sudo docker images
[sudo] password for aaron:
REPOSITORY TAG IMAGE ID CREATED SIZE
john/custom nginx 1.0 ed97200c0c18 3 hours ago 187MB
customnginx 1.0 ed97200c0c18 3 hours ago 187MB
nginx latest 021283c8eb95 3 weeks ago 187MB
Exploring Docker Commands
If you're new to Docker, you can display all available commands by running:
$ docker --help
This command provides the following overview:
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Common Commands:
run Create and run a new container from an image
exec Execute a command in a running container
ps List containers
build Build an image from a Dockerfile
pull Download an image from a registry
push Upload an image to a registry
images List images
login Log in to a registry
logout Log out from a registry
search Search Docker Hub for images
version Show the Docker version information
info Display system-wide information
Management Commands:
builder Manage builds
container Manage containers
context Manage contexts
image Manage images
manifest Manage Docker image manifests and manifest lists
network Manage networks
plugin Manage plugins
system Manage Docker
One useful subcommand is search
which allows you to find images like Nginx:
$ docker search nginx
The output lists available images, and the top result is usually the official image:
NAME DESCRIPTION STARS
nginx Official build of Nginx. 19922
unit Official build of NGINX Unit: Universal Web … 31
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo… 92
nginxinc/nginx-unprivileged Unprivileged NGINX Dockerfiles 152
nginxinc/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGIN… 41
... (additional entries)
You can pull the official Nginx image by running:
$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
2cc3ae149d28: Pull complete
a97d90a43bc9: Pull complete
9571e65a55a3: Pull complete
0b432cb2d95e: Pull complete
24436767f2de: Pull complete
928c92caef0: Pull complete
ca6f48c6db4: Pull complete
Digest: sha256:0acab7c2237e052dc5adf1694ebce0b374063a62b2a1b7f2b3bc9cd3fb8c1ff
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
The term latest
at the end of the image name is known as the image tag—it functions similarly to a version label. For instance, latest
corresponds to the newest version, while a tag like 1.24.0
indicates a specific version. To pull an older version, run:
$ docker pull nginx:1.22.1
1.22.1: Pulling from library/nginx
f1f26f570256: Pull complete
fd03b214774: Pull complete
ef2f2c869944: Pull complete
ac713a9ef2cc: Pull complete
fd071922d543: Pull complete
2a9f38700bb5: Pull complete
Status: Downloaded newer image for nginx:1.22.1
docker.io/library/nginx:1.22.1
Managing Docker Images
After pulling images, it’s a good practice to remove any that are no longer needed. To list available images, run:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu/nginx latest cd238b5026e 3 days ago 128MB
nginx latest dde0cca083bc 2 weeks ago 188MB
nginx 1.22.1 0f8498f13f3a 14 months ago 142MB
To delete a specific image, such as the nginx:1.22.1
image, use the rmi
command. When multiple images share the same repository name, remember to specify the tag:
$ docker rmi nginx:1.22.1
Untagged: nginx:1.22.1
Untagged: nginx@sha256:fc5f5b747575c306aaf884566ebfe0b006240a184d52b923d2f0197108f6b7
Deleted: sha256:0f8498f13fadef3c82cdf069ecc880b01189be63491631d44eeaa5fb29...
After deletion, verifying your images again should show only the remaining ones:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest dde0cca083bc 2 weeks ago 188MB
Running Containers
Running a container is as easy as issuing the docker run
command. For instance, to run an Nginx container:
$ docker run nginx
This command creates a new container and starts the Nginx daemon. However, running the container this way attaches you to its output, making it challenging to run additional commands simultaneously.
The output may look similar to:
$ docker run nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
...
2024/06/14 02:40:53 [notice] 1#1: using the "epoll" event method
2024/06/14 02:40:53 [notice] 1#1: nginx/1.27.0
...
Pressing Ctrl-C will detach you from the container but will also stop it. To run the container in the background, publish ports, and assign it a descriptive name, use the following command:
$ docker run --detach --publish 8080:80 --name mywebserver nginx
This command does the following:
--detach
: Runs the container in the background.--publish 8080:80
: Maps port 8080 on the host to port 80 in the container.--name mywebserver
: Assigns the name "mywebserver" to the container.
To view currently running containers, use:
$ docker ps
You might see output like:
CONTAINER ID IMAGE COMMAND NAMES
34ef97c0c6a5 nginx "/docker-entrypoint..." mywebserver
Tip
Remember that docker ps
only shows running containers. Use docker ps --all
to list both active and stopped containers.
To start a stopped container, reference its container ID or name:
$ docker start 833adf46106a
833adf46106a
And validate its status with:
$ docker ps
If you need to stop a running container, simply run:
$ docker stop mywebserver
Testing the Published Port
After running your container with port mapping, it’s important to verify that it’s accessible. You can do this by connecting to the published port on your host using a tool like netcat (nc
):
$ nc localhost 8080
Type the HTTP request:
GET /
You should receive the HTML response of the Nginx index page:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Press Ctrl-D to terminate the netcat session.
Understanding Docker Run vs. Docker Start
It’s essential to understand the difference between docker run
and docker start
:
- docker run: Creates a new container from an image and starts it.
- docker start: Simply starts an existing, previously created container.
Use docker run
when the container does not already exist and docker start
to resume a stopped container.
Removing Containers and Images
Managing system resources involves cleaning up unused containers and images. To list all containers, run:
$ docker ps --all
To remove a stopped container (for example, one named determined_perlman
), execute:
$ docker rm determined_perlman
Important
Remember: the docker rm
command removes containers, while docker rmi
is used to remove images.
If an image is still in use, such as by the "mywebserver" container, attempting to remove it will result in an error:
$ docker rmi nginx
In that case, stop and remove the container first:
$ docker stop mywebserver
$ docker rm mywebserver
Then remove the image:
$ docker rmi nginx
Using Restart Policies
For scenarios where you need your Nginx container to restart automatically after errors or system reboots, you can add a restart policy. The basic command:
$ docker run --detach --publish 8080:80 --name mywebserver nginx
Can be enhanced with the --restart always
option to ensure continuous operation:
$ docker run --detach --publish 8080:80 --name mywebserver --restart always nginx
If the specified image is not available locally, Docker will automatically pull it.
Building Custom Docker Images
Sometimes, public images may not meet your exact needs, prompting you to build a custom image. Here’s how you can create your own image based on the Nginx image:
Create a directory for your project and navigate into it:
$ mkdir myimage $ cd myimage
Create a simple
index.html
file to serve as your custom HTML content:$ vim index.html
(Insert a line of text as a placeholder for your custom HTML content.)
Create a
Dockerfile
(note the capital D), which provides instructions for building your image:$ vim Dockerfile
Add the following content to the
Dockerfile
:FROM nginx COPY index.html /usr/share/nginx/html/index.html
This tells Docker to use the official Nginx image as the base and copy your custom HTML file into the appropriate directory inside the container.
Other commonly used Dockerfile instructions include:
- RUN: Executes commands during the image build (e.g., installing additional utilities).
- CMD: Specifies the default command to run when the container starts (which can be overridden).
- ENTRYPOINT: Ensures a command is always executed upon container initialization (and is less easily overridden).
Build your custom image using the following command (replace "jeremy" with your Docker Hub username if applicable):
$ docker build --tag jeremy/customnginximage:1.0 myimage
You should see output similar to:
Sending build context to Docker daemon 3.072kB Step 1/2 : FROM nginx ---> dde0cca083bc Step 2/2 : COPY index.html /usr/share/nginx/html/index.html ---> 58d5a293c951 Successfully built 58d5a293c951 Successfully tagged jeremy/customnginximage:1.0
This custom image can now be used in the same way as any other Docker image.
Summary
This article has covered the essentials of creating, managing, running, and building Docker containers—from using public images to constructing your own custom container images. With Docker’s powerful features, deploying applications at scale becomes a seamless process.
For further details and in-depth tutorials, consider exploring the following resources:
Happy containerizing!
Watch Video
Watch video content