Spring Boot 2 アップグレード後に JPA ( Hibernate )が勝手に SEQUENCE を使おうとする問題
問題
Spring Boot 1.5 -> 2.0 に上げたとき MySQL を JPA (Hibernate)経由で利用している場合、 GeneratedValue に AUTO を指定していると INSERT 処理時などに下記のような例外が発生する可能性がある。
Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException Table 'xxx.hibernate_sequence' doesn't exist
原因
Spring Boot の AutoConfiguration では hibernate を使う際に hibernate.id.new_generator_mappings の値のデフォルト値が false になっており、native の id generator が使われていたが Spring Boot 2 になったタイミングでデフォルト値が true になった。 hibernate.id.new_generator_mappings が true の場合、Hibernate 5 では AUTO が指定された場合は常に SEQUENCE 扱いとなる様子。MySQL の場合は SEQUENCE に対応していないため AUTO にしている状態では動かなくなる。
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide
Id generator
The spring.jpa.hibernate.use-new-id-generator-mappings property is now true by default to align with the default behaviour of Hibernate. If you need to temporarily restore this now deprecated behaviour, set the property to false.
Spring Boot 1.5
result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false");
Spring Boot 2.0
result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "true");
対応案
下記2つの対応が考えられる
- spring.jpa.hibernate.use-new-id-generator-mappings の設定を 明示的に false を使う
- 対象となる GeneratetedValue アノテーションすべてに明示的に IDENTITY を指定する
id generator が false は deprecated とあるので true のほうがよさそうだが デフォルトの AUTO のままでは IDENTITY が使われるルートがなさそうなので一括で対応する方法はなさそう。
参考 URL
letsencrypt の certbot renew を apache plugin から nginx(webroot) に切り替える
環境
- Debian 9.3
- certbot 0.10.2
内容
もともと apache がサポートされていたため apache を利用して letsencrypt を利用していたが nginx を使うように変更したため nginx で直接 https 処理を行うように変更したい。
$ vim /etc/letsencrypt/renewal/example.com.conf
下記のようになっているはず
# Options used in the renewal process [renewalparams] authenticator = apache installer = apache account = ......
これを下記のように書き換える
# Options used in the renewal process [renewalparams] authenticator = webroot installer = None account = ...... [[webroot_map]] example.com = /path/to/webroot
このあとそのまま certbot renew をするとよい。 また cron で自動で確認するようになっていると思うので /etc/cron.d/certbot の内容の一部を下記のように書き換える。reload でもいいかもしれないが自分の環境では特に気にすることもないためそのまま restart している。
.... && certbot -q renew ↓ .... && certbot -q renew --post-hook "service nginx restart"
--post-hook か --renew-hook がいいかは1年ぐらい運用したけど毎回失敗しててよくわからなかった。
BSD + ansible で sysrc を用いて利用可能にする
BSD 系では rc.conf に *_enable="YES"
のような形で設定しないと init script 等で起動しない挙動をするようにするのが一般的な様子?(詳しくは未調査)
ansible でこのあたりを編集するのはつらいのでコマンドを用いて設定できるようにするには sysrc を使うと便利。 sysrc はどうやらデフォルトで入ってなさそう(少なくとも DragonflyBSD においては)なのでこれをインストールするタスクも入れる必要がある。 (汎用的に使うには role に設定して dependences にいれておいたほうが便利そう)
- name: install sysrc package: name: sysrc state: present - name: enable openvpn command: sysrc -ni openvpn_enable="YES" register: openvpn_enable_rc changed_when: (openvpn_enable_rc.stdout == "NO -> YES") or (openvpn_enable_rc.stdout == " -> YES")
上記の動作確認は DragonflyBSD で行ったがこの sysrc は存在してもしなくて return code は 0 を返すため設定に成功したかどうかわからず そのままでは changed 設定ができない。苦肉の策として標準出力を用いている。
sysrc の 実行例
以下はもとに設定がない場合。
n をつけない場合
$ sysrc openvpn_enable="YES" openvpn_enable: -> YES
n をつけた場合
$ sysrc -n openvpn_enable="YES" -> YES
i をつけない場合
$ sysrc openvpn_enable sysrc: unknown variable 'openvpn_enable'
i をつける場合何もかえらない。そのキーが存在しない場合に sysrc: unknown variable 'openvpn_enable'
といったメッセージを出す場合があるので前述の ansible task では 念のためつけている。(影響があるのは 設定する場合と -x で削除する場合)
$ sysrc -i openvpn_enable
e は以下のように ダブルクオーテーションの挙動がなにかおかしいので使ってない。
$ sysrc -e openvpn_enable="YES" openvpn_enable=" -> YES
さくらの VPS 上の DragonflyBSD で ipv6 ネットワーク設定をする
環境
- さくら のVPS
- DragonFly v5.0.2-RELEASE
準備
さくら VPS のコントロールパネルで IPv6 アドレスとゲートウェイを確認する。 自分の場合は特に申請してなくてもついていたのでデフォルトで付いている様子。(契約タイミングやデータセンターによるかもしれない) -この IPv6 アドレスは サフィックスに IPv4 アドレスが付いているパターンのものらしい [1]. - 追記)と思ったけど よーく見るとコンパネの記載にあるのは ドットではなくコロンのため、単純に同じ数字を用いた ipv6 アドレスという可能性のほうが高そう。
設定
vtnet0 インタフェースを用いる場合
/etc/rc.conf
# IPv6 ipv6_enable="YES" ipv6_network_interfaces="vtnet0" # あってもなくてもいい ipv6_defaultrouter="fe80::1%vtnet0" ipv6_ifconfig_vtnet0="inet6 (コントロールパネルに表示されるIPv6アドレス) prefixlen 64"
他の設定については /etc/defaults/rc.conf を確認。
簡単に各項目を説明。
key | default | description |
---|---|---|
ipv6_enable | NO | ipv6 を使う場合に YES ( FreeBSD 9 以降?では 使うべきではないらしい が DragonflyBSD では関係ない様子) |
ipv6_network_interfaces | auto | auto の場合は ifconfig -l の結果が入る。自分の場合は 別の設定名で インタフェースが必要なのでそれを使うという意図で明示している。 |
ipv6_defaultrouter | NO | コンパネで確認する ゲートウェイを入れる。 そのままだとなぜか通じないのでインタフェース名を入れると動く。( netstat -f inet6 -rn などを見ると %lo などがついている場合があったので) |
ipv6_ifconfig_vtnet0 | - | ifconfig で設定する内容 ipv6_ifconfig プレフィックス の設定はipv6_network_interfaces の値に入っている場合に使われる様子 |
設定後は ssh で繋いでる場合は 下記の様にするとおそらく良い [2]。 ipv6 設定を反映するためには /etc/rc.d/network_ipv6 を使ったほうが良さそうな気がしてとりあえず入れているがきちんと検証してない。
$ sudo /etc/rc.d/netif restart && sudo /etc/rc.d/routing restart && sudo /etc/rc.d/network_ipv6 restart
つながっているかどうかは 外から ping6 を実行するなどして確認 [3]。
発生した問題
ping6 や ssh で ipv6 アドレスを直接指定して動かした場合に動作せず、サーバ側のコンソールで下記のようなエラーが出る現象があった。
nd6_storelladdr: sdl_alen == 0 nd6_storelladdr: sdl_alen == 0 nd6_storelladdr: sdl_alen == 0
このエラーが出ている部分はこのあたり。 impossible と書いてあるけど…
/usr/src/sys/netinet6/nd6.c
2091 if (sdl->sdl_alen == 0) { 2092 /* this should be impossible, but we bark here for debugging */ 2093 kprintf("nd6_storelladdr: sdl_alen == 0\n"); 2094 m_freem(m); 2095 return (0); 2096 }
自分の場合の原因は、ipv6 アドレスの設定部分だった様子。 記事によっては ifconfig_vtnet0_ipv6 のような ifconfig プレフィックスになっている場合があるが、 少なくとも自分の環境ではこれでは動作せず、上記のような謎エラーが表示される。
ipv6 を prefix とするような設定にするとたぶん大丈夫。 このあたりは /etc/network.subr 内 network6_interface_setup 関数で呼ばれている様子なので詳しい挙動を見たい場合はこのあたりを参考に。
参考文献
- [1] IPv4アドレスを含むIPv6アドレス表記:Geekなぺーじ
- [2] FreeBSD: How To Start / Stop / Restart Network and Routing Services - nixCraft
- [3] Network Troubleshooting Tools, IPv4 and IPv6
- IPv6アドレスの設定方法 – さくらのサポート情報
- さくらのVPS で IPv4 over IPv6ルータの構築
- https://www.freebsd.org/doc/handbook/network-ipv6.html
- https://www.dragonflybsd.org/~labthug/handbook/firewalls.html
2017年 まとめ
技術編
- http client に詳しくなった
- mockito をまともに使い始めた
- spring framework をまともに使い始めた
- spring boot をまともに使い始めた
- gradle をまともに使い始めた
- ansible をまともに使い始めた
- Raspberry Pi を手に入れた
ゲーム編
ハード
- PS4 Pro を買った
- 4K ディスプレイを買った
- Nitendo Switch を買った
-
- 人喰いの大鷲トリコ(未クリア)
- ソードアート・オンライン ホロウリアリゼーション
- ファイナルファンタジー XIV 紅蓮のリベレーター
- ファイナルファンタジー XV
- テイルズオブベルセリア(未クリア)
- 蒼き革命のヴァルキュリア(未クリア)
- バイオハザード6(二回目)
- Republique (未クリア)
- Goat Simulator PS4
- バウンド:王国の欠片 (未クリア)
- Life is Strange
- Horizon Zero Dawn
- Farming Simulator 17
- ゴーストリコン ワイルドランス(未クリア)
- リトルビックプラネット
- NieR: Automata
- ブレイドストーム 百年戦争&ナイトメア
- Lumo (未クリア)
- アサシンクリード IV Black Flag (未クリア)
- ドラゴンクエストXI 過ぎ去りし時を求めて (未クリア)
- 巨影都市 (未クリア)
- アサシンクリードオリジンズ
- 地球防衛軍5
Switch
- ゼルダの伝説 BoW
- ファイアーエムブレム無双
- マリオカート8 DELUXE
- ヒューマンリソースマシン
- スプラトゥーン2
- ゼノブレイド2
漫画編
4 桁行かないぐらいだけど書ききれないので割愛
コーヒー編
- コーヒーに凝り始めた
- 機器
- SCAJ 2017 に行った
- コーヒー豆を買った(合計推定 10 kg )
その他
- ネパールに行った
- 国内の旅行に何回か行った
- 壊れたエアコンで暑さに耐えきれずに引っ越しをした
wp-comments-post.php への投稿が 405 Method Not Allowed になる問題
確認環境
- Wordpress 4.9.1 https://ja.wordpress.org/
- iThemes Security 6.7.0 https://ja.wordpress.org/plugins/better-wp-security/
- nginx 1.12.1 https://nginx.org/en/
問題
wordpress の記事のコメント投稿が 405 Method Not Allowed になる
確認される現象
記事詳細ページのコメント欄へコメントできない
原因
条件1 : nginx の設定
nginx の location ディレクティブで .php を指定して fastcgi に引き渡している。
https://codex.wordpress.org/Nginx#General_WordPress_rules
upstream php { server unix:/tmp/php-cgi.socket; server 127.0.0.1:9000; } ... server { ... location ~ \.php$ { ... fastcgi_pass php; ... }
条件2: iThemes Security の「コメントスパム」設定が有効
iThemes Security で該当項目を有効にしていると 生成される nginx.conf で以下のような 設定が出力される。
# コメントスパムを削減 - セキュリティ > 設定 > WordPress の微調整 > コメントスパム location = /wp-comments-post.php { limit_except POST { deny all; } if ($http_user_agent ~ "^$") { return 403; } valid_referers server_names jetpack.wordpress.com/jetpack-comment/; if ($invalid_referer) { return 403; } }
上記より
nginx の location ディレクティブは最長一致の設定が用いられる[1]。 そのため条件1で設定した .php の location よりも 条件2の /wp-comments-post.php が優先されるはず。そして 条件2の設定では fastcgi_pass がないためそのまま静的ファイルとして処理される。 nginx は静的ファイルの場合は POST は許可されないため 405 になる[2]。
解決方法
- コメントスパム を off にする(暫定対応)
このままだとコメントスパム対応部分が弱いとも考えられるので コメントスパム部分は別のプラグインに任せるか、上記設定を参考にして自分で fastcgi_pass をする設定を追加するなどすればよい気もする。
(余談) iThemes Security が出力する設定を変更することはできないため、対象 location ディレクティブに fastcgi_pass を設定できない。 そして自分は location ディレクティブに fastcgi_pass を記載することなく設定する方法がわからない、というのと wordpress を運用しようとしている人の nginx 力はそんなに高くないと思っているため 技巧を凝らした nginx 設定するのはあんまりよくない気もする。ので「コメントスパムを off にする」ぐらいしか思いつかない。
参考 URL
Spring Boot で Gzip を使ってレスポンスを返す
概要
nginx などの web server では静的ファイルなどを gzip で返すとパフォーマンスがよくなるよーという記事は良くみる。 これを Spring Boot で行うにはどうすればいいか。(アプリケーションから gzip で返す必要性が発生するのかというのは別の話)
設定
https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
server.compression.enabled=false # If response compression is enabled. server.compression.excluded-user-agents= # List of user-agents to exclude from compression. server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript # Comma-separated list of MIME types that should be compressed. server.compression.min-response-size=2048 # Minimum response size that is required for compression to be performed.
server.compression.enabled を true にする。とりあえず有効にするのはここまで。
細かい確認
Spring Boot 1.5 と 2.0 ともに下記バージョンのよう。
- jetty 9.4.7.v20170914
- tomcat 8.5.23
- undertow 1.4.21.Final
それぞれどう違うのかというのを確認しようとして関係の図を書いた。 Spring Boot 1.5 と 2.0 では少し実装が違ったけど 1.5 まとめて疲れたのでここまで。
要するにどれも 標準の java.util.zip.Deflater を使っている。 Deflater は中で(native で) zlib 呼んでるらしい。