Docker makes containers feel like separate, lightweight virtual machines. They have their own hostnames, processes, and networking—but are they actually isolated? Many administrators assume they are without ever verifying the boundaries. If you’ve ever wondered what truly separates your application from the host, this guide is for you. We’ll use simple Docker commands to verify container isolation firsthand and uncover exactly what remains shared with the host.
Think of container isolation as a way to trick a process into thinking it has a server all to itself. If you’ve worked with virtual machines, you’re used to a hypervisor handling the heavy lifting—effectively carving out a slice of hardware. Containers are different.
They don’t virtualize hardware; they use Linux namespaces to carve up the kernel’s view of the system. Basically, the kernel assigns labels to resources like network stacks or process lists. If a process in a container asks "What can I see?", the kernel only shows it the resources tagged with its specific namespace ID. It’s an illusion, sure, but it’s an incredibly effective one for keeping your applications from interfering with the host or each other.
When people ask what container security is, they are usually looking for a way to keep their apps safe from start to finish. It’s not just one thing; it’s the whole process of managing your images, the runtime, and the host machine. The reason isolation is the biggest part of this is simple: if you don’t have a clear boundary, one bad script or one compromised app can easily reach into your host system. By knowing exactly what a container can (and can't) see, you can lock down your configuration and make sure that if one container fails, it doesn't take the whole server down with it.
To observe these boundaries, we’ll use the docker run command—the most common way to spin up a new container. We are using the official Ubuntu image because it provides a familiar Linux userspace that is ideal for testing Docker commands.
Run this command on your host:
docker run -it ubuntu bash
Once the command finishes, your terminal prompt will change. You are now working inside the container’s isolated environment.
Open a second terminal window on your host and run:
docker ps
The output lists every active container, including its unique Container ID, image, uptime, and assigned name. Verify that your Ubuntu container appears in this list before moving to the next step.
Let's see if the container truly has its own identity.
hostname
hostname
You will see two different values. This is because the container uses the UTS (UNIX Timesharing System) namespace, which allows it to maintain a unique hostname independent of your machine.
Namespaces are at work here, too, preventing the container from seeing host-level processes.
ps aux
ps aux
Inside the container, you will only see a small, clean list of processes, with bash as PID 1 because it is the first process started within that PID namespace. Meanwhile, your host terminal shows every system process. This PID namespace separation is vital for container isolation.
Administrators often need to debug a container that is already running in the background. For this, we use docker exec.
|
Feature |
docker run |
docker exec |
|
Purpose |
Creates a new container |
Uses an existing container |
|
State |
Starts a fresh environment |
Hooks into a running process |
|
Typical Use |
Initial testing/deployment |
Debugging or maintenance |
Run this on your host to jump back into your running container:
docker exec -it bash
Run ip addr in both the container and the host. The container uses a separate network namespace, giving it its own virtual interfaces and a private IP address (usually in the 172.17.x.x range). This proves that the container has a private network stack, keeping its traffic separate from your host’s primary interfaces.
Create a file inside the container to test storage boundaries:
touch /testfile.txt
If you check your host’s current directory, you won't see this file. Although Docker stores the container's writable layer on the host, the file does not appear in your host's current working directory because the container has its own mount namespace.
Finally, run this on both the host and the container:
uname -r
You will notice the kernel version is identical. This is the most critical lesson for container runtime security. Because containers share the host kernel, they do not provide the same "hard" security boundary as a virtual machine. According to official Linux kernel documentation, Linux namespaces provide logical partitioning, but they do not replace the need for secure kernel management.
--privileged grants a container access to host devices, effectively bypassing many security namespaces.--net=host shares the host’s network namespace, removing all network isolation./etc or the Docker socket into a container can give the container full control over the host.|
Namespace |
What You Verified |
|
UTS |
Different hostname |
|
PID |
Different process list |
|
Network |
Different interfaces and IP |
|
Mount |
Separate filesystem view |
Before you finish, ensure you’ve confirmed the following:
To maintain a hardened environment, follow these container security best practices based on the CIS Docker Benchmark:
You’ve now verified that containers provide effective logical isolation, but they are not the "air-gapped" environments that virtual machines are. Understanding these boundaries allows you to make informed container security decisions.
Now that you’ve verified isolation firsthand, the next step is learning how Linux capabilities, cgroups, and seccomp further strengthen your environment. Exploring those features will help you move from basic container usage to building truly resilient and secure systems.
Want more Linux security news, vulnerability analysis, and software supply chain updates? Subscribe to the LinuxSecurity Newsletter and get the latest threats, advisories, and expert insights delivered directly to your inbox.