My Docker contexts, visualized
Published on 07 June 2019

Better Monorepo Container Builds with Context Filters

Published on 07 June 2019

If your project has multiple microservices in one git repo, Docker builds can be frustrating.

Changing a file that’s only used in one service can cause a slow image build in another service. If you’re using a tool like Tilt that builds each time you save a file that same save now kicks off multiple builds. Your workflow shouldn’t be slower just because of how you organize your code.

You can now eliminate slow and spurious rebuilds by using Tilt’s new context filters. Let’s look at an example, but basically this is a Tiltfile with 4 services built from the same context so they can share code.

Example

Let’s look at an app with 4 services:

  • frontend

  • shopping_cart

  • users

  • fulfillment

The repo has code for each in a directory, common code for your app, and vendored dependencies:

  • common/

  • frontend/

  • shipping/

  • cart/

  • users/

  • vendor/

The simple Tiltfile looks like

docker_build(‘frontend’, ‘.’, dockerfile=’Dockerfile.frontend’)

docker_build(‘cart’, ‘.’, dockerfile=’Dockerfile.cart’)

docker_build(‘users’, ‘.’, dockerfile=’Dockerfile.users’)

docker_build(‘shipping’, ‘.’, dockerfile=’Dockerfile.shipping’)

When you change a file in the users service, Tilt rebuilds every image (because it’s in the context .). This causes extraneous rebuilds and wastes time.

.dockerignore solves this problem on a per directory basis. However, if you want to exclude a directory only from some builds you’re out of luck. This is what Tilt’s new context filters enable.

Per-Image Context Filters

With the onlycontext filter you can specify which patterns should trigger a build.

docker_build(‘frontend’, ‘.’, dockerfile=’Dockerfile.frontend’, only=[‘frontend’, ‘common’, ‘vendor’])

docker_build(‘cart’, ‘.’, dockerfile=’Dockerfile.cart’, only=[‘cart’, ‘common’, ‘vendor’)

docker_build(‘users’, ‘.’, dockerfile=’Dockerfile.users’, only=[‘users’, ‘common’, ‘vendor’])

docker_build(‘shipping’, ‘.’, dockerfile=’Dockerfile.shipping’, only=[‘shipping’, ‘common’, vendor’)

Now when we change a file in the users service, only the user service rebuilds. But when we change a common file, all the services rebuild.

We can tidy up our Tiltfile with a helper function:

def service_build(name):

docker_build(name, ‘.’, dockerfile=’Dockerfile.’+name, only=[name, ‘common’, ‘vendor’]

service_build(‘frontend’)

service_build(‘cart’)

service_build(‘users’)

service_build(‘shipping’)

Tools Shouldn’t Care How You Organize Your Code

If you’re using a monorepo with multiple microservices now is a great time to give Tilt a spin. We’ve designed Tilt to work with any setup, any architecture, no matter how complex. If you have a funky architecture get in touch and we’ll show you how to get Tilt up and running.


Originally posted on the Windmill Engineering blog on Medium

Related

Keep up with Developments in Microservice Development
 
 
 
Keep up with Developments in Microservice Development

Already have a Dockerfile and a Kubernetes config?

You’ll be able to setup Tilt in no time and start getting things done. Check out the docs! 

Having trouble developing your servers in Kubernetes?