このブログエントリは Oracle Cloud Infrastructure アドベントカレンダー 2023 に参加しています。シリーズ2の 12/03 ぶんの記事です(↓の記事内容は 2023 年 12 月 02 日時点の内容で記載しています):
このブログで紹介するテーマは「プライベート heroku っぽい PaaS 環境を無料で作る」というものです。個人プログラマにとって無料で使える環境というのはありがたいもので、Oracle Cloud Infrastructure(OCI) の always free tier は本当に貴重な環境であります。この環境に加えて、
・sslip.io
・dokku
という2つの無料サービス+無料アプリを使って、自分専用の heroku っぽい PaaS 環境を構築する(ついでに GitHub Actions も併用して CI/CD 環境も用意する)、というものです。
【heroku っぽい環境】
そもそも「heroku っぽい PaaS 環境」の「heroku っぽい」 環境というのがどんな環境なのか、heroku をご存じな人であれば heroku そのものをイメージしていただくのがいいと思うのですが、ご存じない人向けに私の理解で簡単に紹介しておきます。
heroku は 2007 年に創業したクラウドサービス事業名であり、その運営会社名です。Java, JavaScript, Ruby, PHP といった各種プログラミング言語によって開発されたウェブアプリケーションを仮想コンテナ上で実行するプラットフォームを提供しています。ウェブアプリケーションに加えて各種データベースや管理・監視系サービスも併せて利用することができます。最大の特徴は PaaS(Platform as a Services) を体現するシンプルさで、手元にアプリケーションのソースコードがあれば(あるいは GitHub などのソースコードリポジトリがあれば)コマンド1つでクラウド上にアプリケーションをデプロイ/更新/スケールすることができます。"*.herokuapp.com" というアプリ公開用ドメインが提供されていて、早い者勝ちでこのドメインを使ったホスト名によるアプリケーション公開ができます(カスタムドメインを利用することも可能です)。2010 年には買収に伴う形でセールスフォース・ドットコム傘下となり、セールスフォース連携機能も強化されました。
heroku は 2022 年 8 月までは無料枠を提供していましたが、現在は無料で利用することはできません。この記事で紹介する内容は、この heroku 環境を模した(というか、ほぼそのものの)「heroku っぽい」環境を自分専用に構築する、という内容です。
【sslip.io】
自分専用の heroku っぽい環境を作る、実はこれ自体は後述の dokku を使うことでさほど難しくなく構築することができます。問題は「無料で」の部分です。肝心のサーバーは OCI の always free tier などを使うことでなんとかなりそうなものですが、選択肢が少ないのが「アプリ公開用のドメインをどうするか?」でした。
この PaaS 環境はアプリケーションを1つだけ公開するわけではなく、リソースの許す限り(今回の例だと OCI の always free tier 環境の限界まで)使うことができます。つまり "app1.domain.net" と "app2.domain.net" と "app3.domain.net" と・・・のように複数のアプリケーションをこの環境で公開することができるのです。そこでこの "domain.net" に相当するドメインが問題になります。無料のホスト名を入手する DNS サービスなどもありますが、このような heroku っぽいプラットフォームを作ろうとすると、単に1つや2つのホスト名が使える DNS サービスでは不十分で、ワイルドカード DNS("*.domain.net" というワイルドカード付きホスト名に対応した DNS サービス)を、それも無料のものを使う必要があります。
そこで今回使うのが sslip.io です。ここは無料のワイルドカード DNS に対応した無料サービスなのですが、特筆すべきはその便利さです。事前のユーザー登録や設定なども不要(!)で、例えば
XX.XX.XX.XX
というパブリック IPv4 アドレスであれば、
XX.XX.XX.XX.sslip.io
という名前でアクセスできます。しかもワイルドカード DNS に対応しているので、
*.XX.XX.XX.XX.sslip.io
というワイルドカードホスト名を(無料で)使うことができます。まさに今回のテーマのための神サービス! この sslip.io を使って PaaS 上にデプロイした各アプリケーションにホスト名でアクセスすることができるようになります。
【dokku】
そして dokku です。オープンソースの PaaS 環境は数あれど、構築や運用がここまで簡単なものは他にないと思っています(その代わり1サーバーで全環境を構築することになります。複数サーバーを束ねて PaaS 環境を作るのではなく、1サーバーだけのシンプルな構成で構築します)。
dokku 自体が「プライベート版 heroku」という代名詞で呼ばれることもあり、heroku と非常に似たインターフェースを持っています。dokku 本体が docker を内蔵しており、デプロイした各アプリケーションやデータベースは全て docker コンテナとして稼働します(docker コマンドを使って構築・運用するわけではありませんが、docker コマンドでコンテナの様子を確認したりもできます)。
また多くのプラグインも公開されており、例えば今回も使う Let's Encrypt プラグインを使うことでウェブアプリケーションを SSL 証明書に対応させることも(https アクセスに対応させることも)可能です。
これらのサービスやソフトウェアを組み合わせることで heroku っぽい PaaS 環境を無料で構築していきます。
【前提準備】
以下の構築作業に入る上での事前準備として、以下の準備までは完了しているものとします:
・OCI アカウント取得
・Ubuntu ベースの always free tier インスタンスの作成
・同インスタンスへの SSH ログイン
・同インスタンスへの TCP 80 番ポート、および TCP 443 番ポートの解放
重要な点として、always free tier インスタンスは CentOS ベースではなく Ubuntu ベースのもの(デフォルトユーザー名が opc ではなく ubuntu のほう)にする必要があります。CentOS の場合、dokku の標準インストーラーではインストールすることができません。なんか色々工夫することで dokku インストール自体はできるようになるかもしれませんが、インストール後の運用手順とかにも影響ありそうなので、今回の記事では対象外とします。
また今回の作業の最終結果として構築する PaaS 環境ではデプロイされたウェブアプリケーションに 80 番(http)および 443 番(https)ポートで接続することになります。したがって Ubuntu 側もこれらのポートにアクセスされる想定でファイアウォールを準備しておく必要があるのでした(デフォルトでは OCI のサブネットと Ubuntu の ufw の両方が閉じられています)。この辺りはこちらの記事が参考になると思います(私も参考にさせていただきました):
Oracle Cloud(OCI)でポートを開放する方法
前提準備がそろった所で dokku を使ったプライベート PaaS 環境の構築を行います。
【dokku 環境構築作業手順】
SSH で対象の Ubuntu サーバーにログインします。以下、しばらく CLI での作業になります。とりあえずお約束のリポジトリ更新コマンドを実行しておきます:
dokku はインストール用のスクリプトが提供されているので最初にダウンロードします:
sudo を付けてインストールスクリプトを実行します。その際にバージョン番号(2023/12/02 時点での最新バージョンは v0.32.3)を指定します:
このインストール作業は結構時間がかかります(docker のインストールや初期状態で必要なイメージのダウンロードも含みます)。作業が完了してプロンプトが戻るまでしばらく待ちます(ネットワーク次第ですが 10 分前後?)。
インストールが完了したら dokku にドメインを設定します。今回使う always free tier の Ubuntu サーバーのパブリック IP アドレスが XX.XX.XX.XX であったとして、以下のコマンドを実行します(XX.XX.XX.XX 部分を実際の IP アドレスに替えて実行してください):
次に秘密鍵と公開鍵を dokku に登録します。dokku は dokku 自体が git リポジトリを内包していて、この内包 git リポジトリを使ってアプリケーションをデプロイするのですが、その際に利用する鍵ペアを登録する必要があるのでした。お持ちの鍵ペア(秘密鍵ファイルと公開鍵ファイル)があればそれを使うこともできるのですが、後述する CI/CD 機能のため「パスフレーズのない鍵ファイル」を用意することをお勧めします。ここではパスフレーズのない鍵ファイルを作成する手順を紹介します。
以下のコマンドを実行します。実行直後に作成する鍵ファイル名が表示されるので(特に変更の必要がなければ)そのまま Enter キーを押してください。次にパスフレーズの入力を求められますが、今回は何も指定せずにそのまま Enter キーを押してください(再度同じパスフレーズの入力を求められた時もそのまま Enter):
この操作が完了すると /home/ubuntu/.ssh/ フォルダ内に秘密鍵(id_rsa)と公開鍵(id_rsa.pub)の2つが作成されます。念のためパーミッションを 400 に変更しておきます(デフォルトでそうなっていると思いますが、念のため):
これで dokku で使う秘密鍵ファイルと公開鍵ファイルが用意できました(既に所有していた鍵ファイルを使う場合はここから)。
まず以下のコマンドを実行して秘密鍵を登録します:
続いて以下のコマンドを実行して公開鍵を dokku に登録します:
dokku 自体の環境構築はこれでほぼ完了していますが、ついでに前述の Let's Encrypt プラグインも導入しておきます。以下のコマンドを実行してください(2つ目のコマンドは Let's Encrypt で SSL 鍵を作る際に必要なメールアドレスの指定です):
ここまでの作業で dokku のインストール/セットアップは完了しました。
【アプリケーションをデプロイ】
dokku の動作確認の意味も含めて、この状態で一度ウェブアプリケーションをデプロイしてみましょう。自分で使ってみたいアプリケーションがあればそれを使っていただいてもいい※のですが、特にない方は私のアプリを使ってみてください(一応 Node.js で作られていますが、単にメッセージを表示するだけの本当にシンプルなウェブアプリケーションです):
https://github.com/dotnsf/simpleweb
※自作のものなど、他のアプリケーションを使っても構いませんが、この段階ではデータベースなどを併用しないものを用意してください。
まずはアプリケーションのソースコードを入手します。改めて Ubuntu の CLI で以下を実行してソースコードを git clone してください(自分のソースコードを使う場合は自分のコードの URL を指定してください):
このローカルリポジトリに dokku 用のオリジンを追加します(localhost の git を使って dokku という名前で simpleweb のオリジンを作成しています):
このオリジンからデプロイする先のアプリケーション(simpleweb)を dokku 環境にあらかじめ追加しておきます:
では実際にアプリケーションをデプロイします。git コマンドで作成したオリジンに push することで dokku 内へのデプロイが実行される仕組みが提供されているので、デプロイ作業は単に目的のオリジン(dokku)へ main ブランチを git push するだけです(秘密鍵にパスフレーズが指定されている場合はここで入力を促されるので正しいパスフレーズを入力してください):
git push 実行後にデプロイが開始されます。ここではソースコードの内容からプラットフォーム環境(この simpleweb アプリの場合は Node.js 環境)を特定し、このプラットフォーム向けに docker コンテナイメージが作成され、そのイメージが dokku 内の docker コンテナとしてデプロイされることで完了します(というわけで、他のコマンドと比較して長い時間(約1~2分)がかかります):
無事にデプロイが完了したら、最後にポート番号のプロクシ設定をします。この simpleweb アプリケーションは 8080 番ポートで稼働するよう作られているので、80 番ポートから 8080 番ポートに転送してアクセスできるよう設定します:
これで simpleweb アプリケーションが 80 番ポートで公開されているはずです。ウェブブラウザを起動して、
http://simpleweb.XX.XX.XX.XX.sslip.io/
にアクセス("XX.XX.XX.XX" は Ubuntu サーバーの IP アドレス)し、以下のような画面になることを確認してください。このような画面が表示されれば成功です。dokku が正しくインストールされ、アプリケーションもデプロイできて、sslip.io を使ったホスト名での(HTTP による)アプリケーションアクセスができることが確認できました:
ついでに HTTPS アクセスを有効にしましょう。コマンドラインで以下のコマンドを実行します:
ここまで正しく実行した上でウェブブラウザをリロードすると(TSHS が有効になっているので)自動的に HTTP から HTTPS に切り替わり、https アクセスで同じ画面が表示できるはずです(もちろん直接 https://simpleweb.XX.XX.XX.XX.sslip.io/ にアクセスしても同じ結果になります):
【CI/CD】
最後に Github Actions を使った CI/CD 環境の構築手順についても紹介しておきます。GitHub でバージョン管理しているソースコードが更新されたタイミングで自動的に dokku 上のアプリケーションを最新ソースコードのアプリケーションに更新する、というものです。
まずは GitHub 上に管理対象のソースコードリポジトリを用意します。プライベートリポジトリでもパブリックリポジトリでもどちらでも構いません。以下では https://github.com/dotnsf/web-app-test というリポジトリを使った例を紹介しますが、実際に試す場合は実際の(自分が開発者としてアクセスできる)リポジトリを使ってください:
https://github.com/dotnsf/web-app-test
そしてそのリポジトリを使って上述のアプリケーションデプロイ手順を実行しておきます。つまり一度手動でオリジンを追加(git add remote origin)して、アプリケーションを作成(dokku apps:create)して、デプロイ(git push dokku main)して、HTTPS アクセスを有効(dokku letsencrypt:enable)にしておき、アプリケーションに HTTPS アクセスができる状態を作っておきます:
この状態から CI/CD 環境を構築していきます。まずは GitHub Actions を定義するのですが、手始めに秘密鍵を登録します。GitHub の該当リポジトリで "Settings" メニューを選択します:
"Settings" 画面の左メニューから "Secrets and variables" - "Actions" を選択します:
秘密鍵を登録したいので "Secrets and variables" 画面内の "New repository secret" ボタンをクリックします:
秘密鍵を登録する画面が表示されます。NAME 欄には SSH_PRIVATE_KEY と入力します。また value 欄には上述の作業中に作成して使った秘密鍵ファイル(id_rsa)のテキスト内容を "-----BEGIN RSA PRIVATE KEY-----" から "-----END RSA PRIVATE KEY-----" まで)をそのままコピー&ペーストして入力し、最後に "Add secret" ボタンをクリックします:
以下のように表示されれば、GitHub リポジトリへの秘密鍵の登録は完了です:
次にリポジトリ内にプッシュ時に実行される GitHub Actions を定義します。そのためにソースコード内に .github/workflows/ というフォルダを作成し、その中に deploy.yml(つまり .github/workflows/deploy.yml ファイル)を以下の内容で作成します:
青字の XX.XX.XX.XX は Ubuntu サーバーのパブリック IP アドレスで、赤字の web-app-test 部分は(dokku apps:create した時に指定した)アプリケーション名で、それぞれ置き換えて作成してください。またソースコードの書き換えが視覚的にもわかるよう、アプリケーション側にも何らかの変更を加えておいてください。
これらのファイルをリポジトリに追加して更新します:
最後の "git push" が完了すると上記で作成した Github Actions が起動し、定義内容に従って自動的にビルド/デプロイが開始されます。デプロイの様子は Github リポジトリの "Actions" メニューから確認することが可能です:
デプロイ完了後にアプリケーションにアクセスすると、最新のソースコードでデプロイされたアプリケーションが表示されるはずです(元のアプリで表示されていたメッセージの最後に "!" を追加する変更を加えていたのですが、正しく反映されていました):
これで CI/CD も実現できたことになります。ソースコードの main ブランチが更新されてコミット/プッシュされるたびにアプリケーションも自動更新されてデプロイしなおされる、という便利な機能も使うことができそうでした。
【おまけ】
自分が dokku を使っていて気付いたことなのですが、どうもデプロイのたびに変なゴミというか、使われることのないファイルが残ってしまうらしく、特に CI/CD を使って何度もデプロイしていると、どんどんディスクの残り容量が減っていってしまうようでした。これを回避するには定期的に以下のコマンドを実行する必要があります:
面倒でなければ手入力でもいいと思いますし、面倒な場合は crontab にでも登録してアクセス数が比較的少なそうな時間帯に実行するのがいいと思っています。
【まとめ】
以上、無料のサービスだけを組み合わせる形で、CI/CD 含めたプライベート heroku (っぽい)環境を作ることができました。理論上はこの環境にいくつでも複数のアプリケーションを登録して、別々に運用することができる環境なのですが、さすがに always free tier の環境(メモリ 1GB ディスク 30GB)で運用することを考えると、5~6アプリが限界ではないかと思っています。もちろんこのリソーススペック上の制約は有償版を使うことで回避できます。また有償版の OCI なら DNS も使えるので(sslip.io を使う形ではなく)カスタムドメインを利用して環境構築することもできるようになります。 とはいえ、「無料で構築できる PaaS 環境」という素敵な響きにも替え難い魅力がありますよね。いずれはリッチなスペックの VM +カスタムドメインで運用するとしても、初めのうちはこの無料環境でプライベート PaaS を楽しむのも悪くないと思っています。なお(無料というわけにはいきませんが)カスタムドメインやその DNS のセットアップまで含める形で dokku 環境を作ったこともあります(OCI は全く使ってませんけど・・)。その時の内容に興味ある方は私の dokku 関連の過去の記事を参照ください。
このブログで紹介するテーマは「プライベート heroku っぽい PaaS 環境を無料で作る」というものです。個人プログラマにとって無料で使える環境というのはありがたいもので、Oracle Cloud Infrastructure(OCI) の always free tier は本当に貴重な環境であります。この環境に加えて、
・sslip.io
・dokku
という2つの無料サービス+無料アプリを使って、自分専用の heroku っぽい PaaS 環境を構築する(ついでに GitHub Actions も併用して CI/CD 環境も用意する)、というものです。
【heroku っぽい環境】
そもそも「heroku っぽい PaaS 環境」の「heroku っぽい」 環境というのがどんな環境なのか、heroku をご存じな人であれば heroku そのものをイメージしていただくのがいいと思うのですが、ご存じない人向けに私の理解で簡単に紹介しておきます。
heroku は 2007 年に創業したクラウドサービス事業名であり、その運営会社名です。Java, JavaScript, Ruby, PHP といった各種プログラミング言語によって開発されたウェブアプリケーションを仮想コンテナ上で実行するプラットフォームを提供しています。ウェブアプリケーションに加えて各種データベースや管理・監視系サービスも併せて利用することができます。最大の特徴は PaaS(Platform as a Services) を体現するシンプルさで、手元にアプリケーションのソースコードがあれば(あるいは GitHub などのソースコードリポジトリがあれば)コマンド1つでクラウド上にアプリケーションをデプロイ/更新/スケールすることができます。"*.herokuapp.com" というアプリ公開用ドメインが提供されていて、早い者勝ちでこのドメインを使ったホスト名によるアプリケーション公開ができます(カスタムドメインを利用することも可能です)。2010 年には買収に伴う形でセールスフォース・ドットコム傘下となり、セールスフォース連携機能も強化されました。
heroku は 2022 年 8 月までは無料枠を提供していましたが、現在は無料で利用することはできません。この記事で紹介する内容は、この heroku 環境を模した(というか、ほぼそのものの)「heroku っぽい」環境を自分専用に構築する、という内容です。
【sslip.io】
自分専用の heroku っぽい環境を作る、実はこれ自体は後述の dokku を使うことでさほど難しくなく構築することができます。問題は「無料で」の部分です。肝心のサーバーは OCI の always free tier などを使うことでなんとかなりそうなものですが、選択肢が少ないのが「アプリ公開用のドメインをどうするか?」でした。
この PaaS 環境はアプリケーションを1つだけ公開するわけではなく、リソースの許す限り(今回の例だと OCI の always free tier 環境の限界まで)使うことができます。つまり "app1.domain.net" と "app2.domain.net" と "app3.domain.net" と・・・のように複数のアプリケーションをこの環境で公開することができるのです。そこでこの "domain.net" に相当するドメインが問題になります。無料のホスト名を入手する DNS サービスなどもありますが、このような heroku っぽいプラットフォームを作ろうとすると、単に1つや2つのホスト名が使える DNS サービスでは不十分で、ワイルドカード DNS("*.domain.net" というワイルドカード付きホスト名に対応した DNS サービス)を、それも無料のものを使う必要があります。
そこで今回使うのが sslip.io です。ここは無料のワイルドカード DNS に対応した無料サービスなのですが、特筆すべきはその便利さです。事前のユーザー登録や設定なども不要(!)で、例えば
XX.XX.XX.XX
というパブリック IPv4 アドレスであれば、
XX.XX.XX.XX.sslip.io
という名前でアクセスできます。しかもワイルドカード DNS に対応しているので、
*.XX.XX.XX.XX.sslip.io
というワイルドカードホスト名を(無料で)使うことができます。まさに今回のテーマのための神サービス! この sslip.io を使って PaaS 上にデプロイした各アプリケーションにホスト名でアクセスすることができるようになります。
【dokku】
そして dokku です。オープンソースの PaaS 環境は数あれど、構築や運用がここまで簡単なものは他にないと思っています(その代わり1サーバーで全環境を構築することになります。複数サーバーを束ねて PaaS 環境を作るのではなく、1サーバーだけのシンプルな構成で構築します)。
dokku 自体が「プライベート版 heroku」という代名詞で呼ばれることもあり、heroku と非常に似たインターフェースを持っています。dokku 本体が docker を内蔵しており、デプロイした各アプリケーションやデータベースは全て docker コンテナとして稼働します(docker コマンドを使って構築・運用するわけではありませんが、docker コマンドでコンテナの様子を確認したりもできます)。
また多くのプラグインも公開されており、例えば今回も使う Let's Encrypt プラグインを使うことでウェブアプリケーションを SSL 証明書に対応させることも(https アクセスに対応させることも)可能です。
これらのサービスやソフトウェアを組み合わせることで heroku っぽい PaaS 環境を無料で構築していきます。
【前提準備】
以下の構築作業に入る上での事前準備として、以下の準備までは完了しているものとします:
・OCI アカウント取得
・Ubuntu ベースの always free tier インスタンスの作成
・同インスタンスへの SSH ログイン
・同インスタンスへの TCP 80 番ポート、および TCP 443 番ポートの解放
重要な点として、always free tier インスタンスは CentOS ベースではなく Ubuntu ベースのもの(デフォルトユーザー名が opc ではなく ubuntu のほう)にする必要があります。CentOS の場合、dokku の標準インストーラーではインストールすることができません。なんか色々工夫することで dokku インストール自体はできるようになるかもしれませんが、インストール後の運用手順とかにも影響ありそうなので、今回の記事では対象外とします。
また今回の作業の最終結果として構築する PaaS 環境ではデプロイされたウェブアプリケーションに 80 番(http)および 443 番(https)ポートで接続することになります。したがって Ubuntu 側もこれらのポートにアクセスされる想定でファイアウォールを準備しておく必要があるのでした(デフォルトでは OCI のサブネットと Ubuntu の ufw の両方が閉じられています)。この辺りはこちらの記事が参考になると思います(私も参考にさせていただきました):
Oracle Cloud(OCI)でポートを開放する方法
前提準備がそろった所で dokku を使ったプライベート PaaS 環境の構築を行います。
【dokku 環境構築作業手順】
SSH で対象の Ubuntu サーバーにログインします。以下、しばらく CLI での作業になります。とりあえずお約束のリポジトリ更新コマンドを実行しておきます:
$ sudo apt update -y && sudo apt upgrade -y
dokku はインストール用のスクリプトが提供されているので最初にダウンロードします:
$ wget -NP . https://dokku.com/bootstrap.sh
sudo を付けてインストールスクリプトを実行します。その際にバージョン番号(2023/12/02 時点での最新バージョンは v0.32.3)を指定します:
$ sudo DOKKU_TAG=v0.32.3 bash bootstrap.sh
このインストール作業は結構時間がかかります(docker のインストールや初期状態で必要なイメージのダウンロードも含みます)。作業が完了してプロンプトが戻るまでしばらく待ちます(ネットワーク次第ですが 10 分前後?)。
インストールが完了したら dokku にドメインを設定します。今回使う always free tier の Ubuntu サーバーのパブリック IP アドレスが XX.XX.XX.XX であったとして、以下のコマンドを実行します(XX.XX.XX.XX 部分を実際の IP アドレスに替えて実行してください):
$ dokku domains:set-global XX.XX.XX.XX.sslip.io
次に秘密鍵と公開鍵を dokku に登録します。dokku は dokku 自体が git リポジトリを内包していて、この内包 git リポジトリを使ってアプリケーションをデプロイするのですが、その際に利用する鍵ペアを登録する必要があるのでした。お持ちの鍵ペア(秘密鍵ファイルと公開鍵ファイル)があればそれを使うこともできるのですが、後述する CI/CD 機能のため「パスフレーズのない鍵ファイル」を用意することをお勧めします。ここではパスフレーズのない鍵ファイルを作成する手順を紹介します。
以下のコマンドを実行します。実行直後に作成する鍵ファイル名が表示されるので(特に変更の必要がなければ)そのまま Enter キーを押してください。次にパスフレーズの入力を求められますが、今回は何も指定せずにそのまま Enter キーを押してください(再度同じパスフレーズの入力を求められた時もそのまま Enter):
$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa): ←[Enter]キーを押す Enter passphrase (empty for no passphrase): ←パスフレーズを入力せず [Enter] キーを押す Enter same passphrase again: ←もう一度そのまま [Enter] キーを押す Your identification has been saved in /home/ubuntu/.ssh/id_rsa. Your public key has been saved in /home/ubuntu/.ssh/id_rsa.pub.
この操作が完了すると /home/ubuntu/.ssh/ フォルダ内に秘密鍵(id_rsa)と公開鍵(id_rsa.pub)の2つが作成されます。念のためパーミッションを 400 に変更しておきます(デフォルトでそうなっていると思いますが、念のため):
$ chmod 400 ~/.ssh/id_rsa*
これで dokku で使う秘密鍵ファイルと公開鍵ファイルが用意できました(既に所有していた鍵ファイルを使う場合はここから)。
まず以下のコマンドを実行して秘密鍵を登録します:
$ eval "$(ssh-agent)" $ ssh-add -k ~/.ssh/id_rsa
続いて以下のコマンドを実行して公開鍵を dokku に登録します:
$ cat ~/.ssh/id_rsa.pub | sudo dokku ssh-keys:add admin
dokku 自体の環境構築はこれでほぼ完了していますが、ついでに前述の Let's Encrypt プラグインも導入しておきます。以下のコマンドを実行してください(2つ目のコマンドは Let's Encrypt で SSL 鍵を作る際に必要なメールアドレスの指定です):
$ sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git $ dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=(自分のメールアドレス)
ここまでの作業で dokku のインストール/セットアップは完了しました。
【アプリケーションをデプロイ】
dokku の動作確認の意味も含めて、この状態で一度ウェブアプリケーションをデプロイしてみましょう。自分で使ってみたいアプリケーションがあればそれを使っていただいてもいい※のですが、特にない方は私のアプリを使ってみてください(一応 Node.js で作られていますが、単にメッセージを表示するだけの本当にシンプルなウェブアプリケーションです):
https://github.com/dotnsf/simpleweb
※自作のものなど、他のアプリケーションを使っても構いませんが、この段階ではデータベースなどを併用しないものを用意してください。
まずはアプリケーションのソースコードを入手します。改めて Ubuntu の CLI で以下を実行してソースコードを git clone してください(自分のソースコードを使う場合は自分のコードの URL を指定してください):
$ cd $ git clone https://github.com/dotnsf/simpleweb $ cd simpleweb
このローカルリポジトリに dokku 用のオリジンを追加します(localhost の git を使って dokku という名前で simpleweb のオリジンを作成しています):
$ git remote add dokku dokku@localhost:simpleweb
このオリジンからデプロイする先のアプリケーション(simpleweb)を dokku 環境にあらかじめ追加しておきます:
$ dokku apps:create simpleweb
では実際にアプリケーションをデプロイします。git コマンドで作成したオリジンに push することで dokku 内へのデプロイが実行される仕組みが提供されているので、デプロイ作業は単に目的のオリジン(dokku)へ main ブランチを git push するだけです(秘密鍵にパスフレーズが指定されている場合はここで入力を促されるので正しいパスフレーズを入力してください):
$ git push dokku main
git push 実行後にデプロイが開始されます。ここではソースコードの内容からプラットフォーム環境(この simpleweb アプリの場合は Node.js 環境)を特定し、このプラットフォーム向けに docker コンテナイメージが作成され、そのイメージが dokku 内の docker コンテナとしてデプロイされることで完了します(というわけで、他のコマンドと比較して長い時間(約1~2分)がかかります):
無事にデプロイが完了したら、最後にポート番号のプロクシ設定をします。この simpleweb アプリケーションは 8080 番ポートで稼働するよう作られているので、80 番ポートから 8080 番ポートに転送してアクセスできるよう設定します:
$ dokku proxy:ports-add simpleweb http:80:8080
これで simpleweb アプリケーションが 80 番ポートで公開されているはずです。ウェブブラウザを起動して、
http://simpleweb.XX.XX.XX.XX.sslip.io/
にアクセス("XX.XX.XX.XX" は Ubuntu サーバーの IP アドレス)し、以下のような画面になることを確認してください。このような画面が表示されれば成功です。dokku が正しくインストールされ、アプリケーションもデプロイできて、sslip.io を使ったホスト名での(HTTP による)アプリケーションアクセスができることが確認できました:
ついでに HTTPS アクセスを有効にしましょう。コマンドラインで以下のコマンドを実行します:
$ dokku letsencrypt:set simpleweb email (自分のメールアドレス) $ dokku letsencrypt:enable simpleweb
ここまで正しく実行した上でウェブブラウザをリロードすると(TSHS が有効になっているので)自動的に HTTP から HTTPS に切り替わり、https アクセスで同じ画面が表示できるはずです(もちろん直接 https://simpleweb.XX.XX.XX.XX.sslip.io/ にアクセスしても同じ結果になります):
【CI/CD】
最後に Github Actions を使った CI/CD 環境の構築手順についても紹介しておきます。GitHub でバージョン管理しているソースコードが更新されたタイミングで自動的に dokku 上のアプリケーションを最新ソースコードのアプリケーションに更新する、というものです。
まずは GitHub 上に管理対象のソースコードリポジトリを用意します。プライベートリポジトリでもパブリックリポジトリでもどちらでも構いません。以下では https://github.com/dotnsf/web-app-test というリポジトリを使った例を紹介しますが、実際に試す場合は実際の(自分が開発者としてアクセスできる)リポジトリを使ってください:
https://github.com/dotnsf/web-app-test
そしてそのリポジトリを使って上述のアプリケーションデプロイ手順を実行しておきます。つまり一度手動でオリジンを追加(git add remote origin)して、アプリケーションを作成(dokku apps:create)して、デプロイ(git push dokku main)して、HTTPS アクセスを有効(dokku letsencrypt:enable)にしておき、アプリケーションに HTTPS アクセスができる状態を作っておきます:
この状態から CI/CD 環境を構築していきます。まずは GitHub Actions を定義するのですが、手始めに秘密鍵を登録します。GitHub の該当リポジトリで "Settings" メニューを選択します:
"Settings" 画面の左メニューから "Secrets and variables" - "Actions" を選択します:
秘密鍵を登録したいので "Secrets and variables" 画面内の "New repository secret" ボタンをクリックします:
秘密鍵を登録する画面が表示されます。NAME 欄には SSH_PRIVATE_KEY と入力します。また value 欄には上述の作業中に作成して使った秘密鍵ファイル(id_rsa)のテキスト内容を "-----BEGIN RSA PRIVATE KEY-----" から "-----END RSA PRIVATE KEY-----" まで)をそのままコピー&ペーストして入力し、最後に "Add secret" ボタンをクリックします:
以下のように表示されれば、GitHub リポジトリへの秘密鍵の登録は完了です:
次にリポジトリ内にプッシュ時に実行される GitHub Actions を定義します。そのためにソースコード内に .github/workflows/ というフォルダを作成し、その中に deploy.yml(つまり .github/workflows/deploy.yml ファイル)を以下の内容で作成します:
--- name: 'deploy' # yamllint disable-line rule:truthy on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Cloning repo uses: actions/checkout@v2 with: fetch-depth: 0 - name: Push to dokku uses: dokku/github-action@master with: # specify the `main` branch as the remote branch to push to branch: 'main' git_remote_url: 'ssh://dokku@XX.XX.XX.XX:22/web-app-test' ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
青字の XX.XX.XX.XX は Ubuntu サーバーのパブリック IP アドレスで、赤字の web-app-test 部分は(dokku apps:create した時に指定した)アプリケーション名で、それぞれ置き換えて作成してください。またソースコードの書き換えが視覚的にもわかるよう、アプリケーション側にも何らかの変更を加えておいてください。
これらのファイルをリポジトリに追加して更新します:
$ git add . $ git commit -m 'dokku CI/CD with Github Actions' $ git push
最後の "git push" が完了すると上記で作成した Github Actions が起動し、定義内容に従って自動的にビルド/デプロイが開始されます。デプロイの様子は Github リポジトリの "Actions" メニューから確認することが可能です:
デプロイ完了後にアプリケーションにアクセスすると、最新のソースコードでデプロイされたアプリケーションが表示されるはずです(元のアプリで表示されていたメッセージの最後に "!" を追加する変更を加えていたのですが、正しく反映されていました):
これで CI/CD も実現できたことになります。ソースコードの main ブランチが更新されてコミット/プッシュされるたびにアプリケーションも自動更新されてデプロイしなおされる、という便利な機能も使うことができそうでした。
【おまけ】
自分が dokku を使っていて気付いたことなのですが、どうもデプロイのたびに変なゴミというか、使われることのないファイルが残ってしまうらしく、特に CI/CD を使って何度もデプロイしていると、どんどんディスクの残り容量が減っていってしまうようでした。これを回避するには定期的に以下のコマンドを実行する必要があります:
$ docker system prune -f && docker system prune --all -f
面倒でなければ手入力でもいいと思いますし、面倒な場合は crontab にでも登録してアクセス数が比較的少なそうな時間帯に実行するのがいいと思っています。
【まとめ】
以上、無料のサービスだけを組み合わせる形で、CI/CD 含めたプライベート heroku (っぽい)環境を作ることができました。理論上はこの環境にいくつでも複数のアプリケーションを登録して、別々に運用することができる環境なのですが、さすがに always free tier の環境(メモリ 1GB ディスク 30GB)で運用することを考えると、5~6アプリが限界ではないかと思っています。もちろんこのリソーススペック上の制約は有償版を使うことで回避できます。また有償版の OCI なら DNS も使えるので(sslip.io を使う形ではなく)カスタムドメインを利用して環境構築することもできるようになります。 とはいえ、「無料で構築できる PaaS 環境」という素敵な響きにも替え難い魅力がありますよね。いずれはリッチなスペックの VM +カスタムドメインで運用するとしても、初めのうちはこの無料環境でプライベート PaaS を楽しむのも悪くないと思っています。なお(無料というわけにはいきませんが)カスタムドメインやその DNS のセットアップまで含める形で dokku 環境を作ったこともあります(OCI は全く使ってませんけど・・)。その時の内容に興味ある方は私の dokku 関連の過去の記事を参照ください。
dokku に関して、とりあえず環境構築と試験的な運用までが可能な一連の手続きについてはこのブログエントリ内で紹介していますが、実際にはこの中で紹介していない色々な機能があります(スケール対応とか、データベース系のプラグインを併用するとか、・・)。dokku はオンラインヘルプも充実しているので、詳しくはドキュメントを参照してください。
最後に注意点を。今回紹介した方法で dokku 環境を構築してアプリケーションを公開すると、事実上サーバーの IP アドレスを公開する形になります(sslip.io を使っているので、アプリケーションのホスト名の中に IP アドレスが含まれることになるからです)。サーバーの IP アドレスがバレても困らないように SSH などはしっかりセキュアに対策しておくといった対策はしっかりしておきましょう。
私自身は実際に dokku で(カスタムドメインを使って)自作サービスをいくつか運用しています。2年以上使っていますが、とても便利です。この記事が私と同じような技術クラスタの人のお役に立てれば何よりもうれしいです。
最後に注意点を。今回紹介した方法で dokku 環境を構築してアプリケーションを公開すると、事実上サーバーの IP アドレスを公開する形になります(sslip.io を使っているので、アプリケーションのホスト名の中に IP アドレスが含まれることになるからです)。サーバーの IP アドレスがバレても困らないように SSH などはしっかりセキュアに対策しておくといった対策はしっかりしておきましょう。
私自身は実際に dokku で(カスタムドメインを使って)自作サービスをいくつか運用しています。2年以上使っていますが、とても便利です。この記事が私と同じような技術クラスタの人のお役に立てれば何よりもうれしいです。