メインコンテンツまでスキップ

· 約6分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

前回構築したRaspberry Pi上のKubernetesで、WordPressを構築してみました。

ポイント

  • Dockerイメージはオフィシャルのものを使用
  • DBはMariaDB
  • MariaDBの/var/lib/mysqlとWordPressの/var/www/htmlはホスト(Raspberry Pi)上のディスクに永続化

構築

Yamlの構成はこんな感じです。

./
├── mariadb
│ ├── mariadb-persistentvolume.yaml
│ ├── mariadb-service.yaml
│ └── mariadb-statefulset.yaml
└── wordpress
├── wordpress-persistentvolume.yaml
├── wordpress-service.yaml
└── wordpress-statefulset.yaml

2 directories, 6 files

ディスク

Minikubeは以下のホスト上のディレクトで永続ができるように設定済みのようです。 https://minikube.sigs.k8s.io/docs/handbook/persistent_volumes/

  • /data
  • /var/lib/minikube
  • /var/lib/docker
  • /tmp/hostpath_pv
  • /tmp/hostpath-provisioner

/dataディレクトリを使用しようと思いますので、作成します。

mkdir -p /data

MariaDBの構築

使用したリソースは以下のものです。パスワードが平文で書かれていますので、Secretリソースを使うべきかと思います。

リソース説明
StatefulSetデータの永続化が必要なのでDeployment(ReplicaSet)ではなくStatefulSetを使いました
ServicePod間での通信を行うため、ClusterIP ServiceでMariaDBのポート3306を公開します
PersistentVolumeRaspberry Pi上の/data/mariadbをPersistentVolumeとして定義します。
mariadb-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mariadb-statefulset
spec:
selector:
matchLabels:
app: mariadb-app
serviceName: mariadb-service
replicas: 1
template:
metadata:
labels:
app: mariadb-app
spec:
containers:
- name: mariadb
image: mariadb:latest
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: somewordpress
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
- name: MYSQL_PASSWORD
value: wordpress
volumeMounts:
- name: mariadb-pvc
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mariadb-pvc
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: manual
selector:
matchLabels:
app: mariadb
resources:
requests:
storage: 1Gi
mariadb-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mariadb-service
spec:
type: ClusterIP
selector:
app: mariadb-app
ports:
- port: 3306
mariadb-persistentvolume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mariadb-pv-volume
labels:
type: local
app: mariadb
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/mariadb"

WordPressの構築

WordPressもMariaDBとほぼ同じです。違うのはこれぐらいです。

  • Serviceの種別がNodePortで、外部に公開
  • DB接続先をMariaDBのClusterIPで指定
リソース説明
StatefulSetMariaDB同様、データの永続化をするため、StatefulSetを使いました
Service外部から接続するため、NodePortを使用してコンテナ内の80番ポートを30080番として外部公開します。
PersistentVolumeRaspberry Pi上の/data/wordpressをPersistentVolumeとして定義します。
wordpress-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: wordpress-statefulset
spec:
selector:
matchLabels:
app: wordpress-app
serviceName: wordpress-service
replicas: 1
template:
metadata:
labels:
app: wordpress-app
spec:
containers:
- name: wordpress
image: wordpress:latest
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: mariadb-service:3306
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: wordpress
volumeMounts:
- name: wordpress-pvc
mountPath: /var/www/html
volumeClaimTemplates:
- metadata:
name: wordpress-pvc
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: manual
selector:
matchLabels:
app: wordpress
resources:
requests:
storage: 1Gi
wordpress-service.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress-nodepod
spec:
type: NodePort
selector:
app: wordpress-app
ports:
- port: 80
nodePort: 30080
wordpress-persistentvolume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: wordpress-pv-volume
labels:
type: local
app: wordpress
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/wordpress"

起動

サブディレクトリ含めて全Yamlを適用します

$ kubectl apply -f ./ -R
persistentvolume/mariadb-pv-volume created
service/mariadb-service created
statefulset.apps/mariadb-statefulset created
persistentvolume/wordpress-pv-volume created
service/wordpress-nodepod created
statefulset.apps/wordpress-statefulset created
$

起動したか確認

$ kubectl get svc,po,pv,pvc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24h
service/mariadb-service ClusterIP 10.105.29.150 <none> 3306/TCP 36s
service/wordpress-nodepod NodePort 10.100.194.70 <none> 80:30080/TCP 36s

NAME READY STATUS RESTARTS AGE
pod/mariadb-statefulset-0 1/1 Running 0 36s
pod/wordpress-statefulset-0 1/1 Running 0 36s

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mariadb-pv-volume 1Gi RWO Retain Bound default/mariadb-pvc-mariadb-statefulset-0 manual 36s
persistentvolume/wordpress-pv-volume 1Gi RWO Retain Bound default/wordpress-pvc-wordpress-statefulset-0 manual 36s

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mariadb-pvc-mariadb-statefulset-0 Bound mariadb-pv-volume 1Gi RWO manual 36s
persistentvolumeclaim/wordpress-pvc-wordpress-statefulset-0 Bound wordpress-pv-volume 1Gi RWO manual 36s
$

Raspberry Pi上の/dataディレクトリ配下にファイルが作成されていることを確認できます。

$ ls /data/mariadb/
aria_log.00000001 ib_buffer_pool ib_logfile0 multi-master.info performance_schema
aria_log_control ibdata1 ibtmp1 mysql wordpress
$ ls /data/wordpress/
index.php wp-activate.php wp-comments-post.php wp-content wp-links-opml.php wp-mail.php wp-trackback.php
license.txt wp-admin wp-config.php wp-cron.php wp-load.php wp-settings.php xmlrpc.php
readme.html wp-blog-header.php wp-config-sample.php wp-includes wp-login.php wp-signup.php
$

ブラウザでも確認

Raspberry Piの外部からhttp://raspberrypi.local:30080/へアクセス

raspberrypi.local_30080_wp-admin_install.php(iPad).png

無事疎通ができました。 1件画像つきで投稿してみました。

raspberrypi.local_30080__p=5(iPad).png

この状態で、MariaDBのPodを強制的に削除してみます。

$ kubectl delete po mariadb-statefulset-0 
pod "mariadb-statefulset-0" deleted
$ kubectl get po
NAME READY STATUS RESTARTS AGE
mariadb-statefulset-0 0/1 ContainerCreating 0 3s ←自動的にPodが再作成される
wordpress-statefulset-0 1/1 Running 0 9m29s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
mariadb-statefulset-0 1/1 Running 0 9s
wordpress-statefulset-0 1/1 Running 0 9m35s
pi@raspberrypi:~/k8s/minikube-wordpress $

データは/data/mariadbで永続化されているのでMariaDBのPodが再作成された後は、問題なく画面表示ができます。同様に、WordPressのPodを削除しても、問題ありませんでした。

参考

https://minikube.sigs.k8s.io/docs/handbook/persistent_volumes/ https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/ https://docs.docker.jp/compose/wordpress.html

· 約4分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

何番煎じかわかりませんが、Raspberry PiにKubernetes環境を構築したので、記録を残します。 複数台でクラスターを組むこともなく、1台構成です。

環境

Raspberry Pi 4 (8GBメモリ) Raspberry Pi OS 64bit https://www.raspberrypi.org/forums/viewtopic.php?f=117&t=275370

手順

Swapの無効化

sudo apt-get purge -y --auto-remove dphys-swapfile
sudo rm -fr /var/swap

cgroupの有効化

/boot/cmdline.txtの末尾にcgroup_enable=memory cgroup_memory=1を追加。(改行はせず、1行目の末尾に追加)

/boot/cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=8226b72e-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles cgroup_enable=memory cgroup_memory=1

設定後、再起動しましょう

Dockerのインストール

https://docs.docker.com/engine/install/debian/

sudo apt remove docker docker-engine docker.io containerd runc
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=arm64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y

kubectlのインストール

https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

Minikubeにkubectlコマンドが内蔵されているようでしたが、別でインストールしたほうが使いやすい気がしましたのでインストールしました。 kubeadmkubeletはminikubeがインストールしているような気がしましたので、インストールしません。

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt update
sudo apt install -y kubectl

Minikubeのインストール

https://kubernetes.io/ja/docs/tasks/tools/install-minikube/

Raspberry PiはARM64アーキテクチャのため、ダウンロードする実行ファイルはminikube-linux-amd64ではなくminikube-linux-arm64です。

sudo apt install conntrack -y

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-arm64
chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

kubernetesクラスタの作成

vm-driverはnoneとします

sudo minikube start --vm-driver=none

aliasと入力補完の設定

minikubekubectlも毎回sudoが必要で、毎回入力するのは面倒なのでaliasを作成します。 また、入力補完のcompletionも設定します。

~/.bashrc
alias minikube='sudo minikube'
source <(minikube completion bash)
alias kubectl='sudo kubectl'
source <(kubectl completion bash)

動作確認

動作確認としてNginxコンテナを起動してみます。

nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
type: NodePort
selector:
app: nginx-app
ports:
- protocol: "TCP"
port: 80
nodePort: 30080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx-container
image: nginx:latest
kubectl apply -f nginx.yaml

Raspberry Piからはcurl http://localhost:30080で応答がありますし、外部のPCからはhttp://raspberrypi.local:30080/で応答が受け取れました。

感想

  • ARM64対応のイメージが有るものと無いものがあるので注意
  • kubeadmでの構築を試みたのですが、なぜかPOD間通信ができなかったので、Minikubeにしました
  • さてどう活用しようかな

· 約6分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

※個人の調査によるものです。誤りがあればご指摘ください ※2020/8/8現在の情報をもとにまとめました。

AWSとAzureのリージョンなどの考え方を比較しました。

AWS

分類レベル名称定義
レベル小データセンター1つの物理的なデータセンター
レベル中アベイラビリティゾーン (AZ)1 つの AWS リージョン内でそれぞれ切り離され、冗長的な電力源、ネットワーク、そして接続機能を備えている 1 つ以上のデータセンターのことです。各 AZ はそれぞれ他の AZ から物理的に意味のある距離、つまり数キロメートル離れていますが、すべて 100 km 以内 (互いに 60 マイル) に配置されています。
レベル大リージョン1 つの地理的エリアにある、複数の、それぞれが隔離され物理的にも分離された AZ によって構成されています。1 つのデータセンターを 1 つのリージョンとして定義することが多い他のクラウドプロバイダーとは違い、全 AWS リージョンが採用するこのマルチ AZ デザインは、お客様にいくつかのメリットをご提供するものです。

大阪ローカルリージョンは特殊で、

  • 分離された耐障害性の高いインフラストラクチャデザインが 1 つのデータセンター内で構成されます。
  • アジアパシフィック (大阪) ローカルリージョンは 1 つのアベイラビリティーゾーンで構成されており、アジアパシフィック (東京) リージョンと組み合わせて使用することが意図されています。
  • このリージョンには、お客様のセールス担当者からのリクエストが必要です。

とのこと。

他にはLocal Zonesというものがあるようです。現在はロサンゼルスのみで提供されています。

https://aws.amazon.com/jp/about-aws/global-infrastructure/ https://aws.amazon.com/jp/about-aws/global-infrastructure/regional-product-services/ https://aws.amazon.com/jp/about-aws/global-infrastructure/regional-product-services/

Azure

分類レベル名称定義
Azure データセンターネットワークに接続されたコンピューター サーバーのグループを収容する、世界中に存在する一意の物理的な建物です。
Azure Availability ZonesAzure リージョン内の一意の物理的な場所であり、データセンターの障害からアプリケーションとデータを保護する高可用性を提供しています。それぞれのゾーンは、独立した電源、冷却手段、ネットワークを備えた 1 つまたは複数のデータセンターで構成されています。
Azure リージョンAzure リージョンは、待機時間で定義された境界内でデプロイされ、低遅延の専用リージョン ネットワークを使用して接続された一連のデータセンターです。
特大Azure 地域通常、1 つ以上のリージョンを含み、データ所在地とコンプライアンスの境界を保持します。

AWSにはない、「地域」というものが出てきました。リージョンも地域のような気もしますが、英語名はAzure リージョンがAzure regionで、Azure 地域がAzure geographyです。 東日本リージョンと西日本リージョンはペアに指定されているようで、このAzure 地域に該当するようです。

ペアになっているリージョンのメリットとしては、以下が上げらててました

  • 物理的な分離
  • プラットフォームに備わっているレプリケーション
  • リージョン復旧順序
  • 順次更新
  • データ所在地

https://azure.microsoft.com/ja-jp/global-infrastructure/ https://azure.microsoft.com/ja-jp/global-infrastructure/geographies/#geographies https://docs.microsoft.com/ja-jp/azure/best-practices-availability-paired-regions

日本国内リージョンの比較

比較項目AWS東京リージョンAWS大阪ローカルリージョンAzure東日本リージョンAzure西日本リージョン
開設時期2011年2018年2014年2014年
AZ数4131

調べていると、AWS東京リージョンに4つ目のリージョンが開設されたのが、2018年、Azure東日本リージョンがAZに対応したのが2019年のようです。この間はAWS東京リージョンが4AZ、Azure東日本リージョンが1AZとかなりの差があったような形ですね。 また、AWS大阪ローカルリージョンは2021年初頭までに3つのAZをもつフルリージョンになるようです。

https://aws.amazon.com/jp/blogs/news/the-fourth-new-availability-zone-tokyo-region/ https://azure.microsoft.com/ja-jp/updates/general-availability-azure-availability-zones-in-japan-east/ https://aws.amazon.com/jp/blogs/news/in-the-works-aws-osaka-local-region-expansion-to-full-region/

まとめ

AWS側のほうが知識があるので、AWS押しのような内容となりましたが、Azure側の押しポイントがあれば教えて下さい。

· 約10分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

Quarkus(https://quarkus.io/) とはSUPERSONIC SUBATOMIC JAVAで、

A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards.

だそうです。 何言ってるかわかりませんがすごそうです。

GraalVMの機能でJavaのプログラムをネイティブに変換することが可能なので、AWS Lambdaのカスタムランタイムと組み合わせることで AWS Lambda上で動作するJavaアプリケーションの特性である コールドスタートが遅い問題 の解決に期待ができます。

公式サイトの手順に従い試してみましたので、手順を残します。

QUARKUS - BUILDING A NATIVE EXECUTABLE https://quarkus.io/guides/building-native-image

QUARKUS - AMAZON LAMBDA https://quarkus.io/guides/amazon-lambda

環境

  • Docker Desktop (Mac) 2.3.0.4
  • VSCode + Visual Studio Code Remote - Containers extension
  • Amazon Linux 2 (on Docker)

雛形アプリのデプロイ手順

手順1. Amazon Linux 2の環境設定

DockerイメージのAmazon Linux 2はtarunzipができないので色々入れておきます。 全部必要かわからないですが、これぐらい入れておきました。

yum install -y sudo shadow-utils procps tar.x86_64 gzip xz unzip witch git python3 tree

手順2. GraalVMのインストール

公式サイトからダウンロードして展開します。

curl -s -L -o /tmp/graalvm-ce-java11-linux-amd64-20.1.0.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.1.0/graalvm-ce-java11-linux-amd64-20.1.0.tar.gz
tar zxf /tmp/graalvm-ce-java11-linux-amd64-20.1.0.tar.gz -C /opt/
ln -s /opt/graalvm-ce-java11-20.1.0 /opt/graalvm

JAVA_HOMEをGraalVMにして、MavenでのビルドにGraalVMを使用します。

export GRAALVM_HOME=/opt/graalvm
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH

最後にNativeビルド時に必要なnative-imageをインストールします。コマンドはgu(GraalVM Updater)です。

gu install native-image

手順3. Mavenのインストール

Quarkusのビルドで使用するMavenは3.6.2以上のバージョンが必要です。yumでインストールできるバージョンが古かったので、公式サイトからダウンロードしてインストールしました。

curl -s -L -o /tmp/apache-maven-3.6.3-bin.tar.gz https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
tar zxf /tmp/apache-maven-3.6.3-bin.tar.gz -C /opt/
ln -s /opt/apache-maven-3.6.3 /opt/apache-maven

mvnのバージョン確認

bash-4.2# mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /opt/apache-maven
Java version: 11.0.7, vendor: GraalVM Community, runtime: /opt/graalvm-ce-java11-20.1.0
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.19.76-linuxkit", arch: "amd64", family: "unix"
bash-4.2#

GraalVMのJVMで動作していることがわかります。

手順4. Mavenでプロジェクト作成

mvnコマンドでプロジェクトを生成します。

mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
-DarchetypeVersion=1.6.0.Final

しばらくするとプロンプトで質問されますので答えます。 []で囲んだ部分がユーザー入力です。

Define value for property 'groupId': [myGroup]
Define value for property 'artifactId': [myArtifact]
Define value for property 'version' 1.0-SNAPSHOT: : []
Define value for property 'package' myGroup: : [example]
Confirm properties configuration:
groupId: myGroup
artifactId: myArtifact
version: 1.0-SNAPSHOT
package: example
Y: : [Y]

artifactId(myArtifact)でディレクトリが作成され、プロジェクトが生成されます。

作成直後のプロジェクト構成はこんな感じ。

bash-4.2# tree myArtifact/
myArtifact/
├── build.gradle
├── gradle.properties
├── payload.json
├── pom.xml
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── example
│ │ ├── InputObject.java
│ │ ├── OutputObject.java
│ │ ├── ProcessingService.java
│ │ ├── StreamLambda.java
│ │ ├── TestLambda.java
│ │ └── UnusedLambda.java
│ └── resources
│ └── application.properties
└── test
├── java
│ └── example
│ └── LambdaHandlerTest.java
└── resources
└── application.properties

9 directories, 14 files
bash-4.2#

手順5. Lambdaで起動するHandlerの設定

Lambdaで呼び出されるHandlerはresources/application.propertiesquarkus.lambda.handlerにて設定します。

resources/application.properties
quarkus.lambda.handler=test

上記設定の場合は、以下のtestと名前をつけたクラスが呼び出されます。

main/java/example.TestLambda.java
@Named("test")
public class TestLambda implements RequestHandler<InputObject, OutputObject> {
}

あとは通常のLambdaと同様にコーディングします。 雛形にはtestの他にstreamなども用意されています。

手順6. デプロイパッケージの作成

一旦雛形のままデプロイパッケージを作成してみます。

mvn clean package -Pnative

めちゃくちゃ時間がかかります。10分以上かかると思います。

手順7. デプロイパッケージの内容の確認

無事デプロイパッケージができると、target/function.zipが生成されいます。試しに展開してみると、中身はbootstrapのみでした。

bash-4.2# unzip function.zip 
Archive: function.zip
inflating: bootstrap
bash-4.2#

手順8. Lambdaのデプロイ

targetディレクトリ内には、manage.shというファイルも生成されており、ここからAWS上にデプロイしたりできるようです。 私はカスタムランタイムが初めてだったこともあり、マネジメントコンソールから試してみました。 デプロイパッケージ作成後に、target/sam.native.yamlというファイルも生成されるので、ハンドラー名や環境変数はこちらを参考にしました。

関数を新規作成します。 ランタイムをユーザー独自のブートストラップを提供するとします。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen).png

関数を作成したら、プログラムをアップロードします。 関数コードのところのアクションから.zipファイルをアップロードを選び、function.zipを選択します。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen) (1).png

ハンドラーはnot.used.in.provided.runtimeとなります。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen) (2).png

環境変数にDISABLE_SIGNAL_HANDLERSを追加し値をtrueとします。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen) (4).png

ここまでで設定は完了です。以下のJSONをインプットにテスト実行してみましょう。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen) (3).png

{
"name": "Bill",
"greeting": "hello"
}

動作結果がこちら。無事動きました。

ap-northeast-1.console.aws.amazon.com_lambda_home_region=ap-northeast-1(Laptop with MDPI screen) (5).png

AWS SDK を追加

AWS SDKを使用するには単純にpom.xmlに追加するだけでなく、いくつか設定が必要です。

手順1. SSL通信の有効化

resources/application.propertiesに以下の内容を追加します。(公式ドキュメント的にはデフォルトで有効って書いてある気もしますが)

resources/application.properties
quarkus.ssl.native=true

手順2. 依存関係の追加

まずは、quarkus-jaxbが必要とのことで、これを追加します。

pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jaxb</artifactId>
</dependency>

次にAWS SDKのライブラリーを追加するのですが、

For native image, however the URL Connection client must be preferred over the Apache HTTP Client when using synchronous mode, due to issues in the GraalVM compilation (at present).

翻訳すると ただし、ネイティブイメージの場合、GraalVMコンパイルの問題(現在)のため、同期モードを使用するときは、Apache HTTPクライアントよりもURL接続クライアントを優先する必要があります。 だそうです。そのため、以下のような記述となります。

pom.xml
<properties>
<aws.sdk2.version>2.10.69</aws.sdk2.version>
</properties>

<dependencyManagement>
<dependencies>

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${aws.sdk2.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

</dependencies>
</dependencyManagement>
<dependencies>

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<exclusions>
<!-- exclude the apache-client and netty client -->
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</exclusion>
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>commons-logging-jboss-logging</artifactId>
<version>1.0.0.Final</version>
</dependency>
</dependencies>

手順3. Javaコードの作成

S3にアクセスする例ですが、S3Clientを生成する際に、httpClientにて明示的にUrlConnectionHttpClientを指定します。

S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_1)

.httpClient(software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient.builder().build())
.build();

手順4. SSL通信に必要な設定

SSL通信を行うためにデプロイパッケージに以下を含める必要があります。

  • カスタムBootstrap
  • libsunec.so
  • cacerts

まず、src/main/zip.native/ディレクトリを作成し、bootstrapを作成します。

zip.native/bootstrap
#!/usr/bin/env bash

./runner -Djava.library.path=./ -Djavax.net.ssl.trustStore=./cacerts

次にlibsunec.socacertsをコピーします。この2つのファイルはGraalVMに含まれています。

cp $GRAALVM_HOME/lib/libsunec.so $PROJECT_DIR/src/main/zip.native/
cp $GRAALVM_HOME/lib/security/cacerts $PROJECT_DIR/src/main/zip.native/

手順5. デプロイパッケージの作成

デプロイパッケージの作成手順は変わりません。

mvn clean package -Pnative

手順6. デプロイパッケージの内容の確認

SSL有効化した状態でデプロイパッケージを作成すると、target/function.zipの中身が変わります。

bash-4.2# unzip function.zip 
Archive: function.zip
inflating: bootstrap
inflating: cacerts
inflating: libsunec.so
inflating: runner
bash-4.2#

事前準備したbootstrap``cacerts``libsunec.soが含まれているのがわかります。

終わりに

通常のJavaランタイムよりも、コールドスタートが早くなる検証結果はこちらで確認ください。

QuarkusがJava Lambdaを救う!?

· 約2分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

すごいですQuarkus!!!!!! JavaのLambdaのコールドスタートがチョッパヤです!!

以下の公式サイトを参考に試しました。

https://quarkus.io/guides/amazon-lambda#tracing-with-aws-xray-and-graalvm

テスト対象

前回のAWS LambdaのJavaは遅い?とほぼ同じですが、以下が異なります。いずれもQuarkusの制限?制約?です。

  • アノテーションが付いてる
  • httpClientがUrlConnectionHttpClient
ソース全体
package example;

import javax.inject.Named;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;

@Named("test")
public class TestLambda implements RequestHandler<Object, Object> {

@Override
public Object handleRequest(Object input, Context context) {

String ENV_BUCKET = System.getenv("BUCKET");

S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_1)
.httpClient(software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient.builder().build())
.build();

PutObjectResponse result = s3.putObject(
PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
RequestBody.fromString("contents"));

System.out.println(result);

return "";
}
}

検証結果

回数レイテンシ(ms)処理内容
12700
2250
3305
4319
5187

前回はコールドスタートが6200msだったので、めちゃ早になりました!

検証結果(+Provisioned Concurrency)

こんなチョッパヤなQuarkusさんをProvisionedにしたらどうなるんでしょうね。ワクワクしますね。

回数レイテンシ(ms)処理内容
1417
2198
3206
4270
5147

期待を裏切らない速さ!すごいよ、Quarkus!

参考

https://quarkus.io/guides/amazon-lambda#tracing-with-aws-xray-and-graalvm https://aws.amazon.com/jp/blogs/architecture/field-notes-optimize-your-java-application-for-aws-lambda-with-quarkus/