これは 「フィヨルドブートキャンプ Part 2 Advent Calendar 2022」 の3日目の記事です(Part 1 もあります🎅)。 昨日はよかじさんの「フィヨルドブートキャンプのカリキュラム以外でやってよかったこと - よかじみ」という記事でした。

概要

この記事は Heroku が無料プランを終了するのをきっかけに Heroku の代替 OSS「CapRover」 を VPS 上に構築してアプリケーションのデプロイを試した記録です。

背景

フィヨルドブートキャンプは最後の課題「Webサービスを作って公開する」を終えて卒業になります 1

そのWebサービスのデプロイ先として私が検討していたのは Heroku でしたが、 Heroku’s Next Chapter | Heroku でアナウンスがあったとおり2022年11月28日で無料プランが終了しました。 現時点(2022年12月03日)では 最小構成(Eco Dyno と Postgres Mini)で月額 $10 となり、次の機能の価値と浮いた時間に対して格安と考えます。

  • アプリケーションのデプロイが開発端末から実行でき、かつ簡単なこと
  • 大量でないデータの永続化手段としてデーターベースを作成できること
  • 実行環境のメンテナンス(パッチやセキュリティ設定)の手間がほとんどなく、アプリケーションの構築に集中できること
  • 新しい機能によって開発体験がよくなること

この記事では最小構成の年額となる $120(現時点では 16,242 円) 2 を予算として OSS を活用したアプリケーションのデプロイを試します。

実行環境

2022年12月09日までのキャンペーンですが ConoHa VPS のメモリ 2GB/CPU 3Core プランが 3年分 16,711 円 で使えます(詳細は VPS割引きっぷを使ってお得にConoHa VPSを使ってみた にまとめていますので、そちらを参照ください)。今回は上記のプランを実行環境とし、 OS は Ubuntu 22.04 にしました。

Heroku の代替 OSS

CapRover - Free and Open Source PaaS! を使用します。ドキュメントデモ環境(password: captain42) を見ると次のデプロイ方法がありました。

デプロイ方法 補足
Git ローカルリポジトリのディレクトリでコマンド「caprover deploy」を実行する -
TAR形式のアーカイブファイルをアップロードする 試していません
GitHub/Bitbucket/GitLab の Webhook で連携する 試していません
Dockerfile/Dockerイメージ/captain-definition を指定する -
ワンクリック用テンプレート を使用する/追加する 試していません

ハードウェア要件とソフトウェア要件

公式サイトにある前提条件 ではいろいろ書いてありますが要点は次のとおりです。

  • サーバーのメインメモリは 1GB 以上を推奨している
  • OS は Ubuntu を推奨している
  • Docker は v17.06.x 以上が必要になる
  • ファイアウォールは Docker RegistryCluster が不要であれば 80/tcp443/tcp だけ許可すればよさそう

インストール手順

公式サイトにあるセットアップ手順コマンド「 caprover serversetupDocker CE のインストール手順 を踏まえると次のシェルスクリプトになります。

bootstrap.sh
#!/bin/bash
CAPROVER_ROOT_DOMAIN=app.example.com
LETSENCRYPT_CERTIFICATE_EMAIL=admin@example.com

apt update
apt upgrade -y

apt install -y \
  sudo \
  wget \
  curl

# Docker
# See: https://docs.docker.com/engine/install/ubuntu/
echo "127.0.0.1 "`hostname` >> /etc/hosts

apt remove -y \
  docker \
  docker-engine \
  docker.io \
  containerd \
  runc

apt install -y --no-install-recommends \
  ca-certificates \
  gnupg \
  lsb-release

mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update

apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-compose-plugin

# Node.js
# See: https://github.com/nodesource/distributions#installation-instructions
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - &&\
apt install -y nodejs
npm install -g npm

# CapRover
# See: https://caprover.com/docs/get-started.html
mkdir /usr/local/captain
cd /usr/local/captain/

docker run \
  -e BY_PASS_PROXY_CHECK='TRUE' \
  -p 80:80 -p 443:443 -p 3000:3000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /captain:/captain caprover/caprover

# See: https://github.com/caprover/caprover-cli
# Note: https://github.com/coollabsio/get.coollabs.io/blob/main/static/coolify/install.sh
npm install -g caprover

CAPROVER_NEW_PASSWORD=$(echo $(($(date +%s%N) / 1000000)) | sha256sum | base64 | head -c 32)
cat << EOS > /usr/local/captain/config.json
{
  "caproverIP": "$(curl -4 ifconfig.co)",
  "caproverPassword": "captain42",
  "caproverRootDomain": "${CAPROVER_ROOT_DOMAIN}",
  "newPassword": "${CAPROVER_NEW_PASSWORD}",
  "caproverName": "$(hostname)",
  "certificateEmail": "${LETSENCRYPT_CERTIFICATE_EMAIL}"
}
EOS

なお OS の基本設定は次の内容を想定しています。

項目 設定値
ホスト名 self-hostable-heroku-by-captain
ファイアウォール http, https, ssh を許可している

セットアップ手順

前述の bootstrap.sh をスーパーユーザー権限で実行すると次の内容でセットアップ用の設定ファイル「/usr/local/captain/config.json」が作成されます。自身の実行環境向けに設定ファイルを変更してください。

設定項目 設定値 設定内容
caproverIP $(curl -4 ifconfig.co) サーバーのグローバルIPアドレス
caproverRootDomain app.example.com CapRover の Web UI やデプロイしたアプリケーションが稼働するFQDN
newPassword ランダムな英数字32文字 コマンドラインインターフェースでログインする際に必要になります
caproverName ホスト名 同上
certificateEmail admin@example.com Let’s Encrypt に登録するメールアドレス

次にDNSレコードを追加します。ホスト名を app 以外に変更している場合は読み替えてください。

ホスト名 種別 内容
*.app A サーバーのグローバルIPアドレス

dig コマンドや nslookup(dig)テスト【DNSサーバ接続確認】 などで反映されたかを確認してください。

セットアップについては次のコマンドで実行します。もし CapRover を起動してすぐにコマンドを実行した場合はセットアップに失敗することがあります。60秒ほど待ってから再度実行してください。

# caprover serversetup -c /usr/local/captain/config.json ⏎

正常に完了したら CapRover の Web UI の URL が表示され newPassword で指定したパスワードでログインできます。 e.g. https://captain.app.example.com

CapRover

デプロイしてみる

試しにフィヨルドブートキャンプの課題で作成した https://github.com/maeda-m/sinatra-note-app を次の流れでデプロイしてみます。

  1. CapRover の Web UI でアプリケーション(Puma)とデーターベース(PostgreSQL)の枠を作成する
  2. CapRover の Web UI でデーターベースをデプロイする
  3. 開発端末からコマンド「caprover deploy」でアプリケーションをデプロイする

なお CapRover ではワンクリック用テンプレートにおいて Docker Compose に部分対応しています。 例えば Ruby on Rails で構築されている Redmine のワンクリック用テンプレート があり、AP/DB の一括設定ができます。

1. CapRover の Web UI でアプリケーション(Puma)とデーターベース(PostgreSQL)の枠を作成する

アプリケーションの枠を作成する

次の内容でボタン「Create New App」をクリックして枠を作成します。

App Name Has Persistent Data
sinatra-note 未チェック

Create New App

HTTP Settings

次の内容で入力し、ボタン「Save & Update」をクリックします。

入力項目 入力値 入力内容
Enable HTTPS クリックする HTTPS を有効にする
Container HTTP Port 9292 80番ポート以外で HTTP を受付している場合に設定する
Force HTTPS by redirecting all HTTP traffic to HTTPS チェックを入れる HTTP でアクセスされたときに強制で HTTPS にする

HTTP Settings - after

データーベースの枠を作成する

次の内容でボタン「Create New App」をクリックして枠を作成します。

App Name Has Persistent Data
sinatra-note-db チェックを入れる

Create New App

HTTP Settings

次の内容で入力し、ボタン「Save & Update」をクリックします。

入力項目 入力値 入力内容
Do not expose as web-app チェックを入れる 非 Web アプリケーションとして設定する

HTTP Settings - after

2. CapRover の Web UI でデーターベースをデプロイする

App Configs

環境変数 にてユーザー名やデーターベース名を設定します。 またデータの永続化のために VOLUME を設定し、ボタン「Save & Update」をクリックします。

App Configs - after

Deployment

初期化スクリプトや起動オプションの設定を反映した Dockerfile を用意し 🚀 Method 4: Deploy plain Dockerfile に入力します。

Dockerfile
FROM postgres:14.2

ENV POSTGRES_HOST_AUTH_METHOD trust
ENV POSTGRES_INITDB_ARGS --encoding=UTF-8 --locale=C

RUN set -eux; \
  apt update; \
  apt install -y --no-install-recommends \
    ca-certificates \
    wget \
  ; \
  rm -rf /var/lib/apt/lists/*

RUN cd /docker-entrypoint-initdb.d \
  && wget https://raw.githubusercontent.com/maeda-m/sinatra-note-app/main/db/initdb.sql

CMD [ "postgres", "-c", "log_statement=all", "-c", "log_connections=on", "-c", "log_disconnections=on" ]

ボタン「Deploy Now」をクリックするとデプロイ時のログが更新されます。 Build has finished successfully! と表示されれば成功です。

Deployment

3. 開発端末からコマンド「caprover deploy」でアプリケーションをデプロイする

App Configs

環境変数にてデーターベースへの接続情報を設定し、ボタン「Save & Update」をクリックします。

App Configs - after

Deployment

次の Git ローカルリポジトリを用意してデプロイします。 なおデプロイは git archive --format tar を経由するためコミットされていないファイルはデプロイされません。

captain-example
|--.git
|--captain-definition
|--Dockerfile
captain-definition
{
  "schemaVersion": 2,
  "dockerfilePath": "./Dockerfile"
}

Dockerfile
FROM ruby:3.1.1-bullseye

ENV RACK_ENV production

RUN set -eux; \
  apt update; \
  apt install -y --no-install-recommends \
    libpq-dev \
  ; \
  rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/maeda-m/sinatra-note-app.git \
   --branch main \
  /opt/sinatra-note-app

WORKDIR /opt/sinatra-note-app

RUN mv /opt/sinatra-note-app/entrypoint.sh /usr/local/bin/docker-entrypoint.sh \
  && chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 9292
CMD [ "bundle", "exec", "puma" ]

開発端末で caprover login をしてから caprover deploy を実行します。 Deployed successfully と表示されれば成功です。

caprover deploy - start caprover deploy - done

なお Windows Terminal の場合はブランチ名を入力する前に Enter を押下する必要があります 3


デプロイ完了後、しばらくしてアプリケーションURLにアクセスすると無事稼働していました🎉

sinatra-note-app

おわりに

この記事ではデプロイしたアプリケーションのトラブルシューティングについては記載していません。

ログ管理や heroku run のようなことをしたい場合は 公式サイトのトラブルシューティング を参考にしてください。CapRover の Web UI に対するアクセスを制限したい場合は 公式サイトの NGINX Config を参考にしてください。

また CapRover - Free and Open Source PaaS! に関わるすべての方に感謝申し上げます🙏


  1. 課題の目的などは フィヨルドブートキャンプに「自作サービスを作る」という課題がある理由とフィヨルドブートキャンプの取り組み | FJORD BOOT CAMP(フィヨルドブートキャンプ) に詳しい記事がありますので、そちらを参照ください。

  2. 1か月前は1ドル148円台でした。

  3. https://github.com/caprover/caprover/issues/1209