TL;DR
- CentOS上で、mod_jkを使ってApache、Tomcatを連携させる
- mod_jkのビルドには
apxs
が必要 - CentOSの場合、apxsは
httpd-devel
でインストールできる - mod_jkは共有メモリを使うので、SELinuxに阻まれることがあるので注意
というわけで、この記事ではCentOS上にインストールしたApache、Tomcatをmod_jkを使って連携させてみます。
mod_jk
mod_jkとは、Tomcatプロジェクトが開発している、Webサーバーとの接続プラグインのひとつです。
The Apache Tomcat Connectors: mod_jk, ISAPI redirector, NSAPI redirector
Configuring mod_jk for the Apache HTTP Server
mod_jkはApacheをターゲットとしており、他にはIIS、iPlanet Web Server用のプラグインもあるようです。
Tomcatとの通信は、AJP(Apache JServ Protocol)というプロトコルを使用します。
環境
今回の環境は、こちら。
$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
$ java --version
openjdk 11.0.6 2020-01-14 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.6+10-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.6+10-LTS, mixed mode, sharing)
CentOS 7.8、OpenJDK 11です。
Apacheは2.4.6、Tomcatは9.0.34、mod_jkは1.2.48を使用します。
Tomcatをインストールする
それでは、まずはバックエンドになるTomcatをインストールしましょう。今回は、Tomcat 9.0.34を使用します。
$ curl -OL https://downloads.apache.org/tomcat/tomcat-9/v9.0.34/bin/apache-tomcat-9.0.34.tar.gz
$ tar xf apache-tomcat-9.0.34.tar.gz
$ cd apache-tomcat-9.0.34
AJPのConnectorの設定をしておきます。
conf/server.xml
のAJP Connectorのコメントアウトを単純に解除すると、以下のようになるのですが
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector protocol="AJP/1.3"
address="::1"
port="8009"
redirectPort="8443" />
さらにsecretRequired
をfalse
に設定します。
<Connector protocol="AJP/1.3"
address="::1"
port="8009"
redirectPort="8443"
secretRequired="false" />
でないと、AJP Connectorの起動に失敗します。
29-Apr-2020 07:43:56.765 重大 [main] org.apache.catalina.util.LifecycleBase.handleSubClassException コンポーネント[Connector[AJP/1.3-8009]]の開始に失敗しました。
org.apache.catalina.LifecycleException: プロトコルハンドラの起動に失敗しました
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1066)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:438)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.startup.Catalina.start(Catalina.java:633)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:474)
Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.
at org.apache.coyote.ajp.AbstractAjpProtocol.start(AbstractAjpProtocol.java:264)
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1063)
... 12 more
これは、AJPがTomcatの内部データ構造を操作できるため、セキュリティ的な対策を入れるためのもののようです。
起動できるようにするにはsecret
を設定するか、secretRequired
をfalse
にする必要があるようです。今回は、secretRequired
をfalse
にしました。
要するに、緩く設定しました、と。
では、動作確認のために適当にコンテンツを作りましょう。
$ mkdir webapps/sample
$ echo 'Hello Tomcat!!' > webapps/sample/index.jsp
起動。
$ bin/startup.sh
確認。ここで使っているのは、HTTPのConnectorですが。
$ curl localhost:8080/sample/index.jsp
Hello Tomcat!!
これで、Tomcatの準備はOKです。
Apacheをインストールする
次は、Apacheをインストールします。こちらは、yum
で簡単に。
$ sudo yum install httpd
起動。
$ sudo systemctl start httpd
Apache 2.4.6がインストールされました。
$ httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built: Apr 2 2020 13:13:23
とりあえず、起動していることは確認。
$ curl -I localhost
HTTP/1.1 403 Forbidden
Date: Wed, 29 Apr 2020 05:18:36 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 16 Oct 2014 13:20:58 GMT
ETag: "1321-5058a1e728280"
Accept-Ranges: bytes
Content-Length: 4897
Content-Type: text/html; charset=UTF-8
mod_jkをインストールする
mod_jkをインストールしましょう。
$ curl -OL https://downloads.apache.org/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz
$ tar xf tomcat-connectors-1.2.48-src.tar.gz
$ cd tomcat-connectors-1.2.48-src
こんな感じに展開されるので
$ ls -l
合計 32
-rw-r--r--. 1 user user 7274 2月 20 16:43 HOWTO-RELEASE.txt
-rw-r--r--. 1 user user 13597 2月 20 16:43 LICENSE
-rw-r--r--. 1 user user 455 2月 20 16:43 NOTICE
-rw-r--r--. 1 user user 1238 2月 20 16:43 README.txt
drwxr-xr-x. 2 user user 84 2月 20 16:43 conf
drwxr-xr-x. 10 user user 157 2月 20 16:43 docs
drwxr-xr-x. 6 user user 123 2月 20 16:43 jkstatus
drwxr-xr-x. 8 user user 277 2月 20 16:43 native
drwxr-xr-x. 2 user user 238 2月 20 16:43 support
drwxr-xr-x. 4 user user 111 2月 20 16:43 tools
drwxr-xr-x. 9 user user 217 2月 20 16:43 xdocs
nativeディレクトリに移動。
$ cd native
Cコンパイラーは入った状態で、configureしてみます。
$ ./configure
すると、Webサーバーの指定がないと怒られます。
no apache given
no netscape given
configure: error: Cannot find the WebServer
ヘルプを見てみます。
$ ./configure --help
Shared Apacheモジュールとして作成するか、Static Apacheモジュールとして作成するかを選べるようです。
--with-apxs[=FILE] Build shared Apache module.
FILE is the optional pathname to the apxs tool;
defaults to finding apxs in your PATH.
--with-apache=DIR Build static Apache module. DIR is the pathname to
the Apache source directory.
今回は、Shared Apacheモジュールでいきましょう。
apxs
が必要になるということなので、httpd-develパッケージをインストールします。
$ sudo yum install httpd-devel
apxsがインストールされました。
$ which apxs
/usr/bin/apxs
というわけで、もう1度configure。
$ ./configure --with-apxs=`which apxs`
今度はうまくいくので、make、make install。
$ make && sudo make install
インストールされました。
$ ll /usr/lib64/httpd/modules/mod_jk.so
-rwxr-xr-x. 1 root root 1565880 4月 29 05:42 /usr/lib64/httpd/modules/mod_jk.so
/etc/httpd/modulesのシンボリックリンクにもなっています。
$ ls -l /etc/httpd/modules
lrwxrwxrwx. 1 root root 29 4月 29 05:15 /etc/httpd/modules -> ../../usr/lib64/httpd/modules
mod_jkを使って、ApacheとTomcatを連携させる
では、最後にApacheとTomcatを連携させてみましょう。
参考にするドキュメントは、以下あたりで。
Configuring mod_jk for the Apache HTTP Server
The Apache Tomcat Connectors - Common HowTo
今回は、Proxyモジュールあたりに、mod_jkモジュールの読み込みを追加。
/etc/httpd/conf.modules.d/00-proxy.conf
LoadModule jk_module modules/mod_jk.so
Worker(=Tomcat)の設定をしましょう。
/etc/httpd/conf.d/workers.properties
worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
単純にバックエンドのTomcatに転送するか、ロードバランシングもできるのですが、今回はシンプルにローカルのTomcatに転送するだけにしました。
mod_jkの設定。
/etc/httpd/conf.d/welcome.conf
JkWorkersFile /etc/httpd/conf.d/workers.properties
JkMount /* worker1
先ほど作成したWorkerの設定ファイルを指定し、リクエストを転送するパスとWorkerのマッピングを指定します。
で、Apacheを再起動すると…失敗します。
$ sudo systemctl restart httpd
Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details.
Apacheのエラーログを見ると、共有メモリを確保できないようです。
/var/log/httpd/error_log
[Wed Apr 29 05:51:44.727622 2020] [jk:emerg] [pid 27983] Initializing shm:/etc/httpd/logs/jk-runtime-status.27983 errno=13. Unable to start due to shared memory failure.
[Wed Apr 29 05:51:44.727631 2020] [jk:emerg] [pid 27983] Initializing shm:/etc/httpd/logs/jk-runtime-status.27983 errno=13. Unable to start due to shared memory failure.
これを単純に回避するには…SELinuxを無効にしますか。
$ sudo setenforce 0
今度は、再起動に成功します。
$ sudo systemctl restart httpd
確認。
$ curl localhost/sample/index.jsp
Hello Tomcat!!
これで、Apache+mod_jkから、AJPでTomcatと連携できましたね。