3 min • read

Install with bare metal

In cloud environments, provisioning a readily available network load balancer with Emissary-ingress is the best option for handling ingress into your Kubernetes cluster. When running Kubernetes on a bare metal setup, where network load balancers are not available by default, we need to consider different options for exposing Emissary-ingress.

Exposing Emissary-ingress via NodePort

The simplest way to expose an application in Kubernetes is via a NodePort service. In this configuration, we create the Emissary-ingress service] and identify type: NodePort instead of LoadBalancer. Kubernetes will then create a service and assign that service a port to be exposed externally and direct traffic to Emissary-ingress via the defined port.

yaml
---
apiVersion: v1
kind: Service
metadata:
name: ambassador
spec:
type: NodePort
ports:
- name: http
port: 8088
targetPort: 8080
nodePort: 30036 # Optional: Define the port you would like exposed
protocol: TCP
selector:
service: ambassador

Using a NodePort leaves Emissary-ingress isolated from the host network, allowing the Kubernetes service to handle routing to Emissary-ingress pods. You can drop-in this YAML to replace the LoadBalancer service in the YAML installation guide and use http://<External-Node-IP>:<NodePort>/ as the host for requests.

Exposing Emissary-ingress via host network

When running Emissary-ingress on a bare metal install of Kubernetes, you have the option to configure Emissary-ingress pods to use the network of the host they are running on. This method allows you to bind Emissary-ingress directly to port 80 or 443 so you won't need to identify the port in requests.

i.e http://<External-Node-IP>:<NodePort>/ becomes http://<External-Node-IP>/

This can be configured by setting hostNetwork: true in the Emissary-ingress deployment. dnsPolicy: ClusterFirstWithHostNet will also need to set to tell Emissary-ingress to use KubeDNS when attempting to resolve mappings.

diff
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ambassador
spec:
replicas: 1
selector:
matchLabels:
service: ambassador
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
labels:
service: ambassador
app.kubernetes.io/managed-by: getambassador.io
spec:
+ hostNetwork: true
+ dnsPolicy: ClusterFirstWithHostNet
serviceAccountName: ambassador
containers:
- name: ambassador
image: docker.io/datawire/ambassador:2.3.1
resources:
limits:
cpu: 1
memory: 400Mi
requests:
cpu: 200m
memory: 100Mi
env:
- name: AMBASSADOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
livenessProbe:
httpGet:
path: /ambassador/v0/check_alive
port: 8877
initialDelaySeconds: 30
periodSeconds: 3
readinessProbe:
httpGet:
path: /ambassador/v0/check_ready
port: 8877
initialDelaySeconds: 30
periodSeconds: 3
restartPolicy: Always

This configuration does not require a defined Emissary-ingress service, so you can remove that service if you have defined one.

Note: Before configuring Emissary-ingress with this method, consider some of the functionality that is lost by bypassing the Kubernetes service including only having one Emissary-ingress able to bind to port 8080 or 8443 per node and losing any load balancing that is typically performed by Kubernetes services.