Streamlining Development: Setting Up Preview Environment in fly.io with Pull Requests

Satya Swaroop Mohapatra's avatar

Satya Swaroop Mohapatra

Regarding app deployment on Fly, their documentation excellently outlines the simplicity of utilizing commands like fly launch followed by fly deploy, which seamlessly sets up an app on the Fly dashboard and assigns VMs for both the main application and its database. However, a notable omission is the inability to establish preview environments directly from the main application. Luckily I found one github action called superfly/fly-pr-review-apps, but there are some issues with the action , which throws an error if we directly implement it. So we have forked (codemancers/fly-pr-review-apps) the repository into our organization and made some modifications and optimizations, which resulted in generating a preview URL smoothly.

Brief Overview of What This Blog Will Guide You Through

This guide is designed to assist in creating a preview environment on Fly upon the initiation of a pull request, ensuring that the primary application and database instances remain unaffected.

Diving straight into the magic!

Requirements

  1. Make sure you have a personal/organisation account in fly.
  2. Create an organization token in Fly by navigating to dashboard -> tokens.
  3. Ensure you have an existing Dockerfile that is used for building our app in the production environment.
  4. Ensure you have an existing fly.toml file that is used for the production environment.
  5. Make sure to set all the app secrets beforehand in GitHub secrets.
  6. Provision a Postgres cluster in Fly that will be exclusively used for preview environments (the reason will be clarified in later steps).

Once all the prerequisites are ready, we can proceed.

Create a preview YAML file in your .github/workflows directory. I will name it as fly-preview.yml.

name: Preview App
 
on:
  pull_request:
    types: [opened, reopened, synchronize, closed]
 
env:
  FLY_API_TOKEN: ${{ secrets.FLY_ORG_TOKEN }}
  FLY_REGION: <specify your region>
  FLY_ORG: <specify your org>
 
jobs:
  staging_app:
    runs-on: ubuntu-latest
 
    # Only run one deployment at a time per PR.
    concurrency:
      group: pr-${{ github.event.number }}
 
    # Create a GitHub deployment environment per staging app so it shows up
    # in the pull request UI.
    environment:
      name: pr-${{ github.event.number }}
      url: ${{ steps.deploy.outputs.url }}
 
    steps:
      - uses: actions/checkout@v4
 
      - uses: superfly/flyctl-actions/setup-flyctl@master
 
      - name: Deploy
        id: deploy
        uses: codemancers/fly-pr-review-apps@main
        with:
          dockerfile: ./Dockerfile
          postgres: <your-preview-db-name> # the one that i mentioned to create one in the requirements section
 
      - name: Set secrets in Fly
        if: ${{ github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' }}
        run: |
          flyctl secrets set -a reponame-pr-${{ github.event.number }} \
          EXAMPLE_SECRET=${{ secrets.EXAMPLE_SECRET }} \
 
      - name: Update image
        if: ${{ github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' }}
        run: flyctl image update -a reponame-pr-${{ github.event.number }} --skip-health-checks -y
 
      - name: Clean up GitHub environment
        uses: strumwolf/delete-deployment-environment@v2
        if: ${{ github.event.action == 'closed' }}
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          environment: pr-${{ github.event.number }}
 

Obviously, I will explain each and every step; don't worry, I've got you covered.

Workflow Name

name: Preview App

This sets the name of the workflow as "Preview App," which appears in the GitHub Actions section of your repository.

Trigger Event

on:
  pull_request:
    types: [opened, reopened, synchronize, closed]

The workflow is activated by pull request events, specifically when a PR is opened, reopened, synchronized (updated), or closed.

Environment Variables

env:
  FLY_API_TOKEN: ${{ secrets.FLY_ORG_TOKEN }}
  FLY_REGION: <specify your region>
  FLY_ORG: <specify your org>

Global environment variables are defined:

FLY_API_TOKEN: The Fly.io API token, fetched from GitHub Secrets, for authentication. FLY_REGION: Specifies the deployment region on Fly.io. FLY_ORG: The Fly.io organization under which the apps will be deployed.

Jobs

The workflow includes a job named staging_app that utilizes the latest Ubuntu runner from GitHub Actions.

Concurrency

concurrency:
  group: pr-${{ github.event.number }}

This configuration ensures a single deployment per PR at any time, avoiding conflicts or resource duplication.

Environment

environment:
  name: pr-${{ github.event.number }}
  url: ${{ steps.deploy.outputs.url }}

Creates a unique GitHub deployment environment for each staging app, linked to the PR UI, with the url dynamically reflecting the deployed app's URL.

Steps

The job comprises several steps for deploying the application:

  • Checkout: Fetches the repository code for workflow use.
  • Setup Flyctl: Installs Fly CLI (flyctl) to interact with Fly.io.
  • Deploy: Deploys the app to Fly.io using a custom action codemancers/fly-pr-review-apps@main, specifying the Dockerfile and an existing Postgres cluster yourapp-preview-db. name for the attachment.
  • Set Secrets in Fly: Applies app-specific secrets on Fly.io. Executes only when the PR is opened, reopened, or updated.
  • Update Image: Ensures the app uses the latest image on Fly.io, this will make sure our PR changes are reflected in the preview URL. It is only triggered when PR is opened, reopened, or updated.
  • Clean up the GitHub Environment: Cleans up the GitHub deployment environment upon PR closure using strumwolf/delete-deployment-environment@v2, managing resources efficiently.

The good news is that it will automatically destroy the preview app on Fly when the PR is merged or closed. Additionally, we can open multiple PRs in parallel, and each PR will be distinct from the others.

This workflow streamlines the deployment, updates, and management of preview environments for PRs, facilitating live review and testing of changes before merging.

That's it! What are you waiting for? Go ahead and start implementing it to improve your development workflow. Thank me later 😄

References