jonashackt
jonashackt

Reputation: 14479

How to do a health-check to Spring Boot app running inside Windows Docker Windows Container with Ansible?

I want to provision a Spring Boot app into a Windows Docker Container which is hosted on a Windows Docker Host (which is virtualized on a Mac, but this is another story ;) ) with Ansible. I already successfully used Ansible Windows Modules to provision a Spring Boot app to Windows.

I´am in the final chapter and just wanted to add a health-check at the very end. As outlined in the blogpost without Docker this is easy:

  - name: Wait until our Spring Boot app is up & running
    win_uri:
      url: "http://localhost:8080/health"
      method: GET
    register: result
    until: result.status_code == 200  
    retries: 5
    delay: 5

Now with Docker Windows Containers there´s a known limitation so that you can´t use localhost for now. We have to use the Windows Docker Containers internal Hyper-V IP address (you can see the IP after you ran a docker inspect <yourContainerIdHere> inside the JSON output in NetworkSettings.Networks.nat.IPAddress).

My question is: How can I obtain the Windows Docker Container´s Hyper-V internal IP address, output it inside a debug statement and do a health-check similar to the one I outlined?

Upvotes: 2

Views: 2142

Answers (1)

jonashackt
jonashackt

Reputation: 14479

After a far to long journey to just do a simple health-check I found a solution.

At first we have to obtain the Docker Container´s IP address, which could be easily done on a Powershell with this command:

docker inspect --format '{{ .NetworkSettings.Networks.nat.IPAddress }}' <yourInstanceIdHere>

We just have to use the win_shell module.

But because this uses a Docker templating mechanism, Jinja2 templating doesn´t know, it shouldn´t interpret these command this time. We have to escape the curly braces properly, which is outlined in this so q&a already. You could use one of the suggested solutions:

"{%raw%}"{{ .NetworkSettings.Networks.nat.IPAddress }}"{%endraw%}"

or

"{{'{{'}} .NetworkSettings.Networks.nat.IPAddress {{'}}'}}" - both will work for us here.

Now obtaining the IP address from this output, I tried to just register a result and make the health-check. Sadly this doesn´t work, because the returned stdout and stdout_lines do contain your IP, but also the Docker template again - but this time without the escaping sequence, which will in turn let the task fail (as a comment from Davide Guerri in this so answer already reported).

The following comment from lanwen gave an advice to the rescue: We could pipe the first win_shell output into a temporary textfile container_ip.txt and then - in a second win_shell task - we just read the contents of that file and register an output-variable.

This seems to be easy, again we use win_shell:

win_shell: cat container_ip.txt
register: win_shell_txt_return

But hey, that´s not the whole story -> because on Windows, there are nice carriage return line feeds :), which will pollute our IP address with \r\n at the end and will let our health-check fail again.

But again, there´s help: Ansible has a nice splitlines feature (which is slightly un-documented...) We just have to do it with a trailing [0] to obtain the IP:

"{{ win_shell_txt_return.stdout.splitlines()[0] }}"

Now we are able to do our health-check as we wanted in the first place. Here´s the complete solution:

  - name: Obtain the Docker Container´s internal IP address (because localhost doesn´t work for now https://github.com/docker/for-win/issues/458)
    win_shell: "docker inspect -f {% raw %}'{{ .NetworkSettings.Networks.nat.IPAddress }}' {% endraw %} {{spring_boot_app_name}} {{ '>' }} container_ip.txt"

  - name: Get the Docker Container´s internal IP address from the temporary txt-file (we have to do this because of templating problems, see https://stackoverflow.com/a/32279729/4964553)
    win_shell: cat container_ip.txt
    register: win_shell_txt_return

  - name: Define the IP as variable
    set_fact:
      docker_container_ip: "{{ win_shell_txt_return.stdout.splitlines()[0] }}"

  - debug:
      msg: "Your Docker Container has the internal IP {{ docker_container_ip }} --> Let´s do a health-check against this URI: 'http://{{ docker_container_ip }}:{{spring_boot_app.port}}/{{spring_boot_app.health_url_ending}}'"

  - name: Wait until our Spring Boot app is up & running
    win_uri:
      url: "http://{{ docker_container_ip }}:8080/health"
      method: GET
    register: health_result
    until: health_result.status_code == 200  
    retries: 5
    delay: 5

Upvotes: 3

Related Questions