Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Introduction

Docker is a container platform for developing, distributing, and running containerized applications natively on the Linux kernel. While designed for Linux, we can run Docker on Windows via the Windows Subsystem for Linux (WSL). However, setting up Docker on Windows 10 or 11 has different requirements than setting it up on Windows Server. Albeit different, we can run Docker Windows containers on Windows Server with a supported container runtime environment. Further, Windows Server is the only option for running Docker on Windows in a cloud environment (AWS, Azure, etc.).

In this tutorial, we’ll learn to set up Docker on Windows Server. The only prerequisite we need is a machine running Windows Server (2022, 2019, or 2016) as the operating system.

2. Install Docker on the Windows Server

We can choose from three supported container runtimes: Docker CE/Moby, containerd, and Mirantis Container Runtime. Let’s use the Docker CE (Community Edition), which is managed by the open-source Moby project. Microsoft provides a Powershell script that can be run to install the Docker runtime and configure the environment for container-related operating system features on Windows Server.

Let’s start a Powershell session and run the command to install the Docker CE:

PS C:\Windows\system32>Invoke-WebRequest
  -UseBasicParsing "https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1"
  -o install-docker-ce.ps1
.\install-docker-ce.ps1

When we run this script for the first time, it performs the prerequisite setup:

  • Enables the Windows feature: Containers
  • Installs Docker
  • Installs Docker Daemon
  • Configures the docker service
  • Connects to Docker Daemon

The system performs an automatic restart during the installation process. When we aren’t the first user or the script installer, we can always run the script again to verify that the system is set for Docker:

Querying status of Windows feature: Containers...
Feature Containers is already enabled.
DOCKER default                                                                                                             
Installing Docker... C:\Users\Administrator\DockerDownloads\docker-27.3.1\docker\docker.exe
Installing Docker daemon... C:\Users\Administrator\DockerDownloads\docker-27.3.1\docker\dockerd.exe
Configuring the docker service...
Waiting for Docker daemon...
Successfully connected to Docker Daemon.
The following images are present on this machine:
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

Script complete!

Let’s run the docker commands docker version and docker info to get details about the new installation:

$ docker version
Client:
 Version:           27.3.1
 OS/Arch:           windows/amd64

Server: Docker Engine - Community
 Engine:
  Version:          27.3.1
  OS/Arch:          windows/amd64

$ docker info
Client:
 Version:    27.3.1

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 27.3.1
 Storage Driver: windowsfilter
  Windows:
 Kernel Version: 10.0 20348 (20348.1.amd64fre.fe_release.210507-1500)
 Operating System: Microsoft Windows Server Version 21H2 (OS Build 20348.2849)
 OSType: windows
 Architecture: x86_64
 Docker Root Dir: C:\ProgramData\docker
 Product License: Community Engine

We’ve completed the Docker setup on Windows Server and can start using it.

3. Pull a Windows Container Image

Let’s pull or download a Windows Server base image from the Microsoft Container Registry. The Nano Server is an ultralight base image for Windows Server containers:

$ docker pull mcr.microsoft.com/windows/nanoserver:ltsc2022
ltsc2022: Pulling from windows/nanoserver
f66768ec6d65: Pull complete
Digest: sha256:be37c9e8bf388c4e3ef27b4a2592b94adab551e231644ce3c9d4d3dc0a50af41
Status: Downloaded newer image for mcr.microsoft.com/windows/nanoserver:ltsc2022
mcr.microsoft.com/windows/nanoserver:ltsc2022

Notably, the tag of the base image should match the OS version; ltsc2022 for WindowsServer 2022, ltsc2019 for Windows Server 2019, and so on. These base images are themselves based on the Windows 10 OS. Therefore, we can run only Windows containers from these images by default.

Let’s list images:

$ docker images
REPOSITORY                             TAG        IMAGE ID       CREATED       SIZE
mcr.microsoft.com/windows/nanoserver   ltsc2022   890e4cf2e171   3 weeks ago   293MB

It should list the downloaded image.

4. Run a Windows Container

Let’s run a Windows container from the pulled image:

$ docker run -it mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd.exe
Microsoft Windows [Version 10.0.20348.2849]
(c) Microsoft Corporation. All rights reserved.

C:\>

It starts a command prompt within the Windows container. Notably, it lists the Windows version as 10.0 because we’re within a container. We can exit the container with the exit command:

C:\>exit

When a container exits, it switches context to the host Windows Server. We can list the container we exited:

$ docker ps -a
CONTAINER ID   IMAGE                                           COMMAND     CREATED         STATUS                          PORTS     NAMES
79976e7b1972   mcr.microsoft.com/windows/nanoserver:ltsc2022   "cmd.exe"   4 minutes ago   Exited (0) About a minute ago             hopeful_tharp

It generates a container name automatically when we don’t specify one at launch time.

5. Build a New Container Image

Let’s build a new container image from the container we just ran:

$ docker commit 79976e7b1972 helloworld
sha256:4c6db347d185012ac56555e9d31dcbe0601e739985c477a1e23b88e349d6b252

We called the new image helloworld, and can list it along with other images:

$ docker images
REPOSITORY                             TAG        IMAGE ID       CREATED          SIZE
helloworld                             latest     4c6db347d185   34 seconds ago   294MB
mcr.microsoft.com/windows/nanoserver   ltsc2022   890e4cf2e171   3 weeks ago      293MB

Although we didn’t modify the base image we pulled, base images are typically modified and used to develop new, custom images.

6. Run a Command in a Container

Let’s launch a new Windows container using the helloworld image we just built and start an instance of Cmd.exe within the container to run an echo command in the container:

$ docker run --rm helloworld cmd.exe /s /c echo 'Hello Docker on Windows Server'
"Hello Docker on Windows Server"

It outputs the result to the shell itself from where we run the docker run command, and removes the container because we included the –rm option.

7. Use With a Docker Repository/Hub

We can log in to a Docker repository using the docker login command:

docker login [OPTIONS] [SERVER]

The [SERVER] is the repository address or the Server URL; the default is https://index.docker.io/v1 for the Docker Hub. We specify username and password for options.

7.1. Login To Docker Hub

Let’s log in to the Docker Hub:

$ docker login -u username -p password

Login Succeeded

7.2. Tag a Container Image

We need to prefix/tag an image to correspond to the Docker Hub repository we want to upload to. For example, to upload to the baeldung repository we prefix it as baeldung. Let’s tag the helloworld image we created:

$ docker image tag helloworld baeldung/helloworld

Let’s list the images:

$ docker images
REPOSITORY                             TAG        IMAGE ID       CREATED       SIZE
helloworld                             latest     4c6db347d185   2 hours ago   294MB
baeldung/helloworld                      latest     4c6db347d185   2 hours ago   294MB
mcr.microsoft.com/windows/nanoserver   ltsc2022   890e4cf2e171   3 weeks ago   293MB

Indeed, the tagged image is listed.

7.3. Push the Tagged Image to the Docker Hub

While we’re logged in to the Docker Hub, let’s push or upload the tagged image to the repository:

$ docker push baeldung/helloworld
Using default tag: latest
The push refers to repository [docker.io/baeldung/helloworld]
8290390d708d: Pushed
afe057336777: Pushed
latest: digest: sha256:30880b447432edc2f6abf67140e477334d70b130dbc34a94e486224585897b06 size: 740

We can verify the image is uploaded by logging in to the Docker repository uploaded to.

7.4. Remove the Local Copy of the Container Image

When we don’t need an image, we can remove the image:

$ docker rmi baeldung/helloworld
Untagged: baeldung/helloworld:latest
Untagged: baeldung/helloworld@sha256:30880b447432edc2f6abf67140e477334d70b130dbc34a94e486224585897b06

Removing unneeded images is a method usually used to free up disk space.

7.5. Pull a Container Image From the Docker Hub

Let’s pull the container image we just uploaded to Docker Hub:

$ docker pull baeldung/helloworld
Using default tag: latest
latest: Pulling from baeldung/helloworld
Digest: sha256:30880b447432edc2f6abf67140e477334d70b130dbc34a94e486224585897b06
Status: Downloaded newer image for baeldung/helloworld:latest
docker.io/baeldung/helloworld:latest

After that let’s run a command in a Container launched from the pulled image:

$ docker run --rm baeldung/helloworld cmd.exe /s /c echo "Hello!"
Hello!

Again, a Windows container launches, prints the output from the command, and exits.

8. Conclusion

In this article, we learned how to set up Docker on a Windows Server 2022. We can use the same procedure with any of the Docker-supported versions of Windows Server. We discussed pulling a Windows Server base image, running a Windows container from it, creating a new image from a container, and running a command in a container. Furthermore, we discussed logging in to a Docker repository (Docker Hub) to upload and download a tagged Docker image.

As always, the Docker commands’ scripts used in this article are available over on GitHub.