This document shows how to create a Kubernetes Ingress object in a user, hybrid, or standalone cluster for Google Distributed Cloud. An Ingress is associated with one or more Services, each of which is associated with a set of Pods.
Create a Deployment
Use the following steps to create a Deployment:
Create a Deployment manifest:
apiVersion: apps/v1 kind: Deployment metadata: name: hello-deployment spec: selector: matchLabels: greeting: hello replicas: 3 template: metadata: labels: greeting: hello spec: containers: - name: hello-world image: "gcr.io/google-samples/hello-app:2.0" env: - name: "PORT" value: "50000" - name: hello-kubernetes image: "gcr.io/google-samples/node-hello:1.0" env: - name: "PORT" value: "8080"For the purpose of this exercise, these are the important points to understand about the Deployment manifest:
Each Pod that belongs to the Deployment has the
greeting: hellolabel.Each Pod has two containers.
The
envfields specify that thehello-appcontainers listen on TCP port 50000, and thenode-hellocontainers listen on TCP port 8080. Forhello-app, you can see the effect of thePORTenvironment variable by looking at the source code.
Copy the manifest to a file named
hello-deployment.yaml.Create the Deployment:
kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-deployment.yamlReplace
CLUSTER_KUBECONFIGwith the name of the kubeconfig file for your cluster.
Expose your Deployment with a Service
To provide a stable way for clients to send requests to the Pods of your Deployment, create a Service:
Create a Service manifest that exposes your Deployment to clients inside your cluster:
apiVersion: v1 kind: Service metadata: name: hello-service spec: type: ClusterIP selector: greeting: hello ports: - name: world-port protocol: TCP port: 60000 targetPort: 50000 - name: kubernetes-port protocol: TCP port: 60001 targetPort: 8080Copy the manifest to a file named
hello-service.yaml.Create the Service:
kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yamlReplace
CLUSTER_KUBECONFIGwith the name of the kubeconfig file for your cluster.View the Service:
kubectl --kubeconfig CLUSTER_KUBECONFIG get service hello-service --output yamlThe output shows the value of
clusterIPthat has been given to the Service. For example:apiVersion: v1 kind: Service metadata: annotations: ... spec: clusterIP: 10.96.14.249 clusterIPs: - 10.96.14.249 ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - name: world-port port: 60000 protocol: TCP targetPort: 50000 - name: kubernetes-port port: 60001 protocol: TCP targetPort: 8080 selector: greeting: hello sessionAffinity: None type: ClusterIP status: loadBalancer: {}In the preceding output, the
portsfield is an array ofServicePortobjects: one namedworld-portand one namedkubernetes-port. For more information about the Service fields, see ServiceSpec in the Kubernetes documentation.These are the ways a client can call the Service:
Using
world-port: A client running on one of the cluster nodes sends a request to theclusterIPonport(such as10.96.14.249:60000). The ingress controller forwards the request to a member Pod ontargetPort(such asPOD_IP_ADDRESS:50000, wherePOD_IP_ADDRESSis the IP address of a member Pod).Using
kubernetes-port: A client running on one of the cluster nodes sends a request to theclusterIPonport(10.96.14.249:60001). The ingress controller forwards the request to a member Pod ontargetPort(POD_IP_ADDRESS:8080).
Ingress components
These are some of the cluster components related to ingress:
The
istio-ingressDeployment. This is the ingress proxy. The ingress proxy forwards traffic to internal Services according to rules specified in an Ingress object.The
istio-ingressService. This Service exposes theistio-ingressDeployment.The
istiodDeployment. This is the ingress controller. The ingress controller watches the creation of Ingress objects and configures the ingress proxy accordingly.
All of these Istio in-cluster components are installed in the gke-system
namespace. This namespace doesn't conflict with a full Istio/Cloud Service Mesh
installation.
Create an Ingress
Use the following steps to create an Ingress:
Create an Ingress manifest:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: rules: - http: paths: - path: /greet-the-world pathType: Exact backend: service: name: hello-service port: number: 60000 - path: /greet-kubernetes pathType: Exact backend: service: name: hello-service port: number: 60001Copy the manifest to a file named
my-ingress.yaml.Create the Ingress:
kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress.yaml
When you create a user cluster, you specify a value for
loadbalancer.ingressVIP in the cluster configuration file. This IP address is
configured on the cluster load balancer. When you create an Ingress, the Ingress
is given this same VIP as its external IP address.
When a client sends a request to your user cluster ingress VIP, the request is
routed to your load balancer. The load balancer uses the istio-ingress Service
to forward the request to the ingress proxy, which runs in your user cluster.
The ingress proxy forwards the request to different backends depending on the
path in the request URL.
The /greet-the-world path
In your Ingress manifest, you can see a rule that says the path
/greet-the-world is associated with serviceName: hello-service and
servicePort: 60000. Recall that 60000 is the port value in the world-port
section of your hello-service Service.
- name: world-port
port: 60000
protocol: TCP
targetPort: 50000
The ingress Service forwards the request to clusterIP:50000. The request then
goes to one of the member Pods of the hello-service Service. The container, in
that Pod, listening on port 50000 displays a Hello World! message.
The /greet-kubernetes path
In your Ingress manifest, you can see a rule that says the path
/greet-kubernetes is associated with serviceName: hello-service and
servicePort: 60001. Recall that 60001 is the port value in the
kubernetes-port section of your hello-service Service.
- name: kubernetes-port
port: 60001
protocol: TCP
targetPort: 8080
The ingress Service forwards the request to clusterIP: 8080. The request then
goes to one of the member Pods of the hello-service Service. The container in
that Pod, listening on port 8080, displays a Hello Kubernetes! message.
Test the Ingress
Test the Ingress using the
/greet-the-worldpath:curl CLUSTER_INGRESS_VIP/greet-the-worldReplace
CLUSTER_INGRESS_VIPwith the external IP address of the Ingress.The output shows a
Hello, world!message:Hello, world! Version: 2.0.0 Hostname: ...Test the Ingress using the
/greet-kubernetespath:curl CLUSTER_INGRESS_VIP/greet-kubernetesThe output shows a
Hello, Kubernetes!message:Hello Kubernetes!
Disable bundled Ingress
The Ingress capability bundled with Google Distributed Cloud supports ingress capabilities only. You may choose to integrate with Istio or Cloud Service Mesh. These products offer additional benefits of a fully functional service mesh, such as mutual Transport Layer Security (mTLS), ability to manage authentication between services, and workload observability. If you integrate with Istio or Cloud Service Mesh, we recommend that you disable the bundled Ingress capability.
You can enable or disable bundled Ingress with the
spec.clusterNetwork.bundledIngress field in your cluster configuration file.
This field is available to version 1.13.0 clusters and higher only. The
bundledIngress field defaults to true and isn't present in the generated
cluster configuration file. This field is mutable and can be changed when you
create or update a version 1.13.0 or higher cluster.
To disable the bundled Ingress capability, add the
bundledIngressfield to theclusterNetworksection of your cluster configuration file and set its value to false, as shown in the following example:apiVersion: v1 kind: Namespace metadata: name: cluster-hybrid-basic --- apiVersion: baremetal.cluster.gke.io/v1 kind: Cluster metadata: name: hybrid-basic namespace: cluster-hybrid-basic spec: type: hybrid profile: default anthosBareMetalVersion: 1.13.0 gkeConnect: projectID: project-fleet controlPlane: nodePoolSpec: nodes: - address: 10.200.0.2 clusterNetwork: bundledIngress: false pods: cidrBlocks: - 192.168.0.0/16 services: cidrBlocks: - 10.96.0.0/20 ...
Set up HTTPS for Ingress
If you want to accept HTTPS requests from your clients, the ingress proxy must have a certificate so it can prove its identity to your clients. This proxy must also have a private key to complete the HTTPS handshake.
The following example uses these entities:
Ingress proxy: Participates in the HTTPS handshake, and then forwards packets to member Pods of the
hello-serviceService.Domain for the
hello-serviceService: altostrat.com in Example Org
Follow these steps:
Create a root certificate and private key. This example uses a root certificate authority of
root.ca.example.comin Root CA Example Org.openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \ '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \ -out root-ca.crtCreate a certificate signing request:
openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \ "/CN=altostrat.com/O=Example Org"Create a serving certificate for the ingress proxy.
openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \ -in server.csr -out server.crtYou have now created the following certificates and keys:
root-ca.crt: Certificate for the root CAroot-ca.key: Private key for the root CAserver.crt: Serving certificate for the ingress proxyserver.key: Private key for the ingress proxy
Create a Kubernetes Secret that holds the serving certificate and key.
kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \ --namespace gke-systemThe resulting Secret is named
example-server-creds.
Create a Deployment and Service
If you created a Deployment and a Service in the HTTP portion of this guide, leave those in place. If you did not, create them now, following the steps described for HTTP.
Create an Ingress
Creating an Ingress for HTTPS is similar to creating an Ingress for
HTTP, but the Ingress spec for HTTPS includes a tls section
that specifies the host and a Secret. The hosts in the tls section need to
explicitly match the host in the rules section.
If your backend Service is in a separate namespace, then you need to create a Service of type ExternalName in the same namespace as the Ingress to route traffic to the backend Service.
The overall steps for creating an Ingress for HTTPS or HTTP are the same, except for what you configure in the manifest file:
If you previously created an Ingress in the HTTP portion of this document, delete that Ingress before proceeding.
kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingressTo handle traffic for the Service that you created previously, create a new Ingress manifest that has a
tlssection:The
tlsconfiguration enables HTTPS between clients and the ingress proxy.apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress-2 spec: tls: - hosts: - altostrat.com secretName: example-server-creds rules: - host: altostrat.com http: paths: - path: /greet-the-world pathType: Exact backend: service: name: hello-service port: number: 60000 - path: /greet-kubernetes pathType: Exact backend: service: name: hello-service port: number: 60001Save the manifest in a file named
my-ingress-2.yaml, and create the Ingress:kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yamlConfirm that the Ingress was created and is working properly by testing:
Test the
/greet-the-worldpath:curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \ https://altostrat.com/greet-the-world \ --cacert root-ca.crtOutput:
Hello, world! Version: 2.0.0 Hostname: hello-deployment-5ff7f68854-wqzp7Test the
/greet-kubernetespath:curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \ https://altostrat.com/greet-kubernetes --cacert root-ca.crtOutput:
Hello Kubernetes!
Create a LoadBalancer Service
A Service of type LoadBalancer is another way to expose your workloads outside
of your cluster. For instructions and an example for creating a service of type
LoadBalancer, see
Create a Service of type LoadBalancer in Deploy an application.
Cleaning up
Delete your Ingress:
kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAMEReplace
INGRESS_NAMEwith the name of the Ingress, such asmy-ingressormy-ingress-2.Delete your Service:
kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-serviceDelete your Deployment:
kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deploymentDelete your LoadBalancer Service:
kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports