Networking

Service Networking for Containers

Overview

In Cloud 66, your services run inside containers. For a service to be available to anything outside its own container, including public internet access, we need a bridge between the container's internal port and an "outside" port.

This is not limited to HTTP or web traffic. The same concepts apply if your container serves non-HTTP traffic (like web sockets, DB containers or custom TCP / UDP traffic).

Port mapping is a small (but important) part of a core system that underpins container management - service networking. If you need an introduction to the concept of Service Networking, you can find one here.

This guide also covers more advanced configurations like using Non-HTTP ports, mapping multiple ports and traffic matching.

Defining 'Outside'

In this document, "outside" is used for any client of your service that's not inside the container. This includes your other services on different nodes.

Introduction to mapping container ports

What you'll need

Before you start, please check you have the following:

  • A Cloud 66 Account — If you don't already have one, sign up for a Cloud 66 account. Your first server is free, no credit card required.
  • An existing containerized application set up — To make the most of this tutorial you need to have an app already set up in Cloud 66. Follow our Getting Started guide if you're not sure how to do this.

Demo application

This tutorial uses the simple visit counter application we've supplied on Github as a working example.

Mapping container ports

When we set up our demo-app service we configured our ports so that our internal port 5000 was mapped to the public port 80.

Now imagine that your app has evolved to offer secure web (SSL / TLS) access as well as standard web access. TLS traffic typically flows over port 443, so we need to add this to the port mapping for our application.

There are two ways to do this:

  • Using the standard edit service interface
  • Directly modifying the service.yml for your application (this is only recommended for advanced users)

You can also read our guide to using service.yml for more help.

Editing via the UI

To edit your ports using the standard Cloud 66 user interface:

  1. Log into your Dashboard and open your application
  2. Click on Application in the left-hand nav
  3. In the main Services panel, click on the Edit service icon next to the service you wish to configure. This will open a panel on the left-hand side of your screen.
  4. Click the Network & Storage tab
  5. Edit the ports as needed and then click Save Service

Testing your changes

In order for these new settings to be rolled out to your service, you must click the green Apply button (above the Services panel) and then redeploy your application by clicking the Deploy button.

Set up SSL properly

If you actually need HTTPS traffic to be available to the outside world (not just as a demo) you will also need to set up SSL certificates for your application.

Editing config files directly

Cloud 66 uses a YAML file called service.yml to define each service inside your application(s). You can edit the content of this file directly using the Dashboard in two ways:

  1. Via the Services UI, using the left-hand panel we described above - but click the YAML tab instead of Network & Storage
  2. Via the Configuration Files interface

Note that with method 1 you are only editing the section of service.yml specific to your context. So in this case you would be editing the ports section of your service.yml. To edit the file as a whole, you'll need to use method 2.

Advanced service network configuration

This section covers more complex and advanced cases of service networking for containerized applications. If you've never configured a containerized service before, consider following our tutorial on port mapping first.

If you need an introduction to the concept of Service Networking, you can find one here.

Read our guide to using service.yml for more help on customizing your service configuration.

Non-HTTP ports (TCP and UDP)

If your application does not use HTTP traffic you can map ports by specifying the protocol (TCP or UDP).

Let's imagine we have a service that listens on port 5454 on UDP and we would like to make it available to the outside world on port 111.

To achieve this via the edit service interface:

  1. Log into your Dashboard and open your application
  2. Click on Application in the left-hand nav
  3. In the main Services panel, click on the Edit service icon next to the service you wish to configure. This will open a panel on the left-hand side of your screen.
  4. Click on the YAML tab in the panel
  5. Change Container to 5454
  6. Delete any lines for HTTP and HTTPS (unless your service needs them)
  7. Add a new line: udp:111
  8. Click Save Service
  9. Apply the change to the service by clicking the green Apply button (above the Services panel)
  10. Redeploy your application to roll out the change

If you'd prefer to make these changes directly in the (full) service.yml the result would look similar to this:

services:
    my_service:
        ports:
          - container: 5454
            udp: 111

In the example below, our service listens to TCP port 8787 and we want to make it available on port 9000 to the outside world:

services:
    my_service:
        ports:
          - container: 8787
            tcp: 9000

Note that you don't need to set the protocol for the container port - that is defined by the service itself. By specifying the protocol of the HTTP Port you're ensuring that requests that reach the container are using the same networking protocol as the service itself.

Mapping multiple ports

Some services listen to multiple ports. An example is InfluxDB which listens to different ports for queries and admin controls. You can map these relationships using an array in the service.yml. For example:

services:
    my_service:
        ports:
          - container: 8787
            tcp: 9000
          - container: 8788
            tcp: 9001

Examples of default ports

Some example of default ports used by popular programming frameworks or application servers:

ApplicationDefault Port
Rack (webrick)3000
Rack (unicorn, thin, puma)9292
Node (Express)3000
Java (Play)9000
RethinkDB8080
InfluxDB8083, 8086, 8090, 8099
Python (Django)8000

Traffic matching

The traffic_matches option allows you to route incoming traffic to different services based on the incoming domain name. You can specify an array of domains (as strings) to match to your service.

In the following example, if traffic comes in on app.your_domain.com or www.anotherdomain.com on this service port, then traffic will automatically get routed to my-service.

services:
  my-service:
    traffic_matches: ["app.your_domain.com", "www.anotherdomain.com"]

This option also allows you to have multiple services listening on the same port (port 80 for example) as long as they have different rules for matching server names. For example:

services:
  my-first-service:
    traffic_matches: ["app.your_domain.com", "www.anotherdomain.com"]
    ports:
    - container: 5000
      http: 80
  my-second-service:
    traffic_matches: ["app.third_domain.com", "fourthdomain.com"]
    ports:
    - container: 3000
      http: 80

Managing traffic matching via the Dashboard

You can also add and update traffic matching via the dashboard. To edit an existing service:

  1. Log into your Dashboard and open your application
  2. Click on Application in the left-hand nav
  3. In the main Services panel, click on the Edit service icon next to the service you wish to configure. This will open a panel on the left-hand side of your screen.
  4. Click the Network & Storage tab (at the top)
  5. Add or update (or remove) your domain matching strings
  6. Click Save Service
  7. Apply the change to the service by clicking the green Apply button (above the Services panel)
  8. Redeploy your application to roll out the change

Using traffic matches to reroute all traffic

The traffic_matches option can also be used to ensure that any and all traffic hitting your servers is routed to a specific service. To do this, add traffic_matches to that service and set it to match "_" (underscore). This is will route any traffic that hits your servers to this service. For example:

    services:
        <service_name>:
            traffic_matches: ["_"]

Be cautious with this approach as it is effectively a global setting and may disrupt your other services if there are any conflicts.

DNS Behaviour

The dns_behaviour directive allows you to change the default behavior of returned DNS addresses of different versions. As outlined above, ElasticDNS always try to return the version of the container that has the same version of the caller. You can change this behavior by setting dns_behaviour value to non-versioned, in which case ElasticDNS will return the address of containers with the latest version.

Load Balancing

You can change the container network load balancing method with the load_balancing directive. The accepted values are roundrobin, sticky and closest, and the default value is roundrobin which return the list of container's IP for the requested service in roundrobin. If you choose the sticky option, you will get the last IP you got (if you request after 1 minute you may get a new IP). If you choose the closest option, you will get the list of container's IP that exists on caller server (it will return all available IPs if there is no container of the requested service on caller server).

Previous
Filtering traffic to your app