fly.ioを試してみる
公式ハンズオン
まずは公式ハンズオンに従ってやってみる
VS Codeでdevcontainerを立ち上げて試してみる。今回はMS公式のPython3のイメージを使う。
devcontainerが立ち上がったらターミナルからflyctlをインストール。
$ curl -L https://fly.io/install.sh | sh
set channel to shell
flyctl was installed successfully to /home/vscode/.fly/bin/flyctl
Manually add the directory to your $HOME/.bash_profile (or similar)
export FLYCTL_INSTALL="/home/vscode/.fly"
export PATH="$FLYCTL_INSTALL/bin:$PATH"
Run '/home/vscode/.fly/bin/flyctl --help' to get started
今回は適当なdevcontainerなので、環境変数は直接セットする。実際にレポジトリ等で管理する場合には別途設定が必要。
$ export FLYCTL_INSTALL="/home/vscode/.fly"
$ export PATH="$FLYCTL_INSTALL/bin:$PATH"
パスが通っている
$ which fly
/home/vscode/.fly/bin/fly
アカウントの作成。私の場合はfly.ioのウェブサイトで先にやってしまったのでスキップ。実行するとアカウント作成画面が表示されて支払い情報の登録が必要になるっぽい。支払い情報は無料プランであっても必要になる模様。
ということでウェブサイトでアカウント作成済みの場合も、事前に支払い情報を設定しておく必要があることを忘れずに(支払い情報がないとデプロイの最後で「We need your payment information to continue! Add a credit card or buy credit」となって失敗する)
$ fly auth signup
ログイン。多分ローカルだとブラウザが立ち上がって認証画面がでるっぽい。うちの環境はリモートサーバのdevcontainerからだったせいか、開かなかった。URLをクリックして直接開く。
$ fly auth login
failed opening browser. Copy the url (https://fly.io/app/auth/cli/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX) into a browser and continue
Opening https://fly.io/app/auth/cli/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ...
Waiting for session...⣷
"Continue as 自分のメアド" をクリックする。自分の場合はすでにログイン済みだったけど、ログインしてない場合は恐らくログイン画面が挟まれるのだと思う。
以下のように表示されればOK。ブラウザを閉じる。
VS Codeのターミナルのほうもログイン済となる。
Waiting for session... Done
successfully logged in as foo@example.com
ではサンプルのアプリを立ち上げる。
$ fly launch --image flyio/hellofly:latest
ここから対話形式でセットアップしていく。まずアプリ名。アプリ名はどうやら一意である必要がある様子(すでに使用されているアプリ名を指定した場合、セットアップの最後で「Error: Validation failed: Name has already been taken」で失敗となる)
? Choose an app name (leave blank to generate one): kun432-flyio-sample
リージョン。いくつかのリージョンは有償プランのみの様子。とりあえず今回は”Tokyo, Japan”で。
? Choose a region for deployment: [Use arrows to move, type to filter]
Hong Kong, Hong Kong (hkg)
Ashburn, Virginia (US) (iad)
Johannesburg, South Africa (jnb)
Los Angeles, California (US) (lax)
London, United Kingdom (lhr)
Madrid, Spain (mad)
Miami, Florida (US) (mia)
> Tokyo, Japan (nrt)
Chicago, Illinois (US) (ord)
Bucharest, Romania (otp)
Phoenix, Arizona (US) (phx)
問題なければ、ここでURLが決まる。
Hostname: kun432-flyio-sample.fly.dev
fly.ioではPostgreSQLやRedis等のデータベースも使用できる様子。今回は使わない。
? Would you like to set up a Postgresql database now? No
? Would you like to set up an Upstash Redis database now? No
設定はtomlで作成される。
Wrote config file fly.toml
デプロイする。
? Would you like to deploy now? (y/N)
こんな感じでデプロイされる。
Validating /workspaces/fly-io-handson/fly.toml
Platform: machines
✓ Configuration is valid
==> Building image
Searching for image 'flyio/hellofly:latest' remotely...
image found: img_z1nr0lpjz9v5q98w
Watch your app at https://fly.io/apps/kun432-flyio-sample/monitoring
This deployment will:
* create 2 "app" machines
No machines in group app, launching a new machine
Machine 148ed666a5e489 [app] update finished: success
Creating a second machine to increase service availability
Machine 6e82d337c43987 [app] update finished: success
Finished launching new machines
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling
Visit your newly deployed app at https://kun432-flyio-sample.fly.dev/
早速URLにアクセスしてみるとHello, World的な画面が表示されている。
URL末尾にパスを追加するとメッセージが変わるように作られているらしく、/hoge
を追加してみるとこうなる。
で、管理画面の方ではログなどが確認できる。なんか冗長性確保のためなのかな?もう1台用意されてるように見える。コールドスタンバイなのかな?
CLIでもアプリやVMのステータス確認ができる。
$ fly status
App
Name = kun432-flyio-sample
Owner = personal
Hostname = kun432-flyio-sample.fly.dev
Image = flyio/hellofly:latest
Platform = machines
Machines
PROCESS ID VERSION REGION STATE CHECKS LAST UPDATED
app 148ed666a5e489 1 nrt started 2023-07-05T09:46:03Z
app 6e82d337c43987 1 nrt stopped 2023-07-05T09:18:28Z
CLIのヘルプを見てみると、スケールさせたり、DB追加したり、ログの確認やssh/sftpなんかもできるっぽい。
$ fly help
Deploying apps and machines:
apps Manage apps
machine Commands that manage machines
launch Create and configure a new app from source code or a Docker image.
deploy Deploy Fly applications
destroy Permanently destroys an app
open Open browser to current deployed application
Scaling and configuring:
scale Scale app resources
regions V1 APPS ONLY: Manage regions
secrets Manage application secrets with the set and unset commands.
Provisioning storage:
volumes Volume management commands
mysql Provision and manage PlanetScale MySQL databases
postgres Manage Postgres clusters.
redis Launch and manage Redis databases managed by Upstash.com
consul Enable and manage Consul clusters
Networking configuration:
ips Manage IP addresses for apps
wireguard Commands that manage WireGuard peer connections
proxy Proxies connections to a fly VM
certs Manage certificates
Monitoring and managing things:
logs View app logs
status Show app status
dashboard Open web browser on Fly Web UI for this app
dig Make DNS requests against Fly.io's internal DNS server
ping Test connectivity with ICMP ping messages
ssh Use SSH to login to or run commands on VMs
sftp Get or put files from a remote VM.
Platform overview:
platform Fly platform information
Access control:
orgs Commands for managing Fly organizations
auth Manage authentication
move Move an app to another organization
More help:
docs View Fly documentation
doctor The DOCTOR command allows you to debug your Fly environment
help commands A complete list of commands (there are a bunch more)
では一旦削除する。destroyで削除。アプリ名が必要。
$ fly destroy kun432-flyio-sample
Destroying an app is not reversible.
? Destroy app kun432-flyio-sample? Yes
Destroyed app kun432-flyio-sample
Pythonアプリのデプロイ
Pythonアプリのデプロイの流れは以下に記載されている。
シンプルなFlaskを使ったウェブアプリの様子。サンプルコードのレポジトリは以下。
一応サラッとやってみる。まずレポジトリをclone。
$ git clone https://github.com/fly-apps/python-hellofly-flask
$ cd python-hellofly-flask
ファイル構成はこんな感じ。
$ tree .
.
├── Procfile
├── README.md
├── hellofly.py
├── requirements.txt
└── templates
└── hello.html
詳細はドキュメントやレポジトリ参照。
まずパッケージをインストール。
$ pip install -r requirements.txt
まずローカルでアプリを立ち上げてみる。
$ FLASK_APP=hellofly flask run
http://127.0.0.1:5000
で上がってくるのでブラウザでアクセスしてみる。
http://127.0.0.1:5000/hoge
でアクセスしてみると
ということでハンズオンで使ったアプリはこれだったのね。
ではデプロイしてみる。
$ flyctl launch
Creating app in /workspaces/fly-io-handson/python-hellofly-flask
Scanning source code
Detected a Python app
Using the following build configuration:
Builder: paketobuildpacks/builder:base
? Choose an app name (leave blank to generate one): kun432-flask-sample
automatically selected personal organization: XXXXXXXXX
Some regions require a paid plan (bom, fra, maa).
See https://fly.io/plans to set up a plan.
? Choose a region for deployment: Tokyo, Japan (nrt)
App will use 'nrt' region as primary
Created app 'kun432-flask-sample' in organization 'personal'
Admin URL: https://fly.io/apps/kun432-flask-sample
Hostname: kun432-flask-sample.fly.dev
? Overwrite "/workspaces/fly-io-handson/python-hellofly-flask/Procfile"? Yes
? 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
Validating /workspaces/fly-io-handson/python-hellofly-flask/fly.toml
Platform: machines
✓ Configuration is valid
We have generated a simple Procfile for you. Modify it to fit your needs and run "fly deploy" to deploy your application.
Pythonアプリをデプロイする場合のポイントは以下の模様
- ディレクトリの中身は全部デプロイされるイメージにコピーされる
- Heroku何かと同様に
Procfile
でアプリケーションの起動を制御する
Procfileはこんな感じ。
# Modify this Procfile to fit your needs
web: gunicorn server:app
ただこれ元々レポジトリに入っていたけど、fly launch
で上書きしてしまったみたい。正しくは以下のはず。なので修正しておく。
生成されたfly.tomlはこんな感じ
app = "kun432-flask-sample"
primary_region = "nrt"
[build]
builder = "paketobuildpacks/builder:base"
[env]
PORT = "8080"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
ではデプロイ。
$ fly deploy
dockerイメージが作成されているのがわかる。
==> Verifying app config
Validating /workspaces/fly-io-handson/python-hellofly-flask/fly.toml
Platform: machines
✓ Configuration is valid
--> Verified app config
==> Building image
Remote builder fly-builder-muddy-mountain-1469 ready
==> Building image with Buildpacks
--> docker host: 20.10.12 linux x86_64
base: Pulling from paketobuildpacks/builder
c6b348cd73bd: Pulling fs layer
04519a37e0a8: Pulling fs layer
dc5c5b9dba89: Pulling fs layer
ae5e916f75bf: Pulling fs layer
08e65dacaeac: Pulling fs layer
e085946a6c12: Pulling fs layer
1ffc8b380152: Pulling fs layer
(snip)
f92983442b23: Pushed
4d274d05ee12: Pushed
548a79621a42: Pushed
deployment-XXXXXXXXXXXXXXXXXXXXXXXXXX: digest: sha256:d69b44c82c9cb1074a6cab9dd83945dc4402bb297f46d7acd621ae07de79fc5b size: 3243
--> Pushing image done
image: registry.fly.io/kun432-flask-sample:deployment-XXXXXXXXXXXXXXXXXXXXXXXXXX
image size: 281 MB
Watch your app at https://fly.io/apps/kun432-flask-sample/monitoring
Provisioning ips for kun432-flask-sample
Dedicated ipv6: 2a09:8280:1::37:3983
Shared ipv4: 66.241.124.241
Add a dedicated ipv4 with: fly ips allocate-v4
This deployment will:
* create 2 "app" machines
No machines in group app, launching a new machine
Machine 4d891226a1dd87 [app] update finished: success
Creating a second machine to increase service availability
Machine e784e666f01683 [app] update finished: success
Finished launching new machines
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling
Visit your newly deployed app at https://kun432-flask-sample.fly.dev/
デプロイされた。
URLにアクセスしてみたら普通に同じものが見えると思う。
Dockerアプリのデプロイ
Dockerアプリのデプロイ
- Dockerfileがあれば自動で検知してくれる。
- .gitignoreから.dockerignoreを作成してくれる
適当なstreamlitアプリを作ってやってみたけどうまく行かなかったのでもう少し調べる。
Dockerアプリのデプロイ再び
前回は多分テストで使ったDockerfileの設定が良くなかったと思う。ということで1から作ってみた。事前にdocker単体でも動くことを確認しつつやる。
まずdevcontainer
{
"name": "Python 3",
"image": "mcr.microsoft.com/devcontainers/python:1-3.10-bookworm",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"version": "latest",
"dockerDashComposeVersion": "v2"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.black-formatter",
"ms-python.isort"
]
}
}
}
細かい設定は置いておいて、自分の環境では、LAN内のリモートサーバでdockerを動かす形。dockerコマンドをdevcontainer内から実行して、リモートサーバ上のdockerで作成したdockerアプリを動かすことになる。なのでDooDな環境になるので、ここでfeaturesとして追加しておく。
でDockerfile。ここはStreamlitのDockerチュートリアルを参考にした。
FROM python:3.9-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
curl \
software-properties-common \
git \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
EXPOSE 8080
HEALTHCHECK CMD curl --fail http://localhost:8080/_stcore/health
ENTRYPOINT ["streamlit", "run", "streamlit_app.py", "--server.port=8080", "--server.address=0.0.0.0"]
fly.ioはデフォルトだと内部ポートが8080になるようなので(多分変更もできるとは思うけど)、それに合わせて修正した(streamlitはデフォルトだと8501)
requirements.txtとサンプルアプリもstreamlitのサンプルをそのまま使った。
altair
pandas
streamlit
from collections import namedtuple
import altair as alt
import math
import pandas as pd
import streamlit as st
"""
# Welcome to Streamlit!
Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:
If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
forums](https://discuss.streamlit.io).
In the meantime, below is an example of what you can do with just a few lines of code:
"""
with st.echo(code_location='below'):
total_points = st.slider("Number of points in spiral", 1, 5000, 2000)
num_turns = st.slider("Number of turns in spiral", 1, 100, 9)
Point = namedtuple('Point', 'x y')
data = []
points_per_turn = total_points / num_turns
for curr_point_num in range(total_points):
curr_turn, i = divmod(curr_point_num, points_per_turn)
angle = (curr_turn + 1) * 2 * math.pi * i / points_per_turn
radius = curr_point_num / total_points
x = radius * math.cos(angle)
y = radius * math.sin(angle)
data.append(Point(x, y))
st.altair_chart(alt.Chart(pd.DataFrame(data), height=500, width=500)
.mark_circle(color='#0068c9', opacity=0.5)
.encode(x='x:Q', y='y:Q'))
ではまずローカルのdockerでテストしてみる。
$ docker build -t streamlit_sample:latest .
$ docker run -p 8080:8080 streamlit_sample:latest
ブラウザでアクセスしてみて以下のような感じで表示されればOK。
OK。これでdockerアプリとしては動くことが確認できたので、fly.ioでデプロイしてみる。
$ curl -L https://fly.io/install.sh | sh
$ export FLYCTL_INSTALL="/home/vscode/.fly"
$ export PATH="$FLYCTL_INSTALL/bin:$PATH"
$ fly auth login
$ fly launch
Creating app in /workspaces/streamlit-docker-sample
Scanning source code
Detected a Dockerfile app
? Choose an app name (leave blank to generate one): kun432-streamlit-docker-sample
automatically selected personal organization: XXXXXXXX
Some regions require a paid plan (bom, fra, maa).
See https://fly.io/plans to set up a plan.
? Choose a region for deployment: Tokyo, Japan (nrt)
App will use 'nrt' region as primary
Created app 'kun432-streamlit-docker-sample' in organization 'personal'
Admin URL: https://fly.io/apps/kun432-streamlit-docker-sample
Hostname: kun432-streamlit-docker-sample.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? Yes
(snip)
Watch your app at https://fly.io/apps/kun432-streamlit-docker-sample/monitoring
Provisioning ips for kun432-streamlit-docker-sample
Dedicated ipv6: 2a09:8280:1::69:3789
Shared ipv4: 66.241.124.90
Add a dedicated ipv4 with: fly ips allocate-v4
This deployment will:
* create 2 "app" machines
No machines in group app, launching a new machine
Machine 91857550a95383 [app] update finished: success
Creating a second machine to increase service availability
Machine 17811000f3d789 [app] update finished: success
Finished launching new machines
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling
Visit your newly deployed app at https://kun432-streamlit-docker-sample.fly.dev/
作成されたURLにアクセスして先ほどと同じ画面が表示されればOK。
まとめ
- とりあえずめっちゃ簡単にデプロイできて楽。
- render.comも使ってたけど、デプロイめちゃめちゃ遅い、コールドスタートから復帰しない場合がある、等いろいろあったんだけど、今触ってる感じではデプロイも普通だし、コールドスタートからの復帰もそんなに遅いとは感じない。
- ドキュメント見る限りはいろいろできることも多そう。
Herokuの代替としてはいろいろあったけど、fly.ioでもういい気がする。個人的には有料で使ってもいいかなーと思ってるぐらい気に入った。ドキュメント見ながらいろいろ試してみたい。
GitHub Actionsの自動デプロイもできる様子。後で試す。