Dagger in Action: Restoring Developer Confidence in CI
Read more

Dagger in Action: Going from Pull Request to Production Faster at Discern

August 10th, 2023
Dagger Power User - James Qualls at Discern

We’re always interested in hearing how fellow Daggernauts are using Dagger – their use cases, their challenges, and their experiences with deploying Dagger in different environments. Our Discord is a great place to find these stories, and to benefit from the knowledge and experience of the Dagger community.

In this blog post, we’ll share the story of James Qualls (aka devdna on Discord). James, a Principal Engineer at Discern, turned to Dagger to power Discern's highly sophisticated and optimized CI/CD system, which automatically builds and ships a full ephemeral copy of the application on every pull request. Since each ephemeral copy runs in isolation, this system enables Discern's developers to build and test multiple features or versions of the application simultaneously yet independently. Approved builds can be deployed almost instantaneously to production through the same pipeline.

" We want to be able to ship every single day, multiple times a day, as fast as we possibly can. Dagger is enabling us to do that." - James Qualls, Principal Engineer, Discern

The problem: Enabling developers to test and ship features faster

Discern's application consists of an API server written in Go and a Web front-end written in React, bundled together with various dependencies such as PostgreSQL and Temporal. Instead of deploying all test builds to a common staging environment, James' goal was to build a CI/CD pipeline that would enable the development team to rapidly deploy test builds in independent preview environments on Kubernetes.

James was already familiar with Dagger from his previous work with Terraform, Docker and Buildkit, and had been watching it evolve over time. Dagger's introduction of multi-language SDKs, especially the Go SDK, and its programmatic "wrapper" around Docker and Buildkit made it a logical choice for Discern's CI/CD implementation. 

Dagger's open source codebase also meant that the team was able to easily investigate features marked experimental and determine whether it made sense to leverage them. Finally, observing the active Dagger community in action and seeing that user feedback was addressed quickly, mitigated some of the team’s concerns about deploying open source technology for this critical infrastructure. 

"Knowing that our voice could easily be heard in the community and seeing that there was consistency and transparency in how the Dagger team addressed issues, played a huge role in our decision to confidently move forward with using an open source tool."

The solution: Parallelized builds and ephemeral previews with Dagger and Kubernetes

Discern's Dagger pipeline is written using Dagger's Go SDK and uses Dagger's experimental caching feature. It triggers on every pull request and begins by creating two images in parallel: a back-end image for the API server containing Go modules and dependencies, and a front-end image for the Web application containing Node.js dependencies. These images are pushed to a registry and then fed into a Kubernetes deployment managed by GKE Autopilot. The Kubernetes deployment contains multiple pods: one each for the API server, the Web application, a Temporal orchestrator and a PostgreSQL database service.

Once the deployment is completed, the pipeline queries Kubernetes for the address of the database service, runs database migrations and then notifies the user with a preview deployment URL. After the deployment is verified and the pull request is approved and merged, the same pipeline executes again, but against a different production namespace. By virtue of the experimental Dagger cache, the second pipeline execution is extremely fast, resulting in almost instantaneous deployment to production. When the pull request is closed, the pipeline also cleans up after itself by deleting the preview deployment using the Kubernetes SDK.

"Dagger has given us a fast, seamless way for us to spin up an entire version of our application the same way that we would do it if we were running it locally. Every GitHub pull request gets a full copy of the front-end, the back-end, all of our dependencies, Postgres, Temporal, in one neat little bundle. It also gives us confidence that on a per-pull request basis, we're able to test and verify any feature before we actually merge it into production."

The results: Native tooling with rapid and seamless production deployment

By using Dagger as the backbone of its CI/CD system, Discern has benefited in several ways:

  • Native Go support makes it easier for the team to programmatically control what happens in parallel and what happens serially, and to wire other tools (such as the Kubernetes SDK) into the pipeline. Since the team consists of mainly Go programmers, this also means that all the developers in the team are able to participate in the development and maintenance of the pipeline.
  • Using Go makes it easier to change and manipulate the pipeline using the code intelligence features built into most IDEs. Go's built-in type safety ensures that any contractual change to the Dagger APIs is immediately flagged to the developers, and smart refactoring makes it easy to find and update affected pipeline code globally.
  • Instead of constantly deploying to a common staging environment, each developer gets an isolated instance of the complete application. This allows for more sophisticated testing, such as running end-to-end browser-based tests against the Web application, and also eliminates issues caused by stale data inside a shared staging environment.
  • The same Dagger pipeline works consistently both locally and remotely, reducing the feedback loop when modifying the pipeline - for example, when adding tests for a new database engine or a new feature flag.
  • Dagger's experimental caching feature reduces the time required for each CI run, which in turn reduces the time taken for a new feature to go from staging to production.

"The experimental cache took a 15-minute build down to a 2-minute build...this is pretty significant for us."

The future: Reducing build times with improved caching and pipeline optimization

Going forward, one improvement already on James’ radar is to replace the experimental caching with the improved Dagger caching experience that is coming soon with Dagger Cloud. He also hopes to optimize other parts of the pipeline by using optimized base images with all required dependencies already baked in.

Dagger's Go support will be key to making these and other changes, as it allows any member of the engineering team to easily understand the pipeline syntax, refactor and optimize pipeline operations, and integrate new Dagger features as they are released.

“Dagger has given us the ability to build, test, and ship our software in a highly scalable manner from day one. Over the lifetime of our product, this will save us thousands of engineering hours trying to manually debug why our pipeline doesn't work in a traditional hosted CI system like GitHub Actions or Gitlab. I do see us evolving and improving our pipeline for the next five years easily with this system."

Do you have a Dagger story you’d like us to feature? Tell us all about it in Discord!