- 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
A Dockerfile (no file extension) is a definition file that will build and run a container. That container can be a simple Microsoft IIS web application or Python/Flask application or a simple build/reporting service. A definition file helps us with our operational tasks, especially when we are building services or scripts for the repeatable tasks we face on a daily basis.
Here is an example of a Dockerfile that will set up an IIS web server with ASP.NET 4.5 on a Windows system:
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 bin/ /myapp
Wow, I bet you didn't think these few lines would set up an entire IIS web application with ASP.NET 4.5, did you? Well, they do! Let's break this down a bit further.
As explained in my previous post, Docker images are prebuilt "prerequisites" we can install and use when creating and running our container. Within a Dockerfile we specify the base image we want to use by declaring FROM {image name}. In this case, we are using the Docker Hub image for an IIS server Microsoft has provided.
FROM microsoft/iis
The second statement you see uses the RUN command to tell the container, once it is running, to call mkdir c:\myapp. At this point, it creates a new directory inside our container itself called c:\myapp.
At this point Docker has downloaded and built a containerized application based of the Microsoft/iis image with all the base prerequisites needed for setting up an IIS server. In addition we are telling the container also to create a new "virtual" folder inside the container itself. You don't really have access to this location, meaning you won't see it on your local file system. At this point, you just need to trust Docker is doing what you specified (and it is).
Moving on, the next statement you see is another RUN command:
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:"
This RUN command is a bit different but does essentially the same thing. This time we are now specifying that we should create a new PowerShell "shell" by calling:
powershell -NoProfile -Command
Next, we specify our standard PowerShell commands as normal. You may notice that each line has a "\" at the end of it. The backslash is to ensure line continuation within the Docker container.
Install-WindowsFeature NET-Framework-45-ASPNET; \ Install-WindowsFeature Web-Asp-NET45; \ Import-Module IISAdministration; \ New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"
We then install the NET-Framework-45-ASPNET and Web-Asp-Net45 Windows features, just like we would do on a normal IIS web server. We then import the IISAdministration PowerShell module and create a new IIS website called MyApp. The New-IISSite cmdlet also allows us to specify a PhysicalPath and a specific port to bind to. In our case, we are binding all requests to port 8000.
Next, we then run the EXPOSE networking option in our Dockerfile. This option is a bit confusing to some, but it allows the individual who is generating the Docker container to specify a network port the individual can use to interact with the container. EXPOSE does not actually expose the network port. To expose a port to the world (or our network), you would need to specify another option when you run your container. For example, you would do the following:
docker run {image} -p 80
This would actually expose the container to a network outside your local system.
Within our folder that contains our Dockerfile, we should also have a folder named bin. Within this folder, we should have a basic HTML file called index.html with the following content:
<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML> <HEAD> <TITLE> Hello from my Docker for Windows Container! </TITLE> </HEAD> <BODY> <H1>Hi</H1> <P>This is very minimal "hello world" HTML document, but it's running within Docker for Windows</P> </BODY> </HTML>
The last statement in our Dockerfile is the ADD command. This command will add files or scripts or whatever you have specified to the container.
ADD bin/ /myapp
How the ADD command works is that it takes the current directory holding your Dockerfile, and if you have specified a specific folder, like bin/, it would add this directory and all of its contents to /myapp within the Docker container. Here's a visual representation of this:
Now that we have our Dockerfile and our bin/index.html in the same folder, we will now build and run our new container!
To run our new container, open up your PowerShell console. Next, change directories to the folder container for your Dockerfile and bin/index.html folder. For me, I have these located at C:\Docker For Windows Example:
[Open PowerShell Console] cd 'C:\Docker For Windows Example' docker build .
Please note that the full command is docker build . The period at the end is needed, and it references the location of our Dockerfile.
After we have pulled down our image from Docker Hub, we should now have a new IIS website set up and running our index.html page. You can view it by going to your browser and going to:
http://127.0.0.1/index.html
Besides the options I mentioned in our example, you have additional commands available that I believe you will find extremely useful. These additional commands are:
ENTRYPOINT/CMD: You may see this command as either ENTRYPOINT or CMD, but there are only minor differences between the two. An example of how to use CMD is as follows:
General Example: CMD ["executable","param1","param2"] Python Example: CMD ["python", "/usr/src/app/setup.py"] PowerShell Example: CMD [powershell.exe, -executionpolicy, bypass, c:\startup.ps1]
ENV: The ENV statement allows you to specify environmental variables within the container you are running. These can be great for a handful of variables, but this command does slow down your build process.
WORKDIR: WORKDIR allows you to set the working directory within a container. This is great if you want to use relative paths within your container. We'd typically use this before we call our RUN, CMD, ENTRYPOINT, etc. commands in our Dockerfile
You can find more information about all the commands available by visiting Docker's official documentation. Please view this documentation here.
Now that we understand the basics on building containers, we should be familiar enough to start playing around with all the available images on Docker Hub and even starting to create our own.
In the next segment of this series, we will go a bit further and talk about using docker-compose. This amazing feature will allow you to create multiple containers simultaneously. Why is this useful? Imagine creating an application that has both a front-end UI and a back-end database. In the meantime, please check out more information about Docker Compose here.
Hey, great tutorial.
Can you please provide some guidance on how to tweak the Dockerfile in order to run a shiny app.
Thank you.