C# Applications Deployed With Docker and Mono
Lately I’ve been working a lot with Mono , and building C# applications on Linux. Just recently I discovered the official mono image in the Docker Hub Repo . This image comes with xbuild and NuGet (tools we need for building).
So lets do a little work and get a mono application up and running (note I’m using a company application and will remove any references that may be sensitive.) I start by pulling the application’s source code down beside the Dockerfile :
# tree -L 3 .
.
├── Company.Session
│ ├── README.md
│ └── src
│ ├── Company.Session
│ ├── Company.Session.SessionService
│ ├── Company.Session.sln
│ ├── Company.Session.sln.DotSettings
│ └── Company.Session.Tests
└── Dockerfile
5 directories, 4 files
The Dockerfile handles the build, running, and network exposing for this app:
# The Official Mono Docker container
# https://registry.hub.docker.com/_/mono/
FROM mono:3.12
MAINTAINER nessy "nessy@...."
# The TCP ports this Docker container exposes the the host.
EXPOSE 80
ENV LISTEN_ON http://*:80/
ENV POSTGRESQL_USER_ID root
ENV POSTGRESQL_USER_PW password
ENV POSTGRESQL_HOST 172.17.42.1
ENV POSTGRESQL_PORT 5432
ENV POSTGRESQL_DATABASE session
ENV POSTGRESQL_SEARCH_PATH public
# Add the project tarball to Docker container
ADD Company.Session /var/mono/Company.Session/
WORKDIR /var/mono/Company.Session/src/
# Build our project
RUN nuget restore Company.Session.sln
RUN xbuild Company.Session.sln
# Change to our artifact directory
WORKDIR /var/mono/Company.Session/src/Company.Session.SessionService/bin/Debug
# Entry point should be mono binary
ENTRYPOINT mono Company.Session.SessionService.exe
All that is needed now is to build the Docker image:
# docker build --no-cache -t session:0.1 .
After the build we should have some new images:
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
session 0.1 e886dc0f6db2 3 minutes ago 405.3 MB
mono 3.12 ad04eb901ba0 2 weeks ago 348.7 MB
Let’s start the new session image and bind it’s exposed port locally to 2345 :
# docker run -d -p 2345:80 e886dc0f6db2
d8c4a7088da8ba0874c63e30e564a077b1c1a544825d7d1e148862b6b81f5600
We should now have a running Docker container:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d8c4a7088da8 session:0.1 /bin/sh -c 'mono Big 12 seconds ago Up 11 seconds 0.0.0.0:2345->80/tcp stoic_lalande
The Docker command logs will display the output from the running command.
# docker logs d8c4a7088da8
{"date":"2015-03-24T01:44:30.3285150+00:00","level":"INFO","appname":"Company.Session.SessionService.exe","logger":"Topshelf.HostFactory","thread":"1","ndc":"(null)","message":"Configuration Result:\n[Success] Name Company.Session.SessionService\n[Success] ServiceName Company.Session.SessionService"}
...
And lastly we should verify the TCP port mapping is working and we can hit it from the host:
# curl -I localhost:2345
HTTP/1.1 302 Found
Location: http://localhost/metadata
Vary: Accept
X-Powered-By: ServiceStack/4.036 Unix/Mono
Server: Mono-HTTPAPI/1.0
Date: Tue, 24 Mar 2015 01:46:06 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100