UPDATED – Read below!
So while this doesn’t technically involve Sitecore, it’s been super helpful so far when working with some of the docker efforts I’ve been putting forward setting up Identity Server as well as Horizons. Those are still in the works though, so hold tight.
The problem I’d been running into for those came down to the shenanigans with the Uri you had to use. I get that it works perfectly fine to map your port 80 on CM to 44001, use localhost, and all that jazz. Seriously ok stuff. Problem I was having is that in order to get Identity Server working, you had to have a consistent name for when to send the token request and where to send the browser. If you used http://localhost, the request never left the CM box. If you used http://identity, your local browser didn’t know what the hell you were talking about. It was a bit of conundrum.
One solution was to add a hosts file entry like so:
127.0.0.1 identity
Alright, easy enough. But you still had to jack with the whole port thing. And I took a step back and thought “Is this the best way?”
Is this the best way?
Me, in my head
Maybe it isn’t. I dunno. Again, I’m relatively new to docker. So there’s that. I pinged a couple other peeps. Joost Meijles mentioned to me that there was this fancy NPM tool out there called Whales Names which automatically updates your hosts file for you.
That concept kinda blew my mind. Something that listened to docker and did something besides container/image management. Neat! I got it downloaded, ran it and it did things. Some of them great. Others… like installing node and npm..eh. And having to run manually when doing container spin up and down…yeah meh.
After a quick chat with Per Bering, who was also not so thrilled about the thought of having to run node, he recommended I check out something called Windows Hosts Writer. It was essentially a docker image built on .net core that did the same thing. It was a docker container, updating your hosts file with info about other docker containers.
That concept really baked my noodle. I had to try it out. It wasn’t too tough to get things going. I snagged it and ran it. Conceptually it was pretty neat: It listened for connect/disconnect messages from the docker daemon, from a named pipe mapped in through a volume share. (You can map more than file folders, kiddos!) It then updated a file in the container’s folder C:\driversetc\hosts. Except you mapped that to your local C:\windows\system32\drivers\etc\. Interesting indeed!
There were some issues, unfortunately. First, the hosts file entry didn’t have any of the aliases for the container. That was a little clunky. So I forked the repo, and went from there. A couple updates here, and a couple updates there…it was looking better. Not perfect, but better. There was still a problem of running the container on its own. I didn’t love this thought, honestly. If I’m using docker compose to spin things up, why can’t I add it there? I can. And I did. And that made some more issues. First, it was not always the first container to spin up. That meant it wouldn’t be listening for the spin ups before those containers spun up. Also if it stopped first, you’d have some residual junk left in your hosts file. That’s also nasty.
So I did what any developer would do. I rewrote 98% of it. Here’s a list of changes:
- No longer based on events. Having to update the hosts file every time an container started and stopped could end up causing a write fail on the hosts file. That’s not good. The system now runs a timer every five seconds to query the API. Any containers matching the network are added to the dictionary and then written to the hosts file once. Much smoother
- Has a happy cleanup. Windows containers on Windows tend to do derpy things at shutdown. There’s a couple .net core events that get raised on shutdown. They don’t work. I had to snag some old DllImports and use them instead. The good news is that you will be left with a clean hosts file at the end of things, since the stop commands handle correctly here
- Updated the whole thing to run on .net core 3.1. This sized the image down a little bit, which is always nice. It also uses the runtime, not sdk image, which again..smaller.
- Added some other environment configurations in. You can do per-session hosts entries, if you want to run more than one instance at at time. By default, it’s empty, and that’s ok.
- The network you listen to is configurable via environment as well. Useful if you’re in docker compose and it uses ‘docker_default’ rather than ‘nat’
- Added some better logging for the world to see. Think some of it gets eaten from a threading issue, but you should be able to see most/all of it.
So yeah, it was pretty fun. Learned a bit about Docker.DotNet, some about Docker Hub, and some about Github’s Package Repo (which didn’t do what I wanted it to, and deleting packages is gross). Anyway, you can get the image here: https://hub.docker.com/r/rahnemann/windows-hosts-writer manually. It doesn’t have anything Sitecore in it, so it should be good to host publically.
Using it in a docker compose file is even easier:
monitor:
image: rahnemann/windows-hosts-writer:1.1
volumes:
- C:/windows/system32/drivers/etc:C:\driversetc
- source: '\\.\pipe\docker_engine'
target: '\\.\pipe\docker_engine'
type: npipe
environment:
- network=docker_default
Note: The above snippet will target windows version 1909. Read the update at the end on how to target other version such as 1903 and 1809.
Just slap that bit to the services section of your yml and you’re good to go. Literally that easy. It’ll snag the image from Docker Hub and away you go.
Your hosts file should have some stuff like this in there, when things are running:
172.18.218.122 96b09a134df0 cm #96b09a134df0cc189d18107be093316fa44060b51a0ce02aba288cf7950144e5 by whw
172.18.208.220 038589aad6e4 xconnect-processingengine #038589aad6e4f11f4460e93df7c234608bfb5811a98ea1f89a04de56603a3c06 by whw
172.18.217.224 ae9ac90d0391 xconnect-indexworker #ae9ac90d0391a19b54da780334bcb25e796daf7bbefaf7208a1d0003f24b6930 by whw
172.18.217.143 080e4303475b identity #080e4303475b70ca7a1fb3aba63089a3d63d6584da7ad172df4a5eb614a4e213 by whw
172.18.215.141 8df4a2636bab sql #8df4a2636bab8a1efb7822d896b13519b0d3600ea30303b4bda6ad245d243151 by whw
172.18.211.200 4a68d0c07849 solr #4a68d0c078492a48a8b8aa948fa0f72a0d48805c80fbe140d95d74f919cdc48f by whw
172.18.221.203 e4992c8ecb5c monitor #e4992c8ecb5cc19c7668435533c9885a26208e47426f75be55e482384f1ba19c by whw
That means you’ll be able to access your containers with ‘http://cm’ and ‘http://identity’ without any ports specified. Some say this is cheating, but it feels ok to me. Maybe that’s what cheaters say.
You can view the code here: https://github.com/RAhnemann/windows-hosts-writer. I also created a Dockerfile in there for a quick image build, if you wanted to do it on your own. That’s all in the /deploy folder. It’s pretty simple as far as Dockerfiles go:
ARG BASE_IMAGE
FROM $BASE_IMAGE
COPY ./app ./app
WORKDIR /app
USER ContainerAdministrator
ENTRYPOINT ["dotnet", "windows-hosts-writer.dll"]
Copy the app folder, start the dll and run it in the app folder. Like butter, peeps.
Again, special thanks go Per and Joost for the direction on this. Also a shout out to Michael West for being a legit beta tester and always finding a nice way to say “your crap doesn’t work yet”
Update: Thanks to Mr. West for pointing out I completely missed providing support for all non-1909 versions. This has been fixed. You can use the following format to target previous OS versions:
monitor:
image: rahnemann/windows-hosts-writer:1.1-nanoserver-${NANOSERVER_VERSION}
volumes:
- C:/windows/system32/drivers/etc:C:\driversetc
- source: '\\.\pipe\docker_engine'
target: '\\.\pipe\docker_engine'
type: npipe
environment:
- network=docker_default
Update 2: Version 2.0 has been released! Read more about it here.
[…] Edited to add: Yes, there are other ways! On Twitter Reto Hugi pointed me at this interesting post by Rob Ahnemann, which takes another approach: Using another container to dynamically rewrite your hosts file. […]