KUSANAGI Internals


KUSANAGIの中について

この記事は、KUSANAGI Advent Calender の22日目のエントリになります。
3日めには、はじめてのKUSANAGIということで、まったくもって初心者向けじゃないと大評判でした。ええはじめてとは言ったが初心者向けとは言ってないw
さて今回は、KUSANAGIで使用したり生成したりする設定ファイルを中心に、KUSANAGI内部の動作(の一部)について解説したいと思います。

KUSANAGIの設定ファイル

/etc/kusanagi

/etc/kusanagi は、KUSANAGIの仮想マシンデプロイ時に既に存在するファイルです。
以下のように、KUSANAGIのバージョンと、どのクラウドかという情報が記述されます。

KUSANAGI Version 8.0.2-1
aws

この情報は、kusanagi status で表示されます。

/etc/kusanagi.conf

kusanagiコマンドで使用するカレントプロファイルを設定するファイルです。
kusanagi targetで表示する プロファイル名が入ります。また、kusanagi target プロファイル名 を実行すると、このファイルが書き換えられます。
最初の kusanagi provision を行うまで空の文字列が設定されます。

PROFILE="kusanagi_html" 

/etc/kusanagi.d/profile.conf

kusanagi provision した際に入力した情報を格納するファイルになります。
kusanagi コマンドでは、この情報を元に処理を行います。

[kusanagi_html]
PROFILE="kusanagi_html"
KUSANAGI_TYPE="WordPress"
KUSANAGI_FQDN="test.example.com"
KUSANAGI_DIR="/home/kusanagi/kusanagi_html"
KUSANAGI_DBNAME="kusanagi"
KUSANAGI_DBUSER="kusanagi"
KUSANAGI_DBPASS="パスワード"
WPLANG="ja"
OPT_WOO=""
[LAMP]
PROFILE="LAMP"
KUSANAGI_TYPE="lamp"
KUSANAGI_FQDN="lamp.example.com"
KUSANAGI_DIR="/home/kusanagi/LAMP"
KUSANAGI_DBNAME="lamp"
KUSANAGI_DBUSER="lamp"
KUSANAGI_DBPASS="パスワード"
WPLANG=""
OPT_WOO="" 

/etc/kusanagi.d/ssl_sess_ticket.key

kusanagi init時に生成する、 TLSセッションチケットファイルです。
TLSセッションチケットとはTLSのセッション情報を暗号化してクライアント側に保存することで HTTPS通信時に行われるTLSハンドシェイクの手順を省略するしくみです。
これを採用すると、TLS接続時ののレイテンシを削減することができます。詳細は、https://techblog.yahoo.co.jp/infrastructure/ssl-session-resumption/ のTLS Session Ticket 拡張を参考にしてください。

/etc/kusanagi.d/ssl/dhparam.key

kusanagi init時に生成する、DH鍵交換に使用するパラメータファイルです。
KUSANAGIが生成するNGINXの設定では、DH鍵交換を含む暗号スイート(EECDH+CHACHA20、EECDH+CHACHA20-draft、EECDH+AESGCM、EDH+AESGCM、AES256+EECDH、AES256+EDH、ECDHE-RSA-AES256-GCM-SHA384 などなど)を含んでいます。この際、鍵交換に使用されるパラメータファイルを作成する必要があります。
この処理は、openssl dhparam 2048 -out /etc/kusanagi.d/ssl/dhparam.key として実行して、2048bitの暗号を生成するのでかなり時間がかかります。

NGINXの設定ファイル

NGINXの設定ファイルは、プロファイルごとにHTTP/HTTPS用の設定ファイルを用意し、VirtualHostで設定を行います。

/etc/nginx/nginx.conf

NGINXの共通設定となります。
このファイル中で、ログのフォーマット、gzip や brotli の圧縮設定、ファイル関係のチューニングパラメータを記述しています。

/etc/nginx/fastcgi_params

FastCGIのパラメータを記述しています。

/etc/nginx/conf.d/プロファイル_http.conf

HTTP接続で使用する設定ファイルです。
kusanagi provision 時に自動生成されます。この時、/usr/lib/kusanagi/resource/etc/nginx/conf.d/fqdn_http.conf* をテンプレートとしています。
この内容は、プロビジョンタイプによって異なります。

https redirect

kusanagi ssl –https redirect を実行すると、このファイル中の以下のコメントアウトを外します。
逆に、 kusanagi ssl –https noredirect では、コメントアウトします。

# rewrite ^(.*)$ https://test.example.com$request_uri permanent; # SSL ONLY 

/etc/nginx/conf.d/プロファイル_ssl.conf

HTTPS接続で使用する設定ファイルです。
kusanagi provision 時に自動生成されます。この時、/usr/lib/kusanagi/resource/etc/nginx/conf.d/fqdn_ssl.conf* をテンプレートとしています。

SSL証明書

SSL証明書および秘密鍵は、デフォルトでは以下のように自己証明SSL証明書が設定されています。

ssl_certificate /etc/pki/tls/certs/localhost.crt;
ssl_certificate_key /etc/pki/tls/private/localhost.key;

Let’s EncryptのSSL証明書を取得したときは、以下のように変更されます。

ssl_certificate      /etc/letsencrypt/live/test.example.com/fullchain.pem;
ssl_certificate_key  /etc/letsencrypt/live/test.example.com/privkey.pem;

kusanagi ssl –cert 証明書.pem –key 秘密鍵.pem を実行すると、以下のように変更されます。
この「証明書.pem 」は、中間証明書とサーバ証明書を一つのファイルに連結しておく必要があります。

ssl_certificate      /etc/kusanagi.d/ssl/test.example.com/証明書.pem;
ssl_certificate_key  /etc/kusanagi.d/ssl/test.example.com/秘密鍵.pem;

CT

CT(Cirtificate Transparency)の設定をonにする時、以下のコメントを外します。
off にするときは、再度以下の文をコメントアウトします。

#ssl_ct on;
#ssl_ct_static_scts /etc/letsencrypt/live/test001.myzkstr.tech/scts;

HSTS

HSTS(HTTP Strict Transport Security)の設定は、以下の文に対して書き換えを行います。off の状態は以下のようにコメントアウトされています。
kusanagi ssl –hsts weak を設定すると、下記のコメントアウトを外します。

#add_header Strict-Transport-Security "max-age=31536000";

kusanagi ssl –hsts mid の場合、以下のように書き換えます。

#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

kusanagi ssl –hsts high の場合、以下のように書き換えます。

#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

Apache2

Apache2の設定ファイルは、NGINX同様プロファイルごとにHTTP/HTTPS用の設定ファイルを用意し、VirtualHostで設定を行います。
通常のApache2とは違い、mpm_event_module を使用して、event MPM と FastCGIによる駆動にしているのが特徴です。

/etc/httpd/httpd.conf

Apache2 の共通設定となります。
このファイル中で、ログのフォーマット、gzip や brotli の圧縮設定、mpm_event_module の設定を記述しています。

/etc/httpd/conf.modules.d/00-http2.conf

kusanagi-httpd には、http/2用のモジュール mod_http2 を含んでいます。このモジュールを読み込む設定ファイルになります。

/etc/httpd/conf.d/プロファイル_httpd.conf

HTTP接続で使用する設定ファイルです。
kusanagi provision 時に自動生成されます。この時、/usr/lib/kusanagi/resource/etc/httpd/conf.d/fqdn_http.conf* をテンプレートとしています。
この内容は、プロビジョンタイプによって異なります。

https redirect

kusanagi ssl –https redirect を実行すると、以下の RewriteEngine Offを Onにします。
kusanagi ssl –https noredirect を実行すると、以下の RewriteEngine Offを Offにします。


RewriteEngine Off
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

/etc/httpd/conf.d/プロファイル_ssl.conf

HTTPS接続で使用する設定ファイルです。
kusanagi provision 時に自動生成されます。この時、/usr/lib/kusanagi/resource/etc/httpd/conf.d/fqdn_ssl.conf* をテンプレートとしています。

SSL証明書

SSL証明書および秘密鍵は、デフォルトでは以下のように自己証明SSL証明書が設定されています。
Let’s Encrypt の証明書を取得したとき、kusanagi ssl –cert/–key で証明書を指定したときは、NGINXと同様にファイル名を変更します。

SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

HSTS

HSTS(HTTP Strict Transport Security)の設定は、以下の文のhsts の値を変更します。
kusanagi ssl –hsts offのときは0、weak のときは1、midのときは2、highのときは3を設定します。
これにより、NGINXと同様のHTTPヘッダを出力し、同様の動作をします。

Define hsts 0
<If "${hsts} = 1">
       Header set Strict-Transport-Security "max-age=31536000"
</IF>
<ElseIf "${hsts} = 2">
       Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</ElseIF>
<ElseIf "${hsts} = 3">
        Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</ElseIF>

monit

KUSANAGIでは、monitでNGINX/Apache2のアクセスログを監視し、5xx エラーが連続して発生したときに kusanagi restart を行います。
この設定ファイルは、kusanagi provision 実行時に生成されます。また、NGINX と Apache2を切り替えたときに、設定を切り替えます。

/etc/monit.d/プロファイル_nginx.conf, プロファイル_httpd.conf

kusanagi provision 実行時に、プロファイルごとに /etc/monit.d 以下に、NGINXとApache2用の設定ファイルを生成します。
その内容は以下の通りです。
アクセスログファイルを監視し、5xx エラーが連続2回発生したらkusanagi restart します。
5回連続発生した場合はアラートメールを送信し、監視を終了します。そのため、メールが到着したら対処を行う必要があります。

また、この監視は nginx、httpd というグループに属しており、nginx起動時にはnginxグループを、Apache2(httpd)起動時には httpdグループを監視するようにします。

  1. NGINX用(プロファイル_nginx.conf)
    check file プロファイル_nginx with path /home/kusanagi/プロファイル/log/nginx/access.log 
            restart program = "/bin/kusanagi restart"  
            depends on nginx 
            if match '"(GET|POST) /.* HTTP/.*" 5[0-9][0-9] [0-9]+ ' for 2 cycle then restart 
            if 5 restarts within 5 cycles then alert 
            if 5 restarts within 5 cycles then unmonitor 
            group nginx 
     
    check file プロファイル_nginx_ssl with path /home/kusanagi/プロファイル/log/nginx/ssl_access.log 
            restart program = "/bin/kusanagi restart" 
            depends on nginx 
            if match '"(GET|POST) /.* HTTP/.*" 5[0-9][0-9] [0-9]+ ' for 2 cycle then restart 
            if 5 restarts within 5 cycles then alert 
            if 5 restarts within 5 cycles then unmonitor 
            group nginx
  2. Apache2用(プロファイル_httpd.conf)
    check file プロファイル_httpd with path /home/kusanagi/プロファイル/log/httpd/access.log 
            start program = "/bin/kusanagi restart" 
            stop program = "/bin/systemctl stop httpd" 
            depends on httpd 
            if match '"(GET|POST) /.* HTTP/.*" 5[0-9][0-9] [0-9]+ ' for 2 cycle then start 
            if 5 restarts within 5 cycles then alert 
            if 5 restarts within 5 cycles then unmonitor 
            group httpd 
     
    check file プロファイル_httpd_ssl with path /home/kusanagi/プロファイル/log/httpd/ssl_access.log 
            start program = "/bin/kusanagi restart" 
            stop program = "/bin/systemctl stop httpd" 
            depends on httpd 
            if match '"(GET|POST) /.* HTTP/.*" 5[0-9][0-9] [0-9]+ ' for 2 cycle then start 
            if 5 restarts within 5 cycles then alert 
            if 5 restarts within 5 cycles then unmonitor 
            group httpd 

/etc/monitrc

monitrc は monitの設定ファイルです。
このファイルでは、監視間隔(デフォルトで30秒)、ログの設定、サービスポート(localhost:2812)を設定しています。
最後に /etc/monit.d/ 以下のすべてのファイルを読み込んでいます。

# grep -v -e '^#' -e '^$' /etc/monitrc 
set daemon  30              # check services at 30 seconds intervals
set logfile syslog
set httpd port 2812 and
    use address localhost  # only accept connection from localhost
    allow localhost        # allow localhost to connect to the server and
    allow admin:monit      # require user 'admin' with password 'monit'
include /etc/monit.d/*

/etc/monit.d/nginx.conf, httpd.conf

このファイルは、NGINXもしくはApache2(httpd)のサービス監視を行う設定を記述しています。
各プロファイルの設定で depends on nginx や httpd となっていますが、このサービスが起動しているかどうかに依存して、プロファイルの監視設定が有効になるように設定しています。

# cat /etc/monit.d/nginx.conf, httpd.conf
check program nginx with path "/bin/systemctl is-enabled nginx"
        #start program = "/bin/kusanagi restart"
        if status != 0 then unmonitor
        group nginx
# cat /etc/monit.d/httpd.conf
check program httpd with path "/bin/systemctl is-enabled httpd"
        #start program = "/bin/kusanagi restart"
        if status != 0 then unmonitor
        group httpd

/etc/monit.d/alert

alertファイルには、アラート処理を行う設定を記述しています。ここを書き換えると処理を変更することが可能です。
KUSANAGIでは、アラートは localhost の rootへメールを送信します。
rootのaliasを変更する、もしくはこのファイルを変更することで任意のメールアドレスへアラートメールを送信することが可能です。
ただし、メールアドレスによっては postfixの設定を変更する必要があるかもしれません。

set alert root@localhost on {instance, timeout} 
set mailserver localhost 
set mail-format { 
        from: kusanagi@$HOST 
        subject: [KUSANAGI MONIT] $SERVICE $EVENT at $DATE 
        message: Monit alert this action.  
        Please check monit status on $HOST. 
 
Service: $SERVICE 
Event:   $EVENT 
Action:  $ACTION 
Data:    $DATE 
Host:    $HOST 
 
$DESCRIPTION. 
} 

monit status

monit status コマンドは、monit監視の状況を表示するコマンドです。
-g オプションと一緒に使うことで、nginx もしくは httpd グループの監視状況のみを出力することができます。

以下は、NGINX起動時の monit statusの表示例になります。

# monit status -g nginx
File 'kusanagi_html_nginx'
  status                            Accessible
  monitoring status                 Monitored
  permission                        644
  uid                               1000
  gid                               0
  size                              0 B
  timestamp                         0 B
  data collected                    Wed, 21 Dec 2016 21:29:33
File 'kusanagi_html_nginx_ssl'
  status                            Accessible
  monitoring status                 Monitored
  permission                        644
  uid                               1000
  gid                               0
  size                              0 B
  timestamp                         0 B
  data collected                    Wed, 21 Dec 2016 21:29:33
# monit status -g httpd
File 'kusanagi_html_httpd'
  status                            Not monitored
  monitoring status                 Not monitored
  data collected                    Wed, 21 Dec 2016 06:07:12

File 'kusanagi_html_httpd_ssl'
  status                            Not monitored
  monitoring status                 Not monitored
  data collected                    Wed, 21 Dec 2016 06:07:12

monit moniter/unmoniter

monit moniter/unmoniter コマンドは、項目に対して moniterを行う/行わない を切り替えるコマンドです。
kusanagi nginx/httpd では、内部でこのコマンドを起動して、有効なグループの設定のみmoniterを行うようにしています。

NGINX有効時

# monit monitor all -g nginx
# monit unmoniter all -g httpd

Apache2 有効時

# monit monitor all -g httpd
# monit unmoniter all -g nginx

bcache

bcache は KUSANAGIで提供しているプラグインで実現しているページキャッシュです。

wp-config.php

bcache は、wp-config.php の以下の文がコメントアウトしている、もしくは存在しない場合に off 状態になります。
bcache on で、下記の文のコメントアウト(先頭の#)が外れます。

#define('WP_CACHE', true); 

上記文は、wp-config-sample.php に含まれており、WebUIからWordPressの設定を行う場合にはこの行が自動的に含まれます。
WordPress移設などで wp-config.php をコピーしたり、wp core config コマンドを使用してwp-config.phpを設定した場合は含まれないことがあります。
その場合、 /usr/lib/kusanagi/resource/wp-config-sample/(en_US|ja)/wp-config-extra.php の内容を wp-config.php に追記して下さい。

# cat /usr/lib/kusanagi/resource/wp-config-sample/ja/wp-config-extra.php 
/**
 * 開発者へ: WordPress デバッグモード
 *
 * この値を true にすると、開発中に注意 (notice) を表示します。
 * テーマおよびプラグインの開発者には、その開発環境においてこの WP_DEBUG を使用することを強く推奨します。
 */
define('WP_DEBUG', false);

#define('WP_ALLOW_MULTISITE', true);
#define('FORCE_SSL_ADMIN', true);
#define('WP_CACHE', true);

bcacheの仕組み

bcacheを有効にすると、URLをキーにしてPHPで生成したページをMariaDBの以下のテーブルに格納します。

mysql> show columns  from wp_site_cache; 
+-------------+--------------+------+-----+---------+-------+ 
| Field       | Type         | Null | Key | Default | Extra | 
+-------------+--------------+------+-----+---------+-------+ 
| hash        | varchar(32)  | NO   | MUL | NULL    |       | 
| content     | longtext     | NO   |     | NULL    |       | 
| device_url  | text         | NO   |     | NULL    |       | 
| type        | varchar(20)  | YES  | MUL | NULL    |       | 
| post_type   | varchar(200) | NO   |     | NULL    |       | 
| headers     | text         | NO   |     | NULL    |       | 
| user_agent  | text         | NO   |     | NULL    |       | 
| server      | varchar(16)  | NO   |     | NULL    |       | 
| updating    | tinyint(1)   | NO   | MUL | 0       |       | 
| create_time | datetime     | NO   |     | NULL    |       | 
| expire_time | datetime     | NO   | MUL | NULL    |       | 
+-------------+--------------+------+-----+---------+-------+ 
11 rows in set (0.00 sec) 

DBに格納することから、逆に遅くなるのでは?という懸念があると思いますが、KUSANAGIでは innodb_buffer_pool_size や query_cache_size を標準よりも多く設定していることから、上記で登録した内容はオンメモリであることが期待できます。ほぼオンメモリでクエリ処理を行うため、高速にページキャッシュを実現できます。

この仕組み上、MariaDB の binarylog が bcache 未使用の場合より肥大します。そのため、binarylog の最大値を設定するなど、ディスク領域を圧迫しない設定が必要になります。

HTTP レスポンスヘッダ

bcacheの状態は、HTTPのレスポンスヘッダ X-B-Cache で確認できます。

  1. bcache が無効のとき
    X-B-Cache: BYPASS 
  2. bcache でキャッシュにヒットしないとき(キャッシュをクリアしたときも含む)
    X-B-Cache: create 
  3. bcache でキャッシュにヒットしたとき
    X-B-Cache: cache

fcache

fcacheは、FastCGIのキャッシュ機構を使用したページキャッシュになります。

FastCGI cacheの設定

FastCGIキャッシュは、PHPで生成したページをメモリ上に保持し、/etc/nginx/nginx.conf内のfastcgi_cache_pathで指定したメモリ量を超える場合は、指定したディレクトリ(/var/cache/nginx/wordpres)にファイルで保管します。
KUSANAGIでの設定は以下のようになっています。

# grep fastcgi_cache_path /etc/nginx/nginx.conf
fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=wpcache:30m max_size=512M inactive=600m;

HTTPレスポンスヘッダ

fcacheの状態は、HTTPのレスポンスヘッダ X-F-Cache で確認できます。

  1. fcache が無効のとき
    X-F-Cache: BYPASS
  2. fcache でキャッシュにヒットしないとき(キャッシュをクリアしたときも含む)
    X-F-Cache: MISS
  3. fcache でキャッシュにヒットしたとき
    X-F-Cache: HIT

まとめ

ということで、KUSANAGIで生成する設定ファイル、利用する設定ファイルから、kusanagi のいろいろな機能をどう実現しているかを説明してみました。
まだまだ色々説明できることはあるのですが、ちょっと長くなりすぎたので別の機会にまた説明しようかと思います。


Post Author: 宮﨑悟

KUSANAGIの中の人で、プログラミングができて、歌って踊ってベタが塗れるサーバエンジニア(誇張あり)。 物理層からミドルウェアまでを主戦場としていますが、最近はKUSANAGIを作ったりKUSANAGIを作ったりKUSANAGIを作ったりしています。 好きなOSはSolaris。好きなファイルシステムはZFS。好きな仮想化はSolaris Zone。