This task describes how to configure Istio to expose a service outside of the service mesh cluster. In a Kubernetes environment, the Kubernetes Ingress Resources allows users to specify services that should be exposed outside the cluster. However, the Ingress Resource specification is very minimal, allowing users to specify just hosts, paths and their backing services. The following are the known limitations of Istio ingress:
ingress.kubernetes.io
annotations in the Ingress resource specifications. Any annotation other than kubernetes.io/ingress.class: istio
will be ignored.Setup Istio by following the instructions in the Installation guide.
Make sure your current directory is the istio
directory.
Start the httpbin sample, which will be used as the destination service to be exposed externally.
If you installed the Istio-Initializer, do
kubectl apply -f samples/httpbin/httpbin.yaml
Without the Istio-Initializer:
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml)
Create a basic Ingress Resource for the httpbin service
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: simple-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
rules:
- http:
paths:
- path: /status/.*
backend:
serviceName: httpbin
servicePort: 8000
EOF
/.*
is a special Istio notation that is used to indicate a prefix match, specifically a rule match configuration of the form (prefix: /
).
Determine the ingress URL:
If your cluster is running in an environment that supports external load balancers, use the ingress’ external address:
kubectl get ingress simple-ingress -o wide
NAME HOSTS ADDRESS PORTS AGE
simple-ingress * 130.211.10.121 80 1d
export INGRESS_HOST=130.211.10.121
If load balancers are not supported, use the ingress controller pod’s hostIP:
kubectl -n istio-system get po -l istio=ingress -o jsonpath='{.items[0].status.hostIP}'
169.47.243.100
along with the istio-ingress service’s nodePort for port 80:
kubectl -n istio-system get svc istio-ingress
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingress 10.10.10.155 <pending> 80:31486/TCP,443:32254/TCP 32m
export INGRESS_HOST=169.47.243.100:31486
Access the httpbin service using curl:
curl -I http://$INGRESS_HOST/status/200
HTTP/1.1 200 OK
Server: meinheld/0.6.1
Date: Thu, 05 Oct 2017 21:23:17 GMT
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.00105214118958
Content-Length: 0
Via: 1.1 vegur
Connection: Keep-Alive
Access any other URL that has not been explicitly exposed. You should see a HTTP 403
curl -I http://$INGRESS_HOST/headers
HTTP/1.1 403 FORBIDDEN
Server: meinheld/0.6.1
Date: Thu, 05 Oct 2017 21:24:47 GMT
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.000759840011597
Content-Length: 0
Via: 1.1 vegur
Connection: Keep-Alive
Generate keys if necessary
A private key and certificate can be created for testing using OpenSSL.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=foo.bar.com"
Update the secret using kubectl
kubectl create -n istio-system secret tls istio-ingress-certs --key /tmp/tls.key --cert /tmp/tls.crt
Create the Ingress Resource for the httpbin service
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: secure-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
tls:
- secretName: istio-ingress-certs # currently ignored
rules:
- http:
paths:
- path: /status/.*
backend:
serviceName: httpbin
servicePort: 8000
- path: /delay/.*
backend:
serviceName: httpbin
servicePort: 8000
EOF
Set the INGRESS_HOST to point to the ip address and the port number of the ingress service as shown earlier.
Note: Envoy currently only allows a single TLS secret in the ingress since SNI is not yet supported. That means that the secret name field in ingress resource is not used, and the secret must be called
istio-ingress-certs
inistio-system
namespace.
Access the secured httpbin service using curl:
curl -I -k https://$INGRESS_HOST/status/200
Istio’s routing rules can be used to achieve a greater degree of control when routing requests to backend services. For example, the following route rule sets a 4s timeout for all calls to the httpbin service on the /delay URL.
cat <<EOF | istioctl create -f -
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: status-route
spec:
destination:
name: httpbin
match:
# Optionally limit this rule to istio ingress pods only
source:
name: istio-ingress
labels:
istio: ingress
request:
headers:
uri:
prefix: /delay/ #must match the path specified in ingress spec
# if using prefix paths (/delay/.*), omit the .*.
# if using exact match, use exact: /status
route:
- weight: 100
httpReqTimeout:
simpleTimeout:
timeout: 4s
EOF
If you were to make a call to the ingress with the URL http://$INGRESS_HOST/delay/10
, you will find that the call returns in 4s instead of the expected 10s delay.
You can use other features of the route rules such as redirects, rewrites, routing to multiple versions, regular expression based match in HTTP headers, websocket upgrades, timeouts, retries, etc. Please refer to the routing rules for more details.
Note 1: Fault injection does not work at the Ingress
Note 2: When matching requests in the routing rule, use the same exact path or prefix as the one used in the Ingress specification.
Ingresses provide gateways for external traffic to enter the Istio service mesh and make the traffic management and policy features of Istio available for edge services.
The servicePort field in the Ingress specification can take a port number (integer) or a name. The port name must follow the Istio port naming conventions (e.g., grpc-*
, http2-*
, http-*
, etc.) in order to function properly. The name used must match the port name in the backend service declaration.
In the preceding steps we created a service inside the Istio service mesh and showed how to expose both HTTP and HTTPS endpoints of the service to external traffic. We also showed how to control the ingress traffic using an Istio route rule.
Remove the secret and Ingress Resource definitions.
kubectl delete ingress simple-ingress secure-ingress
kubectl delete -n istio-system secret istio-ingress-certs
Shutdown the httpbin service.
kubectl delete -f samples/httpbin/httpbin.yaml
Learn more about Ingress Resources.
Learn more about Routing Rules.