Kubernetes Ingress Virtual Service Configuration
In an Kubernetes cloud, Kubernetes ingress creation triggers creation of north-south or ingress Avi Vantage VirtualService and Pool objects. OpenShift/Kubernetes Service Configuration in Avi Vantage explains how Kubernetes services map to Avi Vantage’s VirtualService and Pool objects. This article explains how Kubernetes ingresses trigger VirtualService and Pool object creation in Avi Vantage.
Note: Support for Ingresses is available beginning 17.2.3 in the 17.2 release series.
Kubernetes Ingresses to Avi Vantage Object Mapping
Kubernetes ingresses can be configured in one of two ways as far as virtual IPs are concerned.
- Dedicated virtual IP per ingress: Each Kubernetes ingress is allocated its own VirtualService/Pool objects and a virtual IP (VIP). This provides the best performance, availability and isolation, but consumes an IP address per route.
- Shared virtual service across multiple ingresses: Each Kubernetes ingress is tied to a pre-created parent shared virtual service and will use the shared virtual service’s virtual IP. This conserves IP addresses, but provides variable performance, no isolation, and shares fate with all sibling routes. A parent shared virtual service is pre-created with HTTP/HTTPS application profiles with listeners on ports 80 and 443 for every Service Engine group configured in the cloud. The parent virtual service’s name is of the form
parent-vs-SEGroupname-Cloudname
.
Starting with releases 17.2.12 and 18.1.3, the cloud configuration override_service_ports
has been introduced. By default, this knob is disabled. When the knob is not set, virtual service for Ingress will use ports from Kubernetes service. When the knob is set, virtual services for Ingress will use well known ports i.e. 80 for HTTP and 443 for HTTPS.
NB: Support for shared virtual services is available beginning 17.2.3 in the 17.2 release series.
The following table maps each type of Kubernetes ingress to Avi Vantage objects.
Kubernetes ingress | Avi Vantage Object | Comment |
Dedicated virtual service per ingress | VirtualService, Pool | Every ingress creates a VirtualService, Pool object. Ingress annotation avi_proxy: '{"dedicated_route": true}' creates a dedicated virtual service (that uses a VIP) per ingress in shared VirtualService Projects/Namespaces. Layer4 (TCP, UDP) ingresses require a dedicated VIP per ingress |
Shared virtual service: HTTP Virtual Hosting ingresses | Pool | HTTP policy is used in parent virtual service to switch host/path to the appropriate pool. |
Shared virtual service: HTTPS ingresses | Child virtual hosted/SNI VirtualService, Pool | SNI is used to route traffic to the appropriate child VirtualService/Pool. |
Shared Virtual Service Mode Configuration
- Field
shared_virtualservice_namespace
configures the cloud to operate in either dedicated or shared VS mode. Check or uncheck Use Shared Virtual Service in the UI above during cloud configuration. Enablingshared_virtualservice_namespace
uses the shared parent virtual service for all ingresses in all namespaces by default. Disablingshared_virtualservice_namespace
creates a dedicated virtual service per ingress in all namespaces by default. - Changing this mode is disruptive and can be time consuming with a large number of ingresses; hence, it is recommended that this be configured once at initial cloud configuration time.
- Individual namespaces can be overriden to operate in either shared or dedicated modes using the
avi_virtualservice: shared|dedicated
namespace annotation.- If
shared_virtualservice_namespace
is enabled for the cloud, namespace annotationavi_virtualservice: dedicated
creates dedicated virtual services for all ingresses in the namespace. - On the contrary, if
shared_virtualservice_namespace
is disabled for the cloud, namespace annotationavi_virtualservice: shared
uses the shared virtual service for all ingresses in the namespace.
- If
- Every ingress can be overriden to create a dedicated virtual service for itself, even if the cloud or the namespace is operating in the shared mode. Ingress annotation
avi_proxy: '{"dedicated_route": true}'
creates a dedicated virtual service for that ingress. The most common use case for dedicated virtual service is for non-HTTP(S) layer 4 (TCP, UDP) ingresses.
Ingress Configuration Examples
NB: The following examples assume the following cloud configuration.
http_container_ports
is configured with 80, 8080.- A Network object is created with an IP address pool for north-south VIPs; a north-south IPAM profile is created and linked to the Network object and the cloud is linked to the north-south IPAM profile.
- A Network object is created with a IP address pool for east-west VIPs; an east-west IPAM profile is created and linked to the Network object and the cloud is linked to the east-west IPAM profile.
Sample Deployment and Service
The following deployment and service are examples for deploying HTTP pods.
Sample deployment configuration in YAML format.
kind: Deployment
apiVersion: apps/v1beta2
metadata:
name: avitest-deployment
labels:
app: avitest
spec:
replicas: 2
selector:
matchLabels:
app: avitest
template:
metadata:
labels:
app: avitest
spec:
containers:
- name: avitest
image: avinetworks/server-os
ports:
- name: http
containerPort: 8080
protocol: TCP
Sample service file to create an east-west service in YAML format.
kind: Service
apiVersion: v1
metadata:
name: avisvc
labels:
svc: avisvc
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
app: avitest
Since default_service_as_east_west_service
is enabled in the cloud configuration, this service creates an east-west virtual service.
If HTTPS pods are deployed, containerPort is usually 443 or 8443 and service port is 443 or 8443.
Sample Ingresses
Dedicated VIP for HTTP Ingress
In this case shared_virtualservice_namespace
is disabled in the cloud and namespace does not have the avi_virtualservice: shared
annotation.
The following sample ingress file creates a http ingress with a dedicated VIP for service avisvc.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: aviingress
spec:
rules:
- host: aviingress1.default.acme.local
http:
paths:
- backend:
serviceName: avisvc1
servicePort: 80
path: /foo
- backend:
serviceName: avisvc2
servicePort: 80
path: /bar
- host: aviingress2.default.acme.local
http:
paths:
- backend:
serviceName: avisvc3
servicePort: 80
This dedicated virtual service ingress will create its own virtual service and pool with its dedicated VIP. VirtualService name is of the form ingressname.dns_sub_domain
. In the example above, a VirtualService called aviingress.default.acme.local
will be created.
Shared VIP for HTTP Ingress
In this case either shared_virtualservice_namespace
is enabled in the cloud or namespace has the avi_virtualservice: shared
annotation.
The following sample ingress file creates a HTTP route associated with parent virtual service parent-vs-Default-Group-Default-Cloud
for service avisvc
.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: aviingress
spec:
rules:
- host: aviingress1.default.acme.local
http:
paths:
- backend:
serviceName: avisvc1
servicePort: 80
path: /foo
- backend:
serviceName: avisvc2
servicePort: 80
path: /bar
- host: aviingress2.default.acme.local
http:
paths:
- backend:
serviceName: avisvc3
servicePort: 80
The HTTP application will be created as a poolgroup and pool for the parent virtual service. Pool name will be of the form namespace-host--path-aviroute-pool-port-protocol
. For example, ingress with host aviingress1.default.acme.local
and path /foo
in namespace default
will have a pool name default-aviingress1.default.acme.local--foo-aviroute-pool-http-tcp
. For the HTTP Ingress object above, 3 Pools will be created for the 3 Services. An HTTP policy will provide host/path switching for the pool.
Dedicated VIP for HTTPS with Edge Termination
In this case shared_virtualservice_namespace
is enabled in the cloud but namespace has the avi_virtualservice: dedicated
annotation.
The avi_virtualservice: dedicated
namespace annotation overrides the shared_virtualservice_namespace
cloud configuration and creates dedicated virtual services for all routes in the namespace.
Namespace looks as follows.
apiVersion: v1
kind: Namespace
metadata:
annotations:
avi_virtualservice: dedicated
name: ns1
spec:
finalizers:
- kubernetes
status:
phase: Active
The following sample ingress file creates a HTTPS ingress with edge termination with a dedicated VIP.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: aviingress
spec:
rules:
- host: aviingress1.ns1.acme.local
http:
paths:
- backend:
serviceName: avisvc1
servicePort: 80
path: /foo
- host: aviingress2.ns1.acme.local
http:
paths:
- backend:
serviceName: avisvc2
servicePort: 80
tls:
- secretName: aviingress1cert
hosts:
- aviingress1.ns1.acme.local
- secretName: aviingress2cert
hosts:
- aviingress2.ns1.acme.local
backend:
serviceName: avisvc3
servicePort: 80
This dedicated virtual service ingress will create its own virtual service with its dedicated VIP. VirtualService name is of the form ingressname.dns_sub_domain
. In the example above, a VirtualService called aviingress.ns1.acme.local
will be created. 2 child SNI VirtualServices called ns1-aviingress-aviingress1cert
will also be created. SNI child VirtualServices will be of the form namespace-ingressname-certificatename
.
Shared VIP for HTTPS with Edge Termination
In this case shared_virtualservice_namespace
is enabled in the cloud.
The following sample ingress file creates a HTTPS ingress with edge termination with a dedicated VIP.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: aviingress
spec:
rules:
- host: aviingress1.ns1.acme.local
http:
paths:
- backend:
serviceName: avisvc1
servicePort: 80
path: /foo
- host: aviingress2.ns1.acme.local
http:
paths:
- backend:
serviceName: avisvc2
servicePort: 80
tls:
- secretName: aviingress1cert
hosts:
- aviingress1.ns1.acme.local
- secretName: aviingress2cert
hosts:
- aviingress2.ns1.acme.local
backend:
serviceName: avisvc3
servicePort: 80
The above ingress will create 2 child SNI VirtualServices for the parent VirtualService called ns1-aviingress-aviingress1cert
. SNI child VirtualServices will be of the form namespace-ingressname-certificatename
.
Automatic Configuration
The following fields in the VirtualServices and Pools objects are automatically derived from Kubernetes Ingress by the cloud connector.
VirtualService Field | Kubernetes Field | Comments |
tenant | Namespace | |
name | Derived from ingress name and optionally certificate name for HTTPS | |
fqdn | Host | |
ip_address | Dedicated VIP: Can be explicitly specified via annotations or will be auto-allocated from the north-south IPAM object Shared VIP: Uses parent VritualServices VIP. |
|
services | Port field in the corresponding service | |
application_profile | Layer4 if overridden via annotations or container ports don't match http_container_ports in Cloud Configuration, else Layer7 | |
network_profile | Default to System-TCP-Proxy unless overridden by annotations | |
pool_group | One for every Service in Ingress | |
pool | One for every Service in Ingress | |
network_security_policy | A default network security policy is created for every new or child SNI virtual service | |
http_policies | Layer7 policy for URL (host, path, port) switching amongst routes sharing the virtual service | |
microservice | A microservice is automatically created for every Service | |
east_west_placement | Always north-south |
Annotations
Additional configuration for Avi VirtualServices can be provided via annotations.
Automatic WAF policy
Starting release 17.2.4, the following annotation automatically creates and attaches a WAF policy to the VirtualService. After initial creation, the WAF policy can be modified independently of the VirtualService. Note that the version field is necessary, since a waf profile was introduced in the VirtualService starting this release.
metadata:
annotations:
avi_proxy: '{"waf_policy": true, "version": "17.2.4"}'
If the cloud uses the shared VirtualService model and just a few Ingresses require WAF service, dedicated VirtualServices can be created just for these Ingresses using the dedicated_route flag. The annotation would be as follows in this case.
metadata:
annotations:
avi_proxy: '{"waf_policy": true, "dedicated_route": true, "version": "17.2.4"}'