In this tutorial, you will learn how to use the Ambassador Edge Stack ingress (AES
for short) . Then, you're going to discover how to have TLS
certificates automatically deployed and configured for your hosts (thus enabling TLS
termination), and route
traffic to your backend
applications. It can function as an API Gateway
, an Ingress Controller
or a Layer 7 Load Balancer
.
Note:
Ambassador Edge Stack 2.X introduces some changes that aren't backward-compatible with 1.X, if you already have an existing installation that uses 1.X and you will like to upgrade to version 2.X please use the following guide for upgrade.
The Ambassador Edge Stack
or AES
for short, is a specialized Control Plane for the Envoy Proxy
. In this architecture, Ambassador Edge Stack
translates configuration (in the form of Kubernetes Custom Resources
) to Envoy
configuration. All the actual traffic is directly handled by the high-performance Envoy Proxy.
At a very high level, AES
works as follows:
- The service owner defines
configuration
viaKubernetes
manifests. - When the manifest is applied to the cluster, the
Kubernetes API
notifiesAmbassador Edge Stack
of the change. Ambassador Edge Stack
parses the change and transforms the configuration into a semantic intermediate representation.Envoy
configuration is generated from thisIR
.- The new configuration is passed to
Envoy
via thegRPC-based Aggregated Discovery Service (ADS) API
. - Traffic flows through the reconfigured
Envoy
, without dropping any connections.
Why use the Ambassador Edge Stack
?
Let us say you are exposing REST
or GRPC
APIs for different tasks (reading account info, writing orders, searching orders, etc.). Depending on the API
, you will want to be able to route to a specific target. For this to happen, more functionality needs to be built inside the ingress proxy. That is API Gateway
, and it is capable of doing more things besides routing traffic.
Ambassador
abstracts the Ingress
spec even more, thus making it easier
to work with, and adds more functionality on top. So, for most use cases you don't need to use the Ingress Controller
functionality of AES
. The recommended way of using AES is via the CRDs, like Hosts
and Mappings
.
After finishing this tutorial, you will be able to:
- Create and manage
Ambassador Edge Stack
releases viaHelm
. - Create and configure the
Ambassador Edge Stack
domain and hosts. - Automatically configure
TLS
certificates for yourHosts
, thus havingTLS
termination. - Create and configure
Ambassador Edge Stack
hostMappings
. - Know about
Ambassador Edge Stack
resource usage in yourDOKS
cluster (Performance Considerations guide).
- Introduction
- Prerequisites
- Step 1 - Installing the Ambassador Edge Stack
- Step 2 - Defining the Listener for Ambassador Edge Stack
- Step 3 - Defining the Hosts for Ambassador Edge Stack
- Step 4 - Configuring DNS for Ambassador Edge Stack
- Step 5 - Creating the Ambassador Edge Stack Backend Services
- Step 6 - Configuring the Ambassador Edge Stack Mappings for Hosts
- Step 7 - Enabling Proxy Protocol
- Step 8 - Verifying the Ambassador Edge Stack Setup
- How To Guides
- Conclusion
To complete this tutorial, you will need:
- A Git client, to clone the
Starter Kit
repository. - Helm, for managing
Ambassador Edge Stack
releases and upgrades. - Doctl, for
DigitalOcean
API interaction. - Kubectl, for
Kubernetes
interaction. - Curl, for testing the examples (backend applications).
Please make sure that doctl
and kubectl
context is configured to point to your Kubernetes
cluster - refer to Step 2 - Authenticating to DigitalOcean API and Step 3 - Creating the DOKS Cluster from the DOKS
setup tutorial.
In this step, you will deploy the Ambassador Edge Stack
to your DOKS
cluster, via Helm
.
Steps to follow:
-
First, clone the
Starter Kit
repository and change directory to your local copy.git clone https://github.com/digitalocean/Kubernetes-Starter-Kit-Developers.git cd Kubernetes-Starter-Kit-Developers
-
Next, add the
Helm
repo, and list the availablecharts
:helm repo add datawire https://app.getambassador.io helm repo update datawire helm search repo datawire
The output looks similar to the following:
NAME CHART VERSION APP VERSION DESCRIPTION datawire/ambassador 6.9.4 1.14.3 A Helm chart for Datawire Ambassador datawire/ambassador-operator 0.3.0 v1.3.0 A Helm chart for Kubernetes datawire/edge-stack 7.3.2 2.2.2 A Helm chart for Ambassador Edge Stack datawire/emissary-ingress 7.3.2 2.2.2 A Helm chart for Emissary Ingress datawire/telepresence 2.6.5 2.6.5 A chart for deploying the server-side component...
Note:
The chart of interest is
datawire/edge-stack
, which will installAmbassador Edge Stack
on the cluster. Please visit the ambassador-edge-stack page, for more details about this chart. -
Before installing Ambassador Edge Stack 2.X itself, you must configure your Kubernetes cluster to support the
getambassador.io/v3alpha1
andgetambassador.io/v2
configuration resources. This is required.kubectl apply -f https://app.getambassador.io/yaml/edge-stack/2.3.0/aes-crds.yaml
Note:
Ambassador Edge Stack 2.X includes a Deployment in the
emissary-system
namespace callededge-stack-apiext
. This is the APIserver extension that supports converting Ambassador Edge Stack CRDs betweengetambassador.io/v3alpha1
andgetambassador.io/v2
. This Deployment needs to be running at all times. -
Then, open and inspect the
03-setup-ingress-controller/assets/manifests/ambassador-values-v7.3.2.yaml
file provided in theStarter Kit
repository, using an editor of your choice (preferably withYAML
lint support). For example, you can use VS Code:code 03-setup-ingress-controller/assets/manifests/ambassador-values-v7.3.2.yaml
Note:
There are times when you want to re-use the existing
Load Balancer
. This is for preserving yourDNS
settings and otherLoad Balancer
configurations. If so, make sure to modify theambassador-values-v7.3.2.yaml
file, and add the annotation for your existingLoad Balancer
. Likewise, you can enableProxy Protocol
as part of modules section in theambassador-values-v7.3.2.yaml
file. Please refer to theDigitalOcean Kubernetes
guide - How To Migrate Load Balancers for more details. -
Finally, install
Ambassador Edge Stack
usingHelm
(a dedicatedambassador
namespace will be created as well):HELM_CHART_VERSION="7.3.2" helm install edge-stack datawire/edge-stack --version "$HELM_CHART_VERSION" \ --namespace ambassador \ --create-namespace \ -f "03-setup-ingress-controller/assets/manifests/ambassador-values-v${HELM_CHART_VERSION}.yaml"
Note:
A
specific
version for the ambassadorHelm
chart is used. In this case7.3.2
was picked, which maps to the2.2.2
release ofAmbassador Edge Stack
(see the output fromStep 2.
). It’s good practice in general, to lock on a specific version. This helps to have predictable results, and allows versioning control viaGit
.
Observations and results:
You can verify Ambassador deployment status via:
helm ls -n ambassador
The output looks similar to (notice that the STATUS
column value is deployed
):
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
edge-stack ambassador 1 2022-02-03 09:56:55.80197 +0200 EET deployed edge-stack-7.3.2 2.2.2
Next check Kubernetes resources created for the ambassador
namespace (notice the deployment
and replicaset
resources which should be healthy, as well as the LoadBalancer
resource having an external IP
assigned):
kubectl get all -n ambassador
The output looks similar to:
NAME READY STATUS RESTARTS AGE
pod/edge-stack-5bdc64f9f6-hhwdc 1/1 Running 0 6m14s
pod/edge-stack-5bdc64f9f6-xz9jl 1/1 Running 0 6m14s
pod/edge-stack-agent-bcdd8ccc8-m9blv 1/1 Running 0 6m14s
pod/edge-stack-redis-64b7c668b9-69c5p 1/1 Running 0 6m14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/edge-stack LoadBalancer 10.245.189.240 68.183.252.190 80:30323/TCP,443:30510/TCP 6m14s
service/edge-stack-admin ClusterIP 10.245.170.181 <none> 8877/TCP,8005/TCP 6m14s
service/edge-stack-redis ClusterIP 10.245.205.49 <none> 6379/TCP 6m14s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/edge-stack 2/2 2 2 6m14s
deployment.apps/edge-stack-agent 1/1 1 1 6m14s
deployment.apps/edge-stack-redis 1/1 1 1 6m14s
NAME DESIRED CURRENT READY AGE
replicaset.apps/edge-stack-5bdc64f9f6 2 2 2 6m14s
replicaset.apps/edge-stack-agent-bcdd8ccc8 1 1 1 6m14s
replicaset.apps/edge-stack-redis-64b7c668b9 1 1 1 6m14s
Finally, list all load balancer resources from your DigitalOcean
account, and print the IP
, ID
, Name
and Status
:
doctl compute load-balancer list --format IP,ID,Name,Status
The output looks similar to (should contain the new load balancer
resource created for Ambassador Edge Stack
in a healthy state):
IP ID Name Status
68.183.252.190 0471a318-a98d-49e3-aaa1-ccd855831447 acdc25c5cfd404fd68cd103be95af8ae active
In the next step, you will learn how to create the Listener
CRDs that tells to Ambassador Edge Stack what port to listen on.
The Listener
CRD defines where, and how, Ambassador Edge Stack should listen for requests from the network (e.g. DO Load Balancer), and which Host definitions should be used to process those requests.
Note:
The Listeners
are never created at the installation, the below steps will guide you how to do it.
A typical Listener
configuration looks like below:
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: http-listener
spec:
port: 8080
protocol: HTTPS
securityModel: XFP
hostBinding:
namespace:
from: ALL
Explanations for the above configuration:
port
: The network port on which Ambassador Edge Stack should listen.protocol
: The protocol Type on which Ambassador Edge Stack will use.protocolStack
: Allows configuring exactly which protocols will be layered together.securityModel
: Defines how the Listener will decide whether a request is secure or insecure.hostBinding
: Mechanism for determining which Hosts will be associated with this Listener.
Note:
Ambassador Edge Stack offers multiple configurations for protocolStack and our recommandation is the XFP
flag to be setup for all the connections to be secure. If the X-Forwarded-Proto
header is present in the requests the AES will decide automatically to redirect all the requests from HTTP over to HTTPS for greater security.
For more details, please visit the AES Listener CRD official documentation.
First, change directory (if not already) where you cloned the Starter Kit
repository.
cd Kubernetes-Starter-Kit-Developers
Next, apply the manifest to create the Listener
:
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/ambassador_listener.yaml
Observations and results:
Inspect the AES Listener
:
kubectl describe listener.getambassador.io
The output looks similar to the following (notice the creation of host bindings via the Spec.Host Binding
field):
Name: http-listener
API Version: getambassador.io/v3alpha1
Kind: Listener
...
Spec:
Host Binding:
Namespace:
From: ALL
Port: 8080
Protocol: HTTPS
Security Model: XFP
Stats Prefix: http-listener
Events: <none>
Name: https-listener
API Version: getambassador.io/v3alpha1
Kind: Listener
...
Spec:
Host Binding:
Namespace:
From: ALL
Port: 8443
Protocol: HTTPS
Security Model: XFP
Stats Prefix: https-listener
Events: <none>
In the next step, you will learn how to create the Host
CRDs which tell Ambassador
how to expose backend hosts (services) to the outside world.
In a real world scenario each host
maps to a service
, so you need a way to tell AES
about your intentions - meet the Host CRD. The Host
CRD can handle TLS termination
automatically, by using HTTP-01
ACME challenge to request TLS certificates
from a well known Certificate Authority
(like Let's Encrypt). Certificates creation and renewal happens automatically once you configure and enable this feature in the Host
CRD.
The custom Host
resource defines how Ambassador Edge Stack
will be visible to the outside world. It collects all the following information in a single configuration resource. The most relevant parts are:
- The
hostname
by whichAmbassador Edge Stack
will be reachable. - How
Ambassador Edge Stack
should handleTLS
certificates. - How
Ambassador Edge Stack
should handle secure and insecure requests.
A typical Host
configuration looks like below:
apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
name: echo-host
namespace: ambassador
spec:
hostname: echo.starter-kit.online
acmeProvider:
email: [email protected]
tlsSecret:
name: tls2-cert
requestPolicy:
insecure:
action: Redirect
additionalPort: 8080
Explanations for the above configuration:
hostname
: The hostname by whichAmbassador Edge Stack
will be reachable.acmeProvider
: Tells Ambassador Edge Stack whatCertificate Authority
to use, and request certificates from. Theemail
address is used by theCertificate Authority
to notify about any lifecycle events of the certificate.tlsSecret
: TheKubernetes Secret
name to use for storing thecertificate
, after the Ambassador Edge StackACME challenge
finishes successfully.requestPolicy
: Tells howAmbassador Edge Stack
should handle secure and insecure requests.
Notes:
- The
hostname
must be reachable from the internet so theCA
can checkPOST
to an endpoint inAmbassador Edge Stack
. - In general the
registrant email address
is mandatory when usingACME
, and it should be a valid one in order to receive notifications when the certificates are going to expire. - The Ambassador Edge Stack built-in
ACME
client knows to handleHTTP-01
challenges only. For otherACME
challenge types likeDNS-01
for example, anexternal
certificate management tool is required (e.g. Cert-Manager).
For more details, please visit the AES Host CRD official documentation.
The following examples configure the TLS
enabled hosts
for this tutorial: echo_host and quote_host.
Steps to follow:
-
First, change directory (if not already) where you cloned the
Starter Kit
repository.cd Kubernetes-Starter-Kit-Developers
-
Then, apply the manifests:
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/echo_host.yaml kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/quote_host.yaml
-
Finally, inspect the
AES
hosts:kubectl get hosts -n ambassador
The output looks similar to the following:
NAME HOSTNAME STATE PHASE COMPLETED PHASE PENDING AGE echo-host echo.starter-kit.online Pending ACMEUserRegistered ACMECertificateChallenge 3s quote-host quote.starter-kit.online Pending ACMEUserRegistered ACMECertificateChallenge 3s
Observations and results:
It takes around 30s
to get the signed certificate for the hosts. At this point, you have the Ambassador Edge Stack
installed and the hosts
configured. But you still don't have the networking (eg. DNS
and Load Balancer
) configured to route
traffic to the cluster
. The missing parts can be noticed in the Kubernetes
events of the hosts that you configured earlier.
Take a look and see what happens for the echo-host
:
kubectl describe host echo-host -n ambassador
The output looks similar to the following:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pending 32m Ambassador Edge Stack waiting for Host DefaultsFilled change to be reflected in snapshot
Normal Pending 32m Ambassador Edge Stack creating private key Secret
Normal Pending 32m Ambassador Edge Stack waiting for private key Secret creation to be reflected in snapshot
Normal Pending 32m Ambassador Edge Stack waiting for Host status change to be reflected in snapshot
Normal Pending 32m Ambassador Edge Stack registering ACME account
Normal Pending 32m Ambassador Edge Stack ACME account registered
Normal Pending 32m Ambassador Edge Stack waiting for Host ACME account registration change to be reflected in snapshot
Normal Pending 16m (x4 over 32m) Ambassador Edge Stack tlsSecret "tls2-cert"."ambassador" (hostnames=["echo.starter-kit.online"]): needs updated: tlsSecret does not exist
Normal Pending 16m (x4 over 32m) Ambassador Edge Stack performing ACME challenge for tlsSecret "tls2-cert"."ambassador" (hostnames=["echo.starter-kit.online"])...
Warning Error 16m (x4 over 32m) Ambassador Edge Stack obtaining tlsSecret "tls2-cert"."ambassador" (hostnames=["echo.starter-kit.online"]): acme: Error -> One or more domains had a problem:
[echo.starter-kit.online] acme: error: 400 :: urn:ietf:params:acme:error:dns :: DNS problem: SERVFAIL looking up A for echo.starter-kit.online - the domain's nameservers may be malfunctioning
...
As seen above, the last event
tells that there's no A
record to point to the echo
host for the starter-kit.online
domain, which results in a lookup failure. You will learn how to fix this issue, in the next step of the tutorial.
In this step, you will configure DNS
within your DigitalOcean
account, using a domain
that you own. Then, you will create the domain A
records for each host: echo
and quote
. Please bear in mind that DigitalOcean
is not a domain name registrar. You need to buy a domain name first from Google, GoDaddy, etc.
First, please issue the below command to create a new domain
(starter-kit.online
, in this example):
doctl compute domain create starter-kit.online
The output looks similar to the following:
Domain TTL
starter-kit.online 0
Note:
YOU NEED TO ENSURE THAT YOUR DOMAIN REGISTRAR IS CONFIGURED TO POINT TO DIGITALOCEAN NAME SERVERS. More information on how to do that is available here.
Next, you will add required A
records for the hosts
you created earlier. First, you need to identify the load balancer external IP
created by the Ambassador Edge Stack
deployment:
kubectl get svc -n ambassador
The output looks similar to (notice the EXTERNAL-IP
column value for the ambassador
service):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
edge-stack LoadBalancer 10.245.189.240 68.183.252.190 80:30323/TCP,443:30510/TCP 6m14s
edge-stack-admin ClusterIP 10.245.170.181 <none> 8877/TCP,8005/TCP 6m14s
edge-stack-redis ClusterIP 10.245.205.49 <none> 6379/TCP 6m14s
Then, add the records (please replace the <>
placeholders accordingly). You can change the TTL
value as per your requirement:
doctl compute domain records create starter-kit.online --record-type "A" --record-name "echo" --record-data "<YOUR_LB_IP_ADDRESS>" --record-ttl "30"
doctl compute domain records create starter-kit.online --record-type "A" --record-name "quote" --record-data "<YOUR_LB_IP_ADDRESS>" --record-ttl "30"
Hint:
If you have only one load balancer
in your account, then please use the following snippet:
LOAD_BALANCER_IP=$(doctl compute load-balancer list --format IP --no-header)
doctl compute domain records create starter-kit.online --record-type "A" --record-name "echo" --record-data "$LOAD_BALANCER_IP" --record-ttl "30"
doctl compute domain records create starter-kit.online --record-type "A" --record-name "quote" --record-data "$LOAD_BALANCER_IP" --record-ttl "30"
Observation and results:
List the available records for the starter-kit.online
domain:
doctl compute domain records list starter-kit.online
The output looks similar to the following:
ID Type Name Data Priority Port TTL Weight
164171755 SOA @ 1800 0 0 1800 0
164171756 NS @ ns1.digitalocean.com 0 0 1800 0
164171757 NS @ ns2.digitalocean.com 0 0 1800 0
164171758 NS @ ns3.digitalocean.com 0 0 1800 0
164171801 A echo 143.244.208.191 0 0 3600 0
164171809 A quote 143.244.208.191 0 0 3600 0
Next, check the AES
hosts status:
kubectl get hosts -n ambassador
The output looks similar to the following (the STATE
column should display Ready
):
NAME HOSTNAME STATE PHASE COMPLETED PHASE PENDING AGE
echo-host echo.starter-kit.online Ready 2m11s
quote-host quote.starter-kit.online Ready 2m12s
Note:
In case the hosts
are still in a pending
state, it might be due to the DNS
propagation delay. Please wait for a couple of minutes, and verify your hosts STATE
column again.
At this point the network traffic will reach the AES
enabled cluster, but you need to configure the backend services paths
for each of the hosts. All DNS
records have one thing in common: TTL
or time to live. It determines how long a record
can remain cached before it expires. Loading data from a local cache is faster, but visitors won’t see DNS
changes until their local cache expires and gets updated after a new DNS
lookup. As a result, higher TTL
values give visitors faster performance, and lower TTL
values ensure that DNS
changes are picked up quickly. All DNS
records require a minimum TTL
value of 30 seconds
.
Please visit the How to Create, Edit and Delete DNS Records page for more information.
In the next step, you will create two simple backend
services, to help you test the Ambassador Edge Stack
setup.
In this step, you will deploy two example backend
services (applications), named echo
and quote
to test the Ambassador Edge Stack
setup.
You can have multiple TLS
enabled hosts
on the same cluster. On the other hand, you can have multiple deployments
and services
as well. So for each backend
application, a corresponding Kubernetes Deployment
and Service
has to be created.
First, you define a new namespace
for the quote
and echo
backend applications. This is good practice in general, because you don't want to pollute the AES
namespace (or any other), with application specific stuff.
Steps to follow:
-
First, change directory (if not already) where the
Starter Kit
repository was cloned:cd Kubernetes-Starter-Kit-Developers
-
Next, create the
backend
namespace:kubectl create ns backend
-
Then, create the echo and quote deployments:
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/echo_deployment.yaml kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/quote_deployment.yaml
-
Finally, create the corresponding
services
:kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/echo_service.yaml kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/quote_service.yaml
Observation and results:
Inspect the deployments
and services
you just created:
kubectl get deployments -n backend
The output looks similar to the following (notice the echo
and quote
deployments):
NAME READY UP-TO-DATE AVAILABLE AGE
echo 1/1 1 1 2m22s
quote 1/1 1 1 2m23s
kubectl get svc -n backend
The output looks similar to the following (notice the echo
and quote
services):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo ClusterIP 10.245.175.185 <none> 80/TCP 2m32s
quote ClusterIP 10.245.158.116 <none> 80/TCP 2m33s
In the next step, you will create the AES Mappings
for the quote
and echo
backend applications.
In this step, you will learn how to create the Ambassador Edge Stack
mappings, so that your backend
applications are ready for inbound/outbound traffic
. The main goal here is to have a basic understanding on how the AES
stack will route
requests to each application
, by introducing a new custom AES
resource. Meet the Mapping CRD.
A typical Mapping
definition looks like below:
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: quote-backend
namespace: ambassador
spec:
prefix: /quote/
host: quote.starter-kit.online
service: quote.backend
What a Mapping
does, is to manage traffic routing for the quote
and echo
services. Each mapping has a set of fields, described below:
name
- a string identifying theMapping
(e.g. in diagnostics).prefix
- theURL
prefix identifying your resource.service
- the name of the service handling the resource; must include thenamespace
(e.g.myservice.othernamespace
) if the service is in a different namespace thanAmbassador Edge Stack
.
First, change directory (if not already) where the Starter Kit
repository was cloned on your local machine:
cd Kubernetes-Starter-Kit-Developers
Next, create a Mapping
for echo and quote backend applications:
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/echo_mapping.yaml
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/quote_mapping.yaml
Observation and results:
Inspect the AES
mappings:
kubectl get mappings -n ambassador
The output looks similar to the following (notice the echo-backend
and quote-backend
lines, and how each maps to a SOURCE HOST
, followed by a SOURCE PREFIX
, and finally a destination service - DEST SERVICE
):
NAME SOURCE HOST SOURCE PREFIX DEST SERVICE STATE REASON
edge-stack-devportal /documentation/ 127.0.0.1:8500
edge-stack-devportal-api /openapi/ 127.0.0.1:8500
edge-stack-devportal-assets /documentation/(assets|styles)/(.*)(.css) 127.0.0.1:8500
edge-stack-devportal-demo /docs/ 127.0.0.1:8500
echo-backend echo.starter-kit.online /echo/ echo.backend
quote-backend quote.starter-kit.online /quote/ quote.backend
You can further explore some of the concepts you learned so far, by following below links:
- Mapping resource:
routes
traffic from theedge
of your cluster to aKubernetes
service - Host resource: sets the
hostname
by whichAmbassador Edge Stack
will be accessed and secured withTLS
certificates.
In the next step, you will learn how to use the DigitalOcean Proxy Protocol
with Ambassador Edge Stack
.
A L4
load balancer replaces the original client IP
with its own IP
address. This is a problem, as you will lose the client IP
visibility in the application, so you need to enable proxy protocol
. Proxy protocol enables a L4 Load Balancer
to communicate the original
client IP
. For this to work, you need to configure both DigitalOcean Load Balancer
and AES
. After deploying the AES Backend Services, and manually enabling the proxy protocol
, you need to configure Ambassador Module
to enable AES
to use the proxy protocol
.
For different DigitalOcean
load balancer configurations, please refer to the examples from the official DigitalOcean Cloud Controller Manager documentation. The Proxy protocol on the DigitalOcean LoadBalancer
needs to be enabled with the following annotations
:
service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol
service.beta.kubernetes.io/do-loadbalancer-tls-passthrough
To enable proxy protocol for AES Backend Services
, you need to run the below steps:
-
Change directory where the
Starter Kit
repository was cloned. -
Edit the
Helm
values file provided in theStarter Kit
repository using an editor of your choice (preferably withYAML
lint support). For example, you can use VS Code:code 03-setup-ingress-controller/assets/manifests/ambassador-values-v7.3.2.yaml
-
Uncomment the
annotations
settings from theservice
section, like in the below example:emissary-ingress: service: type: LoadBalancer annotations: # Enable proxy protocol service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true" # Specify whether the DigitalOcean Load Balancer should pass encrypted data to backend droplets service.beta.kubernetes.io/do-loadbalancer-tls-passthrough: "true"
Note:
You must NOT create a load balancer with
Proxy
support by using theDigitalOcean
web console, as any setting done outsideDOKS
is automaticallyoverridden
by DOKSreconciliation
. -
Save the values file and apply changes using
Helm
:HELM_CHART_VERSION="7.3.2" helm upgrade edge-stack datawire/edge-stack --version "$HELM_CHART_VERSION" \ --namespace ambassador \ -f "03-setup-ingress-controller/assets/manifests/ambassador-values-v${HELM_CHART_VERSION}.yaml"
-
Open and inspect the
03-setup-ingress-controller/assets/manifests/ambassador/ambassador_listener.yaml
file provided in theStarter Kit
repository, using an editor of your choice (preferably withYAML
lint support). For example, you can use VS Code:code 03-setup-ingress-controller/assets/manifests/ambassador/ambassador_listener.yaml
-
In the
spec
section, you will need to comment out theprotocol
field and enable theprotocolStack
for bothlisteners
, like in the example below:... spec: port: 8080 # protocol: HTTPS protocolStack: - PROXY - HTTP - TCP ... spec: port: 8443 # protocol: HTTPS protocolStack: - PROXY - TLS - HTTP - TCP ...
-
Finally, save the file and apply the manifest.
kubectl apply -f 03-setup-ingress-controller/assets/manifests/ambassador/ambassador_listener.yaml
-
Test the echo service via curl (notice that your Public IP will be present in
X-Forwarded-For
andX-Envoy-External-Address
headers):curl -Li https://echo.starter-kit.online/echo/
echo/ main! HTTP/1.1 200 OK content-type: text/plain date: Thu, 23 Dec 2021 10:16:18 GMT content-length: 356 x-envoy-upstream-service-time: 0 server: envoy Request served by echo-5d8d65c665-8spcr HTTP/1.1 GET / Host: echo.starter-kit.online X-Envoy-Original-Path: /echo/ Content-Length: 0 User-Agent: curl/7.77.0 X-Forwarded-Proto: https X-Request-Id: 51e37d36-b810-4c77-8f65-e4f99f5d6b37 Accept: */* X-Forwarded-For: 79.119.116.72 X-Envoy-External-Address: 79.119.116.72 X-Envoy-Expected-Rq-Timeout-Ms: 3000
In the next step, you will test the AES
mappings configuration, and perform HTTP
requests on the backend services using curl
.
In the current setup, you have two hosts configured with TLS
termination: quote.starter-kit.online
and echo.starter-kit.online
. By creating AES Mappings
it's very easy to have TLS
termination support and API Gateway
capabilities.
If pinging quote.starter-kit.online
or echo.starter-kit.online
in the terminal, you can see that packets are being sent to the AES
external IP
. Then, AES
is using the mapping feature to reach the endpoints. Next, you're going to verify if service mappings are working.
First, inspect the Ambassador
services:
kubectl get svc -n ambassador
The output looks similar to:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
edge-stack LoadBalancer 10.245.39.13 68.183.252.190 80:31499/TCP,443:30759/TCP 2d8h
edge-stack-admin ClusterIP 10.245.68.14 <none> 8877/TCP,8005/TCP 2d8h
edge-stack-redis ClusterIP 10.245.9.81 <none> 6379/TCP 2d8h
Next, ping
the quote
service host:
ping quote.starter-kit.online
The output looks similar to the following (notice that it hits the AES
external IP: 68.183.252.190
):
PING quote.starter-kit.online (68.183.252.190): 56 data bytes
64 bytes from 68.183.252.190: icmp_seq=0 ttl=54 time=199.863 ms
64 bytes from 68.183.252.190: icmp_seq=1 ttl=54 time=202.999 ms
...
Now, verify the quote
backend service response using curl
:
curl -Li http://quote.starter-kit.online/quote/
The output looks similar to (notice how it automatically redirects, and is using https
instead):
HTTP/1.1 301 Moved Permanently
location: https://quote.starter-kit.online/quote/
date: Thu, 12 Aug 2021 18:28:43 GMT
server: envoy
content-length: 0
HTTP/1.1 200 OK
content-type: application/json
date: Thu, 12 Aug 2021 18:28:43 GMT
content-length: 167
x-envoy-upstream-service-time: 0
server: envoy
{
"server": "avaricious-blackberry-5xw0vf5k",
"quote": "The last sentence you read is often sensible nonsense.",
"time": "2021-08-12T18:28:43.861400709Z"
}
Finally, please do the same for the echo
service:
curl -Li http://echo.starter-kit.online/echo/
The output looks similar to (notice how it automatically redirects, and is using https
instead):
HTTP/1.1 301 Moved Permanently
location: https://echo.starter-kit.online/echo/
date: Thu, 12 Aug 2021 18:31:27 GMT
server: envoy
content-length: 0
HTTP/1.1 200 OK
content-type: text/plain
date: Thu, 12 Aug 2021 18:31:28 GMT
content-length: 331
x-envoy-upstream-service-time: 0
server: envoy
Request served by echo-5d5bdf99cf-cq8nh
HTTP/1.1 GET /
Host: echo.starter-kit.online
X-Forwarded-Proto: https
X-Envoy-Internal: true
X-Request-Id: 07afec17-4535-4157-bf5f-ad19dafb7bff
Content-Length: 0
X-Forwarded-For: 10.106.0.3
User-Agent: curl/7.64.1
Accept: */*
X-Envoy-Expected-Rq-Timeout-Ms: 3000
X-Envoy-Original-Path: /echo/
Given that proxy protocol
is configured, you should see the original client IP
in the https request header
as well.
If everything looks like above, you configured the Ambassador Edge Stack
successfully.
- Setting up Ingress to use Wildcard Certificates
- Ingress Controller LoadBalancer Migration
- Performance Considerations for the Ambassador Edge Stack
In this tutorial you learned how to set up an Ingress Controller
for your DOKS
cluster using the Ambassador Edge Stack
. Then, you discovered how AES
simplifies some of the common tasks, like: handling TLS
certificates for your applications (thus enabling TLS
termination), routing
traffic to backend
services, and adjusting
resource requests
and limits
for the stack.
Next, observability
plays a key role in every production ready
system. In Section 4 - Set up Observability, you will learn how to enable monitoring for your DOKS
cluster using Prometheus
.