Exposing Applications

Expose Applications using Kubernetes Services

Kubernetes workloads can be exposed to each other, and to the public using Services and Ingresses. A Service allocates a dedicated IP for the exposed application, whereas an Ingress works for HTTP based protocols and alleviates the need for a separate IP for each endpoint. For stateless web-services, using the Serverless framework is another option where the application is deployed with a TLS enabled hostname and auto-scaling for you.

Internal Services

Internal, cluster local services should be configured as regular ClusterIP services.

Public Services

Exposing services to the Internet is done by deploying a LoadBalancer service type with an annotation to allocate a public IP for the service. Without the annotation, a static private IP will be allocated, this is mostly useful for services accessed from outside the cluster via a Site to Site VPN.

Depending upon where you've requested your workloads to run, public IP pools are accessible via the region location in the following manner:

Region

Address Pool Label

ORD1

public-ord1

EWR1

public-ewr1

LAS1

public-las1

sshd-public-service.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
metallb.universe.tf/address-pool: public-ord1
metallb.universe.tf/allow-shared-ip: default
name: sshd
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: sshd
port: 22
protocol: TCP
targetPort: sshd
selector:
app.kubernetes.io/name: sshd

For public services, ensure that externalTrafficPolicy: Local is set on the service. This load balances ingress traffic from the Internet directly to the nodes running the application.

Attaching Service IP directly to Pod

The traditional Kubernetes pattern is one or many Pods with dynamic internal IPs exposed behind a Service or Ingress with a static IP. For certain use cases, where there would only be one Pod behind a service, it can make sense to attach the Service IP directly to the Pod. A Pod would then have a static public IP as it's Pod IP. All connections originating from the pod will have this IP as it's source, and the Pod will see this as it's local IP. This is a non standard approach for containers, and should be used only when the traditional Service / Pod pattern is not feasible. Directly attaching the Service IP is beneficial in the following scenarios:

  • The application needs to expose a large number of ports (above 10), where listing them out in the service definition is impractical

  • The application needs to see the service IP on the network interface inside the pod

  • Connections originating from the Pod to the outside need to originate from the Service IP

  • The application needs to receive all traffic regardless of type and port

  • A Virtual Machine type workload where a static IP provides a more native experience

Please note that an application that directly attaches a Service IP can run with a maximum of 1 replica, as there would otherwise be multiple Pods with the same Pod IP. Traffic to the Pod will not be filtered, all inbound traffic to the IP will be sent to the pod. To provide security, NetworkPolicies can be applied.

A stub Service needs to be created to allocate the IP. The Service should expose only port 1 as in the example below.

apiVersion: v1
kind: Service
metadata:
name: my-app
annotations:
metallb.universe.tf/address-pool: public-ord1
spec:
externalTrafficPolicy: Local
type: LoadBalancer
ports:
- port: 1 # Do not change this
targetPort: attach
protocol: TCP
name: attach
selector:
coreweave.cloud/ignore: ignore # Do not change this

To attach the IP from the Service directly to a Pod, annotate the Pod spec.

annotations:
net.coreweave.cloud/attachLoadbalancerIP: my-app

Ingress

Using an Ingress for HTTP based applications are beneficial as it saves IP addresses and automatically provides a DNS name as well as TLS certificate to allow access to your application via https. CoreWeave already has all the infrastructure setup including the Ingress Controller, all you need to do is deploy an Ingress manifest. The hostname of the Ingress needs to be in the format of <app>.<namespace>.<region>.ingress.coreweave.cloud. The example below demonstrates an Ingress called my-app exposed via an Ingress in the ORD1 region for a namespace tenant-test-default.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/ssl-redirect: "true"
traefik.ingress.kubernetes.io/redirect-entry-point: https
labels:
app.kubernetes.io/name: my-app
name: my-app
spec:
rules:
- host: my-app.tenant-test-default.ord1.ingress.coreweave.cloud
http:
paths:
- backend:
serviceName: my-app
servicePort: http
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- my-app.tenant-test-default.ord1.ingress.coreweave.cloud
secretName: my-app-tls # This secret is automatically created for you

‚Äč