Defining Routes

In Apcera, a route maps a URL (often referred to as an endpoint) to an app. For example, an app might listen for traffic on http://myapp.example.com or tcp://1.2.3.4:123. Apcera load balances and routes traffic received at a given address to the set of jobs listening for that traffic. Routes can be for HTTP or TCP services.

By default, when you create a route of type HTTP, the route endpoint is reachable using over HTTP or HTTPS. You can optionally enforce HTTPS on a route so that clients who attempt to access the route over http:// are redirected to the https:// endpoint. See Enforcing HTTPS on Routes.

The following diagram illustrates a route into a job, and shows the difference between a route and a service binding:

drawing

This section explains how to implement application routes, including:

Default Routes and Ports

By default, when you create an application with apc app create, a default HTTP(S) route is created for you and an available port is exposed on the application (see About Default Port Assignment).

You can disable default route generation using the --disable-routes option (see Disabling Default Route and Port Generation). If you are not deploying a web app, it is recommended that you disable route generation. You can update the app and add a route later if needed.

As described below, the default route scheme is changed for Apcera release 504. In addition, you can customize the cluster-name and create vanity URLs. If you are not using this version of Apcera, refer to the legacy default route section.

Current default routes

Beginning with Apcera version 504, Apcera implements a new scheme for default route generation, as well as new policy requirements and the option to define a default route suffix for custom route URLs.

Default route scheme

Default routes are now constructed using the following scheme:

appname-6chars.cluster-name

Where:

  • appname is the name of the application exposing the route. If the app name contains one or more dots, each dot is removed and NOT replaced with dash or space.

  • Dash delimiter (-) is used to separate the appname from the 6 character random string.

  • 6chars is a string of 6 randomly generated alphanumeric characters comprising letters a to z (lower case), numbers 0 to 9, or both.

  • cluster-name is the domain name of the cluster. See default route suffix below for customizing.

Route policy requirements

Both default and custom route URLs can now be used by multiple apps. If you want to use a route that is already in use by another app, to prevent eavesdropping on the route, you must have policy permission (permit update) for each job. If there is more than one app using the route, you must have permit update for each job that uses that route.

Default route suffix

If you want to use the default route scheme but customize the cluster-name value, you can use policy to define a default route suffix, that is, the domain name portion of the route.

To do this you use the new defaultRouteSuffix policy claim type for job resources to override the default route suffix. This claim instructs the system to use this value instead of what the cluster domain is. Note that this only applies to default routes, not custom routes.

For example, if your cluster-name is cluster.example.com, you can set foo.bar.com as the route suffix using the following policy on the host job:

on job::/sandbox/user {
  { defaultRouteSuffix foo.bar.com }

}

Or, if you wanted to template one of the tokens in the default route suffix, specify it with quotes. For example:

on job::/some/team/[ldapgroup]/public {
  if (LDAP->group == [ldapgroup])
    { permit all defaultRouteSuffix "[ldapgroup].route.example.com" }
}

Legacy default routes

If you are using Apcera version 449 or earlier, default route URLs are constructed from the application name, the current namespace (or one specified by --namespace option) in reverse namespace order, and cluster domain (<app-name>.<reverse-namespace>.<domain>). For example, suppose your current namespace is /sandbox/jane and you are targeting the try.apcera.net Apcera cluster. The following command creates an application named my-app on the target cluster:

apc app create mynode sample-apps/example-node-hello
Deploy path [/src/sample-apps/example-node-hello]:
Instances [1]:
Memory [256MiB]:
╭───────────────────────────────────────────────────────────────╮
│                     Application Settings                      │
├───────────────────┬───────────────────────────────────────────┤
│              FQN: │ job::/sandbox/admin::mynode               │
│        Directory: │ /src/sample-apps/example-node-hello       │
│        Instances: │ 1                                         │
│          Restart: │ always                                    │
│ Staging Pipeline: │ (will be auto-detected)                   │
│              CPU: │ 0ms/s (uncapped)                          │
│           Memory: │ 256MiB                                    │
│             Disk: │ 1GiB                                      │
│           NetMin: │ 5Mbps                                     │
│           Netmax: │ 0Mbps (uncapped)                          │
│         Route(s): │ auto                                      │
│  Startup Timeout: │ 30 (seconds)                              │
│     Stop Timeout: │ 5 (seconds)                               │
╰───────────────────┴───────────────────────────────────────────╯

In the application settings above note that the Route(s) field is set to my-app.jane.sandbox.try.apcera.net, where your application will be accessible.

You can also specify the namespace in which to create an application using the global --namespace flag. For instance, running the following command would result in the route my-app.test.dev.try.apcera.net being assigned to the application:

apc app create my-app --namespace /dev/test

You can assign a custom route (or routes) to an application with the --routes option when calling apc app create, for example:

$ apc app create myapp --routes coolapp.apcera.com

To associate multiple routes with a single application, pass a comma-delimited list of routes:

$ apc app create myapp --routes coolapp.apcera.com, coolapp2.apcera.com

You can also add a route to an application after it's created using the apc route add command.

When choosing a route name, keep in mind the following naming conventions:

  • A route name cannot use forbidden characters, per RFC 3896. These include: $, &, +, ,, /, :, ,, ;, =, ?, and @.
  • The route name must be unique across the cluster. (The default route naming convention enforces this requirement if you create the app in your own namespace or specify your own namespace, such as /sandbox/user.)
  • As a best practice, use policy to require a unique route name for your environment, for example:

      route::/http/io/skanderna/sandbox/[name]
      {
          if (job nameMatch "job::/sandbox/[name]")
          {
              permit map
          }
      }
    

    Refer to the route policy examples for more information.

About Default Port Assignment

By default, applications have a port exposed that is chosen at runtime and exposed via the "PORT" environment variable. If nothing is listening at that port, your application will fail to start. If your app is not a web app and is
intended to have no listening ports, or if you would like to manually select which ports are exposed, you can use the '–disable-routes' when creating your app. You can later manually expose ports on your application using the apc app update command. See Disabling Default Route and Port Generation for more information.

To manually expose a port on a application, use the apc app update command's --port-add option, for example:

apc app update your-app --port-add 4567

By default, if your application is not listening on the specified port then the application will fail to start. You can override this behavior by including the --optional flag when adding the port:

apc app update your-app --port-add 4567 --optional

Now your application will start properly even if nothing is listening on the specified port.

Disabling Default Route and Port Generation

By default, any app you create is assigned a default HTTP route and a port that's exposed via the PORT environment variable. If the app is not a web app, or otherwise doesn't need a route, you can disable this default route generation and port assignment using the --disable­-routes argument.

apc app create someApp --disable-routes
  • To manually create a route for your application, use the apc route add command (see Adding Routes).
  • To manually expose a port on a application, use the --port-add option to the apc app update command (see About Default Port Assignment).

You can also disable default route generation by including disable_routes: true in your application manifest.

Sharing Routes and Route Weights

Multiple applications can share a route. Apcera automatically balances incoming traffic across apps sharing the same route based upon their route weights. A route's weight define how much traffic is directed to receives.

The weights of all apps on a given route are normalized to total 100%. For example, if a route has associated apps with a weight of 0%, those apps receive the difference between the sum of all non-zero routes and 100%. For example, if app A and app B each have a route of "myapp.example.me" at 45%, while app C has "myapp.example.me" at 0%, app C receives 10% of the traffic.

To manage route weights you use the apc route weight command. To specify a route weight use the --weight <value> to specify a weight for the route. The default weight is 0. See Managing Route Weights for more information.

For an example of using route weighting, see the Blue Green Deployment for Java Apps tutorial.

Enforcing HTTPS on Routes

When you add a route of type http to an application, both HTTP and HTTPS endpoints are opened on the Apcera cluster's router. For example, if you create an application with the HTTP route my-app.example.com, then clients can reach the application using either http://my-app.example.com or https://my-app.example.com. You can optionally enforce HTTPS access on an application route, so only clients that request a route using https:// can access the application.

You can optionally enforce that clients use HTTPS when requesting an application route. There are two ways to do this:

  • Use the https-only flag when creating a route. This enforces HTTPS at the Apcera router, which automatically redirects any requests made to the app route using http:// to its https:// endpoint. See Enforcing HTTPS on the router.
  • Configure your job to redirect HTTP requests to HTTPS based on the value of the Apcera-HTTPS request header. This header's value is set to "on" if the router received the request over HTTPS, otherwise it is an empty string. See Enforcing HTTPS on the job.

The first approach allows the cluster to enforce HTTPS on a per-route basis. The second approach lets the job enforce HTTPS on every request it receives.

Notes:

  • HTTPS connections terminate at the Apcera router; job instances do not receive HTTPS traffic on routes of type http.
  • To create HTTPS routes SSL/TLS must be enabled at the cluster level. Refer to the cluster configuration documentation for details.

Enforcing HTTPS on the router

To force a client to use HTTPS access to access a route, you can use the --https-only (or -ho) flag when creating the route. For example, the following creates an HTTPS-only route for the app myapp on the specified port:

apc route add my-app.example.com --port 1234 --app myapp --http --https-only

You use the same flag when creating an application with the apc app create, apc docker run, or apc app from package commands. Auto-generated routes and any routes added via the --routes parameter are marked as HTTPS-only. For example, the following marks the routes http://app1.example.com and http://app2.example.com as HTTPS-only.

apc app create my-app --routes http://app1.example.com,http://app2.example.com --https-only

In the Web Console, check the Only allow HTTPS option when creating the route (see Managing routes and ports).

In a multi-resource manifest you can add https_only: true to a route definition to enforce HTTPS on the route.

Note that once a route has been created with an HTTPS-only route it cannot be changed to a non-HTTPS-route, and vice-versa. For example, suppose you create an app and assign it an HTTPS-only route:

apc app create app1 -p ~/my-app --routes app.example.com --https-only
...
Success!

If you then tried to add the same route endpoint to another app without the --https-only flag then a https-only flag conflict error is generated:

apc app create app2 -p ~/my-app --routes app.example.com
...
Creating app "app2"... error
Error: error creating job: Route app.example.com https-only flag conflict

Enforcing HTTPS on a job

To enforce HTTPS on a job (rather than on the Apcera router) your job can examine the value of the Apcera-HTTPS request header. This header is injected by the Apcera router before it forwards the request to the job instance. If the original request to the router was made over HTTPS then this header is set to on. If the request was not made over HTTPS then the value of Apcera-HTTPS is an empty string and your application can redirect the request to the route's HTTPS endpoint.

For example, suppose you have an Apcera job that uses NGINX as a front-end. The following NGINX configuration redirects the request if the Apcera-HTTPS request header value is empty:

server {
  listen $PORT;
  root  www;

  if ($http_apcera_https != "on") {
    return 301 https://$host$request_uri;
  }

  location / {
    try_files $uri /index.html?$args;
  }
}

If your job uses Apache as the front-end then the following configuration will accomplish the same thing:

RewriteEngine On
Rewritecond %{HTTP:apcera-https} == "on"
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Note that HTTPS connections are terminated at the Apcera router; jobs receive HTTP traffic, only.

If the Apcera-HTTPS request header is set to "on" then the following additional request headers are added that provide details about the SSL connection:

  • Apcera-SSL-Cipher – Specifies the cipher used in the SSL connection between the router and client.
  • Apcera-SSL-Protocol – Specifies the SSL protocol used in the connection.
  • Apcera-SSL-Session-Id – Session identifier for the SSL connection.
  • Apcera-SSL-Session-Reused – Contains "r" if the SSL session was reused; otherwise contains ".".
  • Apcera-SSL-Server-Name – The hostname that was contacted by the client at the beginning of the SSL handshake process.

Managing Routes

You use the apc route command to manage your cluster's routes. You can add or delete an application's route, show applications that share a particular route. For applications that share a given route, you can also control the proportion of traffic delivered per-route.

Use apc route add -h to view command options for adding a route to an app.

Adding Routes

You use apc route add to add an HTTP or TCP route on an app's exposed port. You can specify the route type explicitly with the --type flag, or by including the type in the route endpoint.

Adding HTTP Routes

The following command adds an HTTP route for "myapp.example.me" to the "myapp" application:

apc route add http://myapp.example.me --app myapp

Equivalently, you can use the --type parameter to specify the route type:

apc route add myapp.example.me --app myapp --type http

To have the API server automatically generate a route endpoint and select an available port on the application, specify auto as the command's second argument:

apc route add auto --app myapp --type http

The endpoint is generated according to the default route scheme.

You can also substitute the --http boolean for --type http, for example:

apc route add myapp.example.me --app myapp --http

If you don't specify a port when adding a route, Apcera selects an available port for you.

You can specify the listening port of an app using the --port flag.

apc route add myapp.example.me --app myapp --http --port 4567

Note that if nothing is listening at the specified port, your application will fail to start.

Note: To create HTTPS routes, HTTPS must be enabled at the cluster level. Refer to the cluster configuration documentation for details.

Adding TCP Routes

You can also use apc route add to add a TCP route for your application. Include the auto keyword to have Apcera select an available TCP route for you. For example, the following command automatically selects an available route for the specified app that's listening on (physical) port number 1999.

apc route add auto --tcp --app slogger --p 1999

You can also specify TCP routes in your application's manifest.

Adding Multiple Routes

To add multiple routes, add each route and port separately, for example:

apc docker run demo --image image/repo --memory 1gb --disk 2gb --allow-egress --no-start
apc route add http://demo.apcera-platform.io --app demo --port 8153 --batch
apc route add http://demo.apcera-platform.io --app demo --port 8154 --batch
apc app start demo

Listing Routes

The apc route list commands lists the endpoints and types (HTTP or TCP) of routes assigned to jobs in the current namespace, and the number of jobs that use each route. For example, the output below shows that the app-route.foo.com route endpoint is being used by two applications and my-route.foo.com is being used by one app:

$ apc route list
Working in "/sandbox/admin"
╭──────┬───────────────────┬──────────────╮
│ Type │ Endpoint          │ # Times Used │
├──────┼───────────────────┼──────────────┤
│ http │ app-route.foo.com │ 2            │
│ http │ my-route2.foo.com │ 1            │
╰──────┴───────────────────┴──────────────╯

To show the FQN and UUID of the jobs assigned to each route, and the weight assigned to each route, include -l command flag. For example, the following shows that /sandbox/admin::app1 and /sandbox/admin::app2 both use the app-route.foo.com route endpoint, while the other route is used by job::/dev::app2:

apc route list -l
╭──────┬───────────────────┬────────┬───────────────────────────┬──────────────────────────────────────╮
│ Type │ Endpoint          │ Weight │ Job FQN                   │ Job UUID                             │
├──────┼───────────────────┼────────┼───────────────────────────┼──────────────────────────────────────┤
│ http │ app-route.foo.com │ auto   │ job::/sandbox/admin::app1 │ 3b0a6209-5dcf-408c-8941-cf9f44295f58 │
│ http │ app-route.foo.com │ auto   │ job::/sandbox/admin::app2 │ 0512b2a3-18a9-4d0e-9a45-717b525921dc │
│ http │ my-route2.foo.com │ auto   │ job::/dev::app2           │ 0512b2a3-18a9-4d0e-9a45-717b525921dc │
╰──────┴───────────────────┴────────┴───────────────────────────┴──────────────────────────────────────╯

You can also use the the apc route show <route-endpoint> command to list what apps are using a route:

apc route show app-route.foo.com
Jobs using route 'app-route.foo.com':
╭──────┬────────────────┬────────╮
│ Name │ Namespace      │ Weight │
├──────┼────────────────┼────────┤
│ app1 │ /sandbox/admin │ auto   │
│ app2 │ /sandbox/admin │ auto   │
╰──────┴────────────────┴────────╯

Managing Route Weights

The apc route weight command updates a route's weight:

apc route weight myapp.example.me --app myapp --weight 50%

Assigning a negative weight value to a route make the route inactive.

apc route weight myapp.example.me --app myapp --weight -10%

Also see Blue-green deployment for Java apps to learn how to use route weights to gradually deploy a new version of an application at the same URL as the existing version.

Control access to routes by client IP

By default, all client traffic to a job's defined routes is allowed access. You can optionally define an access control list (ACL) that allows or denies access to a job's routes based on a the client's IP address. A route ACL is defined by one or more rules, each of which defines an IP range in CIDR notation. When a client makes a request for a job route, the Apcera router compares the client's IP to each rule. Once a match is found, the client is allowed or denied access to the job route, based on the rule's definition. If no match is found, the client is allowed access by default.

To specify client IPs to allow or deny, you use the --client-acl parameter when creating an application with the apc app create/update, apc app from package, apc capsule create, apc docker run, and apc job update commands. This parameter takes a string that consists of one or more rules separated by commas. Each rule is composed of the string "allow" or "deny" followed by an IP range in CIDR notation.

For example, the following defines an ACL for the app named webapp that allows traffic from clients in the 128.66.3.0/24 IP range, and another that denies traffic from clients in the 128.66.0.0/16 IP range.

apc app create webapp --client-acl="allow 128.66.3.0/24, deny 128.66.0.0/16"

When the Apcera router handles a request from a client, it compares the client's IP to each rule, from left to right, until it finds a match. If no match is found, the request is allowed. If a match is found, the request is allowed or denied based on the rule's defined action.

If not specified, the first rule assigned to --client-acl is assumed to be an allow. For instance, the following is equivalent to the rules defined above:

apc app create webapp --client-acl="128.66.3.0/24, deny 128.66.0.0/16"

To create a rule that only allows in a specific IP or range and denies all others, you can add deny 0.0.0.0/0 at the end of the list. For example, the following rule will allow access only to 127.0.0.1.

allow 127.0.0.1/32, deny 0.0.0.0/0

Appending deny 0.0.0.0/0 has the effect of making the rule "opt-in" rather than "opt-out".