Best Practices

Dockerfile Centric Development

David Gu

December 4, 2022

Table of Contents

At Recall, we work with a large number of different technologies. From Rust in our real-time media pipelines, to Python + Django in our web-server, to C# and C++ for specific meeting platform integrations.

We also use different operating systems during development (Debian Linux or MacOS), and a lot of the code we write needs to interface with system libraries which are easy to install via a package manager, but painful to build from source.

Because of this, there are a huge variety of versioning issues that could occur in our Linux production environment, but not in a MacOS development environment for example. There are also a number of dependencies that don't have pre-built binaries for MacOS, and are difficult to build from source.

Our Solution

Our solution to this problem is to make our development workflows "Dockerfile Centric". What this means is that:
1. Every project contains a `Dockerfile` with 2 stages, `dev` and `prod`
2. When developing the project, we run the `Dockerfile`, targeting the `dev` stage, and mount the project folder. It's helpful to put this into a script:


bash
	$ cat run-dev-container.sh
  
	#!/bin/bash
	export DOCKER_BUILDKIT=1
  
  image_id_file=$(mktemp)
  docker build \
  	--file $(pwd)/Dockerfile \
  	--target dev \
  	--iidfile $image_id_file \
  	.
    
  docker run \
  	--network host \
  	-v $(pwd):/app \
  	-it \
  	$(cat $image_id_file)


3. We then use VSCode's Remote Development feature to connect to the container.
4. When deploying the project to production, we deploy the same `Dockerfile`, built targeting the `prod` stage.