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:
- Log into your Dashboard and open your application
- Click on Application in the left-hand nav
- 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.
- Click the Network & Storage tab
- Edit the ports as needed and then click Save Service
Testing your changes
You can test whether this has been properly applied by looking at that the Network column of the Services panel.
If you've followed the steps above correctly, the Network column will list both port 80 and port 443.
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:
- Via the Services UI, using the left-hand panel we described above - but click the YAML tab instead of Network & Storage
- 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:
- Log into your Dashboard and open your application
- Click on Application in the left-hand nav
- 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.
- Click on the YAML tab in the panel
- Change Container to
5454
- Delete any lines for
HTTP
andHTTPS
(unless your service needs them) - Add a new line:
udp:111
- Click Save Service
- Apply the change to the service by clicking the green Apply button (above the Services panel)
- 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:
Application | Default Port |
---|---|
Rack (webrick) | 3000 |
Rack (unicorn, thin, puma) | 9292 |
Node (Express) | 3000 |
Java (Play) | 9000 |
RethinkDB | 8080 |
InfluxDB | 8083, 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:
- Log into your Dashboard and open your application
- Click on Application in the left-hand nav
- 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.
- Click the Network & Storage tab (at the top)
- Add or update (or remove) your domain matching strings
- Click Save Service
- Apply the change to the service by clicking the green Apply button (above the Services panel)
- 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).