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.

Leave a Reply

Your email address will not be published. Required fields are marked *




Enter Captcha Here :