Minikube is a local Kubernetes solution designed to make it easy to learn and develop for Kubernetes. All you need is Docker (or a similar container technology) or a Virtual Machine environment, and you can start a Kubernetes cluster with a single command: minikube start.
In this lab, we will use Docker for our container environment. You can find a few useful Docker commands here.
Minikube is designed to create single-node clusters, which can be helpful for those pursuing Kubernetes certifications. You can find more information about Kubernetes certifications from the Cloud Native Computing Foundation (CNCF) here, including the Certified Kubernetes Administrator (CKA) certification.
Once you have created a Docker image, you will want to run it in a cluster. There are several options for doing so, but we will start with the smallest unit, the pod. For example, you can create one pod for the API and another for the frontend.
To create a pod from your Docker images, follow the steps provided in this link.
To create a deployment with a custom Docker image, you can use the following kubectl command:
codekubectl run --image my-spring-boot-demo-docker:latest appAfter executing this command, you should see a message confirming that the pod has been created:
codepod/app createdTo view the status of your pods, you can run the following command:
codekubectl get podsIf you use the -w option with this command, it will watch for changes in the pod's status and display updates in real-time, similar to the -f option in the Linux tail command.
To delete a pod, you can use the following command:
codekubectl delete pod Replace `` with the actual name of the pod you want to delete.
Lets start using Deployments and replicas with our Spring Boot application, that you can find in this link
> kubectl create deployment --image my-spring-boot-demo-docker:latest appWe can check the deployments with:
kubectl get deploymentsWe can also specify the option -l to filter by label.
You might also want to get the pods, and if you do so, there will be a pod with a random name. This is important in case that we want to scale, and for that we can create replicas like this:
> kubectl scale --replicas=3 deployment/app
deployment.apps/app scaledWe can delete our deployments with:
> kubectl delete deployment app
deployment.apps "app" deletedNow, we'll start tagging with different names our container:
> docker image tag my-spring-boot-demo-docker:latest vlad0x/my-spring-boot-demo-docker:v1
> docker image tag my-spring-boot-demo-docker:latest vlad0x/my-spring-boot-demo-docker:v2
> docker image push vlad0x/my-spring-boot-demo-docker:v1
The push refers to repository [docker.io/vlad0x/my-spring-boot-demo-docker]
8053c93da4dd: Layer already exists
d03e5d303c2e: Layer already exists
dc9fa3d8b576: Layer already exists
27ee19dc88f2: Layer already exists
c8dd97366670: Layer already exists
v1: digest: sha256:2f76b217a9090a6b692681ee33c9259ca84d25068cd1723baf55d9dbb73ee1d0 size: 1374
> docker image push vlad0x/my-spring-boot-demo-docker:v2
The push refers to repository [docker.io/vlad0x/my-spring-boot-demo-docker]
8053c93da4dd: Layer already exists
d03e5d303c2e: Layer already exists
dc9fa3d8b576: Layer already exists
27ee19dc88f2: Layer already exists
c8dd97366670: Layer already exists
v2: digest: sha256:2f76b217a9090a6b692681ee33c9259ca84d25068cd1723baf55d9dbb73ee1d0 size: 1374In order for the Kubernetes to work, the Docker images must be in a public location, if we are working with copyrighted images, we must provide a secret.
We can create a deployment using any of our images, then we can describe our deployment and see the image that is using, which is the same image that is used for replicas.
> kubectl create deployment app --image=vlad0x/my-spring-boot-demo-docker:v1
deployment.apps/app created
> kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
app 1/1 1 1 9s
> kubectl describe deployment app
Name: app
Namespace: default
CreationTimestamp: Fri, 09 Sep 2022 19:37:38 -0500
Labels: app=app
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=app
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=app
Containers:
my-spring-boot-demo-docker:
Image: vlad0x/my-spring-boot-demo-docker:v1
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: app-65d8f569c4 (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 21s deployment-controller Scaled up replica set app-65d8f569c4 to 1If you run the get pods command you'll see that the pod was replicated with same name followed by other random characters:
> kubectl get pods
NAME READY STATUS RESTARTS AGE
app-65d8f569c4-4m6fj 1/1 Running 0 59s
app-65d8f569c4-hxn9j 1/1 Running 0 6m43s
app-65d8f569c4-kzrwg 1/1 Running 0 59sThe replicas will allow us to maintain high availability of the application, this is the secret of Kubernetes
We can test this by deleting the pods and then getting the pods, inmediately the replicaset will generate new pods for you.
> kubectl delete pods --all
pod "app-65d8f569c4-4m6fj" deleted
pod "app-65d8f569c4-hxn9j" deleted
pod "app-65d8f569c4-kzrwg" deleted
> kubectl get pods
NAME READY STATUS RESTARTS AGE
app-65d8f569c4-k4j67 1/1 Running 0 19s
app-65d8f569c4-ns5br 1/1 Running 0 19s
app-65d8f569c4-q9nfp 1/1 Running 0 19sWe cannot update replicas, we can update deployments:
# kubectl set image <Name of the container>:<Name of the updated image>
> kubectl set image deployment/app my-spring-boot-demo-docker=vlad0x/my-spring-boot-demo-docker:v2
deployment.apps/app image updated
> kubectl get pods
NAME READY STATUS RESTARTS AGE
app-545489db9f-k7qdq 1/1 Running 0 25s
app-545489db9f-pcfdk 1/1 Running 0 23s
app-545489db9f-zls2z 0/1 ContainerCreating 0 28s
app-65d8f569c4-q9nfp 1/1 Terminating 0 28s
balanced-76755b4cd4-n98sz 1/1 Running 0 12mWhen we change the image, we can see how some pods are terminating, and other are being created, and this allows our application to stay running while we update, certainly a lot of stability for our application. To avoid downtime always have more than two replicas.
If we run again our describe command we can see how the image was changed and the replicas at the end of the result:
> kubectl describe deployment/app
Name: app
Namespace: default
CreationTimestamp: Fri, 09 Sep 2022 19:37:38 -0500
Labels: app=app
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=app
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=app
Containers:
my-spring-boot-demo-docker:
Image: vlad0x/my-spring-boot-demo-docker:v2
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: app-545489db9f (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 26m deployment-controller Scaled up replica set app-65d8f569c4 to 1
Normal ScalingReplicaSet 20m deployment-controller Scaled up replica set app-65d8f569c4 to 3
Normal ScalingReplicaSet 4m deployment-controller Scaled up replica set app-545489db9f to 1
Normal ScalingReplicaSet 3m57s deployment-controller Scaled down replica set app-65d8f569c4 to 2
Normal ScalingReplicaSet 3m57s deployment-controller Scaled up replica set app-545489db9f to 2
Normal ScalingReplicaSet 3m55s deployment-controller Scaled down replica set app-65d8f569c4 to 1
Normal ScalingReplicaSet 3m55s deployment-controller Scaled up replica set app-545489db9f to 3
Normal ScalingReplicaSet 3m52s deployment-controller Scaled down replica set app-65d8f569c4 to 0As you can see in the above result, there is also a list of events that can help us to understand how our application is behaving
Now we are going to create a service to expose the ports:
kubectl expose deployment app --port=8080 --type=LoadBalancerThen we can check the services with the below command:
> kubectl expose deployment app --port=8080 --type=LoadBalancer
service/app exposed
> kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app LoadBalancer 10.102.45.139 <pending> 8080:30368/TCP 18sYou'll notice that the EXTERNAL-IP as pending, the Load Balance service gives you an external IP, anybody can connect to this external IP to the application, this is not recommended as it is bypassing completely your network. Only use load balancers when you know about security, this will be more noticeable when using a Cloud service, where the EXTERNAL-IP will be configured, in the Minikube it won't happen.
Now we can run our application with the below command, that will in our case open a browser to check the spring boot home page, this application contains more REST APIs that can be called with CURL or POST MAN:
minikube service appEach of the pods will work with a round robin to select which of the pods to use.
So far we have created all our deployments in the default namespace. We can create a new namespace with the below command:
> kubectl create namespace dev
namespace/dev created
PS C:\Users\Vlad> kubectl get namespace
NAME STATUS AGE
default Active 18d
dev Active 7s
kube-node-lease Active 18d
kube-public Active 18d
kube-system Active 18dNote: only admins must ave access to the kube-system.
We can create another app in the new namespace like this:
kubectl create deployment --image vlad0x/my-spring-boot-demo-docker:v2 --namespace dev appWe can see all the services, deployments, apps with the below command:
kubectl get all -ADon't forget that you can see all of this in the dashboard as well:
Just like with Docker, we can use a YAML, there is a very simple trick to create a YAML without writting a YAML, we can do so with the option --dry-run and -o specifying yaml like this:
> kubectl create deployment --image vlad0x/my-spring-boot-demo-docker:v2 --namespace dev app --dry-run=client -o yamlapiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: app
name: app
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: app
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: app
spec:
containers:
- image: vlad0x/my-spring-boot-demo-docker:v2
name: my-spring-boot-demo-docker
resources: {}
status: {}Our output is our YML. We can do exactly the same for pods:
>kubectl run --image vlad0x/my-spring-boot-demo-docker:v2 app --dry-run=client -o yamlapiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: app
name: app
spec:
containers:
- image: vlad0x/my-spring-boot-demo-docker:v2
name: app
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}kubectl expose deployment app --namespace default --port=8080 --type=LoadBalancer --dry-run=client -o yamlapiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: app
name: app
namespace: default
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: app
type: LoadBalancer
status:
loadBalancer: {}We can mix different YML separated by ---, where we must be careful with the labels, which is the way how the Service and the Deployments are going to be linked.
We can copy or pass this output to a file and we can save with any name we want, i.e deployment.yml and run it with the below command:
kubectl create -f deployment.ymlIf by any reason we want to know more about the variables to set we can start for example setting the api with a command like this:
> kubectl api-resourcesAt the very core it is just an API, you can use your browser, you can write a program like java, python, node, etc. Any utility that you want to use but the very popular client that people like is the kubectl "Cube Cutle".
Internally a cluster has the Constrol Plane, the nodes and the Cloud provider API. In the Control plane there are important componets like the brain of it called etcd, the scheduler, the api, the c-c-m and the c-m.
Each node consists of two components one is the kubelet the other one is the k-proxy (this one is very important because every part gets its own IP address). Much more documentation can be found in this link
When you install your kubernets, you can have hundreds of clusters, but generally you'll have one client, thats where kubectl comes into play.
Container or virtual machine manager, such as: Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox, or VMware Fusion/Workstation
Installers can be found in this link from the official minikube page,
In case that you are using chocolatey, you can execute the below command:
choco install minikube
From the terminal with administrator privileges, execute the below command, which will download Kubernetes with the current images, it will also create the docker container with 2 CPUs and 8GB of RAM:
minikube start
You should see a message like this at the end:
🏄 Done! kubectl is now configured to use "minikube"
cluster and "default" namespace by defaultIf anything goes wrong, the container was not properly initialized, you might see an output telling that the PROVIDER is not running
😄 minikube v1.26.1 on Microsoft Windows 11 Pro 10.0.22000 Build 22000
✨ Using the docker driver based on existing profile
💣 Exiting due to PROVIDER_DOCKER_NOT_RUNNING: "docker version --format -"
exit status 1: error during connect: This error may indicate that the
docker daemon is not running.:
Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/version":
open //./pipe/docker_engine: The system cannot find the file specified.
💡 Suggestion: Start the Docker service
📘 Documentation: https://minikube.sigs.k8s.io/docs/drivers/docker/There is more help in this link
In previous step the kubectl was installed and configured, from this point we can make use of the cluster:
kubectl get po -A
We can see our contexts with the below command, a context is a mix of your user and the server where you are running, and will tell where the kubectl is executing commands, the context essentially dictates where to run the command:
kubectl config viewAt any time we can list all the deployments with the below command:
kubectl get deployMinikube comes with a beautiful dashboard where we can see Workloads, Services, Config, Storage, Clusters, Definitions and Settings where we can configure a bunch of things
minikube dashboardWe can create a hello world sample with the below commands:
kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.4
kubectl expose deployment hello-minikube --type=NodePort --port=8080We can check if the service started with the below command:
kubectl get services hello-minikubeThe easiest way to access this service is to let minikube launch a web browser for you:
minikube service hello-minikubeAlternatively, use kubectl to forward the port:
kubectl port-forward service/hello-minikube 7080:8080We can delete a deployment with the delete deploy
kubectl delete deploy hello-minikubeTo access a LoadBalancer deployment, use the “minikube tunnel” command. Here is an example deployment:
kubectl create deployment balanced --image=k8s.gcr.io/echoserver:1.4kubectl expose deployment balanced --type=LoadBalancer --port=8080In another window, start the tunnel to create a routable IP for the ‘balanced’ deployment:
minikube tunnelTo find the routable IP, run this command and examine the EXTERNAL-IP column:
kubectl get services balancedYour deployment is now available at :8080
Pause Kubernetes without impacting deployed applications:
minikube pauseUnpause a paused instance:
minikube unpauseHalt the cluster:
minikube stopIncrease the default memory limit (requires a restart):
minikube config set memory 16384Browse the catalog of easily installed Kubernetes services, the below command allows us to see the installed addons:
minikube addons listCreate a second cluster running an older Kubernetes release:
minikube start -p aged --kubernetes-version=v1.16.1Delete all of the minikube clusters:
minikube delete --allTo create an nginx deployment using kubectl, run the following command:
kubectl create deployment --image nginx nginx