- Search Event Logs and error codes with Netikus.net System32 - Thu, Jan 10 2019
- Netikus.net IPMon+ – GUI for ipmon.exe - Tue, Nov 20 2018
- Understanding PowerShell Begin, Process, and End blocks - Mon, Oct 15 2018
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.
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] }
Thank you for th tutorial Unfortunately, for me this fials with the following error message: