grpc-spring-boot-starter使ってるプロジェクトでdockerビルドしたアプリを動かしたらNoSuchMethodErrorに遭遇した
ちょっとよくわからない現象に遭遇した
grpc-spring-boot-starter使ってるプロジェクトでの話だけど ローカルでgradle bootRunして起動した時はgrpc通信部分で問題なく動くのだが dockerイメージにビルドしてコンテナとして動かしたときに下記のようなエラーがでてきた
Exception in thread "grpc-default-executor-0" java.lang.NoSuchMethodError: 'void com.google.protobuf.AbstractMessageLite$Builder.addAll(java.lang.Iterable, java.util.List)'
依存してるライブラリのバージョンがうまく噛み合ってないのかなと思ったので grpc-spring-boot-starterのrelease note確認して、使用してるバージョンで依存してるgrpc-javaのバージョンを特定してから grpc-javaのREADMEに書いてある必要なgradleの依存ライブラリを明示的に書くようにしたら問題解決した
implementation 'io.grpc:grpc-netty-shaded:1.25.0' implementation 'io.grpc:grpc-protobuf:1.25.0' implementation 'io.grpc:grpc-stub:1.25.0'
↑自分はgrpc-spring-boot-starter:3.5.0を使っていたので、grpc-java:1.25.0をgradleに記入した
grpc-spring-boot-starterのREADMEにも特にgrpc-javaの依存を書いておけと見当たらなかったので結構ハマってしまった
ローカルでprotocol buffersのjavaファイルを作るときにはgenerateProtoを使用していて、dockerのイメージをビルドするときも同じコマンドが叩かれている認識なので 生成されるクラスファイルが依存するライブラリのバージョンも同じになるはずだからどの環境で動かしてもこんなエラーには遭遇しないと思ってたんだけど 何か勘違い、見落としがありそうだ.. gradleプロジェクトだとdependenciesタスクで依存してるライブラリのバージョンを確認できるけど、 dockerイメージにするとそのへんを確認する方法がわからなくて困った
grpc-javaのヘルスチェック
grpc-javaを使って実装したgrpcサーバーのヘルスチェックについて書いておきます
grpcのヘルスチェックこうやりましょ的なのが公式から出されています
grpc/health-checking.md at master · grpc/grpc · GitHub
これを自分で実装してもいいかもしれませんがめんどくさいので公式から提供されているものを使いましょう
参考までにkotlinのコード
server = ServerBuilder.forPort(port)
// こんな感じにHealthCheck用のサービスを追加
.addService(HealthStatusManager().healthService)
.build()
.start()
これでサーバー起動するとGrpcのHealthチェック用の口が用意できます
【QUARKUS】KotlinとGradleでサンプル作ってネイティブ起動するところまで
はじめに
QUARKUS触ってみたいなーと前々から思っていたので、KotlinとGradleを使ったQUARKUSのサンプルを作ってみました QUARKUSのドキュメントではmavenのほうが情報が厚そうだったのですが、pom.xml書きたくない、スクリプトで依存性管理したいと思ったのでGradleを選択しました とりあえず今回はネイティブイメージをビルドするところまでです また、自分はmacを使っているのでmacユーザー向けに書いていきます
作成したコードのリポジトリはこちらになります https://github.com/yoshi10321/sample-quarkus-app
GraalVMのインストール
まずGraalVMをインストールします
https://github.com/oracle/graal/releases
macの場合
graalvm-ce-darwin-amd64-{バージョン名}.tar.gz
というファイルをダンロードして解凍します
解凍したディレクトリを
/Library/Java/JavaVirtualMachines
に移動しておきます
/usr/libexec/java_home -V
コマンドを叩くとインストールしてあるJavaのバージョンが見れます
GraalVMがあればOK
環境変数にセットしてGraalVMを使うようにします
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) export PATH=$JAVA_HOME/bin:$PATH
次にネイティブイメージ作成用にnative-image
ツールをインストールしておきます
gu install native-image
ここまでやったらGraalVMのインストールは完了です
Gradleプロジェクトの作成
mavenだと便利なQUAKUSプロジェクト作成用のコマンドが用意されているようですが、現状Gradleではまだそういった便利なものは用意されてなかったので自分で作っていきます
まず好きなディレクトリを作成してそこに移動しておきます
mkdir sample-quarkus-app cd sample-quarkus-app
下記のコマンドでgradleのkotlinプロジェクトが作成できます
gradle init --type=kotlin-application
QUARKUSの設定を追加していく
まずQUARKUSのGradle pluginがまだGradle Plugin Portalに上がってないから./settings.gradle.kts
に下記のコードを追加します
pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { if (requested.id.id == "io.quarkus") { useModule("io.quarkus:quarkus-gradle-plugin:${requested.version}") } } } }
次にbuild.gradle.kts
の中身はこんな感じになりました
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet plugins { // Apply the Kotlin JVM plugin to add support for Kotlin on the JVM. id("org.jetbrains.kotlin.jvm").version("1.3.31") id("org.jetbrains.kotlin.plugin.allopen") version "1.3.41" java id("io.quarkus") version "0.19.1" } allOpen { annotation("javax.ws.rs.Path") annotation("javax.enterprise.context.ApplicationScoped") annotation("sample.quarkus.app.MyAnnotation") } repositories { jcenter() mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation(enforcedPlatform("io.quarkus:quarkus-bom:0.19.1")) implementation("io.quarkus:quarkus-resteasy") implementation("io.quarkus:quarkus-resteasy-jsonb") implementation("io.quarkus:quarkus-kotlin") testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit") testImplementation("io.quarkus:quarkus-junit5") testImplementation("io.rest-assured:rest-assured:3.1.0") } quarkus { setSourceDir(project.projectDir.resolve("src/main/kotlin").absolutePath) setOutputDirectory(project.projectDir.resolve("build/classes/kotlin/main").absolutePath) } kotlin.sourceSets["test"].kotlin.srcDirs("test")
build.gradleの設定で自分が少しハマったところを書いておくと
sourceDir
を設定しないと./gradlew quarkusDev
で起動した時にエラーが発生しますimplementation("io.quarkus:quarkus-resteasy-jsonb")
これを入れないと
@GET @Produces(MediaType.APPLICATION_JSON) fun hello() = Greeting("hello")
このコードのようなjsonフォーマットでレスポンスを返すときのjsonシリアライズでコケました
implementation("io.quarkus:quarkus-kotlin")
これを入れないとkotlinで書いたコードのホットリロードがうまく動かなかったです- kotlinのクラスはデフォルトで
final
クラスになってしまうのでallopenプラグインを使ってopenにします。ただなぜかApplicationScopedアノテーションを付けたクラスでうまく効いてくれなかったので、別途手動でopenをつけたりもしました。(原因調べきれてないです、すいません)
下記のコマンドで起動することで、ホットリロードが有効な状態で起動できます
./gradlew quarkusDev
ブラウザでlocalhost:8080/hello
にアクセスするとjsonのレスポンスが返ってくるのが確認できます
Kotlinのコードはgithubの方を参照していただければと思います https://github.com/yoshi10321/sample-quarkus-app
ネイティブイメージのビルド
環境変数にGRAALVM_HOME
をセットしておく必要があります
macの場合は下記のように設定します
export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/
docker向けにネイティブビルドする場合は下記のコマンドを叩きます
./gradlew buildNative --docker-build=true
実際にDockerにデプロイしていきます Dockerfileを作成して
FROM registry.access.redhat.com/ubi8/ubi-minimal WORKDIR /work/ COPY build/*-runner /work/application RUN chmod 775 /work EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
下記のコマンドでDocker build&runしていきます
docker build -f Dockerfile -t sample/quarkus-app . docker run -i --rm -p 8080:8080 sample/quarkus-app
-> % docker run -i --rm -p 8080:8080 sample/quarkus-app 2019-07-21 16:50:38,190 INFO [io.quarkus] (main) Quarkus 0.19.1 started in 0.013s. Listening on: http://0.0.0.0:8080 2019-07-21 16:50:38,191 INFO [io.quarkus] (main) Installed features: [cdi, kotlin, resteasy, resteasy-jsonb]
0.013秒で起動したというログが確認できました。 Kotlinで書いたコードがこの速さで起動するのは感動ものです
終わりに
少しハマったところもありましたがQUARKUSのアプリケーションをKotlinとGradleを使ってネイティブ起動するところまでいけました ネイティブコードで実行することでJVMの起動が遅い問題が回避できるため、Kubernetes上で起動させたときのオートスケーリング時のパラメータ設定にそこまで気を使わなくても良くなるんじゃないかなということを期待しています 今後も特にQUARKUS, GraalVM周りの情報には期待していきたいですね。
シェアリマインダーツール作る
夫婦間で買物情報の共有(トイレットペーパー切れたーとか)
やることの共有(洗濯するとか)
っていうことをシェアするためのいい感じのツールが欲しくなったので作ってみる(もうあるかもしれないけどあえて自分で作りたい)
とりあえず要件定義
コンセプト
夫婦用リマインダー共有アプリ 一人以上から使用可能
要件定義
- ユーザー登録機能
- FB認証
- Twitter認証
- リマインダー機能
- タイトル・日時・完了ステータス
- 日は必須、時は任意
- 時間になったら通知
- 時間設定時のみ
- リマインダー登録
- リマインダー更新
- リマインダー削除
- タイトル・日時・完了ステータス
- リマインダー同期機能
- アプリ起動のタイミングorリアルタイム?
- プッシュ通知
- 新しいリマインダーが登録されました
- パートナー追加する機能
- パートナー追加
- パートナー削除
- パートナー招待
- 完了にした人によって表現が変わる機能
- 奥さんならピンクのハート、旦那さんなら青のハート
- どっちが完了にしたかわかりやすくする
- ハートが10個たまるとやった側がご褒美をもらえる
- 好きな食べ物作ってくれるとか、お出かけ連れてってくれるとか
- あんま可愛すぎるのもあれだけど
ドメインモデル
最近DDD興味あってドメインモデルの作成をしてみたかったのでやってみた
最初はとりあえず作りきりたいからいくつか機能は削ると思う さて、最後まで作りきれるか
読書ログ:SINGLE TASK 一点集中術
デボラ・ザック著のSINGLE TASKを読んだ そもそもこの本を手にとったきっかけはDaiGoさんのこの動画を見た時に紹介されていたから
自分が気になった部分のみ書いていく(引用部分は本の文章そのままじゃなくて自分の中で崩してます)
気になったところ
p24 シングルタスクできない原因
第一の理由は頭の中にある。つい他のことを考えてしまう 第二の理由は外部にある。外部からの刺激が集中力を奪う
p38
マルチタスクは情報の流れを遮断し、短期記憶へと分断する。短期記憶に取り込まれなかったデータは長期記憶にならずに記憶から抜け落ちていく。なのでマルチタスクは能率が落ちる
この部分は特に気になった。自分は記憶力が無いなーという実感があって、せっかく技術的なこと調べてもなかなか思い出せないというのが悩みとして持っていた そのために最近では忘れないために、というか後で思い出しやすいようにBoostnote使って各技術の後で思い出したいような事は積極的にノートに取るようにしている(Boostnoteは検索もできたりカテゴライズしやすいので便利) ただやはり忘れにくくするような頭にできたらどんなに良いだろうかとは思っていた マルチタスクは情報の流れを遮断して短期記憶に分断するというのは一つの原因だったのかもしれない 結構調べ物をしていると途中で別の知らないワード・技術があるとそっちに引っ張られて、本来調べたかったことから脱線してしまうというのがよくある。 今後はなるべく脱線せずに一つのことを調べてなるべくその中で更に深ぼって調べていくといったことを意識してみようかな とはいえ技術的なことを調べるにあたってそもそも前提知識が抜けてる場合はそこを埋めないと先に進めないということもあると思うので難しい その場合は必要な前提知識含めてどうやって学習を進めていくか整理してからアクションを進めていくみたいにしないといけないと思う 必要になる前提知識でないけど気になるものは、本書にもあったパーキングロットという手法が使えると思う パーキングロットとはそもそもはMTGの場などで使われるような手法らしい、まあなんのことはない途中で本題の議論と違うけど話し合わなければならないテーマが上がったら一旦ホワイトボードなどにメモしておいて、一旦その事は無視して引き続き本題の議論を進める。メモしたテーマはまた後で議論するというやり方 これは先程書いた途中で気になった別の技術に出会った場合にも使えるので試してみよう
p74
マルチタスクの誘惑に負けるのは他人の期待や要求に答えねばならないという義務感に駆られているとき なるほど、と思った 人間ついマルチタスクしたくなってしまう生き物らしい。その原因がこれ なんとなくしっくり来た でもこの気持に負けない精神力を鍛えなければならないと思った これはもちろん単に他人の期待とかを無視して跳ね除けろって話ではない いつ取り掛かるか自分で制御しろって話
p?(わすれた
用が済んだらブラウザのタブは閉じる まあそうだよね。自分もブラウザタブ開きすぎ状態になることがほんとによくある 悪い癖だから直そう
p160
内省の時間で共感力が上がる
自らの感情と経験に触れれば触れるほど、他の人の頭にどんな考えがよぎるのかを、より正確に、より豊かに想像できるようになる by イタリアの研究
これは聞いたことなかったので「へー」って感じだった 共感力の欠如は自分にも見られる気がしてたのでちょっと意識して取り組みたい 内省って苦手だけど..
p162
難しい問題に直面しているとき、自分を客観的に捉えると良い判断ができる 直面してる問題に対して自分を「彼」などの三人称を守護にして文章を書いたりして自分を客観的に見つめる方法がよい
これも試してみたい。よく自分一人で悩むより友達とかが相談に乗ってくれたほうが良い結論が出せるみたいなのがあると思うけどそれと同じかと 三人称視点で文章を書いてみるのは面白そうだと思った
さいごに
この本は結構具体的な手法とかも書いてあってよかった
SINGLE TASK 一点集中術――「シングルタスクの原則」ですべての成果が最大になる
- 作者: デボラ・ザック,栗木さつき
- 出版社/メーカー: ダイヤモンド社
- 発売日: 2017/08/31
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
技術日記6/16-6/21
超亀ログだけど手元に作業ログがあるのでブログにも一応書いておく
AWS Lambdaでスクレイピングアプリを動かす方法を模索してたっぽい
Serverless chromeも検討した GitHub - adieuadieu/serverless-chrome: 🌐 Run headless Chrome/Chromium on AWS Lambda (maybe Azure, & GCP later)
ただ今回スクレイピングをするにあたってセキュアな情報を扱う必要があったためやはり公式じゃないものは使いたくなかった、かつリポジトリのメンテが最近されてなさそうだったので使用するのはやめておいた またこういったものを使ったとき使用するchromeブラウザのアップデートが自分でできないというところも気になる スクレイピングをプロダクション環境で使うのなら、ブラウザの脆弱性が見つかったときすぐパッチを当てて対応できるような状態にはしておきたい あとserverless-chromeだとchromeブラウザ限定になってしまうのも引っかかった 現在ではほとんどなくなってきているけど稀にInternetExplolerしか対応してないページもあるかもしれない(そんなページもうほぼないと思うしそんなサイトは相手にしなくていい気もするけど) まあそうじゃなくともChrome系でうまくスクレイピングできなかった時にFirefoxなど別の手段が選べるような状況にはしておきたかった 同じような理由でpuppeteerは使うのをやめた chromeチームがメンテしてるので公式という安心感はあるけどブラウザが縛られてしまう なので今回はwebDriver使っている
AWS Lambdaにデプロイするにあたってアップロードの上限サイズが有る スクレイピングのアプリをtypescriptで書いているがnode_modulesとかもあげようとすると普通に上限に引っかかる? 何か圧縮する方法があったのだろうか?ちょっと調べられていない
そういった事もあって結局AWS Lambdaの使用はやめることにした
ちょっと他の日のログをまとめるのがめんどいのでこれだけにしとく