Running Your First Container
This lab runs on a real VM
This box is not a Pod but a virtual machine launched by KubeVirt. A separate Linux kernel runs in it, systemd actually manages services, and docker is a real Docker engine, not an imitation. A container started with docker run becomes a real process, and both docker exec and docker logs work as usual.
This lab used to run inside a Pod. That box had dropped every kernel capability, so the step that starts a container was blocked, and you learned by working around it and unpacking image archives by hand. The workaround is no longer needed.
There are two things to know.
- The first start takes a little over a minute. The VM boots and installs Docker, so it is slower than a Pod lab (usually 40 seconds).
- There is no browser preview. Only one grading port is open for connections into the VM. If you start a web server, check it with
curlfrom inside the VM.
Goal
By handling images and containers by hand, you verify for yourself that a tag does not copy an image and that the inside and outside of a container see different file trees.
Why it matters
When people first meet containers, most of them try to memorize commands. But in practice, what gets you stuck is not the commands but the model. "I deleted the image but the container is still alive", "I changed the tag but the disk usage did not shrink", "the file exists inside the container but not on the host" — all of these are explained by one sentence: an image is a pile of read-only layers, and a container is a writable layer on top of it plus a process. So this lab is not about learning commands but about seeing that sentence with your own eyes.
Steps
- Create the
/root/dk1directory and save the list of images available in this box to/root/dk1/images.txt. Both the repository and the tag must be visible.docker imagesdoes not work in this box. Instead, each archive in/opt/images/*.tarhas anindex.json; if you read.manifests[0].annotations["org.opencontainers.image.ref.name"]in it, a name:tag such asdocker.io/library/alpine:3.20comes out as is — it is like looking one layer below to see where the Repository and Tag columns ofdocker imagescome from. - From the
alpine:3.20image, create a container nameddk-hellothat printshello-labhub, and keep the container even after it exits. - Run
nginx:1.27-alpinein the background with the namedk-web. - In the
nginx:1.27-alpinecontainer, read/etc/os-releaseand save it to/root/dk1/web-os.txt. Read it withdocker exec dk-web cat /etc/os-release. If you simply read this VM's/etc/os-release, you get Ubuntu and the check fails — that difference is exactly what the mount namespace does. - Find the container IP address of
dk-weband save only one line, the IPv4 address, to/root/dk1/web-ip.txt. - To
alpine:3.20, add one more name:labhub/base:v1. - Delete the
dk-hellocontainer. Leavedk-webas it is. - Fill in the three lines below with the actual values in
/root/dk1/report.txt.
image=<dk-web 이 쓰는 이미지 이름:태그>
container=dk-web
state=<dk-web 의 현재 상태>
Notes
- You can pull out just the columns you want with
docker images --format '{{.Repository}}:{{.Tag}}'. - It is safer to dig into the JSON directly, as in
docker inspect <이름> | jq -r '.[0].State.Status'. - Common mistake 1: if you add
--rmin step 2, the container disappears immediately and there is nothing to grade. - Common mistake 2: if you read the host's
/etc/os-releasein step 4, you get Ubuntu. You must read it inside the container.
Save the image list
Create the /root/dk1 directory and save the list of images available in this box to /root/dk1/images.txt. Both the repository and the tag must be visible.
docker images does not work in this box. Instead, each archive in /opt/images/*.tar has an index.json; if you read .manifests[0].annotations["org.opencontainers.image.ref.name"] in it, a name:tag such as docker.io/library/alpine:3.20 comes out as is — it is like looking one layer below to see where the Repository and Tag columns of docker images come from.
There is a subcommand that lists images. Do not just read the output on screen; keep it in a file with redirection. Not only the repository name but also the tag column must be left in it.
A container that runs once and ends
From the alpine:3.20 image, create a container named dk-hello that prints hello-labhub, and keep the container even after it exits.
If you give it a name, it is easier to find later. Note that if you add --rm it is deleted as soon as it finishes, leaving nothing to grade.
A container that keeps running in the background
Run nginx:1.27-alpine in the background with the name dk-web.
If you start it in the foreground, it holds your terminal. There is a flag that starts the container detached. It is normal for nginx to keep running without exiting.
Run a command inside a running container
In the nginx:1.27-alpine container, read /etc/os-release and save it to /root/dk1/web-os.txt.
Read it with docker exec dk-web cat /etc/os-release. If you simply read this VM's /etc/os-release, you get Ubuntu and the check fails — that difference is exactly what the mount namespace does.
If you read /etc/os-release on the host, you get Ubuntu. You have to read it inside the container's mount namespace to get Alpine.
Find out the container's IP
Find the container IP address of dk-web and save only one line, the IPv4 address, to /root/dk1/web-ip.txt.
The inspect output is JSON. Dig into it with jq or use a --format template. Only the IP address must remain in the file.
Give the image another name
To alpine:3.20, add one more name: labhub/base:v1.
A tag does not copy an image. After adding the new name, compare the image IDs of the two names.
Clean up only the finished container
Delete the dk-hello container. Leave dk-web as it is.
A stopped container also holds on to its writable layer. You must keep the running one and delete only the finished one.
Turn the current state into a report
Fill in the three lines below with the actual values in /root/dk1/report.txt.
All three lines are checked against the actual inspect values. Do not guess; write values you confirmed with a command.