Containing Software
work in progressThere are many reasons nobody should ever run npm install.1
The same is true for many other package-mangement systems or, really, any kind
of command. Yet this industry subsists on working against our better judgment,
so sometimes that’s inevitable.
In such cases, we might resort to containerization, which at least limits semi-trusted commands to a controlled environment. In its most basic form, we might use one-off containers – for example, spinning up an Arch Linux system:
$ podman run --rm --interactive --tty \
archlinux/archlinux:base-devel shHere we can play around with the command line, largely without worrying about consequences for our host system: With this setup, what happens inside the container stays inside the container – which is discarded after use.
That’s not what we want in this context though: Typically we want to effect changes within the host’s file system, specifically within the current working directory – so we mount that as volume to make it available from within the container:
$ podman run --rm --interactive --tty --userns keep-id \
--volume "$PWD:/home/dev" \
--workdir "/home/dev" \
archlinux/archlinux:base-devel shFor convenience, we also use that shared directory as our working directory
within the container. --userns keep-id ensures that file permissions
correspond to the host system’s when modifying our shared directory.
Thus we can run npm install within the container to share the gravitational
burden of node_modules with the host system.
Except Node isn’t actually available within that image. Let’s build our own:
FROM alpine:latest
RUN apk update
RUN apk upgrade
RUN apk add nodejs
RUN apk add npm
RUN adduser -D peon
USER peon$ podman build --pull=always \
--tag dev:node - < Containerfile.nodeBecause we don’t want our container to depend on any additional files, we use an empty build context here.
We’ve called this image dev:node, so we can use that to launch our Node
container:
$ podman run --rm --interactive --tty --userns keep-id \
--volume "$PWD:/home/dev" \
--workdir "/home/dev" \
dev:node shReusable shell script
#!/usr/bin/env sh
set -eu
name="fndev"
platform="${1:?missing positional argument for platform}"
tag="$name:$platform"
if [ "${2:-""}" = "rebuild" ]; then # XXX: crude
shift
echo "building container image"
podman build --pull=always --tag "$tag" - < "Containerfile.$platform"
fi
hwd=${2:-"$PWD"}
cwd="/home/$name"
podman run --rm --interactive --tty --userns keep-id \
--volume "$hwd:$cwd" --workdir "$cwd" \
"$tag" sh