あなたの最初のOpenRestyプログラム: Hello World
API7.ai
September 9, 2022
新しい開発言語を学び始める際、チュートリアルでは簡単な hello world
の例が提供されます。そこで、まずインストールをスキップして、OpenResty でこの例をどのように書くかを見てみましょう。
$ resty -e "ngx.say('hello world')"
hello world
これはおそらく最もシンプルな hello world コードでしょう。Python と似ていますね。
$ python -c 'print("hello world")'
hello world
この背後には、OpenResty の哲学が表れています。コードは簡潔であるべきで、「入門から挫折まで」という考えを捨てられるようにするべきです。この記事では、hello world の例に焦点を当てます。
OpenResty と NGINX の違いの記事で述べたように、OpenResty は NGINX
をベースにしています。そのため、ここで NGINX の影が見えないのはなぜかと疑問に思うかもしれません。心配ありません。1行のコードを追加して、resty の背後で何が動いているのかを見てみましょう。
$ resty -e "ngx.say('hello world'); ngx.sleep(10)" &
ngx.sleep メソッドを追加したので、文字列 hello world
を出力した後にプログラムが終了しなくなります。これにより、次のように確認できます。
$ ps -ef | grep nginx
root 15944 6380 0 13:59 pts/6 00:00:00 grep --color=auto nginx
ついに NGINX プロセスが現れました!どうやら resty
コマンドは本質的に NGINX サービスを起動しているようです。では、resty
とは何でしょうか?
あなたのマシンには OpenResty がインストールされていないかもしれません。そこで、最初にスキップしたインストール手順に戻り、OpenResty をインストールしてから続けましょう。
インストール
他のオープンソースソフトウェアと同様に、OpenResty はさまざまな方法でインストールできます。例えば、OS のパッケージマネージャーを使う、ソースコードからコンパイルする、Docker イメージを使うなどです。しかし、まずは yum
、apt-get
、brew
などのパッケージマネージャーを使って OpenResty をインストールすることをお勧めします。この記事では、macOS を例にします。
$ brew tap openresty/brewbrew install openresty
他の OS でも同様です。まず、OpenResty のリポジトリ URL をパッケージマネージャーに追加し、その後パッケージマネージャーを使って OpenResty をインストールします。詳細な手順は、公式ドキュメントを参照してください。
しかし、この一見シンプルなインストールの背後には、2つの問題があります。
- なぜソースコードからインストールすることを勧めないのか?
- なぜ OS の公式リポジトリから直接インストールできず、別のリポジトリを設定する必要があるのか?
これらの質問についてまず考えてみてください。
ここで一つ追加したいことがあります。このコースでは、表面的なものの背後にある多くの「なぜ」を取り上げます。新しいことを学びながら考えることを望んでいます。結果が正しいかどうかは重要ではありません。残念ながら、技術分野でも独立した思考は希少です。各人の技術分野や深さの違いにより、どのコースでも教師は個人的な意見や知識の誤りを持ちます。学習プロセスでいくつかの「なぜ」を問い、それを理解することで、徐々に自分の技術体系を形成できます。
多くのエンジニアはソースコードからビルドすることを楽しんでいます。私も何年も前はそうでした。しかし、オープンソースプロジェクトを使う際、私は常に手動で configure
や make
を行い、いくつかのコンパイルパラメータを変更したいと思っていました。これがこのマシンの環境に最適で、性能を最大限に引き出す最良の方法だと感じていました。
しかし、現実はそうではありません。毎回ソースコードをコンパイルする際に奇妙な環境問題に遭遇し、つまずきながらインストールするしかありませんでした。今では、私たちの本来の目的はオープンソースプロジェクトを使ってビジネスニーズを解決することであり、環境との戦いに時間を浪費すべきではないと理解しています。パッケージマネージャーやコンテナ技術は、まさにこれらの問題を解決するために存在します。
本題に戻りましょう。OpenResty をソースコードからインストールする場合、手順が煩雑で、PCRE
や OpenSSL
などの外部依存関係を解決する必要があります。さらに、対応するバージョンの OpenSSL に手動でパッチを当てる必要があります。そうしないと、SSL セッション
を扱う際に機能が不足します。例えば、yield
を引き起こす ngx.sleep のような Lua API が使えなくなります。この部分について詳しく知りたい場合は、公式ドキュメントを参照してください。
OpenResty はこれらのパッチを OpenSSL パッケージスクリプトで自ら管理しています。OpenResty が OpenSSL
のバージョンをアップグレードする際には、対応するパッチを再生成し、完全な回帰テストを行う必要があります。
Source0: https://www.openssl.org/source/openssl-%{version}.tar.gz
Patch0: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0d-sess_set_get_cb_yield.patch
Patch1: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0j-parallel_build_fix.patch
同時に、CentOS での OpenResty の パッケージスクリプトを見て、他の隠れたポイントがあるかどうか確認できます。
BuildRequires: perl-File-Temp
BuildRequires: gcc, make, perl, systemtap-sdt-devel
BuildRequires: openresty-zlib-devel >= 1.2.11-3
BuildRequires: openresty-openssl-devel >= 1.1.0h-1
BuildRequires: openresty-pcre-devel >= 8.42-1
Requires: openresty-zlib >= 1.2.11-3
Requires: openresty-openssl >= 1.1.0h-1
Requires: openresty-pcre >= 8.42-1
ここでわかるように、OpenResty は独自のバージョンの OpenSSL
と zlib
、PCRE
を管理しています。ただし、後者の2つはコンパイルパラメータを調整しており、パッチは保持していません。
これらの要素を考慮すると、詳細を知らない限り、ソースコードから OpenResty をコンパイルすることはお勧めしません。
ソースインストールが勧められない理由は明らかでしょう。最初の質問に答える際に、2番目の質問にも答えました。なぜ OS の公式パッケージリポジトリから直接インストールできず、別のリポジトリを設定する必要があるのか?
これは、公式リポジトリがサードパーティが管理する OpenSSL
、PCRE
、zlib
パッケージを受け入れたくないためです。他のユーザーがどれを選ぶべきか混乱を招くのを防ぐためです。一方、OpenResty は正常に動作するために特定のバージョンの OpenSSL
と PCRE
ライブラリを必要とし、システムのデフォルトバージョンは比較的古いものです。
OpenResty CLI
OpenResty をインストールすると、OpenResty CLI resty
がデフォルトでインストールされます。これは Perl
スクリプトであり、前述の通り、OpenResty のエコシステムツールはすべて Perl
で書かれています。これは OpenResty の作者の技術的嗜好によるものです。
$ which resty
/usr/local/bin/resty
$ head -n 1 /usr/local/bin/resty
#!/usr/bin/env perl
resty CLI は非常に強力で、resty -h
を使うか、公式ドキュメントを読むことで完全な機能リストを確認できます。次に、2つの興味深い機能を紹介します。
$ resty --shdict='dogs 1m' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'
56
上記の例は、Lua
コードを含む Nginx
設定を示しています。これは、共有メモリ辞書の設定とクエリを実現しています。dogs 1m
は、dogs
という名前の共有メモリスペースを 1m
のサイズで宣言する Nginx
設定です。この共有メモリは、Lua コード内で辞書として使用されます。
また、--http-include
と --main-include
パラメータは NGINX
設定ファイルを設定するために使用されるため、上記の例を次のように書き換えることができます。
$ resty --http-conf 'lua_shared_dict dogs 1m;' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'
OpenResty の世界での標準的なデバッグツール、例えば gdb
、valgrind
、sysetmtap
、Mozilla rr
も、resty と一緒に使用できます。これらは通常の開発とテストを容易にするため、resty
の異なるコマンドに対応しています。内部実装は非常にシンプルで、コマンドライン呼び出しの追加レイヤーに過ぎません。valgrind
を例に挙げましょう。
$ resty --valgrind -e "ngx.say('hello world'); "
ERROR: failed to run command "valgrind /usr/local/openresty/nginx/sbin/nginx -p /tmp/resty_rJeOWaYGIY/ -c conf/nginx.conf": No such file or directory
これらは OpenResty の世界だけでなく、サーバーサイドの一般的なツールでもあります。そのため、段階的に学んでいきましょう。
より正式な「hello world」
最初に書いた OpenResty プログラムは、resty
コマンドを使って master
プロセスなしで、特定のポートをリッスンせずに実行しました。次に、別の hello world
プログラムを実装してみましょう。
これを完了するには、少なくとも3つのステップが必要です。
- 作業ディレクトリを作成する。
NGINX
設定ファイルを修正し、Lua
コードを埋め込む。OpenResty
サービスを起動する。
まず、作業ディレクトリを作成しましょう。
$ mkdir openresty-sample
$ cd openresty-sample
$ mkdir logs/ conf/
以下は、OpenResty の content_by_lua
ディレクティブを含む最小限の nginx.conf
です。これにより、ngx.say メソッドが埋め込まれます。
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
content_by_lua '
ngx.say("hello, world")
';
}
}
}
まず、openresty が PATH
環境変数に追加されていることを確認してください。その後、OpenResty サービスを起動します。
$ openresty -p `pwd` -c conf/nginx.conf
エラーが発生しなければ、OpenResty サービスは正常に起動しています。cURL コマンドを使ってアクセスし、返される結果を確認できます。
$ curl -i 127.0.0.1:8080
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
hello, world
おめでとうございます!OpenResty での正式な Hello World
が完成しました!
まとめ
今日学んだことを振り返りましょう。まず、OpenResty のインストールと CLI を「hello, world」の簡単なコードから始め、最後に OpenResty プロセスを起動し、実際のバックエンドプログラムを実行しました。
その中で、resty は今後頻繁に使用するコマンドラインツールです。そのため、このコースのデモコードは、バックグラウンドで OpenResty サービスを起動するのではなく、resty を使って実行されます。
さらに重要なのは、OpenResty の背後には多くの文化的・技術的な詳細が隠れており、海に浮かぶ氷山のようです。このコースを通じて、表面的な API だけでなく、より包括的な OpenResty を紹介できればと思います。