まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:dokku

このブログエントリは Oracle Cloud Infrastructure アドベントカレンダー 2023 に参加しています。シリーズ2の 12/03 ぶんの記事です(↓の記事内容は 2023 年 12 月 02 日時点の内容で記載しています):
2023120101


このブログで紹介するテーマは「プライベート 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分)がかかります):
2023120102


無事にデプロイが完了したら、最後にポート番号のプロクシ設定をします。この simpleweb アプリケーションは 8080 番ポートで稼働するよう作られているので、80 番ポートから 8080 番ポートに転送してアクセスできるよう設定します:
$ dokku proxy:ports-add simpleweb http:80:8080

2023120103


これで simpleweb アプリケーションが 80 番ポートで公開されているはずです。ウェブブラウザを起動して、
  http://simpleweb.XX.XX.XX.XX.sslip.io/
にアクセス("XX.XX.XX.XX" は Ubuntu サーバーの IP アドレス)し、以下のような画面になることを確認してください。このような画面が表示されれば成功です。dokku が正しくインストールされ、アプリケーションもデプロイできて、sslip.io を使ったホスト名での(HTTP による)アプリケーションアクセスができることが確認できました:
2023120104


ついでに HTTPS アクセスを有効にしましょう。コマンドラインで以下のコマンドを実行します:
$ dokku letsencrypt:set simpleweb email (自分のメールアドレス)

$ dokku letsencrypt:enable simpleweb

2023120105


ここまで正しく実行した上でウェブブラウザをリロードすると(TSHS が有効になっているので)自動的に HTTP から HTTPS に切り替わり、https アクセスで同じ画面が表示できるはずです(もちろん直接 https://simpleweb.XX.XX.XX.XX.sslip.io/ にアクセスしても同じ結果になります):
2023120106


【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 アクセスができる状態を作っておきます:
2023120105


この状態から CI/CD 環境を構築していきます。まずは GitHub Actions を定義するのですが、手始めに秘密鍵を登録します。GitHub の該当リポジトリで "Settings" メニューを選択します:
2023120107


"Settings" 画面の左メニューから "Secrets and variables" - "Actions" を選択します:
2023120108


秘密鍵を登録したいので "Secrets and variables" 画面内の "New repository secret" ボタンをクリックします:
2023120101


秘密鍵を登録する画面が表示されます。NAME 欄には SSH_PRIVATE_KEY と入力します。また value 欄には上述の作業中に作成して使った秘密鍵ファイル(id_rsa)のテキスト内容を "-----BEGIN RSA PRIVATE KEY-----" から "-----END RSA PRIVATE KEY-----" まで)をそのままコピー&ペーストして入力し、最後に "Add secret" ボタンをクリックします:
2023120102


以下のように表示されれば、GitHub リポジトリへの秘密鍵の登録は完了です:
2023120103


次にリポジトリ内にプッシュ時に実行される 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" メニューから確認することが可能です:
2023120104


デプロイ完了後にアプリケーションにアクセスすると、最新のソースコードでデプロイされたアプリケーションが表示されるはずです(元のアプリで表示されていたメッセージの最後に "!" を追加する変更を加えていたのですが、正しく反映されていました):
2023120106


これで 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 環境で公開しています。このブログでも何件かの dokku 関連ネタを紹介しています。今回のネタはその1つです:
20220609


dokku を使うことで、ウェブアプリケーションだけでなく PostgreSQL のようなデータベースインスタンスを作って利用することもできます。実際に PostgreSQL データベースを作ってウェブアプリケーションと接続(link)して使う方法をブログエントリとして紹介したこともあります:
http://dotnsf.blog.jp/archives/1080505175.html


最終的に dokku で公開するアプリケーションに関しては dokku アプリから dokku の PostgreSQL に接続して使うことになります。この場合はアプリとデータベースとを link することで、アプリケーション側の環境変数 DATABASE_URL に
postgres://postgres:password@dokku-postgres-mydb:5432/mydb

のような接続文字列の値が設定されます(ホスト名 dokku-postgres-mydb、ポート番号 5432、ユーザー名 postgres、パスワード password、DB名 mydb)。この値を使ってデータベースに接続することになります(ホスト名 dokku-postgres-mydb という値は dokku 内部で解決されて、アプリケーションサーバーと同じ dokku 内で動いている PostgreSQL データベースコンテナに接続されます)。この時点では PostgreSQL データベースは dokku 内のアプリケーションだけに公開されていることになります。


ただアプリケーションを一時的に localhost で起動して、localhost から dokku の PostgreSQL に接続して動作確認したくなることもあります(デバッグ時など)。そのようなことをする場合、dokku 内に作った PostgreSQL を dokku 外の(localhost の)アプリケーションから接続することになり、上述の(dokku 内のアプリケーションから接続する前提の)接続文字列を使うことはできません。このような接続設計を実現するための設定を紹介します。

まず PostgreSQL データベースインスタンス(mydb)を作成します:
# dokku postgres:create mydb

この mydb への(link した dokku アプリからの)接続文字列を確認するには以下のようなコマンドを実行します。実行結果の Dsn 値に対象の接続文字列を確認できます:
# dokku postgres:info mydb

=====> mydb postgres service information
       Config dir:          /var/lib/dokku/services/postgres/mydb/data
       Config options:
       Data dir:            /var/lib/dokku/services/postgres/mydb/data
       Dsn:                 postgres://postgres:password@dokku-postgres-mydb:5432/mydb
       Exposed ports:       -
       Id:                  1f5692d21aeb94de6f7bd9f467c41e2a52d6ee9fdff4d628379c883f72d25f9e
       Internal ip:         172.17.0.29
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/mydb
       Status:              running
       Version:             postgres:14.2

この mydb データベースを dokku 外部から利用するには expose コマンドを実行します:
# dokku postgres:expose mydb

-----> Service mydb exposed on port(s) [container->host]: 5432->31157

すると実行結果に(↑の例だと) 5432->31157 という結果が表示されます。この 31157 というのが dokku 外部からこの mydb に接続するための(外向けの)ポート番号となります。仮にこの dokku が動いているホストの名前が dokku.myserver.com であったとすると、外部アプリからの接続文字列は
postgres://postgres:password@dokku.myserver.com:31157/mydb

を指定すればよい、ということになります。


自分で開発したウェブサービスの公開先として、最近は dokku で作った公開プライベート(=自分専用)クラウド環境が重宝しています。デプロイはソースコードを git clone(pull) して git push するだけ、という非常に簡略化されていることに加え、やはり「自分専用(=使いたいサブドメインを誰かに先に取られている心配がない)」という気持ちの余裕も以外と大きい気がしています。dokku の導入については過去の記事を参照してください:
dokku でプライベート PaaS 環境を構築する(1)
dokku でプライベート PaaS 環境を構築する(2)


今回は dokku のいわゆる CI/CD(Continuous Integration / Continuous Delivery) についてブログエントリを書きます。dokku が非常に便利であるが故に、ソースコードが更新されるたびに手作業で push するのは(大した手間ではないのですが)やはり面倒です。というわけで Git リポジトリへのプッシュをフックとする dokku のデプロイ自動化を実現する方法を調べてみました。特に今回紹介するのは GitHub Actions を使った方法で、ソースコードを GitHub リポジトリで管理している人であればちょっとした設定を追加するだけで CI が実現できます。なお、今回 CI/CD を設定する dokku サーバーは "yellowmix.net" というカスタムドメインを有効に設定してあって、"XXXXX.yellowmix.net" というホスト名でアプリケーションをデプロイできるように設定済みである、という前提で紹介します(手順3の中にこの設定に関わる部分があります)。


以下、その手順紹介です。


【手順1 パスフレーズなしの秘密鍵/公開鍵を作成・登録】
GitHub Actions 内でデプロイを自動実行するため、パスフレーズ無しで作られた秘密鍵が必要です。というわけで、パスフレーズ有りの秘密鍵を使っている場合は作成および登録の再実行が必要になります。

まずは秘密鍵と公開鍵を(再)作成します。dokku サーバーのシェルにログインして、以下のコマンドを実行します:
$ ssh-keygen

この後、秘密鍵を作成するパスを入力するよう促されます。デフォルトでは "~/.ssh/id_rsa" が指定されているはずです。変更する場合は正しいファイルパスを入力、デフォルト設定のままで問題なければそのまま Enter を入力します。

次にファイルのパスフレーズを入力するよう促されますが、今回はパスフレーズのない秘密鍵および公開鍵のペアを作りたいので、空のまま Enter を押して先に進めます。パスフレーズの指定が終わると指定されたパスで秘密鍵および公開鍵が作成されます。特に秘密鍵の内容は手順2でも必要になるので、 cat コマンドで一度中身を確認しておきます("-----BEGIN RSA PRIVATE KEY-----" で始まって "-----END RSA PRIVATE KEY-----" で終わる内容が表示されます):
$ cat ~/.ssh/id_rsa

秘密鍵が作れたら dokku に登録します。上述のセットアップを既に別の(パスフレーズ付きの)秘密鍵で実施済みで、別の秘密鍵が登録済みの場合は、以下のコマンドで一度削除しておきます:
$ sudo dokku ssh-keys:remove admin

改めて(再度)秘密鍵をファイルパスを指定して登録します:
$ cat ~/.ssh/id_rsa | sudo dokku ssh-keys:add admin

これで新しい(パスフレーズのない)秘密鍵が作成され、 dokku に登録されました。続いて GitHub のリポジトリ側で GitHub Actions 側の設定を行います。


【手順2 GitHub の対象アプリケーションに GitHub Actions 用の秘密鍵を設定】
GitHub リポジトリにコミットされたタイミングでデプロイを実行できるよう、対象アプリケーションの GitHub リポジトリに GitHub Actions を設定します。まずは GitHub の対象アプリケーションのページを開き、Settings を選択します(ユーザーの Settings ではなく、アプリケーションの Settings を開きます):
2022060901


CI ワークフローを定義する前に、ワークフロー内で使う秘密鍵の情報を先に登録しておきます。Settings ページの左ペインから Secrets - Actions を選択します:
2022060902


新規に秘密鍵を登録したいので、画面右上の "New repository secret" ボタンをクリックします:
2022060903


秘密鍵を登録する画面が表示されるので、NAME 欄に SSH_PRIVATE_KEY と入力し、Value 欄には手順1で作成した秘密鍵ファイルの内容("-----BEGIN RSA PRIVATE KEY-----" から "-----END RSA PRIVATE KEY-----" まで)をそのままコピー&ペーストして入力し、最後に "Add secret" ボタンをクリックします:
2022060904


以下のように表示されればリポジトリへの秘密鍵の登録は完了です:
2022060905



【手順3 対象アプリケーションに GitHub Actions を設定】
ここまでの準備ができていれば、後はコミット時(プッシュ時)の GitHub Actions を登録することで dokku への自動デプロイを行うことができるようになります。ソースコードに .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@yellowmix.net:22/hostname'
          ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}

このうち、青字部分(main と書かれた部分)は「どのブランチが更新された時に、どのブランチを対象にデプロイするか」を指定しています。今回は「 main ブランチ更新時に main ブランチの内容をデプロイ」したいので、このような設定にしています。master ブランチを使いたい場合はここを master に変更してください。 また赤字部分はデプロイ先のリポジトリ URL です。この例では "yellowmix.net" というドメインホストを使って https://hostname.yellowmix.net/ という URL でアプリケーションを公開するための設定にしています。この部分は皆さんの dokku 環境に合わせて変更する必要があるのでご注意ください。 加えて、最終行に手順2で設定した秘密鍵を使う指定がされています。秘密鍵は外部に漏れてはまずい情報なので、ハードコートや公開変数などは使わずに、このような形で登録済みのシークレット情報を参照するよう指定しています。

なお、この deploy.yml ファイルの中で dokku/github-action というリポジトリが指定されている箇所がありますが、これは dokku から提供されている GitHub Actions 連携用のコンテナイメージです。このコンテナイメージを使ってデプロイを行う、という作業内容になっています。同コンテナイメージのソースコードはこちらで提供されています:


ここまで用意できたら、対象のプロジェクトを GitHub にコミット&プッシュします(以下の例は main ブランチに直接コミットしている想定です):
$ git add .

$ git commit -m 'node v14'

$ git push origin main

プッシュが成功すると GitHub リポジトリで GitHub Actions が起動するはずです。起動の様子はリポジトリ内の "Actions" メニューから確認できます(画面は Actions が実行中の様子):
2022060906


実行が(成功か失敗かで)完了すると、その結果が表示されます(この例では緑マークが付いているので成功しています。失敗は赤):
2022060907


成功・失敗に関係なく、Actions 名部分をクリックすると、Actions の実行ログを見ることができます。特に失敗した場合などはこのログが原因を調べるヒントになっている可能性が高いので、失敗に終わった場合はまずログを参照することになると思います:
2022060908


GitHub Actions が成功していた場合、更新されたアプリケーションが指定 URL で稼働できているはずです。実際にアクセスして動作確認してみましょう:
2022060900


以上、GitHub Actions を使って dokku にアプリケーションを自動デプロイするための設定を紹介しました。dokku は専用のリポジトリに git push するだけでもデプロイが出来て便利ですが、一度 CI/CD の便利さを知ってしまうと「わざわざデプロイする手間が面倒」に感じられてしまうほど便利なので、今後 dokku を使って動かすアプリについては全てこの設定を有効にしてもいいかな、と感じています。


 

前回dokku を使ったプライベート PaaS 環境の構築、およびシンプルなアプリケーションのデプロイ手順を紹介しました。 今回はより実践的なアプリケーションとして PostgreSQL データベースを併用するアプリケーションのデプロイ手順を紹介します(といっても、実は heroku を CLI で操作する時の手順とあまり変わりません・・)。

なお今回紹介する内容は、前回のセットアップ時に "withcorona.world" という独自ドメインを設定している想定で紹介しています。異なるドメインで設定されている場合は自分で設定したドメインに適宜読み替えてください。


【dokku 内で PostgreSQL データベースを動かす】
まず dokku 環境内にデータベースサーバーを用意します。今回は PostgreSQL を使うケースを想定して以下で紹介します。まずは dokku サーバーにログインしておきます。

dokku ではいくつかのサービスが「プラグイン」という形で連携できるよう用意されています。PostgreSQL もその1つです。というわけで、まずは dokku にログインして PostgreSQL プラグインをインストールします:
# dokku plugin:install https://github.com/dokku/dokku-postgres.git

インストールが完了すると PostgreSQL データベースをインスタンス化することができるようになります。例えば "mydb" という名前を付けて1インスタンス作るには以下のように入力します:
# dokku postgres:create mydb

作成後に作ったデータベースインスタンスの情報を確認する場合は以下のように入力します:
# dokku postgres:info mydb

=====> mydb postgres service information
       Config dir:          /var/lib/dokku/services/postgres/mydb/data
       Config options:
       Data dir:            /var/lib/dokku/services/postgres/mydb/data
       Dsn:                 postgres://postgres:XXXXXXXX@dokku-postgres-mydb:5432/mydb
       Exposed ports:       -
       Id:                  a017a6896694987cb0e729b4ec1042f831eecd0d8f726d52eeea435ecd9fcf4e
       Internal ip:         172.17.0.3
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/mydb
       Status:              running
       Version:             postgres:14.2

この確認結果の Dsn 値として紹介されている "postgres://" で始まる文字列がいわゆる接続文字列になっていて、(後述する)環境変数の値になります。 このインスタンスのシェルに入って PostgreSQL の CLI を使ってテーブルを1つ定義しておきたいので、以下のように実行してください(データベースに接続する時は接続文字列の "dokku-postgres-mydb" 部分を "localhost" に変えて実行してください):
# dokku postgres:enter mydb (シェルにログイン)

/# psql "postgres://postgres:XXXXXXXX@localhost:5432/mydb" (psql でデータベースに接続)

mydb=# create table if not exists items ( id varchar(50) not null primary key, name varchar(50) default '', price int default 0, created bigint default 0, updated bigint default 0 ); (SQL で items テーブル作成)

mydb=# \q (データベースから切断)

/# exit (シェルからログアウト)

これで dokku 環境内に mydb という名前の PostgreSQL データベースを1つ作り、items という名前のテーブルを1つ定義する所まで用意できました。続いて、この mydb データベースと items テーブルを使ったウェブアプリケーションを dokku 内で動かします。


【dokku 内で PostgreSQL データベースに接続するアプリケーションを動かす】
dokku 内で PostgreSQL データベースを使うアプリケーションを動かします。今回は以下のサンプルを使います(上記で作成した items テーブルを使うアプリケーションです):
https://github.com/dotnsf/cnapp_postgresql


このアプリケーションの PostgreSQL と接続する部分は以下のように記述されています:
  :
  :
var database_url = 'DATABASE_URL' in process.env ? process.env.DATABASE_URL : settings.database_url; 
var pg = null;
if( database_url ){
  console.log( 'database_url = ' + database_url );
  pg = new PG.Pool({
    connectionString: database_url,
    idleTimeoutMillis: ( 3 * 86400 * 1000 )
  });
  :
  :


具体的な挙動としては、アプリケーション実行時の "DATABASE_URL" という環境変数値を参照し、値が設定されていたらその内容を接続文字列とみなして PostgreSQL サーバーに接続する、という実装内容になっています(説明は省略しますが、接続後に items テーブルを読み書きする内容になっています)。

なので、このアプリケーションが dokku 内で実行される時に、先ほど作成した mydb データベースへの接続文字列が環境変数 DATABASE_URL として定義されていればこのアプリケーションは正しくデータベースに接続して動く、ということになります。

この辺りは heroku ユーザーであればなんとなく「同じだ・・」とわかると思います。で、その環境変数を設定するためには dokku 内のアプリケーションとデータベースがリンクさえされていれば実現できるようになっています(この辺りはクラウドネイティブアプリケーションを開発する際の 12 factors と呼ばれるベストプラクティスに沿った仕様となっています)。

というわけで、まずは dokku にアプリケーションを追加し、データベースとのリンクを設定します。今回は "cnapp" という名前のアプリケーションを作ることにして、この "cnapp" アプリケーションと "mydb" データベースをリンクしておきます(これで cnapp アプリの実行時にデータベース mydb に接続するための接続文字列が環境変数 DATABASE_URL にセットされて起動します):
# dokku apps:create cnapp

# dokku postgres:link mydb cnapp

そして前回同様にこのサンプルアプリを Git clone して、リモート接続先に dokku を追加して、main ブランチを push します:
# git clone https://github.com/dotnsf/cnapp_postgresql

# cd cnapp_postgresql

# git remote add dokku dokku@withcorona.world:cnapp

# git push dokku main

ここまでのコマンドが正しく実行されていると http://cnapp.withcorona.world/ でアクセスできるようになります※:

2022060101


※稀にこの URL では想定していないページ(Nginx のデフォルトページなど)が表示されることがあります。その場合は http://cnapp.withcorona:8080/ のようにポート番号をつけてアクセスするとうまくいきます。その後に以下のコマンドを実行するとポート番号指定なしでも正しく表示できるようになります:
# dokku proxy:ports-add cnapp http:80:8080


これだけでも一応動きますが、ついでに(?) https 接続できるよう、Let's Encrypt プラグインの設定も行っておきます:
# dokku letsencrypt:enable cnapp

最後にウェブブラウザで https://cnapp.withcorona.world/ にアクセスして動作確認します:
2022060102


最初は何も登録されていませんが、名前(name)と価格(price)を入力して追加(Create)すると、そのデータが( PostgreSQL の)mydb データベースの items テーブルに登録され、一覧として表示されるようになります:
2022060103


以上、dokku でデータベース連携アプリケーションを作って動かすための設定でした。PostgreSQL 以外にも dokku には公式機能として MySQL や Redis 、ElasticSearch といったプラグインが用意されているので、クラウドで認証した結果をセッション共有するようなアプリケーションでも動かすことができると思います。




ある程度 heroku を使ったことがある人であれば、dokku は文字通りに heroku ライクなプライベート環境に感じることができると思います(ただ dokku だとほとんどの作業が CLI からのコマンドになる点が、ウェブ GUI で色々用意されている heroku とは異なる点です)。また Cloud Foundry と比較しても、Cloud Foundry では
$ cf push (app)

のようにしてアプリをデプロイしていましたが、dokku はほぼ同様にして、
$ git remote add dokku (app) (を一度実行してから)
$ git push dokku main

といった形でアプリのデプロイができるので、Cloud Foundry の代わりとしても使いやすい環境のように感じています。今回紹介した withcorona.world というドメインは実験用の捨てドメインなのでおそらくこの紹介記事でしか使うことはないと思っていますが、他の取得ドメイン(とちょっと規模の大きめな IaaS 環境)を使って自分のプライベート Cloud Foundry 環境を作って運用してみるつもりでいます。



唐突ですが、自分も使っている IBM Cloud の PaaS 機能の1つである Cloud Foundry ランタイムのサービス終了がアナウンスされました:
Cloud Foundry on IBM Cloud サービス提供終了のお知らせ


個人的にもサービス開始とほぼ同時期から使っていたユーザーとして、またソースコードから一発でクラウド環境で動かすことができる環境として使っていただけに、とても残念なニュースでした。実は少し前から知ってはいたのですが、公開できるのが今日からということで公にできずに悶々としていました(代わりにこのブログの公開準備を進めていました)。

で、IBM Cloud として推奨している移行先は Kubernetes 系サービスや Code Engine とされています:
IBM Cloud FoundryからCode Engineへのマイグレーションに関するベスト・プラクティスの紹介:サービス・バインディングとコード


Code Engine は Kubernetes の K-native をベースとしたコンテナ・ランタイム環境です。無料で使用可能なリソース枠も用意され、これまで Cloud Foundry で動いていたアプリケーションを比較的容易に移行できる環境となっております。


ただ、私自身はこの Code Engine に加えて、以下で紹介する dokku 環境も Cloud Foundry からの移行先としてアリだと思っています。Cloud Foundry よりも heroku と比較されることが多く、また残念ながら無料で運用できるわけではない(プライベート環境なので、そのサーバーリソースが必要)のですが、一方で独自ドメインが使える上にコンテナイメージを意識することなくソースコードから稼働環境を簡単に作れる、という点で相性は悪くないと思っています。 そんな意味も含めて、このタイミングで紹介させていただくことにしました。

予定としては2回に分けて、前半である今回はセットアップ部分を中心に、次回の後半でデータベースなど外部リソースとの連携について触れるつもりでいます。





昨年あたりから heroku を使うことが多くなってきました。無料でもある程度利用できるクラウドリソースが PaaS で提供され、Git と連動してアプリケーションのデプロイができるのが非常に便利です。

とても便利なので利用頻度が高くなっていき、あっという間に無料枠の限界が近づき・・・そして同時に無料枠の制約(インスタンスが使われていないと自動的に止まっちゃうとか、複数インスタンスで運用できないとか)を超えた使い方にも興味が出てきます。そうなってくるとパブリックな heroku 利用もいいけど、プライベートな heroku 環境を自由に使えたらいいなあ、というエンジニア欲も出てきます。

そんな背景もあって、「プライベート版 heroku 」という側面もある dokku を使ってみることにしました。dokku は内部的に docker を使って1台のサーバー内に仮想的な PaaS 環境を構築するものです。heroku (や Cloud Foundry )同様にビルドパックを使った git push デプロイが可能なので、手元のソースコードを簡単に(Dockerfile とか docker イメージ化などを意識せずに)ウェブ上に公開することもできます。1台のサーバーで運用することを想定しているため可用性という面では足りないと感じる面があるかもしれませんが、自分のように作ったアプリを試験的に公開する、という機会が多い場合に非常に重宝します。またプライベート PaaS はインフラ部分の管理を自分で行うことを意味していますが、その点では1台のサーバーの面倒だけみればよい、というのはある意味でアドバンテージにもなり得るものと考えています。

今回は以下の条件で環境を構築してみました:
 ・(2022/06/01 時点で最新の)dokku v0.27.5 を使用する
 ・IBM Cloud 上に Ubuntu サーバーを1台用意して、この中に dokku 環境を導入する
 ・GoDaddy.com で取得した独自ドメイン(withcorona.world)を使った PaaS 環境を作る

IBM Cloud 上に IaaS サーバー(Ubuntu 18.04)を用意するので、このサーバー料金が必要です。IBM Cloud である必要はありませんが、後述のように DNS の設定ができる IaaS 環境が必要です(Vultr.com では同様の設定ができることを確認しています)。なお、dokku は独自ドメインを使わなくても、sslip.io サービスを併用した疑似サブドメインを使って環境構築することもできますが、今回の紹介内容では軽く触れる程度とし、動作確認などは除外させていただきます。


【dokku 環境構築】
では早速 dokku 環境を用意して、アプリケーションを dokku 上で動かしてみます。まずは1度行う必要のある環境構築の手順を紹介します。

最初にクラウド上に Ubuntu サーバーを用意します。今回利用する dokku v0.27.5 では Ubuntu 18.04, Ubuntu 20.04, Ubuntu 22.04 までがサポート対象となっていましたが、古い記事で Ubuntu 18.04 だけがサポートされていたドキュメントを参照していたこともあり、自分も Ubuntu 18.04 を使うことにしました。なお Debian 系はサポート対象ですが、RHEL/CentOS 系は 2022/06/01 時点では Experimental 機能としての提供です。

(自分の場合は)IBM Cloud 上に Ubuntu 18.04 サーバーを1台用意します。スペックは 1 vCPU で 2GB RAM のものとしましたが、ここで選ぶスペックが自分の dokku 環境となるので、比較的多くのアプリケーションを動かす場合や、(多くの DB など)多くのリソースを使うことが想定される場合は少し大きめのサーバーを用意してください:
2022060101


サーバーが用意できたら次はネームサーバーをはじめとする DNS の設定が必要です(独自ドメインを使わない場合はここを無視して dokku のインストール作業まで進んでください)。まずは自分が使うサーバー(今回だと IBM Cloud のサーバー)で DNS を設定するために必要なネームサーバー設定を確認します。IBM Cloud の場合は以下のように
 ・プライマリサーバー: ns1.softlayer.com
 ・セカンダリサーバー: ns2.softlayer.com
を設定するように指定されていることが分かります。ここは皆さんが用意したクラウドサーバーのプロバイダーによって異なるので、自分の環境のネームサーバー設定を調べる必要があります:
2022060102


このネームサーバー設定を自分が取得した独自ドメインに適用します。今回の例では GoDaddy.com で取得した独自ドメインを使うので、GoDaddy.com の DNS 設定を変更することになります。 なお今回は "withcorona.world" という独自ドメインを使って、app1.withcorona.world, app2.withcorona.world, ... といった名称のアプリケーションを運用する前提とします。まずは自分がドメインを取得したベンダーのネームサーバー設定画面(DNS 設定画面)に移動します:
2022060103


ここでネームサーバーを変更します。GoDaddy.com の場合は DNS 管理画面の少し下に設定済みのネームサーバーが表示されている画面があるので、ここの「変更」ボタンをクリックします:
2022060104


そして先ほど確認したプライマリ/セカンダリサーバーを指定します。IBM Cloud の場合はプライマリが ns1.softlayer.com 、セカンダリが ns2.softlayer.com だったので、以下のように入力し、最後に「保存」ボタンをクリックします:
2022060105


この作業はこれまで使っていた独自ドメインの DNS 設定を大きく変えることになるので警告メッセージが表示されることがあります。内容を確認して「続行」します:
2022060106


無事に設定が変更されていることを確認します(この変更内容が実際に有効になるまで1時間程度かかることがあります):
2022060107


ネームサーバーの設定変更が出来たら、次は DNS を dokku 向けのものに変更します。新しい DNS 設定画面(今回の例では IBM Cloud の DNS 設定画面)に移動し、まずメインサーバーとなる独自ドメイン名(今回の例では "withcorona.world")と、 Ubuntu サーバーの IP アドレスを入力してドメインを登録します:
2022060108



そして残りの設定を行います。dokku を独自ドメインで利用するには、以下の内容を設定する必要があります:
レコードターゲット
A@(サーバーの IP アドレス)
CNAME*(独自ドメイン名)


なお IBM Cloud の場合は上述の設定ではなく、以下の設定が必要でした(* は CNAME レコードではなく A レコードとして、ターゲットは独自ドメイン名ではなく IP アドレスで指定する必要がありました):
レコードターゲット
A@(サーバーの IP アドレス)
A*(サーバーの IP アドレス)


最終的にこのような DNS 設定となりました:
2022060109


ここまでの作業で dokku 導入前の事前準備が完了です。ここからは dokku のインストール作業を紹介します。


まず SSH 等で Ubuntu サーバーのシェルにログインします。root 以外でログインした場合は "sudo -i" を実行するなどして root に切り替え、"apt update" と "apt upgrade" を済ませておきます:
$ sudo -i

# apt update -y

# apt upgrade -y

以下のコマンドを実行して dokku を(dokku v0.27.5 を)インストールします:
# wget https://raw.githubusercontent.com/dokku/dokku/v0.27.5/bootstrap.sh;

# DOKKU_TAG=v0.27.5 bash bootstrap.sh

2つ目のコマンドが完了(5~10分くらい)すると(docker ごと)dokku が導入されています。

独自ドメインを利用する場合はそのドメインを登録するため、以下のコマンドを実行します(最後の withcorona.world 部分に独自ドメイン名を指定します):
# dokku domains:set-global withcorona.world

このコマンド実行後に、/home/dokku/VHOST ファイルの中身が指定した独自ドメインになっていることを確認してください:
# cat /home/dokku/VHOST

withcorona.world (と表示されることを確認)

また独自ドメインを所有していない(使わない)場合は以下のコマンドを実行して、sslip.io サービスを使った疑似サブドメインを登録します(最後の 11.22.33.44 部分に Ubuntu サーバーの IP アドレスを指定します):
# dokku domains:set-global 11.22.33.44

# dokku domains:set-global 11.22.33.44.sslip.io


次に、実際に dokku を使う前に(dokku の git 利用時に必要な)秘密鍵と公開鍵のペアを登録する必要があります。普段使っている秘密鍵&公開鍵があればそれを使っても構いませんし、今回の作業のために新たに1ペア作って使っても構いません。鍵ファイルの作り方はこちらなどを参照してください。ここでは秘密鍵: id_rsa 、公開鍵: id_rsa.pub という2つの鍵ファイルが手元にあるものとします。

これらを dokku のサーバー環境に登録します。まずは sftp などでこれら2つのファイルを Ubuntu サーバーの /root/.ssh/id_rsa および /root/.ssh/id_rsa.pub となるよう転送しておきます。ここまでの作業ができているものとして以下の説明を続けます。

まず鍵ファイルはファイルパーミッションが正しくないと正しい挙動になりません。これら2つのファイルのパーミッションを 400 にしておきます:
# chmod 400 /root/.ssh/id_rsa*

これら2つのファイルを dokku 環境に登録します。まずは以下のコマンドを実行して秘密鍵を登録します:
# eval `ssh-agent`

# ssh-add -k ~/.ssh/id_rsa (秘密鍵のパスフレーズ入力を求められるので正しく入力します)

続けて公開鍵も登録します:
# cat ~/.ssh/id_rsa.pub | dokku ssh-keys:add admin

dokku 作業としてはここまででほぼ完了しているのですが、ついでに SSL(https) 接続を想定した準備もしておきましょう。以下の2つのコマンドで Let's Encrypt プラグインを導入・設定しておきます:
# dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

# dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=(自分のメールアドレス)

実際にアプリケーションをデプロイする前の、dokku 環境構築に必要な(1回だけの)作業は以上で終わりです。


【dokku でウェブアプリを動かす】
では構築した dokku 環境を使って実際にウェブアプリケーションを稼働させてみます。ここからの内容は dokku に新しいアプリケーションをデプロイするたびに必要な作業です(ここよりも上で紹介した作業は環境構築時に1回行うだけ)。

まずはウェブアプリケーション(のソースコード)が必要ですが、今回は自分が作ったシンプルな「ハローワールド」アプリであるこれを使って紹介することにします(自分で作ったウェブアプリがある場合はそちらを使っていただいても構いません):
https://github.com/dotnsf/simpleweb


このサンプルはアプリというほどの内容ではないのですが、起動してアクセスすると以下のような画面が表示される、というものです。GitHub ページでも公開しているので、実際のサンプルを見たい場合はこちらにアクセスしてください:
https://dotnsf.github.io/simpleweb/

2022060112
(機能はこれだけ)


過去に heroku や Cloud Foundry、Docker、Kubernetes などのコンテナ環境でクラウドネイティブなアプリを作ったことがある人であれば問題ないと思いますが、ウェブアプリケーション起動時のポート番号を環境変数 PORT から取得するようにしている点にご注意ください(以下はこの simpleweb アプリの app.js のソースコード):
//. app.js
var express = require( 'express' ),
    app = express();

app.use( express.static( __dirname + '/web' ) );

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

では改めてこのコードを例にして dokku 環境で動かすまでの手順を紹介します。まずは "dokku apps:create" コマンドで新しいアプリケーション(今回はアプリケーション名を simpleweb としています)を作成します:
# dokku apps:create simpleweb

次に git clone でソースコードを入手して、ディレクトリ内に移動します:
# git clone https://github.com/dotnsf/simpleweb

# cd simpleweb

(heroku と同様ですが)このソースコードに新しいリモート Git オリジン(dokku)として、dokku 内の Git リポジトリを追加します:
# git remote add dokku dokku@withcorona.world:simpleweb

そして今追加したオリジン dokku に main ブランチを git push します:
# git push dokku main

(秘密鍵のパスフレーズを聞かれるので入力する)

秘密鍵のパスフレーズを聞かれるので入力すると、GitHub ではなく dokku の内部ソースコードリポジトリにコードが Push され、該当ソースコード向けのビルドパック(今回の例であれば Node.js ビルドパック)を使ってソースコードが dokku 内のコンテナとしてデプロイされて起動します(1分くらいかかります)。この辺りの一連の流れは Cloud Foundry のものに近いです。


無事にデプロイが完了すると、http://(アプリ名).(ドメイン名)/ という URL でパブリックアクセスできるようになります。今回の例であれば http://simpleweb.withcorona.world/ です(この時点ではまだ https ではアクセスできません)※。 なおドメイン名を使わない場合は http://(アプリ名).xx.xx.xx.xx.sslip.io/ でアクセスできます(xx.xx.xx.xx は Ubuntu サーバーの IP アドレス):
2022060110


※稀にこの URL では想定していないページ(Nginx のデフォルトページなど)が表示されることがあります(そうなったりならなかったりします・・・)。Nginx のデフォルトページが表示されてしまう場合は http://(アプリ名).(ドメイン名):8080/ のようにポート番号をつけてアクセスするとうまくいきます。その後に以下のコマンドを実行するとポート番号指定なしでも正しく表示できるようになります:
# dokku proxy:ports-add simpleweb http:80:8080



https でアクセスできるようにするにはもう少しコマンドが必要です。単に https でアクセスできるようにするには(Let's Encrypt で証明書を取得して適用するだけであれば)以下の dokku コマンドを入力するだけです:
# dokku letsencrypt:enable simpleweb

更に証明書の自動更新までを有効にする場合は、続けて以下のコマンドを実行します(無効にする場合は "add" を "remove" にします):
# dokku letsencrypt:cron-job --add

ここまで正しく完了すると SSL 証明書が発行&適用されて https://simpleweb.withcorona.world/ でもアクセスできるようになります(ドメインを使わない場合はこの作業を省略しても https アクセスできます):
2022060111


なお、この方法で dokku にデプロイされたアプリケーションは heroku の無料利用時のように(アクセスが一定時間以上なかった場合に)自動停止することはなく、また以下のコマンドでスケールアウトすることもできます(この例ではインスタンス数=3):
# dokku ps:scale simpleweb web=3

利用想定規模と環境構築先の Ubuntu サーバーの規模を合わせて構築することで、非常に有用なプライベート PaaS 環境になりうると思いました。


【まとめ】
今回紹介した dokku を使ったプライベート環境は(無料ではありませんが) heroku ユーザーにとってもメリットを感じられるものだと思います。

今回は dokku 環境の構築と、ランタイム部分(ウェブアプリケーション部分)を dokku 環境でデプロイするまでの手順を紹介しました。次回は(これも heroku での作業とほぼ一緒だったりしますが)PostgreSQL などのデータベースサービスを dokku 内に作ったり、データベースと組み合わせてウェブアプリケーションを動かす方法を紹介する予定です。


【参照】
今回は最小限のインストール手順やコマンドだけを紹介しましたが、詳しくは以下も参照ください:

dokku 公式インストール手順
dokku デプロイコマンド


(2022/06/04 追記)
後編はこちら
http://dotnsf.blog.jp/archives/1080505175.html
 

このページのトップヘ