Skaffold team recently announced an exciting new feature that allows to sync files between your machine and the development container, making a big step forward in supporting interpreted languages likeĀ Node.js.
Skaffold is a command line tool to develop applications against a Kubernetes cluster (either a local Minikube or a remote cluster). Skaffold handles the build, push and deploy process of the image upon code change. Until today, Skaffold was (IMHO) not well-suited to interpreted languages like Node.js, due the inherent slowness of the process. With version 0.16.0, Skaffold supports an hybrid approach, allowing to take advantage of the usual auto-reload mechanisms used by Node.js developers (e.g.: nodemon
):
- When a js file changes, Skaffold syncs it with the container and the app is restarted by
nodemon
- When a file change requires to rebuild the container (for example, a change to
package.json
), Skaffold does the full rebuild, push and deploy
This hybrid approach is perfectly suited to a large class of technology stacks, like Node.js, React, Angular, Python, etc.
Quick tutorial
Code available in the Skaffold [master](https://github.com/GoogleContainerTools/skaffold/tree/master/integration/examples/nodejs)
branch.
Install Skaffold
- Installing Skaffold requires a Kubernetes cluster. A good local choice is Minikube or a recent (edge) Docker for Mac or Docker for Windows.
Create a Node.JSĀ app
- Init
npm
:
npm init
- Add the Express web framework to
package.json
:
npm install express nodemon --save
- Remove
node_modules
locally:
rm -rf node_modules
- Add the
nodemon
run command to thescripts
section inpackage.json
:
"scripts": {"dev": "nodemon index.js"},
- Create
index.js
:
Dockerize it
-
Create a
Dockerfile
: -
Create a Kubernetes pod definition
k8s-pod.yaml
:
If you use an editor that writes temporary files (like vim
) you need aĀ .dockerignore
file to make sure that temporary files do not trigger a container build:
Skaffold configuration
- Create a
skaffold.yaml
:
The deploy
section points to the pod definition, while the build
section points to current directory, where the Dockerfile
is located. The sync
clause disables the full rebuild/push/deploy for *.js
file changes and enables the sync process of those files to the container.
Running Skaffold
skaffold dev
This command starts the Skaffold file watcher, builds the image and deploys it on the cluster; it also shows you the application logs and it handles port forwarding for you. When you see:
...[node] Example app listening on port 3000!
Youāre ready to access the application:
$ curl localhost:3000Hello World!
Development workflow
Make some changes to index.js
. You will see that the modified file is synced to the container and nodemon
restarts the application:
Syncing 1 files for gcr.io/k8s-skaffold/node-example:dirty-11d1880Watching for changes every 1s...[node] [nodemon] starting `node index.js`[node] Example app listening on port 3000!
$ curl localhost:3000Hello World - changed!
Fast and easy!
If you change a file that requires rebuilding the container (like adding a dependency in package.json
) the full build/push/deploy mechanism is triggered:
Starting build...Found [minikube] context, using local docker daemon.Building [gcr.io/k8s-skaffold/node-example]...Sending build context to Docker daemon 10.34MBStep 1/5 : FROM node:8.12.0-alpine---> df48b68da02a
...
Build complete in 8.236026621s
...
[node] Example app listening on port 3000!
The time it takes depends on the complexity of your package.json
.
Future Improvements
Even if changing package.json
does not happen that often, rebuilding a complex app can be lengthy. A mechanism is needed to make use of npm
cache to speed up the process.
My talk
If you want to lean more about local development with Kubernetes, you can watch my talk at the All Day DevOps conference 2018.