Docker Compose "is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services." In this post, I will show how you can work with Docker Compose.

Docker on Windows is now commonplace, and it comes with additional features you may not be familiar with. In my previous posts Install Docker and run containers on Windows and Create a Docker container on Windows with a Dockerfile, I showed you how to create a single container. In this article, I will walk you through how to use docker-compose to create and run multiple containers at once.

When you install the Docker Toolbox on Windows, you already have Docker, but you also get Docker Compose. Before we get started, make sure you have docker-compose installed on your machine by opening up a cmd prompt or PowerShell console, and run the following command:

docker-compose -v

If you did not receive an error, you are good to go. If you did, please make sure you look at my previous posts mentioned above.

During this article we are going to create a simple Microsoft IIS Server in one Docker container and have a second container that will test the first to make sure it is running. To do this, we first need to understand that Docker Compose uses a docker-compose.yml file to detail the specifics for our running containers.

Our docker-compose.yml file looks like this:

version: "3"
services:
    web:
        build:
            context: ./iis-server
            dockerfile: Dockerfile
    test:
        build:
            context: ./iis-server-test
            dockerfile: Dockerfile
        command: powershell -executionpolicy bypass "c:\temp\iis-server-test.ps1"
        depends_on:
            - "web"

A Docker Compose file uses a YAML configuration syntax to build and manage our containers. Additionally, Docker has specified that a docker-compose.yml file can only have a few top-level keys, which define "sections" within our configuration file. For this example, we are only going to be focusing on version, services, and (later on) networks.

With this simple file, we will create two containers. One will be our actual IIS Server with a sample Home.html page. The second container will be a nanoserver that just runs and tests that our IIS Server is up and running (as expected). Now let's break down our folder structure:

./docker-compose.yml
./iis-server/Dockerfile
./iis-server/Home.html
./iis-server-test/Dockerfile
./iis-server-test/iis-server-test.ps1

We have specified at the top of our docker-compose.yml file that we would like to use version 3 of the Docker Compose file reference. We could use additional versions if needed, but version 3 is the recommended one.

The second section, services, is where the fun stuff is! We are going to specify two separate containers (or services) in this section. First, we define our actual web application (site). We give it the simple name web, but it can be anything as long as it is a string with no spacing. We then specify that when we run docker-compose, we want it to build a brand-new image/container using the Dockerfile in the specified location (context). You can see this in the following code snippet:

services:	# A "section" that specifies services
  web:	# The name of our service
    build:	# We specify that we want to build an image
      context: ./iis-server	# The location (can be a URL) of our image
      dockerfile: Dockerfile	# The name of the file to reference (could be any name)

Let's take a look at what is in our ./iis-server/Dockerfile:

FROM microsoft/iis
RUN mkdir c:\myapp
RUN powershell -NoProfile -Command \
    Install-WindowsFeature NET-Framework-45-ASPNET; \
    Install-WindowsFeature Web-Asp-Net45; \
    Import-Module IISAdministration; \
    New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"
EXPOSE 8000
ADD . /myapp

If you are curious about what this file means, please review my last post titled Create a Docker container on Windows with a Dockerfile. This goes into more detail about Dockerfiles. To summarize though, this Dockerfile will pull down an image from the official Docker repository named Microsoft/iis. It will then create a directory, install Windows Features, create a new IIS website, and add my Home.html to the container in our created directory (c:\myapp\Home.html).

The ./iis-server/Home.html file contains just a simple HTML page:

<HTML>
<HEAD>
<TITLE>Using Docker Compose on Windows</TITLE>
</HEAD>
<BODY BGCOLOR="FFFFFF">
<H1>Using Docker Compose on Windows</H1>
<H2><a href="https://4sysops.com">4sysops</a> is a great site!</H2>
<H3>Josh Rickard</H3>
You can reach me here:</br>
<a href="https://twitter.com/MS_dministrator">Twitter</a></br>
<a href="https://github.com/MSAdministrator">GitHub</a></br>
<a href="https://4sysops.com/archives/author/msadministrator/">4sysops Author Page</a></br>
<a href="https://msadministrator.com">MSAdministrator.com</a>
</BODY>
</HTML>

Next, let's talk about our test image/container. The reason I'm creating this container is to simulate how you would have two (or more) containers running at the same time. Like we did with our web container, we specify a name: test.

test:
   build:
      context: ./iis-server-test
      dockerfile: Dockerfile
  command: powershell -executionpolicy bypass "c:\temp\iis-server-test.ps1"
  depends_on:
      - "web"

After we have given our container a name, we next specify that we want to build it. By the way, there are additional options when writing a docker-compose.yml file. For example, you could use the image tag. After specifying our build tag, we then pass in our context (or location) and our Dockerfile name.

Let's look at what is inside both of these next files:

./iis-server-test/Dockerfile
FROM microsoft/nanoserver:latest

RUN mkdir c:\temp
ADD iis-server-test.ps1 c:/temp/

# The command: tag in our docker-compose.yml will run the following
# after we have successfully built our container image
# powershell -executionpolicy bypass c:\temp\iis-server-test.ps1

./iis-server-test/ iis-server-test.ps1
try {
    If((Invoke-WebRequest web).StatusCode -eq 200) {
        Write-Output "IIS Server is alive!"
    } Else {
        Write-Output "IIS Server is not responding"
    }
} catch {
    throw $Error[0]

Understanding the processing order for these two next two tags better explains how they work. First, let's look at the depends_on tag. When we use this value, we are saying to create/build our first container web initially before this container (service). With this setting, we are now forcing the Docker Compose image to build web first before we do anything else. The command tag will only run after building web, which is exactly what we want.

Now that we understand our file structure and what our two containers are doing, all we need to do is run one of two simple commands. I prefer using the second one to see what is happening.

docker-compose up
	or
docker-compose up -build

You should see the following when everything is up and running. Please note that the first time you run this, it may take a while. This is because we are downloading our images from the Docker repository, but after the first time, it should only take a few seconds to build.

Running docker compose up build should display the output above

Running docker compose up build should display the output above

Once you are satisfied your containers are working, you can do the following with them:

docker-compose down		# stops resources up created
docker-compose stop 	# use this to stop any running containers
docker-compose kill		# use this to stop any running containers forcefully
docker-compose rm		# removes stopped service containers

You can find all the files I referenced below:

Subscribe to 4sysops newsletter!

# ./docker-compose.yml
version: "3"
services:
    web:
        build:
            context: ./iis-server
            dockerfile: Dockerfile
    test:
        build:
            context: ./iis-server-test
            dockerfile:  Dockerfile
        command: powershell -executionpolicy bypass "c:\temp\iis-server-test.ps1"
        depends_on:
            - "web"

# ./iis-server/Dockerfile
FROM microsoft/iis
RUN mkdir c:\myapp
RUN powershell -NoProfile -Command \
    Install-WindowsFeature NET-Framework-45-ASPNET; \
    Install-WindowsFeature Web-Asp-Net45; \
    Import-Module IISAdministration; \
    New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"
EXPOSE 8000
ADD . /myapp
# ./iis-server/Home.html
<HTML>
<HEAD>
<TITLE>Using Docker Compose on Windows</TITLE>
</HEAD>
<BODY BGCOLOR="FFFFFF">
<H1>Using Docker Compose on Windows</H1>
<H2><a href="https://4sysops.com">4sysops</a> is a great site!</H2>
<H3>Josh Rickard</H3>
You can reach me here:</br>
<a href="https://twitter.com/MS_dministrator">Twitter</a></br>
<a href="https://github.com/MSAdministrator">GitHub</a></br>
<a href="https://4sysops.com/archives/author/msadministrator/">4sysops Author Page</a></br>
<a href="https://msadministrator.com">MSAdministrator.com</a>
</BODY>
</HTML>
# ./iis-server-test/Dockerfile
FROM microsoft/nanoserver:latest

RUN mkdir c:\temp
ADD iis-server-test.ps1 c:/temp/

# The commannd: tag in our docker-compose.yml will run the following 
# after we have successfully built our container image
# powershell -executionpolicy bypass c:\temp\iis-server-test.ps1
# ./iis-server-test/iis-server-test.ps1
try {
    If((Invoke-WebRequest web).StatusCode -eq 200) {
        Write-Output "IIS Server is alive!"
    } Else {
        Write-Output "IIS Server is not responding"
    }
} catch {
    throw $Error[0]
}
avatar
1 Comment
  1. Kira Resari 3 years ago

    Thank you for th tutorial Unfortunately, for me this fials with the following error message:

    PS C:\Docker Data Directory\DockerComposeTutorial> docker-compose up --build
    Creating network "dockercomposetutorial_default" with the default driver
    ERROR: HNS failed with error : The parameter is incorrect.

Leave a reply

Please enclose code in pre tags

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account