Herokuの無料終了に伴って話題になったPaaSの一つがRailway.app。
最初は期待して触ったんだがNixpacksというビルダーが分かりづらいことと、webアプリだけではなくデータベースやRedisすらも制限時間を食う扱いとなる500時間制限がキツすぎることなどを理由に一旦中止。
しかしクレカを登録したら500時間制限は外れて、一般有料プランと同等のサービスを扱えることから「あれ、意外といいじゃん」となって今に至る。クレカ登録は他のPaaSと同じであくまで人質で、5ドル分を超えなければ請求は発生しないということになっている。ちょっと怖いちゃ怖いけど、一応「今のペースでの見立て」での月の合計額は出るので、身内向けの小さいサービスならわりといいかもしれない。
ただ上に書いてる通り、Railway.appの採用している「Nixpacks」なるビルダーが本当にわかりづらい上に、なにより公式ドキュメントが酷い(renderやfly.ioとは比較にならない酷さ)ので、一応自分が苦労したRailsアプリを上げるまでのことや、他のいくつかの点でのチャート的な説明しておきます。
railway cliのインストール
まず何はともあれ、公式でアカウントを作ることと、railway cliのインストールが必要。ただ結構前のこととはいえ、自分はrailway cliのインストールすら確かむちゃくちゃに苦労した覚えがある。Homebrew(mac)かnpmかshellかscoopでインストールできるので、自分のようにwindowsなら基本的にscoopでいいはずなんだけど、なぜかscoopでは全くインストールできなかった。shellでも何かのエラーにひっかかってあれこれしてインストールしたと思うけど、どうやったか正直覚えてない。
自分のときだけたまたまかもしれないが、ここでひっかかっても「みんなそうなんだ…」という強い気持ちが必要なので頑張って。
プロジェクトを作成
railwayの罠の一つ、「プロジェクト」と「アプリ」が別扱いというのがある。アカウントを作ってダッシュボードに入ると、何もない壁紙に「+New Project」というボタンとアカウントが多分表示されると思うんだけど、ここで作る「プロジェクト」はwebアプリのことではなく、データベースやwebサービスなどのアプリ全体を一つのプロジェクトとして管理する、その「プロジェクト」だ。
この画面でNew Projectを押すと「Githubからデプロイする」か、「テンプレートからデプロイする」か、「空のプロジェクトつくる」か、「データベースたてる」か…などがでてくるが、あくまでそれは「プロジェクト内部に最初に作るサービスを何にするか」という意味になる。もうこの説明の時点でわかりづらい気がする。
自分はこの画面を見たとき、このプロジェクトという言葉にあんまり真剣にとらえず、とりあえずこの画面からwebアプリとPostgresデータベースを立てたもんだから、なぜかwebアプリがデータベースと全く繋がらなくて大変苦労した。環境変数を共有してのデータベースを繋げる際は、「同じプロジェクト内」でデータベースを立てないといけない。わかるか…!そんなんもん…っ!!
わかりづらいんで、自分は「Empty project」を選んで、一旦プロジェクトに名前つけるところから始めるほうがわかりやすい気がする。
webアプリ作成
とりあえずRailsのデプロイの方法は二つある。Githubと紐付けて、Githubにデプロイしたら自動でデプロイが始まる方式と、Githubは使わず直接Railwayにデプロイする方法。どっちでもいいと思う。
railway link
コマンドで紐付けるプロジェクトを選択できる(プロジェクトIDで直接紐付けるのも可能)。あとはrailway up
でデプロイできる。
Githubとの紐付けは特に問題はないので割愛。
Railsの準備
ここから、Railsアプリがエラー起こさずとりあえずデプロイできるまでを説明。rails new
で生成した素のrailsプロジェクトをデプロイする前提。
ビルドパックが基本的に三つあり、標準で推奨されているのがNixpacksで、Herokuと同じようにデプロイできるのがHeroku buildpack、最後がDockerfileに準拠するもの。Heroku buildpackはそれこそHerokuに上げるのと変わらず展開するので何もしないでもデプロイできると思うが、Nixpacksはちょっと手をいれなきゃいけない。(ちなみにHeroku buildpackは非推奨で、じきに廃止するとのこと)
database.yml
ここは簡単で、url: <%= ENV["DATABASE_URL"] %>
をproduction部分に書けばいいだけ。ここにユーザー名やらパスワードやらホストやら全部書かれてるので、同じプロジェクト内にpostgresqlが立ってれば勝手に繋がる。
production:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
もし外部DB繋ぎたいなら、ダッシュボードのwebアプリのVariableに環境変数を足して、DATABASE_URL
としてpostgres://{username}:{password}@{hostname}:{port}/{database}
の形式でアドレスを作って入れればそれだけで繋がるはず。
Procfile
ルートにProcfileというファイルを作成し、以下のようなコマンドを書く
web: rails db:migrate && /bin/bash -l -c "bundle exec puma -C config/puma.rb"
公式ドキュメントだとあたかもworker:も併記できるように書いている。でも自分が試した限り動かないし、公式も別のところでは1サービスしか動かないと書いてある。じゃあなんでworker動くみたいな例書いてるんだと思う。というか、Procfileに書いたらweb: 消してもworker動かないので、worker動かしたいならダッシュボードの設定から、Start Command設定するしかない気がする(もしくはDockerfile)。その場合はwebは動かない。
このあたり厳密に試してないからわからないけど、わざわざ制限かけてるくらいだから別にアプリを立てないとwebとworkerを動かすのはできないかもしれない。HerokuはDynosという割り振りで、webと別に1サービス動かせたけどそれはできないっぽい。
自分は以上の手続きでとりあえず素のRailsはデプロイできた。本当は他にやるべきことあるかもしれないけど。
Selenium(chrome driver)を動かす
自分はwebとDBはfly.ioでいいと思ってたので、fly.ioより豊富なVMのrailwayはseleniumを使ったworker目的に使うことにした。その場合はDockerfileでのchromedriverなどのインストールが必要なので、以下のように指定した(ほぼ先駆者のコピペ)。
FROM ruby:3.0.4
ARG EnvironmentVariable
RUN apt-get update -qq \
&& apt-get install -y nodejs postgresql-client npm \
&& rm -rf /var/lib/apt/lists/* \
&& npm install --global yarn
# Chrome のインストール
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add \
&& echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update -qq \
&& apt-get install -y google-chrome-stable libnss3 libgconf-2-4
# ChromeDriver のインストール。
RUN CHROMEDRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` \
&& curl -sS -o /tmp/chromedriver_linux64.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip \
&& unzip /tmp/chromedriver_linux64.zip \
&& mv chromedriver /usr/local/bin/
WORKDIR /app
COPY Gemfile /app
COPY Gemfile.lock /app
RUN bundle install
COPY . /app
CMD ["bundle", "exec", "sidekiq"]
以上はsidekiq/sidekiq-schedulerでworkerを回す例。
Dockerfileならwebとworkerを同時に回せるのかはよくわからない。出来る人がいたら記事にしてください。