$ run as a normal user# run as root (or with sudo)
Skills in this chapter
- Build tools and package managers — 5 tools
make — one task runner for every project
make gives every project the same short commands: make build, make test, make deploy.
- Used for: a task runner around docker, go, npm or terraform; the same steps locally and in CI.
Good practice:
- Mark task targets
.PHONY; recipe lines start with a Tab. - Keep long logic in scripts; the Makefile only calls them.
- CI runs the same targets as developers (
make lint test).
npm — Node.js packages and scripts
npm installs the dependencies of a JavaScript project and runs its scripts.
pip — Python packages
pip installs Python packages, best inside a virtual environment.
- Used for: Python services, scripts, and tools like Ansible.
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pip freeze > requirements.txt
pip install --no-cache-dir -r requirements.txtGood practice:
- Never
sudo pip installon the system Python. - Pin versions (
==) or use a lock file with hashes.
Maven — Java builds
mvn builds, tests and packages Java apps from pom.xml and pushes the JAR to an artifact repository.
Go — the language of cloud-native tools
go builds one static binary — perfect for tiny container images and internal tools.
- Used for: CLIs, exporters, Kubernetes operators; reading the code of Docker, Kubernetes and Terraform.
go mod tidy
go test -race ./...
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o bin/app .
GOOS=linux GOARCH=arm64 go build -o bin/app-arm64 .Good practice:
- Commit
go.modandgo.sum; rungo vetandgovulncheckin CI. - Build static binaries and use a distroless or scratch base image.
Use the same build in every place
"It works on my machine" ends when the build runs in a container with pinned versions.
- Pin the tool versions (Node 22, Go 1.23, Java 21) in the Dockerfile or CI file.
- Use the lock file of the language (
package-lock.json,go.sum,requirements.txtwith==). - Build in a multi-stage Dockerfile: big build image, small run image.
- Cache the package folders in CI (
~/.npm,~/.m2,~/go/pkg/mod). - Push the result to an artifact or image registry, never rebuild the same version twice.
Remember
Build once, deploy the same artifact to dev, staging and production.