Using Kubernetes for Local Development

Do you like my articles? Never miss one again!

⚡️ Updated on July 3, 2018 to reflect changes introduced by Skaffold 0.9.

In the past years, I’ve been using Kubernetes in production both at RisingStack - the Node.js consulting company I’ve co-founded - and at GoDaddy at large scale. One of the common challenges I’ve seen is the lack of proper tooling on how one can develop their services locally against a real Kubernetes cluster. In practice, it meant that the developers ran their local instances against development or staging environments, which is far from ideal: if don’t have those services running locally, debugging them can be challenging.

A few days ago, I bumped into Skaffold, a command line tool that facilitates continuous development for Kubernetes applications. In this article, I am going to show you how you can start developing a Node.js app with the help of Skaffold and Kubernetes.

Using Kubernetes for Local Development

Skaffold is a command line tool that facilitates continuous development for Kubernetes applications. You can iterate on your application source code locally then deploy to local or remote Kubernetes clusters. Skaffold handles the workflow for building, pushing and deploying your application. It can also be used in an automated context such as a CI/CD pipeline to leverage the same workflow and tooling when moving applications to production. - The official Skaffold docs

In practice, Skaffold can:

  • detect changes in the source code and automatically build, push and deploy
  • automatically update image tags, so you don’t have to do that manually in the Kubernetes manifest files
  • build/deploy/push different applications at once, so it is a perfect fit for microservices too,
  • support both development and production environment, by running the manifests only once, or continuously watching for changes.

Installing Skaffold

Prerequisites:

  1. Make sure that you have Minikube installed - (Skaffold works with any Kubernetes clusters, for the sake of simplicity I picked Minikube)
  2. Make sure that you have kubectl installed
  3. Make sure that you have docker installed

Once you have all the dependencies installed, visit the Skaffold Releases page, and grab a build that suits your system, then put it on the system path.

Developing a Node.js Application with Skaffold

Let’s start with a simple Node.js application - no magic here, just a dummy HTTP server using Express:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const express = require('express')
const app = express()

app.get('/', function (req, res) {
res.json({
status: 'ok'
})
})

app.listen(3000, err => {
if (err) {
throw err
}

console.log('server is listening')
})

Next, let’s create a Dockerfile to containerize the above Node.js application:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM node:8.10.0-alpine

WORKDIR /usr/src/app

COPY package.json .
COPY package-lock.json .
RUN npm install

COPY . .

EXPOSE 3000

CMD node index.js

In order to run this application inside Kubernetes, we have to create a deployment and a service to expose the given deployment. To do so, I am using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# k8s-app.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: node-app
spec:
replicas: 1
template:
metadata:
labels:
app: node-app
spec:
containers:
- name: node-app
image: node-app
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: node-app
labels:
app: node-app
spec:
selector:
app: node-app
ports:
- port: 3000
protocol: TCP
nodePort: 30003
type: LoadBalancer

Now you can create a dockerized Node.js application by issuing the docker build . command. However, with that approach, you would only have the image built, but it wouldn’t be running inside a Kubernetes cluster. This is where Skaffold helps out.

Skaffold uses YAML files to describe workflows. For the above application, ours may look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# skaffold.yaml
apiVersion: skaffold/v1alpha2
kind: Config
build:
artifacts:
- imageName: node-app
workspace: .
docker: {}
bazel: null
local:
skipPush: null
googleCloudBuild: null
kaniko: null
deploy:
helm: null
kubectl:
manifests:
- k8s-app.yml
kustomize: null

As you can see, we have two main parts of the configuration file, the first one being the build section, the second one being the deploy section. In the build section, we can define what artifacts (most probably Docker images) we’d like to build, while in the deploy section we can define resources (like services or deployments) we’d like to see in Kubernetes.

The paths array tells Skaffold where the Kubernetes manifests are, while with the parameters, you can inject variables into the manifests. To get a more detailed description, please refer to the annotated skaffold example.


With these last steps, you’ve finished the setup process of Skaffold. Chances are, if you are already deploying applications using Kubernetes, you can simply reuse your Dockerfile and Kubernetes manifests, so you’ll only have to write the Skaffold yaml.

To start using Skaffold, you will have to start up Minikube (using minikube start), then run Skaffold:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
skaffold dev
Starting build...
Found minikube or Docker for Desktop context, using local docker daemon.
Sending build context to Docker daemon 2.014MB
Step 1/8 : FROM node:8.6.0-alpine
---> b7e15c83cdaf
Step 2/8 : WORKDIR /usr/src/app
---> Using cache
---> e4cf80f4e3d6
Step 3/8 : COPY package.json .
---> Using cache
---> 78f285cee4cb
Step 4/8 : COPY package-lock.json .
---> Using cache
---> 52c2cc2364fe
Step 5/8 : RUN npm install
---> Using cache
---> f773a4b93a4b
Step 6/8 : COPY . .
---> b0cc2a87fe89
Step 7/8 : EXPOSE 3000
---> Running in cd4d940ddaff
---> e2f558c9f067
Step 8/8 : CMD node index.js
---> Running in 4752ba26ff2c
---> 5b62e8667662
Successfully built 5b62e8667662
Successfully tagged 71dba0517e741b4c8a11728cf905fe84:latest
Successfully tagged node-app:5b62e86676627e49417af333b8da588b728bd3c9e5d777f6db5565d0e7a91015
Build complete.
Starting deploy...
Deploying k8s-app.yml...
Deploy complete.

[node-app-5d4df6585b-r87lk node-app] server is listening

Once you start modifying your files, Skaffold will automatically re-deploy to Kubernetes. To access your running service, you can run minikube service [service-name]. In our example, it is minikube service node-app. This will open your default browser with the Node.js application you’ve just deployed.


I hope that this tutorial will save you some time when developing services with Kubernetes - as I am fairly new to Skaffold too, please let me know in the comments below in case I missed anything! You can check out the whole example project on my GitHub.

Furher reading

Do you like my articles? Never miss one again!
docker, kubernetes, node.js, skaffold
Visit GitHub to add a comment