A docker with a multi-stage approach to minimize image size and build time (taking advantage of buildx cache).
.
├── apps
│ └── hobbies-helsinki
├── packages
│ ├── core
│ ├── db-main-prisma
│ └── components
├── static
│ ├── assets
│ └── locales
├── .dockerignore
├── docker-compose.hobbies.yml (specific for hobbies-helsinki)
├── docker-compose.yml (optional: general services like postgresql...)
└── Dockerfile (multistage build for all the apps)
- docker-engine >= 20.10.0
- docker-compose >= 1.29.0
- docker buildkit enabled.
- optional: lazydocker, a beautiful tui.
- optional: dive to debug layer sizes.
Note: Be sure to create a .dockerignore containing at least those entries.
Yarn script | Description |
---|---|
yarn docker:hobbies:develop |
Run apps/hobbies-helsinki in development mode |
yarn docker:hobbies:install |
Install dependencies in cache mount |
yarn docker:hobbies:build |
Create a production build |
yarn docker:hobbies:serve |
Serve production build on localhost:3000, |
yarn docker:prune-cache |
Run this regularly if using in local !!! |
Build and serve commands requires to have a
./apps/hobbies-helsinki/.env.local
present.
yarn docker:hobbies:develop
# Or alternatively
DOCKER_BUILDKIT=1 docker-compose -f ./docker-compose.yml -f ./docker-compose.hobbies.yml up develop
Want to open a shell to debug ?
DOCKER_BUILDKIT=1 docker-compose -f ./docker-compose.hobbies.yml run --rm develop sh
See the latest ./docker-compose.hobbies.yml and ./Dockerfile.
PS: The goal of multistage is mainly to reduce the size of the resulting image, it also allows to skip deps stage (ie: install deps) when no changes are detected in your deps (lock file).
Note: The Kolga tools picks the last stage by default, so the production builder should be the last stage in the Dockerfile.
This stage will install the monorepo and make all node_modules folders available in later stages.
Some commands
To build it independently
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --progress=tty deps
# docker buildx bake -f docker-compose.hobbies.yml --progress=tty deps
To force a rebuild
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --no-cache --force-rm --progress=tty deps
Want to open a shell into it ?
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml run --rm deps sh
This stage will automatically run the deps stage and copy all installed node_modules folder. Then build the thing and remove devDependencies.
PS: You'll have to send some build-args (env variables) in order to have a real build.
Some commands
To build it independentlyDOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --progress=tty builder
# docker buildx bake -f docker-compose.hobbies.yml --progress=tty builder
To force a rebuild
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --no-cache --force-rm --progress=tty builder
Want to open a shell into it ?
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml run --rm builder sh
Launch a production build and listen by default to http://localhost:3000.
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml --env-file .env.secret up runner
PS: you'll have to provide your own .env with required runtime variables.
Some commands
To build it independentlyDOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --progress=tty runner
# docker buildx bake -f docker-compose.hobbies.yml --progress=tty runner
To force a rebuild
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml build --no-cache --force-rm --progress=tty runner
Want to open a shell into it ?
DOCKER_BUILDKIT=1 docker-compose -f docker-compose.hobbies.yml run --rm runner sh
The Openshift environment (that the project uses) does not support caching of the multistage builds. Because of that, we are first creating a cache image out of the deps that the apps needs. We then use the cached image as a base for the actual runner image.
There are 2 different apps related docker files:
- Dockerfile, to define a multistage (deps, builder, runner) image for the apps
- DockerfileCache, to define a cache image for the apps dependencies, which can be used as a base image when building the app image multiple times in the CI pipelines.
Using the Sports-Helsinki app as an example.
Build the cache-image (for the Sports-Helsinki app):
docker-compose -f docker-compose.sports.yml --env-file ./apps/sports-helsinki/.env.local build cache
Build the app runner image (for the Sports-Helsinki app) by using the cache-image as a base image:
BUILDER_FROM_IMAGE=events-helsinki-monorepo-cache:latest docker-compose -f docker-compose.sports.yml --env-file ./apps/sports-helsinki/.env.local build runner
Option | Command |
---|---|
Prune buildx | docker buildx prune |
Prune cachemount caches | docker builder prune --filter type=exec.cachemount |
Remove all containers | docker container rm -f $(docker container ls -qa) |
Clean all images | docker image rm -f $(docker image ls -q) |
Remove all volumes | docker volume rm $(docker volume ls -q) |
Like to remove all docker layers, overlays... Warning you'll lose all your data.
systemctl docker stop
rm -rd /var/lib/docker
systemctl docker start