Design notes on using the Marathon REST API to do discovery - advantageous/lokate-mesos GitHub Wiki

Welcome! We actually wrote a Mesos discovery with an early version of Lokate (called something else and internal). When we refactored and came up with the URI only approach, we dropped Mesos discovery as we stopped using it. Now we need it again. We were using mesos-consul and then doing DNS SRV records for service discovery. Then we switched to a new platform and decided not to use mesos-consul (for now anyway), and then ran into this issue with mesos-dns.

Marathon documents its REST API here (marathon REST API).

We want a Loakte URI query that looks something like this:

Search by container port

# Default host
discovery:marathon:///eventbus.sample-dcos3?containerPort=8081 
# Specify host
discovery:marathon://marathon.mesos:8080/eventbus.sample-dcos3?containerPort=8081

Search by port name

# Default host
discovery:marathon:///eventbus.sample-dcos3?portName=eventbus
# Specify host
discovery:marathon://marathon.mesos:8080/eventbus.sample-dcos3?portName=eventbus

Search by port index

# Default host
discovery:marathon:///eventbus.sample-dcos3?portIndex=0
# Specify host
discovery:marathon://marathon.mesos:8080/eventbus.sample-dcos3?portIndex=0

Search by port (servicePort)

# Default host
discovery:marathon:///eventbus.sample-dcos3?servicePort=10101
# Specify host
discovery:marathon://marathon.mesos:8080/eventbus.sample-dcos3?servicePort=10101

All of this should be doable using the following Mesos REST-API:

$ curl marathon.mesos:8080/v2/apps/sample-dcos3 | jq .

Which gives the following output: (Edited to only show the parts we need for this)

{
  "app": {
    "id": "/sample-dcos3",
    "instances": 3,
    "ports": [
      10101,
      10102
    ],
    "portDefinitions": [
      {
        "port": 10101,
        "protocol": "tcp",
        "name": "eventbus",
        "labels": {}
      },
      {
        "port": 10102,
        "protocol": "tcp",
        "name": "admin",
        "labels": {}
      }
    ],
    "container": {
      "type": "DOCKER",
      "volumes": [],
      "docker": {
        "image": "advantageous/run-java-zip:0.2",
        "network": "BRIDGE",
        "portMappings": [
          {
            "containerPort": 8081,
            "hostPort": 0,
            "servicePort": 10101,
            "protocol": "tcp",
            "labels": {}
          },
          {
            "containerPort": 9090,
            "hostPort": 0,
            "servicePort": 10102,
            "protocol": "tcp",
            "labels": {}
          }
        ],
        "privileged": false,
        "parameters": [],
        "forcePullImage": false
      }
    }
    ],
    "version": "2016-08-19T20:03:20.797Z",
    "tasks": [
      {
        "id": "sample-dcos3.fa3d20ff-6647-11e6-8de6-ea046373ee46",
        "host": "10.16.204.94",
        "ports": [
          19771,
          19772
        ]
        ]
      },
      {
        "id": "sample-dcos3.fa680191-6647-11e6-8de6-ea046373ee46",
        "slaveId": "6a1f41e3-331f-4537-ac95-441184a22f5d-S0",
        "host": "10.16.204.95",
        "ports": [
          14125,
          14126
        ]

        ],
        "appId": "/sample-dcos3",
        "healthCheckResults": [
          {
            "alive": true,

          }
        ]
      },
...
}

Health

Note we check to see if there are health checks, and then we only return a task address if healthCheckResults.alive=true