Tips for running an efficient CI and CD system
Will Munn
works at: focusrite/novation
github: @willm
What is continuous integration?
- Checking every commit can integrate with the current system
- Alerting development teams of failures as quickly as possible
What is continuous delivery?
- Regularly deploying small changes to production
- Alerting development teams of failures as quickly as possible
Tools for CI / CD





Configuring your tool
Tip No1
keep your agents lean


Team A

Team B
Team C


4.x.x
7.10.0

Why is this bad
- Hard to scale
- Uses more resources
Solutions
- install npm packages locally
- Script the agent configuration process
- Use docker
Tip No2
Keep configuration in source control
#! /env/sh
npm install
npm test
git push heroku masterYour build script
git clone git@github.com:willm/speed-up-ci.gitCheckout source
Build step to build and deploy your code
#!/usr/bin/env/ sh
npm install
npm test
git push heroku masterYour build script
git clone git@github.com:willm/speed-up-ci.gitCheckout source
Build step to build and deploy your code
0 9 * * *Cron to run build at 9:00am daily

Plugin that configures canned test data

Plugin that reports awesome test output
Your build script
Plugin that emails stake holders when a release happens
Plugin that zips your built source only and stores it somewhere



Super awesome plugin that is critical to making a release functional.
You can't deploy because the CI server that holds the of the necessary steps is down
Why this is bad
Solutions
- Keep all the CI logic in a script or task runner
- Resist the urge of using every feature / plugin of your CI tool.
- Commit your build definitions (jenkins pipeline, circle.yaml, etc...)
Tip No 3
Avoid npm bloat
#!/usr/bin/env bash
npm init
npm install --save express request mocha typescript grunt




$ du -h -d 1
50M ./node_modules
50M .
$ ls -al node_modules | wc -l
199
$ find . -type f | wc -l
4086

Solutions
- learn node core!
- Install modules as you need them
- Avoid massive frameworks (angular2, ionic)
- Start with lightweight modules and solutions
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({greeting: 'Hello World'}));
}).listen(3000);needle 808Kb vs request 6.3Mb
tape 2.1Mb vs ava 34Mb
router 1.1Mb vs express 1.7Mb
npm scripts vs $BUILD_TOOL
Tip No4
keep your docker images lean
Large Images
- Take up unnecessary disk space on your instances
- Take longer to build and deploy
- More software can = more things to go wrong
Suggested workflow
2 dockerfiles
Development
FROM node:7.10.0-alpine
RUN mkdir /app
ADD package.json /app/package.json
WORKDIR /app
RUN npm install
ADD . /app
RUN npm run build$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node 6.9.2 178934e73268 6 days ago 651.2 MB
node 6.9.2-alpine de529845c111 6 days ago 50.69 MBProduction
FROM 7.10.0-alpine
ADD . /app
WORKDIR /app
CMD npm start
'.' should be a directory containing your built application without dev dependencies, tests and anything else that isn't needed by your application at runtime.
Build steps
- Build development docker image
- Run tests inside development container
- Remove all non runtime specific files
- Build and publish your production docker image with your built artefact.
- Run smoke tests on the running image in a test environment.
- Repeat in production.
Multi stage pipelines
- A new native docker (17.05+) solution for intermediate build and test containers in a single Dockerfile
https://codefresh.io/blog/node_docker_multistage/
Tip No5
Use docker-compose





version: '2'
services:
openshift:
build:
context: './src/test/containers/openshift'
dockerfile: 'Dockerfile'
service:
build:
context: './src/test/containers/service'
dockerfile: 'Dockerfile'
mutual-ssl-service:
build:
context: './src/test/containers/mutual-ssl-service'
dockerfile: 'Dockerfile'
api:
build:
context: '.'
dockerfile: dev.Dockerfile
image: 'yaapi'
expose:
- '3000'
links:
- service
- mutual-ssl-service
- openshift
environment: '...'
command: sh -c 'npm start | node_modules/.bin/bunyan'
tests:
container_name: tests
image: yaapi
command: 'npm test'
working_dir: /app
links:
- api
- serviceOther tips
- Get a build monitor
- Integrate with pull requests
- Try yarn
- Run your tests in parallel
Faster CI with node and docker
By Will Munn
Faster CI with node and docker
- 375