+++ 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] # WEB_DOMAIN="mstdn.syui.ai" # LOCAL_DOMAIN="syui.ai" 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より安く運用できるという点で評価できます。