しおしお

IntelliJのあれやこれや

Dockerfile不要のコンテナビルダーのGradleプラグインを触ってみた

↓を見て便利そうなのでどんな感じなのかなと触ってみました。


gradleにプラグインを追加する

plugins {
  id 'com.google.cloud.tools.jib' version '0.9.2'
}

imageをビルドしてみる

imageのビルドはjibDockerBuildで行います。

./gradle jibDockerBuild

結果はこんな感じになりました。repositoryにはプロジェクト名が、tagにはバージョンが設定されるようです。
なんか、48年前に作成されたことになってますが↓のチケットと同件ですかね。
https://github.com/GoogleContainerTools/jib/pull/412

 ~ docker images  
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
jib-demo                       1.0.0               60f95e9fbe77        48 years ago        138MB

docker run --rm -p 8080:8080 jib-demo:1.0.0でさくっと起動できますね。

Dockerfileを生成してみる

Dockerfileの生成はjibExportDockerContextで行います。

./gradle jibExportDockerContext

タスクを実行すると、build/jib-docker-context配下にDockerfileが生成されます。
内容はこんな感じでした。

FROM gcr.io/distroless/java

COPY libs /app/libs/
COPY resources /app/resources/
COPY classes /app/classes/

ENTRYPOINT ["java","-cp","/app/libs/*:/app/resources/:/app/classes/","siosio.jibdemo.JibDemoApplication"]
CMD []

Docker Hubにpushしてみる

build.gradleにDocker Hubの認証情報とimage名を設定してあげます。

jib {
  to {
    image = "siosio/${project.name}:${project.version}"
    auth {
      username = 'siosio'
      password = '********************************'
    }
  }
  
  container {
    jvmFlags = ['-Xms512m']
    ports = ['8080']
  }
}

pushは、jibタスクで行います。実行すると、pushしたよログが出力されます。

./gradle jib
***** 省略 *****
Container entrypoint set to [java, -Xms512m, -cp, /app/libs/*:/app/resources/:/app/classes/, siosio.jibdemo.JibDemoApplication]

Built and pushed image as siosio/jib-demo:1.0.1

Docker Hubにちゃんと上がってますね。
f:id:sioiri:20180710214843p:plain

pushしたimageを使ってさくっとアプリケーション動かせますね。

 ~ docker run --rm -d -p 8080:8080 siosio/jib-demo:1.0.1
35b36eb58dfce83e81525ab2364e52564f2de4697d3fbb706d7176b4a5d1b83d
 ~ curl http://localhost:8080
キタ─wwヘ√レvv~(゚∀゚)─wwヘ√レvv~─!!%   

imageのカスタマイズ

jibに対するオプションを設定することで、imageに対する設定が色々出来るようです。
例えば、こんな感じにbase imageを指定したり、外部公開するポートを指定したり出来るようです。

jib {
  from {
    image = 'openjdk:alpine'   // base imageの設定
  }
  container {
    jvmFlags = ['-Xms512m']   // jvmオプション
    ports = ['8080']   // 外部公開するポート
  }
}

詳しい使い方は、jib/jib-gradle-plugin at master · GoogleContainerTools/jib · GitHubを。。

SonarQubeの結果をUpsourceに連携してみた

External inspections support - Help | Upsource を参考にやってみました。

SonarQubeにUpsourceに連携するための拡張をインストールする

upsource-sonar-plugin-0.1-SNAPSHOT.jarをダウンロードして、
$SONARQUBE_HOME/extensions/pluginsにおいてあげます。
SonarQubeを再起動するとこんな感じに管理画面にUpsource Integrationが表示されます。
f:id:sioiri:20180522075811p:plain

Gradleなプロジェクトにもろもろの設定を追加する

Gradleのsonarqubeプラグインを導入します。

plugins {
  id "org.sonarqube" version "2.6.2"
}

SonarQubeの結果をUpsourceに連携するには、VCSのリビジョン番号が必要になるので、
build.gradleの中で以下のように取得してシステムプロパティにせっていして

def revision = 'git rev-parse HEAD'.execute().text.trim()
System.setProperty("sonar.upsource.revision", revision)

ドキュメントにあるように、Upsouceに連携するための情報をプロジェクト直下のgradle.propertiesに設定します。
revisionは、build.gradleで設定しているのでここでは設定不要です。

# sonarqubeの情報
systemProp.sonar.host.url=http://localhost:9000

# upsourceの情報
systemProp.sonar.upsource.url=http://localhost:8080
systemProp.sonar.upsource.project=test-app
systemProp.sonar.upsource.token=siosio
systemProp.sonar.analysis.mode=issues

sonar.upsource.tokenには、UpsourceプロジェクトのintegrationタブのAuthentication token(下の画像の赤枠の部分)に設定した値を指定します。
デフォルトだとAuthentication tokenには何も設定されていないので適当な値を指定しましょう。
f:id:sioiri:20180522195153p:plain

動かしてみた結果

こんな感じにSonarQubeさんに指摘されるようなのを作ってみました。

package siosio;

import java.util.*;

public class Hoge {

    private static final String HOGE = "HOGE";

    public static void main(String[] args) {
        String hoge = null;
    }
}

実行するとsonar.analysis.mode=issuesが非推奨だよと言われるけど、Upsourceへの連携は成功しています。

> Task :sonarqube
The use of the issues mode (sonar.analysis.mode=issues) is deprecated. This mode will be dropped in the future.

Upsourceで確認すると、IntelliJさんのInspection結果と同じような感じに表示されます。
f:id:sioiri:20180523075238p:plain

Upsource側ですべて確認できるのなかなか良さそう。

AWS Secrets Managerの値をSpring Bootでいい感じに使えるようにした

AWS Secrets Manager | シークレットをローテーション、管理、取得 | アマゾン ウェブ サービス (AWS)に保存した値を、アプリケーションの設定値として使えるようにしてみた。
例えば、 @Valueを使って、Secrets Managerの値を設定したりできる感じ

作ったもの

EnvironmentPostProcessorの実装クラスを作って、Secrets Managerの値を最も優先して使えるようにしています。*1

ソースコードGitHub - siosio/spring-cloud-aws-secrets-manager

使ってみる

spring-cloud-aws-secrets-managerは公開していないので、git cloneしてMavenローカルリポジトリにインストールしてからDependenciesに追加してあげます。
Gradleの場合は、こんな感じになります。

  runtime 'com.github.siosio:spring-cloud-aws-secrets-manager:1.0.0'

Secrets Managerに値を登録する。今回は動いていることを確認しやすくするためにspring.datasource.urlにでたらめな値を設定してみてます。
f:id:sioiri:20180428071232p:plain

アプリケーションを実行する前にAWSの認証情報を設定してあげます。環境変数の場合はこんな感じになります。

export AWS_ACCESS_KEY_ID=your_access_key_id
export AWS_SECRET_ACCESS_KEY=your_secret_access_key

実行すると、こんな感じにjdbcUrlがダメだよとエラーになるので、Secrets Managerの値を参照して動いているのがわかります。
Dependencies追加するだけで、Secrets Managerの値がさくっと使えるのはちょっと便利かもしれない。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Driver org.h2.Driver claims to not accept jdbcUrl, (๑•̀ㅂ•́)و✧

残念なところ

Spring Cloud for Amazon Web Servicesとセットで使うことができないです。
spring cloud awsの最新版(2.0.0.RC1)が依存しているAWS SDKのバージョンがSecrets Manager SDKのバージョンよりだいぶ古いのが原因です。

おわり。

*1:73. Spring Boot Applicationを参考に作りました

Spring Cloud AWSを使ってS3にファイルを保存してみた

Spring Cloud for Amazon Web Servicesを使ってS3にファイルを保存してみたお話です。

依存ライブラリ

compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.cloud:spring-cloud-starter-aws')

バージョンはこんな感じです

+--- org.springframework.boot:spring-boot-starter-web -> 2.0.1.RELEASE
+--- org.springframework.cloud:spring-cloud-starter-aws -> 2.0.0.M4

S3にファイルを保存するコード

9.3 Uploading filesを参考に書いてみました

@RestController
@RequestMapping("/api")
class TestController(
        private val resourceLoader: ResourceLoader
) {

    @GetMapping("/test1")
    @ResponseStatus(HttpStatus.OK)
    fun test(): Unit {
        println("resourceLoader.javaClass.name = ${resourceLoader.javaClass.name}")
        (resourceLoader.getResource("s3://バケット名/test.txt") as WritableResource).outputStream.writer().use { 
            it.write("書き込みテスト")
        }
    }
}

動かしてみる

環境変数AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを設定して実行します。
EC2で実行した場合は、メタデータからリージョン情報が取得されるらしいです。

$JAVA_HOME/bin/java -Dcloud.aws.stack.auto=false -Dcloud.aws.credentials.useDefaultAwsCredentialsChain=true -jar hoge.jar

標準出力にはこれがでたので、ResourceLoaderの実装としてPathMatchingSimpleStorageResourcePatternResolverがインジェクとされているのがわかる。

resourceLoader.javaClass.name = org.springframework.cloud.aws.core.io.s3.PathMatchingSimpleStorageResourcePatternResolver

S3でファイルが作られていることも確認と。
f:id:sioiri:20180418081324p:plain

IntelliJ IDEA 2018.1 Public Previewでpostfix code completionが追加できるようになってた

IntelliJ IDEA 2018.1 Public Previewでpostfix code completionが追加できるようになってたのでお試ししてみた。

登録方法はこんな感じ。

Postfix Completionの設定画面から追加ダイアログを開く

流れ的にはこんな感じ。
ここにハマりポイントがあって、「+」を押した時に下の画像のようにJavaが複数表示されているとうまく登録されない…
原因は、Postfix Completionを登録するようなプラグインをインストールしているから。プラグインを消すと、Javaがひとつだけになってちゃんと登録されるようになります。
f:id:sioiri:20180301070908p:plain

ダイアログでPostfix Completionの内容を登録する

この例だと、primitive以外に対してクラス名を取ってくるみたいな感じです。

$EXPR$がPostfix Competionを実行した対象が入る部分になっていて、$END$がPostfix Completion後にカーソルを移動する場所になります。

f:id:sioiri:20180301073425p:plain

動かしてみると…

こんな感じにちゃんと使える!
f:id:sioiri:20180301074335g:plain

Gradle4.6-rc1からのBOMサポート

Gradle 5.0のfeature previewでGradle5.0からはデフォルトで有効になるかもしれないやつらしいです。
Gradle4.6 RC1で使う場合には、enableFeaturePreview('IMPROVED_POM_SUPPORT')をsettings.gradleに追加してこの機能を有効化する必要がある。

settings.gradle

enableFeaturePreview('IMPROVED_POM_SUPPORT')

build.gradle

dependencies {
  // bom
  compile 'com.nablarch.profile:nablarch-bom:5u12'
  // bomにバージョン番号が定義されているのでバージョン番号は不要
  compile 'com.nablarch.framework:nablarch-fw-web' 
}

Gradle4.6-rc1からのJUnit5サポートを試してみた

Gradle4.6からのJUnit5サポートをお試ししてみた。

これより古いバージョンはGradleからJUnit5のテストを実行する - しおしおのエントリのようにする必要があると。

build.gradleの内容

test.useJUnitPlatformでJUnit5を有効化してあげる。
これだけでよくて、昔のバージョンのようにJUnit Platform Gradle Pluginは不要になる。

buildscript {
  ext.junit_version = '5.0.3'
}

test {
  useJUnitPlatform()

  // ログを出力したい場合…
  testLogging {
    events "passed", "skipped", "failed", "standardOut", "standardError"
  }
}

dependencies {
  
  testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version"
 
  testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version"
}

実行

./gradlew clean testで実行する。
ログを有効かしていると、こんな感じのものが出力される。

:test
sample.ParameterizedSampleTest > [1] 1 PASSED
sample.ParameterizedSampleTest > [2] 2 PASSED
sample.JUnit5Sample > test() PASSED
sample.ParamTest > [1] hoge, 4 PASSED
sample.ParamTest > [2] 1, 1 PASSED
sample.ParamTest > [1] (hoge, 4) PASSED
sample.ParamTest > [2] (abcdefg, 7) PASSED
BUILD SUCCESSFUL in 2s

テストのレポートはhtmlファイルでbuild/reports/testsに出力される。
JUnit Platform Gradle Pluginのようにxmlのテスト結果だけじゃないので良い感じ。

JaCoCoプラグイン

下を追加して、./gradlew clean test jacocoTestReportカバレッジが取れるようになる。

apply plugin: 'jacoco'

Gradle&JUnit5でJaCoCoを使う - しおしおみたいなことも要らなくなる。


おわり。