TT Lab
Get started
Learn Learning paths Courses

Volumes, Networks and Compose

Declare a Stack and Check It Against Reality

Continue in TT Lab

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.

Goal

You declare a stack of two services in a Compose file, start the same stack by hand as well, and compare whether the declared values and the actual values match exactly.

Why it matters

If you understand Compose only as "a tool that starts several containers at once", you get only half of it. The real value is that the shape of the stack is written in a file and remains in the repository. And this value holds only when the file and reality match. The moment someone fixes a container by hand, the file is no longer documentation but a lie, and nobody knows about that lie until the next deployment. That is why the last step of this lab is not building a new feature but comparison. The habit that every team using declarative tools must have is here.

Steps

Write /root/ops3/compose.yaml with the structure below. Indent with 2 spaces, and the top-level keys (services:, volumes:, networks:) must start at the very beginning of the line.

  1. Put services: at the top level and, under it, declare the two services web: and cache: with 2-space indentation.
  2. Set web's image to nginx:1.27-alpine and cache's image to alpine:3.20, and for cache also write a command so that it keeps running.
  3. Put networks: at the top level and declare appnet: under it, then, in the networks: list of both services, put - appnet.
  4. In web, add ports: and put "127.0.0.1:8081:80" in it. On cache, do not put ports.
  5. Put volumes: at the top level and declare webdata:, then, in web's volumes:, put webdata:/usr/share/nginx/html.
  6. In cache, use environment: to put CACHE_TTL with the value 60, and in web, use depends_on: to put - cache.
  7. Start the same stack by hand. The network name is ops3net, and the container names are ops3-web (nginx:1.27-alpine, publishing 127.0.0.1:8081:80) and ops3-cache (alpine:3.20, environment variable CACHE_TTL=60), and you attach both to ops3net.
  8. There is nothing new to create in this step. You confirm that the declaration up to step 6 and the actual containers of step 7 match exactly on the three items: image, port and environment variable.

Notes

Declare two services

Put services: at the top level and, under it, declare the two services web: and cache: with 2-space indentation.

Put the service names under the top-level services with 2-space indentation. If the indentation is off, the meaning of the whole file changes.

Specify the image and command

Set web's image to nginx:1.27-alpine and cache's image to alpine:3.20, and for cache also write a command so that it keeps running.

alpine's default command ends immediately, so you must also write a command that keeps running.

Declare a shared network

Put networks: at the top level and declare appnet: under it, then, in the networks: list of both services, put - appnet.

Declare networks at the top level and refer to that name from each service. Both places are needed.

Ports only on the loopback

In web, add ports: and put "127.0.0.1:8081:80" in it. On cache, do not put ports.

You can prefix the port string with a binding address. Do not use ports for a service that only does internal communication.

Declare a named volume

Put volumes: at the top level and declare webdata:, then, in web's volumes:, put webdata:/usr/share/nginx/html.

Declare the name in the top-level volumes and use it in the service together with the target path.

Environment variable and startup order

In cache, use environment: to put CACHE_TTL with the value 60, and in web, use depends_on: to put - cache.

Remember that depends_on guarantees only order, not readiness.

Start the same stack by hand

Start the same stack by hand. The network name is ops3net, and the container names are ops3-web (nginx:1.27-alpine, publishing 127.0.0.1:8081:80) and ops3-cache (alpine:3.20, environment variable CACHE_TTL=60), and you attach both to ops3net.

Create the network first and then attach the containers. Use exactly the same values as those written in the declaration file.

Compare the declaration with reality

There is nothing new to create in this step. You confirm that the declaration up to step 6 and the actual containers of step 7 match exactly on the three items: image, port and environment variable.

Grading directly compares the values read from the compose file with the inspect values of the actual containers. If even one character differs, they are out of sync.