Configure a route extension

Service Extensions enables supported Application Load Balancers to use plugins or send callouts to backend services to insert custom processing in the processing path. Route extensions run in the request processing path when the load balancer receives request headers and before it evaluates the URL map. This page describes how to configure route extensions.

For an overview about Application Load Balancer extensions, see Cloud Load Balancing extensions overview.

A route extension for an Application Load Balancer points to the following resources:

  • A forwarding rule to attach to
  • A plugin or a callout backend service whose backends run the ext_proc gRPC API

A route extension groups related extension services into a chain. You can configure both plugins and callouts in the same extension chain. The extension chain selects the traffic to act on by using Common Expression Language (CEL) match conditions. The load balancer evaluates a request against match conditions for a chain in a sequential manner. When a request matches the conditions defined by a chain, all extensions in the chain act on the request. Only one chain matches a given request.

The extension references the load balancer forwarding rule to attach to. After you configure the resource, the load balancer starts sending matching requests to extension services.

For information about the limits related to Application Load Balancer extensions, see the Quotas and limits page.

Configure using plugins

This section uses an example to show you how to configure a route extension by using a plugin that rewrites the :host request header to service-extensions.com when the path matches /extensions. The earlier host and the newly configured host are mapped to backend services in different regions, which demonstrates the routing behavior.

All extension resources that reference a given plugin must be of the same type. The extensions must also have the same load balancing scheme. You can't configure Cloud Load Balancing extensions with plugins that are already used in Media CDN extensions.

Before you begin

  1. Create a plugin that contains your custom code.

  2. Create and configure an Application Load Balancer that supports route extension plugins.

    Follow the instructions on the Set up a cross-region internal Application Load Balancer with VM instance group backends page for all steps, except the following:

    • Name the backend service as service-one.
    • Point service-one to a virtual machine (VM) instance in region A.
    • Point gl7-gilb-url-map to service-one by default.
  3. Set up an additional backend service, service-two and point it to a VM in region B.

  4. To the URL map, add a path matcher pointing to service-two. Use the gcloud compute url-maps add-path-matcher command with the following sample values:

    gcloud compute url-maps add-path-matcher gl7-gilb-url-map \
        --path-matcher-name=rewrite-host \
        --default-service=service-two \
        --new-hosts=service-extensions.com \
        --location=global
    
  5. Set up a way to send test requests to your service (for example, by running curl). If you're using an internal load balancer, create a client VM for testing.

Configure a route extension by using a plugin

  1. Check the behavior before an extension is configured.

    1. Verify that a request without an explicit path goes to region A:

      curl FORWARDING_RULE_IP
      

      Replace FORWARDING_RULE_IP with the IP address of the forwarding rule. To find the IP address, use the gcloud compute forwarding-rules describe command.

      The output is similar to the following and indicates that the page is served from a VM in region A:

      Page served from region-A-vm
      
    2. Verify that there is no match for /extensions in the URL map:

      curl FORWARDING_RULE_IP/extensions
      

      Replace FORWARDING_RULE_IP with the IP address of the forwarding rule. To find the IP address, use the gcloud compute forwarding-rules describe command.

      The output indicates that there is no match for /extensions in the URL map. The output is similar to the following:

      <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
      <html><head>
      <title>404 Not Found</title>
      </head><body>
      ...
      
  2. Configure the route extension.

    Console

    1. In the Google Cloud console, go to the Service Extensions page.

      Go to Service Extensions

    2. Click Create extension.

      A wizard opens to guide you through some initial steps.

    3. For the product, select Load Balancing. Then, click Continue.

      A list of supported Application Load Balancers appears.

    4. For the load balancer type, select cross-region internal Application Load Balancer. Then, click Continue.

    5. For the extension type, select Route extensions, and then click Continue.

    6. To open the Create extension form, click Continue.

      In the Create extension form, notice that the preceding selections, which appear at the top of the page, are not editable.

    7. In the Basics section, do the following:

      1. Specify a unique name for the extension.

        The name must start with a lowercase letter followed by up to 62 lowercase letters, numbers, or hyphens and must not end with a hyphen.

      2. Optional: Enter a brief description about the extension by using a maximum of 1,024 characters.

      3. Optional: In the Labels section, click Add label. Then, in the row that appears, do the following:

        • For Key, enter a key name.
        • For Value, enter a value for the key.

        To add more key-value pairs, click Add label. You can add a maximum of 64 key-value pairs.

        For more information about labels, see Create and update labels for projects.

    8. For Forwarding rules, select one or more forwarding rules to associate with the extension—for example, cr-ilb-forwarding-rule.

      Forwarding rules that are already associated with another extension can't be selected and appear disabled.

    9. For Extension chains, add one or more extension chains to execute for a matching request.

      To add an extension chain, do the following, and then click Done:

      • For New extension chain, specify a unique name.

        The name must conform with RFC-1034, use only lowercase letters, numbers, and hyphens, and have a maximum length of 63 characters. Additionally, the first character must be a letter and the last character must be a letter or a number.

      • To match requests for which the extension chain is executed, for Match condition, specify a Common Expression Language (CEL) expression—for example, request.path.startsWith("/extensions").

        For more information about CEL expressions, click Get syntax help or see CEL matcher language reference.

      • Add an extension to execute for a matching request. For route extensions, you can specify only one extension.

        Under Extensions, do the following, and then click Done:

        • For Programmability type, select Plugins.

        • For Extension name, specify a unique name.

          The name must conform with RFC-1034, use only lowercase letters, numbers, and hyphens, and have a maximum length of 63 characters. Additionally, the first character must be a letter and the last a letter or a number.

        • For Plugin, select a plugin created using Service Extensions for the same product and extension type.

        • For Forward headers, click Add header, and then add HTTP headers to forward to the extension (from the client or the backend). If a header isn't specified, all headers are sent.

        • Optional: For Fail open, if you want the extension to fail open, select Enabled. In this case, if the call to the extension fails or times out, request or response processing continues without error. Any subsequent extensions in the extension chain are also executed.

          By default, the Fail open field isn't selected. In this case, if response headers have not been delivered to the downstream client, a generic HTTP 500 status code is returned to the client. If response headers have been delivered, the HTTP stream to the downstream client is reset.

    10. Click Create extension.

    gcloud

    1. Define the plugin in a YAML file and associate it with a global forwarding rule—for example, cr-ilb-forwarding-rule.

      cat >route-plugin.yaml <<EOF
          name: route-ext
          forwardingRules:
          - https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/global/forwardingRules/cr-ilb-forwarding-rule
          loadBalancingScheme: INTERNAL_MANAGED
          extensionChains:
          - name: "chain1"
            matchCondition:
              celExpression: 'request.path.startsWith("/extensions")'
            extensions:
            - name: 'ext1'
              service: projects/PROJECT_ID/locations/global/wasmPlugins/WASM_PLUGIN
              failOpen: false
              supportedEvents:
              - REQUEST_HEADERS
      EOF
      

      Replace the following:

      • PROJECT_ID: the project ID.
      • WASM_PLUGIN: the ID or the fully qualified name of the plugin
    2. Import the route extension. Use the gcloud service-extensions lb-route-extensions import command with the following sample values.

      gcloud service-extensions lb-route-extensions import route-ext \
          --source=route-plugin.yaml \
          --location=global
      

    After a route extension is created, it takes a little time for the new plugin to be distributed across all locations. The time might vary across locations because the plugin isn't delivered to all locations simultaneously.

  3. To verify that the route extension works as expected, use the same curl command:

    curl FORWARDING_RULE_IP/extensions
    

    The output is similar to the following and indicates that the page is served from a VM in region B:

    Page served from region-B-vm
    

    To verify that the plugin runs only for requests with the /extension path prefix, repeat the curl command without a path.

    curl FORWARDING_RULE_IP
    

    The output is similar to the following:

    Page served from region-A-vm
    

Configure using callouts

This section shows you how to configure a route extension by using a callout.

Before you begin

Create the required resources as described in Configure a callout backend service.

Configure a route extension by using a callout

The following example shows how to configure a route extension to call when the path matches /extensions. The route callout server in the callout-vm changes the Host header to service-extensions.com, sets the path to /, and then sends an instruction to the load balancer to recompute the route. The traffic then flows to l7-ilb-backend-service2 instead of l7-ilb-backend-service.

  1. Check if there's a match for /extensions in the URL map.

    1. Run the following curl command against the forwarding rule in the client VM:

      curl FORWARDING_RULE_IP/extensions
      

      Replace FORWARDING_RULE_IP with the IP address of the forwarding rule. To find the IP address, use the gcloud compute forwarding-rules describe command.

      The output indicates that there is no match for /extensions in the URL map. The output is similar to the following:

      <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
      <html><head>
      <title>404 Not Found</title>
      </head><body>
      ...
      
  2. Configure the route extension.

    Console

    1. In the Google Cloud console, go to the Service Extensions page.

      Go to Service Extensions

    2. Click Create extension.

      A wizard opens to guide you through some initial steps.

    3. For the product, select Load Balancing. Then, click Continue.

      A list of supported Application Load Balancers appears.

    4. Select a load balancer type. For regional load balancers, also specify the region. Click Continue.

    5. For the extension type, select Route extensions, and then click Continue.

    6. To open the Create extension form, click Continue.

      In the Create extension form, notice that the preceding selections, which appear at the top of the page, are not editable.

    7. In the Basics section, do the following:

      1. Specify a unique name for the extension.

        The name must start with a lowercase letter followed by up to 62 lowercase letters, numbers, or hyphens and must not end with a hyphen.

      2. Optional: Enter a brief description about the extension by using a maximum of 1,024 characters.

      3. Optional: In the Labels section, click Add label. Then, in the row that appears, do the following:

        • For Key, enter a key name.
        • For Value, enter a value for the key.

        To add more key-value pairs, click Add label. You can add a maximum of 64 key-value pairs.

        For more information about labels, see Create and update labels for projects.

    8. For Forwarding rules, select one or more forwarding rules to associate with the extension—for example, l7-ilb-forwarding-rule.

      Forwarding rules that are already associated with another extension can't be selected and appear disabled.

    9. For Extension chains, add one or more extension chains to execute for a matching request.

      To add an extension chain, do the following, and then click Done.

      • For New extension chain, specify a unique name.

        The name must conform with RFC-1034, use only lowercase letters, numbers, and hyphens, and have a maximum length of 63 characters. Additionally, the first character must be a letter and the last character must be a letter or a number.

      • To match requests for which the extension chain is executed, for Match condition, specify a Common Expression Language (CEL) expression—for example, request.path.startsWith("/extensions").

        For more information about CEL expressions, click Get syntax help or see CEL matcher language reference.

      • Add an extension to execute for a matching request. For route extensions, you can specify only one extension.

        Under Extensions, do the following, and then click Done:

        • For Programmability type, select Callouts.

        • For Extension name, specify a unique name.

          The name must conform with RFC-1034, use only lowercase letters, numbers, and hyphens, and have a maximum length of 63 characters. Additionally, the first character must be a letter and the last a letter or a number.

        • For Authority, enter the authority header from the gRPC request sent from load balancer to the extension service.

        • For Backend service, select a backend service created by following the instructions in Configure a callout backend service.

        • For Timeout, specify a value between 10 and 1000 milliseconds, after which a message on the stream times out while the load balancer is still waiting for a response from the ext_proc service.

        • For Forward headers, click Add header, and then add HTTP headers to forward to the extension (from the client or the backend). If a header isn't specified, all headers are sent.

        • Optional: For Fail open, if you want the extension to fail open, select Enabled. In this case, if the call to the extension fails or times out, request or response processing continues without error. Any subsequent extensions in the extension chain are also executed.

          By default, the Fail open field isn't selected. In this case, if response headers have not been delivered to the downstream client, a generic HTTP 500 status code is returned to the client. If response headers have been delivered, the HTTP stream to the downstream client is reset.

    10. Click Create extension.

    gcloud

    1. Define the callout in a YAML file and associate it with the forwarding rule. Use the sample values provided.

      cat >route.yaml <<EOF
          name: route-ext
          forwardingRules:
          - https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/us-west1/forwardingRules/l7-ilb-forwarding-rule
          loadBalancingScheme: INTERNAL_MANAGED
          metadata: {"fr": "{forwarding_rule_id}", "key2": {"key3":"value"}}
          extensionChains:
          - name: "chain1"
            matchCondition:
              celExpression: 'request.path.startsWith("/extensions")'
            extensions:
            - name: 'ext11'
              authority: ext11.com
              service: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/us-west1/backendServices/l7-ilb-callout-service
              failOpen: false
              timeout: 0.1s
      EOF
      

      Replace PROJECT_ID with the project ID.

      The metadata field in the extension configuration lets you pass any JSON objects from the load balancer to the extension server. The metadata is sent in ProcessingRequest and encoded as protobuf.Struct. Any text within the JSON object that matches the specified forwarding rule ID is replaced with the fully qualified resource URL of the forwarding rule associated with the client request.

    2. Import the route extension. Use the gcloud service-extensions lb-route-extensions import command with the following sample values.

      gcloud service-extensions lb-route-extensions import route-ext \
         --source=route.yaml \
         --location=us-west1
      
  3. Verify that the route extension works as expected. Use the same curl command:

    curl FORWARDING_RULE_IP/extensions
    

    The output indicates that the traffic matched the virtual host service-extensions.com and reached the l7-ilb-backend-service2 service even though the original request did not. The output is similar to the following:

    Page served from second backend service
    

    To validate that the callout is targeting only requests with the /extension prefix, repeat the curl command without the path prefix.

    curl FORWARDING_RULE_IP
    

    The output is similar to the following:

    Page served from: l7-ilb-backend-example-1c7t
    

Limitations for route extensions

  • Cross-project referencing between extensions and the forwarding rule isn't supported.
  • Route extensions don't support HTTP body processing.
  • Route extensions cannot override the processing mode of ext_proc stream.
  • A direct response from the extension to the client isn't supported for route extensions. If your route extension server responds to a processing request with a processing response that contains a direct response, the load balancer ignores the processing response.

What's next