Introduction
Welcome to this hands-on lab on the basics of container security with Docker. Docker is a powerful platform for developing, shipping, and running applications in containers. While containers provide process isolation, securing them is crucial for protecting your applications and the host system.
In this lab, you will explore Docker container security fundamentals. You will first verify that Docker is properly configured in the LabEx environment. Then, you will run a basic Nginx web server container, inspect its running processes, and examine its resource consumption. Finally, you will learn how to apply fundamental security controls by setting resource limits on a container.
By the end of this lab, you will have a practical understanding of the initial steps involved in securing a Docker environment.
Verify Docker Installation and Setup
In this step, you will verify that Docker is already installed in the LabEx environment and ensure you have the proper permissions to use it.
The LabEx virtual machine comes with Docker pre-installed. Let's first check the Docker version to confirm it's available.
docker --version
You should see an output similar to this, confirming that Docker is installed correctly:
Docker version 20.10.21, build 20.10.21-0ubuntu1~22.04.3
Now let's check if the Docker daemon is running:
sudo systemctl status docker
This command will show you the status of the Docker service. You should see that it's active and running.
To run Docker commands without sudo, your user needs to be in the docker group. In the LabEx environment, your user is already configured with the proper permissions. Let's verify this:
groups $USER
You should see docker in the output, confirming that your user has the necessary permissions:
labex : labex sudo docker ssl-cert
Since your user is already in the docker group, you can run Docker commands directly without needing sudo.
Let's test that Docker is working properly by running a simple command:
docker info
This command will display system-wide information about Docker, confirming that you can communicate with the Docker daemon successfully.
Run a Basic Web Server Container
In this step, you will run your first container. We will use the official nginx image, which provides a lightweight and high-performance web server.
To run a container, you use the docker run command. We will use a few common flags:
-d: Runs the container in detached mode (in the background).-p 8080:80: Maps port 8080 on the host to port 80 inside the container. This allows you to access the Nginx server vialocalhost:8080.--name webserver: Assigns a memorable name to your container.nginx: The name of the image to use.
Execute the following command to start the Nginx container:
docker run -d -p 8080:80 --name webserver nginx
Docker will first check if the nginx image is available locally. If not, it will automatically download it from Docker Hub and then start the container. You can see the container is running using the docker ps command.
docker ps
The output will show your webserver container, its ID, the image it's based on, and the port mapping.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp webserver
Now, let's test if the web server is working. Use curl to send a request to the server on the mapped port.
curl localhost:8080
You should see the default Nginx welcome page HTML as output, which confirms your container is running and accessible.
<!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. For further configuration, refer to the
<a href="http://nginx.org/">nginx.org</a> documentation.
</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Examine Container Processes and Resource Usage
In this step, you will learn how to inspect the processes running inside a container and monitor its resource consumption. This is a fundamental skill for debugging and understanding how your containerized application behaves.
A key feature of containers is process isolation. From the host's perspective, you can see what's running inside a container without having to exec into it. The docker top command allows you to view the main processes of a container.
Run the following command to see the processes inside your webserver container:
docker top webserver
The output shows the Nginx master process running as root and its worker processes running as systemd+ (a system user for improved security). Notice that there are multiple worker processes, which is typical for Nginx to handle concurrent requests efficiently.
UID PID PPID C STIME TTY TIME CMD
root 4098 4078 0 14:34 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 4161 4098 0 14:34 ? 00:00:00 nginx: worker process
systemd+ 4162 4098 0 14:34 ? 00:00:00 nginx: worker process
Next, let's look at the container's resource usage. The docker stats command provides a live stream of a container's CPU, memory, network, and disk I/O. To get a static snapshot for this lab, we'll use the --no-stream flag.
docker stats --no-stream webserver
This command will display a table with the current resource metrics for the webserver container.
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
bda2386621a1 webserver 0.00% 3.125MiB / 3.505GiB 0.09% 6.31kB / 1.27kB 0B / 12.3kB 3
From this output, you can see that the container is using very little CPU (0.00%), about 3.1 MiB of memory out of the available 3.5 GiB system memory (0.09%), and has 3 running processes (the Nginx master and 2 worker processes). This information is vital for identifying performance bottlenecks or potential resource leaks in your applications.
Inspect Container Security Properties such as Resource Limits
In this step, you will explore one of the most basic but critical container security features: resource limits. By default, a container can use as much of the host's CPU and memory as it wants. Setting limits prevents a single container from consuming all available resources and impacting other containers or the host itself.
First, let's inspect the configuration of the webserver container we created earlier. The docker inspect command provides a detailed JSON output with all the container's settings.
docker inspect webserver
The output is very long. You can use the --format flag to extract specific fields. Let's check if any memory limit is set.
docker inspect --format='{{.HostConfig.Memory}}' webserver
The output will be 0, which means there is no memory limit.
0
Now, let's create a new container with a memory limit. First, you need to stop and remove the existing container, as we will reuse the port mapping.
docker stop webserver
docker rm webserver
Next, run a new Nginx container, but this time add the --memory="100m" flag to limit its memory usage to 100 megabytes. We'll also give it a new name.
docker run -d -p 8080:80 --name webserver-limited --memory="100m" nginx
Now, inspect the memory limit of this new container.
docker inspect --format='{{.HostConfig.Memory}}' webserver-limited
This time, the output will be the memory limit in bytes (100 × 1024 × 1024).
104857600
You have successfully applied a resource constraint to a container, which is a foundational step in container security and resource management.
Summary
In this lab, you gained hands-on experience with the fundamental aspects of Docker and container security.
You successfully:
- Verified Docker installation and configured proper access permissions in the LabEx environment.
- Ran a basic Nginx web server as a Docker container.
- Mapped ports to access the containerized application from the host.
- Inspected the processes running inside a container using
docker top. - Monitored live resource usage with
docker stats. - Learned how to set resource limits, such as memory, on a container to improve system stability and security.
These skills are the building blocks for managing and securing more complex, multi-container applications in a production environment.



