line-fact-check is a free and open source fact checker platform.
It is structured as a multi-language monorepo, with focus on cross-platform development.
Note: this Docker Compose setup uses Docker daemon socket mount for it to be able to load images to host Docker daemon. This has security implications, but since everything is controlled by Nix, the risk is minimized.
We still need a better way to pin Docker Compose's services to images built by the build service.
Because Nix use is encouraged in the build process, the best way to bring up the project's environment
is to use Docker Compose to fire up a nixos/nix
container to build and run images locally without
having to install Nix on your local machine.
To pre-build, build, or rebuild the images, run
Note that this has a side-effect of loading whatever images we're building with
compose
tag
# Start build-images service
# This will build the Docker images and load it to your host Docker daemon
docker-compose up build-images
After build-images
has finished, we can bring up other components:
docker-compose up
To simplify and minimize Nix build time, we use stateful multi-stage Docker Compose definition for each compose run. Each run is also attached to a Docker volume, which is shared across runs, so that we can cache Nix store across builds.
You must manually clean up your Nix store cache volume.
build-images
is our build service for our compose.
The service is stateful in that it copies your working directory into the container when it starts. That is used to build images for the entire compose.
The built images is tagged with latest
, so that downstream app services can find them.
The rest of services are our app components: the HTTP backend, frontend, and PostgreSQL database.
To rebuild images for the compose after code changes, bring current compose down and bring up
a new build-images
.
If rebuilding does not work (i.e. app components still point to old versions),
try removing the old images before bringing up build-images
again,
or use our cheat sheet.
to manually build new images.
We use Nix flake to pin everything and have reproducible builds.
Nix flake is heavily used in our GitHub Actions CICD pipelines, and it does most of the heavy lifting of setting stuff up.
Thanks to Nix flake, we can build this repository without having to clone it first:
# Build from branch main
nix build\
--extra-experimental-features nix-command \
--extra-experimental-features flakes \
github:kaogeek/line-fact-check/main#docker-factcheck
This ensures that every one of us and the pipelines always have the same build and test environment.
The project's outputs or artifacts are all defined as flake outputs.
For example, our backend in /factcheck is built into Go binary as flake output #factcheck
. Another output docker-factcheck
is just #factcheck
inside a Docker image.
However, most of our devs don't have Nix installed locally. But most have Docker.
To hack around this, the official NixOS image nixos/nix
is actually very handy.
We can run the NixOS container and use it to try to interact with Nix:
# Try Nix command
docker run -it nixos/nix:latest
The simplest way to run this project via Nix is by referencing the remote GitHub repository. We do this by running a NixOS container (with mounted volume).
We then use Nix inside that to build our image within the container. We finish off by copying the result to host machine filesystem, mounted at /workspace within the container
docker run --rm -v $(pwd):/workspace nixos/nix:latest sh -c \
"nix build github:kaogeek/line-fact-check/main#docker-factcheck --extra-experimental-features nix-command --extra-experimental-features flakes && cp result /workspace/"
The command above, while simple, will write result to your ./result
. This is stateful, and will break if run back-to-back. This script will fix that by appending our flake "version" to the name of file.
Differences to example above
-
Read from local directory instead of remote GitHub repository with
.#docker-factcheck
-
Cache Nix store with simple Docker volume with
-v line-fact-check-nix-store:/nix/store
. -
Unique output, where FLAKE_VERSION is appended to the result image filename
docker run --rm -v $(pwd):/workspace -v line-fact-check-nix-store:/nix/store nixos/nix:latest sh -c '
cp -r /workspace /source
cd source
export FLAKE_VERSION="$(nix eval --extra-experimental-features nix-command --extra-experimental-features flakes .#version.text --raw)"
# Build docker-factcheck with unique result name using the actual flake version
nix build .#docker-factcheck --extra-experimental-features nix-command --extra-experimental-features flakes
# Copy the result to workspace
cp result /workspace/result-factcheck-$FLAKE_VERSION
echo "copied to /workspace/result-factcheck-$FLAKE_VERSION"
'