Skip to main content

Networking and Public Ingress

Flyte leverages Knative and Kourier to manage application networking, providing a system for both public ingress and internal service discovery. This architecture relies on deterministic naming and environment variable injection to ensure that applications can be reached reliably by external users and by other applications within the same cluster.

Deterministic Resource Naming

Every application in Flyte is backed by a Knative Service (KService). Because all applications are deployed into a single namespace (defined as AppNamespace = "flyte" in app/internal/k8s/app_client.go), Flyte must ensure that resource names are unique across different projects and domains.

The KServiceName function in app/internal/k8s/app_client.go generates these names by concatenating the application name, project, and domain:

func KServiceName(id *flyteapp.Identifier) string {
raw := strings.ToLower(fmt.Sprintf("%s-%s-%s", id.GetName(), id.GetProject(), id.GetDomain()))
if len(raw) <= maxKServiceNameLen {
return raw
}
sum := sha256.Sum256([]byte(id.GetProject() + "/" + id.GetDomain() + "/" + id.GetName()))
suffix := hex.EncodeToString(sum[:4])
prefix := raw
if len(prefix) > maxKServiceNameLen-9 {
prefix = prefix[:maxKServiceNameLen-9]
}
return prefix + "-" + suffix
}

This implementation addresses the Kubernetes DNS label limit of 63 characters. If the combined string exceeds this limit, Flyte truncates the prefix and appends a deterministic 8-character SHA256 suffix. This ensures that even with long project or domain names, the resulting KService name remains unique and valid for Kubernetes.

Public Ingress Generation

Public access to applications is managed through the PublicIngress method in AppK8sClient. This method constructs a URL that matches the domain templates expected by the Kourier ingress gateway.

The generation logic depends on the InternalAppConfig provided during initialization:

func (c *AppK8sClient) PublicIngress(id *flyteapp.Identifier) *flyteapp.Ingress {
if c.cfg.BaseDomain == "" {
return nil
}
scheme := c.cfg.Scheme
if scheme == "" {
scheme = "https"
}
host := strings.ToLower(fmt.Sprintf("%s.%s",
KServiceName(id), c.cfg.BaseDomain))
url := scheme + "://" + host
if c.cfg.IngressAppsPort != 0 {
url += fmt.Sprintf(":%d", c.cfg.IngressAppsPort)
}
return &flyteapp.Ingress{PublicUrl: url}
}

If BaseDomain is not configured, Flyte does not generate a public URL, effectively keeping the application private. When configured, the URL follows the pattern {kservice-name}.{base-domain}, which Kourier uses to route incoming traffic to the appropriate Knative revision.

Internal Service Discovery

For cross-application communication within the cluster, Flyte injects a discovery pattern into the application's environment. During the buildKService phase in app/internal/k8s/app_client.go, Flyte calculates an internal endpoint pattern and assigns it to the INTERNAL_APP_ENDPOINT_PATTERN environment variable.

if len(podSpec.Containers) > 0 {
suffix := renderNamespacedSuffix(c.cfg.NamespacedNameSuffixTemplate, appID.GetProject(), appID.GetDomain())
podSpec.Containers[0].Env = append(podSpec.Containers[0].Env, corev1.EnvVar{
Name: "INTERNAL_APP_ENDPOINT_PATTERN",
Value: fmt.Sprintf("http://{app_fqdn}-%s.%s.svc.cluster.local", suffix, ns),
})
}

The NamespacedNameSuffixTemplate (typically {{ project }}-{{ domain }}) allows the system to match the naming convention used by KServiceName. Application code can then use this pattern to resolve the internal ClusterIP of other services by replacing the {app_fqdn} placeholder with the target application's name. This avoids the overhead of routing internal traffic through the public ingress gateway.

Visibility and Lifecycle Control

Flyte uses Knative visibility labels to control whether an application is exposed externally. When an application is "stopped," Flyte does not delete the KService resource. Instead, it scales the deployment to zero and restricts its visibility to the cluster.

In app/internal/k8s/app_client.go, the Stop method applies a patch that sets the networking.knative.dev/visibility label to cluster-local:

patch := []byte(fmt.Sprintf(
`{"metadata":{"labels":{"%s":"true","%s":"%s"}},"spec":{"template":{"metadata":{"annotations":{"autoscaling.knative.dev/min-scale":"%s","autoscaling.knative.dev/initial-scale":"%s"}}}}}`,
labelAppStopped,
labelKnativeVisibility,
visibilityClusterLocal,
scaleZero,
scaleZero,
))

To ensure that pods are terminated immediately rather than waiting for the standard Knative scaling window, Flyte explicitly deletes the LatestReadyRevisionName after patching the service. When the application is restarted via a Deploy call, Flyte clears these labels, restoring public visibility and triggering Knative to scale the pods back up based on the original specification.