A Deeper Dive
In the hello-world example we were told to play around with something more ambitious. So let's do that...
Ubuntu in a Container
docker run -it ubuntu bash
You should now see a new prompt that looks something like this:
root@f4b5c7e4b6b4:/#
This prompt indicates that you are now inside a Docker container running a Ubuntu image. The root@f4b5c7e4b6b4 part is the hostname of the container (yours may be different), and the /# part is the command prompt.
Here is an overview of the commands we used:
docker run # Base command to create and start a new container
-i # Interactive - keep STDIN open (allows you to type into container)
-t # Allocate a pseudo-Terminal (gives you the shell prompt)
ubuntu # The image to use (in this case, official Ubuntu image)
bash # The command to run inside container (start a bash shell)
We can combine tags to make the command shorter: -it is the same as -i -t. Without -it:
-ionly: You can send input but display will be weird-tonly: You get nice formatting but can't type input- neither: Container runs the command and exits unless it has a foreground process
A "bash shell" is the command line interface (CLI). It so happens that if we run:
docker run -it ubuntu
docker run -it ubuntu sh
to get a simple shell instead of bash. You can also do
docker run -it ubuntu zsh
When we are inside the container, if we run:
cat /etc/os-release
You should see the following output:
PRETTY_NAME="Ubuntu 24.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.1 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
confirming that you are indeed running a Ubuntu container. This container does not have any additional software installed, so you have a clean Ubuntu environment to work with. To exit the container, you can type exit and press Enter.
What can we see?
Currently, in VS Code, we have a single terminal open. If we run
ps
PID TTY TIME CMD
1030 pts/0 00:00:00 bash
34776 pts/0 00:00:00 ps
To see all processes, we can either run htop for an interactive view, or run
ps aux
The number in the left column PID is the Process ID, and everything that is running has a unique ID. To demonstrate, check out the script continuous.py. This script simply writes the date and iteration number to a log file. It will keep running until we terminate it.
To run it:
python continuous.py &
The & makes sure we are spat back out into the terminal. Now run
ps
PID TTY TIME CMD
1035 pts/0 00:00:00 bash
1815 pts/0 00:00:00 python
2065 pts/0 00:00:00 ps
ps aux we can also find our process:
codespa+ 1815 0.0 0.1 17172 9984 pts/0 S 15:47 0:00 python continuous.py
ps, but we can see it when we run ps aux.
OK, now let's go back into our ubuntu container:
docker run -it ubuntu
ps command.
root@b752bb229154:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
9 pts/0 00:00:00 ps
Well OK, fine, but we're not in the same terminal, so of course we wouldn't see it. But now try running ps aux...
root@b752bb229154:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4588 3840 pts/0 Ss 15:49 0:00 /bin/bash
root 10 0.0 0.0 7888 3968 pts/0 R+ 15:52 0:00 ps aux
You find that you have access to no information about any processes running outside of your container. If you install and run htop you will find the same level of visibility.
Notice that if you run lscpu you can still see the system level resources, but it is possible to limit this aswell.
Further reading
If you want a real deep dive into namespaces and cgroups, I strongly recommend you check out the brilliant video from Liz Rice, Containers From Scratch. There are three versions of this lecture, but they are all good.