One of the subtler and fantastic parts of the
DockerFile specs is the ability to copy files from one image to another. Today we'll show how to build and deploy from a single file. If we describe a very simple
FROM node:8 as builder RUN npm install RUN npm run build FROM nginx:latest as http COPY --from:builder /usr/app/dist /usr/share/nginx/html
If you don't know much about
Dockerfile then please go read some other better intro's, otherwise you'll hopefully notice the oddity of the double
FROM command. What's happening here is the following:
nodemachine is spun up.
- Node build the site.
- Docker then copies the
distdirectory from the Node image into the
nginxserver to be hosted.
The Linux lot of you will note this technique is just an extension of the make-it-yourself paradigm, but in a way that's seperate of the usual build-dependency chaos.
But could we go faster?
That's it really, we have an image that deploys a node project. But I use this model in my CI and waiting for a full NPM install on a major project is a pain, so I've split the
RUN npm run build step into a two stage process:
FROM node:8 as builder COPY package*.json ./ RUN npm install COPY .babelrc .env.* *.js *.webmanifest *.json *.html ./ COPY src ./src RUN npm run build FROM nginx:latest as http COPY --from:builder /usr/app/dist /usr/share/nginx/html
See Docker has an very powerful cache layer, allowing any step to be skipped if every prior step was identical in it's input. The theory being, is that if the
package.json file hasn't changed, then both the
RUN npm install step's are skipped allowing it to only worry about the more likely source change.
But what about nginx's configuration?
This is the even cooler and slightly contentious bit. A bigger project would argue that the following is a bit dirty, but if you appreciate my side-projects are a solo show then you might forgive me.
All my services describe how they're hosted and their configuration, within their repo. So by that I mean my code contains both the source, and the configuration code describing the hosting process, meaning they're responsible all the way up to responding correctly on 80.
That means the
nginx.conf sits next to my projects source code(a sys-admin wretches in the corner). This inversion of duty is frankly amazing to run solo. I can run every project both locally and on a cloud server with literally the same build pipeline. On the cloud it's behind an HTTP's load-balancer to provide TLS, and locally I simply connect to an exposed 80.