2024-04-23 13:21:26 +00:00
+++
date = "2022-08-27"
tags = ["heroku","fly"]
title = "herokuからfly.ioへの移行"
slug = "fly-heroku"
+++
herokuのplan:free(hobby)が廃止され、`mo/$31`になるので、[heroku](https://heroku.com/)から[fly.io](https://fly.io/)へ移行を考えています。
> Heroku Dynos starts at $7/month, Heroku Data for Redis® starts at $15/month, Heroku Postgres starts at $9/month.
https://blog.heroku.com/next-chapter
herokuのこれまでの評価は、素晴らしかったです。感謝しかありません。ありがとう!
### fly.io plan:free(hobby)
クレジットカードを登録するとplan:hobbyが使えるようになります。クレジットカードはできればVプリカ(visaプリペイドカード)などを使用するようにしてください。登録できない場合に通常のクレジットカードで登録するしかありません。このへんは未検証です。
> Add a payment method to get even more free allowances.
>
> VM: shared-cpu 2,340 hours per month Run 3 shared-cpu-1x VMs with 256MB RAM full time.
> Volumes 3GB Provision 3GB of persistent volumes for permanent storage
> Bandwidth 160GB per month See outbound data transfer for regional breakdown
> Anycast IPs Unlimited IPv6, 1 IPv4 per active app Additional IPv4 addresses are $2 per month
> Certificates 10 active certificates Add 10 certificates to your apps
- dyno : 2,340
- ram : 256M
- strage(volume) : 3G
https://fly.io/docs/about/pricing/
fly.ioはかなりherokuを意識しているようで、cliもありますので、herokuと同じように使いやすいと思いました。
herokuからの移行は[こちら](https://fly.io/launch/heroku)から自動で移行するツールがあります。が、これでうまくいくとは思っていません。
注意点としては以下になります。
- herokuとfly.ioで使うメールアドレスを同一のものにすること
これを行わないとfly.ioでherokuのメールアドレスからアカウントが作成された上で、appをdeployします。この際、アカウントにはクレジットカードの登録も必要です。あらかじめfly.ioで作成している場合、そのアカウントは使われません。
fly.ioの`launch/heroku`を使う際はherokuとfly.ioで使うメールアドレスを同一のものにしておきましょう。
さて、ではherokuからの移行ツールが動作するかというと、当然ですが移行ツールでは正常にdeployが完了しませんでした。
したがって、docsを読んで最初からfly.io用にdeployできる構成を作らなければなりません。
### mastodon
> ここではfly.ioでmastodonを正常に動作させるまでをやります
fly.ioでmastodonを動かす場合、(1)memory:512Mにすること、(2)redis-serverを独自に立ち上げることが重要になります。
公式のdockerfileでもdeployは成功しますが、logsを見てみると、redisの処理がうまく行かず、webにアクセスできませんでした。
さらに、独自のアドレスを使う場合は、fly.ioの`apps/xxx/certificates`で証明書を発行した上でCNAMEを追加します。ここまでやって初めて正常に動作しました。
ref : https://github.com/tmm1/flyapp-mastodon
```sh
$ fly apps create xxx
$ fly scale memory 512
```
```toml:fly.toml
app = "xxx"
kill_signal = "SIGINT"
kill_timeout = 5
[env]
2024-12-21 06:52:52 +00:00
# WEB_DOMAIN="mstdn.syui.ai"
# LOCAL_DOMAIN="syui.ai"
2024-04-23 13:21:26 +00:00
LOCAL_DOMAIN="xxx.fly.dev"
LANG="en_US.UTF-8"
RAILS_ENV = "production"
RAILS_LOG_TO_STDOUT = "enabled"
WEB_CONCURRENCY = "1"
REDIS_HOST = "xxx-redis.internal"
REDIS_PORT = "6379"
S3_ENABLED=false
SINGLE_USER_MODE=true
OTP_SECRET=""
SECRET_KEY_BASE=""
# LOCAL_HTTPS=false
[deploy]
release_command = "bundle exec rails db:migrate"
[mounts]
processes = ["rails"]
source = "mastodon_uploads"
destination = "/opt/mastodon/public/system"
[processes]
rails = "bundle exec rails s -p 8080"
sidekiq = "bundle exec sidekiq"
[[statics]]
guest_path = "/opt/mastodon/public"
url_prefix = "/"
[[services]]
internal_port = 8080
processes = ["rails"]
protocol = "tcp"
[[services.ports]]
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
[[services.http_checks]]
path = "/health"
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
```
`OTP_SECRET` , `SECRET_KEY_BASE` は`fly secrets set`したほうがいいです。ですが、secretsは不安定なので、envに書いたほうがいいです。理由は後述します。
私の場合、下記のようにDBを引き継いだのですが、反映されませんでした。
```sh
$ heroku config
$ fly pg create xxx
$ fly proxy 5432 -a xxx
---
# host=localhost
$ export DATABASE_URL=postgres://xxx:xxx@localhost:5432
$ pg_dump --no-owner -C -d $HEROKU_DATABASE_URL | psql -d $DATABASE_URL
---
$ fly pg attach -a $app $app_db
# DATABASE_URLにsecrets setしている場合はattachは動きません。unsetしてください
$ fly secrets unset DATABASE_URL
```
以前のsecret-keyなどもenvに入れて、`rails db:setup`を実行していません。引き継ぎなのでmigrateの処理を入れています。
しかし、新しくアカウントを作り直すことになったので、最初から初期化してdeployするのがおすすめかもしれません。
```sh
$ fly pg create --name xxx-pg
$ fly pg attach -a xxx xxx-pg
# fly deploy -c fly.setup.toml
```
次は、redis-serverを作ります。
```toml:fly.redis.toml
app = "xxx-redis"
[[mounts]]
source = "xxx_redis"
destination = "/data"
```
volume sizeが3G以上になる場合、課金が発生します。
```sh
$ fly apps create xxx-redis
$ fly vol create -c fly.redis.toml xxx_redis --size 1
$ fly deploy --config fly.redis.toml --build-target redis-server
```
dockerからなのか、ちょっとしたことですぐに動かなくなります。例えば、mediaのurlがうまく取得できない場合でもそういった事が起こるので、注意が必要です。問題が発生した場合、pgをresetしたほうが早いです。
```sh
$ fly vol create mastodon_uploads --size 1
```
```sh
# こういったやり方で画像をuploadしている場合は動かなくなる
PAPERCLIP_SECRET="xxx"
PAPERCLIP_ROOT_URL="https://github.com/syui/xxx/raw"
```
最終的には、appを`deploy`します。
```sh
$ fly deploy
$ fly open
```
```sh
$ fly ssh console
# https://zenn.dev/kumasun/articles/12dcc7b3e91722945228
# 新しくアカウントを作る
$ cd mastodon
$ RAILS_ENV=production bundle exec bin/tootctl accounts create $USER --email=$EMAIL --confirmed --role admin
# 既存のアカウントを上書き
$ RAILS_ENV=production bundle exec bin/tootctl accounts modify $USER --email=$EMAIL --confirm --role admin
```
sidekiqが遅い場合があり、redisが原因だと思われます。しかし、これ以上の方法があるとは思えません。
あと、fly.io(cli)は、バグっているので、まあまあの割合で有効に動作しないことがあります。なにかおかしいと思ったときは、そういうこともあるということで。私の場合、secretsに入れたはずのやつが消えたり、消したはずのやつが残ってたり、DATABASE_URLを消したあとにもattachで追加できなくなったりといったことが頻発しました。
#### mastodon/dockerfile
> 下記からは主にうまく動作しない手順となります。
通常は`fly launch`にてy/NでNにします。こうすることでdockerfileが上書きされず、mastodonのdockerfileを使用します。
```toml:fly.toml
[processes]
web = "bundle exec puma -C config/puma.rb"
worker = "bundle exec sidekiq"
[build]
[build.args]
BUNDLER_VERSION = "2.3.9"
NODE_VERSION = "14"
RUBY_VERSION = "3.0.4"
[deploy]
release_command = "bundle exec rails db:migrate"
[env]
PORT = "8080"
[[services]]
processes = ["web"] # this service only applies to the web process
http_checks = []
internal_port = 8080
protocol = "tcp"
script_checks = []
```
多少、dockerfileを手直ししてdeployすればいいです。postgres, redisのurlをenvに入れておきましょう。これはdockerfileに入れてもfly.ioに入れてもいいです。herokuからの移行は[こちら](https://fly.io/docs/rails/getting-started/migrate-from-heroku/)を参考にしてください。
```sh
$ ruby -v
$ rbenv install 3.0.4
$ bunlde
$ fly secrets set DATABASE_URL=xxx
$ fly secrets set REDIS_URL=xxx
$ fly deploy
$ fly open
```
#### fly.io/dockerfile
> 下記からは主にうまく動作しない手順となります。
fly.ioが生成するdockerfileを使ってdeployする大まかなヒントです。
> ruby '~> 3.1.0'
```sh
$ rbenv install 3.1.0
$ ruby -v
$ bundle
$ fly auth login
$ fly launch
$ fly deploy
> An error occurred while installing idn-ruby (0.1.4), and Bundler cannot
> An error occurred while installing charlock_holmes (0.7.7), and Bundler cannot
...
```
> Dockerfile
```
ARG DEV_PACKAGES="git build-essential libpq-dev wget vim curl gzip xz-utils libsqlite3-dev ffmpeg libicu[0-9][0-9] libicu-dev libidn11 libidn11-dev libpq-dev libxdamage1 libxfixes3 zlib1g-dev libcairo2 libdatrie1 libgdk-pixbuf2.0-0 libgraphite2-3 libharfbuzz0b libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpixman-1-0 librsvg2-2 libthai-data libthai0 libvpx[5-9] libxcb-render0 libxcb-shm0 libxrender1 libglib2.0-0"
```
これでやっと通りました。
しかし、`bundle exec rails assets:precompile`で`libicudata.so.67: cannot open shared object file: No such file or directory - /app/vendor/bundle/ruby/3.1.0/gems/charlock_holmes`が出ます。
> Dockerfile
```sh
ENV OTP_SECRET=xxx
RUN gem pristine --all
ARG PROD_PACKAGES=xxx libglib2.0-0
```
#### postgres
fly-postgres(pg)はpublicではなくprivateです。container内からしかアクセスできません。ただし、localからアクセスする手段があります。それを使いheroku-pgのdumpをfly-pgに追加します。
```sh
$ heroku config
$ fly pg create
$ fly proxy 5432 -a xxx
---
# host=localhost
$ export DATABASE_URL=postgres://xxx:xxx@localhost:5432
$ pg_dump --no-owner -C -d $HEROKU_DATABASE_URL | psql -d $DATABASE_URL
---
$ fly pg attach --app $app $app_db
# DATABASE_URLにsecrets setしている場合はattachは動きません。unsetしてください
$ fly secrets unset DATABASE_URL
```
#### redis
fly.ioはredisがつらい。もしかしたらherokuのrediscloud使えばいいかも。でも`REDIS_URL`に入れてもうまく動作しなかった。
```sh
$ heroku addons:create rediscloud
```
総評として、herokuがよすぎた。
追記 : 調整することで、fly.ioでもかなり快適に動作するようになりました。ただし、総合的に見てherokuのほうが便利です。fly.ioはherokuより安く運用できるという点で評価できます。