Lab 2b: Advanced Kubernetes
Ingress
Kubernetes Ingress manages external access to services in a cluster, typically over HTTP and HTTPS. It provides features such as load balancing, SSL termination and name-based routing.
Install Ingress Controller
An Ingress resource requires an Ingress Controller deployed in your cluster to function. One very common controller is the NGINX ingress controller.
Warning
The following instruction installs the NGINX ingress controller only in minikube.
Create an Ingress Resource
Start by creating and applying the following Ingress resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wikijs-ingress
spec:
rules:
- host: wikijs.cluster.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wiki-svc
port:
number: 3000
The configuration above routes traffic from "wikijs.cluster.org" to the wiki-svc service, which should be running on port 3000. To see if the ingress has been correctly applied, run:
Warning
The following instruction is needed only in minikube to expose the ingress to your host.
Now navigate to http://127.0.0.1/
Questions 5-6
Question 5
Why you are not seeing the WikiJS page? What can you do to Fix the issue?
Question 6
Your cluster now exposes a NodePort and an Ingress for the same service. Can you think about some reasons why this is considered a bad practice? Which other service type would you use in this case?
Use NetworkPolicy resources
Network policies in Kubernetes are managed by the CNI. The basic resource (compatible with all CNIs) is the NetworkPolicy.
By default, everything is allowed in Kubernetes. A default-deny policy looks like:
# policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Apply the policy and check Internet connectivity from test container e.g.,:
You should not be allowed to ping the google website.
Question 7
Create a new namespace called test and install the ubuntu test container in this namespace. Can the container ping google.com ?
To remove the policy run:
Question 8
Create a NetworkPolicy that allows WikiJS to receive connections from every Pod but prevents it to initiate connections. Also WikiJS should not be able to connect to the Internet. Provide the YAML content of the policy.
The Sidecar pattern in Kubernetes
The following is a Kubernetes application that deploys a Wordpress website and a database for storing its content.
First, we need to delete all the resources from the previous step.
This can be done either by deleting each resource by name: e.g., kubectl delete service/wiki-svc or by destroying and re-creating the cluster. See Delete Minikube.
# wordpress.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:lts
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
- name: MYSQL_DATABASE
value: "wordpress"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress:latest
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: "mysql-service"
- name: WORDPRESS_DB_USER
value: "root"
- name: WORDPRESS_DB_PASSWORD
value: "password"
- name: WORDPRESS_DB_NAME
value: "wordpress"
volumeMounts:
- name: wordpress-storage
mountPath: /var/www/html
volumes:
- name: wordpress-storage
persistentVolumeClaim:
claimName: wordpress-pvc
---
apiVersion: v1
kind: Service
metadata:
name: wordpress-service
spec:
selector:
app: wordpress
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
Exercise 9
We want to add a sidecar proxy container (nginx) named logs-proxy that listens to port 8080. This sidecar forwards each request to the Wordpress container and prints each request to the STDOUT in JSON format. In this exercise you will provide the updated wordpress.yaml file.
graph LR
A[User] --> B[Wordpress Service]
B --> |8080| C[logs-proxy]
C -->|80| D[Wordpress]
D -->A
Warning
Do not provide screenshots of the file. Only text will be considered for the submission of this exercise.
Tip
You can use the ConfigMap resource to add configuration files to a Pod. See the Kubernetes documentation.
Service Mesh in Kubernetes
We will use Istio as a service mesh in this lab.
1. Install Istio
First install and download Istio using the official instructions.
Warning
You do not have to follow the entire tutorial from the istio website, just install Istio.
2. Run the tutorial
Run the bookinfo tutorial on the Istio website and answer the following questions:
Questions
Question 10
Does Istio - in the current configuration - allow pod-to-pod communication and is the communication secure? Explain your reasoning and commands you use to verify that.
Tip
You can use the kubectl exec -it <podname> -- bash command in some of the containers to get a shell.
Question 11
Look at the pods and containers installed by Istio. Where are the sidecar containers installed? Which commands are executed?
Tip
You can inspect the content of a Pod using the kubectl describe <podname> command.
3. Deep dive in Istio and service mesh concepts.
It is possibe to enable mTLS in Istio to encrypt and secure traffic between applications. Specifically it allows both PERMISSIVE and STRICT mode.
Question 12
Enable mTLS first in PERMISSIVE and then in STRICT mode. Does Istio - in each of the configuration - allow pod-to-pod communication and is the communication secure? Explain your reasoning and commands you use to verify. Then, draw a conclusion about the security of Istio depending on the settings that are used.
Introduction to Helm
Helm is a package manager and template engine for Kubernetes that allows to easily manage applications. Helm applications are called charts and they are collection of files that describe Kubernetes resources.
Why Helm ?
Some of the reasons that make Helm a popular solution are:
- Easy Deployment: A single command can install complex applications
- Version Control: Helm charts can be versioned, allowing you to roll back to previous versions of your application if needed.
- Reusability: Helm charts can be reused across different environments, ensuring consistency in deployments.
Helm Tutorials
We suggest you to follow the official quickstart guide for Helm.
Helm chart for WikiJS
A Helm chart lets you package the WikiJS Deployment, Service, and (optional) Ingress into a single, reusable artifact. Users can install the chart with one command and tweak parameters via values.yaml (to e.g., edit the exposed ports or application configuration).
Chart layout (Create the layout under charts/wiki-js/)
Creat the chart's scheleton by running: helm create wiki-js. The tool should generate the following set of files:
wiki-js
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
Here are some examples of files you can edit to effectively install the app on Kubernetes:
Chart.yaml
apiVersion: v2
name: wiki-js
description: A Helm chart for deploying WikiJS on Kubernetes
type: application
version: 0.1.0
appVersion: "2.5"
values.yaml
replicaCount: 3
image:
repository: lscr.io/linuxserver/wikijs
tag: latest
pullPolicy: IfNotPresent
service:
type: NodePort
port: 3000
nodePort: 30080
ingress:
enabled: true
host: wikijs.local
tls: false
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "wiki-js.fullname" . }}
labels:
{{- include "wiki-js.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "wiki-js.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "wiki-js.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: wikijs
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "wiki-js.fullname" . }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "wiki-js.selectorLabels" . | nindent 4 }}
ports:
- protocol: TCP
port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
{{- if eq .Values.service.type "NodePort" }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}
templates/ingress.yaml (enabled when ingress.enabled is true)
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "wiki-js.fullname" . }}
spec:
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "wiki-js.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}
Render the chart
Rendering the chart means interpolating the YAML templates with the values provided in values.yaml to produce Kubernetes mannifests.
Render the chart to see the generated manifests (optional):
Install the chart with default values:
Verify the deployment: