Managing multiple environments

There’s great content here. I will leave here also how we do it (similar to @aswinmohanme):

build-and-deploy:
  name: Build and deploy
  runs-on: ubuntu-latest
  needs: 
    # (...)
  steps:
    - uses: actions/checkout@v2

    - uses: superfly/flyctl-actions/setup-flyctl@master
    
    - run: flyctl -a our-app-staging deploy --remote-only
      if: github.ref == 'refs/heads/develop'
      env:
        FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

    - run: flyctl -a our-app-production deploy --remote-only
      if: github.ref == 'refs/heads/main'
      env:
        FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

Locally there’s a handy env var FLY_APP (ex: export FLY_APP=our-app-name) , you could also pass -a our-app-name on every fly command or

1 Like

I like the idea of having the two scripts. But I was also thinking having something akin to the Heroku piplines could be nice.

A caveat: This -a <staging-or-prod> trick doesn’t work with Machine apps (yet): Preview: Deploying applications on Machines with flyctl - #6 by ignoramous

Well, “pipelines” seems to be on Fly’s roadmap anti-roadmap: Rough edges for multi-app services - #2 by kurt

I keep the app name in the fly toml the staging app, and when I want to deploy production I promote the latest staging image to production, so I never build a new image for production, simply deploy one of staging’s images:

#!/usr/bin/env ruby
require "json"

js = JSON.parse(`flyctl image show --json`)
registry = js["Registry"]
tag = js["Tag"]
repo = js["Repository"]
production_app = "app-production"

cmd = "flyctl deploy -i #{registry}/#{repo}@#{tag} -a #{production_app}"
puts "----> Running #{cmd}"
system(cmd)
1 Like

Ah, similar to: Deploy fly apps using custom made bot - #3 by kurt

This works because I guess you must have already deployed the required config (aka fly.toml) to prod at least once?

Sharing my solution here.

I have two apps deployed: foo.fly.dev and foo-dev.fly.dev.

Make sure you create them running: flyctl deploy -a <appn_ame>.

The toml file does not have an app name and my gh workflow is this:

➜ cat .github/workflows/fly.yml
name: Fly Deploy Prod
on:
  push:
    branches:
      - main
      - dev
env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - name: run_flyctl
        run: |
          echo "github.ref is: ${{github.ref}}"
          if [[ "${{github.ref}}" == "refs/heads/main" ]]; then
            echo "deploying to PROD"
            flyctl deploy --remote-only -a drio-fly
          fi
          if [[ "${{github.ref}}" == "refs/heads/dev" ]]; then
            echo "deploying to DEV"
            flyctl deploy --remote-only -a drio-fly-dev
          fi
3 Likes

@drio I’m new to fly.io but I generally like what you’ve got here. one question about it though, how are you providing environment vars to your container when running it locally? the handling of env vars for locals is the one piece of the equation that i don’t quite understand yet with fly.io

cheers / thanks for any insights,
joel

I’m a little confused about how to implement the multiple environments. I have an app deployed called myapp-back-end and I want to have it deployed as two different apps, dev and production, so that I can deploy different branches on the dev app.

I tried running:
fly deploy -a myapp-back-end-dev

because I was hoping that would deploy the same branch onto a different app called myapp-back-end-dev running on another machine. But I got this error:

==> Verifying app config
Validating C:\Users\username\Documents\Node projects\myapp-back-end\fly.toml
Platform: machines
--> Verified app config
✓ Configuration is valid
Error: Could not find App "myapp-back-end-dev"

maybe try FlyCD (flycd.dev)

Hi… If you want to continue with flyctl itself, you can just register the new app name first:

fly app create myapp-back-end-dev
fly deploy  -a myapp-back-end-dev

(I use this all the time.)

The differences between fly app create, fly deploy, and fly launch do confuse a lot of people… Basically, the middle one is for apps that already exist—at least in a minimal, metadata form.

1 Like

For anyone that looking the answer in 2024, here is how I managed multiple environments:

Step 1: Create two deploy tokens:

(one for development workflow and one for production workflow)

flyctl tokens create deploy -a my-app-dev

and copy the token and go to github, settingssecrets and variables → create new secret named FLY_API_TOKEN_DEV and copy the token into the secret.

flyctl tokens create deploy -a my-app-prod

do the same this time create a variable called FLY_API_TOKEN_PROD

Step 2: Create two Github workflows one for each environment

.github/worflows/development.yaml:

name: Deploy to development
on:
  push:
    branches:
      - dev
env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
  deploy:
    name: Deploy Development App
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - run: flyctl deploy -a my-app-dev --remote-only

.github/worflows/production.yaml:

name: Fly Deploy
on:
  push:
    branches:
      - master
env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN_PROD }}
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - run: flyctl deploy -a hawalla-backend-prod --remote-only

Step 3: Create two .toml files

`fly.dev.toml:`


[build]
.
.

[env]
.
.


[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = false
  auto_start_machines = true
  min_machines_running = 0
  processes = ["app"]

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 1024

[deploy]
release_command = "php artisan migrate --force"

fly.prod.toml:

[build]
  [build.args]

[deploy]
  release_command = 'php artisan migrate --force'

[env]
.
.

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

[[vm]]
  size = 'performance-1x'
  memory = '4gb'
  cpu_kind = 'performance'
  cpus = 1
3 Likes