Containers¶
Practical 6.4 containers-annex.pdf · PDF
At Tramuntana Apps, Marta finishes a web app on her laptop. It works. She copies it to the server. It does not start. Another version of the language, a missing library, a different configuration file: "but it works on my machine!"
The lesson hidden in that sentence: an app is not only its code. It is the code plus everything around it. Every service on your server so far (SSH, Samba, NFS, CUPS) was installed with apt, straight on the system, all mixed together. On this page you install the next one differently: inside a box that carries everything it needs.
What you will learn
- Explain what a container is and how it differs from a virtual machine
- Tell an image from a container, and say what a registry and a tag are
- Install Podman on
ubu-srvand run a container, interactively and in the background - Publish a port and reach the containerised service from another machine
- List, inspect, stop, start and remove containers and images
- Why a container is not a small virtual machine
The box that changed shipping¶
Until the 1950s, ships were loaded piece by piece: sacks, barrels, crates, each a different shape. On 26 April 1956 the trucking businessman Malcom McLean sent the ship Ideal X from Newark to Houston with 58 identical metal boxes on deck. The crane did not care what was inside. Loading became fast, cheap and predictable. Software copied the idea, and even the name.
A container is a running program closed in a box that carries everything it needs: its files, its libraries, its configuration.
An image is the packed, read-only template a container is started from.
One image, many containers: like one recipe and many cooked dishes.
Container or virtual machine?¶
You built virtual machines in Unit 2. They look similar from far away, but they are built very differently:
flowchart TB
subgraph VMSIDE ["Virtual machines"]
direction TB
V1["<b>VM 1</b><br>app + libraries<br>+ its own kernel and OS"]
V2["<b>VM 2</b><br>app + libraries<br>+ its own kernel and OS"]
HYP["<b>Hypervisor</b><br>pretends to be hardware"]
HOS1["<b>Host OS</b>"]
HW1["<b>Hardware</b>"]
V1 --> HYP
V2 --> HYP
HYP --> HOS1 --> HW1
end
subgraph CTSIDE ["Containers"]
direction TB
C1["<b>Container 1</b><br>app + libraries"]
C2["<b>Container 2</b><br>app + libraries"]
ENG["<b>Container engine</b><br>Podman"]
HOS2["<b>Host OS</b><br>one kernel, shared by all"]
HW2["<b>Hardware</b>"]
C1 --> ENG
C2 --> ENG
ENG --> HOS2 --> HW2
end
| Virtual machine | Container | |
|---|---|---|
| Isolates | A whole computer (virtual hardware) | A group of processes |
| Kernel | Its own, one per VM | The host's, shared by all |
| Size | Gigabytes (ubu-srv: a 20 GB disk) |
Megabytes (the nginx image: 165 MB) |
| Starts in | The time of a boot | About a second |
| Can run another OS family | Yes (Windows on Linux) | No: Linux containers need a Linux kernel |
Careful: a container is not a small virtual machine
A VM pretends to be hardware and boots its own kernel. A container is an ordinary process of the host that has been given its own view of the files, the network and the process list. You will see this with your own eyes in a minute.
Install Podman and run your first container¶
On ubu-srv (ssh srv), as your normal user. Take a snapshot first.
Ubuntu 26.04 LTS answers podman version 5.7.0 (a later 5.7.x after updates is fine). Now the first box:
Podman says Trying to pull quay.io/podman/hello:latest..., downloads the image, starts a container from it, the container prints !... Hello Podman World ...! with a drawing of three seals, and ends. One command, five hidden steps: pull the image, create the container, start it, run the program, exit.
Never type sudo podman
It works, but it is a separate, root-owned set of containers and images. Stay without sudo all week: Podman does not need it.
A Debian inside an Ubuntu¶
-it = interactive, with a terminal. --rm = delete the container when it ends. The prompt changes to something like root@82c447e03466:/#: that number is the container's ID. Inside the box:
cat /etc/os-release # PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
whoami # root
ls /home # empty: the server's users are not here
uname -r # the kernel version
exit
Back on ubu-srv, run cat /etc/os-release (Ubuntu 26.04) and uname -r again.
The files say Debian; the kernel line is the same string inside and outside. That is the whole definition of a container on one screen: its own files, the host's kernel. And whoami says root, but only inside the box: you started it as a normal user, and rootless Podman maps the box's root to your own user outside.
What is left on the server¶
podman ps # running containers: none
podman ps -a # all containers: the hello one, Exited
podman images # images on disk
The hello image weighs 787 kB and debian:13 124 MB. Compare that with your VM's 20 GB disk.
Images, registries and tags¶
An image name has four parts:
- A registry is a server that stores images, like an app store for server software.
docker.iois Docker Hub;quay.iois Red Hat's. - A tag is the version. No tag means
latest, which changes without warning: in a company, write the tag. - Always type the full name. Docker assumes
docker.iowhen the registry is missing; Podman prefers that you say it.
Docker and Podman: a short history¶
- 15 March 2013: at the PyCon conference in California, Solomon Hykes, founder of the small hosting company dotCloud, shows in a lightning talk an internal tool called Docker. The Linux kernel could already isolate processes (the oldest piece,
chroot, is from 1979), but it was hard to use. Docker made it one command. Version 1.0 came on 9 June 2014. - 22 June 2015: Docker, CoreOS and other companies create the Open Container Initiative (OCI) under the Linux Foundation: an open standard for the image format and for how a container is run. Since then an image built with one tool runs on any other.
- 16 January 2019: Red Hat publishes Podman 1.0: the same commands, but with no background service and no need for root.
| Podman (what we use) | Docker | |
|---|---|---|
| Command | podman run ... |
docker run ... (same options) |
| Background service | None: each container is a child of your command | dockerd, a daemon running as root |
| Without root | The default | Possible, needs extra setup |
| Image recipe file | Containerfile (also reads Dockerfile) |
Dockerfile |
| Several containers | podman compose |
docker compose |
| Image names | Write the registry: docker.io/library/nginx |
nginx means docker.io/library/nginx |
| Images | OCI: the same ones | OCI: the same ones |
Everything on this page works with Docker by changing one word. When a job offer says Docker, you can say yes.
A web server in a box¶
This is the Practical 6.4 sheet. Start nginx, a popular web server, in the background:
-d= detached: run in the background and give the prompt back.--name web= a name instead of a random one.-p 8080:80= publish a port: host port 8080 → container port 80. The host side is always written first.
Picture a door numbered 8080 in the wall of ubu-srv, a corridor, and the door 80 of the box. A port inside the box is invisible from outside until -p opens that corridor.
flowchart LR
B["<b>Browser on the host PC</b><br>http://192.168.122.10:8080"] -->|"port 8080"| H["<b>ubu-srv</b><br>the wall: door 8080"]
H -->|"-p 8080:80"| C["<b>container web</b><br>nginx listens on 80"]
Prove that it serves:
podman ps shows STATUS Up 2 seconds and PORTS 0.0.0.0:8080->80/tcp; curl answers HTTP/1.1 200 OK and Server: nginx/1.30.5 (the last number may be higher). Then open http://192.168.122.10:8080 in the browser of your host PC: "Welcome to nginx!". (Typing localhost on the host would ask the host itself, not the VM.)
Why not -p 80:80? A normal user cannot open ports below 1024, and we run Podman without root.
Look inside¶
podman logs web # start-up lines, then one line per request
podman top web # the processes of the box
podman exec -it web bash # a shell inside the running box
cat /etc/os-release
exit
logsshows a line like"GET / HTTP/1.1" 200 ...for each visit: find your own browser's.topshows onenginx: master processand severalnginx: worker process: just processes.- Inside,
/etc/os-releasesays Debian 13: this nginx image is built on Debian, running on an Ubuntu kernel.
Stop, start, remove¶
| Command | What it does |
|---|---|
podman stop web |
Stops it; the container still exists (podman ps -a) |
podman start web |
Starts the same container again |
podman rm web |
Deletes it, but refuses while it is running |
podman rm -f web |
Stops and deletes it |
podman images / podman rmi |
Lists / deletes images |
podman rm web on a running container gives: Error: cannot remove container ... as it is running - running or paused containers cannot be removed without force. And stop is not delete: only rm makes it disappear.
Two boxes from one image¶
Start web again on 8080, and a second container web2 on host port 8081 from the same image. Two things fail on purpose:
- A second container also called
web→the container name "web" is already in use. - A second container on host port 8080 → an error about the port being busy.
One image, many containers. One host port, one owner.
Key takeaways¶
- A container is a group of normal host processes in a box with its own files; it shares the host's kernel. A VM has virtual hardware and its own kernel.
- An image is the read-only template; a container is one instance of it. Images live in a registry and are versioned by a tag (write it:
latestchanges). - Podman runs containers without root and without a daemon, with the same commands and the same OCI images as Docker.
podman run -d --name web -p 8080:80 imageruns a service in the background and publishes host port 8080 to container port 80.ps -a,logs,top,exec,stop,start,rm -f: list, inspect and manage the boxes.
Quick check¶
1. What does a container share with the server it runs on?
- The kernel
- Its files
- Its list of users
- Nothing at all
A container has its own files (Debian inside, Ubuntu outside) and its own users, but no kernel of its own: uname -r prints the same string inside and outside.
2. What is an image?
- The read-only template a container starts from
- A container that is running right now
- A screenshot of a server's desktop
- A full backup of a virtual machine
The image is the packed template on disk; each container is one instance started from it. One image, many containers.
3. In -p 8080:80, which number is the port on the host?
- 8080
- 80
- Both of them
- Neither of them
The host side is always written first: host port 8080 forwards to port 80 inside the container.
4. Which command also lists the containers that are stopped?
- podman ps -a
- podman ps
- podman images
- podman logs
podman ps shows only running containers; -a adds the stopped ones. stop keeps a container until you rm it.
5. Which sentence about Docker and Podman is true?
- They run the same OCI images with almost the same commands
- They use two different, incompatible image formats
- Both of them need a daemon running as root
- Neither of them can publish container ports
Since the OCI standard (2015) images work in any tool. Podman has no root daemon; Docker uses dockerd. The commands differ in one word.
6. Why did we publish nginx with -p 8080:80 and not -p 80:80?
- A normal user cannot open host ports below 1024
- nginx refuses to listen on port 80 inside a box
- Port 80 is reserved for SSH on Ubuntu Server
- Podman only accepts host ports above 8000
We run rootless Podman, and ports below 1024 need root on the host. Inside the box nginx still listens on 80.
7. Marta's app works on her laptop but not on the server. Her teammate suggests a container. Select the two that are true.
- The image carries the app together with its libraries and configuration
- The same image runs the same way on her laptop and on the server
- The container brings its own kernel, so any OS family will work
- The container will run Windows programs on the Linux server
"Works on my machine" happens because the app is code plus everything around it. An image packs all of that, so it behaves the same everywhere. But it uses the host's kernel: Linux containers need Linux.
Today the box stored nothing. Next, you put a real web page and data inside, and discover that the box forgets: Images, volumes and ports.