Setup
Before you start, make sure you have installed Docker first.
Installing Kubernetes
1. Installing Kubernetes
You can install Kubernetes:
# This also installs kubectl, the Kubernetes Client CLI
brew install kubernetes-cli
And install Minikube (a tool that sets up a single-node Kubernetes cluster, i.e., the master node and the worker node will be in the same node):
brew install minikube
2. Starting Minikube virtual machine
Don't forget to ensure that the Docker daemon is running. (Run your VM if you are using Mac, i.e., your Docker Desktop or Rancher Desktop.)
minikube start
# Starting local Kubernetes cluster...
# Starting VM...
# SSH-ing files into VM...
# ...
# Kubectl is now configured to use the cluster.
3. Verify that the cluster is working
Use the kubectl cluster-info
command to show cluster information:
kubectl cluster-info
# Kubernetes control plane is running at https://127.0.0.1:49155
# CoreDNS is running at https://127.0.0.1:49155/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Use the kubectl get nodes
to list cluster nodes:
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 53m v1.24.1
4. SSH to the single Minikube node (optional)
You can do minikube ssh
to log into your single Kubernetes node:
minikube ssh
# docker@minikube:~$
Creating a simple Docker image
1. Create a simple Node.js server
Install Node.js and create the following app.js
file.
It's a simple server that listens to port 8080 and responds with the hostname of the machine it's running in (not the hostname of the host machine).
// app.js
// Code from Kubernetes in Action (Marko Lukša)
const http = require('http');
const os = require('os');
var handler = (request, response) => {
console.log('Received request from ' + request.connection.remoteAddress);
response.writeHead(200);
response.end("You've hit " + os.hostname() + '\n');
};
console.log('Kubia server starting...');
var www = http.createServer(handler);
www.listen(8080);
2. Create the Dockerfile for the image
Save the following file as Dockerfile
FROM node:12
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]
3. Build the Docker image
Build the docker image:
# docker build [options] <path|url>
# (*) --tag, -t <tagName>: name and optionally a tag in the 'name:tag' format
docker build -t kubia .
Verify the built image:
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# kubia latest e679b37d4075 3 minutes ago 864MB
4. Running the container image (optional)
Run the container with the following command:
# docker run [options] <image> [command] [...arg]
# (*) --name <name>: assignb name to the running container
# (*) --publish, -p <hostPort>:<containerPort>: publish container port(s) to the host
# (*) --detach, -d: run in background and print container ID
docker run --name kubia-container -p 8080:8080 -d kubia
# f4befa105984a1937302c6c75e4fca4dec16ca7f3e194df3fd63abb395015f9f
Try accessing the server from localhost:8080
:
curl localhost:8080
# You've hit f4befa105984
To stop (and delete) the container:
docker ps
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# f4befa105984 kubia "node app.js" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp kubia-container
docker stop kubia-container
docker rm kubia-container
Running your first app
1. Ensure that your Kubernetes cluster is running
If you are using Minikube:
minikube start
2. Deploying your Docker image
Normally, you would create a JSON/YAML description of your cluster, but to get things started, we'll use a one-line command to get it running:
# Load the image to Minikube:
# minikube image load <imageName>
minikube image load kubia
# Create the pod
# (*) --image=<image>: specifies the image that you want to run
# (*) --port=8080: tells Kubernetes that your app is listening on port 8080
# (*) --image-pull-policy=Never: tells Kubernetes to not pull the image (use local image)
kubectl run kubia --image=kubia --port=8080 --image-pull-policy=Never
Verify that the pod is running (may take a while until the status becomes Running
):
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# kubia 1/1 Running 0 80s
3. Expose the pod's IP
Each pod has their own IP, but it's internal to the cluster.
A LoadBalancer
service is the standard way to expose a service to the internet. With LoadBalancer
, each service gets its own external IP address. (minikube.sigs.k8s.io.)
Expose your pod using a LoadBalancer
service like so:
kubectl expose pod kubia --type=LoadBalancer --name kubia-http
# service/kubia-http exposed
4. Accessing your pod
You can check the services like the following. It takes time for the load balancer to be created, so you will see <pending>
for a while.
kubectl get services
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 34h
# kubia-http LoadBalancer 10.106.201.80 <pending> 8080:30429/TCP 2m54s
minikube tunnel
so that the load balancer gets an external IP. (Otherwise it will get stuck on <pending>
.)After you get the external IP, you can access your pod like so:
kubectl get services
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 35h
# kubia-http LoadBalancer 10.106.201.80 127.0.0.1 8080:30429/TCP 64m
curl 127.0.0.1:8080
# You've hit kubia
See also
- Google Kubernetes Engine (GKE) — To explore multi-node Kubernetes cluster hosted on Google Cloud. Using this tool, you don't have to manually set up all the cluster nodes and networking (Lukša). — https://cloud.google.com/container-engine/docs/before-you-begin
References
- Kubernetes in Action (Marko Lukša) — Chapter 2. First steps with Docker and Kubernetes
- Are the master and worker nodes the same node in case of a single node cluster? — https://stackoverflow.com/questions/63967089/are-the-master-and-worker-nodes-the-same-node-in-case-of-a-single-node-cluster
- docker build — https://docs.docker.com/engine/reference/commandline/build/
- docker run — https://docs.docker.com/engine/reference/commandline/run/
- Pushing images — https://minikube.sigs.k8s.io/docs/handbook/pushing/
- Images — https://kubernetes.io/docs/concepts/containers/images/
- Kubernetes service external ip pending — https://stackoverflow.com/questions/44110876/kubernetes-service-external-ip-pending