Service has only 4 Layers (iptables, ipvs have 4 layers), which means, it can only work on TCP/IP Layer or the 4. Layer of ISO/OSI Model. If client need to send application a https request, where should we put the SSL certificate for https?
The answer is Ingress Controller, for this there are three options:
- Nginx
- Traefik
- Envoy
How Ingress works:
1 Install Ingress Controller
for installation see at: https://github.com/kubernetes/ingress-nginx/tree/master/deploy
for file in namespace.yaml configmap.yaml rbac.yaml with-rbac.yaml mandatory.yaml; do wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/$file; done
First of all we need a new namespace for Ingress-Controller:
kubectl apply -f namespace.yaml
This commnd will create a new namespace with name ingress-nginx
Then the rest services:
[root@k8smaster ingress-nginx]# kubectl apply -f .
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
namespace/ingress-nginx unchanged
configmap/nginx-configuration unchanged
configmap/tcp-services unchanged
configmap/udp-services unchanged
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
namespace/ingress-nginx unchanged
serviceaccount/nginx-ingress-serviceaccount unchanged
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole unchanged
role.rbac.authorization.k8s.io/nginx-ingress-role unchanged
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding unchanged
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding unchanged
deployment.apps/nginx-ingress-controller unchanged
[root@k8smaster ingress-nginx]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-6f84777694-59xpv 1/1 Running 0 1m
We want to use Ingress to provide service also to external client. In order to do this, we need one more Service - NodePort (Installation reference also see: https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal)
In this example it doesn't mention on which port this service should exposed. We will define it by ourself:
apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx
As you see nodePort: 30080 and 30443 are new defined by us! Then deploy this service
root@k8smaster ingress-nginx]# kubectl apply -f service-nodeport.yaml service/ingress-nginx created
[root@k8smaster ingress-nginx]# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.103.72.25 <none> 80:30080/TCP,443:30443/TCP 16s
Now we have a Ingress controller up and running.
2. Perform a handson with Ingress
For this Handson I'm gonna to create a deployment with 3 replicas and a Service, which forward service 80 to container port 80. After this I create a new Ingress-Service and assign it to Service myapp-svc. With Host myapp.crazy-chinese.com I can access the myapp-svc and finnaly reach the backend pods (deployment myapp-deployment).
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-myapp annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - host: myapp.crazy-chinese.com http: paths: - backend: serviceName: myapp-svc servicePort: 80 --- apiVersion: v1 kind: Service metadata: name: myapp-svc namespace: default spec: selector: app: myapp release: canary ports: - name: http port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp-container image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80
Then apply the template you can see:
[root@k8smaster ingress]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE myapp-deployment-f5f97bb54-2mpqg 1/1 Running 0 15m 10.244.1.66 k8snode1 myapp-deployment-f5f97bb54-gjmz7 1/1 Running 0 15m 10.244.2.50 k8snode2 myapp-deployment-f5f97bb54-zjz6r 1/1 Running 0 15m 10.244.1.65 k8snode1
[root@k8smaster ingress]# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24d <none> myapp-svc ClusterIP 10.98.111.57 <none> 80/TCP 15m app=myapp,release=canary [root@k8smaster ingress]# kubectl get ingress NAME HOSTS ADDRESS PORTS AGE ingress-myapp myapp.crazy-chinese.com 80 15m
Because of host myapp.crazy-chinese.com is still unknow on my client machine. I must add this to my /etc/hosts file.
127.0.0.1 localhost 127.0.1.1 bai 172.16.0.11 k8smaster 172.16.0.12 k8snode1 myapp.crazy-chinese.com 172.16.0.13 k8snode2 myapp.crazy-chinese.com
Now I open my web browser and tipp http://myapp.crazy-chinese.com:30080
it shows me, that I can reach my application backend!
3 Create Certificat for HTTPS
We want create and sign a certificat for https request:
[root@k8smaster ingress]# openssl genrsa -out tls.key 2048 Generating RSA private key, 2048 bit long modulus ..........+++ ....+++ e is 65537 (0x10001) [root@k8smaster ingress]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Munich/L=Munich/O=DevOps/CN=tomcat.crazy-chinese.com [root@k8smaster ingress]# ll total 16-rw-r--r-- 1 root root 1310 Jan 27 07:17 tls.crt -rw-r--r-- 1 root root 1679 Jan 27 07:16 tls.key
[root@k8smaster ingress]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key secret/tomcat-ingress-secret created
[root@k8smaster ingress]# kubectl get secret
NAME TYPE DATA AGE
default-token-rxs5t kubernetes.io/service-account-token 3 24d
tomcat-ingress-secret kubernetes.io/tls 2 1m
[root@k8smaster ingress]# kubectl describe secret tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1310 bytes
tls.key: 1679 bytes
Add following template to create deployment, service and ingress for tomcat application and enable tls certificate:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-tomcat-tls annotations: kubernetes.io/ingress.class: "nginx" spec: tls: - hosts: - tomcat.crazy-chinese.com - secretName: tomcat-ingress-secret rules: - host: tomcat.crazy-chinese.com http: paths: - backend: serviceName: tomcat-svc servicePort: 8080 --- apiVersion: v1 kind: Service metadata: name: tomcat-svc namespace: default spec: selector: app: tomcat release: canary ports: - name: http port: 8080 targetPort: 8080 - name: ajp port: 8009 targetPort: 8009 --- apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: tomcat release: canary template: metadata: labels: app: tomcat release: canary spec: containers: - name: tomcat-container image: tomcat:8.5.32-jre8-alpine ports: - name: http containerPort: 8080 - name: ajp containerPort: 8009
We see in host option, we specified tomcat.crazy-chinese.com als url, which should be encripted by using spec.tls.hosts
With spec.tls.secretname we can specifiy the name of tls certificate.
After this create the service, we can use https://tomcat.crazy-chinese.com:30443/ to visit tomcat default page...