Skip to content

Lab 01 Understanding Docker

Alex Thissen edited this page Nov 16, 2025 · 9 revisions

Understanding Docker

In this lab you will learn the basics about containers and the Docker CLI.

Open a new terminal session

Make sure you have Visual Studio Code open. Stop the debugger if it's still running from Lab 0.

Use Ctrl+Shift+P or Command+Shift+P to open the command palette and type create. Select Create New Terminal (With Profile) from the list of matches and then choose the bash profile. This should open a new terminal tab, at the bottom of your screen.

Docker CLI basics

The GitHub Codespace has Docker tooling installed allowing you to use the docker CLI command to interact with the containers, images and compositions in the Codespace.

Use the following command to see running containers:

docker ps

Even though you haven't started any yourself, there are some running containers. The output should look similar to this:

image

The running containers were put there by installing and initializing Dapr.

  • Zipkin is a collector for application telemetry.
  • Redis is used as a general-purpose state store and pub/sub messaging system.
  • The placement and scheduler container are used by Dapr to schedule workloads.

Running an existing container

There are many container images available free to use. The simplest one is 'hello-world'. It outputs a simple message to the console and then exits. Fetch the container image from the default container registry (Docker Hub):

docker pull hello-world:latest

The output should look similar to this:

latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete 
Digest: sha256:54e66cc1dd1fcb1c3c58bd8017914dbed8701e2d8c74d9262e26bd9cc1642d31
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest

Note that the image is pulled from docker.io/library, which is the address of the 'Docker Hub' registry. It contains publicly available images, often free to use.

The next step is to run it:

docker run hello-world

The output should look like this:

Hello from Docker!
This message shows that your installation appears to be working correctly.
[..]

If you see error messages, please ask for help from a proctor.

Running a web server

Just seeing 'hello world' on your screen is nice, but not very useful. Containers are capable of running workloads on your machine without requiring any setup. Let's run a containerized web server (Nginx) and connect it to your machine's network adapter so you can access it.

The process is similar as before: fetch and run the container. This time we will allow the run command to do the fetching automatically. Also, we will provide a port mapping from your laptop (left) to the remote container (right) using the -p 8080:80 argument. This maps the left hand port on your machine to the container port. The -d argument runs the container in detached mode, so it won't block your terminal. The --name nginx argument creates a named container, which is optional, but makes it easier to interact with it later on.

Run the following command to start an Nginx server instance with the name nginx:

docker run -d -p 8080:80 --name nginx nginx:latest

The output should look similar to this:

Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
5c32499ab806: Already exists 
375a694db734: Pull complete 
5f825f15e2e0: Pull complete 
16d05858bb8d: Pull complete 
08cfef42fd24: Pull complete 
3cc5fdd1317a: Pull complete 
4f4e50e20765: Pull complete 
Digest: sha256:8adbdcb969e2676478ee2c7ad333956f0c8e0e4c5a7463f4611d7a2e7a7ff5dc
Status: Downloaded newer image for nginx:latest
ce5d627ef786b1e4ea338f8406fec7782a559df742b608ae31729281602904ad

This has started the Nginx container with a unique identifier ce5d627ef786b1e4ea338f8406fec7782a559df742b608ae31729281602904ad. This identifier will be different in your case.

You can view the logs of a running container by referring to its name (ngnix in this case) or by specifying a unique part of the container id (for example ce5). View the Nginx logs with this command:

docker logs nginx

The output should look like this:

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/10/07 09:13:41 [notice] 1#1: using the "epoll" event method
2025/10/07 09:13:41 [notice] 1#1: nginx/1.29.1
2025/10/07 09:13:41 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14+deb12u1) 
2025/10/07 09:13:41 [notice] 1#1: OS: Linux 6.8.0-1030-azure
2025/10/07 09:13:41 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025/10/07 09:13:41 [notice] 1#1: start worker processes
2025/10/07 09:13:41 [notice] 1#1: start worker process 29
2025/10/07 09:13:41 [notice] 1#1: start worker process 30
2025/10/07 09:13:41 [notice] 1#1: start worker process 31
2025/10/07 09:13:41 [notice] 1#1: start worker process 32

Viewing logs is very useful when a container fails to start. Very often, it will show you what you need to correct, or at least provide something that you can use in a search engine to get help.

Custom port forwarding

You should now be able to go to the Ports tab in Visual Studio Code, and add a port mapping.

image

Click on 'Add Port' and type 8080. Press enter to create the port forward. Next, click on the 'globe' icon next to the port in the list, to open a new browser tab that shows Nginx running.

This should show a page similar to this:

image

Stopping a running container

To stop the Nginx container and remove it, run the following command:

docker rm -f nginx

If you just want to stop a running container, and be able to start it up later that is also possible.

Run, stop and restart new Nginx container with these commands:

docker run -d -p 8080:80 --name nginx nginx:latest
docker stop nginx
docker start nginx

Note that because we are starting an existing container, we don't need to provide any additional arguments, like port mappings.

Building a container image

In this chapter, you will build a custom container image for the frontend of our workshop application, store it locally and run it.

Navigate to the Frontend project and examine the contents of the directory:

ls /workspaces/Workshop-Azure-AI/src/AskVantage/AskVantage.Frontend

The output should be similar to this:

appsettings.Development.json  appsettings.json  AskVantage.Frontend.csproj  bin  Components  Dockerfile  obj  Program.cs  Properties  Services  wwwroot

One of the files is named Dockerfile describing the build process for the frontend container image. The command docker buildx build will create a local images file. You need to provide the location of the Dockerfile as the -f argument. Also, you must set the right context, so the Frontend project's dependency 'AskVantage.Frontend.Client' is also available to the Docker daemon when building the image. This is the last argument of the build command and is . for the current directory.

Move to the 'src' directory and build the container image:

cd /workspaces/Workshop-Azure-AI/src
docker buildx build -t frontend:v1 -f ./AskVantage/AskVantage.Frontend/Dockerfile .

Building an image can take a few minutes, while your machine is working on it, open up the Dockerfile to see the recipe that builds the container image. Open this file: /workspaces/Workshop-Azure-AI/src/AskVantage/AskVantage.Frontend/Dockerfile

This is a multi-stage Dockerfile that first copies the files to the 'base' image, then uses a containerized compiler 'build' to build a release version of the Frontend. Finally it copies the artifacts to a new image 'final'.

If all is well, you should now have a local container image with a compiled version of the Frontend project.

Running frontend as a container

In a terminal, type the following command to run a container with the Frontend app.

docker run --name frontend -d -p 5223:8080 frontend:v1

This command runs the frontend container with the name frontend and maps port 5223 on the host to port 8080 inside the container. This port was already declared as a port named Frontend inside the devcontainer.json file. Go to the Ports tab again, and click on the 'globe' icon next to that port number to view the frontend application.

Note that we haven't launched the Image API yet, so clicking on the buttons will not work. In a later lab, we will deploy the whole solution.

Stopping and removing the container

Run this command to stop and delete the frontend container:

docker rm -f frontend

In a later lab you will use Aspire to run containers for you as part of your composition.