惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
人人都是产品经理
人人都是产品经理
G
GRAHAM CLULEY
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LangChain Blog
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
博客园 - 司徒正美
Last Week in AI
Last Week in AI
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
Simon Willison's Weblog
Simon Willison's Weblog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Schneier on Security
Y
Y Combinator Blog
月光博客
月光博客
博客园 - Franky
T
Threatpost
Security Latest
Security Latest
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
T
The Exploit Database - CXSecurity.com
A
About on SuperTechFans
I
Intezer
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cisco Blogs
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
美团技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
Know Your Adversary
Know Your Adversary
IT之家
IT之家
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
NISL@THU
NISL@THU
博客园 - 三生石上(FineUI控件)
L
Lohrmann on Cybersecurity
小众软件
小众软件
PCI Perspectives
PCI Perspectives
N
News and Events Feed by Topic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Engineering at Meta
Engineering at Meta

Learn Cloud Native

Agentgateway rate limiting for agents | Learn Cloud Native Local development with coding agents on Kubernetes using Signadot | Learn Cloud Native cuenv: one typed file for your whole project | Learn Cloud Native Preflight: AI Code Review Before You Push Anatomy of AI Agents Accessing Google Drive from Next.js Top Cloud-Native & Kubernetes Certifications [2026 Guide] Rapid microservices development with Signadot How to prepare for Istio certified associate exam (ICA) Global Rate Limiting in Istio with Envoy Rate Limit Service My Journey with Istio: From Incubation to Graduation Cilium Network Policy Tutorial: Secure Kubernetes Step by Step Kubernetes Networking: How kube-proxy and iptables Work Istio ServiceEntry: DNS vs. STATIC Resolution & Endpoints Explained Apply an Istio DestinationRule Globally (Mesh-Wide) Istio Rate Limiting: Configure a Local Rate Limiter in Envoy How to expose custom ports on Istio ingress gateway Portainer Tutorial: A Web UI for Kubernetes & Containers Traefik Proxy 2.x and TLS 101 Kubernetes CLI (kubectl) tips you didn't know about Setting up SSL certificates with Istio Gateway ArgoCD Best Practices You Should Know 在 OCI Ampere A1 计算实例上运行 AI Running AI On OCI Ampere A1 Instance How to Deploy Traefik Proxy Using Flux and GitOps Principles Firebase Emulators with Next.js: Local Setup Guide Running Hugo on free Ampere VM (Oracle Cloud Infrastructure) How to use kwatch to detect crashes in Kubernetes clusters Continuous profiling in Kubernetes using Pyroscope Monitoring containers with cAdvisor Creating a Kubernetes cluster in Google Cloud (LAB) Your first Kubernetes Pod and ReplicaSet (LABS) Container Lifecycle Hooks Maybe Convert Wasm Extension Config? GetIstio - CLI, training, and community Attach multiple VirtualServices to Istio Gateway Kubernetes Volumes Explained: Keep Data Beyond the Pod Send a Slack message when Docker images are updated Kubernetes Network Policy Ambassador Container Pattern Start Kubernetes Release Sidecar Container Pattern Kubernetes Init Containers Deploying multiple Istio Ingress Gateways Branch by Abstraction Pattern The Strangler Pattern Kubernetes Development Environment with Skaffold Securing Kubernetes Ingress with Ambassador and Let's Encrypt All About the Ingress Resource How to quarantine Kubernetes pods? Getting started with Kubernetes Horizontal partitioning in MongoDB Docker image tagging scheme Six things to keep in mind when working with Dockerfiles Beginners guide to Docker Beginners guide to gateways and proxies Deploy and Operate Multiple Istio Meshes in one Kubernetes Cluster Managing service meshes with Meshery Circuit Breaking in Istio Explained Build and push your Docker images using Github Actions Kubernetes and Istio service mesh workshop materials Build Netlify-like deployment for React app using Kubernetes pods Six exciting enhancements in Istio 1.4.0 Fallacies of Distributed Systems CAP Theorem Explained Master the Kubernetes CLI (kubectl) - Cheatsheet Minikube Basics and How to Get Started with Kubernetes 5 Tips to Be More Productive with Kubernetes What are sticky sessions and how to configure them with Istio? Debugging Kubernetes applications using Istio Kubernetes Ingress and Istio Gateway Resource Zero Downtime Releases using Kubernetes and Istio Traffic Mirroring with Istio Service Mesh Expose a Kubernetes service on your own custom domain
Deploying to Fly.io using Dagger and Github
Peter Jausovec · 2024-07-20 · via Learn Cloud Native

I was looking for a simple service where I could, ideally, run a single CLI command and deploy a simple Javascript or Typescript server. One of the suggestions was Fly.io. I've later also tried Render, which works similarly.

Starting with Fly.io

The deployment to Fly.io is fairly straightforward. Once you install the CLI and configure your app (most of it is automatic, i.e. just confirm the defaults), you can deploy your app with a single command -- fly deploy. However, we could do better than that and do automatic deployments on every push to the main branch.

I was hoping Fly.io would integrate with GitHub automatically where I could select my repo and it would automatically do deploys. However, at the time of writing this, Fly.io didn't support that. Which means, you have to configure the GitHub action on your own. Let's see how we can do that!

Setup Github action for Fly.io

I am going to assume you have the CLI and app set up already. If not, you can fork my todo app as an example. Alternatively, create a simple server yourself with bun create elysia app. You can follow the instructions here.

Back to Github actions.

To deploy to Fly.io from a Github action you'll need a token to authenticate with Fly.io. You can do that by running the fly CLI inside your app folder:

fly tokens create deploy -x 999999h

Take the output of the command and go to your Github repo to store it as a repository secret. This will make the token available for use in the Github action.

Open your Github repository and:

  1. Click Settings.
  2. From the Secrets and variables dropdown click Actions.
  3. Click New repository secret.
  4. Paste the output of the command above in the Secret field.
  5. Name the secret FLY_API_TOKEN.
  6. Click Add secret.

Let's create the Github action! In your repository, create a new file in the .github/workflows folder and name it deploy.yaml:

name: Fly Deploy
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    concurrency: deploy-group
    steps:
      - uses: actions/checkout@v4
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - run: flyctl deploy --remote-only
        working-directory: ./app
        env:
          FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

The action is fairly straightforward. It runs on every push to the main branch, and it checks out the code from the repository using the checkout action. Once the code is checked out, it runs the flyctl deploy command using the superfly/flyctl-actions/setup-flyctl action.

Note

Note that if you're app is in a subfolder, don't forget to set the working-directory to the correct path. In my case, I created the app in the ./app folder so I set the working-directory field to that value.

That's it! Now every push to the main branch triggers a deployment to Fly.io. If you had any database migrations or other setup steps, perhaps running unit tests you could see how the Github action could become a bit more complex. So before we get to that spot, I'll show you another tool that I looked at recently - Dagger.

Daggerize your scripts

Dagger is a tool that allows you to replace your scripts used for setup, building, testing, deploying and bunch of other things, with functions written in a programming language. In this article I'll use Go, but you can also write Dagger functions in Python and TypeScript.

One of the reasons why I typically reach for a shell script is that it's easy to write and I can run it right away. You can say writing simple script with Go/Python/TypeScript isn't that hard either, but I'd disagree. It's not the "writing the code" that makes it hard and tedious for me, it's more of the "setting up the environment" part and "download the tooling and dependencies" (make sure you get the right version!), packaging the "script" etc.

This is what Dagger made easy for me. I can bootstrap the Dagger function with a single command (dagger init), write the function and run it without ever downloading any dependencies or setting up the environment!

To run a Dagger function you can use call command in the Dager CLI (e.g. dagger call [function_name]). I am not going to write a walkthrough, because the quickstart in Dagger's docs is great, so check that out if you're interested.

Writing a Dagger function for Fly.io

Back to the Github action and the Fly.io stuff. Here's what I did in terms of writing a Dagger function to replace or rather abstract the flyctl CLI. The full source is here, but sinces there's not much to it, I'll paste the functions here as well:

// Deploy deploys an app from the src folder to Fly.io
func (m *Flyio) Deploy(ctx context.Context,
	// +required
	src *Directory,
	// +required
	token *Secret) (string, error) {
	return m.FlyContainer(ctx, token).
		WithMountedDirectory("/src", src).
		WithWorkdir("/src").
		WithExec([]string{"/root/.fly/bin/flyctl", "deploy"}).
		Stdout(ctx)
}

// FlyContainer creates a container with the flyctl CLI installed
func (m *Flyio) FlyContainer(ctx context.Context, token *Secret) *Container {
	return dag.Container().
		From("alpine:3.20.0").
		WithExec([]string{"apk", "add", "curl"}).
		WithExec([]string{"curl", "-LO", "https://fly.io/install.sh"}).
		WithExec([]string{"sh", "install.sh"}).
		WithSecretVariable("FLY_API_TOKEN", token)
}

The FlyContainer function creates (and returns) a new Docker container based on alpine:3.20.0, installs curl, downlads the script and installs the Fly.io CLI and then mounts an environment variable FLY_API_TOKEN from the secret passed to the function (Secret is a concept in Dagger that allows you to input things like API keys, passwords, into Dagger functions without exposing them in the logs, for example).

The Deploy function uses the FlyContainer function to create a container, mounts the source directory that was pass-in by the user, and then runs the flyctl deploy command in that mounted folder and pipes the output to standard out (stdout).

When I said you don't need to download any dependencies or set up the environment, I meant it. You can run the Dagger function right away, without any setup. The Dagger CLI acts as a CLI for these functions - for example, here's what happens if you list the functions in this module I created:

Name            Description
deploy          Deploy deploys an app from the src folder to Fly.io
fly-container   FlyContainer creates a container with the flyctl CLI installed

Then, to run the deploy function, you can do something like this:

dagger call deploy --src ./projects/htmx-todo/app --token=env:FLYIO_TOKEN

Note the --src flag is the path to the source code of the app you want to deploy, and the --token flag is the deployment token. It's prefixed with env which is telling Dagger to read the value from the environment variable. Other options here are file, to read the secret value from a file, or cmd to run a command and use the output as the value.

You might wonder -- well, this is all great, but how can I run this same Dagger function from my environment? Do I need to clone the repo, or what do I do? This is the REALLY COOL part - when calling dagger call or dagger functions you can point to the location of the Dagger module (e.g. the Github repo for example where I published the module) and it will work the same way as if you had the module locally:

$ dagger functions  -m github.com/peterj/dagger-modules/flyio@46138d1028f721d7a0cdc03794c64aa063584f46

```console
Name            Description
deploy          Deploy deploys an app from the src folder to Fly.io
fly-container   FlyContainer creates a container with the flyctl CLI installed

Putting it all together

The last step is to run the Dagger function in the Github action. There's a published Github Action for running Dagger and to use it you can modify your workflow, something like this:

name: Fly Deploy with Dagger
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    concurrency: deploy-group
    steps:
      - uses: actions/checkout@v4
      - uses: dagger/dagger-for-github@v5
        with:
          verb: call
          module: github.com/peterj/dagger-modules/flyio@46138d1028f721d7a0cdc03794c64aa063584f46
          args: deploy --src $PWD --token=env:${{ secrets.FLY_API_TOKEN }}

The Github action looks more or less the same, but now if your deployment "script" changes, you can update the Dagger function(s), easily test them locally (without setting up anything) and you can be confident that if it works locally, it will work in the CI as well.