Control Ingress Traffic
In a Kubernetes environment, the Kubernetes Ingress Resource
is used to specify services that should be exposed outside the cluster.
In an Istio service mesh, a better approach (which also works in both Kubernetes and other environments) is to use a
different configuration model, namely Istio Gateway.
A Gateway
allows Istio features such as monitoring and route rules to be applied to traffic entering the cluster.
This task describes how to configure Istio to expose a service outside of the service mesh using an Istio Gateway
.
Before you begin
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 have enabled automatic sidecar injection, deploy the
httpbin
service:$ kubectl apply -f @samples/httpbin/httpbin.yaml@
Otherwise, you have to manually inject the sidecar before deploying the
httpbin
application:$ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@)
Determine the ingress IP and ports as described in the following subsection.
Determining the ingress IP and ports
Execute the following command to determine if your Kubernetes cluster is running in an environment that supports external load balancers:
$ kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.21.109.129 130.211.10.121 80:31380/TCP,443:31390/TCP,31400:31400/TCP 17h
If the EXTERNAL-IP
value is set, your environment has an external load balancer that you can use for the ingress gateway.
If the EXTERNAL-IP
value is <none>
(or perpetually <pending>
), your environment does not provide an external load balancer for the ingress gateway.
In this case, you can access the gateway using the service's node port.
Depending on your environment, follow the instructions in one of the following mutually exclusive subsections.
Determining the ingress IP and ports when using an external load balancer
Follow these instructions if you have determined that your environment does have an external load balancer.
Set the ingress IP and ports:
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
Note that in certain environments, the load balancer may be exposed using a host name, instead of an IP address.
In this case, the EXTERNAL-IP
value in the output from the command in the previous section will not be an IP address,
but rather a host name, and the above command will have failed to set the INGRESS_HOST
environment variable. In this case, use the following command to correct the INGRESS_HOST
value:
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
Determining the ingress IP and ports when using a node port
Follow these instructions if you have determined that your environment does not have an external load balancer.
Set the ingress ports:
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
Setting the ingress IP depends on the cluster provider:
GKE:
$ export INGRESS_HOST=<workerNodeAddress>
You need to create firewall rules to allow the TCP traffic to the ingressgateway service's ports. Run the following commands to allow the traffic for the HTTP port, the secure port (HTTPS) or both:
$ gcloud compute firewall-rules create allow-gateway-http --allow tcp:$INGRESS_PORT $ gcloud compute firewall-rules create allow-gateway-https --allow tcp:$SECURE_INGRESS_PORT
IBM Cloud Kubernetes Service Free Tier:
$ bx cs workers <cluster-name or id> $ export INGRESS_HOST=<public IP of one of the worker nodes>
Minikube:
$ export INGRESS_HOST=$(minikube ip)
Other environments (e.g., IBM Cloud Private etc):
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o 'jsonpath={.items[0].status.hostIP}')
Configuring ingress using an Istio Gateway
An ingress Gateway describes a load balancer operating at the edge of the mesh that receives incoming HTTP/TCP connections. It configures exposed ports, protocols, etc. but, unlike Kubernetes Ingress Resources, does not include any traffic routing configuration. Traffic routing for ingress traffic is instead configured using Istio routing rules, exactly in the same was as for internal service requests.
Let's see how you can configure a Gateway
on port 80 for HTTP traffic.
Create an Istio
Gateway
:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: httpbin-gateway spec: selector: istio: ingressgateway # use Istio default gateway implementation servers: - port: number: 80 name: http protocol: HTTP hosts: - "httpbin.example.com" EOF
Configure routes for traffic entering via the
Gateway
:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: httpbin spec: hosts: - "httpbin.example.com" gateways: - httpbin-gateway http: - match: - uri: prefix: /status - uri: prefix: /delay route: - destination: port: number: 8000 host: httpbin EOF
You have now created a virtual service configuration for the
httpbin
service containing two route rules that allow traffic for paths/status
and/delay
.The gateways list specifies that only requests through your
httpbin-gateway
are allowed. All other external requests will be rejected with a 404 response.Note that in this configuration, internal requests from other services in the mesh are not subject to these rules but instead will default to round-robin routing. To apply these or other rules to internal calls, you can add the special value
mesh
to the list ofgateways
.Access the httpbin service using curl:
$ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/status/200 HTTP/1.1 200 OK server: envoy date: Mon, 29 Jan 2018 04:45:49 GMT content-type: text/html; charset=utf-8 access-control-allow-origin: * access-control-allow-credentials: true content-length: 0 x-envoy-upstream-service-time: 48
Note that you use the
-H
flag to set the Host HTTP Header to “httpbin.example.com”. This is needed because your ingressGateway
is configured to handle “httpbin.example.com”, but in your test environment you have no DNS binding for that host and are simply sending your request to the ingress IP.Access any other URL that has not been explicitly exposed. You should see an HTTP 404 error:
$ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/headers HTTP/1.1 404 Not Found date: Mon, 29 Jan 2018 04:45:49 GMT server: envoy content-length: 0
Accessing ingress services using a browser
Entering the httpbin
service URL in a browser won't work because you can't tell the browser to pretend to be accessing httpbin.example.com
like with curl
. In a real world situation, this is not a problem because because you configure the requested host properly and DNS resolvable. Thus, you use the host's domain name in the URL, for example, https://httpbin.example.com/status/200
.
To work around this problem for simple tests and demos, use a wildcard *
value for the host in the Gateway
and VirutualService
configurations. For example, if you change your ingress configuration to the following:
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /headers
route:
- destination:
port:
number: 8000
host: httpbin
EOF
You can then use $INGRESS_HOST:$INGRESS_PORT
(e.g., 192.168.99.100:31380
) in the browser URL. For example, http://192.168.99.100:31380/headers
should display the request headers sent by your browser.
Understanding what happened
The Gateway
configuration resources allow external traffic to enter the
Istio service mesh and make the traffic management and policy features of Istio
available for edge services.
In the preceding steps, you created a service inside the service mesh and exposed an HTTP endpoint of the service to external traffic.
Cleanup
Delete the Gateway
configuration, the VirtualService
and the secret, and shutdown the httpbin service:
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@
See also
Deploy a custom ingress gateway using cert-manager
Describes how to deploy a custom ingress gateway using cert-manager manually.
Configuring Istio Ingress with AWS NLB
Describes how to configure Istio ingress with a network load balancer on AWS.
Describes how to configure Istio to expose a service outside of the service mesh, over TLS, mutual TLS or JWT authentication.
Incremental Istio Part 1, Traffic Management
How to use Istio for traffic management without deploying sidecar proxies.
Introducing the Istio v1alpha3 routing API
Introduction, motivation and design principles for the Istio v1alpha3 routing API.
Traffic Mirroring with Istio for Testing in Production
An introduction to safer, lower-risk deployments and release to production.