Ubuntu kubernetes experiment notes
Setup locally for development and experiments: qemu, kubernetes, minikube
qemu:
sudo apt-get install qemu-system
kubernetes:
curl -LO https://dl.k8s.io/release/`curl -LS https://dl.k8s.io/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mkdir -p /usr/local/bin/
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version --client
minikube:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
chmod +x ./minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/
Start minikube:
minikube start --driver=qemu
Check status:
kubectl get all
Stop minikube:
minikube stop
Create first simple configuration
File: pod.yml
apiVersion: v1
kind: Pod
metadata:
name: short-app
labels:
components: frontend
spec:
containers:
- name: short-app
image: wordpress
ports:
- containerPort: 80
resources:
limits:
memory: "128Mi"
cpu: "500m"
File: node-port.yml
apiVersion: v1
kind: Service
metadata:
name: short-app-port
spec:
type: NodePort
ports:
- port: 3000
targetPort: 80
nodePort: 31200
selector:
components: frontend
Run it:
minikube start --driver=qemu
kubectl apply -f pod.yml
kubectl apply -f node-port.yml
kubectl get pods short-app
kubectl get services
minikube ip
Open page in the browser http://192.168.1.1:31200
Monitor:
kubectl describe pods short-app
kubectl describe service short-app-port
Stop:
minikube stop
Run from CLI:
kubectl run my-pod --image=wordpress --labels="components=backend"
Delete:
kubectl delete pod my-pod
App-deployment
File app-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: short-app-deployment
spec:
replicas: 1
selector:
matchLabels:
components: frontend
template:
metadata:
labels:
components: frontend
spec:
containers:
- name: short-app
image: wordpress
ports:
- containerPort: 80
resources:
limits:
memory: "128Mi"
cpu: "500m"
Run deployment:
kubectl apply -f app-deployment.yml
Inspect deployment:
kubectl get deployments.app
kubectl describe deployments.app short-app-deployment
kubectl rollout history deployment short-app-deployment
Set (change) image in the app deployment from CLI:
kubectl set image deployment.apps/short-app-deployment short-app=wordpress:latest
Restart deployment (in case imagePolicy: always (when image with tag :latest)):
kubectl rollout restart deployment short-app-deployment
Delete deployment:
kubectl delete deployments.app short-app-deployment
Network
File app-service.yml
apiVersion: v1
kind: Service
metadata:
name: short-app-clusterip
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
selector:
components: frontend
File app-deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: short-app-deployment
spec:
replicas: 1
selector:
matchLabels:
components: frontend
template:
metadata:
labels:
components: frontend
spec:
containers:
- name: short-app
image: wordpress:latest
ports:
- containerPort: 80
resources:
limits:
memory: "128Mi"
cpu: "100m"
Run configuration:
kubectl apply -f app-service.yml
kubectl apply -f app-deployment.yml
kubectl get all
Setup ingress:
minikube addons list
minikube addons enable ingress
File ingress.yml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myingress
annotations:
nginx.ingress.kubernetes.io/add-base-url: "true"
spec:
ingressClassName: nginx
rules:
- host: short-app.dev
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: short-app-clusterip
port:
number: 80
Run it:
kubectl apply -f ingress.yml
kubectl get ingress
File postgres-deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment
spec:
replicas: 1
selector:
matchLabels:
components: database
template:
metadata:
labels:
components: database
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: demodb
- name: POSTGRES_USER
value: demouser
- name: POSTGRES_PASSWORD
value: demopass
resources:
limits:
memory: "500Mi"
cpu: "300m"
volumeMounts:
- name: postgres-pvc
mountPath: /var/lib/postgresql/data
subPath: postgres
volumes:
- name: postgres-pvc
persistentVolumeClaim:
claimName: postgres-pvc
File postgres-service.yml:
apiVersion: v1
kind: Service
metadata:
name: postgres-clusterip
spec:
type: ClusterIP
ports:
- port: 5432
protocol: TCP
selector:
components: database
File postgres-pvc.yml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
resources:
requests:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
Run them:
kubectl apply -f postgres-pvc.yml
kubectl apply -f postgres-deployment.yml
kubectl apply -f postgres-service.yml
kubectl get all
kubectl get persistentvolumeclaims
Delete volume:
kubectl delete persistentvolumeclaims postgres-pvc
Secrets
Useful commands:
kubectl create secret generic pg-secret --from-literal PASSWORD=my_pass
kubectl get secrets
kubectl describe secrets
kubectl get secrets pg-secret --template={{.data.PASSWORD}} | base64 -d
kubectl delete secrets pg-secret
echo -n demo | base64
ZGVtbw==
File postgres-secret.yml:
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
type: Opaque
data:
POSTGRES_DB: 'ZGVtbw=='
POSTGRES_USER: 'ZGVtbw=='
POSTGRES_PASSWORD: 'ZGVtbw=='
Run it:
kubectl apply -f postgres-secret.yml
kubectl get secrets postgres-secret
File postgres-deployment.yml (use secrets):
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment
spec:
replicas: 1
selector:
matchLabels:
components: database
template:
metadata:
labels:
components: database
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
resources:
limits:
memory: "500Mi"
cpu: "300m"
volumeMounts:
- name: postgres-pvc
mountPath: /var/lib/postgresql/data
subPath: postgres
volumes:
- name: postgres-pvc
persistentVolumeClaim:
claimName: postgres-pvc
File api-deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: short-api-deployment
spec:
replicas: 1
selector:
matchLabels:
components: backend
template:
metadata:
name: short-api
labels:
components: backend
spec:
containers:
- name: short-api
image: wordpress
ports:
- containerPort: 3000
resources:
limits:
memory: "500Mi"
cpu: "200m"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: short-api-secret
key: DATABASE_URL
livenessProbe:
exec:
command:
- curl
- --fail
- http://localhost:3000/api
initialDelaySeconds: 300
periodSeconds: 30
failureThreshold: 2
File api-service.yml:
apiVersion: v1
kind: Service
metadata:
name: short-api-clusterip
spec:
type: ClusterIP
ports:
- port: 3000
protocol: TCP
selector:
components: backend
Generate base 64 string:
echo -n postgresql://demo:demo@postgres-clusterip:5432/demo | base64
cG9zdGdyZXNxbDovL2RlbW86ZGVtb0Bwb3N0Z3Jlcy1jbHVzdGVyaXA6NTQzMi9kZW1v
File api-secret.yml:
apiVersion: v1
kind: Secret
metadata:
name: short-api-secret
type: Opaque
data:
DATABASE_URL: 'cG9zdGdyZXNxbDovL2RlbW86ZGVtb0Bwb3N0Z3Jlcy1jbHVzdGVyaXA6NTQzMi9kZW1v'
# DATABASE_URL
# postgresql://demo:demo@postgres-clusterip:5432/demo
Run them:
kubectl apply -f api-secret.yml
kubectl apply -f api-deployment.yml
kubectl apply -f api-service.yml
kubectl get all
kubectl get secrets
File ingress.yml (with api backend):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myingress
annotations:
nginx.ingress.kubernetes.io/add-base-url: "true"
spec:
ingressClassName: nginx
rules:
- host: my-app.dev
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: short-app-clusterip
port:
number: 80
- pathType: Prefix
path: "/api"
backend:
service:
name: short-api-clusterip
port:
number: 3000
Run it:
kubectl apply -f ingress.yml
kubectl get all
File api-config.yml:
apiVersion: v1
kind: ConfigMap
metadata:
name: short-api-config
data:
inputFileSizeMax: 10Mb
outputFileFormat: "jpg"
Run it:
kubectl apply -f api-config.yml
Debug (show logs)
kubectl logs pod/postgres-deployment-56ffb4857b-bfcv8
minikube dashboard
kubectl exec -it <pod_id> -- /bin/bash
Delete environment:
kubectl get all
kubectl delete deployments.app short-app-deployment
kubectl delete deployments.app short-api-deployment
kubectl delete deployments.app postgres-deployment
kubectl delete service short-app-clusterip
kubectl delete service short-api-clusterip
kubectl delete service postgres-clusterip
kubectl get persistentvolumeclaims
kubectl delete persistentvolumeclaims postgres-pvc
kubectl get secret
kubectl delete secret short-api-secret
kubectl delete secret postgres-secret
Delete environment:
kubectl get all
kubectl delete deployments.app short-app-deployment
kubectl delete deployments.app short-api-deployment
kubectl delete deployments.app postgres-deployment
kubectl delete service short-app-clusterip
kubectl delete service short-api-clusterip
kubectl delete service postgres-clusterip
kubectl get persistentvolumeclaims
kubectl delete persistentvolumeclaims postgres-pvc
kubectl get secret
kubectl delete secret short-api-secret
kubectl delete secret postgres-secret
kubectl get configmaps
kubectl delete configmaps short-api-config
kubectl get ingress
kubectl delete ingress myingress
Helm
Commands:
sudo snap install helm
helm repo add stable https://charts.helm.sh/stable
helm repo update
helm repo list
helm search repo mysql
clear directory template, file values.yaml
add into template directory app-deployment.yml, app-service.yml, ingress.yml
helm install short-service-release ./short-service
kubectl get all
helm ls
make some modifications in the templates
helm upgrade short-service-release ./short-service
helm install --debug --dry-run short-service-release ./short-service
helm uninstall short-service-release
helm lint ./short-service
Templates
appVersion: {{ .Values.version }}
appName: {{ .Values.name | quotes }}
image: "{{ .Values.image }}:{{ .Values.version }}"
Conditions:
{{ if eq .Values.env "prod" }}token: "value"{{ end }}
{{- if eq .Values.env "prod" }}
token: "prodToken"
{{- else }}
token: "devToken"
{{- end }}
Variables:
{{- $varName := 1 }}
key: {{- $varName }}
Loops:
...
Users:
- name: User1
role: admin
- name: User2
role: user
...
{{- range $index, $user := .Values.users }}
{{ $user.name }}: "{{ $user.role }} - {{ $index }}"
{{- end }}
That's all.