Gradle で Maven BOM を作る

概要

Gradle で複数のプロジェクトでバージョンを共通なものにしたい場合などのために BOM を作成する。

前提

ここでは下記バージョンをもとにしたドキュメントやソースを参照している

BOM とは

"bill of materials" 、つまり部品表の略。(あるいは "build of materials" と記載されている例もある) アーティファクトを列挙し、その BOM を利用する際に依存するバージョンを統一することができる。

maven.apache.org

BOM の例

Spring Boot Dependencies

Spring Boot の BOM, 基本的には Spring Boot で開発する場合はこれが使われており、 Spring Boot 内で使われているものと同じバーションのものをアプリケーション側でも利用することが多いと思う。

Spring Boot の依存関係は別途 HTML ドキュメントとして出力されており、下記のようにドキュメントのページで確認できる。

軽く触ったりする場合などは明示的に使っているパターンは少なくて、通常は下記のような Gradle Plugin が自動的に Spring Boot Dependencies を import してくれている。

Spring Framework BOM/Spring Security BOM

Spring Framework の BOM。基本的には リリースされるモジュールのバージョンを一括で登録してある BOM となっているようにみえる。

Spring Boot Dependencies にも利用されている。

spring-boot/pom.xml at v2.2.0.M4 · spring-projects/spring-boot · GitHub

JUnit BOM

JUnit の BOM

AWS Java SDK BOM

AWS Java SDK の BOM

Gradle で BOM を作成する

Magen の pom.xml ではそのまま DepenendencyManagement セクションにアーティファクト情報を記載すれば良い。

gradle の場合は方法は確認した限りでは2つ。

  • java-platform-plugin を利用する
  • spring team の DependencyManagment plugin を利用する

java-platform-plugin を利用する

docs.gradle.org

dependencies 以下に constrains として追加する。おそらく基本的には api を用いると思う(理由は未調査)

dependencies {
    constrains {
        api 'org.springframework:spring-core:4.0.3.RELEASE'
    }
}

scope import の場合は dependendy として追加する。 java-platform plugin はデフォルトでは dependencies は許可されてないので別途 許可する設定を追加する。

javaPlatform {
    allowDependencies()
}

dependencies {
    api platform('io.spring.platform:platform-bom:1.0.1.RELEASE')
}

publish する場合は maven-publish plugin を利用して以下のように記述する。

publishing {
    publications {
        maven(MavenPublication) {
            from components.javaPlatform
        }
    }
}

spring team の DependencyManagment plugin を利用する

Gradle の場合は 依存性の記載には spring チームが出している Dependency Management Plugin を利用する。 これを利用することによって MavenDependencyManagement セクションで行うような記載ができるようになる。

plugins.gradle.org

docs.spring.io

dependencyManagement {
    dependencies {
        dependency 'org.springframework:spring-core:4.0.3.RELEASE'
    }
}

scope import の場合

dependencyManagement {
    imports {
        mavenBom 'io.spring.platform:platform-bom:1.0.1.RELEASE'
    }
}

dependencies には下記のようにバージョン情報を抜いて記載できる。この場合は dependencyManagement に記載のある 4.0.3.RELEASE が利用される。

dependencies {
  implementation 'org.springframework:spring-core'
}

ここまではまあ通常の用途で、その記載対象となるプロジェクト下でのバージョン情報や、 multiproject などで sub project でのバージョン情報などを省略できる。

他の独立したプロジェクト(別リポジトリ等)で利用したい場合は その dependencyManagement 情報を publish する必要がある。このとき必要なのが maven-publich プラグインである。(maven リポジトリの場合) これを使うことで gradle のプラグインで記載された dependencyManagement を pom.xml で出力し、 maven リポジトリを通じてその他のプロジェクトで利用できる形にできる。

Maven Publish Plugin

publishing {
    publications {
        maven(MavenPublication) {
        }
    }
}

例: Gradle scripts to generate a BOM and then consume that BOM · GitHub

また pom.xml 側で記載されているような properties を記載したい場合には以下のように書く。

publishing {
    publications {
        maven(MavenPublication) {
            pom {
                properties['spring.boot.version'] = '2.2.0.M4'
            }
        }
    }
}

ローカルで使って見る場合には publishToMavenLocal タスクを使って local repo に入れたうえで 利用側で mavenLocal() の記載があれば maven repository にデプロイしなくても確認できると思う。

Gradle で BOM を利用する

使い方はおそらく2つ。

  • Gradle Dependency Management Plugin の imports に記載する。
  • Gradle 5.0 以上の場合は implementation platform() する

前者の場合は dependencyMananement の部分に imports で記載すると利用できる。

dependencyManagement {
     imports {
          mavenBom 'io.spring.platform:platform-bom:1.0.1.RELEASE'
     }
}

dependencies {
     compile 'org.springframework.integration:spring-integration-core'
}

Dependency Management Plugin

後者の場合は Gradle 5.0 から Gradle 側で利用方法が提供されているためその書き方もできる。

dependencies {
    // import a BOM
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE')

    // define dependencies without versions
    implementation 'com.google.code.gson:gson'
    implementation 'dom4j:dom4j'
}

gradle.org

注意点としては lombokannotationProcessor の利用が必要な場合は annotationProcessorにも BOM の記載が必要になる。

stackoverflow.com

以上

Debian 8 -> 9 にあたり sshd_config に必要だった変更

Debian -- jessie の openssh-server パッケージに関する詳細

openssh 6.7

Debian -- stretch の openssh-server パッケージに関する詳細

openssh 7.4

変更点

Protocol は 7.0 のタイミングでコンパイル時にデフォルトで無効、7.6 のタイミングで完全に削除。 説明文も 7.6 では 1.5 と 1.3 についての記載が削除されている。 debian 9 の openssh は 7.4 のため デフォルトで無効にされており、 Protocol の設定は不要(または設定できない?)になる。

OpenSSH 7.0/7.0p1 (2015-08-11)

OpenSSH is a 100% complete SSH protocol 2.0 implementation and
includes sftp client and server support. OpenSSH also includes
transitional support for the legacy SSH 1.3 and 1.5 protocols
that may be enabled at compile-time.
OpenSSH 7.6/7.6p1 (2017-10-03)

OpenSSH is a 100% complete SSH protocol 2.0 implementation and
includes sftp client and server support.

それに伴い下記設定群が不要(設定できない?)になる

  • RSAAuthentication
  • ServerKeyBits
  • RhostsRSAAuthentication

UsePrivilegeSeparation については設定のデフォルトとしては sandbox になる。 手元の debian サーバの 設定は yes になっているが、 yes と sandbox の違いはよくわからない。

参考URL

差分

今後のバージョン

2018 年まとめ

技術編

  • コードをほぼ書かなかった
  • 小規模 Minecraft サーバを運用した
  • 相変わらず OpenVPN を触っていた
  • Kotlin を少し触った
  • vue.js を少し触った
  • TypeScrypt を少し触った

ゲーム編

2018 年に購入または 2018 年にプレイした形跡があるもの

家財編

  • SHARP の空気清浄機を買った
  • ダイソン Hot & Cool 空気清浄機を買った
  • 無印の超音波式加湿器を買った
  • 象印のスチーム式加湿器を買った
  • I-O-DATA の NAS 16TB を買った
  • CyberPower の UPS を買った
  • パナソニックのレッグリフレを買った

ボードゲーム

  • ゲムマに行って2本のゲームを買った
  • 友人の作ったゲームをやった

漫画編

  • 958 冊買った

映画編

  • グレイテストショウマン
  • カメラを止めるな
  • Search
  • インターステラー
  • Pixel
  • ファイティングマン 怒りの除雪車
  • グレートウォール
  • La La Land
  • セッション

その他

  • 冬桜を見に行った
  • 入籍した

Minecraft Server の JVM をモニタリングする

目的

Minecraft が高負荷になる場合に FullGC が発生したかなどの JVM 側の負荷なのか 単純に Minecraft 自体での処理が重いのかなどの切り分けを行うためにモニタリングしたい。

方法

自分のサーバは基本的に prometheus によるモニタリングを行っているので Minecraft のサーバ自体のモニタリングが行えるとよい。

GitHub - prometheus/jmx_exporter: A process for exposing JMX Beans via HTTP for Prometheus consumption

手順

前提

  • Minecraft が運用されている
  • Prometheus が運用されている
  • Grafana が運用されている

JMX のメトリクスを取得できるようにする

jmx_exporter によるメトリクスの取得を行うための javaagent の jar を落とす。

$ curl -OLJ https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar

jmx_exporter 用の config ファイルを用意。今回は簡単のため空ファイルを作成。

$ touch config.yaml

javaagent のオプションを指定して起動。jmx_exporter の jar ファイルはパス指定でも良さそうだが config.yaml がうまく動かなかったので場所を変えたい場合は要確認。下記は 8080 ポートで開く例。(実運用では jmx_exporter で 8080 はあまり使わない)

java -jar -javaagent:.jmx_prometheus_javaagent-0.3.1.jar=8080:config.yaml  -jar minecraft_server.jar nogui

Prometheus で メトリクスを取得するようにする

簡単な例。正確な記述は割愛。

  - job_name: jmx
    static_configs:
    - targets: ['xxx.xxx.xxx.xxx:port']

グラフの用意

最近の Grafana では公式のページにある程度設定されたダッシュボードがあり、これを import することによってだいたいそのまま使うことができる様子。

https://grafana.com/dashboards/3457

下記のような表示になる。GC カウントも見られ、FullGC が多いかどうかを確認でき、メモリバウンドなのかなどの確認がしやすくなる。

f:id:nise_nabe:20180830225535p:plain

結果

自分のサーバでは特に FullGC が発生してはいなかった。 原因としてログインしているユーザによる牧場で牛や豚が大量にいたことが原因のようだった。

その他

prometheus で minecraft 特有のメトリクスを取得も可能な様子。

https://github.com/sladkoff/minecraft-prometheus-exporter

この exporter は spigot という minecraft server に MOD が導入できる(api 利用が可能になる)ものを利用することによって可能な様子。自分はバニラサーバで動かしているので一旦導入は保留。

Spring Boot 2 アップグレード後に JPA ( Hibernate )が勝手に SEQUENCE を使おうとする問題

問題

Spring Boot 1.5 -> 2.0 に上げたとき MySQLJPAHibernate)経由で利用している場合、 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

https://github.com/spring-projects/spring-boot/blob/v1.5.14.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java#L207

        result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false");

Spring Boot 2.0

https://github.com/spring-projects/spring-boot/blob/v2.0.3.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java#L237

        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) に切り替える

環境

内容

もともと 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