Saturday, March 14, 2020

Use Kubernetes locally and make Nginx & MariaDB Pods

Prerequisite

  • OS: ubuntu 18.04.2 LTS

What is Kubernetes?

Kubernetes is a container orchestration tool developed by Google. Kubernetes is a platform tool to manage containerized workloads and services.
Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available.
-- Kubernetes https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/

Official Interactive tutorial

If you don't want to install minikube locally, you can also try the official kubernetes interactive tutorial.

Minikube

But we don't use the tutorial. We will use Minikube to run Kubernetes locally. But what is minikube? The website of Kubernetes explains what it is.
Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a Virtual Machine (VM) on your laptop for users looking to try out Kubernetes or develop with it day-to-day.
-- Kubernetes https://kubernetes.io/docs/setup/learning-environment/minikube/

Kubernetes vs Docker-compose vs Docker Swarm

Kubernetes is for running and connecting containers on multiple hosts (= cluster). Each node is a VM or a physical computer that serves as a worker machine in a Kubernetes cluster according to their explanation.

Use minikube

Install minikube

See this page of Kubernetes. This tutorial is well written.

Use minikube and kubectl

Simply run this command to start minikube.
$ minikube start
Then you will see these messages:
Now we are ready to use "kubectl" locally. Kubectl is a command line tool for controlling Kubernetes clusters.

Create nginx service

With kubectl, we will use a container image nginx:1.7.9 to deploy nginx in our kubernetes cluster.
At first, make sure the maser node is working:
$ kubectl get all 
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   3d7h
Then create yaml files somewhere as follows:
nginx_deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    name: nginx
spec:
  selector:
    matchLabels:
      name: nginx
  replicas: 1 # tells deployment to run 1 pod matching the template
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.23.1
        ports:
        - containerPort: 80
        resources:
          limits:
            memory: 512Mi
            cpu: "1"
          requests:
            memory: 256Mi
            cpu: "0.2"
nginx_service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30080
      name: http
  selector:
    name: nginx
  externalIPs:
   - 192.168.49.2
Save the files and run this command:
$ cd (the directory where you saved the two yaml files)
$ kubectl apply -f ./nginx_deploy.yml  -f ./nginx_service.yml

Check the nginx from browser

Check your minikube IP:
$ minikube ip
192.168.99.100
Check port number:
$ kubectl describe service/nginx
Name:                     nginx
Namespace:                default
Labels:                   name=nginx
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"name":"nginx"},"name":"nginx","namespace":"default"},"spec":{"...
Selector:                 name=nginx
Type:                     NodePort
IP:                       10.111.250.254
Port:                     http  80/TCP
TargetPort:               80/TCP
NodePort:                 http  30080/TCP ####Port number is here!!!!!!!####
Endpoints:                172.17.0.4:80,172.17.0.5:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
Or simply use this command: 
$ minikube service nginx --url
http://192.168.99.100:30080
Check from the browser with the IP and port. Confirm nginx is working in the cluster.
We can expose this nginx as loadbalancer:
$ kubectl expose deployment nginx-deployment --type=LoadBalancer --name=lb-nginx
$ minikube service nginx --url
http://192.168.49.2:30920
Then you can use this URL to access your service.

The difference between NodePort and LoadBalancer is:

Create MariaDB service

Now we will create MariaDB service. At first, we will create the volume (space to save mariadb's data). Create the following files:
persistent_valume_claim.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    app: mariadb
  name: mariadb-pv-claim
spec:
  storageClassName: manual
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1000M
persistent_volume.yaml:
kind: PersistentVolume
apiVersion: v1
metadata:
  name: mariadb-pv
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 1000M
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
Now apply the files:
$ cd (the directory where you saved the two yaml files)
$ kubectl apply -f ./persistent_volume.yaml
$ kubectl apply -f ./persistent_valume_claim.yaml  
The we will create deployment for mariadb. Create the following files:
mariadb_deploy.yml
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: mariadb-deployment
spec:
  replicas: 1 # how many replicas of pods you want to create
  selector:
    matchLabels:
      app: mariadb
  template: # details for pods
    metadata:
      labels:
        app: mariadb # service will look for this label
    spec: # specification for Pods
      containers:
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 
        env:
        - name: MARIADB_ROOT_PASSWORD
          value: secret
        resources:
          limits:
            memory: 512Mi
            cpu: "1"
          requests:
            memory: 256Mi
            cpu: "0.2"
and mariadb_service.yml:
apiVersion: v1
kind: Service
metadata:
  name: mariadb
  labels:
    name: mariadb
spec:
  selector:
    app: mariadb
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
Save the files and run this command:
$ cd (the directory where you saved the two yaml files)
$ kubectl apply -f ./mariadb_deploy.yml  -f ./mariadb_service.yml
Now you will have mariadb service:
$ kubectl get all 
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1       <none>         443/TCP        80m
lb-nginx     LoadBalancer   10.103.22.52    <pending>      80:30150/TCP   27s
mariadb      ClusterIP      10.103.28.199   <none>         3306/TCP       21m
nginx        NodePort       10.109.85.209   192.168.49.2   80:30080/TCP   6s

Now we will create configmap for mariadb service as "mariadb_configmap.yml":
apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-configmap
data:
  database_url: mariadb
Then apply this file:
$ kubectl apply -f ./mariadb_configmap.yml
Now we can use the mariadb:
$ kubectl exec mariadb-deployment-644cf75948-9prh6 mariadb -- mariadb -uroot -proot -e "select version()"
version()
10.9.3-MariaDB-1:10.9.3+maria~ubu2204

To access from outside of Pods, we need to expose the mariadb:
$ kubectl expose deploy/mariadb-deployment --port 3306 --target-port 3306 --type LoadBalancer --name=mariadb-exposed

Now we can get the URL of the exposed mariadb:
$ minikube service mariadb-exposed --url
http://192.168.49.2:31955

We can use this information to connect to the DB.

Cleaning up

To delete the service and deployment after confirming from the browser:
$ kubectl delete service/nginx service/mariadb deployment.apps/nginx-deployment deployment.apps/mariadb-deployment
$ kubectl delete pvc mariadb-pv-claim
$ kubectl delete pv mariadb-pv
$ kubectl get all