How to Deploy a REST API in Kubernetes

Beginner guide on how to create and deploy a REST API in local Kubernetes.
profile
Andy YeungFirst published: 2021-02-03Last updated: 2025-06-25
rest-api-kubernetes

This blog will help you get started on deploying your REST API in Kubernetes. First, we'll set up a local Kubernetes cluster, then create a simple API to deploy.

There are already a lot of free resources available explaining basic Kubernetes concepts, so go check those out first if you haven't already. This blog is intended for beginners but assumes you already have a basic understanding of Kubernetes and Docker concepts.

1. Set Up Local Kubernetes

There's a couple options for running Kubernetes locally, with the most popular ones including minikube, k3s, kind, microk8s. In this guide, any of these will work, but we will be using k3s because of the lightweight installation.

Install k3d, which is a utility for running k3s. k3s will be running in Docker, so make sure you have that installed as well. We used k3d v4.0 in this blog.

1curl -s https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash

Set up a cluster named test:

  • The port flag is for mapping port 80 from our machine to port 80 on the k3s load balancer. This is needed later when we use ingress.
1k3d cluster create test -p "80:80@loadbalancer"

Optionally, check that your kubeconfig got updated and the current context is correct:

1kubectl config view
2kubectl config current-context

Optionally, confirm that k3s is running in Docker. There should be two containers up, one for k3s and the other for load balancing:

1docker ps

Make sure that all the pods are running. If they are stuck in pending status, it may be that there is not enough disk space on your machine. You can get more information by using the describe command:

1kubectl get pods -A
2kubectl describe pods -A

There's a lot of kubectl commands you can try, so I recommend checking out the list of resources and being aware of their short names:

1kubectl api-resources

2. Create a Simple API

We will create a simple API using Express.js.

Set up the project:

1mkdir my-backend-api && cd my-backend-api
2touch server.js
3npm init
4npm i express --save
1// server.js
2const express = require("express");
3const app = express();
4app.get("/user/:id", (req, res) => {
5const id = req.params.id;
6res.json({
7id,
8name: John Doe #${id}
9});
10});
11app.listen(80, () => {
12console.log("Server running on port 80");
13});

Optionally, you can try running it if you have Node.js installed and test the endpoint /user/{id} with curl:

1node server.js
2// request:
3curl http://localhost:80/user/123
4// response: {"id":"123","name":"John Doe #123"}

Next, add a Dockerfile and .dockerignore:

1// Dockerfile
2FROM node:12
3WORKDIR /usr/src/app
4COPY package*.json ./
5RUN npm i
6COPY . .
7EXPOSE 80
8CMD ["node", "server.js"]

1// .dockerignore
2node_modules

Then, build the image and push it to the Docker Hub registry:

1docker build -t <YOUR_DOCKER_ID>/my-backend-api .
2docker push <YOUR_DOCKER_ID>/my-backend-api

3. Deploy

Now, we deploy the image to our local Kubernetes cluster. We use the default namespace.

Create a deployment:

1kubectl create deploy my-backend-api --image=andyy5/my-backend-api
  • Alternatively, create a deployment with a YAML file:
1kubectl create -f deployment.yaml
1// deployment.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5  name: my-backend-api
6  labels:
7    app: my-backend-api
8spec:
9  replicas: 1
10  selector:
11    matchLabels:
12      app: my-backend-api
13  template:
14    metadata:
15      labels:
16        app: my-backend-api
17    spec:
18      containers:
19      - name: my-backend-api
20        image: andyy5/my-backend-api

Create a service:

1kubectl expose deploy my-backend-api --type=ClusterIP --port=80
  • Alternatively, create a service with a YAML file:
1kubectl create -f service.yaml
1// service.yaml
2apiVersion: v1
3kind: Service
4metadata:
5  name: my-backend-api
6  labels:
7    app: my-backend-api
8spec:
9  type: ClusterIP
10  ports:
11  - port: 80
12    protocol: TCP
13    targetPort: 80
14  selector:
15    app: my-backend-api

Check that everything was created and the pod is running:

1kubectl get deploy -A
2kubectl get svc -A
3kubectl get pods -A

Once the pod is running, the API is accessible within the cluster only. One quick way to verify the deployment from our localhost is by doing port forwarding:

  • Replace the pod name below with the one in your cluster
1kubectl port-forward my-backend-api-84bb9d79fc-m9ddn 3000:80
  • Now, you can send a curl request from your machine
1curl http://localhost:3000/user/123

To correctly manage external access to the services in a cluster, we need to use ingress. Close the port-forwarding and let's expose our API by creating an ingress resource.

  • An ingress controller is also required, but k3d by default deploys the cluster with a Traefik ingress controller (listening on port 80).
  • Recall that when we created our cluster, we set a port flag with the value "80:80@loadbalancer". If you missed this part, go back and create your cluster again.

Create an Ingress resource with the following YAML file:

1kubectl create -f ingress.yaml
2kubectl get ing -A
1// ingress.yaml
2apiVersion: networking.k8s.io/v1
3kind: Ingress
4metadata:
5  name: my-backend-api
6  annotations:
7    ingress.kubernetes.io/ssl-redirect: "false"
8spec:
9  rules:
10  - http:
11      paths:
12      - path: /user/
13        pathType: Prefix
14        backend:
15          service:
16            name: my-backend-api
17            port:
18              number: 80
  • Now try it out!
1curl http://localhost:80/user/123

If you want to learn more on how to deploy using a managed Kubernetes service in the cloud, such as Google Kubernetes Engine, then check out the excellent guides on the official Kubernetes docs.

Share On:
Share on TwitterShare on LinkedIn