- Print
- DarkLight
- PDF
A service represents a single data plane proxy. Often this is attached to a deployed application in a sidecar pattern, but it can also standalone, as in the case for edges. Services are denoted by the #Service definition.
Service File
Services are stored in a “service file”. Although services can be written entirely by hand, we highly recommend generating a service with the CLI init command.
Example Service
Here is an example of a service configured for mTLS ingress and mTLS health checks.
// declare the package -- typically the project/namespace name
package tenant
// Import the GSL schemas as alias 'gsl' and import the globals package from the current project
import (
gsl "greymatter.io/gsl/spec/v1"
"tenant.module/greymatter:globals"
)
Myapi: gsl.#Service & {
// Boilerplate used for internal processing
context: Myapi.#NewContext & globals
name: "myApi"
display_name: "My API"
version: "v2.0.2"
description: "An API that is mine"
api_endpoint: "https://\(context.globals.edge_host)/services/\(context.globals.namespace)/\(name)/"
api_spec_endpoint: "https://\(context.globals.edge_host)/services/\(context.globals.namespace)/\(name)/"
business_impact: "low"
owner: "Tenant"
health_options: {
spire: gsl.#SpireUpstream
}
ingress: {
"service-info": gsl.#ServiceInfo
// (name) means replace this parenthesis with the value of name, in this case "myApi".
// this is the main listener.
(name): {
// Using two mixins, one to set the protocol and the other to set security.
gsl.#HTTPListener
gsl.#MTLSListener
routes: {
// route everything matching the prefix "/"
"/": {
upstreams: {
// arbitrary upstream name since we provide a static IP and port.
"local": {
gsl.#Upstream
instances: [
{
host: "127.0.0.1"
port: 443
},
]
}
}
}
}
}
}
// Connects the tenant edge to this service
edge: {
edge_name: "edge"
// match services/<tenant namespace>/<service name>
// Note that \(variable) syntax means substitute the variable into the string.
routes: "/services/\(context.globals.namespace)/\(name)": {
prefix_rewrite: "/"
// This upstream name is NOT arbitrary. It is set to the service name which means
// the IP and port will be dynamically discovered.
upstreams: (name): {
gsl.#Upstream
namespace: context.globals.namespace
// set mTLS on the upstream.
gsl.#MTLSUpstream
}
}
}
}
// All services must be "exported". This syntax means: append a new key-value to the exports struct,
// where the key is "myApi" (arbitrary name) and the value is the service definition defined above.
exports: "myApi": Myapi
Exports
For Sync to register a service file, they must be “exported”. To export a service, simply add it to the exports struct:
exports: "myApi": Myapi
Typically this line exists at the bottom of the file and is auto-generated. The keys of the struct do not matter only the values.
To temporarily delete a service (for debugging or other purposes), you can comment out that line. Sync will treat it as deleted.
Main listener
The main listener is a special listener on a service denoted by the listener name matching the service name. Every service must have a main listener. Main listeners are unique from other listeners because:
It runs the metrics filter on its traffic
It handles all service discovery traffic
Since the main listener runs the metrics filter by default, only routes on that listener are reported.
When using service discovery between two data plane proxies, traffic can only flow from main listener to main listener. Statically defined endpoints do not have this limitation.
Main listeners also listen on the defaulted proxy port 10908. You cannot override this port without overriding all ports for all services. Thus, you should seek an alternative to changing the default port if conflicts arise.
Schema
#Service: {
name: string
namespace: string
mesh_id: string
service_id: string
api_endpoint?: string
api_spec_endpoint?: string
description?: string
enable_instance_metrics: bool
enable_historical_metrics: bool
business_impact: string
version?: string
owner?: string
owner_url?: string
capability?: string
runtime?: string
documentation?: string
prometheus_job: string
external_links?: [...]
display_name?: string
upgrades?: string
health_options: {...}
ingress?: {...}
egress?: {...}
raw_upstreams: {...}
edge?: {...}
}
Schema Definitions
Field | Type | Description | |
---|---|---|---|
name | string | Required | The name of the service. Must match the name of the Kubernetes workload, otherwise the configuration will not propagate to the injected data plane proxy. Must also be unique within a GSL project (namespace). |
namespace | string | Preset | The GSL project name. This should map to the namespace the service gets deployed into. Populated from the project globals file. |
mesh_id | string | Preset | The name of the mesh the service will get deployed into. Populated from the project globals file. |
service_id | string | Preset | The id of the service used by Catalog for health check associations. Must match the name of the service. |
api_endpoint | string | Optional | Catalog metadata field containing a URL to the service. HTTP-only. This value is displayed on the Dashboard card as a link. |
api_spec_endpoint | string | Optional | Catalog metadata field containing a URL to the service’s OpenAPI specification. HTTP-only. Will also allow the Dashboard to display the API specification. |
description | string | Optional | A description of the service to display on the Dashboard service card. |
enable_instance_metrics | bool | Deprecated | Enables the metrics to be displayed by the Dashboard in the Instance View. |
enable_historical_metrics | bool | Deprecated | enables the aggregate metrics view in the Dashboard. Only available for HTTP services. |
business_impact | string | Optional | Catalog metadata field representing the impact to the business the service has. |
version | string | Optional | Catalog metadata field containing the version of the deployed service. |
owner | string | Optional | Catalog metadata field containing the owner (the one responsible for) of the service. |
owner_url | string | Optional | Catalog metadata field. Contains the URL to the owner’s page. |
capability | string | Optional | Catalog metadata field containing the capability of the service. |
runtime | string | Optional | Catalog metadata field containing the runtime of the service. |
documentation | string | Optional | Catalog metadata field. |
prometheus_job | string | Preset | The job id used by Prometheus metrics scrapping. This value should never be changed. |
external_links | Optional | An arbitrary list of links relevant to the service, used to link out to Grafana, Tracing tools, Kibana and other 3rd party capabilities for DevOps Administrators. | |
display_name | string | Optional | A Catalog metadata field containing a human-friendly name for the service. This value is used for the Dashboard card. |
upgrades | string | Optional | Controls proxy-wide websocket support. Possible values: websocket |
health_options | Optional | Controls the options related to the service’s health checking subsystem. | |
ingress | Required | A map of ingress names to ingresses. An ingress is a listener which accepts traffic originating from outside the proxy’s host machine. The ingress names should be descriptive but are ultimately arbitrary with one exception. The ingress named after the service name is reserved for the main listener. | |
egress | Optional | A map of egress names to egresses. An egress is a listener which accepts traffic originating from inside the proxy’s host machine. Egress names should be descriptive but are ultimately arbitrary. | |
raw_upstreams | Optional | A map of upstream names to upstreams. A “raw” upstream is divorced from a route and listener. It exists within the proxy’s upstream registry typically to provide filters with upstream connection information. For example, the ExternalAuthzFilter connects to the external authorization service directly through an upstream rather than tunneling through a defined listener. | |
edge | Optional | The routing configurations lining the tenant edge with the service. |
ExternalLink
Field | Type | Description | |
---|---|---|---|
title | string | Required | Name of the link to display. |
url | string | Required | URL of the link. |
{
title: string
url: string
}
HealthOptions
Health checks are collected by Catalog and used to display health information in the dashboard. TLS configurations that match the overall mesh’s security policy must be configured here otherwise the service will fail to connect to the health subsystem.
Below are the TLS configurations for connecting to the health checking subsystem. These are required if the mesh is configured for TLS. Mix-ins conforming to the UpstreamTLSSchema definition are:
Field | Type | Description |
---|---|---|
tls | struct | Possible inputs include: TLSUpstream & MTLSUpstream |
spire | Spire configurations for connecting to the health checking subsystem. Required if the mesh is configured for Spire based TLS. | |
secrets | Secrets (if any) used by the metrics filter. MetricsSecrets. |
health_options: {
tls: gsl.#MTLSUpstream
}
Ingress
Ingresses are listeners specifically configured for incoming traffic. Mix-ins that implement the ingress schema include:
#HTTPListener
#TCPListener
#UDPListener
Each listener mix-in enables that protocol for the ingress. They are mutually exclusive. Available options change depending on the features of the protocol’s listener.
Egress
Egresses are listeners specifically configured for outgoing traffic. Otherwise, they follow the same schemas as ingresses.
Edge
Each service contains an block for the route between an edge and the service. Although this configuration is applied to the edge and can be written at the edge, for convenience and coordination of configuration, it also exists at the service level.
Non-HTTP Edge Routing
The service’s edge configuration is setup to centralize all traffic through a single listener. HTTP routing allows for requests to get directed appropriately. This behavior cannot be replicated with non-HTTP traffic. TCP and UDP services that are accessible from the edge must operator on a unique listener. The configuration for edge-to-service routing must also occur on the edge service file, not using the service definitions edge field.
{
edge_ingress: string
edge_name: string
routes: {...}
}
edge_ingress
(String, Preset). The name of the ingress listener that the route should handle traffic from. This is set by default to be the name of the edge. As a result, the default listener for the edge-to-service link is the main listener of the edge.
edge_name
(String, Mandatory). The service name of the edge.
routes
(map[string]Route, Mandatory). A map of route matches to upstreams. Follows the same format of an #HTTPListener routes map.