⚡️ 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.
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:
Prerequisites:
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.
Let's start with a simple Node.js application - no magic here, just a dummy HTTP server using Express:
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:
FROM node:8.10.0-alpineWORKDIR /usr/src/appCOPY package.json .COPY package-lock.json .RUN npm installCOPY . .EXPOSE 3000CMD 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:
# k8s-app.ymlapiVersion: extensions/v1beta1kind: Deploymentmetadata:name: node-appspec:replicas: 1template:metadata:labels:app: node-appspec:containers:- name: node-appimage: node-appports:- containerPort: 3000---apiVersion: v1kind: Servicemetadata:name: node-applabels:app: node-appspec:selector:app: node-appports:- port: 3000protocol: TCPnodePort: 30003type: 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:
# skaffold.yamlapiVersion: skaffold/v1alpha2kind: Configbuild:artifacts:- imageName: node-appworkspace: .docker: {}bazel: nulllocal:skipPush: nullgoogleCloudBuild: nullkaniko: nulldeploy:helm: nullkubectl:manifests:- k8s-app.ymlkustomize: 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:
skaffold devStarting build...Found minikube or Docker for Desktop context, using local docker daemon.Sending build context to Docker daemon 2.014MBStep 1/8 : FROM node:8.6.0-alpine---> b7e15c83cdafStep 2/8 : WORKDIR /usr/src/app---> Using cache---> e4cf80f4e3d6Step 3/8 : COPY package.json .---> Using cache---> 78f285cee4cbStep 4/8 : COPY package-lock.json .---> Using cache---> 52c2cc2364feStep 5/8 : RUN npm install---> Using cache---> f773a4b93a4bStep 6/8 : COPY . .---> b0cc2a87fe89Step 7/8 : EXPOSE 3000---> Running in cd4d940ddaff---> e2f558c9f067Step 8/8 : CMD node index.js---> Running in 4752ba26ff2c---> 5b62e8667662Successfully built 5b62e8667662Successfully tagged 71dba0517e741b4c8a11728cf905fe84:latestSuccessfully tagged node-app:5b62e86676627e49417af333b8da588b728bd3c9e5d777f6db5565d0e7a91015Build 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.