Let’s put the “Build once, Run anywhere” promise to the test: build the container for the mock service
Though there are many, many, many ways to run a service you’ve built in different environments, most of them require extensive reconfiguration, are problem prone and break easily. Just ask any developer that has built apps for IIS .
Docker is very popular because it solves this problem neatly. It builds a container -a box- within which your application lives. This stays the same everywhere, be it the dev PC, your local staging and production environment or the cloud. You still need, of course, to know how to communicate to other services or how the world reaches you, but this is reduced to a few configuration files.
And, while usually I’m suspicious against overhyped products and technologies, Docker really is easy to use.
How easy? Well, that’s what we need to do for our mock service:
- Install docker for your OS and create an account in docker hub
- Inside the wiremock folder, create an empty text file named Dockerfile (no extension)
- Open it with a text editor and paste the following (I’ll explain below):
FROM rodolpheche/wiremock LABEL maintainer="Your Name <firstname.lastname@example.org>" ADD mappings/*.json /home/wiremock/mappings/ ADD __files/*.* /home/wiremock/__files/ CMD ["java", "-cp", "/var/wiremock/lib/*:/var/wiremock/extensions/*", "com.github.tomakehurst.wiremock.standalone.WireMockServerRunner", "--global-response-templating", "--verbose"]
4. Open a command window in the wiremock folder and enter the following command:
docker image build -t graubfinancemock:1.0 .
We’ve built our container image, now lets run it:
docker container run --publish 80:8080 --detach --name graubfinancemock graubfinancemock:1.0
To test if it works, open a browser and navigate to http://localhost/servicehealth .
The last step is to publish it so that it’s available for others (like our cloud instance which we’ll create next) to use. In the command window enter the following commands (use the login details you created in dockhub, step 1):
docker login docker image tag graubfinancemock:1.0 YOURUSERNAME/graubfinancemock:1.0 docker image tag graubfinancemock:1.0 YOURUSERNAME/graubfinancemock:latest docker image push YOURUSERNAME/graubfinancemock:1.0 docker image push YOURUSERNAME/graubfinancemock:latest
That’s it. Seriously, we’re done. But let’s take a moment and explain what we did.
First of all, the dockerfile. It contains all the info for your container and, in our case, states the following:
- “FROM rodolpheche/wiremock“: don’t begin from an empty environment; instead, use the image named “wiremock” from account “rodolpheche“, who has already created and published a suitable docker configuration (thanks!)
- The two “ADD” lines tell it to add (duh) files into the filesystem of the container
- The “CMD” tells the container what to do when it starts. In our case, it runs the java package of wiremock, passing a few command line options, like –global-response-templating
Now the docker commands.
- The “docker image build” builds the image, i.e. creates the docker file system and stores the configuration. It gives it a name (graubfinancemock) and a version (1.0). A version is just a string; it could also be, say, 1.0-alpha, 2.1-RC2, 4.2.1 and so on.
- The “docker container run”, obviously, runs the image. The important thing here is the “–publish 80:8080”. By default, the wiremock server listens to port 8080. So here we instruct docker to map port 80 (visible from the world) to port 8080 (inside the docker container). That’s why we can use the url http://localhost/servicehealth and not http://localhost:8080/servicehealth .
- The last this is to publish the image. You need to login, obviously, and then you have to tag the image. You can assign as many tags as you want, so you can e.g. publish to many repositories. The format is REPOSITORY/IMAGE:VERSION. In docker hub the repo name is your username, but it can be different in private repositories. After tagging, you push the tag, which uploads the image.
Note that apart from the normal version (graubfinancemock:1.0) we also tag the image as latest (graubfinancemock:latest). This way when using the image we won’t need to update the version every time we upload a new one; we’ll just say “get the latest”.
But be careful here: if you build a service -forget our mock for a minute, let’s say we’re building an actual service- and people are using your image as :latest, they might unwillingly jump to an incompatible version with breaking changes (say, from 1.x to 2.0). So it’s a much safer strategy to tag your images as :1.0-latest, :2.0-latest etc instead of just :latest. This way, consumers are fairly certain that they only get non-breaking changes.
Private repositories are out of scope for this post, but in an enterprise setting you’ll probably need them; you usually don’t want the whole world to be able to use your container images. Creating a private repo is not hard, but it’s not free anymore. The easiest ways to do that is in Dockerhub itself or in Azure, where it’s called a container registry. Using it, though, is exactly the same as a public one. If it’s not on docker hub, you just have to prefix the tag with the repo address (see “Now the new feature!” in this post).
So now we have our docker configuration. Ready to ship?
2 thoughts on “Design by contract Tutorial, part 3/6: [Docker] Mock your interfaces using Swagger, Wiremock, Docker, Azure Devops, Terraform and Azure”