Joe Czucha
Joe Czucha

Reputation: 4295

Finding the next available port with Ansible

I'm using Ansible to deploy a Ruby on Rails application using Puma as a web server. As part of the deployment, the Puma configuration binds to the IP address of the server on port 8080:

bind "tcp://{{ ip_address }}:8080"

This is then used in the nginx vhost config to access the app:

upstream {{ app_name }} {
  server {{ ip_address }}:8080;
}

All of this is working fine. However, I now want to deploy multiple copies of the app (staging, production) onto the same server and obviously having several bindings on 8080 is causing issues so I need to use different ports.

The most simple solution would be to include the port in a group var and then just drop it in when the app is deployed. However, this would require background knowledge of the apps already running on the server and it kind of feels like the deployment should be able to "discover" the port to use.

Instead, I was considering doing some kind of iteration through ports, starting at 8080, and then checking each until one is not being used. netstat -anp | grep 8080 gives a return code 0 if the port is being used so perhaps I could use that command to test (though I'm not sure of how to do the looping bit).

Has anyone come up against this problem before? Is there a more graceful solution that I'm overlooking?

Upvotes: 1

Views: 1614

Answers (1)

Konstantin Suvorov
Konstantin Suvorov

Reputation: 68269

I'd define list of allowed ports and compare it to available ports.

Something like this:

- hosts: myserver
  vars:
    allowed_ports:
      - 80
      - 8200
  tasks:
    - name: Gather occupied tcp v4 ports
      shell: netstat -nlt4 | grep -oP '(?<=0.0.0.0:)(\d+)'
      register: used_ports

    - name: Set bind_port as first available port
      set_fact:
        bind_port: "{{ allowed_ports | difference(used_ports.stdout_lines | map('int') | list) | first | default(0) }}"
      failed_when: bind_port | int == 0

    - name: Show bind port
      debug: var=bind_port

You may want to tune 0.0.0.0 in the regexp if you need to check ports on specific interface.

Upvotes: 3

Related Questions