Run Kubernetes API server locally

Masato Naka
3 min readMar 25, 2023

--

Overview

In this post, I’ll share how to run Kube API server in your local. If you are not familiar with Kubernetes components in the control plane, it’d be great to start with playing with API server.

What is Kube API server?

Kube API server is a component in the control plane of Kubernetes, which is responsible for managing Kubernetes objects that are stored in etcd (another component for datastore). For more details, you can check the official document: https://kubernetes.io/docs/concepts/overview/components/.

Every time we use kubectl, it sends a request to API server to create/get/update/delete Kubernetes resources.

Kubernetes controllers/operators are also a client of Kube API server, which send requests to API server to get the status of its target objects and make changes via API server.

Kube API server is the central component that interacts with other components.

To gain deeper understanding of Kubernetes components, we can’t skip Kube API server.

Prerequisite

  • bash: brew install bash
  • openssl: brew install openssl
  • etcd: brew install etcd

If you’re using Mac you can install them via brew

Steps

Run etcd

Running Kube API server locally is helpful to get more familiar with it.

Kube API server uses etcd as a backend datastore, we need etcd to run API server.

You can start etcd by the command etcd:

etcd
...
{"level":"info","ts":"2023-03-26T07:07:29.803+0900","caller":"api/capability.go:75","msg":"enabled capabilities for version","cluster-version":"3.5"}
{"level":"info","ts":"2023-03-26T07:07:29.803+0900","caller":"etcdserver/server.go:2595","msg":"cluster version is updated","cluster-version":"3.5"}

Build Kubernetes

You can build Kubernetes with the following steps:

git clone https://github.com/kubernetes/kubernetes && kubernetes
git checkout release-1.26 # you can choose any version
make

Prepare certificates

Prepare the following shell script to create certificate for service account and api-server

# service account
openssl genrsa -out service-account-key.pem 4096
openssl req -new -x509 -days 365 -key service-account-key.pem -subj "/CN=test" -sha256 -out service-account.pem

# api-server
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=test" -days 10000 -out ca.crt
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -config csr.conf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf

# kubeconfig
kubectl config set-cluster local-apiserver \
--certificate-authority=ca.crt \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=kubeconfig

kubectl config set-credentials admin \
--client-certificate=server.crt \
--client-key=server.key \
--embed-certs=true \
--kubeconfig=kubeconfig

kubectl config set-context default \
--cluster=local-apiserver \
--user=admin \
--kubeconfig=kubeconfig

kubectl config use-context default --kubeconfig=kubeconfig

In this post, we don’t see how those commands works in details. For more details about certificates, you can check Generate Certificates Manually.

Run API server

Now we are going to run API server that is built in the above step:

PATH_TO_KUBERNETES_DIR=~/repos/kubernetes/kubernetes # the path to your cloned kubernetes repo

You can check the API server’s version:

${PATH_TO_KUBERNETES_DIR}/_output/bin/kube-apiserver --version
Kubernetes v1.26.3-11+9043dd888deae0

Start the API server

${PATH_TO_KUBERNETES_DIR}/_output/bin/kube-apiserver --etcd-servers http://localhost:2379 \
--service-account-key-file=service-account-key.pem \
--service-account-signing-key-file=service-account-key.pem \
--service-account-issuer=api \
--tls-cert-file=server.crt \
--tls-private-key-file=server.key \
--client-ca-file=ca.crt

Check the component status with the following command:

kubectl get componentstatuses --kubeconfig kubeconfig
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Unhealthy Get "https://127.0.0.1:10259/healthz": dial tcp 127.0.0.1:10259: connect: connection refused
controller-manager Unhealthy Get "https://127.0.0.1:10257/healthz": dial tcp 127.0.0.1:10257: connect: connection refused
etcd-0 Healthy {"health":"true","reason":""}

Only etcd is healthy as we don’t run scheduler and controller manager.

Try using the API server

We need to create default/default service account with the following command:

kubectl create sa default --kubeconfig kubeconfig

Now you can create a nginx Pod with the following command:

kubectl run nginx --image nginx --kubeconfig kubeconfig

You can list Pods with kubectl get pods :

kubectl get pod --kubeconfig kubeconfig
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 41s

(The Pod will remain Pending status as there’s no kubelet, which is a component to start a container for Pod)

Clean up the Pod

kubectl delete pod nginx --kubeconfig kubeconfig

Summary

In this post, I shared how to run Kube API server locally (with the dependent component etcd) and created a Pod object using kubectl.

We run API server with different configuration: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/

--

--

Masato Naka

An SRE engineer, mainly working on Kubernetes. CKA (Feb 2021). His Interests include Cloud-Native application development, and machine learning.