DOCKER:
What is Docker?
Docker is a tool that helps you:
● Package your applications with all dependencies (like libraries, frameworks, etc.) into a
container.
● Run your applications consistently across different environments (your PC, cloud, servers).
● Make deployment faster and more reliable.
Why Use Docker?
Imagine you're building an app, and it works perfectly on your PC. But when you run it on another PC or
server, it fails because of different software versions or missing libraries.
Docker solves this problem by packaging your app with everything it needs into a container, ensuring it
works anywhere.
Types of Docker Components We'll Use:
1. Docker Engine – Core part of Docker that runs containers.
2. Docker CLI (Command-Line Interface) – Used to manage containers and images.
3. Docker Compose – Helps manage multi-container applications.
Step-by-Step Docker Installation
Here’s exactly what to do in your Ubuntu environment.
I'll explain each command so you know why it's needed.
Step 1: Update Your Ubuntu
This ensures your package list is up to date.
bash
sudo apt update
sudo apt upgrade -y
Explanation:
● sudo apt update – Refreshes the list of available packages.
● sudo apt upgrade -y – Updates all installed packages to the latest versions.
Step 2: Install Required Dependencies
Run this to install tools Docker needs.
bash
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
Explanation:
● ca-certificates – Ensures your system trusts secure websites.
● curl – A tool to download files from the internet.
● gnupg – Adds support for verifying digital signatures.
● lsb-release – Helps your system identify your Linux distribution.
Step 3: Add Docker’s GPG Key and Repository
The GPG key ensures you download the official Docker packages securely.
bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o
/etc/apt/keyrings/docker.gpg
Explanation:
● mkdir -p /etc/apt/keyrings – Creates a directory to store the Docker key.
● curl -fsSL – Downloads Docker’s GPG key.
● gpg --dearmor – Converts the key into a readable format.
Next, add the Docker repository:
bash
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg]
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Explanation:
This command tells your system where to download Docker from.
Step 4: Install Docker Engine
Now, install Docker.
bash
sudo apt update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
docker-compose-plugin
Explanation:
● docker-ce – Docker Engine Community Edition.
● docker-ce-cli – Command-line tool to manage Docker.
● containerd.io – Core component to manage containers.
● docker-buildx-plugin – Allows building images efficiently.
● docker-compose-plugin – Helps manage multi-container apps.
Step 5: Start Docker Service
Start the Docker service to make it ready to use.
bash
sudo service docker start
What is a Docker Image?
A Docker image is like a blueprint for your app. It contains:
● Your app’s code
● System libraries (e.g., Python, Java)
● Configuration files
● Operating system files
An image is used to create a container, which is a running instance of your app.
Think of an image as a template and a container as a running app.
Example to Understand Docker Image and Container
Imagine you have a game (app). To play it:
1. Docker Image = Game DVD (the blueprint)
2. Docker Container = Game running on your PC (a running instance)
You can make multiple containers from one image, like playing the same game on different PCs.
Why Use Docker Images?
Without Docker:
● You must manually install everything (Python, libraries, dependencies) on every system where
your app runs.
With Docker:
● You package everything into one image and run it anywhere without installing extra stuff.
How a Docker Image Works
1. You create a Dockerfile – A text file that tells Docker how to build the image
2. Docker builds the image from the Dockerfile.
3. You run a container from the image to use your app.
Simple Analogy:
Term Example
Dockerfile Recipe (instructions)
Docker Image Cake (template)
Docker Container Slice of cake (running app)
Objective: Build a Simple Docker Image for a Blockchain Concept
We'll use a very basic blockchain concept in Python, package it in a Docker image, and run it inside a
Docker container. This will help participants learn:
1. What a Docker image is
2. How to build and run a Docker container
3. How a simple blockchain works (without complex theory)
Step 1: Create a Simple Blockchain App (No Prior Knowledge Needed)
1. Create a project folder:
bash
mkdir simple-blockchain
cd simple-blockchain
2. Create a Python file (blockchain.py):
bash
nano blockchain.py
Add this simple blockchain code:
Python
import hashlib
import time
class Block:
def __init__(self, index, previous_hash, timestamp, data):
self.index = index
self.previous_hash = previous_hash
self.timestamp = timestamp
self.data = data
self.hash = self.calculate_hash()
def calculate_hash(self):
return
hashlib.sha256(f"{self.index}{self.previous_hash}{self.timestamp}{self.data}".encode()).hexdigest()
def create_genesis_block():
return Block(0, "0", time.time(), "Genesis Block")
def create_new_block(previous_block, data):
return Block(previous_block.index + 1, previous_block.hash, time.time(), data)
# Create the blockchain
blockchain = [create_genesis_block()]
print("Genesis Block created!")
# Add a new block
new_block = create_new_block(blockchain[-1], "This is the second block")
blockchain.append(new_block)
print(f"New Block Added: {new_block.index} with Hash: {new_block.hash}")
Step 2: Create a Dockerfile
The Dockerfile tells Docker how to package your app.
1. Create a Dockerfile:
bash
nano Dockerfile
2. Add the following content:
Dockerfile
# Use the official Python image
FROM python:3.9
# Set the working directory
WORKDIR /app
# Copy the current directory contents into the container
COPY . .
# Run the Python app
CMD ["python", "blockchain.py"]
Step 3: Build the Docker Image
Run this command to build your Docker image:
bash
docker build -t simple-blockchain . →include space and dot at end of command
If you face the error , Fix: Grant Docker Permissions:and if you get error like unab
1. Add your user to the Docker group:
bash
sudo usermod -aG docker $USER
This command adds your user to the docker group, which has the necessary permissions to interact with
Docker.
2. Restart your session:
a. Log out and log back in, or you can use the following to refresh your group membership:
bash
newgrp docker
3. Test Docker Access:
After doing this, try running the Docker command again:
bash
docker build -t simple-blockchain .
If you still encounter issues:
1. Check Docker Service:
Ensure that the Docker service is running:
bash
sudo systemctl start docker
2. Verify Permissions:
Check the permissions of /var/run/docker.sock:
bash
ls -l /var/run/docker.sock
The permissions should show the docker group having read/write access. If not, you may need to adjust
the socket's permissions.
sudo chmod 777 /var/run/docker.sock
Using Buildx Specifically If you're using docker buildx build, ensure you specify the context:
bash
docker buildx build -t simple-blockchain .→include space and dot at end of command
Step 4: Run the Docker Container
Run your Docker container:
bash
docker run simple-blockchain
You’ll see output like this:
mathematical
Genesis Block created!
New Block Added: 1 with Hash: a3f8e24f3f6a...
✅ To create a private Docker registry and push your blockchain image into it, follow these steps:
Step 1: Set Up Your Private Docker Registry
Step 1: Pull the registry Image
Manually pull the Docker Registry image from Docker Hub:
bash
docker pull registry:2
Step 2: Start a Docker Registry Container
You can run a local Docker registry by using the official registry image:
bash
docker run -d -p 5000:5000 --name registry registry:2
if you see the, "Unable to find image 'registry:2' locally", means that Docker can't find the registry:2
image on your local machine, and it's trying to pull it from Docker Hub but is unable to.
Follow below steps:
Step 1: Pull the registry Image
Manually pull the Docker Registry image from Docker Hub:
bash
docker pull registry:2
This will download the latest version (2.x) of the Docker Registry image.
You should see the registry container listed.
If you face the error "Conflict. The container name '/registry' is already in use", which means that a
container with the name registry already exists.
To resolve this, you have two options:
Option 1: Remove the Existing Container
If you no longer need the existing container, you can remove it and then run the new one:
1. Stop the existing container:
bash
docker stop registry
2. Remove the existing container:
bash
docker rm registry
3. Now, start a new registry container:
bash
docker run -d -p 5000:5000 --name registry registry:2
Option 2: Use a Different Name for the New Container
If you want to keep the existing container and just start a new one with a different name, use a different
container name like my-registry:
bash
docker run -d -p 5000:5000 --name my-registry registry:2
This will start the new registry container with the name my-registry instead of registry.
Step 2: Run the Registry
Once the image is pulled, you can run the Docker registry container:
bash
This starts a Docker registry that listens on port 5000 of your local machine.
2. Verify the Registry is Running
Check that the registry is running:
bash
docker ps
You should see a container named registry running.
Step 2: Tag the Image for Your Private Registry
Before you push your image to the private registry, you need to tag it with your registry's address.
1. Tag the Image
Assuming your image name is simple-blockchain, tag it like this:
bash
docker tag simple-blockchain localhost:5000/simple-blockchain
Here, localhost:5000 is your private registry (running on port 5000), and simple-blockchain is your image
name.
Step 3: Push the Image to Your Private Registry
Push the tagged image to the private registry:
bash
docker push localhost:5000/simple-blockchain
This will upload the image to your local registry running at localhost:5000.
Step 4: Verify the Image is Pushed
You can verify that the image is in your registry by checking the registry API:
bash
curl http://localhost:5000/v2/simple-blockchain/tags/list
This will show the tags associated with the simple-blockchain image.
Step 5: Pull the Image from Your Private Registry
On any machine that has access to your private registry, you can pull the image like this:
bash
docker pull localhost:5000/simple-blockchain
This will start the registry on port 5000 on your local machine.
Step 3: Verify the Registry
Make sure the registry container is running:
bash
docker ps
You should see the registry container listed.
Command:
docker run -i -t ubuntu /bin/bash
This command is used to run an interactive Ubuntu container with a Bash shell.
Explanation of Flags:
● docker run creates and starts a new container.
● -i keeps the standard input (STDIN) open for interactive mode.
● -t allocates a pseudo-TTY (terminal) for the container.
● ubuntu specifies the Ubuntu image (Docker pulls it if not available locally).
● /bin/bash runs the Bash shell inside the container.
Steps to be followed:
1. Pull the Ubuntu image if not available using the command docker pull ubuntu.
2. Run the container with an interactive shell using docker run -i -t ubuntu /bin/bash.
3. After running the command, a shell prompt appears (root@container-id:/#), allowing Linux
commands to be executed inside the container.
4. To exit the container, type exit or press Ctrl + D.
Docker Basic Commands
1. Display Docker Version and Information
Command:
docker --version
Description: This command checks the installed Docker version. It confirms whether Docker is installed
and shows the currently installed version.
bash
docker info or docker version
Description: These commands provide system-wide information about Docker, including details such as
the number of running and stopped containers, total images, storage details, and system configurations.
2. List Docker Images
bash
docker image ls or docker images
Description: Displays a list of all Docker images available on the system. The output includes the
repository name, tag, image ID, creation date, and size.
3. Execute a Docker Image
bash
docker run <docker-image-name>
Description: This command creates and starts a container from the specified Docker image. If the image
is not available locally, Docker automatically pulls it from the default registry (Docker Hub) before
running the container.
4. List Running Docker Containers
To view only active containers:
bash
docker container ls
# OR
docker ps
5. List All Containers (Including Exited Containers)
To display both running and stopped containers:
bash
docker container ls --all
6. List Available Docker CLI Commands
To get a list of Docker commands:
bash
docker
For container-specific commands:
bash
docker container --help
7. Stop a Running Container
To stop a container, use its Container ID or Name:
bash
docker container stop <container_id>
# OR
docker stop <container_id>
8. Restarting a Docker Container
Docker provides a simple command to restart a running or stopped container.
i. Restart a Running or Stopped Container
To restart a container, use:
bash
docker restart <container_id>
or
bash
docker restart <container_name>
ii. Example
If you have a container named peer0.org2.example.com, restart it using:
bash
docker restart peer0.org2.example.com
or by its container ID:
bash
docker restart 787335fb6d9e
9. View Logs of a Docker Container
To check the logs of a running or stopped container:
bash
docker logs <container_id>
Running an Nginx Container and Port Mapping
1. Running an Nginx Container
To start an Nginx container in detached mode, use the following command:
bash
docker run -d --name web1 nginx
● -d → Runs the container in the background.
● --name web1 → Assigns the container a custom name web1.
● nginx → Uses the official Nginx image from Docker Hub.
2. Checking if Nginx is Running on the Host Machine
Even though the Nginx container is running, it does not expose its ports to the host by default. To check
if nginx is running inside the container:
bash
ps aux | grep nginx
This lists processes related to nginx.
3. Testing Nginx Without Port Mapping
Try accessing the Nginx default page:
bash
curl localhost:80
This will fail because port 80 is not exposed to the host.
4. Running an Nginx Container with Port Mapping
To make Nginx accessible from the host machine, use port mapping:
bash
docker run -d --name web2 -p 8080:80 nginx
● -p 8080:80 → Maps port 80 of the container to port 8080 on the host.
● Now, Nginx will be accessible at localhost:8080.
5. Checking Connectivity
Verify if Nginx is reachable after running web2:
bash
curl localhost:8080
This should return the Nginx Welcome Page HTML.
Creating a Docker Image
This section outlines the standard method for creating a Docker image, following best practices.
1. Create a Working Directory
First, create a directory to store the Dockerfile:
bash
mkdir mydockerimage
cd mydockerimage
2. Create a Dockerfile
A Dockerfile defines the structure of the image. Create it using:
bash
nano Dockerfile
Insert the following content:
dockerfile
# Use an official Ubuntu base image
FROM ubuntu:latest
# Set image metadata
LABEL maintainer="[email protected]"
# Update system packages and install curl
RUN apt-get update && apt-get install -y curl
# Set a default command for the container
CMD ["echo", "Hello, this is a standardized Docker image."]
Save and exit.
3. Build the Docker Image
Execute the following command:
bash
docker build -t myimage .
● -t myimage → Assigns the image name as myimage.
● . → Uses the current directory as the build context.
4. Verify the Image
To confirm the image was created successfully:
bash
docker images
5. Run a Container from the Image
Execute a container based on the image:
bash
docker run myimage
To run in detached mode:
bash
docker run -d --name mycontainer myimage
To check running containers:
bash
docker ps
6. Stopping and Removing Containers
To stop a running container:
bash
docker stop mycontainer
To remove a stopped container:
bash
docker rm mycontainer
7. Removing the Docker Image (Optional)
To delete the image if no longer needed:
bash
docker rmi myimage
Ensure no containers are using it:
bash
docker ps -a
Summary of commands:
Step Command Description
1 mkdir mydockerimage && cd mydockerimage Creates a working directory.
2 nano Dockerfile Creates and edits the Dockerfile.
3 docker build -t myimage . Builds a new Docker image.
4 docker images Lists available images.
5 docker run myimage Runs a container from the image.
6 docker ps -a Lists all containers (running and
stopped).
7 docker stop mycontainer Stops a running container.
8 docker rm mycontainer Removes a stopped container.
9 docker rmi myimage Deletes the Docker image.
Running a Container with Automatic Removal and Monitoring Docker Events
1. Running a Container with the --rm Flag
The --rm flag ensures that a container is automatically removed after it stops.
Command:
bash
docker run -d --rm --name webhello myimage
Explanation:
● -d → Runs the container in detached mode (background).
● --rm → Automatically removes the container after it stops.
● --name webhello → Assigns a name to the container.
● myimage → Uses the custom image you created (myimage).
2. Checking Container Persistence With and Without --rm
i. Run a container without --rm:
bash
docker run -d --name webhello myimage
ii. List all containers (including stopped ones):
bash
docker ps -a
The container remains in the list even after stopping it.
iii. Run the same container with --rm:
Bash
Fix: Remove the Existing Container
Stop and Remove the Container Manually
bash
docker stop webhello
docker rm webhello
Then, run the command again:
bash
docker run -d --rm --name webhello myimage
iv. Check again with:
bash
docker ps -a
Since --rm is used, the container disappears after stopping because it gets automatically removed.
3. Monitoring Docker System Events
Docker provides a command to track system-level events in real time.
Command:
bash
docker system events
This continuously displays events such as:
● Container start/stop
● Image pulls/removals
● Network changes
● Volume actions
The docker system events command runs in real time and only shows new events as they happen. If
nothing is happening in Docker, the command will appear unresponsive.
Let's test it:
Open two terminal windows:
1. In Terminal 1, start monitoring Docker events:
bash
docker system events
2. In Terminal 2, trigger some Docker actions, such as:
bash
docker run -d --rm --name testcontainer nginx
docker stop testcontainer
docker rmi myimage
After running these commands in Terminal 2, you'll start seeing real-time events in Terminal 1.
If docker system events still shows nothing:
Make sure Docker is running:
bash
systemctl status docker
● Try restarting the Docker daemon:
bash
sudo systemctl restart docker
Terminal 1: system events
Terminal 2: Operation of commands
Namespaces in Docker
1. Introduction to Namespaces
Namespaces are a fundamental Linux kernel feature used by Docker to isolate processes. They ensure that
containers operate independently by providing a unique execution environment.
2. Types of Namespaces in Docker
Docker uses multiple namespaces to isolate containers from the host system:
Namespace Description
PID (Process ID) Isolates process IDs so that each container has its own process
space.
Network Provides each container with its own network stack (IP, routes,
etc.).
Mount Manages file system mount points, ensuring container-specific
mounts.
UTS (Unix Timesharing Allows containers to have independent hostnames and domain
System) names.
IPC (Inter-Process Enables process communication within the same container but
Communication) isolates it from other containers.
User Assigns different user IDs and group IDs inside the container,
enhancing security.
3. How Docker Uses Namespaces
● When a container starts, Docker automatically assigns it a new set of namespaces.
● This ensures isolation between the host and other containers.
● Docker allows limited sharing of namespaces for specific use cases (e.g., --pid=host for sharing
the host’s PID namespace).
4. Checking Namespaces in Docker
You can inspect namespaces using Linux commands:
List namespaces in the host system:
sh
lsns
● Check a container’s PID namespace:
sh
docker inspect --format '{{ .State.Pid }}' <container_id>
● View network namespaces:
sh
ls /var/run/netns/
5. Practical Example
You can test namespace isolation by running two containers and observing their process and network
isolation.
sh
docker run -d --name container1 alpine sleep 1000
docker run -d --name container2 alpine sleep 1000
Now, check if processes are isolated:
sh
docker exec container1 ps aux
docker exec container2 ps aux
Each container only sees its own processes.
6. Namespace Sharing in Docker
In some cases, containers may share namespaces:
● --network=host: Shares the host's network stack.
● --pid=host: Shares the host’s process space.
● --ipc=container:<id>: Shares IPC between two containers.
7.Check Namespace IDs of Each Container
Find the PID of a container and inspect its namespaces:
sh
CONTAINER_PID=$(docker inspect --format '{{ .State.Pid }}' container1)
ls -l /proc/$CONTAINER_PID/ns
These are Linux namespaces used by Docker to isolate containers. Each namespace provides a separate
execution environment for specific system resources.
1.PID Namespace (Process Isolation)
● What it does:
○ Isolates process IDs inside the container.
○ A container sees only its own processes, not the host’s.
● Example:
○ Run ps aux inside a container → You’ll see only container processes.
○ On the host, use docker inspect --format '{{ .State.Pid }}' <container_id> to see the
container’s process mapped to the host.
2.NET Namespace (Network Isolation)
● What it does:
○ Provides each container with a separate network stack.
○ Containers get their own IP address, routes, and interfaces.
● Example:
○ docker exec <container> ip a shows container’s isolated network interfaces.
○ Containers can have separate or shared networks (--network=host removes isolation).
❖ Run an interactive shell inside the container:
sh
docker exec -it be46a6735c69 bash
❖ Run a specific command inside the container:
sh
docker exec be46a6735c69 ls /
i. Check if You're Inside the Container
Run:
sh
hostname
This should return a different hostname than your host machine, confirming you’re inside the container.
ii. List Filesystem
Run:
sh
ls -l /
This lists the container’s root directory, separate from your host.
iii. Check Running Processes
Run:
sh
ps aux
You will see only the processes running inside the container, not the host’s processes.
iv. Install Packages (If Needed)
For Ubuntu containers, you may need to update first:
sh
apt update && apt install -y nano curl
This installs nano and curl inside the container.
v. Exit the Container
Simply type:
sh
exit
3.IPC Namespace (Interprocess Communication Isolation)
● What it does:
○ Isolates shared memory (SHM), message queues, and semaphores.
○ Prevents one container from accessing IPC resources of another.
● Example:
○ Inside a container, run ipcs → Shows only container’s IPC resources.
Check IPC resources inside a container:
sh
docker run -it --name ipc_test --ipc=private ubuntu bash
apt update && apt install -y iputils-ping
ipcs
Expected output: Only IPC resources within the container are listed.
Check IPC namespace of the container from the host:
sh
docker inspect --format '{{ .State.Pid }}' ipc_test
sudo ls -l /proc/<PID>/ns/ipc
Summary of Commands
Namespace Command Inside Command on Host
Container
IPC ipcs ls -l /proc/$(docker inspect --format '{{ .State.Pid }}'
ipc_test)/ns/ipc
MNT `mount grep root`
UTS hostname hostname
USER id id
4.MNT Namespace (Filesystem Isolation)
● What it does:
○ Gives each container a separate filesystem view.
○ Changes in one container’s mount points don’t affect others.
● Example:
○ mount | grep root inside a container → Shows isolated filesystem.
Each Docker container has its own filesystem using the MNT (mount) namespace, meaning
changes inside one container do not affect the host or other containers.
i. Check Mount Points Inside a Container
Run a container and check its mount points:
sh
docker run -it --name mnt_test ubuntu bash
mount | grep root
This shows the root filesystem mount inside the container.
Compare with the host:
Run this outside the container (on the host):
sh
mount | grep root
➔ The output should be different from the container's output.
ii. Check Container’s Mount Namespace from Host
Find the PID of the running container:
sh
docker inspect --format '{{ .State.Pid }}' mnt_test
➔ Suppose it returns 26513, then check its mount namespace:
sh
sudo ls -l /proc/26513/ns/mnt
➔ Expected output: A symlink showing the mount namespace.
iii. Verify Mount Namespace Isolation
Find all mount namespaces on the system:
sh
lsns | grep mnt
➔ This lists all processes with separate mount namespaces.
Compare with the host’s mount namespace:
sh
readlink /proc/self/ns/mnt
readlink /proc/26513/ns/mnt
Summary of Commands
Command Where to Purpose
Run
`mount grep root` Inside the container
`mount grep root` On the host
docker inspect --format '{{ .State.Pid }}' mnt_test On the host Get container's process ID
(PID)
ls -l /proc/<PID>/ns/mnt On the host Check container's mount
namespace
`lsns grep mnt` On the host
readlink /proc/self/ns/mnt On the host Get the host’s mount namespace
readlink /proc/<PID>/ns/mnt On the host Get the container’s mount
namespace
5.UTS Namespace (Hostname & Domain Isolation)
● What it does:
○ Allows containers to have a different hostname from the host.
● Example:
○ Run hostname inside a container → Shows a different name than hostname on the host.
i. Check Hostname Inside a Container
Run a container with a custom hostname:
sh
docker run -it --name uts_test --hostname=mycontainer ubuntu bash
Inside the container, check the hostname:
sh
hostname
➔ Expected output: mycontainer (not the host’s hostname).
ii. Compare with the Host
Run this outside the container (on the host):
sh
hostname
➔ Expected output: Host’s actual hostname, which should be different from the container.
iii. Check UTS Namespace from Host
Find the PID of the running container:
sh
docker inspect --format '{{ .State.Pid }}' uts_test
➔ Suppose it returns 22410, then check the UTS namespace symlink:
sh
sudo ls -l /proc/26769/ns/uts
➔ This confirms the container has its own UTS namespace.
Compare with the host’s UTS namespace:
sh
readlink /proc/self/ns/uts
readlink /proc/26769/ns/uts
Summary of Commands
Command Where to Run Purpose
hostname Inside the Shows container’s hostname
container
hostname On the host Shows the host’s hostname
docker inspect --format '{{ .State.Pid }}' uts_test On the host Get container’s PID
ls -l /proc/<PID>/ns/uts On the host Check container’s UTS
namespace
readlink /proc/self/ns/uts On the host Get host’s UTS namespace
readlink /proc/<PID>/ns/uts On the host Get container’s UTS
namespace
6.USER Namespace (User ID Isolation)
● What it does:
○ Allows containers to have different user/group IDs than the host.
○ Improves security by mapping container root user to a non-root user on the host.
● Example:
○ Inside a container, id shows different UID/GID values than on the host.
The USER namespace allows a container to have different user and group IDs from the host. This
improves security by preventing container root access from affecting the host system.
i. Check User ID Inside a Container
Run a new container and check UID/GID:
sh
docker run -it --rm --name user_test ubuntu bash
Inside the container, run:
sh
id
➔ Expected output: Shows uid=0(root) gid=0(root), meaning the container has root privileges
inside itself but not on the host.
ii. Compare with the Host
Run the same command on the host:
sh
id
➔ Expected output: Your actual host user ID, which is different from the container’s root.
Summary of Commands
Command Where to Run Purpose
id Inside the Shows container’s UID/GID
container
id On the host Shows host’s UID/GID
docker run --rm -it --user 1000:1000 ubuntu bash On the host Runs container as a non-root
user
docker inspect --format '{{ .State.Pid }}' user_test On the host Get container’s PID
ls -l /proc/<PID>/ns/user On the host Check container’s USER
namespace
readlink /proc/self/ns/user On the host Get host’s user namespace
readlink /proc/<PID>/ns/user On the host Get container’s user
namespace
iii. Check User Namespace Mapping
To run a user-mapped container, create one with a mapped UID/GID:
sh
docker run --rm -it --user 1000:1000 ubuntu bash
Inside the container, check:
sh
id
➔ Expected output: uid=1000 gid=1000, meaning it runs as a non-root user inside the container.
iv. Check User Namespace on the Host
Find the container’s PID:
sh
docker inspect --format '{{ .State.Pid }}' user_test
➔ Suppose it returns 27261, then check its USER namespace:
sh
sudo ls -l /proc/27261/ns/user
Compare with the host’s user namespace:
sh
readlink /proc/self/ns/user
readlink /proc/27261/ns/user
➔ If different, the container has its own user namespace.
Summary of Commands
Command Where to Run Purpose
id Inside the Shows container’s UID/GID
container
id On the host Shows host’s UID/GID
docker run --rm -it --user 1000:1000 ubuntu bash On the host Runs container as a non-root
user
docker inspect --format '{{ .State.Pid }}' user_test On the host Get container’s PID
ls -l /proc/<PID>/ns/user On the host Check container’s USER
namespace
readlink /proc/self/ns/user On the host Get host’s user namespace
readlink /proc/<PID>/ns/user On the host Get container’s user
namespace
Namespace Purpose
PID Isolates process IDs
NET Provides a separate network stack
IPC Isolates shared memory & message queues
MNT Isolates the filesystem
UTS Separates hostnames & domain names
USER Separates user IDs & permissions
Control Groups (cgroups)
control groups cgroups limit and allocate resources cpu memory io etc for docker containers
i. Check cgroups on the host
list cgroups available on your system
sh
sudo ls /sys/fs/cgroup
expected output → displays different resource controllers cpu memory blkio etc
ii. Run a container with cpu limit
limit the container to 50 percent of a single cpu core
sh
docker run -it --rm --cpus="0.5" ubuntu bash
inside the container run
sh
cat /sys/fs/cgroup/cpu.max
expected output → 50000 half a cpu core
iii. Run a container with memory limit
limit the container to 256mb ram
sh
docker run -it --rm --memory="256m" ubuntu bash
inside the container check memory limits
sh
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
expected output → 268435456 256mb in bytes
v. Verify cgroup configuration from the host
find the container pid
sh
docker inspect --format '{{ .State.Pid }}' container_id
suppose it returns 27261 check cgroup settings
sh
cat /proc/27261/cgroup
expected output → shows container’s cgroup assignments
vi. Run a container with cpu and memory limits together
limit to one cpu and 512mb ram
sh
docker run -it --rm --cpus="1" --memory="512m" ubuntu bash
verify inside the container
sh
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
Summary of commands
command where to run purpose
ls /sys/fs/cgroup on the host list available cgroups
docker run -it --rm --cpus="0.5" ubuntu bash on the host run a container with 50
percent cpu
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us inside the show cpu limit
container
docker run -it --rm --memory="256m" ubuntu bash on the host run a container with
256mb ram
cat /sys/fs/cgroup/memory/memory.limit_in_bytes inside the show memory limit
container
docker inspect --format '{{ .State.Pid }}' container_id on the host get container pid
cat /proc/pid/cgroup on the host check cgroup settings
docker run -it --rm --cpus="1" --memory="512m" ubuntu on the host run a container with
bash both limits