gradleビルドを高速化したい
非常に柔軟なビルドスクリプトが書けるGradle
業務システム界隈ではまだまだ普及期、Android界隈では標準といった具合の知名度でしょうか。 柔軟な記載ができる一方でgoovyのシンタックスシュガーに悩まされている方も多いのではないでしょうか。 私もその一人です。ちなみに特にこの記事でgradleの文法について触れるつもりはありません。
今回は高速化のお話
ローカル環境にしてもCI環境にしてもビルド時間は短いに越したことはないですよね。 開発者フィードバックが早まるため、バグの検出が前倒し出来て生産性の向上に直結します。 最近はそのあたりの課題に取り組んでいたので知見を書き残しておこうと思います。
まずは計測
課題解決は現状と理想を定義するところから始まります。 何かビルドが遅い気がするからなんとかしたい、ではなく「ベストプラクティスとしては一回のビルドが〇分以内と定義されているから今のビルド時間とギャップがある」のように具体的に課題を設定しましょう。 計測にはJUnitが出してくれるレポートや、gradle自体にもレポートや分析の機能が搭載されているため、利用しましょう。 調査の結果、実はビルドが遅いわけではなかった、なんて結論になるかもしれません。
計測したら現状を分析
現状を分析していくと大抵の場合、ボトルネックとなっている部分があるはずです。 それはコンパイルだったり、テストだったり、特定のプロジェクトだったり・・・ 原因によって有効な対処法は異なります。
改善
私が実施した改善策をいくつかご紹介しておきます。 特にheap領域の割り当てはデフォルト設定のまま利用されている場合、結構な効果が期待できると思います。
コンパイルが遅い
- gradleが利用するjvmのheap領域を増やす。 GRADLE_OPTSやgradle.propertiesで設定できます。
- --parallelオプションを利用する こちらは独立したマルチプロジェクト構成のときにのみ有効
テストが遅い
- テストプロセスが利用するjvmのheap領域を増やす。 こちらはgradleが利用するjvmとは別の設定です。 https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test
- テストを分割する 下記の公式ドキュメントが参考になります。 遅いテストを切り出して早いテストを短いサイクルで流すやり方ですね。 GoogleのTestSizeの考えに近いと思います。 https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests
テストを並列実行する テストを切り出してもまだ遅い場合はテストのプロセスを並列化する方法があります。 テストがそれぞれスレッドセーフかつ実行順に依存しない作りになっていることが前提です。 https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test
分割と並列化の合わせ技 テストがそれぞれスレッドセーフかつ実行順に依存しない単位に切り出し、それらを別々のGradleプロセスとして実行する。 CI環境であれば分割数分コンテナを用意してパイプラインで実行するイメージですね。 構築は少し大変ですが、その後のスケールが楽になります。
俺たちのテスト改善はこれからだ
まだプロジェクト初期段階であればJUnitの@Categoryをつけておくと後から困らない気がします。 年代物のプロジェクトの場合は・・・頑張ってください。
ECSデビューメモ
クラスター、サービス、タスク定義、タスクの違い
クラスターはただの箱。 タスク定義からタスクを生成する、それを束ねたものがサービス。 タスクが協調して一つのサービスを提供する。
動的ポートマッピング
タスク定義でポートを0にすると、動的ポートマッピングが行われる。 タスクのポート管理をよしなにやってくれるらしいけど、向けたいポートはどうやって管理されるのだろうか。
タスクの停止
ECSは高いので使わないときは停止しておきたい。 しかし、単純にタスクを停止しただけではすぐに新しいタスクが立ち上がってしまう。 完全に停止させたい場合は必要なタスク数を0にすることで、停止状態を維持できる。 自動起動と停止を実現するにはlambdaでECSサービスを更新するfunctionを書いてやればよい。
amplifyで作成したAppSyncのAPIKeyが失効した
amplify pushに失敗する
こんな感じのエラーが出て失敗する。
UPDATE_FAILED GraphQLAPIKey AWS::AppSync::ApiKey Fri May 17 2019 00:37:17 GMT+0900 (JST) API key not found: xxxxxxxxxxxxxx (Service: AWSAppSync; Status Code: 404; Error Code: NotFoundException; Request ID: xxxxx)
API Keyが失効
API Keyによる認証方式はあくまで開発ユースを想定しており、7日間で失効するらしい。 https://aws-amplify.github.io/docs/js/api#aws-appsync-sdk
自動更新設定
${project}/amplify/backend/api/motibetas/parameters.jsonに "APIKeyExpirationEpoch": "-1" を設定することでKeyの失効時に自動更新してくれるようになる。
https://aws-amplify.github.io/docs/cli/graphql#apikeyexpirationepoch
ELBを作成する際の注意点
そこまで冗長化は必要ないけどそれなりにセキュアにしたい場合のVPC構成
このスライドの右(あるいは左)半分のみ構築してEC2を運用されている方もいるのではないでしょうか。 私もその一人です。
この構成の何が良いかというと、 見出しのとおり、そこそこセキュアで安いという点。
すべてをpublic subnetに曝け出しているよりはかなり安全になります。
ELBを追加
この環境でAutoscalingを実施するためにELBを立てるとします。 すると困るのがsubnetの扱い。
ALBを作成する際には配置するsubnetを2つ指定しなければなりません。 今存在するsubnetは2つしかないのでそれぞれ指定します。
すると「次のサブネットにはインターネットゲートウェイが存在しません。」との表示が。 そりゃprivate subnetはNATゲートウェイ経由にしてるからな! と自信満々に作成してしまったあなた(私)、こんな現象に出くわしていませんか?
たまにインスタンスに繋がらない(極端にレイテンシが増加する)
低負荷状態であるにもかかわらず、なぜかインスタンスに繋がらないことがある。 ヘルスチェックを確認しても特に異常なし。 繋がらない、ではなく繋がらないことがある。というのがやっかいなところ。 私もかなり頭を捻りました。
するとこんな記事を発見
どうやらインターネット向けのELBにprivate subnetを紐づけるのは間違いらしい。
ちゃんと公式にも回避策が書いてありました。 https://aws.amazon.com/jp/premiumsupport/knowledge-center/public-load-balancer-private-ec2/ 空のpublic subnetを作って紐づければよいみたいですね。
ELBが配置される場所
作成時にsubnetを指定するので、てっきりターゲットが存在するsubnetに配置しなければいけないものだと思い込んでいましたが、どうやら違うみたいです。 バランシングの候補になるのはおそらくELBが配置されているAZ全体。
むしろインターネット向けのELBをprivate sunbetに配置すると外からは見えない様子・・・ おそらくですが、繋がったり繋がらなかったりしたのはpublic subnet側のAZを経由してprivate側にアクセスが行われていたためと推測しています。
ちゃんと警告は読みましょう
ちゃんと作成時の警告を素直に受け取っていればこんなことにはならなかったのにね。
AWS Amplify Vue.js vuetifyでサンプル実装
ついに始動
AWSソリューションアーキテクトの勉強等もあり、プロジェクトの構想からはずいぶんと時間が経ってしまいましたが、 いよいよ本格的にオリジナルアプリの開発に着手しました。
まずは基盤づくり
https://qiita.com/shunp/items/d491adfadd570f66f990
こちらの記事を参考にプロジェクトのセットアップを行いました。 ただし、私の場合はBuefyではなくvuetifyを使うため、vuetify公式サイトを参照しながら必要な部分は書き換えています。
<template> <div> <nav class="level"> <div class="level-item has-text-centered"> <v-form ref="form"> <v-text-field v-model="input.name" label="Task"></v-text-field> <v-text-field v-model="input.description" label="Description"></v-text-field> </v-form> </div> <div class="level-item has-text-centered"></div> </nav> <button class="button is-link" @click="createTodo">ADD</button> <ul id="todo"> <li v-for="todo in todos" :key="todo"> <span class="todo-wrapper">{{ todo.name }}</span> </li> </ul> </div> </template> <script> import { API, graphqlOperation } from "aws-amplify"; import * as mutations from "@/graphql/mutations"; import * as queries from "@/graphql/queries"; export default { name: "todo", data: function() { return { input: { name: "", description: "" }, todos: [] }; }, created: async function() { await this.listTodos(); }, methods: { createTodo: async function() { if (this.input.name !== "" || this.input.description !== "") { await API.graphql( graphqlOperation(mutations.createTodo, { input: this.input }) ).catch(err => console.error(err)); await this.listTodos(); } else { console.info("input empty"); } }, listTodos: async function() { const res = await API.graphql(graphqlOperation(queries.listTodos)).catch( err => console.error(err) ); this.todos = res.data.listTodos.items; } } }; </script> <style scoped> </style>
import Vue from 'vue' import './plugins/vuetify' import App from './App.vue' import router from './router' import store from './store' import Amplify, * as AmplifyModules from 'aws-amplify' // 追記 import { AmplifyPlugin } from 'aws-amplify-vue' // 追記 import aws_exports from './aws-exports' // 追記 import Vuetify from 'vuetify' import 'vuetify/dist/vuetify.min.css' Vue.use(Vuetify) Amplify.configure(aws_exports) // 追記 Vue.use(AmplifyPlugin, AmplifyModules) // 追記 Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app')
動作確認
タスクの名前と説明を入力して「ADD」をクリックすると、タスクリストに入力した値が表示されました。
勉強メモ
・async await ・createdのタイミング
AWSソリューションアーキテクトアソシエイト試験に合格しました
祝合格
タイトルの通りです。 これから挑戦される方の参考になればと思い、私の経歴と試験対策について書いておこうと思います。
AWS歴
業務で約半年ほど利用。 利用経験があるサービスはec2,vpc,s3,codebuild,codepipeline,lambda,cloudwatch,cloudformation等。 DB、コンテナやデータ処理系のサービスはほとんど触ったことがありません。
勉強法
ちょうどAWS reinventで対策講座があったので一通り視聴 ⇒Udemyの講座で触ったことのないサービスの説明を中心に一周して模擬試験で理解度確認 ⇒間違えたところをホワイトペーパーで確認 という流れを時間がある限り繰り返しました。
https://www.udemy.com/aws-associate/
丸3日ほどの勉強時間でなんとか合格できました。 実務経験のある方ならサクッと合格できるのではないでしょうか。 決して安い受験料ではないのでしっかり準備して臨むに越したことはないですが。