はじめに
タイトルどおりのハンズオンです。
古すぎない Mac or Windows PC とインターネット接続、やり遂げる意志以外の前提条件はありません。
作成したコンテナのデプロイまで試したい場合は、OpenShift クラスター環境が必要です。
以下の記事は M1 Mac で検証 & 執筆しておりますので、Windows 組の方はよしなに読み替えて下さい。
準備
ハンズオン実施中はインターネットに接続している必要があります。
まずは Java がないと始まりません。
% java -version
として、Java 17 または 21 が見つかれば OK です。
なかった場合は Semeru Runtimes をインストールしましょう。
https://developer.ibm.com/languages/java/semeru-runtimes/downloads/
このハンズオンの作成は M1 Mac で Semeru Runtimes の 21 を使用しています。
Mac で複数の JDK インストールを切り替える方法は、"Mac Java 切り替え" あたりでググってみて下さい。
各プラットフォーム用の Podman をインストールしておきます。
Mac の場合は以下です。
% brew install podman
brew コマンドがないと言われた方は Homebrew のインストールから。
https://brew.sh/ja/
Podman のインストールができたら、Podman Machine を初期化して起動しておきます。
% podman machine init
% podman machine start
アプリケーションのビルドのために Maven が必要です。お持ちでない場合はこれも Homebrew で。
% brew install maven
アプリケーションのテストに curl を使用します。お持ちでない場合は(以下略)。
% brew install curl
Openshift クラスターを操作するために oc コマンドが必要です。
Mac の方はこれも Homebrew でインストールできます。
% brew install openshift-cli
Windows の方は、Red Hat アカウントをお持ちであれば こちら から入手できると思います(未確認)。
もしくは こちら を参照して下さい。
IDE は Visual Studio Code (以下 VSCode) を使用します。お持ちでない場合はこちらから。
https://azure.microsoft.com/ja-jp/products/visual-studio-code
既にインストール済みの方は、バージョンが 1.78 以降であることを確認して下さい。
VSCode をインストールしたら、Liberty Tools 追加機能をインストールします。
左端で縦にアイコンが並んでいるところから、追加機能のアイコン をクリックして、検索窓に Liberty と入力します。
Liberty Tools のパネルをクリックして、Install ボタンを押します。
インストールが済んだら、エクスプローラーのアイコン を押します。
今回は自分のホームディレクトリに code-workspace という名前のディレクトリを作成して、ワークスペースに追加しています。みなさまは他のディレクトリでも構いません。
スタータープロジェクトのダウンロード
Open Liberty の Web サイトに、スタータープロジェクトを作成してダウンロードできるページがあります。
https://openliberty.io/start/
スタータープロジェクトは Liberty で稼働させるアプリケーション開発を始める際のテンプレートになるプロジェクトです。何もないところから始めるのは意外に大変なのですが、Liberty ではスタータープロジェクトを簡単に作成して入手できるので、すぐにアプリケーション開発を始めることができます。
Group は何でもよいですが今回は com.babatch.demo とします。
Artifact は liberty-container とでもしましょう。
Java SE はお手許の環境に合わせて 17 もしくは 21、Java EE/Jakarta EE はせっかくなので 10.0 で、MicroProfile は使わないと思いますので None としましょう。
Generate Project を押すとダウンロードが始まりますので、適当なディレクトリにダウンロードし、liberty-container ディレクトリを作ってその中に展開して、liberty-container ディレクトリを先ほど作成した code-workspace ディレクトリに移動します。
ここで、VSCode のエクスプローラーでワークスペースを展開すると、このようになっているはずです。
まずは Hello World
はじめてのアプリケーション開発といえば Hello World ですね。K&R なつかしー。
VSCode のエクスプローラーで src/main 下の java/com/babatch/demo/rest を選択して、New File... を押します。
新規ファイル名を HelloWorldResource.java として、内容を編集します。
右下にこのダイアログが出てきた場合は、Install を押しておきましょう。
今後の作業中にも何度か同様のダイアログが出ますが、Install を押しておいて構いません。
Get Started with Java Development というタイトルのウィンドウが開いて、Java ランタイムをインストールするように言われることがありますが、Java は既にインストールしたはずですので、確認だけしておきます。
create a new terminal をクリックして、java -version
を打ちます。
% java -version
openjdk version "21.0.2" 2024-01-16 LTS
IBM Semeru Runtime Open Edition 21.0.2.0 (build 21.0.2+13-LTS)
Eclipse OpenJ9 VM 21.0.2.0 (build openj9-0.43.0, JRE 21 Mac OS X aarch64-64-Bit 20240116_96 (JIT enabled, AOT enabled)
OpenJ9 - 2c3d78b48
OMR - ea8124dbc
JCL - 78c4500a434 based on jdk-21.0.2+13)
確認できたら Mark Done をクリックします。
エクスプローラーのアイコンを押して編集作業に戻ります。
HelloWorldResource.java を以下の内容で編集して保存します。
package com.babatch.demo.rest;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/helloworld")
public class HelloWorldResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHelloWorld() {
return "Hello World.";
}
}
HelloWorldResource.java と同じディレクトリに最初から作成されている、RestApplication.java の内容を見ておきます。
@ApplicationPath("/api")
となっていますね。
Liberty 構成の確認
src/main/liberty/config/server.xml も見ておきます。server.xml は Liberty の主要な構成ファイルです。
webApplication タグで、コンテキストルートがどのように設定されているか確認しておきます。
httpEndpoint に host="*" がないので、このままでは Liberty サーバーと同じマシンからのリクエストしか受け付けることができません。以下のように書き足して保存しておきましょう。
<httpEndpoint id="defaultHttpEndpoint"
host="*"
httpPort="9080"
httpsPort="9443" />
liberty-container 直下の pom.xml も見ておきましょう。
plugins タグの中で liberty-maven-plugin が構成されています (VSCode にインストールした Liberty Tools とは異なります)。
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<version>3.10.2</version>
</plugin>
これが使えるおかげで、Liberty サーバーをあらかじめインストールしておくことなく、Maven の Central Repository から必要なファイルを自動的に取ってきて作成したアプリケーションをテストしたり、サーバーとアプリケーションをまるごとパッケージして配布可能な zip ファイルを作成したりすることができます。
アプリケーションのテスト
お待たせしました。では作成したアプリケーションをテストしてみましょう。
ターミナルを開いて、カレントディレクトリを code-workspace/liberty-container へ移します。
移ったら ./mvnw liberty:dev
として、dev モードで起動した Liberty 上でアプリケーションをテストします。
% ./mvnw liberty:dev
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< com.babatch.demo:liberty-container >-----------------
[INFO] Building liberty-container 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- liberty:3.10.2:dev (default-cli) @ liberty-container ---
Downloading from central: https://repo.maven.apache.org/maven2/io/openliberty/openliberty-kernel/maven-metadata.xml
(以下略)
Maven と liberty-maven-plugin を使用することで、必要なファイルが自動的にダウンロードされて、テストの準備が実行されます。あらかじめ Liberty サーバーをダウンロードしてインストールしておく必要はありません。
下の行が表示されて画面のスクロールが止まります。
[INFO] [監査 ] CWWKZ0003I: アプリケーション liberty-container が 0.300 秒で更新されました。
別のターミナルを開いて、以下のようにしてアプリケーションをテストします。
% curl http://localhost:9080/liberty-container/api/helloworld
Hello World.
REST アプリケーションから Hello World. が返ったでしょうか。
dev モードの威力を一つ見ておきましょう。
HelloWorldResource.java の "Hello World." メッセージを、お好きな文字列に書き換えて保存します。
もう一度、curl を使用してアプリケーションをテストします。
% curl http://localhost:9080/liberty-container/api/helloworld
Hello Beer!
dev モードではこのように、アプリケーションの変更を自動的に検知して再ビルドがかかり、変更内容をすぐに確認することができます。
dev モードを起動したターミナルに戻ると、アプリケーションの再ビルドの様子がわかると思います。このターミナルで Ctrl+C を押して、dev モードを終了しておきます。
コンテナのビルド
まず、コンテナ内にコピーするためにアプリケーションの war ファイルをビルドしておきます。
先ほどのターミナルから以下を発行します。
% ./mvnw install
これにより、target 直下に liberty-container.war が作成されます。
次に、Dockerfile1 の内容を確認しておきます。
FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
COPY --chown=1001:0 /src/main/liberty/config /config
RUN features.sh
COPY --chown=1001:0 target/*.war /config/apps
RUN configure.sh
1行目の FROM はベースイメージの指定ですね。
今回は OpenJ9 (Semeru Runtimes) の Java 21 で稼働する Open Liberty の最小化イメージを使用します。
2行目はプロジェクト内の /src/main/liberty/config ディレクトリを、コンテナイメージの /config ディレクトリにコピーするように指示しています。
3行目は features.sh を実行するよう指示しています。FROM で指定しているイメージ名に kernel-slim が入っていますので、このイメージは Liberty フィーチャーに必要なファイルを同梱していません。そのため、features.sh を実行して、フィーチャーに必要なファイルをダウンロードしてコンテナイメージに組み込みます。
組み込むフィーチャーは、server.xml の <featureManager>
タグ内で列挙されています。
4行目は target 直下の war ファイルを、コンテナイメージの /config/apps ディレクトリにコピーしています。想像通り、アプリケーションのインストールですね。
5行目の configure.sh は、Enterprise Functionality に必要なファイルを構成したり、iFix を構成したりするのに使用されます。
では、コンテナイメージをビルドしてみましょう。
% podman build -t liberty-container:1.0-SNAPSHOT .
-t で指定している文字列はコンテナイメージ名とタグ名を : で区切ったもの、. は Dockerfile が存在するディレクトリへの相対パスです。
無事にビルドが完了したら、作成されたコンテナイメージを確認してみましょう。
% podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/liberty-container 1.0-SNAPSHOT 67dec371e37c About a minute ago 559 MB
(以下略)
作成されたコンテナイメージを Podman を使用してコンテナとして起動し、動作を確認します。
% podman run -d --name liberty-container -p 9080:9080 liberty-container:1.0-SNAPSHOT
% podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1342ec848a7f localhost/liberty-container:1.0-SNAPSHOT /opt/ol/wlp/bin/s... 4 seconds ago Up 4 seconds 0.0.0.0:9080->9080/tcp liberty-container
% curl http://localhost:9080/liberty-container/api/helloworld
Hello Beer!
おっと、Beer! のままでしたが、まぁ、よしとしましょう。
コンテナを停止して削除しておきます。
% podman stop liberty-container
% podman rm liberty-container
Liberty コンテナの OpenShift へのデプロイ
「あー deployment 作って service 作って route 作って yaml 地獄めんどくせー」と思ったそこのあなた、Liberty では必要ありません。Operator が提供されていますので、必要最小限の yaml で Liberty コンテナの OpenShift クラスタへのデプロイメントは完了します。
OpenShift クラスタの準備は読者のみなさま各自でお願いします。
ワークショップなどでこの記事を使用している場合、OpenShift クラスタへのログインやイメージレジストリについての情報は、インストラクターの方にお尋ね下さい。
クロスプラットフォーム開発への対応
今回は M1 Mac (arm64 アーキテクチャー) で開発を行っていて、デプロイ先の OpenShift クラスターは amd64 アーキテクチャーとなっています。
コンテナイメージのビルドの際には特に考えずに podman build
コマンドを発行しました。この場合、(可能であれば) podman build
コマンドを発行したビルドホストのアーキテクチャーに対応したコンテナイメージが作成されます。
このままの、つまり arm64 アーキテクチャーのみに対応したコンテナイメージを OpenShift クラスターにデプロイしても、アーキテクチャーが異なるために稼働させることができません。
そこで、以下の手順で、arm64 と amd64 の両方に対応したマルチアーキテクチャーのコンテナイメージのように扱うことのできるマニフェストリストを作成して、コンテナイメージをビルドします。(マニフェストについて詳しくは こちら。)
ここまででお気づきと思いますが、amd64 環境、つまり Intel Mac や Windows で作業されている方は、 この作業を実施する必要はありません 。
% podman rmi localhost/liberty-container:1.0-SNAPSHOT
% podman manifest create liberty-container:1.0-SNAPSHOT
% podman build --platform linux/amd64,linux/arm64 --manifest liberty-container:1.0-SNAPSHOT .
build の出力を見ていると、2つのアーキテクチャーのコンテナイメージが順にビルドされている様子がわかると思います。
単に podman build --platform=linux/amd64 ...
として amd64 のイメージを作るのでもよいとは思いますが、個人的には今後、パブリッククラウドで ARM アーキテクチャーのコンテナ環境 が流行る予感がしており、もしそうなった場合にはこの方法が役に立つのではと思います。デプロイする際に amd64 か arm64 かを気にせずに作業できるはずです。
では本題の OpenShift へのデプロイ
まずは OpenShift クラスタにログインします。
いくつか方法があると思いますが、私の場合はこんな感じです。ご使用の環境のお作法に従って下さい。
% oc login --token=sha256~xxx --server=https://api.yyy.zzz.nnn.ibm.com:6443
自分用にプロジェクトを作成します。
ワークショップなどでクラスターを共用している場合は、メールアドレスの @ より左側など、他の参加者と重複しない名前にします。
% oc new-project <プロジェクト名>
以下、<プロジェクト名> は自分で作成したもので読み替えて下さい。
先に作成しておいたコンテナイメージを、OpenShift クラスタ側のイメージレジストリへ push します。
イメージレジストリの route のホスト名を確認します。下はもちろん例ですので、以降はご利用の環境に合わせてホスト名を適宜読み替えて下さい。
% oc -n openshift-image-registry get route
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
default-route default-route-openshift-image-registry.apps.yyy.zzz.nnn.ibm.com image-registry <all> reencrypt None
今回は OpenShift クラスターの内部イメージレジストリを使用しますが、パブリッククラウド環境でクラウドが提供するイメージレジストリを使用するなどの場合は、その環境のお作法に従って下さい。
ローカルのレジストリにあるコンテナイメージに、クラスタ側での名前を付与します。
今回の環境では、クラスタ側での名前は <上で確認した route のホスト名>/<プロジェクト名>/<イメージ名>:<タグ> となります。ご使用の環境のお作法に従って下さい。
% podman tag localhost/liberty-container:1.0-SNAPSHOT default-route-openshift-image-registry.apps.yyy.zzz.nnn.ibm.com/<プロジェクト名>/liberty-container:1.0-SNAPSHOT
ここでイメージレジストリにログインしておきます。これも環境ごとのお作法に従って下さい。
% podman login -u admin -p $(oc whoami -t) default-route-openshift-image-registry.apps.yyy.zzz.nnn.ibm.com
クラスタ側での名前を指定して、コンテナイメージを push します。マルチアーキテクチャーのコンテナイメージの場合 (M1 Mac で作業している方) は以下で push します。
% podman manifest push --all default-route-openshift-image-registry.apps.yyy.zzz.nnn.ibm.com/<プロジェクト名>/liberty-container:1.0-SNAPSHOT
マルチアーキテクチャーでないコンテナイメージの場合 (Intel Mac や Windows の方) は以下で push します。
% podman push default-route-openshift-image-registry.apps.yyy.zzz.nnn.ibm.com/<プロジェクト名>/liberty-container:1.0-SNAPSHOT
正しく push できれば、image と imagestream が作成されているはずです。
% oc get image | fgrep liberty-container
% oc get imagestream | fgrep liberty-container
Open Liberty Operator をインストールします。
OpenShift コンソールで Operator → OperatorHub を開きます。
自分用に作成したプロジェクトを選択して、Open Liberty Operator を検索します。
Open Liberty パネルをクリックし、続けてインストールボタンを押します。
インストールモードで「クラスターの特定のnamespace」を選択して、自分用に作成したプロジェクト名を選択してインストールボタンを押します。
「インストールされた Operator: 使用の準備ができています」と表示されれば Operator のインストールは完了です。
Open Liberty Operator で提供される CRD を以下のようにして確認することができます。
% oc api-resources --api-group=apps.openliberty.io
この節の冒頭で書いたように、今回は Open Liberty Operator を使用してコンテナのデプロイから route での公開までを実行します。
OpenLibertyApplication リソースの yaml を下のように作成します。
ファイル名を liberty-container.yaml として保存します。
apiVersion: apps.openliberty.io/v1
kind: OpenLibertyApplication
metadata:
name: liberty-container
spec:
applicationImage: <プロジェクト名>/liberty-container:1.0-SNAPSHOT
expose: true
あとはこのリソースを oc create
すれば、コンテナがデプロイされて、route 経由でクラスター外からアクセスできるはずです。
% oc create -f ./liberty-container.yaml
状況を確認します。
% oc get all
route の情報から、アプリケーションの URL のホスト名部分がわかります。
OpenShift クラスター上の REST アプリケーションにアクセスしてみます。
% curl https://liberty-container-<プロジェクト名>.apps.yyy.zzz.nnn.ibm.com/liberty-container/api/helloworld
Hello Beer!
正しく Hello Beer! (もしくは自分で書いた文字列) が表示されたでしょうか。
Open Liberty Opertor を使用すると、deployment も service も route も自力で作成する必要がなく、たったこれだけの OpenLibertyApplication の yaml でデプロイから公開までイケちゃいます。
実は Open Liberty Operator にはまだまだたくさんの便利機能が満載になっています。また別の機会にご紹介できればと考えています。
では今回のハンズオンはこの辺で。おつかれさまでした。
あ、1時間で終わらなかった方、ごめんなさい! ちょっと多かったかな…。
-
ちなみに、現在では Dockerfile とは言わず、Containerfile と呼ばれることも増えてきています。以前はコンテナランタイムといえばほぼ Docker 一択でしたが、最近は Docker 以外のランタイムも使用されることが増えているためでしょう。今回使用している Podman はどちらのファイル名でも認識してくれます。 ↩