RvR

Primary Navigation

Hello internet, the past few days I've been playing with fly.io. I must admit I'm not entirely sure why, but it seemed like a fun project. They even have a getting started project for deno. Sadly it uses something called dinatra which hasn't received a commit in 16 months. So that project seems just about dead.

Therefore I decided to take their starter project and make it my own. One of the other things I found frustrating is that flyctl (their command line utility) will automatically scan the project and create a dockerfile. This is cool, but their template is coded to use deno 1.14, which is about 17 months old. That's essentially an eternity in the open source world.

So what should we do to get started? Well, we'll need a server. Obviously I'm not going to use dinatra, since the project seems dead; more importantly, the standard library provides a perfectly good server out of the box.

Fly recommends:

import {
  app,
  get,
  post,
  redirect,
  contentType,
} from "https://denopkg.com/syumai/dinatra/mod.ts";

const greeting = "<h1>Hello From Deno on Fly!</h1>";

app(
  get("/", () => greeting),
  get("/:id", ({ params }) => greeting + `</br>and hello to ${params.id}`),
);

Let's do our own version like:

server.sh

import { serve } from "https://deno.land/std@0.173.0/http/server.ts";

serve(() => {
  return new Response(
    `Hello from deno.`,
  );
}, { port: 8080 });

My version is a bit shorter, but also includes slightly less functionality. Whatever.

We can test this by running:

deno run --allow-net server.ts

Great, we get a boring response when we do:

curl localhost:8080
Hello from deno.%

Now we have our (slightly, and in my opinion) improved version of the server implemented. But remember the issue about fly's template for deno projects? Let's avoid that and create our own dockerfile:

Dockerfile

FROM denoland/deno:1.30.3 as base

USER deno

WORKDIR /app

COPY . ./

RUN deno cache server.ts

CMD ["run", "--allow-net", "--allow-env", "--allow-read", "server.ts"]

At this point we should have a project looking like this:

.
├── Dockerfile
└── server.ts

Not terribly exciting. It's about to get... not so exciting. Let's try building our simple image:

docker build . -t deno_hello_fly

We can find our image by running

docker image ls

You should get something like:

REPOSITORY           TAG            IMAGE ID       CREATED         SIZE
deno_hello_fly       latest         00270a10eba1   3 minutes ago   186MB

We have our new image. Let's start it:

docker run -p 8080:8080 deno_hello_fly

Well that's too hard for me to remember. Binding ports manually and specifying the name? Nothx. Let's wrap this all in a compose file, so that we can just use the same standard command to start things up.

docker-compose.yaml

version: "3.9"

services:
  deno:
    container_name: deno_hello_fly
    image: deno_hello_fly
    build:
      context: .
      dockerfile: Dockerfile
      target: base
    ports:
      - 8080:8080

Now we don't have to think because we can just rely on docker-compose to do the heavy lifting:

docker-compose up

If we need to rebuild something, then that's easy:

docker-compose up --build

Lovely. We can now test everything locally. (Ok there's not so much to test right now, but maybe something will come later.)

Our project should look like this:

.
├── Dockerfile
├── docker-compose.yaml
└── server.ts

Let's get back to fly. They suggest the following:

fly launch

It will ask you a bunch of stuff and you should answer accordingly:

reed@reed test % fly launch
Creating app in /path/to/your/source
Scanning source code
Detected a Dockerfile app
? Choose an app name (leave blank to generate one): my-app-name
automatically selected personal organization: youremail@domain.com
? Choose a region for deployment: Stockholm, Sweden (arn)
Created app my-app-name in organization personal
Admin URL: https://fly.io/apps/my-app-name
Hostname: my-app-name.fly.dev
? Would you like to set up a Postgresql database now? No
? Would you like to set up an Upstash Redis database now? No
Wrote config file fly.toml
? Would you like to deploy now? No
Your app is ready! Deploy with `flyctl deploy`

This is great. This has created a .toml file that looks like:

fly.toml

# fly.toml file generated for my-app-name on 2023-02-19T18:20:27+01:00

app = "my-app-name"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[experimental]
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

I must admit I haven't played around with these settings at all. Maybe we can try that later; instead I've raced on to the next step:

flyctl deploy

This command will build the container and send the image up to the interwebs. It then suggests to run fly info. Sadly we immediately receive:

Command "info" is deprecated, Replaced by 'status', 'ips list', and 'services list'
App
  Name     = my-app-name
  Owner    = personal
  Status   = running
  Version  = 0
  Platform = nomad
  Hostname = my-app-name.fly.dev

Services
PROTOCOL	PORTS
TCP     	80 => 8080 [HTTP]
            443 => 8080 [TLS, HTTP]

IP Addresses
TYPE	ADDRESS            	REGION	CREATED AT
v6  	some:ip:address  	global	1m29s ago

It seems like they need to update their documentation to no longer suggest the deprecated command.

Instead fly status gives:

App
  Name     = my-app-name
  Owner    = personal
  Version  = 0
  Status   = running
  Hostname = my-app-name.fly.dev
  Platform = nomad

Deployment Status
  ID          = big-long-id-here
  Version     = v0
  Status      = successful
  Description = Deployment completed successfully
  Instances   = 1 desired, 1 placed, 1 healthy, 0 unhealthy

Instances
ID      	PROCESS	VERSION	REGION	DESIRED	STATUS 	HEALTH CHECKS     	RESTARTS	CREATED
1234asdf	app    	0      	arn   	run    	running	1 total, 1 passing	0       	1m27s ago

Great. We're almost there. Just one last command for now:

fly open

This should launch your app in a new browser window. Hopefully you see:

Hello from deno.

The end state of our project here is:

.
├── Dockerfile
├── docker-compose.yaml
├── fly.toml
└── server.ts

This seems like a long enough post for now. Tomorrow we'll get some more features. Look for thoughts about adding a custom domain name to our app, along with deploying it automatically every time we push to github.

Next Post Previous Post Navigation