Creating Docker Containers for Legacy Windows Console Applications
This is a continuation of a post about Legacy Windows Applications
In this example we are going to create an image for starting a container in Docker. This container will provide a http post endpoint to take a file and provide back some converted result from a "legacy" application. If you read this post it will show you how to automate the legacy application installs and that provides a good start for containerizing a legacy windows application.
The use case for this example is wanting to run a legacy windows console application and post files to it to be ran and then receive the output. If all you want to run is a .net core WebApi or MVC application there are easier ways to do that.
In this example we are going to use:
The information contained in this example can be paired with this blog post to dockerize legacy windows applications.
Creating the Docker Build
Create an empty directory and call it what you are going to name the image. I used "http-zip-service". This will be our "build" directory.
In this folder place the contents of the ConsoleCommandProxy publish. Create an empty text file called "dockerbuild". We need the ConsoleCommandProxy project because we need a way to send files to the legacy console application and get the results from outside of the container.
In this example the Compress-Archive cmdlet in Powershell will simulate our legacy application.
When we run "docker build" in a directory the "dockerbuild" file controls how docker creates the image. Let's put some content in the docker build file.
Fairly simple and straight forward. Next we need to change things in the HttpHost files.
Change the file "hosting.json" to: This will allow the ConsoleCommandProxy to use any IP address in the container and communicate via port 5000.
Next change the file "appsettings.json" to:
This will use the Compress-Archive cmdlet in Powershell to create a zip file. A user will post a file and then receive a compressed file back. The powershell cmdlet "CompressArchive" is our legacy application for this example.
The above settings for the ConsoleCommandProxy define that when a file is posted (input file is {0} in the arguments), it will run a command line exe and return the output file (output is {1} in the arguments). The output extension is ".zip" because we want that extension all the time. You can leave this as "" if you just want to use the output extension. And the command is "powershell.exe".
When a user posts a file to http://some-ip:5000 it will take the file run the command using the arguments and send back the zipped output of the command to the user.
Now let's build a container and see how it works.
From the command line go to the directory where the build files are and run the command:
docker build -t http-zip-service .
The following should happen:
This will have docker build an image from the current directory named http-zip-service and not run it.
Next we will start the image in a container and poke around and see if we can make the HttpHost run. This is where we would make sure that the legacy application is working right inside of the container. If it doesn't work we can troubleshoot and change the continer build and install.ps1 scripts at this time to get it working.
In the command line type:
docker run -it http-zip-service powershell
This will have docker start a container using the "http-zip-service" image in interactive and terminal mode and start Powershell for us. This effectively starts the container and logs us into the container's console.
You will see this:
Now let's start the app. Run the following in the shell on the container:
Unfortunately the HttpHost is a .NET CORE 2.2 application and the .NET CORE 2.2 runtimes are not installed in the container. Let's fix that.
Exit the container. It will stop.
In the build directory on the host create a "install.ps1" file and use the following text:
Now edit your "dockerfile" to look like:
Now let's rebuild the image:
docker build -t http-zip-service .
It should build.
Now start it and try to run the app again.
docker run -it http-zip-service powershell
It should work when you run "dotnet httphost" from the command line.
Now it is working. Press CTRL+C on the keyboard and exit the app then quit from the console which will exit the container.
Change the "dockerfile" to include an entry point at the bottom:
Rebuild the image:
docker build -t http-zip-service .
Now we are going to run the image in "detached" mode with ports published. Detached mode means the containers will run in the background. We can view what is running by using the command "docker ps". The port 5000 in the container will be published to the host on port 5001. This way we can open a browser (outside of the container) and connect to the service inside the container.
The command we want to run is:
docker run -d -p 5001:5000 http-zip-service
If you want to see running containers:
docker ps
If you want to see all containers:
docker ps -a
If you want to stop a container:
docker stop <container-id>
If you want to start a stopped container:
docker start <container-id>
If you want to remove a container:
docker rm <container-id>
Docker will capture the stdout from a container and log it. To view the logs for a container use:
docker logs <container-id>
If you open a browser in the host and go to the url http://localhost:5001/health you should see "Healthy". Or from the command line:
curl http://localhost:5001/health
Let's see what happens when we try to zip a file via http. From the command line run:
curl -v -F file=@appsettings.json http://localhost:5001 --output "test.zip"
A test.zip should be created and will contain the original file.
When Things Go Wrong:
- Typos. Lots of text files and typing means lots of chances for typos. Double check the syntax and variable names in scripts.
- If your docker build fails and you want to see what state the container was in at that build step read this stackoverflow.com.
- If you want to attach a terminal to a running container use the docker attach or docker exec commands.
- Viewing the event viewer in windows server core. There is no GUI in Windows Server Core. If something goes wrong with your install in the container you may need to access the information contained in the Event Viewer.
In the next blog post let's move away from the numeric IP address and do service discovery with Docker, Consul and Registrator.