Raspbian に Java 9 をインストール
Raspbian の Oracle Java 8 のバージョンを確認してみます。
$ sudo -s # apt update # apt search oracle-java8-jdk oracle-java8-jdk/stable 8u65 armhf Java™ Platform, Standard Edition 8 Development Kit
合わせて、OpenJDK の方も確認してみます。
# apt search openjdk-8-jdk default-jdk/stable 2:1.8-58+b2 armhf Standard Java or Java compatible Development Kit default-jdk-headless/stable 2:1.8-58+b2 armhf Standard Java or Java compatible Development Kit (headless) openjdk-8-jdk/stable 8u171-b11-1~deb9u1 armhf OpenJDK Development Kit (JDK) openjdk-8-jdk-headless/stable 8u171-b11-1~deb9u1 armhf OpenJDK Development Kit (JDK) (headless)
OpenJDK の方は、8u171 なのに対して、もう一方は 8u65 ともう更新されることはないような雰囲気です。
今回、Java 8 にこだわるつもりもないので、最新をと思いたちましたが、まだ Java 10 はなかったので、Java 9 をインストールすることにしました。
# apt search jdk # apt install openjdk-9-jdk -y
openjdk-9-jdk をインストール後、以前のバージョンの JDK は削除したかったので、find /usr -name 'java'
、dpkg -l | grep gcj
、dpkg -l | grep jdk
などして、不要となったパッケージが残っていないか確認して、apt remove
で削除しました。
Java 8 と Java 10 での MixerInfo の並び順の違い
macOSでJDKのインストールにsdkmanを使っての話ですが、Java 8では声を出してくれていたコードが、Java 10で実行すると喋らないなと悩んでいたのですが、 単純にAudioSystem.getMixerInfo()が返す順序が変わっていただけということだった。
確認するためのコードは、こんな感じ
package jp.pigumer.javasound import javax.sound.sampled.AudioSystem object MixerInfoList extends App { val info = AudioSystem.getMixerInfo() info.zipWithIndex.foreach { case (mi, index) ⇒ println(s"$index: ${mi.getName}") } }
Java 8(Oracle JDK)
java version "1.8.0_171" Java(TM) SE Runtime Environment (build 1.8.0_171-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode) 0: Default Audio Device 1: Built-in Microphone 2: Built-in Output 3: Port Built-in Microphone 4: Port Built-in Output
Java 10(Oracle JDK)
java version "10.0.1" 2018-04-17 Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10) Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode) 0: Port Built-in Microphone 1: Port Built-in Output 2: Default Audio Device 3: Built-in Microphone 4: Built-in Output
Java 10(OpenJDK)
openjdk version "10" 2018-03-20 OpenJDK Runtime Environment 18.3 (build 10+46) OpenJDK 64-Bit Server VM 18.3 (build 10+46, mixed mode) 0: Port Built-in Microphone 1: Port Built-in Output 2: Default Audio Device 3: Built-in Microphone 4: Built-in Output
ECS タスクを Fargate でスケジュール起動
Fargate で ECS タスクを起動するためには、launchType で "FARGATE"、ネットワーク設定で awsvpc として、サブネット、セキュリティグループ等を設定する必要があります。 これらのことが、CloudWatch Event の Rule でまだ設定することができないようです。
そのため、以下のような Lambda Function を作成して、Lambda で タスクを起動するようにしてみました。
import boto3 def lambda_handler(event, context): client = boto3.client('ecs') response = client.run_task( cluster = '${ClusterArn}', taskDefinition = '${TaskArn}', count = 1, launchType = 'FARGATE', networkConfiguration = { 'awsvpcConfiguration': { 'subnets': [ '${Subnet1}', '${Subnet2}' ], 'securityGroups': [ '${SecurityGroup}' ], 'assignPublicIp': 'ENABLED' } } ) print(response) return 'Success'
run_task の cluster には、ECS Cluster の Arn を、taskDefinition には TaskDefinition の Arn が必要になります。 また、サブネット名、セキュリティグループ名も必要です。これらを、CloudFormation のテンプレートで、Export された値を ImportValue してデプロイするように、プロジェクトを作成してみました。
Fargate がついに東京に
Service
首を長くして待ってましたが、ついに Fargate が東京にやってきました。 ということで、以前米国東部 (バージニア北部) に作っていたものを、 東京(ap-northeast-1)に変えて実行してみました。
GitHub - PigumerGroup/aws-ecs-fargate
Task
polly で mp3 を生成してそれを S3 に保存する Task を Fargate で実行できるようにしてみました。
GitHub - PigumerGroup/sbt-aws-cloudformation-example
両方とも、ちゃんと実行できましたぁ。うれしい。
これからは、どんどん ECS を使っていきたい気持ちです。
スレッド数を CloudWatch のカスタムメトリクスとして Publish する
micrometer を使ってスレッド数を CloudWatch のカスタムメトリクスとして Publish してみました
// https://mvnrepository.com/artifact/io.micrometer/micrometer-registry-cloudwatch libraryDependencies += "io.micrometer" % "micrometer-registry-cloudwatch" % "1.0.5"
package com.pigumer.example; import java.util.Properties; public class MicrometerProperties { public Properties DEFAULT; public MicrometerProperties() { DEFAULT = new Properties(); DEFAULT.setProperty("cloudwatch.enabled", "true"); DEFAULT.setProperty("cloudwatch.namespace", "MICROMETER"); DEFAULT.setProperty("cloudwatch.step", "PT1M"); DEFAULT.setProperty("cloudwatch.batchSize", "1"); } }
package com.pigumer.example; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClientBuilder; import io.micrometer.cloudwatch.CloudWatchConfig; import io.micrometer.cloudwatch.CloudWatchMeterRegistry; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; import java.time.Duration; import java.util.Properties; import java.util.stream.IntStream; public class Main { private static AmazonCloudWatchAsync cloudWatch = AmazonCloudWatchAsyncClientBuilder.standard().withRegion("ap-northeast-1").build(); private static Clock clock = Clock.SYSTEM; private static CloudWatchConfig config = new CloudWatchConfig() { private Properties properties = new MicrometerProperties().DEFAULT; @Override public String get(String key) { return properties.getProperty(key); } }; private static Runnable sleep = () -> { try { Thread.sleep(60000); } catch (Exception e) { e.printStackTrace(); } }; public static void main(String[] args) throws Exception { CloudWatchMeterRegistry registry = new CloudWatchMeterRegistry(config, clock, cloudWatch); new JvmThreadMetrics().bindTo(registry); IntStream.range(1, 20).forEach(n -> new Thread(sleep).run()); Thread.sleep(60000 * 3); } }
スレッド数を CloudWatch のカスタムメトリクスとして Publish する
package jp.pigumer.monitor; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync; import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClientBuilder; import com.amazonaws.services.cloudwatch.model.Dimension; import com.amazonaws.services.cloudwatch.model.MetricDatum; import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest; import com.amazonaws.services.cloudwatch.model.StandardUnit; import java.lang.management.ManagementFactory; import java.util.Date; public class CloudWatchReporter implements Runnable { private AmazonCloudWatchAsync cloundwatch = AmazonCloudWatchAsyncClientBuilder.standard().build(); private String id; public CloudWatchReporter(String id) { this.id = id; } @Override public void run() { Double count = (double) ManagementFactory.getThreadMXBean().getThreadCount(); MetricDatum metricData = new MetricDatum() .withDimensions(new Dimension().withName("Id").withValue(id)) .withMetricName("thread_count") .withUnit(StandardUnit.Count) .withValue(count) .withTimestamp(new Date()); PutMetricDataRequest request = new PutMetricDataRequest() .withNamespace("CUSTOM/TEST") .withMetricData(metricData); cloundwatch.putMetricDataAsync(request); } }
この CloudWatchReporter を 1 分間隔で実行して CloudWatch に Publish します。
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); ScheduledFuture handler = scheduler.scheduleAtFixedRate( new CloudWatchReporter("test"), 0, 1, TimeUnit.MINUTES);
TOTP - Time-Based One-Time Password
TOTP について調べるため、AWS の MFA で使うことのできる 仮想 MFA アプリケーションと同様の機能を持つアプリケーションを作成してみました。
TOTP の仕様
- RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm
- RFC 6238: TOTP: Time-Based One-Time Password Algorithm
使い方
ユーザのホームディレクトリに .onetime というディレクトリを作成し、そのディレクトリに onetime.properties というファイルを作成します。
$ mkdir ~/.onetime $ cat > ~/.onetime/onetime.properties
onetime.properties には、AWS の MFA を有効にしたときに表示されるシークレットキーを設定します。
secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX