Software development of explosion! -夢の破片(カケラ)たちの日々-

ソフトウェア開発を中心としたコンピューター関連のネタを扱ったブログです

Software development is passion and explosion!

Scala で AWS CDK Javaを使ってみる

はじめに

Scala Advent Calendar 2019 - Qiita の 16日目への寄稿です。

AWS CDK が、 2019年7月11日 に Generally Available となりました。
そして、2019年11月26日に AWS CDK for Java も Generally Available となりました。
Scalaから使ったら更に読み書きし易くなったりしないものだろうか?と思い立ったので試してみます。

環境構築

AWS CDK の Getting Started Prerequisites を見ると、 Node.js が必要とのこと。
マシンのOSに依存させるのは嫌なので、ここではDockerイメージ内で作業することとします。

実行方法は、GitHubリポジトリーのREADMEをご覧ください。

いざ!CDK

実行したコンテナー内で cdk init --language java を実行します。

[zsh@d535e914ac9e cdk]$ dk init --language java
Applying project template app for java
Initializing a new git repository...

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'zsh@be05ff957502.(none)')
Unable to initialize git repository for your project.
Executing mvn package...
# Welcome to your CDK Java project!

This is a blank project for Java development with CDK.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests.

## Useful commands

 * `mvn package`     compile and run tests
 * `cdk ls`          list all stacks in the app
 * `cdk synth`       emits the synthesized CloudFormation template
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk docs`        open CDK documentation

Enjoy!

[zsh@d535e914ac9e cdk (master +)]$ 

これで、 pom.xml が出来ました。

[zsh@d535e914ac9e cdk (master +)]$ ls
src  target  README.md  cdk.json  pom.xml
[zsh@d535e914ac9e cdk (master +)]$ 

pomの中身とCDKのバージョン

作られたpom.xmlを見てみると、グループIDは software.amazon.awscdk、バージョンはCDK本体のバージョンの後ろに .DEVPREVIEW が付与された形。
おそらくGAになったら外れるでしょう。

[zsh@d535e914ac9e cdk (master +)]$ cat pom.xml 
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myorg</groupId>
    <artifactId>cdk</artifactId>
    <version>0.1</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.myorg.CdkApp</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- AWS Cloud Development Kit -->
        <dependency>
            <groupId>software.amazon.awscdk</groupId>
            <artifactId>core</artifactId>
            <version>1.18.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
[zsh@d535e914ac9e cdk (master +)]$ cdk --version
1.18.0 (build bc924bc)
[zsh@d535e914ac9e cdk (master +)]$ 

sbtへ移植

new project

[zsh@73d67aca507d ~]$ sbt new scala/hello-world.g8
[info] Set current project to zsh (in build file:/home/zsh/)
[info] Set current project to zsh (in build file:/home/zsh/)

A template to demonstrate a minimal Scala application 

name [Hello World template]: 
Template applied in /home/zsh/./cdk

[zsh@73d67aca507d ~]$ ls
cdk  target
[zsh@73d67aca507d ~]$ cd cdk 
[zsh@73d67aca507d cdk (master +%)]$ ls
project  src  target  README.md  build.sbt  cdk.json  pom.xml
[zsh@73d67aca507d cdk (master +%)]$ 

これで、CDKを使うアプリの本体のベースが出来ました。
build.sbt へ pom.xml の内容を記述して、Scalaのコードを記述していきます。
build.sbt はこんな感じにしました。

import sbt.Keys.{libraryDependencies, scalaVersion}

scalaVersion := "2.13.1"

name := "hello-world"
organization := "com.github.poad"
version := "1.0"

val cdkVersion = "1.18.0"
libraryDependencies ++= Seq(
    "software.amazon.awscdk" % "core" % cdkVersion
)

流石に Java のコードを Scala へ移植する部分や、Javdocを調べてScalaのコードを記述する部分の説明については割愛します。

cdk.json

Getting Started With the AWS CDK - AWS Cloud Development Kit (AWS CDK) の 「cdk ls」を実行すると以下のようなエラーが出力されます。 (Javaのクラスを残したままだと発生しないかと思います。。。)

[zsh@bd8ee7c9cbb6 cdk (master *+)]$ cdk ls
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli) on project cdk: An exception occured while executing the Java class. com.myorg.HelloApp -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
Subprocess exited with error 1

あるいは、pom.xml を削除していると、以下のようなエラーが出力されます。

[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ cdk ls
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli): Goal requires a project to execute but there is no POM in this directory (/home/zsh/cdk). Please verify you invoked Maven from the correct directory. -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MissingProjectException
Subprocess exited with error 1

これらの原因は、cdk init で生成される cdk.json というファイルです。

{
  "app": "mvn -e -q exec:java",
  "context": {
    "@aws-cdk/core:enableStackNameDuplicates": "true"
  }
}

以下のように書き換えます。

{
  "app": "sbt run",
  "context": {
    "@aws-cdk/core:enableStackNameDuplicates": "true"
  }
}

これで正しく動くようになります。

[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ cdk ls
[info] [launcher] getting org.scala-sbt sbt 1.3.4  (this may take some time)...
downloading https://repo1.maven.org/maven2/org/scala-sbt/sbt/1.3.4/sbt-1.3.4.jar ...
:: loading settings :: url = jar:file:/usr/local/sbt/bin/sbt-launch.jar!/org/apache/ivy/core/settings/ivysettings.xml
downloading https://repo1.maven.org/maven2/org/scala-sbt/main_2.12/1.3.4/main_2.12-1.3.4.jar ...
:: loading settings :: url = jar:file:/usr/local/sbt/bin/sbt-launch.jar!/org/apache/ivy/core/settings/ivysettings.xml
downloading https://repo1.maven.org/maven2/org/scala-sbt/io_2.12/1.3.1/io_2.12-1.3.1.jar ...
downloading https://repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.10/scala-library-2.12.10.jar ...
:: loading settings :: url = jar:file:/usr/local/sbt/bin/sbt-launch.jar!/org/apache/ivy/core/settings/ivysettings.xml
:: loading settings :: url = jar:file:/usr/local/sbt/bin/sbt-launch.jar!/org/apache/ivy/core/settings/ivysettings.xml
    [SUCCESSFUL ] org.scala-sbt#sbt;1.3.4!sbt.jar (1087ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/logic_2.12/1.3.4/logic_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#logic_2.12;1.3.4!logic_2.12.jar (460ms)
    [SUCCESSFUL ] org.scala-sbt#io_2.12;1.3.1!io_2.12.jar (1526ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/main-settings_2.12/1.3.4/main-settings_2.12-1.3.4.jar ...
downloading https://repo1.maven.org/maven2/org/scala-sbt/actions_2.12/1.3.4/actions_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#actions_2.12;1.3.4!actions_2.12.jar (595ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/run_2.12/1.3.4/run_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#main-settings_2.12;1.3.4!main-settings_2.12.jar (612ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/command_2.12/1.3.4/command_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#run_2.12;1.3.4!run_2.12.jar (452ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/collections_2.12/1.3.4/collections_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#command_2.12;1.3.4!command_2.12.jar (466ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/scripted-sbt-redux_2.12/1.3.4/scripted-sbt-redux_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-lang#scala-library;2.12.10!scala-library.jar (2808ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/scripted-plugin_2.12/1.3.4/scripted-plugin_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#scripted-sbt-redux_2.12;1.3.4!scripted-sbt-redux_2.12.jar (450ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-lm-integration_2.12/1.3.4/zinc-lm-integration_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#collections_2.12;1.3.4!collections_2.12.jar (569ms)
downloading https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.2.0/scala-xml_2.12-1.2.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#scripted-plugin_2.12;1.3.4!scripted-plugin_2.12.jar (441ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/launcher-interface/1.1.3/launcher-interface-1.1.3.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-lm-integration_2.12;1.3.4!zinc-lm-integration_2.12.jar (450ms)
downloading https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#launcher-interface;1.1.3!launcher-interface.jar (454ms)
downloading https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.11.2/log4j-core-2.11.2.jar ...
    [SUCCESSFUL ] org.scala-lang.modules#scala-xml_2.12;1.2.0!scala-xml_2.12.jar(bundle) (685ms)
downloading https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.11.2/log4j-slf4j-impl-2.11.2.jar ...
    [SUCCESSFUL ] org.apache.logging.log4j#log4j-api;2.11.2!log4j-api.jar (465ms)
downloading https://repo1.maven.org/maven2/com/github/cb372/scalacache-caffeine_2.12/0.20.0/scalacache-caffeine_2.12-0.20.0.jar ...
    [SUCCESSFUL ] org.apache.logging.log4j#log4j-slf4j-impl;2.11.2!log4j-slf4j-impl.jar (469ms)
downloading https://repo1.maven.org/maven2/io/get-coursier/lm-coursier-shaded_2.12/2.0.0-RC5-2/lm-coursier-shaded_2.12-2.0.0-RC5-2.jar ...
    [SUCCESSFUL ] com.github.cb372#scalacache-caffeine_2.12;0.20.0!scalacache-caffeine_2.12.jar (449ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-logging_2.12/1.3.2/util-logging_2.12-1.3.2.jar ...
    [SUCCESSFUL ] org.apache.logging.log4j#log4j-core;2.11.2!log4j-core.jar (811ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/librarymanagement-core_2.12/1.3.0/librarymanagement-core_2.12-1.3.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-logging_2.12;1.3.2!util-logging_2.12.jar (476ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/librarymanagement-ivy_2.12/1.3.0/librarymanagement-ivy_2.12-1.3.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#librarymanagement-core_2.12;1.3.0!librarymanagement-core_2.12.jar (601ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/compiler-interface/1.3.1/compiler-interface-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#compiler-interface;1.3.1!compiler-interface.jar (456ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-compile_2.12/1.3.1/zinc-compile_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#librarymanagement-ivy_2.12;1.3.0!librarymanagement-ivy_2.12.jar (687ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-relation_2.12/1.3.2/util-relation_2.12-1.3.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-relation_2.12;1.3.2!util-relation_2.12.jar (437ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/sjson-new-scalajson_2.12/0.8.2/sjson-new-scalajson_2.12-0.8.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-compile_2.12;1.3.1!zinc-compile_2.12.jar (445ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-position_2.12/1.3.2/util-position_2.12-1.3.2.jar ...
    [SUCCESSFUL ] com.eed3si9n#sjson-new-scalajson_2.12;0.8.2!sjson-new-scalajson_2.12.jar (448ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/shaded-scalajson_2.12/1.0.0-M4/shaded-scalajson_2.12-1.0.0-M4.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-position_2.12;1.3.2!util-position_2.12.jar (456ms)
downloading https://repo1.maven.org/maven2/org/spire-math/jawn-parser_2.12/0.10.4/jawn-parser_2.12-0.10.4.jar ...
    [SUCCESSFUL ] com.eed3si9n#shaded-scalajson_2.12;1.0.0-M4!shaded-scalajson_2.12.jar (463ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/completion_2.12/1.3.4/completion_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.spire-math#jawn-parser_2.12;0.10.4!jawn-parser_2.12.jar (468ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/task-system_2.12/1.3.4/task-system_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#completion_2.12;1.3.4!completion_2.12.jar (448ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/tasks_2.12/1.3.4/tasks_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#task-system_2.12;1.3.4!task-system_2.12.jar (524ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/testing_2.12/1.3.4/testing_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#tasks_2.12;1.3.4!tasks_2.12.jar (455ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-tracking_2.12/1.3.2/util-tracking_2.12-1.3.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#testing_2.12;1.3.4!testing_2.12.jar (465ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-classpath_2.12/1.3.1/zinc-classpath_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-tracking_2.12;1.3.2!util-tracking_2.12.jar (443ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-apiinfo_2.12/1.3.1/zinc-apiinfo_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-classpath_2.12;1.3.1!zinc-classpath_2.12.jar (459ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc_2.12/1.3.1/zinc_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-apiinfo_2.12;1.3.1!zinc-apiinfo_2.12.jar (453ms)
downloading https://repo1.maven.org/maven2/jline/jline/2.14.6/jline-2.14.6.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc_2.12;1.3.1!zinc_2.12.jar (448ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-control_2.12/1.3.2/util-control_2.12-1.3.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#main_2.12;1.3.4!main_2.12.jar (9125ms)
downloading https://repo1.maven.org/maven2/com/swoval/file-tree-views/2.1.3/file-tree-views-2.1.3.jar ...
    [SUCCESSFUL ] jline#jline;2.14.6!jline.jar (447ms)
downloading https://repo1.maven.org/maven2/net/java/dev/jna/jna/4.5.0/jna-4.5.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-control_2.12;1.3.2!util-control_2.12.jar (451ms)
downloading https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/4.5.0/jna-platform-4.5.0.jar ...
    [SUCCESSFUL ] net.java.dev.jna#jna;4.5.0!jna.jar (904ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-interface/1.3.2/util-interface-1.3.2.jar ...
    [SUCCESSFUL ] com.swoval#file-tree-views;2.1.3!file-tree-views.jar (1016ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/sjson-new-core_2.12/0.8.3/sjson-new-core_2.12-0.8.3.jar ...
    [SUCCESSFUL ] net.java.dev.jna#jna-platform;4.5.0!jna-platform.jar (839ms)
downloading https://repo1.maven.org/maven2/com/lmax/disruptor/3.4.2/disruptor-3.4.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-interface;1.3.2!util-interface.jar (434ms)
downloading https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.7.0/protobuf-java-3.7.0.jar ...
    [SUCCESSFUL ] com.eed3si9n#sjson-new-core_2.12;0.8.3!sjson-new-core_2.12.jar (577ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-cache_2.12/1.3.2/util-cache_2.12-1.3.2.jar ...
    [SUCCESSFUL ] com.lmax#disruptor;3.4.2!disruptor.jar (676ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/sjson-new-murmurhash_2.12/0.8.3/sjson-new-murmurhash_2.12-0.8.3.jar ...
    [SUCCESSFUL ] com.eed3si9n#sjson-new-murmurhash_2.12;0.8.3!sjson-new-murmurhash_2.12.jar (444ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/test-agent/1.3.4/test-agent-1.3.4.jar ...
    [SUCCESSFUL ] io.get-coursier#lm-coursier-shaded_2.12;2.0.0-RC5-2!lm-coursier-shaded_2.12.jar (7176ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar ...
    [SUCCESSFUL ] com.google.protobuf#protobuf-java;3.7.0!protobuf-java.jar(bundle) (1011ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/compiler-bridge_2.12/1.3.1/compiler-bridge_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-cache_2.12;1.3.2!util-cache_2.12.jar (987ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-classfile_2.12/1.3.1/zinc-classfile_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#test-agent;1.3.4!test-agent.jar (449ms)
downloading https://repo1.maven.org/maven2/com/jcraft/jsch/0.1.54/jsch-0.1.54.jar ...
    [SUCCESSFUL ] org.scala-sbt#test-interface;1.0!test-interface.jar (443ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/gigahorse-okhttp_2.12/0.5.0/gigahorse-okhttp_2.12-0.5.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#compiler-bridge_2.12;1.3.1!compiler-bridge_2.12.jar (446ms)
downloading https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp-urlconnection/3.7.0/okhttp-urlconnection-3.7.0.jar ...
    [SUCCESSFUL ] com.jcraft#jsch;0.1.54!jsch.jar (459ms)
downloading https://repo1.maven.org/maven2/com/eed3si9n/gigahorse-core_2.12/0.5.0/gigahorse-core_2.12-0.5.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-classfile_2.12;1.3.1!zinc-classfile_2.12.jar (670ms)
downloading https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp/3.14.2/okhttp-3.14.2.jar ...
    [SUCCESSFUL ] com.eed3si9n#gigahorse-okhttp_2.12;0.5.0!gigahorse-okhttp_2.12.jar (452ms)
downloading https://repo1.maven.org/maven2/com/typesafe/ssl-config-core_2.12/0.4.0/ssl-config-core_2.12-0.4.0.jar ...
    [SUCCESSFUL ] com.squareup.okhttp3#okhttp-urlconnection;3.7.0!okhttp-urlconnection.jar (447ms)
downloading https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar ...
    [SUCCESSFUL ] com.eed3si9n#gigahorse-core_2.12;0.5.0!gigahorse-core_2.12.jar (475ms)
downloading https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar ...
    [SUCCESSFUL ] org.reactivestreams#reactive-streams;1.0.2!reactive-streams.jar (454ms)
downloading https://repo1.maven.org/maven2/org/scala-lang/modules/scala-parser-combinators_2.12/1.1.2/scala-parser-combinators_2.12-1.1.2.jar ...
    [SUCCESSFUL ] com.typesafe#ssl-config-core_2.12;0.4.0!ssl-config-core_2.12.jar(bundle) (1013ms)
downloading https://repo1.maven.org/maven2/com/typesafe/config/1.3.3/config-1.3.3.jar ...
    [SUCCESSFUL ] org.slf4j#slf4j-api;1.7.26!slf4j-api.jar (783ms)
downloading https://repo1.maven.org/maven2/com/squareup/okio/okio/1.17.2/okio-1.17.2.jar ...
    [SUCCESSFUL ] org.scala-lang.modules#scala-parser-combinators_2.12;1.1.2!scala-parser-combinators_2.12.jar(bundle) (690ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-core_2.12/1.3.1/zinc-core_2.12-1.3.1.jar ...
    [SUCCESSFUL ] com.squareup.okhttp3#okhttp;3.14.2!okhttp.jar (1709ms)
    [SUCCESSFUL ] com.typesafe#config;1.3.3!config.jar(bundle) (693ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-persist_2.12/1.3.1/zinc-persist_2.12-1.3.1.jar ...
downloading https://repo1.maven.org/maven2/org/scala-sbt/zinc-compile-core_2.12/1.3.1/zinc-compile-core_2.12-1.3.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-core_2.12;1.3.1!zinc-core_2.12.jar (788ms)
downloading https://repo1.maven.org/maven2/com/trueaccord/scalapb/scalapb-runtime_2.12/0.6.0/scalapb-runtime_2.12-0.6.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-compile-core_2.12;1.3.1!zinc-compile-core_2.12.jar (672ms)
downloading https://repo1.maven.org/maven2/com/trueaccord/lenses/lenses_2.12/0.4.12/lenses_2.12-0.4.12.jar ...
    [SUCCESSFUL ] com.squareup.okio#okio;1.17.2!okio.jar (1405ms)
downloading https://repo1.maven.org/maven2/com/lihaoyi/fastparse_2.12/0.4.2/fastparse_2.12-0.4.2.jar ...
    [SUCCESSFUL ] com.trueaccord.lenses#lenses_2.12;0.4.12!lenses_2.12.jar (481ms)
downloading https://repo1.maven.org/maven2/com/lihaoyi/fastparse-utils_2.12/0.4.2/fastparse-utils_2.12-0.4.2.jar ...
    [SUCCESSFUL ] com.lihaoyi#fastparse_2.12;0.4.2!fastparse_2.12.jar (635ms)
downloading https://repo1.maven.org/maven2/com/lihaoyi/sourcecode_2.12/0.1.3/sourcecode_2.12-0.1.3.jar ...
    [SUCCESSFUL ] com.lihaoyi#fastparse-utils_2.12;0.4.2!fastparse-utils_2.12.jar (478ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/sbinary_2.12/0.5.0/sbinary_2.12-0.5.0.jar ...
    [SUCCESSFUL ] com.trueaccord.scalapb#scalapb-runtime_2.12;0.6.0!scalapb-runtime_2.12.jar (1505ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/core-macros_2.12/1.3.4/core-macros_2.12-1.3.4.jar ...
    [SUCCESSFUL ] com.lihaoyi#sourcecode_2.12;0.1.3!sourcecode_2.12.jar (482ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/protocol_2.12/1.3.4/protocol_2.12-1.3.4.jar ...
    [SUCCESSFUL ] org.scala-sbt#core-macros_2.12;1.3.4!core-macros_2.12.jar (518ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/template-resolver/0.1/template-resolver-0.1.jar ...
    [SUCCESSFUL ] org.scala-sbt#sbinary_2.12;0.5.0!sbinary_2.12.jar (743ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/ipcsocket/ipcsocket/1.0.0/ipcsocket-1.0.0.jar ...
    [SUCCESSFUL ] org.scala-sbt#template-resolver;0.1!template-resolver.jar (441ms)
downloading https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.10/scala-compiler-2.12.10.jar ...
    [SUCCESSFUL ] org.scala-sbt.ipcsocket#ipcsocket;1.0.0!ipcsocket.jar (455ms)
downloading https://repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.12.10/scala-reflect-2.12.10.jar ...
    [SUCCESSFUL ] org.scala-sbt#protocol_2.12;1.3.4!protocol_2.12.jar (1202ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/util-scripted_2.12/1.3.2/util-scripted_2.12-1.3.2.jar ...
    [SUCCESSFUL ] org.scala-sbt#util-scripted_2.12;1.3.2!util-scripted_2.12.jar (450ms)
downloading https://repo1.maven.org/maven2/com/github/cb372/scalacache-core_2.12/0.20.0/scalacache-core_2.12-0.20.0.jar ...
    [SUCCESSFUL ] com.github.cb372#scalacache-core_2.12;0.20.0!scalacache-core_2.12.jar (457ms)
downloading https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/2.5.6/caffeine-2.5.6.jar ...
    [SUCCESSFUL ] com.github.ben-manes.caffeine#caffeine;2.5.6!caffeine.jar (1017ms)
downloading https://repo1.maven.org/maven2/org/scala-sbt/ivy/ivy/2.3.0-sbt-cb9cc189e9f3af519f9f102e6c5d446488ff6832/ivy-2.3.0-sbt-cb9cc189e9f3af519f9f102e6c5d446488ff6832.jar ...
    [SUCCESSFUL ] org.scala-sbt#zinc-persist_2.12;1.3.1!zinc-persist_2.12.jar (5683ms)
    [SUCCESSFUL ] org.scala-sbt.ivy#ivy;2.3.0-sbt-cb9cc189e9f3af519f9f102e6c5d446488ff6832!ivy.jar (1037ms)
    [SUCCESSFUL ] org.scala-lang#scala-reflect;2.12.10!scala-reflect.jar (6224ms)
    [SUCCESSFUL ] org.scala-lang#scala-compiler;2.12.10!scala-compiler.jar (8766ms)
:: retrieving :: org.scala-sbt#boot-app
    confs: [default]
    81 artifacts copied, 0 already retrieved
[info] [launcher] getting Scala 2.12.10 (for sbt)...
downloading https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.0.6/scala-xml_2.12-1.0.6.jar ...
downloading https://repo1.maven.org/maven2/org/fusesource/jansi/jansi/1.12/jansi-1.12.jar ...
    [SUCCESSFUL ] org.fusesource.jansi#jansi;1.12!jansi.jar (1318ms)
    [SUCCESSFUL ] org.scala-lang.modules#scala-xml_2.12;1.0.6!scala-xml_2.12.jar(bundle) (2602ms)
:: retrieving :: org.scala-sbt#boot-scala
    confs: [default]
    6 artifacts copied, 0 already retrieved
[info] Loading project definition from /home/zsh/cdk/project
[info] Loading settings for project cdk from build.sbt ...
[info] Set current project to hello-world (in build file:/home/zsh/cdk/)
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
[info] Compiling 2 Scala sources to /home/zsh/cdk/target/scala-2.13/classes ...
[info] Non-compiled module 'compiler-bridge_2.13' for Scala 2.13.1. Compiling...
8 warnings found
[info]   Compilation completed in 7.349s.
[info] Done compiling.
[info] running com.myorg.CdkApp 
[success] Total time: 27 s, completed Dec 10, 2019 2:32:33 PM
CdkStack
[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ 

cdk.json の記述を変えれば Gradle などでも動きそうですね。

cdk deploy

[zsh@bd8ee7c9cbb6 cdk (master *+%)]$cdk deploy
[info] Loading project definition from /home/zsh/cdk/project
[info] Loading settings for project cdk from build.sbt ...
[info] Set current project to hello-world (in build file:/home/zsh/cdk/)
[info] running com.myorg.CdkApp 
[success] Total time: 2 s, completed Dec 10, 2019 2:33:53 PM
CdkStack: deploying...
CdkStack: creating CloudFormation changeset...
 0/2 | 2:34:07 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata 
 0/2 | 2:34:09 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated
 1/2 | 2:34:09 PM | CREATE_COMPLETE      | AWS::CDK::Metadata | CDKMetadata 
 2/2 | 2:34:11 PM | CREATE_COMPLETE      | AWS::CloudFormation::Stack | CdkStack 

 ✅  CdkStack

Stack ARN:
arn:aws:cloudformation:us-west-2:XXXXXXXXXXXX:stack/CdkStack/xxxxxxxx-xxxx-xxxx-xxxx-067aa3cae1e0
[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ 

これで CloudFormation Stack が出来ました。 f:id:poad1010:20191210233704p:plain

当然ながら、それで作られるリソースも居ます。 f:id:poad1010:20191210233810p:plain

cdk destroy

cdkで作ったStackやリソースを削除するには、 cdk destroy を使います。

[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ cdk destroy
[info] Loading project definition from /home/zsh/cdk/project
[info] Loading settings for project cdk from build.sbt ...
[info] Set current project to hello-world (in build file:/home/zsh/cdk/)
[info] running com.myorg.CdkApp 
[success] Total time: 2 s, completed Dec 10, 2019 2:38:36 PM
Are you sure you want to delete: CdkStack (y/n)? y
CdkStack: destroying...

 ✅  CdkStack: destroyed
[zsh@bd8ee7c9cbb6 cdk (master *+%)]$ 

これで CloudFormation Stack が削除されました。 f:id:poad1010:20191210234013p:plain f:id:poad1010:20191210234024p:plain

流石に CloudFormation や CDK の API は調べていただくということで、説明はここまでとなります。

まとめ

以下の設定を行うだけで、とても簡単にAWS CDK を Scala で使うことが出来ました。

ただし、CDKのAPIが良くできていて、Scalaでやるメリットは大きくはなさそうです。(メリットがあるケースはアプリもScalaだから、CDKもScalaで使いたいといった言った程度でしょうか?)

検証コード

今回作った検証コードは こちら

GitHub Actions で AWS CDK

はじめに

AWS Advent Calendar 2019 - Qiita の 10日目への寄稿です。

AWS CDK が 2019年7月11日に、 GitHub Actions が 2019年11月14日にそれぞれ GAと なりました。 qiita.com のようにGitHub へクレデンシャルを登録しておけば、 GitHub Actions を使って CDK によるCloudFormation Stack の構築が出来るのでは無いか?と思い立ったので試してみました。 今回はPythonで記述してみようと思います。

環境構築

GitHub Actions では、Docker コンテナーを使うということで CDK 入りの軽量なコンテナーとなる Dockerfile を github.com 作りました。 そして、CDK を使って CloudFormatuon Stac kを構築するためのコードと、それを動かす GitHub Workflow は GitHub - poad/Advent に置いています。 リポジトリーを分けた方が理解しやすいこともあって分けています。

そもそも Action と Workflow って何?

GitHub Actions では、Action と呼ばれる機能を作成したり、既に用意されている Action を Workflow から呼び出して CI/CD を行います。

Action

後述する Workflow から呼び出して実行するための機能。 Docker コンテナー上で実行される。 action.yml で定義する。

Workflow

前述した Action をパラメーターと共に順に実行していく手順をYAMLで記述したもの。 .github/workflows/main.yml で定義する。

CodePipeline との比較

ざっくりとCodePipeline と比較してみます。

CodePipeline GitHub Actions
GitHub との親和性
AWS との親和性
単発実行 ×

※ 上記評価はあくまでも個人的な主観です

GitHub との親和性

CodePipeline では、GitHubリポジトリーとブランチしか指定出来ません。 一方、GitHub Actions では、リポジトリーとブランチの組み合わせ以外にも、リポジトリーとタグの組み合わせを指定できるほか、 push 以外を起動トリガーと出来ます。

AWS との親和性

当然ながら、CodePipeline であれば CloudFormation や ECS など、様々なサービスのデプロイを既存の Action として指定できます。 また、GitHub Actions はAWSのクレデンシャルを使用して AWS CLIAWS CDK を使用します。 IAM ロールなどを絞りたい場合に専用の IAM ユーザーを作成して絞る必要があります。 一方、CodePipeline では、CodePipeline 自体やそこから呼び出す AWS のサービス向けの IAM ロールを CodePipeline 毎に作成・指定することが出来ます。

単発実行

GitHub Actions では、リポジトリーへの push などを行わないと実行できません。 同じコード、設定で 再デプロイしたい場合に実行する方法がなさそうです。

Action を作ってみる

実は、AWS CDK GitHub Actions · Actions · GitHub Marketplace · GitHub として既に CDK を使うための GitHub Actions があります。 そのまま使用すればいいのですが、それでは記事にならないどころか、必要となった場合に作り方が分からなくなります。

そこで、上記のActionを参考に自分で作ってみます。

Dockerfile

alpine:3npmpython3pipawsclicdk をインストールします。 entrypoint.sh として、CDK のコードで使用する Python module のインストールを行い、 workflow で指定された各サブコマンドを実行するシェルスクリプトを ENTRYPOINT とします。

action.yml

Action の定義を行います。

action.yml のシンタックスMetadata syntax for GitHub Actions - GitHub Help

workflow を作る

.github/workflows/main.yml を作ります。 main.yml 以外に YAML ファイルを置いた場合にどう動くのかは試してません。 先述したとおり、ビルドやデプロイなど、どういった作業の流れなのかを定義したファイルです。 その名の通りですね。

ちなみに、シンタックスWorkflow syntax for GitHub Actions - GitHub Help

step が CodePipeline の Actionのような位置づけで、uses で GitHub Action を指定して with で指定したパラメーターが、 INPUT_プレフィックスが付いて、大文字化された値が環境変数としてActionのDockerコンテナーに渡されます。

なので、例えば cdk_subcommandINPUT_CDK_SUBCOMMAND となります。

今回は、 working_dir で指定した相対パスとなるように cdk init を行っている点がポイントです。

これを、workflow でビルドやデプロイしたいリポジトリーへ push します。

cdk init/CDK を使うコードの作成

ここに関しては、特にこの記事のテーマとしては特記することはありません。
ただ単に、CDK が動く環境で以下のコマンドを実行するだけです。 今回は、 cdk init で作られる CloudFormation Stack が作られれば良いため、特に Python のコードの追加・変更・削除は行っていません。

cdk init --language python

苦労した点

  • GitHub Actions という名前の紛らわしさ
    Action 定義あっての workflow と勘違いしてしまう。。。
    GitHub Workflow なら、やりたい目的を達成するために Action という部品を組み合わせて workflow で処理するんだとわかりやすいと思うのですが、
    個々の Action がメインのようなサービス名なのがイマイチ。
    Action が使いたいのではなくて、ビルドしたりデプロイしたりするのを自動化したいから、目的を達成するのに名前が非直感的かな?と。
    些細なことですが、理解するのに苦労した理由の一つのように思えます。

  • 実は workflow やその中のAction で使うコード(ビルド・デプロイ対象) は clone する step が必要
    actions/checkout@v1 という Action を指定した step があります。
    これは、Action の Docker コンテナーが実行時にマウントする WORKSPACE の場所へ、
    その workflow 定義がコミットされているリポジトリーの内容を clone するためのものです。
    これが必要であると気づくまでが、最も時間を要しました。
    workflow 定義と共に clone されているのですが、そのパスはマウントされないですし、
    Action 定義でもマウント出来るようには出来なくて困りました。
    まぁ、他のリポジトリーのコードがビルド対象です!と言った場合に、確かにその方が要らぬコードが混入しないので正しいかも。

  • Docker のbest practice に従った対応を入れていると動かないことも
    Docker コンテナー内で作業を行うユーザーが root でないと、ファイルアクセスのパーミッションが無くて動きません。 工夫すれば動くのかも知れませんが、流石にそこまでのメリットはなさそう。。。

参考にしたサイト

qiita.com

zshでgit switchが補完されるようにする

前回の記事で、Ubuntuzshをインストールしたはいいが、git switch が補完されずに困っていた。 poad1010.hatenablog.com

調べてみると、こんなIssue が! github.com

どうやら、gitリポジトリのmasterにあるgit-completionを使えば良さそう。

mkdir -p ~/.zsh
curl -o ~/.zsh/git-completion.bash https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash
curl -o ~/.zsh/_git https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.zsh

echo "# Load completion files from the ~/.zsh directory." >> ~/.zshrc
echo "zstyle ':completion:*:*:git:*' script ~/.zsh/git-completion.bash" >> ~/.zshrc
echo "fpath=(~/.zsh $fpath)" >> ~/.zshrc

echo "autoload -Uz compinit && compinit" >> ~/.zshrc

これでzshを立ち上げ直したら、見事!git switch が保管できた!

ちなみに、git switchは、最近、checkout -b ではなく、switch -c を使えだとか、checkoutの代わりにswitchを使えという流れみたいなので、gitをアップデートして、switchコマンドに慣れておいた方がいい。

この辺を読めば、Ubuntu bionicでも最新のgitが使える。 text.baldanders.info

zshでzsh-completions

目的

家の macOS Catalina をようやく、bash から zsh へ移行した。 bashよりも使いやすいため、Dockerコンテナーを使って設定を試し、その手順を書き残そうと思う。

手順

docker pull

docker pull ubuntu:bionic

docker run と最新化

docker run --rm -it --name ubuntu ubuntu:bionic bash
apt update -qq
apt full-upgrade -qqy

zsh と git のインストール

apt install -qqy --no-install-recommends git ca-certificates
apt install -qqy --no-install-recommends zsh

Prezto のインストール

zsh
cd $HOME
git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
setopt EXTENDED_GLOB
for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
  ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
done

これで Prezto のインストールはOK

zsh-completions

git clone https://github.com/zsh-users/zsh-completions.git  "${ZDOTDIR:-$HOME}/.zsh-completions"
echo 'fpath=(${ZDOTDIR:-$HOME}/.zsh-completions/src $fpath)' >> $HOME/.zshrc

zsh-completions のインストールもこれで良い。

というか。。。

公式サイトの手順でaptリポジトリーを追加しようにも、証明書の期限切れ?らしくてエラーとなるオプションで回避出来はするはずだけども、セキュリティー的によくないからやってない。 https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-completions&package=zsh-completions

echo 'deb http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04/ /' > /etc/apt/sources.list.d/shells:zsh-users:zsh-completions.list
wget -nv https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/xUbuntu_18.04/Release.key -O Release.key
apt-key add - < Release.key
apt update -qq
W: GPG error: http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04  InRelease: The following signatures were invalid: EXPKEYSIG 9CBE063CAB8FE1F1 shells:zsh-users:zsh-completions OBS Project <shells:zsh-users:zsh-completions@build.opensuse.org>
E: The repository 'http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04  InRelease' is not signed.

bashのcomplationよりも優秀で、↓のように候補が一覧表示されたりする、

$ git c<tab>
 -- common commands --
checkout  -- checkout a branch or paths to the working tree
clone     -- clone a repository into a new directory
commit    -- record changes to the repository

追記

テーマ変更の方法もメモしとく

# テーマ一覧
prompt -l
 
# テーマをプレビュー
prompt -p <テーマ名>
 
# すべてのテーマをプレビュー
prompt -p
 
# テーマを適用(再起動したら戻る)
prompt <テーマ名>

# テーマ適用(.zpreztorc)
zstyle ':prezto:module:prompt' theme '<テーマ名>'

個人的には、元のbashみたいに見える redhat テーマが好き

OpenJDK まとめ(2019年5月6日版)

Oracle JDKの公開アップデート提供が終了したことで色々と騒ぎになっていますが、 サードパーティ製のOpenJDK(OpenJDKのディストリビューション)を使えば大抵は解決するだろう。 楽観的ではなくOracleJava 11をリリースするタイミングで、 JavaFXJava Mission Control/Java Flight RecorderなどをOSS化しているので、 乗り換えれば良いというお話です。

ちなみに、JavaJava SEが有償化したのではなく、 OpenJDKのディストリビューションのひとつである Oracle JDK の公開アップデートが終了した話のまとめは 「Java 有償化」で誤解する人になるべく分かりやすく説明するためのまとめ - Togetter や、なぜ「Javaが有償化する」と誤解されてしまうのか考えてみる - kazokmr's Blog をご覧下さい。

さて、ここからが本題。

数あるOpenJDKのうち、どれを使えばいいの?ということになりそうなので、 OpenJDKのディストリビューションにはどんなものがあるかご紹介します。

※ 筆者はJavaのいちユーザーに過ぎないため、細かい間違いなどはあるかと思いますがご了承ください。

OpenJDK (Oracle公式バイナリ)

OpenJDK

Oracleが中心(あくまでも中心であって、Oracle以外のベンダーも開発に参加しています。新機能の追加は主にOracleらしいです。)に開発されているOpenJDKのOpenJDKプロジェクトによるビルド。 6ヶ月毎にアップデートされて行く。 メジャーバージョンが変わって行くものの、実は今までのOracle JDKでは、 同じメジャーバージョンのアップデートリリースで機能追加が行われていたものが、 きちんと不具合修正のみと機能追加を含むという採番ルールに変わっただけという。。。

JDKの新しいリリース・モデル、および提供ライセンスについて

Red Hat版OpenJDK (この子はだけは無償ではないです)

Red Hat Developer | Red Hat OpenJDK Download

OpenJDKのセキュリティアップデートなどは、JDK 7の頃からRed Hat(最近、RedとHatの間にスペース入るようになったらしい。どうでもいいけど)が中心に行っているそうで、Red Hat Enterprise Linuxと、Windows版が提供されている。

LTSサポートあり。

無償で使えるのはWindows版(おそらくWindows Serverを除く?)だけなので、開発者向けの配布だそうです。

開発者向けの配布で、商用利用はサブスクリプションに加入する必要があるとのこと。

LIBERICA JDK

BellSoft | Java Platform and Applications Experts

BellSoft が提供しているOpenJDKディストリビューション。 LTSサポートあり。 AlpineLinux (must-libc)版あり?(少なくともDockerイメージは提供されています) JavaFX(多分OpenFX)も付属。 Windowsの32bit版もある。

多分、未だJigsaw対応出来ていなくて、Java 8のままなんだけども。。。というプロジェクトや、幾ら何でも6ヶ月毎の更新は対応が間に合わないという型の乗り換え先の最有力候補なんじゃなかろうか?

現状、後述のZuluの方がAlpineLinux対応はしっかりしているらしいです。

Zulu Enterprise

Get Java Support OpenJDK Support subscriptions Java Security Updates

Azul Systemsが提供しているOpenJDKディストリビューション。 LTSサポートあり。 AlpineLinux (must-libc)版あり。 ライセンスはOpenJDKと同じGPLv2+クラスパス例外。 Java 11からはLICENSE テキストファイルが同封されなくなったが、同封のreadme.txtに記載されている。 また、それに加えてZulu/Azul Systemsの免責事項などが記載された利用規約が存在する。(記述内容がGPLv2+クラスパス例外と矛盾する場合はGPLv2+クラスパス例外が優先されるようなことが英語で書かれている)

LIBERICA JDKの次に有力な候補ではないかと思われる。(特にAlpineLinuxを使う場合)

ちなみに、ソースコードは要求しないと貰えないようです。 (昔のインターネット回線が遅かったり、常時接続じゃなかった頃を思い出させられる)

Amazon Corretto

Amazon Corretto(本番環境に対応したOpenJDKディストリビューション)| AWS

Amazon(AWS)が提供しているOpenJDKディストリビューション。 LTSサポートあり。 Windows版、Mac版もある。 基本的にはAmazon Linux向けかな? Javaの父であるJames Goslingは、現在Amazonに所属していることもあって話題となった。 Amazon Linux 2ベースで動いているJavaアプリは、これを使うのが良いのだろう。 (うちのプロジェクトは、AWSに乗っていても、後発のAmazon Linuxに乗り換えてすらいないで 他のOpenJDKディストリビューションに乗り換えましたけどね)

SapMachine

SapMachine | An OpenJDK release maintained and supported by SAP

SAPが提供が提供しているOpenJDKディストリビューション。 LTSサポートあり。 PPCLinux版があるのが特徴。

AdoptOpenJDK

AdoptOpenJDK - Open source, prebuilt OpenJDK binaries

AdoptOpenJDKコミュニティが提供しているOpenJDKディストリビューション。 AdoptOpenJDKプロジェクト自体は、OpenJDKのビルドファームということで、 マイクロソフト含めて様々なベンダーがスポンサーとなっている。 HotSpot VM(Oracle JDKをはじめ、各OpenJDKディストリビューションはこれ)ベースと、 IBMのOpenJ9ベースの両方を提供しているのが特徴。 LTSサポートあり。

ただし、政治的な都合でTCKと呼ばれる互換性確認テストを通せていない。 (AdoptOpenJDKをTCK通したら、他のOpenJDKディストリビューションの存在意義が皆無になるから、 Oracleが嫌がっているという風の噂も。。。噂ですからね)

ちなみに、Windows版にOpenFXをバンドルする予定があるとか。

おまけ

IcedTea

https://icedtea.classpath.org/wiki/Main_Page

Java 8までのRed HatのOpenJDKディストリビューション。 (ページタイトルがMainPageって。。。)

IcedTea-Web

IcedTea-Web - IcedTea

上記IceTeaから分離したJava Web StartOSS実装。 今後、Java Web Startを無償で使うなら、IceTea-Webになるのだろう。

謝辞

OpenJDKソムリエの @yamadamn さん、ご確認およびご指摘いただきましてありがとうございました。

Vagrant で Tiny Core Linux!

boot2docker を使ってみたところ、その起動の速さに驚かされた。 そこで、Vagrant でTiny Core Linuxを使ったら起動が早くてカスタマイズしやすいヘッドレスなLinux環境が構築できるのでは?と思ったのでやってみた。

  1. Tiny Core Linuxのインストール 公式サイトからCorePlusのISOイメージをダウンロードしてインストール。

  2. Vagrant Box化するために色々と設定(ここがハマりどころポイントその1) 2.1. vagrant ユーザーの追加 2.2. (ここ重要!) /etc/sudoers に vagrant ユーザーを追加 visudoなんて使えないので、vimなりechoなり。。。 2.3. curl と opensshをインストール tceやtc-load使います。 2.4. (ここ重要!) /opt/bootlocal.sh に 以下を追加

/usr/local/etc/init.d/openssh start

2.5. (ここも重要!) sshd_config を作成 とりあえずコピーで大丈夫です。

cp /usr/local/etc/ssh/sshd_config.orig /usr/local/etc/ssh/sshd_config

2.6. (ここ超重要!!!) /opt/.filetool.lst に変更したファイルパスを追加する こんな感じになります。

opt
home
etc/shadow
etc/passwd
etc/sudoers
usr/local/etc/ssh/sshd_config

2.7. (ここも超重要!!!) filetool.sh -b してバックアップに含める Tiny Core Linux は、起動毎にルートファイルシステムをバックアップから復元している(?)ようで、これをしないで再起動すると、変更が吹き飛びます。 2.8. VM再起動 2.9. (やや重要) ホストのSSH鍵を /opt/.filetool.lstに追加してfiletool.sh -b 2.10. (基本) Vagrantの公開鍵を /home/vagrant/.ssh配下に配置する

  1. Box 化
  2. (やや重要) Vagrantfileの編集(なければ作って) こんなんになります。
module VagrantPlugins
  module GuestTinyCoreLinux
    module Cap
      class Halt
        def self.halt(machine)
          begin
            machine.communicate.sudo('poweroff')
          rescue Net::SSH::Disconnect, IOError
            # Ignore, this probably means connection closed because it
            # shut down and SSHd was stopped.
          end
        end
      end
    end
    class Guest < Vagrant.plugin('2', :guest)
      def detect?(machine)
        machine.communicate.test('[ "$(cat /etc/os-release | grep ^NAME | cut -d = -f2)" = "TinyCore" ]')
      end
    end
  end
end

Vagrant.configure("2") do |config|
  config.vm.define "tinycore" do |config|
    config.vm.box = "poad/tinycorelinux"
    config.ssh.username = "vagrant"
    config.ssh.password = "vagrant"
    config.ssh.shell = "sh"
    config.vm.synced_folder ".", "/vagrant", disabled: true
    config.vm.boot_timeout = 75
    config.vm.graceful_halt_timeout = 35
    config.vm.provider "virtualbox" do |vb|
      vb.memory = "2048"
    end
  end
end

解説

module VagrantPlugins
  module GuestTinyCoreLinux
    module Cap
      class Halt
        def self.halt(machine)
          begin
            machine.communicate.sudo('poweroff')
          rescue Net::SSH::Disconnect, IOError
            # Ignore, this probably means connection closed because it
            # shut down and SSHd was stopped.
          end
        end
      end
    end
    class Guest < Vagrant.plugin('2', :guest)
      def detect?(machine)
        machine.communicate.test('[ "$(cat /etc/os-release | grep ^NAME | cut -d = -f2)" = "TinyCore" ]')
      end
    end
  end
end

は、Vagrant Plugin の記述になります。 Tiny Core Linux か否かを Guest classの detect?メソッドを使用して確認します。(/etc/os-releaseのNAMEが TinyCoreであれば有効となるプラグインとなります。) Tiny Core Linux であれば、vagrant halt コマンドの実体は poweroff を使うようにしています。

これで、Tiny Core Linux の起動と終了には問題が無くなった。 VirtualBoxの共有フォルダーが使えない?は仕方ない。

OpenBSDをVirtualBoxだけでUEFIインストール

VirtualBoxを使用して、UEFI起動するOpenBSD 6.4のVMを作成する手順です。 UEFI起動するようにOpenBSD 6.4をインストールするには、 公式の手順ではUSB FlashモリーなどのUSB接続のストレージが必要となってしまいます。 でも、VM作るのにUSB接続のストレージなんか使いたくない!って人のための手順です。

  1. Linux VM(〜BSDVMでも良いし、VirtualBoxでマウント出来るディスクイメージへdd出来るなら、ホストOSを使っても良い)を用意します。
  2. Linux VMに1GBくらいの仮想HDDを追加します。
  3. https://www.openbsd.org/faq/faq4.html#Download から、installXX.fs をダウンロードします。
  4. Linux VMから 2.で追加した仮想HDDへ、ddコマンドを使用してinstallXX.fs イメージを書き込みます。(ここ重要)
  5. OpenBSDをインストールするVMを作成し、installXX.fs イメージを書き込んだ仮想HDDを接続します。
  6. このこのVMには、OpenBSDをインストールする先の仮想HDDも必要となります
    1. VMUEFIオプションを有効にして起動すると、OpenBSDインストーラーが起動するため、画面に従ってインストールを行います。

本当なら、installXX.iso や cdXX.isoでUEFI起動出来ればいいのですけどね。。。

余談ですが、上記手順でインストールして、拙著のQiita記事qiita.com の手順に構築したVagrant Boxもあります。 app.vagrantup.com