しおしお

IntelliJ IDEAのことなんかを書いてます

Spring Cloud AWSで異なるリージョンにあるSESを使ってみる

Spring Cloud AWSのSESでアプリケーションとは異なるリージョンにあるSESを使う方法
*1

アプリケーションのリージョンの指定

リージョンの指定は、application.propertiesにこんな感じに設定します。

cloud.aws.region.auto=false
cloud.aws.region.static=ap-northeast-1

EC2のメタデータからとってこれる場合はこんな感じになります。

cloud.aws.region.auto=true

SES用のリージョンを設定するConfigurationの作成

アプリケーション用のリージョンを設定してしまうと、SESのAutoConfigurationもそのリージョン情報を使ってしまうので、強制的に別のリージョンを使うようにするConfigurationクラスを追加します。

MailSenderAutoConfigurationの実装を見ると、AmazonSimpleEmailServiceがBean定義されていない場合のみアプリケーションのリージョンを使ってAmazonSimpleEmailServiceClientを生成するようなので、Configurationクラス側でSES用のリージョンをもとにAmazonSimpleEmailServiceClientのBeanを定義してあげます。

@Configuration
public class SimpleEmailConfiguration {

    @Bean
   public AmazonWebserviceClientFactoryBean<AmazonSimpleEmailServiceClient> amazonSimpleEmailService(
            @Value("${aws.ses.region}") final String region,
            final AWSCredentialsProvider credentialsProvider) {
        return new AmazonWebserviceClientFactoryBean<>(AmazonSimpleEmailServiceClient.class,
                credentialsProvider, new StaticRegionProvider(region));
    }
}

SES用のリージョンを設定する

Configurationクラスが受け取るリージョン名をapplication.propertiesに設定します。

aws.ses.region=us-east-1

これでSpring Cloud AWSを使った場合でも、異なるリージョンにあるSESをサクッと使えるようになります。

*1:SESは東京リージョンにないので、アプリケーションを東京リージョンで動かした場合は必ず違うリージョンになってしまう

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

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


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

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

imageをビルドしてみる

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

./gradle jibDockerBuild

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

 ~ 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でさくっと起動できますね。

※48年前問題は、0.9.7のリリースで追加されたcontainer.useCurrentTimestampを使うことで、ビルド日時に変えられるようです。
build.gradleにこんな感じのものを追加するだけですね。

jib {
  container {
    useCurrentTimestamp = true
  }
}

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' 
}