A FoundationDB CI framework that provides an environment for building and testing code that depends on FoundationDB. Works identically on your local machine and in GitHub Actions.
- Provides a base container with the FoundationDB client library
- The base container may be extended by providing a custom Dockerfile
- Automatically starts an FDB container for integration testing
- Configures the client container with the appropriate cluster file
- Supports both local development and GitHub Actions workflows
- Caches Docker images in CI to prevent rebuilds on every workflow run
- Provides a
/cachedirectory that persists between container runs
Add fenv as a git submodule in your project:
git submodule add https://github.com/janderland/fenv.gitLocal development:
./fenv/fenv.sh --build --exec fdbcli --exec "status"GitHub Actions:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./fenv
- run: ./fenv/fenv.sh --exec fdbcli --exec "status"You can extend the base fenv image with your own build tools and dependencies by providing a custom Dockerfile.
Create a Dockerfile that uses the fenv base image:
ARG FENV_DOCKER_TAG
FROM fenv:${FENV_DOCKER_TAG}
# Install Go
RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xz
ENV PATH="/usr/local/go/bin:${PATH}"
ENV GOCACHE="/cache/gocache"
ENV GOMODCACHE="/cache/gomod"
# Install golangci-lint
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
sh -s -- -b /usr/local/bin v1.62.2
ENV GOLANGCI_LINT_CACHE="/cache/golangci-lint"The FENV_DOCKER_TAG argument is automatically provided and ensures your extended image is based on the correct version of fenv.
The /cache directory is backed by a Docker volume that persists between container runs. This makes it an ideal location for build and test caches (as shown in the example above with Go's module cache and golangci-lint cache).
Extended images are automatically namespaced by project to prevent collisions when multiple projects use fenv. The image name format is fenv-ext-{project_name}:{tag}.
The project name is determined in the following order:
- Explicit
FENV_PROJECT_NAMEenvironment variable - Git remote repository name (e.g.,
myprojectfromgit@github.com:user/myproject.git) - Current directory name as a fallback
This ensures that different projects can have different extended images without interfering with each other, even if they happen to be at the same git commit hash.
Use the fenv.sh script to manage your development environment:
# Build the fenv container (and optionally an extended image)
./fenv/fenv.sh --build
./fenv/fenv.sh --docker ./Dockerfile --build
# Execute commands in the container
./fenv/fenv.sh --exec fdbcli --exec "status"
# Interactive shell
./fenv/fenv.sh --exec bash
# Tear down containers and volumes
./fenv/fenv.sh --down
# Show help
./fenv/fenv.sh --helpThe script can be called from any directory. Your current working directory is automatically mounted as the container's working directory at /src.
A common pattern is to create a ci.sh script that invokes fenv with your build and test commands:
#!/bin/bash
./fenv/fenv.sh \
--docker ./Dockerfile \
--build \
--exec sh -c '
shellcheck ci.sh
hadolint Dockerfile
go build ./...
golangci-lint run ./...
go test ./... -timeout 5s
'This script can be run both locally and in CI, ensuring identical behavior.
Set the FENV_FDB_VER environment variable to use a different FoundationDB version:
FENV_FDB_VER=7.3.43 ./fenv/fenv.sh --buildUse the fenv action in your workflows:
name: test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./fenv
with:
ext_dockerfile: './Dockerfile'
- run: ./ci.shThe action automatically:
- Sets up Docker Buildx
- Caches the FDB server image
- Builds and caches your extended image (if provided)
- Exports environment variables for subsequent steps
Use a matrix strategy to test against multiple FoundationDB versions:
jobs:
test:
strategy:
matrix:
fdb_ver: ['7.1.61', '7.3.43']
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./fenv
with:
fdb_ver: ${{ matrix.fdb_ver }}
ext_dockerfile: './Dockerfile'
- run: ./ci.shUser-configurable:
FENV_FDB_VER: FoundationDB version (default:7.1.61)FENV_CACHE_VOLUME: Custom cache volume name (optional)FENV_PROJECT_NAME: Project name for namespacing extended images (optional, auto-derived from git remote or directory name)
Auto-computed (available after running fenv):
FENV_DOCKER_TAG: Docker tag for the base fenv imageFENV_EXT_DOCKER_TAG: Docker tag for the extended image (if built)FENV_IMAGE: Selected image name used by docker compose
Container-internal (used by shim.sh entrypoint):
FENV_FDB_HOSTNAME: FDB server hostname (default:fdb)FENV_FDB_DESCRIPTION_ID: Cluster description:id (default:docker:docker)
| Name | Description | Required | Default |
|---|---|---|---|
fdb_ver |
FoundationDB version | No | 7.1.61 |
ext_dockerfile |
Path to custom Dockerfile for extending fenv image | No | - |
project_name |
Project name for namespacing extended images | No | Repository name |
| Name | Description |
|---|---|
fenv_docker_tag |
Docker tag for base fenv image |
fenv_ext_docker_tag |
Docker tag for extended image (if built) |
fenv_ext_image_built |
Whether extended image was built (true/false) |
The base fenv image includes:
- OS: Debian 12
- FoundationDB: Client library and
fdbclicommand-line tool - Linters:
shellcheck(v0.10.0),hadolint(v2.7.0) - Utilities:
jp(JMESPath CLI v0.2.1) for JSON processing - Build Tools:
git,curl,build-essential
See fdb-mutex for a complete example showing:
- Custom Dockerfile extending fenv with Go toolchain
- ci.sh script for build and test
- GitHub Actions workflow integration