Everyone wants to play with the Kubernetes(K8s). There are many options from Google, AWS, Heroku, etc. They offer free tiers that anyone can play with. But what if you want to have your K8s. On your laptop, for fun or to learn something new, without any restrictions.

What is k3s

The K3s is lightweight k8s by the rancher for Linux. K3s is intended to work with low resources and IoT devices. So, it can easily run on laptops. It is packed as a single binary so it is easy to setup. It requires to have installed docker, as nodes will be run inside containers.

What is k3d

The k3d is a wrapper around k3s as well made by the rancher. It intends to ease installation by detecting running OS, downloading binaries, and setting up the default configuration for the target OS.

Installation and usage

To install k3d and start a local cluster is rather easy. For example, if you are running Linux or OSX you could install it by using the brew:

> brew install k3d

When done you can do:

> k3d
Usage:
  k3d [flags]
  k3d [command]

Available Commands:
  cluster     Manage cluster(s)
  completion  Generate completion scripts for [bash, zsh, fish, powershell | psh]
  config      Work with config file(s)
  help        Help about any command
  image       Handle container images.
  kubeconfig  Manage kubeconfig(s)
  node        Manage node(s)
  registry    Manage registry/registries
  version     Show k3d and default k3s version

Flags:
  -h, --help         help for k3d
      --timestamps   Enable Log timestamps
      --trace        Enable super verbose output (trace logging)
      --verbose      Enable verbose output (debug logging)
      --version      Show k3d and default k3s version

Use "k3d [command] --help" for more information about a command.

If you do not have installed brew you can check other installation options on the k3d site.

Create cluster

Assuming you already have installed the docker and the kubectl you can init new cluster:

> k3d cluster create private-cluster

INFO[0000] Prep: Network
INFO[0000] Created network 'k3d-private-cluster'
INFO[0000] Created volume 'k3d-private-cluster-images'
INFO[0001] Creating node 'k3d-private-cluster-server-0'
INFO[0002] Creating LoadBalancer 'k3d-private-cluster-serverlb'
INFO[0002] Starting cluster 'private-cluster'
INFO[0002] Starting servers...
INFO[0002] Starting Node 'k3d-private-cluster-server-0'
INFO[0014] Starting agents...
INFO[0014] Starting helpers...
INFO[0014] Starting Node 'k3d-private-cluster-serverlb'
INFO[0016] (Optional) Trying to get IP of the docker host and inject it into the cluster as 'host.k3d.internal' for easy access
INFO[0020] Successfully added host record to /etc/hosts in 2/2 nodes and to the CoreDNS ConfigMap
INFO[0020] Cluster 'private-cluster' created successfully!
INFO[0020] --kubeconfig-update-default=false --> sets --kubeconfig-switch-context=false
INFO[0020] You can now use it like this:
kubectl config use-context k3d-private-cluster
kubectl cluster-info

You can check some info for the local cluster:

> kubectl cluster-info

Kubernetes control plane is running at https://0.0.0.0:49996
CoreDNS is running at https://0.0.0.0:49996/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://0.0.0.0:49996/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Or get all nodes:

> ❯ kubectl get nodes

NAME                           STATUS   ROLES    AGE     VERSION
k3d-private-cluster-server-0   Ready    master   2m28s   v1.18.16+k3s1

Get all running pods:

❯ kubectl get pod --all-namespaces

NAMESPACE     NAME                                     READY   STATUS      RESTARTS   AGE
kube-system   local-path-provisioner-6d59f47c7-8j4z6   1/1     Running     0          2m29s
kube-system   metrics-server-7566d596c8-jwtxr          1/1     Running     0          2m29s
kube-system   helm-install-traefik-5lbnw               0/1     Completed   0          2m30s
kube-system   svclb-traefik-d2cvn                      2/2     Running     0          2m4s
kube-system   coredns-7944c66d8d-7b5rc                 1/1     Running     0          2m29s
kube-system   traefik-758cd5fc85-df4mq                 1/1     Running     0          2m4s

Deploy a Pod

Let start the Apache server in local cluster:

> kubectl run test --image=httpd \
--port=80 \
--replicas=3 \
--restart='Always' \
--expose \
--requests='cpu=100m,memory=256Mi' \
--limits='cpu=200m,memory=512Mi' \
--labels=app=apache,version=1
Flag --replicas has been deprecated, has no effect and will be removed in the future.
service/test created
pod/test created

Check pod and services:

❯ kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          94s
❯ kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.43.0.1      <none>        443/TCP   6m55s
test         ClusterIP   10.43.98.145   <none>        80/TCP    101s

The local cluster in addition to default services and pods has running httpd service and attached service all named test.

The basic work with a cluster

You can stop the cluster when done with it, so it does not eat not needed resource:

❯ k3d cluster stop private-cluster
INFO[0000] Stopping cluster 'private-cluster'

List all clusters managed by k3s:

❯ k3d cluster list
NAME              SERVERS   AGENTS   LOADBALANCER
private-cluster   0/1       0/0      true

Start it again:

❯ k3d cluster start private-cluster

INFO[0000] Starting cluster 'private-cluster'
INFO[0000] Starting servers...
INFO[0000] Starting Node 'k3d-private-cluster-server-0'
INFO[0005] Starting agents...
INFO[0005] Starting helpers...
INFO[0005] Starting Node 'k3d-private-cluster-serverlb'

Check all:

❯ kubectl get all --all-namespaces
NAMESPACE     NAME                                         READY   STATUS      RESTARTS   AGE
kube-system   pod/helm-install-traefik-5lbnw               0/1     Completed   0          17m
kube-system   pod/local-path-provisioner-6d59f47c7-8j4z6   1/1     Running     1          17m
kube-system   pod/metrics-server-7566d596c8-jwtxr          1/1     Running     1          17m
kube-system   pod/svclb-traefik-d2cvn                      2/2     Running     2          17m
default       pod/test                                     1/1     Running     1          12m
kube-system   pod/coredns-7944c66d8d-7b5rc                 1/1     Running     1          17m
kube-system   pod/traefik-758cd5fc85-df4mq                 1/1     Running     1          17m

NAMESPACE     NAME                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
default       service/kubernetes           ClusterIP      10.43.0.1       <none>        443/TCP                      17m
kube-system   service/kube-dns             ClusterIP      10.43.0.10      <none>        53/UDP,53/TCP,9153/TCP       17m
kube-system   service/metrics-server       ClusterIP      10.43.133.151   <none>        443/TCP                      17m
kube-system   service/traefik-prometheus   ClusterIP      10.43.5.75      <none>        9100/TCP                     17m
kube-system   service/traefik              LoadBalancer   10.43.44.46     172.19.0.2    80:31193/TCP,443:30794/TCP   17m
default       service/test                 ClusterIP      10.43.98.145    <none>        80/TCP                       12m

NAMESPACE     NAME                           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
kube-system   daemonset.apps/svclb-traefik   1         1         1       1            1           <none>          17m

NAMESPACE     NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/local-path-provisioner   1/1     1            1           17m
kube-system   deployment.apps/metrics-server           1/1     1            1           17m
kube-system   deployment.apps/coredns                  1/1     1            1           17m
kube-system   deployment.apps/traefik                  1/1     1            1           17m

NAMESPACE     NAME                                               DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/local-path-provisioner-6d59f47c7   1         1         1       17m
kube-system   replicaset.apps/metrics-server-7566d596c8          1         1         1       17m
kube-system   replicaset.apps/coredns-7944c66d8d                 1         1         1       17m
kube-system   replicaset.apps/traefik-758cd5fc85                 1         1         1       17m

NAMESPACE     NAME                             COMPLETIONS   DURATION   AGE
kube-system   job.batch/helm-install-traefik   1/1           26s        17m

Notice in the namespace named default there is a pod test and service test. This means our deployed httpd server is online.

Conclusion

Without going into details and reading long manuals you can get a fully functional K8s cluster to learn and develop. It is easy to operate so you can focus on learning to use K8s.