Search code examples
azureazure-service-fabricazure-service-fabric-mesh

Exposing multiple services in Service Fabric Mesh


I am trying to expose two services (Web API and Chat Bot), which are opening the same ports internally through a Service Fabric Mesh Network's Ingress Controller.

Running the definition below always lets one of the two services fail.

What's unclear to me:

  1. Is that because they are both opening the same ports (80 and 443) internally?
  2. Is that generally a bad idea and I should use a reverse-proxy like NGINX?
  3. Can I get two different IP addresses fot the two services?

File:

{
  "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "apiVersion": "2018-07-01-preview",
      "name": "contosomaintenance",
      "type": "Microsoft.ServiceFabricMesh/applications",
      "location": "westeurope",
      "dependsOn": [
        "Microsoft.ServiceFabricMesh/networks/contosomaintenance-network"
      ],
      "properties": {
        "services": [
          {
            "name": "contosomaintenance-api",
            "properties": {
              "description": "Contoso Maintenance REST API",
              "osType": "Linux",
              "codePackages": [
                {
                  "name": "contosomaintenance-api",
                  "image": "robinmanuelthiel/contosomaintenance-api:latest",
                  "endpoints": [
                    {
                      "name": "http",
                      "port": 80
                    },
                    {
                      "name": "https",
                      "port": 443
                    }
                  ],
                  "resources": {
                    "requests": {
                      "cpu": "0.5",
                      "memoryInGB": "1"
                    }
                  }
                }
              ],
              "replicaCount": "1",
              "networkRefs": [
                {
                  "name": "[resourceId('Microsoft.ServiceFabricMesh/networks', 'contosomaintenance-network')]"
                }
              ]
            }
          },
          {
            "name": "contosomaintenance-bot",
            "properties": {
              "description": "Contoso Maintenance Chat Bot",
              "osType": "Linux",
              "codePackages": [
                {
                  "name": "contosomaintenance-bot",
                  "image": "robinmanuelthiel/contosomaintenance-bot:latest",
                  "endpoints": [
                    {
                      "name": "http",
                      "port": 80
                    },
                    {
                      "name": "https",
                      "port": 443
                    }
                  ],
                  "resources": {
                    "requests": {
                      "cpu": "0.5",
                      "memoryInGB": "1"
                    }
                  }
                }
              ],
              "replicaCount": "1",
              "networkRefs": [
                {
                  "name": "[resourceId('Microsoft.ServiceFabricMesh/networks', 'contosomaintenance-network')]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2018-07-01-preview",
      "name": "contosomaintenance-network",
      "type": "Microsoft.ServiceFabricMesh/networks",
      "location": "westeurope",
      "dependsOn": [],
      "properties": {
        "description": "Contoso Maintenance Network",
        "addressPrefix": "10.0.0.0/22",
        "ingressConfig": {
          "layer4": [
            {
              "name": "contosomaintenance-api-ingress-http",
              "publicPort": "20001",
              "applicationName": "contosomaintenance",
              "serviceName": "contosomaintenance-api",
              "endpointName": "http"
            },
            {
              "name": "contosomaintenance-api-ingress-bot",
              "publicPort": "20002",
              "applicationName": "contosomaintenance",
              "serviceName": "contosomaintenance-bot",
              "endpointName": "http"
            }
          ]
        }
      }
    }
  ]
}

Solution

  • Update 2018-12-10

    The new ApiVersion has been released(2018-09-01-preview) and the new way of exposing Services is by using the Gateway resource. More information can be found on this github thread and this docs.

    This is a snippet for a gateway(only) exposing two services within the same application:

    {
      "apiVersion": "2018-09-01-preview",
      "name": "helloWorldGateway",
      "type": "Microsoft.ServiceFabricMesh/gateways",
      "location": "[parameters('location')]",
      "dependsOn": [
        "Microsoft.ServiceFabricMesh/networks/helloWorldNetwork"
      ],
      "properties": {
        "description": "Service Fabric Mesh Gateway for HelloWorld sample.",
        "sourceNetwork": {
          "name": "Open"
        },
        "destinationNetwork": {
          "name": "[resourceId('Microsoft.ServiceFabricMesh/networks', 'helloWorldNetwork')]"
        },
        "http": [
          {
            "name": "web",
            "port": 81,
            "hosts": [
              {
                "name": "*",
                "routes": [
                  {
                    "name":  "helloRoute",
                    "match": {
                      "path": {
                        "value": "/",
                        "rewrite": "/",
                        "type": "Prefix"
                      }
                    },
                    "destination": {
                      "applicationName": "helloWorldApp",
                      "serviceName": "helloWorldService",
                      "endpointName": "helloWorldListener"
                    }
                  }
                ]
              }
            ]
          },
          {
            "name": "kuard",
            "port": 82,
            "hosts": [
              {
                "name": "*",
                "routes": [
                  {
                    "name":  "kuardRoute",
                    "match": {
                      "path": {
                        "value": "/",
                        "rewrite": "/",
                        "type": "Prefix"
                      }
                    },
                    "destination": {
                      "applicationName": "helloWorldApp",
                      "serviceName": "kuardService",
                      "endpointName": "kuardListener"
                    }
                  }
                ]
              }
            ]
          }
        ],
        "tcp": [
          {
            "name": "web",
            "port": 80,
            "destination": {
              "applicationName": "helloWorldApp",
              "serviceName": "helloWorldService",
              "endpointName": "helloWorldListener"
            }
          },
          {
            "name": "kuard",
            "port": 8080,
            "destination": {
              "applicationName": "helloWorldApp",
              "serviceName": "kuardService",
              "endpointName": "kuardListener"
            }
          }
        ]
      }
    }
    

    Notes:

    • The application is the same helloWorld sample with an extra service
    • The gateway has been modified to expose different ports via TCP and HTTP
    • Is not possible to expose services via network anymore(as noted in the original answer)

    Original Answer

    Currently there are two big limitations with Networks:

    • One network per application: You can't have one application in two networks. source
    • One network ingress per service: When you define the ingress with multiple rules targeting multiple services, only one of them will work properly, even though the deployment succeed in most cases without warning. source

    These are public preview limitations, maybe fixed on GA.

    In this case, if you need to expose two services your alternatives are:

    • Create two networks and two applications: Each application with individual services get deployed on their own networks, each service will have different IPs.
    • Create a proxy service: Using solutions like NGINX to receive all connections and route the requests internally to apropriate services.
    • Use the gateway resource: SF Mesh will release soon a gateway service based on envoy, when available will be the best solution for this scenario, it will work very similar to NGINX approach above, but managed by Azure, it is not available yet but will be released soon.