Red Hat - Open Innovation Labsのブログ - TECH PLAY

TECH PLAY

Red Hat  - Open Innovation Labs

Red Hat - Open Innovation Labs の技術ブログ

全900件

Red Hatでソリューションアーキテクトをしている田中司恩( @tnk4on )です。 ついにこの時が来ました!Apple Silicon搭載Mac(以下、ARM Mac)でOpenShiftが動くようになりました!本記事では誰でも実行可能なインストール手順を解説します。 さぁ、全世界OpenShiftインストール愛好家の皆さん、レッツトライ! (お約束。本記事の内容は検証を目的としており、本番環境での使用や公式なサポートを保証するものではありません。) -目次- Hello, Apple Silicon SNO on ARM Macの構成概要 構成図 構成の特徴 前提条件 パラメーター一覧 インストール方法 Gitリポジトリのクローン インストーラーとOpenShift CLIの入手 RHCOS ISOの入手 DNSサーバーの実行 1. Podman machineをルートモードに変更 2. Podman machineのsystemd-resolvedを停止 3. dnsmasq.confの修正 4. コンテナの実行 Macホストの設定変更 1. /etc/resolver 2. /etc/hosts RHCOS ISOのテスト起動とデバイス名の確認 install-config.yamlの更新 1. インストール先ディスク 2. プルシークレット 3. SSHキー Ignitionファイルの作成 IgnitionファイルをRHCOS ISOへ埋め込む 1. aliasコマンドの登録 2. Ignitionファイルの埋め込み OpenShiftノードの静的IPアドレス設定 1. 環境変数の設定 2. ISOにカーネル引数を設定する RHCOS ISOの起動 (参考)インストール状況のモニタリング 環境のリセット インストール後の状況 One more thing ? Hello, Apple Silicon 2020年11月にM1チップが発表されて以降、ARM Macは高性能、高効率なコンピューターとして注目を集めています。 ところが、このARM Mac上でOpenShiftを動かす取り組みにはこれまで問題がありました。 関連するKCSとしては下記があります。 Can I run RHEL virtualized in a Mac using the Apple M1 processor? - Red Hat Customer Portal 要約すると、 Apple M1チップ(後継のM2も同様)は4Kまたは16Kのページサイズを使用している aarch64版RHEL 7/8は64Kページサイズ用にコンパイルされている この違いによりARM MacではRHEL 7/8 を仮想マシンとして実行できないという問題が発生しています。 現行のOpenShift 4は2019年にリリースされて以降、ベースOSのRed Hat Enterprise Linux CoreOS(以下、RHCOS) はRHEL 8をベースとしてリリースされてきました。そのため、ARM Macではaarch64版RHCOSであっても仮想マシンとして起動できない状況がこれまで続いています。 その後リリースされたaarch64版RHEL 9ではページサイズが4Kに変更されたため、ARM MacでRHEL 9の実行が可能になりました。そしてようやく、OpenShift 4.13のリリースと合わせてRHEL 9ベースのRHCOS(実際は9.2)がリリースされることになり、ARM MacでOpenShiftを動かせるようになったのです。 以降はOpenShift 4.13のRC版を使ってARM MacにシングルノードのOpenShiftをインストールする方法をご紹介します。 SNO on ARM Macの構成概要 構成図 Single Node OpenShift on ARM Mac(UPI)のアーキテクチャー 構成の特徴 1台のARM Mac上で全て完結できるように下記のような特徴があります。 ホストネットワーク上の静的IPアドレスを使用可能 インストールに必要なインフラ要件はDNSサーバーのみ インストール時にBootstrapノードが不要 コンテナを活用し、Macホストの設定変更を最小限にする 前提条件 Macホストからインターネットにアクセスできること Proxy経由、非接続環境も対応可能だと思いますが動作確認はしていません Macホストに仮想マシンを実行できる空きリソースがあること 最小リソース:8 vCPU, 16GB RAM, Disk 100 GB Apple Virtialization Frameworkに対応した仮想環境アプリを用意すること UTM 、 VMware Fusion 、など "Podman Love" コンテナの実行に Podman を使うので Podman Desktop の導入を推奨 *1 他には、OpenShiftのインストール方法に多少の理解があることが望ましいですが、本記事で省略している内容は 製品ドキュメント や 赤帽エンジニアブログ の記事などを参考にしてください パラメーター一覧 インストールに必要なパラメータの一覧です。 ネットワーク 項目 内容 サンプル値 静的IPアドレス1 MacホストのIPアドレス 192.168.1.150 静的IPアドレス2 OpenShiftノードのIPアドレス 192.168.1.40 ネットワークアドレス CIDR 表記の IP ネットワークブロック 192.168.1.0/24 デフォルトゲートウェイ パブリックネットワークへのゲートウェイ 192.168.1.1 ドメイン、クラスター名 項目 内容 サンプル値 ドメイン <base_domain> home.lab クラスター名 <cluster_name> sno 必要なDNSレコード 項目 内容 サンプル値 Kubernetes API api.<cluster_name>. <base_domain> api.sno.home.lab Kubernetes API(内部クラスター通信) api-int.<cluster_name>. <base_domain> api-int.sno.home.lab アプリケーションIngressトラフィック *.apps.<cluster_name>. <base_domain> *.apps.sno.home.lab OpenShiftノード <host_name>. <cluster_name>. <base_domain> m1-ocp.sno.home.lab インストール方法 参照するインストールドキュメントは下記をベースとしますが、本記事ではARM Mac用に様々なカスタマイズを加えています。 15.2.2. 単一ノードの OpenShift を手動でインストールする Gitリポジトリのクローン インストールに必要なファイル類のテンプレートを用意しています。下記URLのリポジトリをクローンしてご利用ください。 GitHub - tnk4on/sno-on-arm-mac: Install Single Node OpenShift on Apple Silicon-based Mac (ARM Mac) git clone https://github.com/tnk4on/sno-on-arm-mac.git cd sno-on-arm-mac インストーラーとOpenShift CLIの入手 インストールに必要な openshift-install とクライアントの oc を入手して実行パスに配置します。 export OCP_VERSION=4.13.0-rc.2 export ARCH=aarch64 mkdir src cd src curl -LO https://mirror.openshift.com/pub/openshift-v4/$ARCH/clients/ocp/$OCP_VERSION/openshift-install-mac.tar.gz curl -LO https://mirror.openshift.com/pub/openshift-v4/$ARCH/clients/ocp/$OCP_VERSION/openshift-client-mac.tar.gz tar zxf openshift-install-mac.tar.gz tar zxf openshift-client-mac.tar.gz sudo cp openshift-install oc /usr/local/bin/ cd .. OCP_VERSION : 「4.13.0-rc.0」以降を指定します ARCH : ARM Macに対応した「aarch64」を指定します *2 ダウンロードしたアーカイブは src ディレクトリに一時保存します 実行バイナリの配置先はPATH環境変数であればどこでも可能です RHCOS ISOの入手 インストールに使用するRHCOSのISOイメージを入手します。 mkdir iso export ISO_URL=$(openshift-install coreos print-stream-json | grep location | grep $ARCH | grep iso | cut -d\" -f4) curl -L $ISO_URL -o iso/rhcos-live.iso ダウンロードしたISOは iso ディレクトリに保存します。インストールを繰り返す場合はISOの再利用が可能です。 ISOの名前は任意で変更しても問題ありません DNSサーバーの実行 Podmanを使用してDNSサーバーをコンテナで実行します。コンテナイメージは OpenShift Local で使用しているものを利用します。 *3 以降はPodman Desktopを導入後の状態からの解説です。Podman Desktopのインストール方法は下記を参考にしてください。 MacOS | Podman Desktop 1. Podman machineをルートモードに変更 Podman machineで1024番以下のポートをバインドするためにルートモード(rootful)に変更します。 podman machine stop podman machine set --rootful podman machine start Podman machineの実行前であれば podman machine init --rootful で初期設定する方法でも可 2. Podman machineの systemd-resolved を停止 UDPポート53番を使用できるようにPodman machineで実行中の systemd-resolved を停止します podman machine ssh sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf podman machine ssh systemctl restart systemd-resolved podman machine ssh ss -ltnup Podman machineの実行OSであるFedora CoreOSはデフォルトで systemd-resolved が稼働するため設定変更が必要です 関連Issue: macOS : cannot listen on the TCP port: listen tcp4 :53: bind: address already in us · Issue #17690 · containers/podman Podman machineを削除して再作成した場合は再度設定が必要です 3. dnsmasq.confの修正 利用する環境に合わせてドメイン名、ホスト名、IPアドレスを修正します。 dnsmasq.confのサンプルを展開 user=root port= 53 expand-hosts log-queries log-facility=- local=/home.lab/ domain=home.lab address=/apps.sno.home.lab/192.168.1.40 address=/api.sno.home.lab/192.168.1.40 address=/api-int.sno.home.lab/192.168.1.40 address=/m1-ocp.sno.home.lab/192.168.1.40 ptr-record=40.1.168.192.in-addr.arpa,m1-ocp.sno.home.lab rev-server=192.168.1.0/24,127.0.0.1 log-queries と log-facility :デバッグ目的で標準出力にクエリログを出力します。不要であれば削除可能です。 ptr-record :OpenShiftノードのみ逆引き設定が必要です。これが無いとインストールが正常に完了しません。 *4 rev-server :逆引きを行うDNSサーバーは自分自身(127.0.0.1)を指定します。 4. コンテナの実行 Podmanを使いDNSサーバーをコンテナで実行します podman run -d --rm -p 53:53/udp -v ./dnsmasq.conf:/etc/dnsmasq.conf --name dnsmasq quay.io/crcont/dnsmasq:latest Mac上の dnsmasq.conf をバインドマウントしてコンテナ内に読み込みます (注意)Mac上では podman system service は使用できないので、コンテナを自動実行したい場合はPodman machine内に仕込むなどの工夫が必要です --rm を付けるかどうかはお好みでどうぞ Macホストの設定変更 Macホスト自身からOpenShiftクラスターへのアクセスに必要なDNS名前解決の設定を行います。 1. /etc/resolver ブラウザー等からOpenShiftクラスターへ接続する際に<cluster_name>. <base_domain>のDNSクエリはコンテナで実行中のDNSサーバーへ転送するように /etc/resolver を使用します。 sudo tee /etc/resolver/sno.home.lab &>/dev/null <<EOF nameserver 127.0.0.1 EOF 2. /etc/hosts oc クライアントは /etc/resolver を通過したDNS名前解決を行わないため、静的に /etc/hosts にOpenShiftクラスターのKubernetes APIのDNSレコードを登録します。 sudo tee -a /etc/hosts &>/dev/null <<EOF 192.168.1.40 api.sno.home.lab EOF RHCOS ISOのテスト起動とデバイス名の確認 使用する仮想環境アプリでOpenShiftノード用の仮想マシンを作成します。 [UTMの場合の設定参考値] 項目 サンプル値 CPU(Cores) 8 Memory(MB) 16384 Storage(GB) 100 *5 Use Apple Virtualization オン Network Mode Bridged Boot ISO Image <任意のパス>/iso/rhcos-live.iso CPU、Memoryのサンプル値は最小リソース要件より 15.1.3. 単一ノードに OpenShift をインストールするための要件 仮想マシン作成後、ISOから起動します。ISOの起動手順は仮想環境アプリに準じます。 正常にRHCOSがLiveモードで起動すると core ユーザーでログインした状態のコンソールが表示されます。 その後、インストールに必要なストレージデバイス名とNIC名を確認します。 sudo fdisk -l ip a (参考) NIC: enp0s1 (UTM), ens160 (VMware Fusion) ストレージデバイス: /dev/vda (UTM), /dev/nvme0n1 (VMware Fusion NVMe), /dev/sda (VMware Fusion SATA) install-config.yamlの更新 ご利用の環境に合わせて install-config.yaml の内容を修正します。 install-config.yamlのサンプルを展開 apiVersion: v1 baseDomain: home.lab compute: - name: worker replicas: 0 controlPlane: name: master replicas: 1 metadata: name: sno networking: clusterNetworks: - cidr: 10.128.0.0/14 hostPrefix: 23 machineNetwork: - cidr: 192.168.1.0/24 networkType: OVNKubernetes serviceNetwork: - 172.30.0.0/16 platform: none: {} bootstrapInPlace: installationDisk: /dev/vda pullSecret: '{"auths":...}' sshKey: 'ssh-ed25519 AAAA...' 1. インストール先ディスク 前項で確認したストレージデバイス名に合わせて、 install-config.yaml 内の installationDisk: 値を修正します。 bootstrapInPlace: installationDisk: /dev/vda 2. プルシークレット Red Hat Hybrid Cloud Console から入手したプルシークレットを pullSecret: に貼り付けます。 pullSecret: '{"auths":...}' 3. SSHキー 事前に作成したSSHキーペアの公開鍵を sshKey: に貼り付けます (参考) 25.1.6. クラスターノードの SSH アクセス用のキーペアの生成 sshKey: 'ssh-ed25519 AAAA...' Ignitionファイルの作成 インストールディレクトリを作成し、Ignitionファイルを作成します。 mkdir ocp cp install-config.yaml ocp openshift-install --dir=ocp create single-node-ignition-config (注意)Ignitionファイルを作成すると使用した install-config.yaml は失われるので、毎回コピーして元ファイルを残すようにしましょう Ignitionファイルの作成後のインストールディレクトリ構成は下記のようになります ocp ├── auth │   ├── kubeadmin-password │   └── kubeconfig ├── bootstrap-in-place-for-live-iso.ign ├── metadata.json └── worker.ign Bootstrap Inplace方式でインストールするため、 worker.ign は使用しません IgnitionファイルをRHCOS ISOへ埋め込む RHCOS ISOにIgnitionファイルを埋め込むには coreos-installer を使用します。しかしながらMac向けの coreos-installer コマンドは無いため、コンテナで実行して代用します。 1. aliasコマンドの登録 コンテナ実行コマンドをaliasコマンドとして登録します alias coreos-installer='podman run --privileged --rm \ -v $PWD:/data \ -w /data quay.io/coreos/coreos-installer:release' coreos-installer --version バージョンが表示されればOKです (参考) 15.2.2.1. coreos-installer によるインストール ISO の生成 ドキュメントのコンテナ実行コマンドはLinux向けで記載されているためMac上のPodmanで実行した場合はエラーになります。そのためバインドマウントオプションをMac向けに修正しています。 2. Ignitionファイルの埋め込み coreos-installer コマンドを使い、RHCOS ISOに bootstrap-in-place-for-live-iso.ign ファイルを埋め込みます coreos-installer iso ignition embed -fi ocp/bootstrap-in-place-for-live-iso.ign iso/rhcos-live.iso エラーなくコマンドが終了すれば成功です。特にログ出力などはありません。見た目はISOファイルの更新日時が変更されるくらいです。 OpenShiftノードの静的IPアドレス設定 RHCOS ISOイメージに事前にカーネル引数を設定することで、RHCOSライブ環境の起動時に静的IPアドレスを設定します。 (余談)OpenShiftノードに静的IPアドレスを設定する方法はドキュメントやKCSにもいくつか手順がありますが、今回のインストール方法(SNOのBootstrap Inplaceインストール)では下記の理由により後述するISOにカーネル引数を設定する方法しか採用できません。 coreos-installer iso ignition embed と coreos-installer iso customize が併用できない Ignitionファイルを埋め込んでいるため自動でインストールが始まってしまう(ライブ環境起動後に手動でカーネル引数の設定ができない) 1. 環境変数の設定 カーネル引数に指定する環境変数を設定します export IP=192.168.1.40 export GATEWAY=192.168.1.1 export NETMASK=255.255.255.0 export INT=enp0s1 export HOSTNAME=m1-ocp.sno.home.lab export DNS=192.168.1.150 2. ISOにカーネル引数を設定する coreos-installer コマンドを使い、ISOにカーネル引数を設定します coreos-installer iso kargs modify -a "console=ttyS0 rd.neednet=1 ip=${IP}::${GATEWAY}:${NETMASK}:${HOSTNAME}:${INT}:none nameserver=${DNS}" iso/rhcos-live.iso (参考:KCS) Single Node OpenShift (SNO) to support static IP configuration during installation - Red Hat Customer Portal RHCOS ISOの起動 iso/rhcos-live.iso を使用してISOを起動します。ISO起動後は自動でクラスターのインストールが開始されます。 インストールの自動実行中、下記のタイミングで再起動が2回行われます。 1回目:ISO起動→ディスクへ書き込み完了後 2回目:Bootstrap開始→Bootstrap完了後 (余談) 4.13.0-rc.0 を使用すると、Bootstrapプロセスに移行後にRHCOSからCentOS Stream CoreOSへ切り替わります。 4.13.0-rc.2 以降はRHCOSに完全移行しました。 (参考)インストール状況のモニタリング OpenShiftのインストール実行中、ターミナルウィンドウを複数開き下記のコマンドを利用してログのモニタリングができます。 ターミナル1: RHCOSノード上のログ export IP=192.168.1.40 sed -i -e "/${IP}/d" ~/.ssh/known_hosts ssh core@${IP} -o "StrictHostKeyChecking=no" journalctl -b -f ターミナル2:Cluster Operatorの起動状況 export KUBECONFIG=ocp/auth/kubeconfig watch -n 1 oc get co ターミナル3:インストールログ export KUBECONFIG=ocp/auth/kubeconfig openshift-install --dir=ocp wait-for bootstrap-complete openshift-install --dir=ocp wait-for install-complete ターミナル4: DNSサーバーのログ podman logs -f dnsmasq 環境のリセット インストールに問題があった場合は下記を実行して環境をリセットします。その後、IgnitionファイルをRHCOS ISOへ埋め込む手順から再開します。 インストールディレクトリの削除 rm -rf ocp ISOイメージの初期化 coreos-installer iso reset iso/rhcos-live.iso インストール後の状況 インストール直後のディスク使用量(ディスクイメージのサイズ)は 約23 GBでした。 Activity Monitorで見たCPU、メモリの状況は下記の通りです。ホストはM1 MAX(10コア/64GB RAM)です。 CPUの状況 Memoryの状況 Chrome、VS Code、Podman Desktop、UTMなどを立ち上げた状態でも、特にOSの動作上の重さなどは感じられません。 One more thing ? OpenShift 4.13のRC版が公開されたことにより、誰でもARM MacにOpenShiftをインストールすることができるようになりました。 *6 現時点ではインストールができる状態に辿り着いたところなので、実際の性能面や互換性は未知数です。ですが、普段使いのARM Macで常時動かせるOpenShift環境があるというのはとてもワクワクします。M2 MaxやM1 Ultraなどを搭載した端末ならどこまでできるのか?などと考えるのも楽しいものです。 さらに!今回紹介したUPIをベースとした手動インストール方法の他に、もっとインストールを簡単にする方法があります。 支援付きインストーラー(Assisted Installer) とOCP 4.12から登場した エージェントベースのインストーラー(Agent-Based Installer) です。残念ながら本記事執筆時点ではARM Macに対してこれらの方法を用いたインストールができません。インストールの確認ができたらまた別の記事にて紹介したいと思います。 (2023/4/3、追記) エージェントベースのインストール記事を公開しました! rheb.hatenablog.com (2023/5/10、追記) 支援付きインストーラーの記事を公開しました! rheb.hatenablog.com *1 : 他のコンテナ実行環境でも代替えは可能だと思いますが、せっかくなのでPodmanを使いましょう! *2 : ハマりポイントその1。バイナリ名が同じなのでopenshift-install versionを実行してrelease architecture:の出力結果を確認するしかamd64なのかarm64なのか判別できません。 *3 : OpenShift Localの中で動いているコンテナについてはこの記事で紹介しています https://rheb.hatenablog.com/entry/crc_remote_connecting *4 : ハマりポイントその2。このPTRレコードが無いとCluster Operatorの起動終盤で進まなくなります。 *5 : 100GBでもインストール前の検証にパスするようにバグが修正されました https://github.com/openshift/installer/pull/7025 *6 : 非公開イメージを使ったRed Hat公式ブログの記事はありましたが、誰でもインストールできるようになったのは4.13 RC版公開以降です。 https://cloud.redhat.com/blog/openshift-on-an-apple-m1-vm-with-red-hat-advanced-cluster-management
こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 前回に引き続きRed Hat OpenShift Data Science(RHODS)についての記事となります。 rheb.hatenablog.com 今回はRHODSで利用できるカスタムイメージの作り方や、その他役立つ設定などをご紹介していきます。 カスタムイメージについて 前回の記事の中で、RHODSではデフォルトで利用可能な5つのコンテナイメージがあることに触れました。 ・Minimal Python ・Standard Data Science ・CUDA ・PyTorch ・TensorFlow それぞれのイメージの中身について詳しくは以下のドキュメントをご参照下さい。 access.redhat.com しかしながら実際の機械学習においてはこれらのイメージの中で提供されるライブラリでは不足するケースがあるかと思います。 その場合、以下二つの選択肢が考えられます。 1) デフォルトのイメージを起動後、追加のライブラリをインストールする 2) 追加ライブラリを含むカスタムイメージを作成し、そちらを利用する まず一つ目についてですが、アドホックに試したいライブラリを追加しながら開発をするという点では良いと思われます。ただし、無計画にpipでライブラリをインストールするとバージョンや依存関係の管理が困難となるため、 Poetry や pipenv などの管理ツールを利用するのが良いと思われます。 二つ目のカスタムイメージとはデフォルトで提供されるコンテナイメージとは別にユーザー自身が作成し登録、管理するイメージです。 複数のユーザーで共通的に使われることが分かっているライブラリなどがある場合は、予めそれを含めた形でコンテナイメージを作成しておくことで、ユーザー側でのインストール作業を無くし、環境準備に必要な手間や時間を節約することができます。 一方でデフォルトイメージではRed Hatがイメージに含まれるPythonのライブラリも含め管理しており、それらのバージョンアップも提供しますが、カスタムイメージではこうした作業はユーザー自身で行う必要があります。 カスタムイメージの作成方法としてゼロから自分でイメージを作成する方法もありますが、より簡単な方法としてデフォルトのイメージに対して必要なライブラリを追加し、別のコンテナイメージとしてビルドするやり方が考えられます。 今回はこの方法でカスタムイメージを作成し、RHODSに追加してみたいと思います。 カスタムイメージの作成 1 まずデフォルトイメージの取得元を確認したいと思います。 RHODSをクラスタにインストールすると、デフォルトのコンテナイメージを redhat-ods-applications プロジェクト以下に見つけることができます。 oc get imagestream -n redhat-ods-applications --- NAME IMAGE REPOSITORY TAGS UPDATED minimal-gpu default-route-openshift-image-registry.apps.mycluster2.ljxh.p1.openshiftapps.com/redhat-ods-applications/minimal-gpu py3.8-cuda-11.4.2-2 2 hours ago pytorch default-route-openshift-image-registry.apps.mycluster2.ljxh.p1.openshiftapps.com/redhat-ods-applications/pytorch py3.8-cuda-11.4.2-2 2 hours ago s2i-generic-data-science-notebook default-route-openshift-image-registry.apps.mycluster2.ljxh.p1.openshiftapps.com/redhat-ods-applications/s2i-generic-data-science-notebook py3.8-v1 2 hours ago s2i-minimal-notebook default-route-openshift-image-registry.apps.mycluster2.ljxh.p1.openshiftapps.com/redhat-ods-applications/s2i-minimal-notebook py3.8-v1 2 hours ago tensorflow default-route-openshift-image-registry.apps.mycluster2.ljxh.p1.openshiftapps.com/redhat-ods-applications/tensorflow py3.8-cuda-11.4.2-2 2 hours ago 例えばここで s2i-generic-data-science-notebook の中身を見てみると、annotationの記載内容からイメージ取得元のQuayのリポジトリやコードを管理しているGitHubのアドレスを見つける事ができます oc get imagestream s2i-generic-data-science-notebook -o yaml -n redhat-ods-applications --- apiVersion: image.openshift.io/v1 kind: ImageStream metadata: annotations: kfctl.kubeflow.io/kfdef-instance: rhods-nbc.redhat-ods-applications opendatahub.io/notebook-image-desc: Jupyter notebook image with a set of data science libraries that advanced AI/ML notebooks will use as a base image to provide a standard for libraries avialable in all notebooks opendatahub.io/notebook-image-name: Standard Data Science opendatahub.io/notebook-image-order: "20" opendatahub.io/notebook-image-url: https://github.com/red-hat-data-services/notebooks/tree/main/jupyter/datascience/ubi8-python-3.8 # GitHubリポジトリ openshift.io/image.dockerRepositoryCheck: "2023-03-13T03:28:45Z" creationTimestamp: "2023-03-13T03:28:44Z" generation: 2 labels: component.opendatahub.io/name: jupyterhub opendatahub.io/component: "true" opendatahub.io/notebook-image: "true" name: s2i-generic-data-science-notebook namespace: redhat-ods-applications resourceVersion: "89518" uid: 67a69042-65b9-43d9-b7d1-12130aaef565 spec: lookupPolicy: local: true tags: - annotations: opendatahub.io/notebook-python-dependencies: '[{"name":"Boto3","version":"1.17"},{"name":"Kafka-Python","version":"2.0"},{"name":"Matplotlib","version":"3.4"},{"name":"Numpy","version":"1.19"},{"name":"Pandas","version":"1.2"},{"name":"Scikit-learn","version":"0.24"},{"name":"Scipy","version":"1.6"}]' opendatahub.io/notebook-software: '[{"name":"Python","version":"v3.8"}]' openshift.io/imported-from: quay.io/modh/odh-generic-data-science-notebook # Quayリポジトリ from: kind: DockerImage name: quay.io/modh/odh-generic-data-science-notebook@sha256:ebb5613e6b53dc4e8efcfe3878b4cd10ccb77c67d12c00d2b8c9d41aeffd7df5 generation: 2 importPolicy: importMode: Legacy name: py3.8-v1 referencePolicy: type: Source コンテナイメージについては、 quay.io/modh/odh-generic-data-science-notebook ソースコードについては、 https://github.com/red-hat-data-services/notebooks/tree/main/jupyter/datascience/ubi8-python-3.8 で管理されていることがわかりました。 それではこちらの GitHubリポジトリ にアクセスしましょう。 開くと ubi8-python-3.8 というディレクトリの中にコンテナイメージを作成するためのDockerfileや、Pythonのライブラリ依存関係を表すファイルなどがあるのがわかります。 Pipfile、Pipfile.lockは pipenv というPythonの依存関係管理ツールで利用されるファイル形式です。 Pythonでよく用いられるpipによるインストールでは、requirements.txtというファイルに使用したいライブラリのバージョンを書きますが、 pip-tools などを使わない場合、各ライブラリのハッシュ値を含めた厳密な依存関係の管理を行うことができません。 pipenvではライブラリのインストール時にPipfile.lockというロックファイルを作成し、厳密な依存関係管理を可能としています。 またpipenv以外でよく使用されるツールとしては Poetry があります。こちらはPipfileを使用するpipenvとは異なり、ライブラリの依存関係等をpyproject.tomlという PEP518 で標準化された形式で表現します。Poetryはpyproject.tomlからpoetry.lockというロックファイルを作成します。 Pipfileにライブラリを追加するパターン まずはシンプルにPipfileへ利用したいライブラリを追記してみましょう。 先ほどのGitHubリポジトリでは同じStandard Data Scienceのイメージでも、UBI8 + Python 3.8、UBI9 + Python 3.9というベースイメージとPythonのバージョンが異なる複数のコードを管理しています。 今回はPython 3.9の方のPipfileを取得し、そこに追加したいライブラリの情報を加えます。 [[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [dev-packages] [packages] # Datascience and useful extensions boto3 = "~=1.26.69" jupyter-bokeh = "~=3.0.5" elyra-python-editor-extension = "~=3.14.2" kafka-python = "~=2.0.2" matplotlib = "~=3.6.3" numpy = "~=1.24.1" pandas = "~=1.5.3" plotly = "~=5.13.0" scikit-learn = "~=1.2.1" scipy = "~=1.10.0" jupyterlab-lsp = "~=3.10.2" jupyterlab-widgets = "~=3.0.5" jupyter-resource-usage = "~=0.6.0" jupyterlab-s3-browser = "~=0.10.1" # Parent image requirements to maintain cohesion jupyterlab = "~=3.5.3" jupyter-server = "~=2.1.0" jupyter-server-proxy = "~=3.2.2" jupyter-server-terminals = "~=0.4.4" jupyterlab-git = "~=0.41.0" nbdime = "~=3.1.1" nbgitpuller = "~=1.1.1" # --- thamos = "~=1.29.1" wheel = "~=0.38.4" # 追加ライブラリ ray = "~=2.3.0" xgboost = "~=1.7.4" [requires] python_version = "3.9" ここからpipenvコマンドでロックファイルを作成します。 作業環境にpipenvが無い場合はまずpipでインストールしましょう。 ## pipenvのインストール # pip install pipenv # ロックファイルの作成 pipenv lock これで追加ライブラリを含んだPipfile.lockが作成されました。 あとはこれをイメージに追加しコンテナをビルドします。 以下が今回利用するDockerfileです。 FROM quay.io/modh/odh-generic-data-science-notebook:v2 # Install Python packages and Jupyterlab extensions from Pipfile.lock COPY Pipfile.lock ./ RUN echo "Installing softwares and packages" && micropipenv install && rm -f ./Pipfile.lock # Fix permissions to support pip in Openshift environments RUN chmod -R g+w /opt/app-root/lib/python3.9/site-packages && \ fix-permissions /opt/app-root -P ベースイメージとして、先ほど確認したQuayのリポジトリからUBI9+Python3.9のイメージのタグを指定しています。 またCOPY句で、作成したPipfile.lockをコンテナ内に配置し、こちらを元にライブラリのインストールを行います。 ライブラリのインストールには先ほど使用したpipenvではなく micropipenv を使用しています。 通常のpipenvはライブラリのインストール時に自動でPython仮想環境を作成しますが、micropipenvはコンテナでの利用を前提とし、仮想環境の作成を行わずライブラリのインストールのみを行います。 micropipenvはPipfile.lockだけでなく、Poetryが使用するpoetry.lockや、requirements.txtという複数の形式に対応しているのが特徴です。 より詳しくはGitHubや以下のブログ(英語)をご参照下さい。 developers.redhat.com このDockerfileをPodmanでビルドします。 DockerfileとPipfile.lockがあるディレクトリで以下のコマンドを実行しましょう。 podman build . -t custom-datascience-image:pipfile ビルドしたらQuay.ioにプッシュします。 # ログイン podman login # タグ付け podman tag custom-datascience-image:pipfile quay.io/jishikaw/custom-datascience-image:pipfile # プッシュ podman push quay.io/jishikaw/custom-datascience-image:pipfile 今回はパブリックなリポジトリにイメージを置いたため こちら からアクセスできます。 ここまででPipfileを使って依存関係を管理しながらカスタムイメージのビルドができました。 Poetryで依存関係を管理するパターン もう一つのパターンとして既存でPoetryを使用して依存関係を管理しているパターンについても考えましょう。 この場合はPipfileに対してライブラリを追加するのではなく、Poetryのpyproject.tomlにPipfileに書かれたライブラリを追記します。 今回は下記のpyproject.tomlを作成しました。 [tool.poetry] name = "my custom notebook" version = "0.1.0" description = "my custom notebook" authors = ["jpishikawa"] [tool.poetry.dependencies] python = "~=3.9" elyra = "^3.11.0" mlflow = "^1.28.0" # 以下はPipfileから追記 # Datascience and useful extensions boto3 = "~=1.26.69" jupyter-bokeh = "~=3.0.5" elyra-python-editor-extension = "~=3.14.2" kafka-python = "~=2.0.2" matplotlib = "~=3.6.3" numpy = "~=1.24.1" pandas = "~=1.5.3" plotly = "~=5.13.0" scikit-learn = "~=1.2.1" scipy = "~=1.10.0" jupyterlab-lsp = "~=3.10.2" jupyterlab-widgets = "~=3.0.5" jupyter-resource-usage = "~=0.6.0" jupyterlab-s3-browser = "~=0.10.1" # Parent image requirements to maintain cohesion jupyterlab = "~=3.5.3" jupyter-server = "~=2.1.0" jupyter-server-proxy = "~=3.2.2" jupyter-server-terminals = "~=0.4.4" jupyterlab-git = "~=0.41.0" nbdime = "~=3.1.1" nbgitpuller = "~=1.1.1" # --- thamos = "~=1.29.1" wheel = "~=0.38.4" [tool.poetry.dev-dependencies] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" このファイルがあるディレクトリで以下を実行しロックファイルを作成します。 作業環境にpoetryが無い場合はインストールします。 ## Poetryのインストール # pip install poetry # ロックファイルの作成 poetry lock 実行すると以下が表示されロックファイルの作成が中断されました。 Updating dependencies Resolving dependencies... (3.9s) The current project's Python requirement (>=3.9,<4.0) is not compatible with some of the required packages Python requirement: - scipy requires Python <3.12,>=3.8, so it will not be satisfied for Python >=3.12,<4.0 - scipy requires Python <3.12,>=3.8, so it will not be satisfied for Python >=3.12,<4.0 Because no versions of scipy match >1.10.0,<1.10.1 || >1.10.1,<1.11.0 and scipy (1.10.0) requires Python <3.12,>=3.8, scipy is forbidden. So, because scipy (1.10.1) requires Python <3.12,>=3.8 and my custom notebook depends on scipy (~=1.10.0), version solving failed. • Check your dependencies Python requirement: The Python requirement can be specified via the `python` or `markers` properties For scipy, a possible solution would be to set the `python` property to ">=3.9,<3.12" For scipy, a possible solution would be to set the `python` property to ">=3.9,<3.12" https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies, https://python-poetry.org/docs/dependency-specification/#using-environment-markers どうやらscipyのバージョン1.10.0をインストールする場合、Pythonのバージョンは3.12未満であることを明記する必要があるそうです。 メッセージの内容に合わせ元のpyproject.tomlを修正します。 [tool.poetry] name = "my custom notebook" version = "0.1.0" description = "my custom notebook" authors = ["jpishikawa"] [tool.poetry.dependencies] # 変更 python = ">=3.9,<3.12" elyra = "^3.11.0" mlflow = "^1.28.0" # 以下はPipfileから追記 # Datascience and useful extensions boto3 = "~=1.26.69" jupyter-bokeh = "~=3.0.5" elyra-python-editor-extension = "~=3.14.2" kafka-python = "~=2.0.2" matplotlib = "~=3.6.3" numpy = "~=1.24.1" pandas = "~=1.5.3" plotly = "~=5.13.0" scikit-learn = "~=1.2.1" scipy = "~=1.10.0" jupyterlab-lsp = "~=3.10.2" jupyterlab-widgets = "~=3.0.5" jupyter-resource-usage = "~=0.6.0" jupyterlab-s3-browser = "~=0.10.1" # Parent image requirements to maintain cohesion jupyterlab = "~=3.5.3" jupyter-server = "~=2.1.0" jupyter-server-proxy = "~=3.2.2" jupyter-server-terminals = "~=0.4.4" jupyterlab-git = "~=0.41.0" nbdime = "~=3.1.1" nbgitpuller = "~=1.1.1" # --- thamos = "~=1.29.1" wheel = "~=0.38.4" [tool.poetry.dev-dependencies] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" 改めて poetry lock を実行しロックファイルを作成しましょう。 私の環境では大体3分弱でpoetry.lockが作成されました。 あとはPipfileの時と同様にロックファイルをコピーしコンテナをビルドします。 micropipenvを使ってpoetry.lockからライブラリをインストールする場合、pyproject.tomlも必要になるためそちらもコピーします。 FROM quay.io/modh/odh-generic-data-science-notebook:v2 # Install Python packages and Jupyterlab extensions from poetry.lock COPY poetry.lock pyproject.toml ./ RUN echo "Installing softwares and packages" && micropipenv install && rm -f ./poetry.lock && rm -f ./pyproject.toml # Fix permissions to support pip in Openshift environments RUN chmod -R g+w /opt/app-root/lib/python3.9/site-packages && \ fix-permissions /opt/app-root -P このDockerfileを使ってビルドします。ビルドしたら先ほどと同様に Quayリポジトリにプッシュします。 podman build . -t custom-datascience-image:poetry podman tag custom-datascience-image:poetry quay.io/jishikaw/custom-datascience-image:poetry podman push quay.io/jishikaw/custom-datascience-image:poetry これで無事コンテナイメージを作成することができました。 既にPoetryを使って依存関係の管理をしている場合はこちらの方法を取ると良いでしょう。 RHODSへのカスタムイメージの追加 ここからはRHODSのコンソールを使用し、先ほど作成したカスタムイメージをインポートします。 画面左の"Settings -> Notebook images"からインポート画面に移ります。 インポートするコンテナイメージの場所や、RHODS上で表示する名前、説明、含まれるパッケージ等の情報を入力していきます。 入力が完了したら"Import"を実行しましょう。 無事にインポートができました。 カスタムイメージ一覧の画面では"Enable"のトグルにより、ユーザーがNotebook作成時にこのカスタムイメージを選択できるか管理することができます。 Notebookの起動画面を見ると追加したカスタムイメージが表示されていることを確認できます。 あとはデフォルトのイメージと同様に起動するとNotebook画面が表示されます。 Notebookの自動停止 最後にRHODS上でアクティブでないNotebookの自動停止設定について見ていきたいと思います。 RHODSコンソールの"Settings -> Cluster settings"を選択すると、 "Stop idle notebooks"という項目があります。 これはアクティブでないNotebookを一定時間後に自動で停止し、Podに割り当てたリソースを回収してくれる機能です。 例えば、GPUを使った学習などを行なっている場合、なるべくGPUを稼働させておきたいため、Notebook停止までの時間を短くすることでリソースを有効に活用することが可能となります。 停止されたNotebookについても作業中のデータはアタッチされたPVに保存されるため、再度Notebookを立ち上げてもすぐに作業を再開できます。 デフォルトではオフとなっていますが上記のような場合では設定しておくとよいでしょう。 まとめ 今回はRHODSのカスタムイメージの作成や、そのインポート等についてご紹介しました。 Pythonでは他の言語と異なり依存関係の管理について色々なやり方があり、慣れないと大変な面もありますが、今回の内容を参考に是非カスタムイメージ作成にチャレンジしてみて下さい。 また今回の記事で作成したファイルは こちら に置いています。 今回ご紹介する方法はあくまで参考となります。カスタムイメージの作成は利用者自身の責任となるため予めご了承下さい。 ↩
Red Hatの森若です。 今回は個人でChatGPT Proを契約したので、ChatGPTをRHELの運用に使えるか試してみます。 趣旨とご注意 ログの意味を教えてもらう やりたいことの実現方法を聞いてみる チェックリストのたたき台を作ってみる ドキュメントの検索をさせてみる ナレッジベースを特定バージョンむけに書き換える RHELアップグレードのための稟議書を書いてもらう 趣旨とご注意 趣旨: 乗るしかない このビッグウェーブに…… ということで流行りもので遊んでみるという話です。検索を汚染しないようにChatGPTの出力は画像で貼りつけます。 ご注意: ChatGPT(に限らず現状の大規模言語モデルと呼ばれるもの)は「それらしいテキストを生成する」という技術で、厳密な論理や一貫性のある主張、 発言が正しいことの裏づけなどはできません。使う場合には特徴を踏まえて使いましょう。 ログの意味を教えてもらう 使っているとログがでたもののよくわからないこと、ちょいちょいありますね。 ログをそのまま検索して→それらしいblogや掲示板の書き込みをみつけて→記述内容を読んで〜 みたいなことがよくあります。 これをChatGPTでやってみましょう。 プロンプト : このようなログが出ました。原因と対策を教えてください。 (ログをコピペ) 寸評 : それらしい出力がでてきました。原因は100点をあげられます。対策は70〜80点くらいでしょうか。既にクラッシュして再起動しているはずですからgnome-shellのrestartは意味がありません。gnome-shellをXで利用しているときにはこの操作が可能ですが、Waylandで動作しているときにはこの操作ができません。とはいえこのログしか情報がなく、システムがどのように構成されているかわからないので最初にぱっと思いつく内容としては十分価値があると言ってよさそうです。 もうちょっとややこしい例をためしてみます。ややこしいのでGPT-4を使います。長いので回答は途中まででカットです。 寸評 : なかなかやりますね! 意味と原因のパートは90点です。「依存」という言葉の使い方がややあいまいです。実際には前後関係の矛盾ですが、やはり実際の設定やこのログ発生時の操作がわからない状態ですから十分許容範囲です。 対策は60〜70点くらいでしょうか。/usr/lib/systemd/system/ 以下のファイルを修正するように指示していますが、これはパッケージ更新等で書き変わるので危険です。さらにこのログに登場していない他のunitからも、B.targetやC.targetへの依存関係があるかもしれませんがその事は考慮されていません。とはいえこのログから「ぱっと思いつく内容」としては十分価値があるものです。 やりたいことの実現方法を聞いてみる プロンプト : RHEL 8でtelnetサーバを構築したい 寸評 : telnetは推奨ではなくsshを使うべきという前書きは良いですね。その後に続く手順は(実際には全く使えませんが)30点くらいでしょうか。RHEL 8にはtelnet-serverパッケージが同梱されていますので、EPELを有効にする必要はありません。その他にもsystemdで置き替えられたxinetdを利用しようとしたりしていました。telnet-serverに出番があったRHEL 4〜5くらいの資料の影響が強いのかもしれません。 次は意地悪ですがサポート対象外の構成をあえて聞いてみます。 プロンプト : Windowsのファイル共有をRHELでCIFSマウントして、それをNFSサーバとしてエクスポートしようと思います。考えられる問題と回避策をおしえてください。問題がなければ設定方法をおしえてください。 (中略) 寸評 : 「一般的には推奨されません」と言えるのはえらいです。80点。最後に複数プロトコルに対応したNASを勧めているのもよいです。「問題がなければ〜」と言っているので手順は出さないでもよかったかもしれません。 チェックリストのたたき台を作ってみる プロンプト : RHELでWebサーバを構築して問題なく動作しています。セキュリティを強化するために日常的な運用の中で配慮するべき点と行ったほうがよい作業のチェックリストの案を表形式で作ってください。 (回答は長いので途中で切れています。「続きをおねがいします」のように言うと続きを答えてくれます。何回か繰り返すと同じ項目がでたりするので適当なところで切り上げます。) 寸評 : ふんわりとした質問にはふんわりとした回答が帰ってきます。とはいえ何もない時のたたき台としてはいいんじゃないでしょうか。個別の項目について検討すると実際に対応するための知識が不足していることや「問題なく」と思っていたけど実は不明瞭だった点に気付くきっかけになりそうです。 プロンプト : RHEL8でsshサーバーを構築しようとしています。インターネットには接続されておらず主にシステム間の連携のために利用します。セキュリティとトラブル予防のため、構築時にチェックするべき項目をおしえてください。 (中略) (以下略) 寸評 : よく言及されるチェック項目は表示してくれる印象です。点をつけるなら80点くらいでしょうか。それまで設定項目やコマンドを出していたのにSELinuxの話になった途端に雑になりました。そういうblog記事とかたくさんインプットとして学習したんでしょうね。しょうがないね(涙)。 ドキュメントの検索をさせてみる プロンプト : RHEL の ssh設定についてドキュメントのURLをおしえてください 寸評 : 「いかにもそれらしいテキストを生成する」という点ではいい仕事をしているのですが、実際にはこのURLは存在しません。404でエラーとなりますので0点です。ドキュメントの検索は検索エンジンに頼むほうがよさそうです。 ナレッジベースを特定バージョンむけに書き換える テキストの処理をやってもらうタスクを試していきます。 複数バージョンにまたがっていてややこしくなってしまったナレッジベース記事を、特定バージョンむけのシンプルなものに書き換えられるでしょうか。 プロンプト : 以下はRed Hatのナレッジベース記事です。RHELの複数バージョンについて記載がありますが、RHEL 8についての記事に書き換えてください (ナレッジ記事コピペ) (中略) (以下略) 寸評 : 頼んでいないのに和訳してくれたのはさておき、途中まではいい調子でした。ただし主な目的のバージョン毎の分離に失敗して、RHEL 6での設定方法(/etc/init.d/function)が混ざってしまいました。コピー&ペースト時に箇条書きの情報が失われるため、どこからどこまでがRHEL8むけの情報か判別が困難なことが原因でしょう。 RHELアップグレードのための稟議書を書いてもらう プロンプト : RHEL 7は2024年6月に通常のサポートが終了してソフトウェアのメンテナンスが終了し、ELSを購入した場合にだけごく一部のパッケージがメンテナンスされます。現在利用中のRHEL 7をRHEL 8へ更改するための予算申請のための稟議書の下書きを作成してください。 寸評 : RHELはサブスクリプションでバージョン依存しないから既存のものを使いまわせる(同時に稼動するシステム数だけ買えばOK)という点をのぞけばかなりいい出力だと思います。システムの移行に必要な作業もケースバイケースですが、さすがというか定型文に近いものを生成させると優秀で120点あげたいです。
Red Hat でコンサルタントをしている菅原と申します。 この記事では、意外とあまり説明されていないような気がする Linux システムで発生するハングタスクについて少し説明したいと思います。現場のシステムでもハングタスク検知の設定がされていることが多いと思いますが、ハングタスクとは何なのかを正しくご理解いただくことで、ハングタスク検知を行う目的が明確になること、また、実際の障害事例もご紹介することで、通常あまりハングタスクと関連づけて考えないような設定でもハングタスク発生につながる場合があることを知っていただき、少しでもシステム管理や障害の理解、障害対応などのお役に立てれば幸いです。 なお、この記事では RHEL のみを対象に書いていますが、他の Linux ディストリビューションにも適用される内容と思います。 ハングタスク (hung tasks) とは ハングタスクとは読んで字のごとしでハングしたタスク (Linux カーネルではプロセスとスレッドを統一して取り扱っており、タスクと呼んでいます。以降、本記事では「タスク」と「プロセス」は同義語として捉えていただいて結構です) のことです。症状としては典型的にはタスクの処理が進行しなくなるのでいわゆる「刺さった」ような状態となることが挙げられます。より厳密には、ps コマンドで見たときの状態が "D" で一定以上長く滞留しているとハングしていると見なされます。 タスクの D 状態 (D state) とは D 状態は英語では uninterruptible sleep と表記され、日本語に訳すと「割り込みできないスリープ状態」になります。この状態にいるタスクに例えば kill コマンドでシグナルを送ったとしても、割り込み不可なのでシグナルの受信は今実行中の処理が終わって D 状態を抜けるまで待たされることになっています (なので、D 状態で刺さっているプロセスを kill してもプロセスを止められないのです)。 実はこの D 状態というのは、ユーザーモードではなくカーネルモードで実行していないと見られない状態です。例えば、ディスク等のデバイスに対して入出力を盛んに実行しているプロセスの状態をよく見ていると D 状態になることは珍しいことではありません。D 状態は短時間であればそれ自体が問題なわけではなく、問題は「長く滞留する」というところです。 また、スリープ状態と呼んではいますが、実際にタスクがスリープしているとは限らず、カーネル内で忙しく何らかの処理を実行している場合も多いことに注意が必要です。ただ、タスクのユーザー空間としては、システムコールを呼び出して戻りを待っており、戻ってくるまでユーザー空間の処理が一切進まないという意味ではスリープ状態 (S 状態) に似ていると言えるかも知れません。 D 状態が必要な理由 D 状態というのは、カーネル内部で何らかの排他制御が必ず関わっています。排他制御というのは、あるコードを複数のタスクが並行処理すると問題が発生するような場合に、「この部分は1度に1個のタスクにしか実行させない」という仕組みを実現するものです。そのような部分のことを「クリティカルセクション」と呼びます。 クリティカルセクションに入るときには「ロック」を取得し、抜けるときに取得したロックを解放します。ひとつのロックはひとつのタスクにしか所有できないため、先にクリティカルセクションを実行しているタスクが存在するときに、後から別のタスクが同じクリティカルセクションを実行するためにロックを取得しようとすると、前のタスクがロックを解放するまで待たされることになります。このようにして、複数のタスクがカーネル内のクリティカルセクションを同時に実行させないようにしています。カーネル内には多種多様なクリティカルセクションが存在し、それぞれのクリティカルセクションによって、複数の異なる種類のロックを目的に合わせて使い分けています。ロックは大きく分けるとロックを待つときにタスクがスリープするものとしないものに分類できますが、D 状態は「割り込みできないスリープ」状態なので、スリープする方のロックが関わっています。後でご紹介する事例2つでは、スリープするタイプのロックとしてどちらも mutex が関わっていました。 参考文献: Linux kernel doc "Lock types and their rules" また、なぜ D 状態が割り込みできないのかというと、取得したロックをきちんと解放するためです。仮にロックを取得して処理をしている途中でもシグナルの受信などによりタスクの他の部分の処理に飛べてしまったとすると、例えば割り込んだ処理がタスクを終了させてしまったりして取得したロックが正しく解放されない可能性が出てきます。これでは他のタスクが同じクリティカルセクションを実行しようとしても永久にロック待ち状態に陥ってしまうだけでしょう。なので、一度タスクがロックを取得したら、解放するまでクリティカルセクションから出て他の部分へ飛んでしまわないように、シグナルなどによるタスクに対する割り込みを禁止しているわけです。 D 状態へ出入りするタスクの様子を時間軸にそってまとめると、以下のようになります。 タスク状態を D に変更 ロックを取得 (他のタスクによって既に取得されている場合は解放されるまでスリープして待つ) クリティカルセクションの実行 ロックを解放 タスク状態を D から他の状態に変更 ハングタスク発生時に起きていること さて、ここまで見てきたように、タスクが長時間 D 状態に滞留しているということは、上記の 1、4、5 には長時間かかる要素はないので、2 か 3 のどちらかで長時間滞留していることになります。長時間ロックを待っているタスクがいるということは、他のタスクが長時間同じロックを保持し続けているということも推測できますので、実際には、 クリティカルセクションの実行に長時間かかっているタスク (1個だけ) 長時間ロックを待っているタスク (1個以上) の両方が同時に存在している確率が高いです。 とここまでの説明で疑問を持たれた方はおられないでしょうか。というのは、D 状態はカーネルモードでしか入れないタスク状態なわけですから、ここで言っているロックはカーネルロックになるわけですし、クリティカルセクションもカーネル内部のコードの一部です。つまり、ハングタスクが発生する原因は排他制御に絡んだカーネルバグなのでは? カーネルバグだとしたら、システム管理者にできることはサポートケースを上げて早く直してもらうことぐらいしかないんじゃないの? と。 ところが、実際にはカーネルバグではない原因によってもハングタスクが発生することがあるんです。システムの構成やシステム運用手順を注意深く設計しないと、バグではない理由でハングタスクにやられることがあるという事例を少しだけご紹介したいと思います。 とその前に、ハングタスクに関するカーネル設定をおさらいしておきしましょう。 ハングタスクに関するカーネル設定 RHEL で設定できる、ハングタスクに関するパラメータは以下の4つです。いずれも sysctl パラメータなので、/etc/sysctl.d/ 配下のファイルや /etc/sysctl.conf 等に書いておいてシステム起動時に自動設定したり、稼働中に sysctl コマンドで動的に設定したりできます。 kernel.hung_task_warnings kernel.hung_task_timeout_secs kernel.hung_task_check_count kernel.hung_task_panic 個々のパラメータの意味と設定方法についてはこちらの KCS に詳しく記載されていますのでご覧ください。なお、日本語版だと RHEL 8/9 に対する言及がありませんが、RHEL 8/9 に対しても適用できるナレッジです。対応する英語版 KCS をご覧いただくと RHEL 8/9 も対象とされていますので気になる方はそちらもチェックしていただくと良いでしょう。 https://access.redhat.com/ja/solutions/915423 (日本語版) https://access.redhat.com/solutions/60572 (英語版) システム管理上特に重要なのは D 状態での滞留時間の上限、つまりこれ以上長く D 状態で滞留しているとハングとみなす時間を決める hung_task_timeout_secs と、ハングタスクを検出したときにカーネルパニックを起こすかどうかを決める hung_task_panic でしょう。 前者は、あまり短いと頻繁にハングタスクを検出する恐れがありますし、一方あまり長く設定するとタスクの処理が進まなくなってから長時間障害の検知ができない危険があり、一概に何秒が良いとは言えないパラメータです。サーバ上で稼働しているワークロードの性質や、SLA によって注意深く設定する必要があります。あくまで目安でしかありませんが、一般的には 120〜600 (単位は秒)ぐらいの範囲で設定値が決定されることが多いようです。 後者は 0 がカーネルパニックなしの設定で、1 がカーネルパニックを起こす設定です。カーネルパニックする場合、kdump が構成されていれば vmcore (カーネルクラッシュダンプ) を取得してハングタスクの原因を解析できる可能性を残すことができます。パニックの有無と関係なく、ハングタスク検出時にはログに "INFO: task xxxxx:NNNNN blocked for more than TTTseconds." のようにメッセージが記録されます。アプリケーションの SLA などによっては、ハング検出するたびにパニックさせなくても、ハングが発生したことがわかれば良いといったケースもあると思います。 ハングタスク事象の解析 実際にハングタスクが発生した際に発生の原因を特定するには、前述の設定で kernel.hung_task_panic=1 を設定してハングタスク検知でカーネルパニックを起こさせ、さらに kdump によってカーネルクラッシュダンプを取得して解析することが必須です。ただし、この記事で説明しきれる内容ではありませんので、kdump 設定方法や解析のやり方などについてはここで解説することはいたしません。知識として、ハングタスクの原因調査にはそのような設定が必要、とだけご承知おきください。 ハングタスクの事例 ようやく前提となるハングタスクの説明が終わりましたので、実際の障害事例をご紹介していきたいと思います。今回は2件の事例をご紹介します。 RPM アップデートをトリガーとして tuned がハングタスク化した事例 実際にお客様先で発生した事例です。polkit RPM をアップデートしたところ、tuned サービスプロセスがハングして、kernel.hung_task_panic=1 の設定をされていたためカーネルパニックが発生しました。 RPM のアップデートはシステムメンテナンスと考えればサービスやアプリケーションを停止した上で行うという考え方もあれば、リブートが不要なアップデート自体は適宜実施するという考え方もあります。この場合は、リブートが不要なアップデートなのでアプリケーションを停止せずに RPM のアップデートを適用したケースです。 詳しい調査の経緯は省略しますが、何が起きていたかといいますと、 polkit RPM のアップデートを適用したところ、RPM インストール後に自動実行されるスクリプト (ポストインストールスクリプトレット) 中で、polkit のサービスの再起動を試行する "systemctl try-restart polkit.service" が実行された 実は tuned サービスの systemd ユニットファイルの中で polkit サービスを Requires に記述されており、polkit サービス再起動前に tuned サービスが停止された tuned サービス停止後に polkit サービスを再起動し、tuned サービスを再度起動した tuned のデフォルト設定ではサービス起動時に /etc/sysctl.conf および /etc/sysctl.d/* に記載されている設定を適用するようになっているので、適用した このとき、sysctl.conf ファイルに "kernel.nmi_watchdog=0" と "kernel.nmi_wathdog=1" という、矛盾した設定が両方記載されていたため、kernel.nmi_watchdog に対して 0 と 1 両方の値を書き込む動作が発生するようになっていた (設定ファイルの順序として最後に書き込まれるのが 1 だったため、通常稼働時には 1 の設定) sysconf 適用中、kernel.nmi_watchdog に 0 を書き込んだ時点で tuned サービスタスクが起動途中でハング kernel.hung_task_timeout_secs に設定した時間が経過したため kernel.hung_task_panic=1 の設定にしたがってカーネルパニック発生し、その後 kdump によりカーネルクラッシュダンプを保存してサーバ再起動 という現象が起きていたことがわかりました。 ちょっとここで nmi_watchdog について説明が必要になりますね。nmi_watchdog とはハードロックアップディテクタと呼ばれる仕組みで、「カーネルモードでハードウェア割り込み禁止の状態で10秒を超える時間ループする」状態がハードロックアップと定義されています。ハングタスクと似ていて少し紛らわしいのですが、ハングタスクの D 状態はタスクの割り込み(主にシグナルによる)が禁止されているだけでハードウェア割り込みは有効なので、D 状態で実行中のタスクがスケジューラによって一時実行を中断され他のタスクに CPU を明け渡したり、ハードウェアイベント待ちのためスリープして CPU を明け渡したりといったことが起こり得ますが、ハードロックアップの場合はハードウェア割り込みを禁止した状態でカーネル内でループするので、スケジューラが中断することもできず、タスクだけではなくシステム全体がハングしたような状態になったりします。nmi_watchdog は、NMI (non-maskable interrupt=マスクできない割り込み) という禁止不可能な特殊な割り込みを使ってこれを検知し、設定によってはカーネルパニックを起こさせてハング状態からの復旧をさせたりすることができる仕組みです。 で、nmi_watchdog を有効にするとシステム上のすべての CPU 上で watchdog カーネルスレッドが起動されます。ps コマンドで見ると、こんなタスクが動いているのが見えるかも知れません。 root 16 0.0 0.0 0 0 ? S 2022 0:00 [watchdog/0] root 19 0.0 0.0 0 0 ? S 2022 0:16 [watchdog/1] root 26 0.0 0.0 0 0 ? S 2022 0:16 [watchdog/2] root 32 0.0 0.0 0 0 ? S 2022 0:16 [watchdog/3] ... root 32 0.0 0.0 0 0 ? S 2022 0:16 [watchdog/31] "[watchdog/N]" の N の部分は CPU コアの番号を表しています。このように、コマンド名に相当する文字列が [] で囲まれているタスクは、ユーザー空間で動いているものではなく、純粋にカーネル内部で動いているカーネルスレッドと呼ばれているのですが、kernel.nmi_watchdog=1 の設定をすると、すべての CPU コアに対して1つずつ、watchdog スレッドが起動されます。 kernel.nmi_watchdog=1 であるとき、つまり watchdog スレッドが存在しているときに 0 を設定するとハードロックアップディテクタが無効にされ、これらのスレッドも終了させるのですが、スレッドを終了させる kthread_stop() 関数の肝となる部分は以下のようになっています。 set_bit(KTHREAD_SHOULD_STOP, &kthread->flags); kthread_unpark(k); wake_up_process(k); wait_for_completion(&kthread->exited); 上記は RHEL 9 kernel-5.14.0 の kernel/kthread.c:L646-L649 の抜粋ですが、RHEL 7/8 でも本質的には変化ありませんし、最新の upstream kernel 6.2.5 (下記リンク) でもあまり変わっていませんでした。 https://elixir.bootlin.com/linux/v6.2.4/source/kernel/kthread.c#L696 ここで行っていることをざっくり説明しますと スレッドに対して終了を指示するフラグ KTHREAD_SHOULD_STOP をセットして スレッドを起こして スレッドの終了を待つ というロジックになっています。つまり、スレッドを終了させるにしても、一度そのスレッドが実行されて自発的に終了する必要がある仕組みというわけです。 この障害事例では、CPU コアの1つでリアルタイムスケジューリングポリシーで動作するアプリケーションが稼働して CPU を 100% 占有している状態だったため、watchdog スレッドがウェイクアップできない状況になっていました。watchdog スレッドは通常のタスクと同じポリシーを使うようになっていて、リアルタイムスケジューリングポリシーで稼働するタスクの方が優先度が高くなっています。そのため、ウェイクアップされた watchdog スレッドはランキューに入って実行待ちになったまま、リアルタイムアプリケーションが CPU を自発的に明け渡すのを永久に待っている形となっていました。tuned の kernel.nmi_watchdog への 0 の書き込みによって呼び出された kthread_stop() 関数は、実行待ちとなったまま終了もできないスレッドが終了するのを永久に待っており、その間 D 状態が継続していたために tuned タスクがハングしたと見なされたわけです。なお、RHEL のスケジューリングポリシーについて詳しくは下記リンクのドキュメントをご参照ください。 参考文献: Red Hat Enterprise Linux 9 『システムの状態とパフォーマンスの監視と管理』第30章 スケジューリングポリシーの調整 本障害を発生させる条件が、リアルタイムアプリケーション稼働中でかつ kernel.nmi_watchdog=1 の設定で watchdog スレッドが各 CPU コア上に存在している状態において、kernel.nmi_watchdog=0 を設定して watchdog スレッドを終了させようとする、であることがはっきりしましたので、これを解決するには tuned サービスの起動中に nmi_watchdog の有効・無効状態を変更しなければよいはずです。というわけで、sysctl 設定から kernel.nmi_watchdog=0 をすべてコメントアウトして kernel.nmi_watchdog=1 を1つだけ残す設定として再現テストを行ったところ、tuned のハングを回避できることがわかりましたので、お客様にも同じ設定を適用していただくように依頼して解決しました。 CPU リソースが不足してハングタスクとみなされた事例 こちらは、前述の事例とはだいぶ趣が異るハングタスク事例で、コンテナ実行環境で発生した事象になります。OpenShift などコンテナ実行環境では、各コンテナのリソース (メモリや CPU など) に制限をかけるのに、Linux カーネルの cgroups (Control Groups) という機能が利用されています。赤帽エンジニアブログでも "cgroup" あるいは "cgroups" で検索するとヒットしてくる多くの記事が OpenShift を初めとするコンテナ技術の関連記事です。 また、本事象では、アプリケーション以外の雑多な処理 (例えばハードウェア割り込みの処理や、OS の様々な管理など。家事になぞらえて「ハウスキーピング」などと呼ばれます) は実行しないように特定の CPU コアを予約してアプリケーション専用として置いておく、isolcpus も関係しています。 参考記事: 赤帽エンジニアブログ "レッドハットが考えるNFV環境向けのチューニング" コンテナ実行環境では、コンテナリソースの制限に cgroups という機能が利用されていると書きましたが、cgroups は一般の RHEL システムでも有効になっており、以下のような mount コマンドの出力 (抜粋) に見覚えのある方もおられるのではないでしょうか。これは RHEL 8 での出力例です。 cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_cls,net_prio) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpu,cpuacct) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb) cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,rdma) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer) このように、cgroups 機能は /proc や /sys のような疑似ファイルシステムを経由して設定にアクセスするようになっており、これらのマウントポイントの下に、タスク (=プロセス・スレッド、そしてこの文脈ではコンテナも) の起動と終了に伴い、動的にディレクトリ構造の作成や削除が行われます。つまり、タスクの起動や終了が増えていくにしたがって、それだけ /sys/fs/cgroup 以下のディレクトリ構造の作成や削除の処理も増大していくということです。そして、このような /sys/fs/cgroup 以下のディレクトリ構造の管理は典型的なハウスキーピングの一種なので、先ほど触れた isolcpus で予約していない、ハウスキーピング用の CPU コアで実行されるというところが重要な意味を持ちます。 この事象では、サーバに搭載された CPU コアの大半を isolcpus でアプリケーション専用と予約しており、残り少ないハウスキーピング CPU がこうした管理をほそぼそと実行するような構成となっていたことが災いしていました。障害発生時には、コンテナの終了に伴い /sys/fs/cgroup 以下に作成されていたディレクトリ構造を削除する際に、処理を実行していた CPU のランキュー (run queue: カーネルのスケジューラが実行待ちタスクを管理するデータ構造) が非常に長くなっていたことがわかっています。1個の CPU の限られた時間を、数多くのタスクが奪い合っていたと言っても良いかも知れません。 この場合はハングしたタスクは systemd で、終了したコンテナに対応する /sys/fs/cgroup/memory 配下のディレクトリ構造を削除していたのですが、処理が完了する前にタイムスライスを使い切って他の実行待ちタスクに CPU を明け渡し、次のタイムスライスを待つ、ということを繰り返していたと見られます。最初の事例でご紹介したハードロックアップのところでも触れましたが、D 状態はタスクへの割り込みは禁止されますが、OS としての動作を見れば割り込みが禁止されてはいませんので、スケジューラにより D 状態にある systemd タスクから他のタスクへ実行を移したり、その逆も行われます。このケースでは、多数のタスクが同じ CPU 上で実行を待っていたため、一度 CPU を明け渡すと次に CPU が割り当てられて実行できるまで、かなりの間実行待ちであったと思われます。 /sys/fs/cgroup は疑似ファイルシステム (本来のデータストレージではなく、カーネルへの API を提供するためのファイルシステムという意味で擬似) ではありますが、ファイルシステムという複雑なデータ構造を管理するカーネルのサブシステムである以上、ディレクトリやファイルの作成や削除などの操作には他のファイルシステムと同様に排他制御が必要です。systemd はシステムコール経由でディレクトリの削除をカーネルに依頼した後、排他制御のため D 状態となってカーネルの処理が完了するのを待っていました。カーネルのディレクトリ削除処理は正常に進行していたのですが、他の多数のハウスキーピングタスクと CPU 時間を奪い合う状況だったため処理の完了までに kernel.hung_task_timeout_secs に設定した時間を超える長時間を要してしまい、ハングタスクとして検知されてカーネルパニックに至ったと考えられます。 緩和策としては、 isolcpus に指定するコア数を減らしてハウスキーピング CPU を増やす kernel.hung_task_timeout_secs に指定するタイムアウトを延長して、同じ状況でハングタスクが検知されないようにする といったことが考えられますが、最初にご紹介した事例とは異なり発生条件が動的で再現が難しいため、緩和策として設定値が妥当であるか判断するには、現実に近い負荷テストを実施して有効性を確認する必要があります。また、前者の対応はサーバのキャパシティ (同時に実行できるアプリケーションコンテナ数) に影響を与えるので、1台のサーバだけの問題ではなくシステム全体への影響を考慮する必要があり、対応するにしても慎重に行う必要があるでしょう。 システムを構築する際、アプリケーション性能を最適化するため、できるだけ多くのハードウェア資源をアプリケーションの実行に振り向けたいのは自然なことですが、ハウスキーピングタスクも OS の稼働には重要な処理ですので、システムの安定稼働にはアプリケーション実行とハウスキーピングに振り分ける資源のバランスも大変重要である、という教訓が得られた事例となりました。 むすび ちょっと長い記事となってしまいましたし、Linux カーネルの様々な機能や概念が登場してすべてを解説しきれていないので理解が難しい面もあるかも知れませんが、ハングタスクとは何か、また、OS バグではない原因によってもハングタスクが発生する事例を通じて、システムの安定稼働のためにシステムを構成・設定を全体的に検討する必要があることを知っていただけたら幸いです。
こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 昨年末にManaged版のRed Hat OpenShift Data Science(RHODS)の GAが発表 されました。 このManaged版のRHODSはAWSで利用可能なManaged OpenShiftであるROSAや、OpenShift Dedicatedにアドオンとしてインストールできるサービスとなっています。 ただし、現在(2023年2月)日本ではAWS Marketplace上でRHODSの購入がサポートされておらず使いたいけど使えないという状態となってしまっていました。 しかしながら実は先月にRHODSのもう一つの提供オプションである Self-managed版がGA となりました。 提供される機能としてはManaged版と同じものが利用可能 1 ですが、インストール先としてオンプレミスを含めた様々な環境のOpenShiftが選択できる利用オプションとなっています。 今回はこのSelf-managed版のRHODSをOpenShiftにインストールし各種機能の概要を紹介していきたいと思います。 RHODSのインストール Self-managed版のRHODSは通常のOperatorと同様にOpenShiftのOperatorHubからインストールすることができます。 管理者画面からOperatorHubを開き、 data science などで検索すると見つけることができます。 タイルを開くとインストール画面へ。 インストールを開始すると、RHODSのOperator自体はすぐにデプロイされますが、 RHODSのメインダッシュボードが利用可能になるまで少し時間がかかるためしばらく待機しましょう。(大体15分から20分くらいかかります) RHODSダッシュボードへのアクセス RHODSのアプリケーションは redhat-ods-applications というProjectにデプロイされます。 まずはデプロイされたPodが正常に稼働しているか見てみましょう。 # oc get pod -n redhat-ods-applications --- NAME READY STATUS RESTARTS AGE etcd-58c5d57cc9-dg6mg 1/1 Running 0 122m modelmesh-controller-58b5d7c5b8-bqxt6 1/1 Running 0 122m modelmesh-controller-58b5d7c5b8-gbds8 1/1 Running 0 122m modelmesh-controller-58b5d7c5b8-s6jks 1/1 Running 0 122m notebook-controller-deployment-6fd6b67b4b-k6lx4 1/1 Running 0 121m odh-model-controller-6cb4cb8544-7pz6t 1/1 Running 0 122m odh-model-controller-6cb4cb8544-g9f4d 1/1 Running 0 122m odh-model-controller-6cb4cb8544-q9hms 1/1 Running 0 122m odh-notebook-controller-manager-8d5986c9f-f6tfw 1/1 Running 0 121m rhods-dashboard-74f8bcb97c-59h99 2/2 Running 0 122m rhods-dashboard-74f8bcb97c-hrm6r 2/2 Running 0 122m rhods-dashboard-74f8bcb97c-lgfpd 2/2 Running 0 122m rhods-dashboard-74f8bcb97c-tswmv 2/2 Running 0 122m rhods-dashboard-74f8bcb97c-xt8s8 2/2 Running 0 122m ダッシュボードや各種のコントローラーがPodとしてデプロイされています。 ダッシュボードにはOCPコンソール右上の四角9つのアイコン 2 からアクセスすることができます。 アクセスすると認証が求められるので自分のユーザーでログインしましょう。 これで無事RHODSのダッシュボードにアクセスできました。 Jupyter Notebookの起動 ダッシュボードの初期画面でJupyterのタイルをクリックするとJupyter Notebookの起動画面に移ります。 RHODSではデフォルトで5つのコンテナイメージを提供しています。 これらはRHODSのサービスの一部としてRed Hatが管理し、ライブラリのアップデート等を提供するコンテナイメージとなっています。 ・Minimal Python ・Standard Data Science ・CUDA ・PyTorch ・TensorFlow それぞれのイメージにどんなライブラリのどのバージョンが含まれているかを確認するにはイメージ名横の?マークをクリックすると表示されます。 また以下のドキュメントでもライブラリの情報がまとまっているためご参照下さい。 access.redhat.com こうしたデフォルトイメージが利用可能な一方で、実際の機械学習プロジェクトに取り組む場合、追加のライブラリを利用したいというニーズがあるかと思います。 その場合はRHODSにカスタムイメージを追加することでデフォルトのイメージと同様に利用することができます。 カスタムイメージの追加に関しては次回のブログで書きたいと思います。 今回はStandard Data Scienceのイメージを起動してみたいと思います。 Start server をクリックし1、2分程度でJupyter Notebookの環境が立ち上がります。(イメージをPullするため初回は少し時間がかかります。) 初期状態ではディレクトリが一つあるだけですが、 画面左のGitアイコンからGitリポジトリをクローンし作業することができます。 また各NotebookのPodにはデフォルトで20GBのボリュームがアタッチされており、そちらに作業内容が保存されます。 そのため一度コンテナを停止し、利用するコンテナイメージを変更して再度立ち上げたとしても過去の作業内容が失われず作業を継続することができます。 Data Science Project 一度RHODSのダッシュボードに戻り、今度はData Science Projectsというメニューを見ていきましょう。 先ほどNotebookを立ち上げた際は rhods-notebooks というRHODSインストール時に作成されたProjectの中でNotebookのPodが起動していました。 RHODSの画面からData Science Projectを作成すると新たに専用のProjectがOpenShiftクラスタ内に作成され、その中で各種Podが起動する形となります。 今回は akabou engineering blog というData Science Projectを作成しました。 画面を開くと4つの項目が表示されます。 ・Workbenches ・Cluster storage ・Data connections ・Models and model servers それぞれどういったものか確認をしていきましょう。 Workbenches Workbenchesでは1つのProject内で複数Notebookの作成を行うことができます。 先ほどもRHODSダッシュボードからNotebookの起動を行いましたが、実はあちらのパターンでは一人のユーザーに対して同時に複数のNotebookイメージを起動できないという制限がありました。 Data Science Projectを作成しWorkbenchesからNotebookを作成することで、一人のユーザーが異なるライブラリを含む複数のイメージを使用してコンテナ環境を同時に持つことが可能となります。 また現在はこのData Science Projectは個々のユーザーごと作成するようになっていますが、今後複数人で一つのData Science Projectを共有し、その中で共同作業できるよう機能のエンハンスが計画されています。 3 Cluster storage Cluster storageでは当該のData Science Projectで利用するPersistenVolumeを管理します。 WorkbenchesからNotebookを作成する際に新たなストレージを作成することができましたが、こちらの項目から個別にストレージだけを作成することも可能となっています。 作成したストレージはNotebookにアタッチして利用することができます。 Data connections Clsuter storageはNotebook Podに直接アタッチするいわゆるブロックストレージを管理するものでしたが、Data connectionsではAWS S3などのオブジェクトストレージへの接続情報を管理します。 機械学習を行う際に、入力データをオブジェクトストレージから取得したり、学習済みモデルをオブジェクトストレージに保存し管理するということはよく行われているかと思います。 一方でオブジェクトストレージ上のデータの入出力に必要な秘密情報(Secret Access Keyなど)を直接コードに記載することはセキュリティ上の懸念となります。 Data connectionsでは特定のオブジェクトストレージへのアクセス情報を設定し、それをアクセスを実施したいWorkbenchに渡すことで安全なデータアクセスを可能とします。[^4] AWS S3だけでなく、OpenShift Data Foundationなども利用することができ、オンプレミス環境でも同様のデータアクセスが可能となります。 Models and model servers Models and model serversではNotebook上で学習させた機械学習モデルをAPIとして公開することが可能となります。こちらの機能は2023年2月現在Field Trialとして提供されています。 4 RHODSのモデルサービングに関する機能はOSSコミュニティで開発が進められている KServe がベースとなっています。 学習済みモデルをデプロイする際は、まずモデルのデプロイ先となるサーバーを作成します。こちらはKServeにおける ServingRuntime と呼ばれるカスタムリソースです。 サービング用のPodのサイズやレプリカ数、外部公開するか、認証の有無について設定していきます。 デプロイ先のサーバーを作成したら、そこへ学習済みモデルをデプロイしていきます。 RHODSのモデルサービングでは一つのServingRuntimeに複数の異なる学習済みモデルをデプロイするModelMeshと呼ばれるデプロイ方法を提供しています。ModelMeshについて詳しくは こちら をご参照下さい。 現在RHODSのModelMeshでデプロイ可能なモデル形式には制限があり、ONNXとOpenVINO形式のみが対象となっています。 5 そのため学習したモデルをオブジェクトストレージに保存する前に各種ライブラリ(tf2onnx、sklearn-onnx、等)を使用してモデル形式を変換しておきます。 オブジェクトストレージに保存されたモデルがあるディレクトリへのパスを指定しデプロイを行います。Data connectionを既に作成している場合、その認証情報を使ってモデルを取得することができます。 デプロイが完了すると推論エンドポイントとなるURLが表示されます。 あとはこのモデルを利用したいアプリケーションからこちらのURLに対してリクエストを投げることで入力データに応じた推論結果を得ることができます。 まとめ 今回はRHODSについてご紹介しました。 RHODSはコンテナとして機械学習の開発・推論環境を提供するほか、今後のロードマップではKubeflow Pipelinesを利用したパイプライン機能の提供なども計画されており、機械学習のプラットフォームとしてより機能を拡充していく予定です。ご興味ありましたら是非お気軽にレッドハットまでお問い合わせ下さい。 またRed Hatの開発者向けサイトでは一部機能を無償で体験することもできます。こちらも合わせて見てみて下さい。 developers.redhat.com 厳密にはManaged版の方が新バージョンの提供が早いらしいですが、ほぼ同じです。 ↩ このアイコンのことをBento menuと呼ぶらしいです。 ↩ 将来的な機能提供を保証する内容ではありません。 ↩ 詳しくはRHODSのサービス定義(英語)をご確認下さい。 https://access.redhat.com/support/policy/updates/rhods/service ↩ 今後の機能エンハンスでより多くのモデル形式に対応の予定です。 ↩
Red Hat のソリューションアーキテクトの井上たかひろです。 Red Hat にはクラウドネイティブアプリの開発に役立つ、ソフトウェアのラインナップが充実していることをご存知ですか? ここでは、それらのソフトウェア [Red Hat Application Services] に関する注目ニュースを、各製品技術に特化したソリューションアーキテクトがご紹介していきます。 今回は 2023/2月号となります。 想定読者 エンタープライズアーキテクト アプリケーション開発者 システムの提案をするSIerの方 特集1: Red Hat がひっそりと開発しているデータストア - Infinispan の概要 よくいろいろな役割の開発者の方々から「Red Hat はデータストアを持ってないよね」と言われることがあります。 でも、実は、Red Hat はほとんどの人に知られることなくひっそりと昔から開発してきたデータストアがあるのです。 本特集では、Red Hat が開発している OSS データストアである Infinispan の概要を紹介します。 Infinispan は Red Hat Data Grid (RHDG)という名前で提供しています。 Infinispan は「インメモリー・データ・グリッド」と呼ばれる分類のデータストアです。 KVSを使用されている開発者の方からは、「インメモリー・データ・グリッドは、キー・バリュー・ストア(KVS)の事でしょ?」と言われる事が良くあります。インメモリー・データ・グリッドは、データへのアクセス方法はKVSと同じですが、さらにたくさんの機能を持っています。今回は全ての機能を紹介しきれませんが、残りの機能については次回以降紹介していきます。 rheb.hatenablog.com 特集2: 忘れていませんか?APIの見える化 API基盤を検討されているお客様は多いかと思いますが、APIを活用していくためには、どのようなAPIが存在し、どう使ったらいいのか、APIの詳細情報をデベロッパーポータルで公開する「APIの見える化」が重要です。 本特集では、APIの見える化を実現するために、Red HatのAPI管理製品である3scale API Managementのデベロッパーポータルのカスタマイズ方法について解説しています。 rheb.hatenablog.com 特集3: Red Hat SSO(Keycloak)でステップアップ認証してみる(アプリはQuarkusで) Red Hat SSO 7.6からステップアップ認証がサポート対象になっています。 ステップアップ認証は、OIDCのACR(Authentication Context Class Reference)を利用して実現しており、WebアプリやAPIで、参照の場合はログイン認証のみで、更新の場合はログイン認証+OTPやWebAuthを使った生体認証などができるようになります。こういった処理は自作でやっていたところが多く、本機能を利用することで標準仕様に基づいたステップアップ認証が簡易に実現可能となります。 本特集では、Red Hat SSOでステップアップ認証の設定と、アプリはQuarkusを使って、ステップアップ認証の動作確認を紹介しています。 qiita.com 直近GAになった製品群 最近リリースとなった Application Services 製品群のリストをご紹介します。 見逃している製品が無いか、是非一度ご確認ください。 Red Hat AMQ Streams 2.3.0 Camel Extensions for Quarkus 2.13.2
こんにちは。Red Hatでソリューションアーキテクトをしている杉本 拓です。 API基盤の導入を検討されているお客様は多くいらっしゃるかと思いますが、APIを活用していくためには、組織内にどのようなAPIが存在するのか、APIを簡単に発見することができ、そしてそのAPIの仕様がどのようになっているのか、更にどう使うのか、あるいは使用条件など、その詳細情報が見えるようになっている「APIの見える化」が実現されている必要があります。その観点において、APIのデベロッパーポータルというのは非常に重要な役割を持っています。今回の赤帽エンジニアブログでは、 Red Hat Application Foundations に含まれるAPI管理の製品 3scale API Management のデベロッパーポータルをカスタマイズして、APIの見える化を実現する方法について、Red Hat Developersサイトの 記事 の翻訳を通じて紹介したいと思います。 APIの見える化は、API管理基盤の構想を建てる上で重要な側面です。APIの見える化をいかに実現するかは、APIの採用や利用に直接影響を及ぼします。企業規模が大きくなればなるほど複数の開発チームが開発するAPIの数は増え、そのAPIを内部APIとして再利用したり、そのAPIを利用してアプリケーションを開発するパートナー向けにAPIを共有する必要性が高まってきます。しかしながら、もし開発チームが既存のAPIを発見できなければ、同じ機能を持つAPIを新規に実装することも起こりえます。もしそうなってしまうと、無駄に労力を重ねることになり、せっかく開発した既存のAPIも活用されなくなってしまうことになりかねません。また、APIの利用者の観点からしても、APIを使おうとした時にいちいちAPIの開発者に連絡して仕様を確認しなければならないというのは非常に効率の悪いやり方です。 社内の開発チームやパートナーが、APIを開発したチームに直接連絡することなく、APIがどこにあるのか見つけ出し、どのように使ったらいいのかを簡単に理解することができるような方法というものが必要になってきます。APIの見える化とは、単にAPIの一覧を提供してAPIを見つけやすくすることにとどまらず(これはこれで最初に取るべき重要なステップではありますが)、API仕様に関するドキュメント、リクエスト/レスポンスの形式、登録して利用するまでのフロー、APIを使う際のビジネス的な条件(パートナーの場合)などを通じて、API利用者がAPIを理解するために必要な情報を提供し、再利用を促進していくようなことにも対応していかなくてはなりません。。 解決策としてのデベロッパーポータル デベロッパーポータルは、まさにこのような課題に対する解決策を提供するものです。デベロッパーポータルを通じて、API利用者はどのようなAPIがあるのか検索やフィルタリングをしたり、興味のあるAPIについて学習をして理解を深め、利用したい場合には登録して利用申請をすることができるようになります。APIを提供する企業は、その目的や想定される利用者に応じてデベロッパーポータルのカスタマイズを行い、デベロッパーポータルの機能を利用して検索やフィルタリングの機能を持ったAPIカタログを簡単に構築することもできるようになります。 以下のセクションでは、Red Hat 3scale API Management を使用して、上記のようなユースケースに対応する動的な API カタログを構築する方法を解説していきます。 APIカタログの構築 では、デベロッパーポータルで表示するすべてのAPIカタログを構築しいきましょう。ここでの実装は、 APIs.json のプロジェクトをベースとしています。このAPIs.jsonのJSONファイルをデベロッパーポータルで使用することで、APIについて表示するために必要な情報すべてを取得することも可能です。 ただ実際には、さまざまな理由から、3scale API Managementで管理されているすべてのAPIをこのJSONを通じて公開したくない場合もあるかもしれません。そのような場合にはAPI提供者は追加のチェック項目とルールを設定して、どのAPIを公開し、どのAPIを公開しないかを制御することができるようになります。以下の例では、流用制限、価格、サポートなど、APIに関する基本的な情報を持っているAPIである場合のみ公開することとし、それらの基本情報を持っていないAPIは共有の対象外と判断し、発見することができないようにしたいと思います。3scaleでは、APIの基本情報としてアプリケーションプランのフィーチャー (Features)の機能を使用することでこれを実現することができ、関連するフィーチャー (Features)が設定されていないAPIは発見することができないようにすることができます。 注:APIが検索対象となるかどうかのここでの条件はあくまでも例であり、実際の業務観点やユースケースに応じて条件を変更することは当然可能です。例えば、以下ののチェック項目や条件をすべて削除して、3scale API Managementで管理されているすべてのAPIを検出可能にすることも可能です。 APIs.jsonを作成してデベロッパーポータルをカスタマイズするには、以下の手順に従っていきます。 1. 3scale API Managementの管理ポータルにログインし、Audience → Developer Portal → Contentに移動します。 New Page のドロップダウンをクリックし、 New Section を選択して新しいセクションを作成します(図1)。 図1 2. セクションのTitleで catalog と名前を設定し、図2に示すように Partial path を変更します。 Create section をクリックしてセクションを作成します。カスタマイズに必要なファイルは、このセクションの中で設定していきます。 図2 3. 図3に示すように、以下の表にある設定情報を使用して apis.json という新しいページを作成します。Layoutフィールドが空であること、Liquidが有効であること、正しいパスとセクションが設定されていることを確認してください。GitHubのリンクにあるapis.jsonのファイルの中身をソースコードとして貼り付けて、 Create Page をクリックします。 図3 セクション 値 Title apis.json Section |-catalog Path /catalog/apis.json Layout 何も選択されていない状態 Advanced Options > Liquid enabled チェックを入れてください Code URL GitHub のリンク 4. 3scale API Managementの管理ポータルでDeveloper Portal → Draftsに移動し、 Publish All をクリックします。 図4 5. デベロッパーポータルの画面を開き、 /catalog/apis.json のエンドポイントに移動します。図 5 に示すように、API のリストと関連する詳細が記載された JSON が表示されるはずです。 図5 APIカタログのページ作成 APIカタログのページは、APIを発見するための重要な要素となります。次のステップとして、図6にあるように、すべてのAPIをデベロッパーポータルにリストアップし、それらを検索可能にするためのセクションを追加していきましょう。これにより、API利用者はテキスト検索をおこなってAPIを見つけたり、様々な条件を指定してAPIをフィルタリングしたり、APIを選択してより詳細な情報を取得することができるようになります。このようにして、API利用者は必要なAPIを簡単に見つけることができるようになります。 図6 APIをリストアップするセクションは、以下の手順で作成していきます。 1. 図7に示すように、以下の表にある設定情報を使用して API List というタイトルで新しいページを作成します。正しいパスとセクションが設定されていることを確認してください。GitHubのリンクで提供されているコードをコピーして貼り付けて(ここでは、LayoutとLiquidのセクションの設定値を変更する必要はありません)、 Create Page をクリックします。 図7 セクション 値 Title API List Section |-catalog Path /catalog/list Code URL GitHub のリンク APIの詳細セクション 一覧ページでAPIを検索して絞り込んだ後、API利用者は選択したAPIについてより詳細を知りたいと思うかもしれません。そのようなニーズに対応するために詳細ページを作っていきましょう。このページには、インタラクティブなAPIドキュメントととして、APIのリクエスト/レスポンスで使用されるデータモデル、サインアップの際のオプション、サブスクリプションのプラン、利用規約、サポートオプションなど、APIを把握するために必要な情報が様々含まれます。 APIの詳細セクションは、以下の手順で作成していきます。 1. 図8に示すように、以下の表にある設定情報を使用して API Details というタイトルで新しいページを作成します。Liquidが有効であることと、正しいパスとセクションが設定されていることを確認してください。GitHubのリンクにあるコードをコピーして貼り付け、 Create Page をクリックします。Layout セクションは変更する必要はありません。 図8 セクション 値 Title API Details Section |-catalog Path /catalog/details Advanced Options > Liquid enabled チェックを入れてください Code URL GitHub のリンク 2. 3scale API Managementの管理ポータルでDeveloper Portal → Drafts へ移動し、 Publish All をクリックします(図9)。これにより作成したドキュメントがドラフト状態から公開状態になります。 図9 APIの検索 では最後に、以下の手順でAPIカタログを実際に見てみましょう。 注:3scale API Management 管理ポータルで新しいAPIプロダクトを追加し、アプリケーションプランとそのアプリケーションプランで有効になっているフィーチャー (Features)の設定、およびその API と同じシステム名を持つAPIドキュメントのファイルを使用することによってAPIカタログの動的性質を確認することも可能です。 1. デベロッパーポータルの画面を開き、 /catalog/list のエンドポイントに移動するとAPI の一覧が表示され、検索バーと右側の "Categories" の下にあるフィルター(フィーチャー (Features)の設定)を使って検索とフィルタリングができるようになっているはずです (図 10 参照)。 図10 2. APIを選択してクリックすると、API呼び出しのテストをおこなうことができるインタラクティブなドキュメントや、サブスクリプションプランへのサインアップなど、API の詳細情報が表示されます (図 11 参照)。また、API の利用者が API について知りたいと思うことがあれば、さらにセクションや情報を追加することも可能です。また、画像や CSS ファイルなどのアセットの追加も簡単におこなうことができるので、API提供者は、デベロッパーポータル全体を組織のブランドに沿ったものにカスタマイズすることもできます。 図11 まとめ APIの見える化というのは、どのような組織にとってもAPI戦略の重要な側面であることに間違いありません。APIプロダクトのチームはこのことを後回しにするのではなく、API構築の初期段階から検討していくことでその恩恵に預かることができるようになります。API提供者は、検索、フィルタリング、分類、APIドキュメント、使用に関するルール、利用規約などのAPIの見える化で必要な要素を取り入れることにより、APIのセルフサービス化を効率的に進めていくことができます。 本記事では例を通じて、Red Hat 3scale API Management を使用して動的でインタラクティブな API カタログを作成する方法を学びました。これにより、APIプロダクトのチームは API の見える化と使いやすさを向上させ、API の活用を促進することができます。このようなカスタマイズを3scaleのデベロッパーポータルで行ってみたい方のために、本記事で使用しているファイルは GitHub でアクセスできるようになっていますので是非試してみてください。 Red Hat 3scale API Management を使い始めよう Red Hat 3scale API Managementを使うことでAPI を簡単に管理できるようになり、パフォーマンス、API利用者の管理、将来の成長のために開発された3scaleのAPI基盤上で、API の共有、保護、配布、制御、収益化を実現することができます。3scale API Management のコンポーネントは、オンプレミス、クラウド、またはその組み合わせのいずれにもデプロイすることができます。 Red Hat OpenShift API Management は、3scale API Management のホスティングかつフルマネージドのバージョンです。興味があり、試してみたいという方は、 製品ページ をご覧になってみてください。 参考情報 rheb.hatenablog.com rheb.hatenablog.com rheb.hatenablog.com
レッドハットの杉村です。Ansible のテクニカルサポートをしています。 RHEL の設定変更を Ansible から容易にできるようにするための RHEL System Roles について、以前のブログで紹介されていました。 rheb.hatenablog.com Ansible Automation Platform からこの System Roles を利用しようとすると、せっかく便利に使いたいと思っているのに見つけられないというエラーになってしまいます。 例えばこのようなプレイブックを書いたとします。 --- - hosts: all gather_facts: false become: true vars: timesync_ntp_servers: - hostname: foo.example.com iburst: true - hostname: bar.example.com iburst: true - hostname: baz.example.com iburst: true roles: - linux-system-roles.timesync プロジェクトとジョブテンプレートを作成して実行すると、このようにエラーとなってしまいました。 Ansible Automation Platform ではコンテナイメージとして用意された実行環境 (Execution Environment) を使って Ansible のコマンドを実行するのですが、標準で提供するコンテナイメージの中には System Roles のパッケージはインストールされていないため、controller の OS にインストールしてあっても参照することができないためにエラーとなってしまいます。 ERROR! the role 'linux-system-roles.timesync' was not found in /runner/project/roles:/runner/requirements_roles:/home/runner/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/runner/project この実行環境についてはこちらの記事もご覧ください。 rheb.hatenablog.com このコンテナは Podman を使って実行します。Podman にはコンテナ外のディレクトリをマウントして参照できる設定があり、これを Ansible Automation Platform でも利用することができます。以前はこの設定は単に参照させるために使われたものではあったのですが、Ansible Automation Platform 2.1.2 以降からはオーバーレイマウント(上書き)のためにも設定できるようになりました。 設定 → ジョブ設定 → 分離されたジョブに公開するパス にこの行を追加します。 "/usr/share/ansible/roles/:/home/runner/.ansible/roles:O", "/usr/share/ansible/collections/:/home/runner/.ansible/collections:O" 初期値としては2行入っていますので、カンマ区切りで追加して保存してください。 再度ジョブテンプレートを実行すると、今度は成功します。 もしコントローラが1台ではなくクラスタになっているようなときは、それぞれのコントローラで System Roles のパッケージをインストールしてください。 $ sudo su - # dnf install rhel-system-roles 簡単ではありますが RHEL System Roles の使い方について紹介しました。 Ansible はクラウドリソースやネットワーク機器の扱いが多くなっているように感じておりまして、RHEL を直接設定していくという機会は減ってきているようには思いますが、System Roles は力を入れて開発が進められていますのでご活用いただけましたら幸いです。 Ansible Automation Platform の評価ライセンスリクエストはこちらからご利用いただけます。60日間利用できます。 www.redhat.com Happy Automation!
Cloud製品を担当しているソリューションアーキテクトの輿水です。 今週末の1月27日に開催される「あけおめ OpenShift.Run 2023 〜福袋は誰の手に?〜」のご案内です。このイベントは、OpenShiftのユーザーグループ主催によるイベントです。 開催概要 日時:2023年1月27日(金)12:00-19:00 オンライン開催 ▼参加登録ページ openshift.connpass.com セッション 日頃OpenShiftに深く関わっている方のDeepな内容から、比較的初心者に優しいセッションまで取り揃えてご用意しておりますので、Kubernetesは知っているけどOpenShiftは聞いたことがある程度という方から本番環境で活用している方までどなたもご参加頂けます。開催時間が長時間に渡りますので、フルで参加でなくても必要な部分のみ参加でも問題ありません。正式なタイムテーブルと各セッションの概要がリリースされ次第、本記事も更新します。(以下は1/24現在の情報で、変更になる場合があります) [中級] MultiCloud Gatewayでデータを統治せよ! [中級] OpenShiftの次世代CNIプラグイン「OVN-Kubernetes」Deep Dive [中級] Azure Red Hat OpenShift を Terraform でコード化! [中級] OpenShiftクラスターのアップグレード自動化への挑戦! [中級] 結局OpenShiftでの監視どうしたらいいんだっけ? [中級] Openshift Dev Spaces ( と OpenShift Sandbox ) で ブラウザ上でアプリケーション開発できる環境を構築して みた [中級] OpenShiftでスポットインスタンスを使おう [中級] GitOps Operator のソース読んでみた [初級] Operatorさえあればへのつっぱりはいらんですよ?? [初級] おすすめ kubectl プラグイン のご紹介 ( oc コマンドでも使えるよ ) [ALL] OpenShiftのリリースノートを整理してみた 今回は、ただセッションを聞くだけではなく、ミニゲームやクイズ、 もくもくハンズオン (過去に赤帽ブログで紹介したハンズオン+α予定)、Ask The Expertなど、参加している人が楽しめる参加型を目指しております。 お楽しみ企画 大規模もくもく会 クイズ大会 ミニゲーム大会 展示会 雑談団らんスペース Ask The Expert 非売品プレゼント!? ※お楽しみ企画は仮のため、変更になる可能性があります。また、お楽しみ企画への参加は任意です。 アクセス方法 イベントにアクセスするためのURLはconnpass上で公開されます。配信は「 Gather 」というプラットフォームを利用します。connpassの募集ページにチラリと画面が出ておりますが、アバター利用してRPGの世界に入ってゆくイメージです。 ブラウザ(Chrome,Firefox)があればアクセス可能です。GatherのURLは .townドメインのため、会社環境からアクセスする場合は、.townドメインへのアクセスが許可されているか、ご確認ください。会社環境からアクセスした時、画面がゲーム画面のようで一見遊んでるように見えてしまうのが玉に瑕です。なおGather利用不可の場合には、YouTubeでの配信も予定しておりますので、そちらをご利用ください。 Gatherを利用する際、アカウントを作る必要はありません。イベントのURLにアクセスすると次のような参加画面が表示されるので、適当な名前を入力してJoinしてください。名前はconnpass IDと同じだと運営側としてはわかりやすくて助かります。 Join後の基本操作は「移動する」(矢印キー)「そこにあるオブジェクトにアクセスする」(xキー)「xキーから元に戻る」(Esc)です。「そこにあるオブジェクトにアクセスする」というのは「Google Formを開く」「動画サイトを開く」「ハンズオン画面を開く」「カートに乗る」「ワンちゃんを自分のペットにする」などの操作です。とりあえずこの3つを覚えておけば大丈夫です。移動の際は、物理空間と同様に部屋の壁は通り抜けることができず、決められた入り口を通る必要があります。基本的には他の人や物を通り抜けることはできません(ghostモードという、人を通り抜けるオプションはあります)。他にも様々な操作が可能ですので、興味があればgatherのFAQを参照してください。 support.gather.town 名前やアバターは随時変更できます。参加後、左下のマイクやカメラの設定の横にキャラクターの変更メニューがありますので、こちらも適宜お好きなように髪型や服、アクセサリーなどを選んで変更してください。本イベントの運営者は基本的に赤い帽子をかぶっております。 お楽しみ企画 お楽しみ企画のひとつとして、事前連動企画を行ってます。ツイートに掲載されている該当のGoogle Formにクイズが掲載されているので、それに回答してお送りいただくと、イベント内で福袋(物理)の抽選に役立ちます。 OpenShift.Run2023はフルリモートイベント!でも \..物理福袋🎁../ 勝手につくってみた💪 福袋抽選フォームv1📝: https://t.co/rDtqG2ZIOr ⚠️connpass ID 間違えたら引っかからないので要注意⚠️ #openshiftjp #リモートイベントを楽しみ隊 #盛りあげ隊員求むっ — Kazu@capsmalt (@capsmalt) 2023年1月23日 ぜひ、ご参加ください。1月27日、会場にてお待ちしております。
こんにちは、Red Hat Middleware Technical Account Managerのイアンです。 Technical Account Manager (TAM)として、お客様のシステムの安定稼働をさせるために私は、日々お客様からのサポートケースに対応しています。 その中で、お客様の環境、アプリ、現象などを速やかに再現して原因と対応方法を提供することを心がけています。 物理サーバーや仮想マシン上のミドルウェアをご利用している場合は、自分のローカル環境で割と簡単に再現環境を立ち上げられますが、最近は OpenShift 上のアプリの問い合わせが増えてきました。 OpenShift Local (旧名: CodeReady Containers)を用いて検証用のOpenShift環境を立ち上げることができますが、起動するのに時間かかり、PCのリソースも結構必要です。 ただアプリをイメージ化し、コンテナを起動したいだけなのですが、もっといいやり方がないでしょうか? OpenShift環境上でアプリケーションをデプロイする時は、アプリをソースからビルドする Source-To-Image (s2i)の仕組みがよく使用されるかと思います。 中々いい仕組みで、OpenShift環境がなくても、ローカルで利用することができます! 目次 目次 推奨環境 Podmanについて s2iでのアプリイメージ作成 ランタイムイメージの作成 Stupid s2i/container Tricks ビルドの加速化 latest以外のイメージの利用方法 データベースドライバ導入 EAPとデータベースのPod作成 まとめ 推奨環境 Source-To-ImageをローカルPCで実行するためには、コンテナエンジンが必要です。 Docker と Podman がよく使われています。 当記事では、Fedora 35上の Podman を使用します。 なお、PodmanのコマンドラインツールはDockerと互換性がありますので、Dockerで実行する場合は podman を docker に置き換えて頂ければ使えると思います。 Podmanについて 当記事では、Podmanの詳細には触れませんが、ご興味がある方には、弊社が提供している トレーニング の受講をご検討頂ければ幸いです。 また、Red Hat Developerアカウントをお持ちの方は、 developers.redhat.com から 電子書籍 を無償でダウンロードできます。 Podman入門として Podman In Action をおすすめします。 s2iでのアプリイメージ作成 まずは、最新の s2i バイナリを Source-To-Imageのリポジトリ からダウンロードし、展開します。 また、サンプルアプリとして、 JBoss Enterprise Application Platform (EAP) の Quickstarts の中の helloworld-rs (単純なRESTサービス)を利用するので、 jboss-eap-quickstarts リポジトリをローカルに clone し、 jboss-eap-quickstarts ディレクトリに移動します。 $ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git ... $ cd jboss-eap-quickstarts s2i を使うためには、ビルダーイメージが必要です。 OpenShiftと同じRed Hatが提供している JBoss EAP 7.4ビルダーイメージ を使います。 $ podman pull registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8:latest NOTE: registry.redhat.ioからダウンロードするためには、 podman login registry.redhat.io を使ってRed Hatアカウントにログインする必要があります。 準備ができたら、以下の s2i コマンドを使って、 helloworld-rs のアプリをビルドし、イメージを作成します。 最終イメージ名は localhost/eap-app:latest になります。 s2i build . registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 eap-app \ --copy \ --pull-policy never \ -e GALLEON_PROVISION_LAYERS=jaxrs-server \ -e GALLEON_PROVISION_DEFAULT_FAT_SERVER=true \ -e MAVEN_ARGS_APPEND="-f helloworld-rs/pom.xml" \ -e MAVEN_S2I_ARTIFACT_DIRS=helloworld-rs/target NOTE: OpenShiftと違って、いくつかの $MAVEN_... の環境変数を指定しています。 Quickstartsのソースのサブディレクトリの中の helloworld-rs をビルドするために必要です。 アプリのソースコードはソースディレクトリ直下にある場合は、別ディレクトリの pom.xml などを指定しなくても良いです。 ビルダーイメージからコンテナが起動され、Mavenのビルドが始まります。 Checking if image "registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8" is available locally ... Checking if image "registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8" is available locally ... Provisioning WildFly server... INFO Performing Maven build in /opt/jboss/container/wildfly/s2i/galleon/provisioning/generic_layers INFO Using MAVEN_OPTS -XX:+UseParallelOldGC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+ExitOnOutOfMemoryError ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.713 s [INFO] Finished at: 2023-01-22T12:27:45Z [INFO] ------------------------------------------------------------------------ INFO Copying deployments from helloworld-rs/target to /deployments... '/tmp/src/helloworld-rs/target/ROOT.war' -> '/deployments/ROOT.war' INFO Cleaning up source directory (/tmp/src) INFO Copying server to /s2i-output INFO Linking /opt/eap to /s2i-output Build completed successfully s2i のビルドが完了したら、新しい eap-app イメージがローカルのリポジトリに作成されます。 $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/eap-app latest 6c2779ffb971 43 seconds ago 1.15 GB registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 latest a34c07e25cbf 6 weeks ago 1.01 GB このイメージはそのまま実行できます。 $ podman run --rm \ --name eap \ -p 18080:8080 \ -e ENABLE_ACCESS_LOG=true \ localhost/eap-app:latest \ /opt/eap/bin/openshift-launch.sh アプリの動作を確認します。 $ curl -w "\n" http://localhost:18080/rest.json {"result":"Hello World!"} コンテナ起動時に $ENABLE_ACCESS_LOG の環境変数を指定したので、コンテナの標準出力に以下のようなアクセスログも出ます。 $ podman logs --tail=10 eap ... 12:29:14,076 INFO [io.undertow.accesslog] (default task-1) 10.0.2.100 - - [22/Jan/2023:12:29:14 +0000] - "GET /rest/json HTTP/1.1" 200 25 これで、OpenShiftと同様の s2i 仕組みを使って、アプリのイメージを作成し、起動できました。 でも、これだけではありません。 ランタイムイメージの作成 先に作ったアプリのイメージのサイズをご覧になりましたでしょうか? 1GBほどとなってしまい、ビルダーイメージとほぼ同じサイズです。 ビルダーイメージの上にアプリを載せただけですので、アプリに必要ではないビルド関連のファイル(Maven, s2i)が含まれています。 ローカルでの検証だけなので、サイズがそんなに問題ではないかもしれませんが、OpenShiftと同様のランタイムイメージを使ってイメージを作成できます。 通常のOpenShift上のビルドは、ビルドから作成したアーティファクトを自動的にランタイムイメージにコピーしてくれますが、ローカルの場合は自動的にできません。 jboss-eap-quickstarts ディレクトリに .s2i/bin ディレクトリを作って、中の assemble-runtime ファイルを作って、中身を以下のように設定します。 #!/usr/bin/env bash mkdir /opt/eap cp -r /home/jboss/s2i/s2i-output/server/* /opt/eap chown -R jboss:root /opt/eap && chmod -R ug+rwX /opt/eap NOTE: assemble-runtime のコマンドはOpenShiftの eap74-basic-s2i.json テンプレートを参照して作成しました。 chmod u+x .s2i/bin/assemble-runtime で実行可能にします。 また、ランタイムイメージを pull しましょう。 $ podman pull registry.redhat.io/jboss-eap-7/eap74-openjdk11-runtime-openshift-rhel8 これができたら、前回の s2i コマンドに runtime イメージ関連のオプションを足して実行します。 $ s2i build /path/to/jboss-eap-quickstarts registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 eap-app \ --runtime-artifact /s2i-output:s2i \ --runtime-image registry.redhat.io/jboss-eap-7/eap74-openjdk11-runtime-openshift-rhel8 \ --runtime-pull-policy never --copy \ --pull-policy never \ -e GALLEON_PROVISION_LAYERS=jaxrs-server \ -e GALLEON_PROVISION_DEFAULT_FAT_SERVER=true \ -e MAVEN_ARGS_APPEND="-f helloworld-rs/pom.xml" \ -e MAVEN_S2I_ARTIFACT_DIRS=helloworld-rs/target 実行すると、 s2i は前回と同様にアプリをビルドしますが、ビルドのアーティファクトが含まれている /s2i-output ディレクトリをランタイムイメージの /home/jboss/s2i ディレクトリにマウントします。 その後、用意した assemble-runtime スクリプトが動き、ビルド結果を /opt/eap にコピーします。 最後にランタイムイメージを eap-app としてローカルリポジトリにプッシュします。 出来上がった eap-app イメージにはMaven, s2iなどのビルド関連のファイルがないので、ビルダーイメージの場合よりサイズを小さくできます。 $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/eap-app latest 352389a94bf3 15 seconds ago 814 MB registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 latest a34c07e25cbf 6 weeks ago 1.01 GB registry.redhat.io/jboss-eap-7/eap74-openjdk11-runtime-openshift-rhel8 latest 164d988e5c07 6 weeks ago 532 MB Stupid s2i/container Tricks ビルドの加速化 ここまで来て、数回 s2i でアプリをビルドして気づいたかと思いますが、毎回依存モジュールのダウンロードが必要となり、時間がかかっています。 サポートエンジニアとして、現象を再現する時は、コードを修正し、実行することを何回も繰り返すので、 s2i のビルドを加速させたらビルドに要している時間を省いて早く再現することができます。 ビルダーイメージは /tmp/artifacts/m2 をローカルMavenリポジトリとして使用しています。 そのため、コンテナ用のボリュームを /tmp/artifacts にマウントすれば、ダウンロードした依存モジュールを今後のビルドでも再利用できます。 s2i の -v オプションでボリュームマウントを指定できます。 $ podman volume create eap-build-repo $ s2i build . registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 eap-app \ --copy \ --pull-policy never \ -e GALLEON_PROVISION_LAYERS=jaxrs-server \ -e GALLEON_PROVISION_DEFAULT_FAT_SERVER=true \ -e MAVEN_ARGS_APPEND="-f helloworld-rs/pom.xml" \ -e MAVEN_S2I_ARTIFACT_DIRS=helloworld-rs/target \ -v "eap-build-repo:/tmp/artifacts" もう一度 s2i build コマンドを実行すると、アプリのビルドがすぐに終わります。 latest以外のイメージの利用方法 当記事を書いた時の eap74-openjdk11-openshift-rhel8 イメージはJBoss EAP 7.4.8を使用していますが、 例えば、お客様の環境に合わせて、 7.4.2 を使いたい場合はどうすればいいでしょうか? 残念ながら、以下のようなコマンドを使っても、ビルダーイメージの latest が使用されてしまいます。 $ s2i build . registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8:7.4.2 eap-app \ ... ここでイメージのタグを使えます! 以下のコマンドで jboss-eap-7/eap74-openjdk11-openshift-rhel8:7.4.2 イメージを localhost/eap74-openjdk11-openshift-rhel8:latest としてタグ付けします。 $ podman pull registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8:7.4.2 $ podman tag registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8:7.4.2 localhost/eap74-openjdk11-openshift-rhel8:latest タグ付けしたら、 s2i build コマンドで新規にタグ付けしたイメージを使います。 $ s2i build . localhost/eap74-openjdk11-openshift-rhel8 eap-app \ ... Source-To-Imageは localhost/eap74-openjdk11-openshift-rhel8:latest を使いますが、そのタグは実は jboss-eap-7/eap74-openjdk11-openshift-rhel8:7.4.2 を指していますので、JBoss EAP 7.4.2のイメージが出来上がります。 このやり方はランタイムイメージにも適用できます。 データベースドライバ導入 OpenShiftと同じs2i仕組みですので、環境変数を使って、データベースドライバの導入と設定を行えます。 今回のサンプルアプリはデータベースを使っていませんが、もしお持ちのアプリがデータベースを使っている場合の設定方法を紹介します。 NOTE: 以下の手順は Getting Started with JBoss EAP for OpenShift Container Platform Red Hat JBoss Enterprise Application Platform 7.4 の Datasources 章を参照して作成しました。 まずは、 jboss-eap-quickstarts ディレクトリに extensions ディレクトリを作成します。 その中に、 modules/org/postgresql/main ディレクトリを作成します。 extensions/modules/org/postgresql/main の中に PostgreSQL 14のJDBCドライバー (記事作成当時は postgresql-42.5.1.jar )を置きます。 同じディレクトリに module.xml を作成し、中身を以下のように設定します。 NOTE: resource-root の path 属性をダウンロードしたJDBCドライバーのファイル名に設定します。 <? xml version = "1.0" ?> <module xmlns = "urn:jboss:module:1.1" name = "org.postgresql" > <resources> <resource-root path = "postgresql-42.5.1.jar" /> </resources> <dependencies> <module name = "wildflyee.api" /> <module name = "sun.jdk" /> <module name = "ibm.jdk" /> <module name = "javax.api" /> <module name = "javax.transaction.api" /> </dependencies> </module> extensions/drivers.env ファイルを作って、中身を以下にします。 このファイルはEAP起動時のデータベースドライバーの登録に使用されます。 DRIVER DRIVERS=POSTGRES POSTGRES_DRIVER_NAME=postgresql POSTGRES_DRIVER_MODULE=org.postgresql POSTGRES_DRIVER_CLASS=org.postgresql.Driver POSTGRES_XA_DATASOURCE_CLASS=org.postgresql.xa.PGXADataSource 最後に extensions/install.sh を作ります。 このファイルはSource-To-Buildの中で実行され、 modules サブディレクトリを /opt/eap/modules にコピーし、 drivers.env を /opt/eap/bin/openshift にコピーします。 NOTE: install.sh の詳細は Modules, Drivers, and Generic Deployments をご参照ください。 #!/bin/bash injected_dir=$1 source /usr/local/s2i/install-common.sh install_modules ${injected_dir}/modules configure_drivers ${injected_dir}/drivers.env 最終的に extensions ディレクトリの構成は以下のようになります。 extensions ├── drivers.env ├── install.sh └── modules └── org └── postgresql └── main ├── module.xml └── postgresql-42.5.1.jar ここで s2i build を実行して、アプリのイメージを作成します。 NOTE: 今回は $CUSTOM_INSTALL_DIRECTORIES の環境変数を指定しています。 $ s2i build /path/to/jboss-eap-quickstarts registry.redhat.io/jboss-eap-7/eap74-openjdk11-openshift-rhel8 eap-app \ --copy \ --pull-policy never \ -e GALLEON_PROVISION_LAYERS=jaxrs-server \ -e GALLEON_PROVISION_DEFAULT_FAT_SERVER=true \ -e MAVEN_ARGS_APPEND="-f helloworld-rs/pom.xml" \ -e MAVEN_S2I_ARTIFACT_DIRS=helloworld-rs/target \ -e CUSTOM_INSTALL_DIRECTORIES=extensions ... INFO Copying deployments from helloworld-rs/target to /deployments... '/tmp/src/helloworld-rs/target/ROOT.war' -> '/deployments/ROOT.war' INFO Processing ImageSource mounts: extensions INFO Processing ImageSource from /tmp/src/extensions INFO Cleaning up source directory (/tmp/src) INFO Copying server to /s2i-output INFO Linking /opt/eap to /s2i-output Build completed successfully s2i は無事に extensions ディレクトリの install.sh を実行できました。 起動する時は、環境変数を用いてデータソースを設定します。 $ podman run \ --rm \ --name eap \ -p 18080:8080 \ -e ENABLE_ACCESS_LOG=true \ -e DB_SERVICE_PREFIX_MAPPING=test-postgresql=TEST \ -e TEST_NONXA=true \ -e TEST_CONNECTION_CHECKER=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker \ -e TEST_EXCEPTION_SORTER=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter \ -e TEST_USERNAME=postgres \ -e TEST_PASSWORD=changeme \ -e TEST_POSTGRESQL_SERVICE_HOST=localhost \ -e TEST_POSTGRESQL_SERVICE_PORT=5432 \ -e TEST_DATABASE=test \ localhost/eap-app:latest \ /opt/eap/bin/openshift-launch.sh EAPのCLIを使って、データソースが作成されたことを確認できますが、実際のデータベースがないため、接続テストを行うとエラーになります。 $ podman exec eap /opt/eap/bin/jboss-cli.sh -c "/subsystem=datasources/data-source=test_postgresql-TEST:test-connection-in-pool" { "outcome" => "failed", "failure-description" => "WFLYJCA0040: failed to invoke operation: WFLYJCA0047: Connection is not valid", "rolled-back" => true } ローカル環境でもEAPとデータベースを試せたらいいですね。 EAPとデータベースのPod作成 Podmanの機能の一つとして、複数コンテナを一つPodとして管理することが可能です(Kubernetesと同じような概念です)。 この機能を用いて、PostgreSQLとEAPの2つのコンテナを起動し、お互いに接続できるようにします。 3つのコマンドを使って、Podを作成して、PostgreSQLとEAPのコンテナをPodの中に作成します。 $ podman pod create -n eap \ -p 18080:8080 $ podman create \ --pod eap \ --name postgres \ -e POSTGRES_USER=postgres \ -e POSTGRES_PASSWORD=changeme \ -e POSTGRES_DB=test \ postgres:14 $ podman create \ --pod eap \ --name eap-app \ -e ENABLE_ACCESS_LOG=true \ -e DB_SERVICE_PREFIX_MAPPING=test-postgresql=TEST \ -e TEST_NONXA=true \ -e TEST_CONNECTION_CHECKER=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker \ -e TEST_EXCEPTION_SORTER=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter \ -e TEST_USERNAME=postgres \ -e TEST_PASSWORD=changeme \ -e TEST_POSTGRESQL_SERVICE_HOST=localhost \ -e TEST_POSTGRESQL_SERVICE_PORT=5432 \ -e TEST_DATABASE=test \ localhost/eap-app:latest \ /opt/eap/bin/openshift-launch.sh 作成したPodを podman pod start eap で起動します。 2つコンテナが起動したことを確認できます。 NOTE: pause のコンテナは cgroups の名前空間を管理するためのもので、Podmanが自動的に起動/停止します。 $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d27be4db5138 k8s.gcr.io/pause:3.5 39 seconds ago Up 27 seconds ago 0.0.0.0:18080->8080/tcp d15a4ef315f2-infra 2e7170d72f23 docker.io/library/postgres:14 postgres 39 seconds ago Up 26 seconds ago 0.0.0.0:18080->8080/tcp postgres 205e1e9c1691 localhost/eap-app:latest /opt/eap/bin/open... 39 seconds ago Up 26 seconds ago 0.0.0.0:18080->8080/tcp eap-app 今回は、データベースへの接続テストを行うと、成功します。 $ podman exec eap-app \ /opt/eap/bin/jboss-cli.sh -c "/subsystem=datasources/data-source=test_postgresql-TEST:test-connection-in-pool" { "outcome" => "success", "result" => [true] } Podを停止したい場合は podman pod stop eap を実行します。 まとめ OpenShift環境を使わくても、s2iの仕組みやコンテナ技術を使って、ローカルで色々検証することが可能です。 お客様の環境や現象をすぐに再現し、原因究明を行うことはTAMとして誇りに思います。
Red Hat のソリューションアーキテクトの伊藤ちひろ ( @chiroito )です。 よくいろいろな役割の開発者の方々から「Red Hat はデータストアを持ってないよね」と言われることがあります。 でも、実は、Red Hat はほとんどの人に知られることなくひっそりと昔から開発してきたデータストアがあるのです。 本記事では、Red Hat が開発している OSS データストアである Infinispan の概要を紹介します。 Infinispan は Red Hat Data Grid (RHDG)という名前で提供しています。 Infinispan は「インメモリー・データ・グリッド」と呼ばれる分類のデータストアです。 KVSを使用されている開発者の方からは、「インメモリー・データ・グリッドは、キー・バリュー・ストア(KVS)の事でしょ?」と言われる事が良くあります。インメモリー・データ・グリッドは、データへのアクセス方法はKVSと同じですが、さらにたくさんの機能を持っています。今回は全ての機能を紹介しきれませんが、残りの機能については次回以降紹介していきます。 本記事では、Infinispan と RHDG のことを「データグリッド」と記載します。 データグリッドとは みなさんは「そもそも、何ができるの?」と思われるかもしれません。 データグリッドは、アプリケーションとインフラストラクチャの両方に対して、様々なメリットを提供します。以下のようなメリットがあります。 アプリケーションの観点では、 KVSとしてデータグリッドへ様々なデータ形式のデータを格納できます。 各データの寿命を設定したり、データに変更があった場合に変更を検知できます。 データをアプリケーション側へロードするのではなく、アプリケーションからデータグリッドへ処理を依頼することで低遅延高スループットな処理を実現できます。 アプリケーションが欲しいデータがデータグリッド上にない場合、他のデータストアから自動的に取得することや、アプリケーションが頻繁に使うデータをアプリケーション側に自動的にキャッシュできます。 KVSとは異なり、キーを使用しないデータアクセスも可能です。 この様な機能をJavaのみならず様々な言語でサポートしています。 インフラストラクチャの観点では、 全てのノードがデータを読み書き可能で、必要に応じてスケールイン/アウトできます。 ざまざまな要件に対応可能なデプロイ方法、データの複製・分散方法があり、リージョンを跨いだ構成も実現できます。 全ての通信経路は暗号化でき、クラウドだけではなくオンプレでも稼働できます。 さまざまなデファクトスタンダードと統合されており、十分な運用ツール群も提供しています。 よく使われる用途 次にデータグリッドの使用用途ですが、 データグリッドは、世界中のさまざまな業界の、多くの企業で使用されています。 よく使われる業界は、 通信 金融機関 小売業 などが挙げられ、 IoT 広告 ゲーム ECサイト などのシステムで導入されています。 使われ方も様々で ユーザ情報のような頻繁にアクセスされる情報 セッション情報のような一時的に使用されて変更の多いデータ ECサイトのカート 同時に複数のユーザから変更される在庫数の管理 負荷の高い処理のキャッシュ などがあります。 日本では、公開できる事例は少ないものの、多くの使用実績があります。 データの格納方法 アプリケーションが、データグリッド上のデータへアクセスする方法は基本的にはKVSと同様です。 KVSをご存じないJavaエンジニアの方は、JavaでいうMapインターフェースをイメージしてください。 「キー」と「バリュー」の組み合わせでアクセスし、この組み合わせはエントリと呼ばれます。 データは、データグリッド上にキャッシュと呼ばれる単位で管理されています。これはRDBMSでいうテーブルです。 複数のキャッシュを定義することで複数種類のデータを格納できます。 アプリケーションはAPIを使用してキャッシュのインターフェースを取得します。 データを格納するときは、put メソッドに、キーとバリューを指定します。 データを読み込むときは、getメソッドにキーを指定するとバリューを得られます。 扱えるデータ型 データグリッドは文字列から複雑なオブジェクトまで様々なデータ型を扱えます。 これらのデータは、実際にはデータグリッドによって、データグリッドが扱いやすい形式に変換されてデータグリッドのメモリ中に格納されます。 テキストや数値などのデータはもちろん、XMLやJSONといったドキュメント型のデータも格納できます。 ドキュメント型のデータは文字列として格納されます。 Java の場合はドキュメント型の文字列を JsonObjectやXMLObjectとして読み込んで使用します。 また、複雑なオブジェクトはprotobuf形式に変換して格納されます。 もちろん、オブジェクトの中にコレクションクラスのオブジェクトも含められるため、1つのキーに対して複数のオブジェクトを格納できます。 他にも、Javaの場合はJakarta EE のアプリケーションサーバの設定を変えるだけで、HTTPのセッションオブジェクトを格納できます。 今回は、データグリッドの概要を紹介しました。次回以降、性能面や可用性面を中心にどの様な事ができるのかを紹介します。
Red Hatの小島です。 本記事では、パブリッククラウドで利用する従量課金形式のRHELで、Red Hat Insightsを利用する方法をご紹介します。 前置き Red Hat Insightsの利用方法 参考情報 前置き 有効なRHELのサブスクリプションを持っていると無料で利用できる、Red Hat InsightsというSaaS形態のサービスがあります。Red Hat InsightsはRHELを始めとするRed Hat製品の問題(RPMパッケージの脆弱性情報や設定情報の不備など)を未然に検知し、Red HatのWebサイト上でHTMLベースのレポートを表示するサービスです。Red Hat Insightsの概要については、下記の記事もご参照ください。 rheb.hatenablog.com さて、このRed Hat Insightsですが、実は、 Red Hatの認定パブリッククラウドプロバイダーが提供するRHELを使う時でも利用できるようになっています。 例えば、AWS/Azure/GCPなどのマーケットプレイスで払い出された従量課金形式のRHELインスタンスを利用している場合、利用者はRHELの利用料金を、Red Hatではなく、提供元のクラウドプロバイダー(AWS, Microsoft, Googleなど)に全て支払うようになっていますが、このときもRed Hat Insightsを利用することができます。 この場合に限っては、利用者は、有効なRHELのサブスクリプションを持っておく必要はありません。 Red Hat Insightsを使うときは、最低限Red Hatのアカウントを作っておく必要があります。無料で作成できますので、アカウントを持っていない場合は、 Red Hatのカスタマーポータル から作成しましょう。ここで作成したアカウントを使うことにより、パブリッククラウドに払い出されたRHELインスタンスで、Red Hat Insightsの利用を開始できます。 Red Hat Insightsの利用方法 RHEL7までのRHELインスタンスを利用している場合、次のコマンドを実行して、Red Hat Insightsのクライアントパッケージをインストールします。クラウドプロバイダーが提供するRHELインスタンスについては、デフォルトで RHUI(Red Hat Update Infrastructure) という、クラウドプロバイダーが運用管理するRHELのリポジトリサーバーを参照できるように設定されており、最初からyumやdnfコマンドでRHELのパッケージをインストールできるようになっています。なお、RHEL8以降の場合は、クライアントパッケージはデフォルトでインストールされているため、このコマンドの実行は不要です。 $ sudo yum -y install insights-client 次に、insights-clientパッケージの設定ファイル(/etc/insights-client/insights-client.conf)で、Red Hat Insightsを利用するためのBASIC認証を設定します。設定ファイルの末尾に、設定項目を追加して保存します。なお、 ユーザー名とパスワードはプレーンテキストとして保存されるため、Red Hat Insightsを利用するための専用のユーザーを新規作成しておくことを推奨します。 $ sudo tee -a /etc/insights-client/insights-client.conf <<EOF > /dev/null > auto_config=False > authmethod=BASIC > username=<上記で作成したRed Hatアカウントのユーザー名> > password=<上記で作成したRed Hatアカウントのパスワード> > EOF 最後に、RHELインスタンスをRed Hat Insightsに登録するコマンドを実行します。 $ sudo insights-client --register Successfully registered host XXXXXXXXXX Automatic scheduling for Insights has been enabled. Starting to collect Insights data for XXXXXXXXXX Uploading Insights data. Successfully uploaded report from XXXXXXXXXX to account YYYYYYYYYY. View the Red Hat Insights console at https://console.redhat.com/insights/ Red Hat Insightsへの登録が完了すると、上記のような View the Red Hat Insights console at https://console.redhat.com/insights/ というメッセージが出力されます。 Red Hat InsightsのWebページ にアクセスして、RHELインスタンスのシステム情報があることを確認できます。 このように、オンプレとパブリッククラウドの両方でRed Hat Insighsを利用することで、ハイブリッドクラウドでのRHELの一貫した運用を実現する手助けとなります。ぜひともご活用ください。 参考情報 パブリッククラウドでのRed Hat Insights利用ガイド access.redhat.com Red Hat Update Infrastructure が管理する既存の RHEL システムに Red Hat Insights をデプロイする access.redhat.com AWSで利用可能なオンデマンド(従量課金)RHELイメージの一覧 access.redhat.com Azureで利用可能なオンデマンド(従量課金)RHELイメージの一覧 learn.microsoft.com GCPで利用可能なオンデマンド(従量課金)RHELイメージの一覧 cloud.google.com
Red Hat のソリューションアーキテクトの森です。 Red Hat にはクラウドネイティブアプリの開発に役立つ、ソフトウェアのラインナップが充実していることをご存知ですか? ここでは、それらのソフトウェア [Red Hat Application Services] に関する注目ニュースを、各製品技術に特化したソリューションアーキテクトがご紹介していきます。 今回は 2023/1月号となります。 想定読者 エンタープライズアーキテクト アプリケーション開発者 システムの提案をするSIerの方 特集1: JBoss EAP 7.x から JBoss EAP 8-Beta への移行方法 こちらの特集では、最近リリースされたJBoss EAP 8-Betaについて説明します。JBoss EAP 8 で導入された変更点について解説し、アプリケーションを JBoss EAP 7.4 から移行するために必要な手順を示します。 rheb.hatenablog.com 特集2: Application Manages Servicesの紹介 Red Hat Summit: Connect | Japan 2022でお話させていただきました「Application Manages Servicesの紹介」のまとめ記事になります。 本記事では一部のマネージドサービスについてご紹介をさせて頂きます。 rheb.hatenablog.com 特集3: Red HatのService Registryを使用したQuarkusアプリケーション Application Services Newsletter 2022年11月号記事の Red HatのService Registryを使用してスキーマの進化に対応しよう! の続編として、今回の記事ではService Registryを使用したQuarkusアプリケーションについて紹介しています。 rheb.hatenablog.com 直近GAになった製品群 最近リリースとなった Application Services 製品群のリストをご紹介します。 見逃している製品が無いか、是非一度ご確認ください。 Red Hat JBoss Enterprise Application Platform 8-Beta Red Hat build of Quarkus 2.13 Red Hat Data Grid 8.4 Red Hat build of Apache Camel for Spring Boot 3.18 Red Hat build of OptaPlanner 8.29
みなさんメリークリスマス。Red Hatのさいとうです。例年になく静かなクリスマスを過しながら、このAnsible Advent Calendar最終日12月25日の記事を書いています。 2022年もAnsible界隈では大きな動きがいくつかありました。個人的にはコンテナ実行環境とPrivate AutomationHubに やられた 注力した1年でした。 毎年、Advent Calendarの最終日には、来年に向けて僕が「来そう」だと予想している技術をご紹介しているのですが、来年、2023年に来そうなのは「Ansible SDK」です。 Ansible SDK Ansible SDKは、2022年に本格的な活動が始まった最新のプロジェクトの中の1つです。ソースコードの最初のコミットは2022年7月26日ですね。 commit 318bde98585223f00842a8a1605f0f1d6089dd21 Author: Abhijeet Kasurde <akasurde@redhat.com> Date: Tue Jul 26 19:14:22 2022 +0530 Initial commit CI/CDなどのシステムからAnsibleを利用しようとすると、これまではansible-playbookコマンドを実行し、その実行結果をハンドリングするというのが一般的な利用方法でした。Ansibleはシンプルなコマンドラインツールですから、すでに稼動しているJenkinsなどのシステムに組み込むには、このansible-playbookコマンドを実行する仕組み開発し、プラグインとして組み込むというのが一般的な利用方法ではないでしょうか。 Ansible SDKは、このようなコマンド実行という仕組みではなく、よりプログラマブルでキメ細かい制御を実現したいというパワーユーザ向けのSDKです。Ansibleを外部システムから便利に利用するため機能、たとえば実行環境(ネイティブ環境、コンテナ環境)の切り替えといった機能をまとめてSDKとして提供しています(していく予定だと思います)。 Ansible SDKの ソースコードリポジトリ Ansible SDKの デモ Ansible SDKの ドキュメント これまでのAnsible Python API Ansibleは、ansible-playbookやansible-galaxyなどのシンプルなコマンドラインツール群で構成されていますが、それらのコマンドラインツールが内部で利用しているPython APIを、外部プログラムから利用できるようPython APIも提供しています。誰も使ってないけれど。 例えば、pingモジュールを2回(うち1回はdata='crash'で失敗させる)をlocalhostとserver00(こっちは未到達)に実行するようなPlaybookを、Python APIを利用して書くと以下のようになります。この例では、既存のPlaybookのロードなどの処理は書いておらず、必要最低限の処理としてcallback程度しか書いていませんが、これは...わざわざPython APIを使用するよりも、普通にansible-playbookコマンドで叩いたほうが確かに良さそうです。 #!/usr/bin/env python import json import shutil import ansible.constants as C from ansible.executor.task_queue_manager import TaskQueueManager from ansible.module_utils.common.collections import ImmutableDict from ansible.inventory.manager import InventoryManager from ansible.parsing.dataloader import DataLoader from ansible.playbook.play import Play from ansible.plugins.callback import CallbackBase from ansible.vars.manager import VariableManager from ansible import context class ResultsCollectorJSONCallback (CallbackBase): def __init__ (self, *args, **kwargs): super (ResultsCollectorJSONCallback, self).__init__(*args, **kwargs) self.host_ok = {} self.host_unreachable = {} self.host_failed = {} def v2_runner_on_unreachable (self, result): host = result._host self.host_unreachable[host.get_name()] = result def v2_runner_on_ok (self, result, *args, **kwargs): host = result._host self.host_ok[host.get_name()] = result print (json.dumps({host.name: result._result}, indent= 4 )) def v2_runner_on_failed (self, result, *args, **kwargs): host = result._host self.host_failed[host.get_name()] = result def main (): host_list = [ 'localhost' , 'server00' ] context.CLIARGS = ImmutableDict(connection= 'smart' ) sources = ',' .join(host_list) if len (host_list) == 1 : sources += ',' loader = DataLoader() passwords = dict () results_callback = ResultsCollectorJSONCallback() inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, inventory=inventory) tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, stdout_callback=results_callback, ) play_source = dict ( name= "Ansible Play" , hosts=host_list, gather_facts= 'no' , tasks=[ dict (action= dict (module= 'ping' )), dict (action= dict (module= 'ping' , args= dict (data= 'crash' ))), ] ) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) try : result = tqm.run(play) finally : tqm.cleanup() if loader: loader.cleanup_all_tmp_files() shutil.rmtree(C.DEFAULT_LOCAL_TMP, True ) print ( "UP ***********" ) for host, result in results_callback.host_ok.items(): print ( '{0} >>> {1}' .format(host, result._result[ 'ping' ])) print ( "FAILED *******" ) for host, result in results_callback.host_failed.items(): print ( '{0} >>> {1}' .format(host, result._result[ 'msg' ])) print ( '{0} >>> STDOUT:{1}' .format(host, result._result[ 'module_stdout' ])) print ( '{0} >>> STDERR:{1}' .format(host, result._result[ 'module_stderr' ])) print ( "DOWN *********" ) for host, result in results_callback.host_unreachable.items(): print ( '{0} >>> {1}' .format(host, result._result[ 'msg' ])) if __name__ == '__main__' : main() 実行してみると、成功、失敗、未到達といった状況もハンドリングでき、実用としては十分ではありますが、やはりちょっと手間がかかりますね。 $ python example_api.py { "localhost": { "ping": "pong", "invocation": { "module_args": { "data": "pong" } }, "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "warnings": [ "Platform darwin on host localhost is using the discovered Python interpreter at /usr/bin/python3, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-core/2.14/reference_appendices/interpreter_discovery.html for more information." ], "_ansible_no_log": null, "changed": false } } UP *********** localhost >>> pong FAILED ******* localhost >>> MODULE FAILURE See stdout/stderr for the exact error localhost >>> STDOUT:Traceback (most recent call last): File "/Users/hsaito/.ansible/tmp/ansible-tmp-1671962136.749241-66036-54422040219731/AnsiballZ_ping.py", line 107, in <module> _ansiballz_main() File "/Users/hsaito/.ansible/tmp/ansible-tmp-1671962136.749241-66036-54422040219731/AnsiballZ_ping.py", line 99, in _ansiballz_main invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS) File "/Users/hsaito/.ansible/tmp/ansible-tmp-1671962136.749241-66036-54422040219731/AnsiballZ_ping.py", line 47, in invoke_module runpy.run_module(mod_name='ansible.modules.ping', init_globals=dict(_module_fqn='ansible.modules.ping', _modlib_path=modlib_path), File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/runpy.py", line 210, in run_module return _run_module_code(code, init_globals, run_name, mod_spec) File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/runpy.py", line 97, in _run_module_code _run_code(code, mod_globals, init_globals, File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/runpy.py", line 87, in _run_code exec(code, run_globals) File "/var/folders/kb/tk3jg2mn4m1535zd5zr4lnkc0000gn/T/ansible_ping_payload_4qlm0wra/ansible_ping_payload.zip/ansible/modules/ping.py", line 89, in <module> File "/var/folders/kb/tk3jg2mn4m1535zd5zr4lnkc0000gn/T/ansible_ping_payload_4qlm0wra/ansible_ping_payload.zip/ansible/modules/ping.py", line 79, in main Exception: boom localhost >>> STDERR:Shared connection to localhost closed. DOWN ********* server00 >>> Failed to connect to the host via ssh: ssh: connect to host server00 port 22: Network is unreachable Ansible Python APIの ドキュメント Ansible SDKの良いところ 従来のPython APIは、Ansible Coreが提供するAPIを利用しています。つまり、Ansible Runnerが提供するような、Playbook実行環境の切り替え(ネイティブ実行環境とコンテナ実行環境の切り替え)や、Receptorを経由したPlaybook実行環境の延伸といった、エンタープライズ環境で求められるような魅力的な機能を利用することができませんでした。 Ansible SDKでは、自動化フレームワークの中でAnsible Runnerを利用しています。また、実行環境の延伸手段としてReceptorを利用することができます。これは、Red Hatが提供しているAnsible automation controllerと同じ仕組みであるため、「コンテナ環境でPlaybookを実行したい」、「遠隔地にある実行環境を利用してPlaybookを実行したい」といったリクエスにも対応することができます(仮に今はできなくても近い将来可能となるはずです)。 Ansible SDKによるPlaybookの実行 Ansible SDKを利用するには、以下のコンポーネントが必要です。あらかじめインストールしておきましょう。SDKは、ソースコードリポジトリをcloneして、最新版を利用します。 $ python -m venv venv/ansible-sdk $ source venv/ansible-sdk/bin/activate (ansible-sdk)$ pip install -U pip (ansible-sdk)$ pip install ansible-core (ansible-sdk)$ pip install ansible-runner (ansible-sdk)$ pip install receptorctl (ansible-sdk)$ git clone git://github.com/ansible/ansible-sdk (ansible-sdk)$ cd ansible-sdk (ansible-sdk)$ pip install -e . Ansible SDKでは、Ansible Runnerを利用してPlaybookを実行するためのフレームワークを提供します。では、pingモジュールを実行してみましょう。以下のコードを example00.py として保存します。 #!/usr/bin/env python import asyncio from tempfile import mkdtemp from ansible_sdk import AnsibleJobDef from ansible_sdk.executors import AnsibleSubprocessJobExecutor, AnsibleSubprocessJobOptions async def main (): executor = AnsibleSubprocessJobExecutor() executor_options = AnsibleSubprocessJobOptions() tmp_data_dir = mkdtemp() jobdef = AnsibleJobDef( data_dir=tmp_data_dir, playbook= None , module= 'ping' , host_pattern= 'localhost' ) job_status = await executor.submit_job(jobdef, executor_options) async for line in job_status.stdout_lines: print (line) await job_status if __name__ == '__main__' : asyncio.run(main()) 実行してみると、たしかにad-hocコマンド( ansible localhost -m ping )と同様の結果が得られました。前述の通りAnsible SDKは、自動化のフレームワークとしてAnsible Runnerを使用しているので、Runnerの流儀にしたがって /tmp/ に、data_dir(今回は空)とartifactsが保存されるワーキングディレクトリが作成されているはずです。 (ansible-sdk)$ python example00.py [WARNING]: No inventory was parsed, only implicit localhost is available localhost | SUCCESS => { "changed": false, "ping": "pong" } (ansible-sdk)$ ansible localhost -m ping [WARNING]: No inventory was parsed, only implicit localhost is available localhost | SUCCESS => { "changed": false, "ping": "pong" } (ansible-sdk)$ find /tmp/tmp* /tmp/tmp64v1c63m /tmp/tmpl3r13t33 /tmp/tmpl3r13t33/artifacts /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86 /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/rc /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/status /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/fact_cache /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/stderr /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/stdout /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/command /tmp/tmpl3r13t33/artifacts/110fb364-db2b-480e-8225-ff32838abd86/job_events Ansible SDKからコンテナ実行環境を利用する Ansible Runnerを利用しているということは、前述のad-hocコマンドやPlaybookの実行時にDocker/podmanを利用したコンテナベースの実行環境が利用できるということです。そこで、アップストリームにある サンプルコード を参考に、コンテナ実行環境でad-hocコマンドを実行するコードを書いて example01.py として保存します。 #!/usr/bin/env python import asyncio from tempfile import mkdtemp from ansible_sdk import AnsibleJobDef from ansible_sdk.executors import AnsiblePodmanJobExecutor, AnsiblePodmanJobOptions async def main (): executor = AnsiblePodmanJobExecutor() executor_options = AnsiblePodmanJobOptions(container_image_ref= 'quay.io/ansible/ansible-runner:devel' ) tmp_data_dir = mkdtemp() jobdef = AnsibleJobDef( data_dir=tmp_data_dir, playbook= None , module= 'pause' , module_args= 'seconds=180' , host_pattern= 'localhost' ) job_status = await executor.submit_job(jobdef, executor_options) async for line in job_status.stdout_lines: print (line) await job_status if __name__ == '__main__' : asyncio.run(main()) example01.py では、ansible-runnerコンテナ(quay.io/ansible/ansible-runner:devel)を利用して、ad-hocコマンドを実行しています。awx-eeイメージが存在しないことを確認してから、 example01.py を実行してみましょう。 (ansible-sdk)$ podman images REPOSITORY TAG IMAGE ID CREATED SIZE (ansible-sdk)$ python example01.py [WARNING]: You are running the development version of Ansible. You should only run Ansible from "devel" if you are modifying the Ansible engine, or trying out features under development. This is a rapidly changing source of code and can become unstable at any point. [WARNING]: Unable to parse /runner/inventory/hosts as an inventory source [WARNING]: No inventory was parsed, only implicit localhost is available Pausing for 180 seconds (ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort) localhost | SUCCESS => { "changed": false, "delta": 180, "echo": true, "rc": 0, "start": "2022-12-25 09:04:33.396725", "stderr": "", "stdout": "Paused for 180.0 seconds", "stop": "2022-12-25 09:07:33.397015", "user_input": "" } pauseモジュールの実行中に、別ターミナルをオープンしてコンテナの実行状況を確認してると、コンテナ実行環境を利用してad-hocコマンドとしてpauseモジュールが実行されているのがわかります。 $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 076655c80b00 quay.io/ansible/ansible-runner:devel ansible -i /runne... About a minute ago Up About a minute ago ansible_runner_3cff6702-dab0-47ce-9879-748d950e1442 $ podman inspect 076655c80b00 [ { "Id": "076655c80b00fdb9348be9bfb61d6193bfd8504e5e006bd0f935ad7dddc11944", "Created": "2022-12-25T09:04:31.419783404Z", "Path": "entrypoint", "Args": [ "ansible", "-i", "/runner/inventory/hosts", "-m", "pause", "-a", "seconds=180", "localhost" ], ...省略... "Cmd": [ "ansible", "-i", "/runner/inventory/hosts", "-m", "pause", "-a", "seconds=180", "localhost" ], "Image": "quay.io/ansible/ansible-runner:devel", ...省略... "CreateCommand": [ "/usr/bin/podman", "run", "--rm", "--tty", "--interactive", "--workdir", "/runner/project", "-v", "/tmp/tmpu4bv0901/:/runner/:Z", "--env-file", "/tmp/tmpu4bv0901/artifacts/3cff6702-dab0-47ce-9879-748d950e1442/env.list", "--quiet", "--name", "ansible_runner_3cff6702-dab0-47ce-9879-748d950e1442", "quay.io/ansible/ansible-runner:devel", "ansible", "-i", "/runner/inventory/hosts", "-m", "pause", "-a", "seconds=180", "localhost" ], ...以下略... 2023年のAnsibleとわたし 2023年、オペレーションの自動化を提供するエコシステムの一部としてAnsibleを利用しており、かつRed Hat Ansible automation controllerやAWXのような本格的な自動化フレームワークを必要としないCI/CDなどのシステムは、徐々にこのSDKを利用したものに移行しはじめるのではないかと予想しています。 2022年のFestやContributor Meetupで紹介されて、2023年に大きく飛躍しそうなプロジェクトは他にもありますが、このような新しいプロジェクトには、我々のようなコントリビューターが開発に参加するチャンスが多くあります。Ansible SDKをみなさんのエコシステムを支える自動化基盤技術の1つとして検討してみてください。 それでは、みなさんメリークリスマス & ハッピーオートメーション! :)
はじめに 今年最後のアドベントカレンダーを担当します、コンサルタントの金子です。クリスマスということでサンタクロースがプレゼントを持ってきたご家庭もあるかとお思いますが、セキュリティは万全でしょうか。OpenShift の Identity Provider に htpasswd をお使いの方もいらっしゃるかもしれませんが、OpenShift をよりセキュアにして安心安全な年末年始を過ごしましょう。 目次 はじめに 目次 Identity Provider 環境 Red Hat Singl Sign-on (KeyCloak) の設定 Operator のインストール KeyCloak インスタンスのデプロイ KeyCloak の設定 Realm の作成 Realm の設定 WebAuthn Passwordless Policy の設定 Required Actions の設定 Flows の設定 Bindings の設定 Client の作成と設定 ユーザーの追加 Identity Provider の設定 設定準備 OpenShift OAuth の設定  ログインの検証 終わりに Identity Provider OpenShift 4.x では構築後にデフォルトでは、 kubeadmin ユーザーが利用できます。クラスター管理者権限 (cluster-admin) を持つこのユーザーだけでも普段の検証は行なえますが、ユーザー名がすべての OpenShift クラスターで固定であることや、パスワードが変更できないことから Identity Provider 設定後にクラスター管理者権限を持つユーザーを登録した時点で削除することが推奨されています。 access.redhat.com kubeadmin はさておき、OpenShift では様々な Identity Provider が利用できます。どちらの Identity Provider をお使いでしょうか。LDAP を利用したり、Azure AD などと OpenIDConnect で接続されている方もいるかと思います。 access.redhat.com 今回は生体認証を利用し OpenShift へログインすることを実現するために、Red Hat Single Sign-on (RHSSO) を利用します。RHSSO は OpenShift の Identity Provider として利用でき、また Operator を利用してインストールことができます。 今年の7月ごろに 7.6 が GA になり、WebAuthn が利用できるようになりました。これにより、FIDO2規格に対応したOS/ブラウザ(スマートフォーン含む)で、生体認証が実現できます。 今回はこの記事で紹介されている機能を利用しつつ OpenShift にログインできるようにしようと思います。 rheb.hatenablog.com 環境 今回は以下の環境で検証を行います。 作業端末: Macbook Pro (Montery) OpenShift バージョン:4.11 RHSSO バージョン:7.6 Red Hat Singl Sign-on (KeyCloak) の設定 Operator のインストール OperatorHub から RHSSO をインストールします。インストール方法は GUI か CLI どちらでも構いません。今回は見やすいように GUI で導入しました。 OperatorHub で RHSSO を検索 今回は rhsso プロジェクトに Operator を導入します。channel は stable を利用します。Update は自動を選択します。 RHSSO Operator インストールオプション Install ボタンをクリックしたあとは、インストールが完了するまで待ちましょう。 KeyCloak インスタンスのデプロイ OpenShift Web Console の Operators - Installed operators を開くと、Red Hat Single Sign-on がインストールされていることが確認できますので、該当の Operator をクリックします。 RHSSO API の一覧から Keycloak を選択し、Yaml 編集画面を開きます。 KeyCloak の Custom Resource を利用することで冗長性の確保や外部DBを利用した事もできますが、目的は生体認証のため、冗長性などは無視して進めます。設定内容は次のとおりです。 デプロイ完了後、設定通りの内容の場合、 rhsso プロジェクト配下に credential-example-keycloak という名前の Secret が作成されていることが確認できますので、KeyCloak の Admin のパスワードを確認します。 KeyCloak の設定 Administration Console にログインします。先程確認した Admin のパスワードを利用してコンソールにログインします。 Realm の作成 サンプルのため、Realm の名前は test としてます。 Realm の設定 WebAuthn Passwordless Policy の設定 Realm 作成後、Authentication の設定を行います。[Configure] - [Authentication] を開きます。 メニューバーから [WebAuthn Passwordless Policy] を開き、 User Verification Requirement を required に設定し Save し、 [Required Actions] に移動します。 Required Actions の設定 [Required Actions] にて、 Register を押して、 Webauthn Register Passwordless を追加します。その後、Webauthn Register Passwordless の Default Action を有効にします。これにより、新規ユーザーが初回ログイン時に Webauthn の登録が求められるようになります。 Flows の設定 [Flows] タブを開くと、 Browser の Flow が開いているかと思いますので、右にある Copy を押して、 Browser をベースにした新規の Authentication Flow を作成します。フロー名は Webauthen とします。 Flow を修正していきます。今回の認証フローは、ユーザー名入力後、ユーザー認証として、パスワードか指紋認証によりログインできるようにします。まずはユーザー名とパスワード認証のフォームを削除し、ユーザー名のフォームに差し替えます。 設定の細かい部分は以下の製品ドキュメントを参照していただければと思います。 access.redhat.com 設定した内容は次のとおりです。 Username のフォームを追加(もともとあったUsername、Passwordのフォームは削除) パスワード認証か Passwordless Authenticator かを選択するフローを追加 上記フローに Passwordless の Execution と Password フォームのフローを追加 フローの設定はここまでです。 Bindings の設定 [Bindings] タブを開き、設定した Flow の [webauthn] を Browser の認証フローで利用するよう設定します。 Browser Flow のプルダウンから Webauthen を選択し、 Save ボタンをクリックしてください。 ここまでで、Webauthn に関する設定は完了です。 Client の作成と設定 メニューから Clients を選択し、 Create ボタンを押してください。Client 名に idp-4-ocp を指定し、 Client Protocol は openid-connect が選択されていることを確認して Save をクリックしてください。 client idp-4-ocp が作成されると設定画面が開きます。 Setting の Access Type を confidential に、 Validation URL に https://oauth-openshift.apps.<cluster_name>.<domain>/oauth2callback/keycloak を設定します cluster_name>. は環境により読み替えてください。 keycloak は OpenShift 側で登録する Identity Provider の名称です。要件に合わせて変更しても構いません。設定後 save します。 次に、 Credentials タブを開き、Secret を記録します。別途 Identity Provider の設定時に利用します。 ユーザーの追加 OpenShift にログインするユーザーを追加します。 Test Realm の [Manage] の [Users] をクリックします。 Add user ボタンが右側にあるので、クリックしてユーザーを追加します。サンプルのためユーザー名を sample として登録します。 ユーザー登録後、登録したユーザーの Credentails を開くとパスワードが設定できますので、パスワードを設定してログインができるようにします。 Identity Provider の設定 そろそろ設定も大詰めです。KeyCloak インスタンスを OpenShift の Identity Provider として利用できるように設定します。まずは、OpenShift が KeyCloak へアクセスするときの Secret を設定します。 設定準備 Secret 作成では、先程記録した idp-4-ocp の Credential を指定します。${Credential} を読み替えてください。 $ oc -n openshift-config create secret generic keycloak-client-secret --from-literal=clientSecret=${Credential} RHSSO が OpenShift の Route にデフォルトで設定される証明書を信頼済みとするように、CA 証明書を取得し、ConfigMap として登録します。OpenShift の証明書が正規のベンダーにより購入済みのものの場合、以下のCA証明書の取得、ConfigMap としての登録、Identity Provider 登録時の ca フィールドの指定は不要となります。 CA 証明書の取得 $ oc -n openshift-ingress-operator get secret router-ca -o jsonpath="{ .data.tls.crt }" | base64 -d -i > ca.crt ConfigMap として登録 $ oc -n openshift-config create cm keycloak-ca --from-file=ca.crt OpenShift OAuth の設定  OAuth Custom Resource から、Identity Provider を設定します。以下のコマンドを実行します。 issuer は KeyCloak インスタンスのアクセス情報を指定します。 Realm 名は test となっていますが環境に合わせて変更してください。 $ cat <<EOF | oc apply -f - apiVersion: config.openshift.io/v1 kind: OAuth metadata: name: cluster spec: identityProviders: - mappingMethod: claim name: keycloak openID: ca: name: keycloak-ca claims: email: - email name: - name preferredUsername: - preferred_username clientID: idp-4-ocp clientSecret: name: keycloak-client-secret issuer: https://keycloak-rhsso.apps.ocp4.example.com/auth/realms/test type: OpenID EOF ここまでで、identity Provider の設定は完了です。設定の反映には数分かかるので少しまちます。 ログインの検証 Identity Provider が正常に設定されると、OpenShift Web Console のログイン画面が次のようになります。 keycloak をクリックして登録したユーザーでログインします。 sample ユーザーで Sign In します。パスワードでサインインすると Security Key の登録として、生体認証登録が行えるようになります。 認証が完了すると、OpenShift のログインが完了します。ただここではパスワード認証でログインしているため、一旦ログアウトします。OpenShift からのログインだけでは完全にログインしたことにならない場合があるため、RHSSO からもログアウトしておきます。 今環境では、以下にアクセスすると、 sample ユーザーでログインしたことになっているため、ログアウトしました。 https://keycloak-rhsso.apps.ocp4.example.com/auth/realms/test/account/ 改めて、ログインしてみます。Web Console の keycloak をクリックします。先ほどと異なり、パスワード入力の下に Try Another Way というリンクが見えますのでクリックします。 音 すると、パスワードか Security Key 認証か選択する画面が表示されます。ここで、Security Key を選択します。 Google Chrome から Touch ID を利用した認証の確認がポップアップで表示されます。 スキャンを行うと、ログインが完了し、OpenShift Web Console が表示されることが確認できます。 終わりに Red Hat Single Sign-on を利用することで、OpenShift に生体認証を利用してログインできることが確認できました。これで安心して年を越すことができそうです。来年もセキュアな一年にしましょう。
こんにちは。Red Hatでソリューションアーキテクトをしている杉本 拓です。 前回書いたRed HatのService Registryの記事 ではService Registryの概要と基本的な使い方について解説しましたが、今月の赤帽エンジニアブログの記事では、QuarkusのアプリケーションからService RegistryをKafkaと組み合わせて使用する方法についてご紹介したいと思います。なお、本記事の内容は、 Using Quarkus applications with Kafka instances and Red Hat OpenShift Service Registry をベースとしています。 事前準備 Service Registryを利用したアプリケーションをビルドを進める前に、以下の事前準備をしておきましょう。 マネージドサービスでの環境の作成 Red Hat Hybrid Cloud Console で以下の準備をしておいてください。 Kafkaインスタンスの作成 Service Registryインスタンスの作成 Service Accountの作成 (KafkaとService Registryで共通) KafkaインスタンスとService Registryインスタンスでのアクセス権の設定 なお、これまでの赤帽ブログで上記の実施手順についてご紹介していますので、以下の記事もご参照ください。 rheb.hatenablog.com rheb.hatenablog.com Kafkaインスタンスのアクセス権の設定画面から Manage access をクリックし、作成したサービスアカウントを使用してConsumer/ProducerそれぞれのアプリケーションアクセスできるようにトピックとConsumer groupに対して、以下のようにアクセス権を設定しておきます。 なお、Service Registryでのサービスアカウントの設定では、使用するサービスアカウントに対してManager権限を付与しておいてください。 ローカルのアプリケーション開発環境 ローカルマシンでアプリケーションをビルドするための環境としては以下を用意しておいてください。 OpenJDK 11 以上 Apache Maven 3.8 以上 IDE (Visual Studio CodeやEclipseなど) ソースコードのインポート 事前準備ができたら、まずはRed Hatの Application ServicesのGithubリポジトリ からソースコードをインポートします。 git clone https://github.com/redhat-developer/app-services-guides app-services-guides なお、このApplication ServicesのGithubリポジトリには、Red HatのマネージドKafkaやService Registryを利用するためのガイドやサンプルコードがありますので、ぜひ参考にして頂ければと思います。 ここで使用するサンプルコードはcode-examplesフォルダにあるquarkus-service-registry-quickstartという名前のプロジェクトですので、このフォルダをVisual Studio Codeに取り込むと以下のように、KafkaのProducerとConsumerのアプリケーションフォルダが表示されます。 KafkaとService Registryにアクセスするための設定 では次に、このサンプルのQuarkusアプリケーションからKafkaとService Registryにアクセスするための設定をしていきましょう。Red Hatのマネージドサービスとして提供されているKafkaとService Registryにアクセスするには、事前準備のところで用意したKafkaインスタンスとService Registryインスタンスへの接続情報とService Account (KafkaとService Registryで共通)が必要となりますので、 Hybrid Cloud Console で値を確認してそれぞれの情報を取得しておきましょう。 <bootstrap_server> : 使用するKafkaインスタンスのBootstrap serverのホスト名 <service_registry_url> : 使用するService RegistryインスタンスのCore Registry APIのURLのFQDNまで <service_registry_core_path> : Service RegistryのCore Registry APIのURLへのパス (通常 "/apis/registry/v2") <oauth_token_endpoint_uri> : OAuth認証で使用されるSASL/OAUTHBEARERトークンのエンドポイントURL <client_id>: Service AccountのClient ID <client_secret>: Service AccountのClient Secret Producer/Consumerそれぞれのソースコードのフォルダ(src/main/resources)にあるapplication.propertiesファイルには、既に必要な接続情報が環境変数を使用してアプリケーションに渡せるようになっていますので、ターミナルから環境変数を設定しておきます(以下の接続情報はそれぞれ取得した値に変更してから環境変数を設定してください)。 $ export KAFKA_HOST=<bootstrap_server> $ export SERVICE_REGISTRY_URL=<service_registry_url> $ export SERVICE_REGISTRY_CORE_PATH=/apis/registry/v2 $ export RHOAS_SERVICE_ACCOUNT_OAUTH_TOKEN_URL=<oauth_token_endpoint_uri> $ export RHOAS_SERVICE_ACCOUNT_CLIENT_ID=<client_id> $ export RHOAS_SERVICE_ACCOUNT_CLIENT_SECRET=<client_secret> Kafkaトピックの作成 サンプルアプリケーションで使用するKafkaトピックをOpenShift Streams for Apache Kafkaで作成します。 Hybrid Cloud ConsoleのKafkaインスタンス にアクセスし、 quotes という名前のトピックを作成しましょう。Partitions数、Message retention、Replicaの値については、ここではデフォルトのままで構いません。 サンプルのQuarkusアプリケーションの実行 このサンプルアプリケーションでは、以下のような構成になっています。 Consumer (QuotesResourceクラスで実装) : quoteトピックからメッセージを取得し、その値をServer-Sent Eventsを使用してブラウザ画面に表示 Producer (QuotesProducerクラスで実装) : 5秒間隔でQuote (見積もり) の値をランダムで生成し、quoteトピックにパブリッシュ 接続情報の設定ができたら、以下のコマンドでConsumerアプリケーションを実行してみましょう(環境変数の設定をお忘れなく)。 $ cd ~/code-examples/quarkus-service-registry-quickstart/consumer $ mvn quarkus:dev Consumerアプリケーションが正常に起動したら、ターミナルは以下のような画面になっているかと思います。 次にブラウザから http://localhost:8080/quotes.html にアクセスすると Quotes の値を表示するようになっています。Consumerアプリケーション起動時にはProducerアプリケーションが起動していないため、値は何も表示されません。 では次に、Consumerアプリケーションを実行したままターミナルをもう一つ起動し、以下のコマンドでProducerアプリケーションを実行してみましょう(環境変数の設定をお忘れなく)。 $ cd ~/code-examples/quarkus-service-registry-quickstart/consumer $ mvn quarkus:dev Producerアプリケーションが正常に起動すると、ターミナルには以下のように表示されます。 Consumerアプリケーションに含まれている Webアプリケーション にブラウザでアクセスすると、Producerアプリケーションから5秒間隔でQuotesの値が生成された値が、以下のように表示されるのを確認できるかと思います。 Hybrid Cloud Console でService Registryインスタンスを見てみると、サンプルアプリケーションで利用されていたQuotesのスキーマがアーティファクトとして登録されていることが確認できます。 このサンプルアプリケーションでは、Avroフォーマットのスキーマのシリアライズとデシリアライズにおいて、ApicurioのService Registryの機能が利用されており、ProducerとConsumerのアプリケーションのapplication.propertiesでは、それぞれ io.apicurio.registry.serde.avro.AvroKafkaSerializer と io.apicurio.registry.serde.avro.AvroKafkaDeserializer が使用されています。このサンプルアプリケーションが実行されたタイミングでQuotesのAvroスキーマがService Registryに登録され、それを元にスキーマに対してルールを設定することができるようになり、スキーマの進化にも対応してくことができるようになります。
Cloud製品を担当しているソリューションアーキテクトの輿水です。 OpenShift Advent Calendar 2022 の12/22の記事です。 以前 All learning | Red Hat Developer というサイトにハンズオン(英語)があることをご紹介しましたが、その一部を日本語に翻訳し、手軽に試せる自己学習型OpenShiftハンズオン環境として提供し始めました。非公式ではありますが、使っているプラットフォームとコンテンツは公式と同じですので、同等の内容を学ぶことができます。 rheb.hatenablog.com ハンズオンを行うために、ご用意いただくのはブラウザ(Firefox,Chrome)のみです。指定のURLにアクセスしコースをlaunchすると、環境がデプロイされて、OpenShiftの演習とターミナルがセットされた環境が使用可能になります。コースをlaunchするためにアカウントを作る必要はありません。このハンズオンの長所と短所は以下の通りで、 Developer Sandbox for Red Hat OpenShift のように同じ環境を長期間継続して使えるものではなく、単発のものです。しかしながら、何度でも使えるので1回目はただただコピペで進む、2回目は自分でコマンド実行など繰り返し学習することができます。 長所 ブラウザ(Firefox,Chrome)があれば試せる アカウント作成不要 コマンドはコピー&ペースト可能 admin権限あり 何度でも実施可能 短所 都度デプロイするので、環境が準備されるまで多少待つ必要がある(10〜30分程度) 環境は一定時間が経過すると自動的に削除される 削除された後、再度デプロイしても、それまでに行った操作は保存されていない(新しい環境になる) 学習コースの内容は、まだほとんどOpenShiftを触ったことがない初学者向けで、CLIやGUIを利用してOpenShiftの基本的な操作を手順通りに実行してゆくものです。 それでは、現在用意されているコース内容を簡単に説明します。各コースへのリンクは下記のgithubにあります。 OpenShiftハンズオンへようこそ github.com 基本的な操作とアプリケーションのデプロイ方法 OpenShiftクラスタにOpenShift Command Line Tool(ocコマンド)とWebコンソールでログインするところから始め、CLIやGUIでのプロジェクトの作成、イメージやソースを利用してアプリケーションをデプロイする方法を学びます。デプロイされたアプリケーションの外部公開を行って実際にアプリケーションにアクセスします。また、ひとつのプロジェクトを複数のユーザーで共同利用する方法も実施します。 Login to an OpenShift cluster (Japanese) 概要:OpenShiftクラスターにログインしてユーザーの操作を行います OpenShiftクラスタのWebコンソールURLを調べてアクセス OpenShift Command Line Tool(ocコマンド)の利用 OpenShiftの新規ユーザー作成と権限付与 ユーザーの切替 Getting Started with OpenShift for Developers (Japanese) 概要:OpenShift環境で既存のイメージを利用してアプリケーションをデプロイします ocコマンドでOpenShiftクラスタにアクセス WebコンソールでOpenShiftクラスタにアクセス 既存のイメージを利用してアプリケーションをデプロイ デプロイしたアプリケーションをスケール OpenShift Routeを利用して外部に公開されたURLにアクセス Deploying Applications From Source (Japanese) 概要:OpenShift環境でソースをビルドしてアプリケーションをデプロイします ocコマンドを利用してプロジェクトを作成、Webコンソールで確認 Webコンソールを利用してソースからblogアプリをビルド&デプロイ Webコンソールでアプリのログを確認 外部に公開されたURLにアクセスしアプリの確認 アプリの削除 ocコマンドでアプリを再度デプロイ ビルドトリガーの設定 GitOps Gitリポジトリに置かれたコードをSingle Source of Truthとみなし、コードとインフラを常に同じ状態に保つ運用のベストプラクティスをGitOpsと呼びます。Cloud NativeなGitOps継続的デリバリーツールArgo CDを利用して、OpenShiftでのどのように動作するかを体験します。また、Kubernetesのマニフェスト管理ツールであるKustomizeやKubernetesアプリケーションのパッケージマネージャーであるHelmと統合した場合の動作を体験できます。 Getting Started with ArgoCD and OpenShift GitOps Operator (Japanese) 概要:OpenShiftのGitOpsを体験します OpenShiftのGitOpsについて OpenShift GitOps Operatorのインストール Argo CDインスタンスにCLIとGUIを用いて接続する サンプルアプリケーションをデプロイ Gitで変更を行った内容がアプリに反映されることを確認 Working with Kustomize (Japanese)/Working with Helm (Japanese) 概要:Argo CDとKustomize / Helmの統合 Kustomize / Helmについて Kustomizedアプリケーションをデプロイする Helmチャートをデプロイする Pipeline OpenShift Pipelines はTektonを使用してパイプラインを構築するための、Cloud Nativeな継続的CI/CDソリューションです。PVを持つbackendとfrontendからなる投票アプリケーションのデプロイを通して、OpenShiftでのどのように動作するかを体験します。 Getting Started with OpenShift Pipelines (Japanese) 概要:OpenShift Pipelinesを使用してアプリケーションのデプロイを自動化する方法 OpenShift Pipelines Operatorをインストール サンプルTaskを作成 Taskリソース定義 Tekton Pipelineを作成 frontend と backend からなる投票アプリケーションをデプロイ Serverless Getting Started with OpenShift Serverless (Japanese) 概要:Cloud Nativeな開発モデルを提供するOpenShift Serverlessの基本的な使用方法 OpenShift Serverlessのserviceをデプロイ 複数のrevisionsをデプロイ Serverless serviceの基本コンポーネントについて Serverlessがscale-to-zeroを可能にする方法 canary および blue-green デプロイメント knative client の利用 Playground Playgrounds OpenShift 4.11 (Japanese) 概要:決まった演習項目はなく、自由に試すための環境 現時点では、コース内容は初学者向けで「ざっくり体験する」レベルのものが多いですが、今後、様々なコースを拡充してゆく予定です。また、定期的に「もくもく会」と称して、あらかじめデプロイした環境をpoolしておき、待ち時間なしにコースが始められ、かつQ&A可能な会を行っております。connpassでお知らせしておりますので、お時間が合えばご参加ください(※12/22時点では次の開催のご案内はありません) openshift.connpass.com Red Hat製品を無料で試してみよう この自己学習型OpenShiftハンズオン環境意外にも、Red Hat製品を無料でトライできる方法があり、次のblogにまとまってますので、ぜひ、こちらも参照ください。 rheb.hatenablog.com お知らせ 2023/01/27に「OpenShift.Run 2023 冬の陣」を開催します。 OpenShift.Runは、OpenShiftやKubernetes、クラウドネイティブテクノロジーに関わる知見や運用ノウハウなどを共有し合う話です。と同時に、お祭り感覚で飲みながらラフに楽しんで頂く場です。connpassで参加募集始まりました。ぜひご参加ください。登壇者も募集してます。 openshift.connpass.com
Red Hatの森若です。 今回はsystemd-journald と、systemd-journaldがログ情報を保存するjournalのローテートについての話です。 結論 systemd-journald とは? journalファイル群 journalのローテートと削除 1000人のユーザがいるシステム SplitMode設定 結論(再) まとめ 結論 ユーザが多い環境では /etc/systemd/journald.conf で SplitMode=noneに変更しよう。 systemd-journald とは? systemd-journaldは、systemdと統合されたログ収集・保存サービスです。 従来から syslogで使われてきた /dev/log や systemd unitの標準出力・標準エラー出力など様々な入力をうけつけ、 専用の journal とよばれるバイナリログへ保存します。 従来のsyslogによるログと比較して、journalではデータが構造化されていてたとえばログ優先度や 「x月y日10:10から10:30まで」のような検索ができるほか、 マイクロ秒単位のタイムスタンプ群や関連するsystemd unitなど追加のメタデータを含んでいてアプリケーションからの拡張も可能で便利に利用できます。 RHEL 7,8,9のデフォルトでは、journalはtmpfs上に作成され、再起動により消えます。 rsyslogのimjournal pluginがjournalを読み、/var/log/messagesなどに保存します。 つまりjournalは主にrsyslogへの中継役として利用されています。 journalは中継役として使うだけではなく専用のコマンド journalctl を利用して検索・閲覧できます。 このときさきほどのメタデータによる検索が役に立ちます。 systemctl status chronyd.service のようなコマンドでサービスに関連した最近のログが表示されるのも journalを活用したものです。 journalはtmpfs上で利用するほかに、通常のファイルシステム上へ保存して利用することもできます。 利用開始は非常に簡単で、root権限で /var/log/journal ディレクトリを作成し、systemd-journaldを再起動するだけです。 # mkdir /var/log/journal # systemctl restart systemd-journald journalは便利ですが、長期間・大量のログに対応するログ管理ソリューションではありません。 たとえばjournalctlによる検索・表示はjournal全体を読み込みます。数GB〜10GB程度におさまる範囲で利用するのがよいでしょう。 journalファイル群 journal は、複数のファイルからなっています。通常のシステム管理で直接操作することはありませんが、 /run/log/journal または /var/log/journal ディレクトリの中身を見てみます。 journalを構成する各ファイルを「journalファイル」と呼んでjournalと区別します。 以下の例は私がデスクトップ用途に常用している環境のものです。ユーザ数や設定により細かな違いはありますが、見た目はおおむねこのようになります。 $ tree /var/log/journal/ /var/log/journal/ └── 0e5c275b71674a68a37d977e8902c7c7 (中略) ├── system@9946b0564b1841efba5ba6f72db3d490-00000000000f8e55-0005f02c9e33e417.journal ├── system@9946b0564b1841efba5ba6f72db3d490-00000000000fe0e8-0005f040c28107ac.journal ├── system.journal (中略) ├── user-1000@e5f646cd6f8249748eb5d5759a730a90-00000000000f8e69-0005f02cbe48cdc9.journal ├── user-1000@e5f646cd6f8249748eb5d5759a730a90-00000000000fe1b3-0005f040c284aad9.journal └── user-1000.journal ファイル名が長くて面倒そうですが、前述のとおりこれらのファイル群を直接操作することは基本的にありません。 以下簡単にまとめます。 /run/log/journal または /var/log/journal の下のディレクトリは、machine-id です。複数マシンのjournalを集約しても競合しないように、システム毎に一意なmachine-idでディレクトリが作成されています。 system.journal と user-<UID>.journal が、最新の journal ファイルです。新しいログはこのファイルに保存されます。journalファイルは内容がログ1行相当でも最低8MiBで作成され、必要に応じて8MiB単位で大きくなります。 命名規則から想像がつくように、多数のユーザがログインする環境では user-<UID>.journal は各ユーザに対応します。 1度でもログインしたことがある全ユーザのjournalファイルが作成されます。ssh接続やコンソールからのログイン、GUIセッションなどのユーザの対話的なセッション内で発生したログはこちらに保存されます。 journalファイルのuidはrootでgidはsystemd-journalです。ただし該当ユーザに読み込みを許可するACLが設定されるため、ユーザは特権やsystemd-journalグループへの参加なしで読み込めます。つまり journalctl --user コマンドで自分のセッションのログを閲覧できます。 ログインをともなわない、単にUIDが設定されるだけのサービスのログはsystem.journalに保存されます。 system@9946b0564b1841efba5ba6f72db3d490-00000000000f8e55-0005f02c9e33e417.journal のような長いファイル名のファイルは、ローテートされた過去のjournalです。 興味がある方のために紹介すると (もとのファイル名のbase部分)@(namespaceで決まる長い数字)-(journalのカーソル位置)-(時刻).journal のような規則で命名されています。 journalのローテートと削除 systemd-journaldはログをjournalに保存するタイミングで、時間・サイズなどの条件を判定してjournalを自動的にローテートします。デフォルトでは記録をはじめて30日経過する、全体で利用できる容量(デフォルトは 4GiBまたはパーティションの10%のどちらか小さなサイズ )の1/8のサイズになる等の契機でローテートします。 systemd-journaldによるローテートはlogrotateと異なり定期的に実行するものではなく、ログ出力タイミングで行われる点に違和感があるかもしれません。system.journal はシステムが単純に動作しているだけでもログが出力されますが、user-<UID>.journal は該当するユーザのログインがなければ全く出力されませんから、ローテートもずっと行われません。 一部journalファイルが古すぎて気になるような場合は、 journalctl --rotate コマンドで強制的にローテートを発生させることができます。 ローテートされた過去のjournalは、やはりログ出力のタイミングで設定に従い削除されます。最新のjournalファイルが削除されることはありません。 1000人のユーザがいるシステム さて、1000人のユーザが散発的にログインして利用するシステムを考えてみます。共用されるHPCクラスタや大学の演習環境のようなイメージです。 user-<UID>.journal が1000個(!)できます。1つ最低8MiBですから、最低で8GiB弱になります。 8GiB弱のサイズは、systemd-journaldがデフォルトで設定する「4GiBまたはパーティションの10%のどちらか小さなサイズ」を越えています。 最新のjournalファイルは削除されませんが、ローテートにより作成された過去のjournalは、サイズ上限に影響されるので作成後すぐに削除されます。 この状況でsystem.journalにローテートが発生すると、journalからサービスなどの過去のログがほとんど消えてしまいます。その後徐々にログが蓄積されていき、次回のローテートでまた消えるという動作の繰り返しになります。これは用途によらずまずい動作です。 SplitMode設定 このようなケースでは、各ユーザセッションのログも1つのjournalファイルにまとめて記録する方が期待に近い動作になります。 /etc/systemd/journald.conf で以下の設定を行います。デフォルトでは "uid" となっていますが、これを "none" とすると全体が systemd.journalに記録されます。 SplitMode=none ファイルをユーザ毎に分割しないことで、ローテーション時に参照できる過去のログが極端に少なくなる現象を避けられます。 1つのファイルにまとめた結果として、各ユーザがデフォルトでは自分のセッションのログを読めません。システム全体のログを読むのと同じ権限が必要になります。 結論(再) ユーザが多い環境では /etc/systemd/journald.conf で SplitMode=noneに変更しよう。 まとめ journal 利用上のポイント journalは複数のファイルに分けられた形で存在する journalの操作はjournalctlコマンドと systemd-journald の設定でおこなう logrotateではなく systemd-journald自身がローテートをおこなう 古いjournalはsystemd-journaldがローテートのタイミングで削除する 削除条件は複数あるがサイズ上限の典型的な値は4GiB 最新のjournalは条件によらず削除されない ユーザが多いときのjournalの注意点 最新のjournalファイルは内容によらず1つ 8MiB以上 SplitMode=uid で 容量4GiBのデフォルトの上限設定では500ユーザで確実にサイズの上限を越える サイズ上限を越えた場合実用上の問題がある動作になる サイズ上限を越えないよう SplitMode=none の設定を行う
こんにちは、ソリューションアーキテクトの蒸野(ムシノ)です。 今回は、Red Hat Developerのブログ Apache Camel boosts Quarkus performance | Red Hat Developer の翻訳記事を紹介させて頂きたいと思います。 一部、記事の内容を分かりやすくするため、オリジナルにない補足事項を追加しています。ご承知おきいただけらと思います。 Camel Quarkusは、 Apache Camelコミュニティのサブプロジェクトであり、Quarkus上でCamelを実行できるようにするものです。Apache Camelは、 こちら でも説明させていただいたように、あらゆるシステム統合を解決することを目的としたオープンソースコミュニティプロジェクトです。Quarkusは、OpenJDK、HotSpotとGraalVMで動作し、早い起動時間と低いメモリ使用率が特徴のJavaフレームワークです。 この記事では、 Camel が長い時間とともにどのように変化してきたか、そしてなぜ Quarkus を採用するのかについて説明します。 また、クイックガイドとして、Camel Quarkus プロジェクトを作成し、パフォーマンスの大きな利点を体験していただけるように簡単なサンプルを示したいと思います。 Apache Camel が特別な理由 Apache Camel はコンテナやKubernetesが登場するよりも先んじて存在していました。他のIntegration製品に対して、 Apache Camel の大きな利点は、非常に軽量に保たれている点です。誤解を恐れずに言うと、Camel はJavaプロジェクトに組み込む小さなライブラリです。 その軽量さ故に、新しいトレンドに素早く適応し、さまざまなランタイム(Webコンテナ、Java EEサーバー、OSGi、Spring Bootなど)に適合することができました。Apache Camel は進化と改良を続け、長年にわたって利用され、利用実績が豊富である機能を提供するという大きな長所があります。 他のIntegration製品が誕生し、初期の成功を収め停滞している間、 Apache Camel コミュニティは、風の変化をよく読み、必要に応じて新しい船体や帆を進化させながら航海し続けていると言えます。 コンテナにおけるJavaのメモリ使用量 Kubernetes とコンテナが登場する以前は、Javaプロセス上にサービスを束ねることが理にかなっていました。多くのIntegrationサーバ(エンタープライズ・サービス・バス)は、インフラとメモリ消費を節約するために、多くのIntegrationプロセスを一つに集約していました。 コンテナの出現により、Integrationのアプローチは大規模なIntegrationサーバから独立した実行アプリケーションに移行し始め、マイクロサービスとして知られるようになりました。しかし開発者は、この新しいアプローチが非常にメモリを消費することにすぐに気づきました。 新しい言語などはメモリフットプリントを最小化するのに役立つように見えましたが、Javaが長い時間をかけて成長してきた機能やライブラリの代替をもたらすものではありませんでした。しかし、Javaの利用を継続するとしても、メモリ使用量に問題があるのなら何か新たな手を打つの必要がありました。 Welcome to Camel Quarkus Camel Quarkus は、Camel コアライブラリとその豊富なコネクターコンポーネントを Quarkus にもたらします。 Quarkus は、クラウドベースのアプリケーションにおけるJavaの使用を促進する一方で、 非Kubernetes ユーザーがベアメタル上で最大のパフォーマンスでアプリケーションを実行することを可能にします。 Quarkus のミッションは、最小限のメモリで超高速にJavaを実行し、コンテナベースのプラットフォームでの実行を最適化し、ランニングコストを削減することです。以下のサブセクションでは、これらの目標について説明します。 パフォーマンスの向上 Quarkus は、 Apache Camel のパフォーマンスを飛躍的に向上させ、 Camel を実行する他のJavaランタイムを凌駕しています。 Camel Quarkus の改善点として、以下が挙げられます。 起動時間が数秒以下 低メモリーフットプリント ウォームアップの必要なし サーバーレス特性(Camel-K) 下記は、基本的なRESTful API呼び出しとRESTful API呼び出しおよびデータベースアクセスの2つの操作について、さまざまなデプロイメントの起動時間を比較したものです。ネイティブコンパイルによる Quarkus は、実質的に瞬時に終了します。通常のJavaジャストインタイム(JIT)コンパイラーを使用した Quarkus は、従来のJavaよりもはるかに高速です。ネイティブモードの Quarkus は、RESTサービスの起動に数百分の1秒しかかからないなど、速さが際立っています。 下記は、同じ操作のメモリフットプリントを示しています。Quarkusをネイティブモードで使用した場合、消費量は最小限なレベルまで低下します。 ライブコーディング 効率的な開発の重要な側面として、コーディングとテスト中に快適さと生産性を感じることであり、これは「developer joy」としても知られています。 Quarkus で Camel との統合を行う主な利点の1つはライブコーディングモードです。このモードでは、トライアンドエラーを繰り返し、コンパイル、起動、再試行のサイクルを早めることができます。ライブコーディングモードでは、コードを変更すると、それが即座に検出されて適用されるため、失敗してもすぐに再試行することができます。例えば、ライブコードモードでの更新は、 Apache Camel を使い始めたばかりでまだ理解が深まっていないときに非常に役に立ち、事実上、学習プロセスを加速させます。 下記の図は、 Apache Camel ルートをコーディングおよび更新する際に、ライブコーディン グモードがどのように機能するかを示しています。 Quarkus のライブコーディングモードでは、コードを更新するたびに、新しいコードの再実行がトリガーされます。 Quarkus コミュニティは、コード作成を簡素化し、開発者の生産性を高めることにも役立っています。たとえば、Integrationサービスを実装する際に、DevやProd環境ごとに異なる設定を提供する必要がある場合、 Camel Quarkus では、1つの設定ファイルですべての環境に対応するプロパティを定義することができます。 例えば次のように Camel ルートでバックエンドサービスと統合する必要があるとします。次の XML 定義で Camel の定義行っています。 この XML は、括弧の間に定義されたパラメータによってターゲットホストを指定しています。 <to uri="http:{{api.backend1.host}}/camel/subscriber/details"/> 次に、エンドポイントを設定するために、設定ファイル内でプロパティを指定します。最初のプロパティはデフォルト(本番環境)の設定値を定義し、2番目のプロパティはライブコーディングモードを有効にしたときに有効になるdev環境用のプロパティを設定しています。 api.backend1.host = end1:8080 %dev.api.backend1.host = localhost:9000 Camel Quarkus on Camel 3 Camel Quarkus は、 Apache Camel の進化版である Camel 3 で生まれました。この時点で、 Camel Quarkus は Camel のプロジェクトファミリーとなりました。 Camel 3: コアフレームワークと統合ツール Camel Quarkus:QuarkusのためのCamel拡張機能 Camel K: Kubernetesのための軽量なサーバーレス統合プラットフォーム Camel のバージョン2からバージョン3になった主な理由の1つは、 Camel Quarkus と Camel K に誕生させることでした。これらは、皆さんも推測されているように、コンテナ上で Camel を実行することを示しています。 Camel-K は Kubernetes環境 でのみ利用可能ですが、Camel Quarkusはコンテナでもスタンドアロンでも実行可能です。 Camel 3 では、 Quarkus 上で動作させるために多くの内部改良が施されています。特に、Javaリフレクションの使用を排除するために多くの作業が行われ、 Camel はネイティブモードで実行できるようになりました。もう1つの大きな仕事は、Camelフレームワークのコアをモジュール化することでした。これにより、メモリのフットプリントを大幅に削減し、起動時間や実行速度を高速化することができました。 Camel Quarkus のサンプル実行 Camel Quarkus が何であるかを理解したところで、簡単なサンプルを実行してその利点を体験してみたいと思います。 ここでは、Camel Quarkusの最初の一歩を踏み出すために、簡単なサンプルで理解することを意図しています。 前提条件 このサンプルを再現するためには、以下の要件がシステムにインストールされていることを確認してください。 JDK 11+ (任意のディストリビューション) Maven 3.6.2以上 オプションで ネイティブコンパイル用GraalVM 22.3 ジェネレーターの設定 下記の記事を参考にスケルトンを作成します rheb.hatenablog.com ここではタイマーコンポーネントを使用して画面に簡単なメッセージをログとして出力するサンプルを作成します。 Quarkusのコードジェネレーターで、「camel」と入力しフィルタリングします。 コードジェネレーターインターフェースには、Quarkusで使用できるすべての Apache Camel 拡張機能が表示されます。 Java DSL と XML DSL を使用した 2 つの Camel ルートを作成します。 フィルタされたリストから、Camel Timer と Camel XML を選びます。選択済みのものがインターフェイス上に表示されます。 「Generate your application」 と書かれた赤いボタンをクリックし、プロジェクトを生成してダウンロードします。 Work on the Camel code ZIPファイルをダウンロードし、適切なフォルダでプロジェクトを解凍してください。 次に、 Camel Java DSLルート を含む以下のJavaクラス定義を「src/main/java/org/acme/TimerRoute.java」ファイルに追加してください。 package org.acme; import org.apache.camel.builder.RouteBuilder; public class TimerRoute extends RouteBuilder { @Override public void configure() throws Exception { from("timer:java?period=1000").id("route-java") .log("Hello World from Java DSL"); } } そしてターミナルに下記コマンドを入力して、開発モードのCamel Quarkusアプリケーションを起動します。 mvn clean quarkus:dev Quarkusが起動すると、次のようなメッセージが何度も繰り返し表示されるはずです。 INFO [route-java] (Camel (camel-1) thread #1 - timer://java) Hello World from Java DSL INFO [route-java] (Camel (camel-1) thread #1 - timer://java) Hello World from Java DSL INFO [route-java] (Camel (camel-1) thread #1 - timer://java) Hello World from Java DSL ・・・ コードの修正 Quarkus Camel アプリケーションを開発モードで実行すると、ライブコーディングモードが有効になっているので、コード修正してみます。 XML DSL を使用して2つ目のCamelルートを追加することで、その動作を確認してみましょう。 次の XML 定義を「src/main/resources/routes.xml」に追加します。 <routes xmlns="http://camel.apache.org/schema/spring"> <route id="route-xml"> <from uri="timer:xml?period=1000"/> <log message="Hello World from XML DSL"/> </route> </routes> 「src/main/resources/application.properties」を編集して、Camel に XML ルート定義の場所を知らせる次のプロパティを追加します。 camel.main.routes-include-pattern = classpath:routes.xml 「保存」をクリックすると、 Quarkus が変更を即座に検出して自動的に再起動し、新しいCamel XML定義が追加されます。 ターミナルにJava DSLとXML DSLの両方のメッセージが表示されるはずです。 INFO [route-java] (Camel (camel-1) thread #1 - timer://java) Hello World from Java DSL INFO [rou.xml:5] (Camel (camel-1) thread #2 - timer://xml) Hello World from XML DSL INFO [route-java] (Camel (camel-1) thread #1 - timer://java) Hello World from Java DSL INFO [rou.xml:5] (Camel (camel-1) thread #2 - timer://xml) Hello World from XML DSL ・・・ パフォーマンスの測定 ログの詳細を見ると、Apache CamelとQuarkusがいかに早く再起動したかが分かります。 ... Apache Camel 3.18.3 (camel-1) started in 71ms ... code-with-quarkus 1.0.0-SNAPSHOT on JVM (powered by Quarkus 2.13.5.Final-redhat-00003) started in 1.632s. しかし、 Quarkus の本来のパフォーマンスは、プロジェクトをネイティブモードでビルドしたときに発揮されます。 次のコマンドを実行します。 mvn clean package -Pnative ビルドプロセスは数分で完了します。完了したら、ネイティブアプリケーションで実行します。 ./target/*-runner アプリケーションの出力を注意深く観察すると、起動時に消費される時間がわかります。 次のログは、ネイティブモードで動作するCamel Quarkusの超高速の起動時間を示しています。 ... Apache Camel 3.18.3 (camel-1) started in 2ms ... code-with-quarkus 1.0.0-SNAPSHOT native (powered by Quarkus 2.13.5.Final-redhat-00003) started in 0.510s. メモリ使用量についてはどうでしょうか。以下のコマンドを実行し、物理RAM上のプロセスへのメモリ割り当てを反映する常駐セットサイズ(RSS)を検査します。 ps -o rss,command このコマンドの出力は、次のように表示されるはずです。 30408 ./target/code-with-quarkus-1.0.0-SNAPSHOT-runner RSS使用量が30MBほどであることを示しています。 最後に 如何でしたでしょうか? Camel Quarkusは、Apache Camel に新たな次元をもたらす重要な技術的な進化といえます。Quarkusは、非常に高速で反応性の高いシステム統合と、「パフォーマンスの向上」、「developer joy」、そして Quarkus が体現するコンテナファーストのスタートラインとなります。 ご意見をお待ちしております。 参照リンク: https://access.redhat.com/documentation/ja-jp/red_hat_integration/2022.q4/html-single/camel_extensions_for_quarkus_reference/index https://access.redhat.com/documentation/ja-jp/red_hat_integration/2022.q4/html/getting_started_with_camel_extensions_for_quarkus/index https://access.redhat.com/documentation/ja-jp/red_hat_integration/2022.q4/html/developing_applications_with_camel_extensions_for_quarkus/index
 はじめに OpenShift Advent Calendar 2022 20日目 の投稿です。 みなさん、こんにちは。レッドハットでOpenShiftのソリューションアーキテクトをしている小野です。主にエッジコンピューティングを担当しています。 以前の記事で、エッジデバイス向けの軽量版OpenShiftであるMicroShiftというオープンソースをご紹介しました。 rheb.hatenablog.com Kubernetesでエッジデバイスのアプリケーションのライフサイクルを管理する場合、エッジデバイスが数台の内は直接kubectlで事足りますが、本番展開時に数万以上のエッジデバイスを対象にする必要が出てくると、効率化を考える必要が出てきますよね。そんな時は、Advanced Cluster Management for Kubernetes(以降、ACMと略)を使うと便利です。このACMが、正に「エッジへもクラウドネイティブなアプローチを拡張する」ために大事な役割を担います。 本稿では、エッジデバイスへインストールしたMicroShiftをAWS上に展開したACMから管理する簡単な手順をご紹介します。 なお、「そもそもACMとは?」という方は、以下の記事をご参照いただけますと幸いです。 rheb.hatenablog.com それでは、始めていきましょう〜! ACMをMicroShiftで使う場合の構成 まずはACMとMicroShiftとでどの様な構成になるのか見てみたいと思います。 この絵を見てみると、ACMがエッジのHubとなって、HelmやGit、ArgoCDなどの外部システムと連携したオペレーションをエッジへも適用する役割に見えます。 OpenShiftでACMを利用する場合は、ACMがAPIドリブンのOpenShiftクラスタのプロビジョニング機能(OpenShift Hive)と連携し、OpenShiftクラスタのインストールをACMから行うことも可能です。一方、MicroShiftでACMを利用する場合は、(少なくとも現時点は)エッジデバイスへプロビジョニング済みのMicroShiftをACMへインポートして利用します。 一番シンプルな使い方は、クラウドやオンプレミスの環境でセットアップしたHubクラスタ側でアプリケーションの配置ポリシ(Placement)を定義し、Hubクラスタ側で管理されるクラスタラベルに応じて、MicroShiftへのアプリケーションの配置をコントロールする使い方です。 構築に当たっては、そもそもMicroShiftやACMがインストールされた状態で、 ①まずHubクラスタを作る ②次にMicroShiftをHubクラスタへ登録するための認証情報を取得する ③そして、MicroShiftへKlusterletとAddon Agentをデプロイし、取得した認証情報を使ってHubクラスタに登録する、 の3ステップで完了です。以下、構築を進めていきましょう。 事前準備 エッジデバイスへMicroShiftをインストール まずは肝心のMicroShiftをエッジデバイスにインストールする方法を記載しておきます。MicroShiftのインストールは以下の公式ドキュメントを参照してください。 RHELへインストールする場合は、レッドハッとのパッケージリポジトリからdnfでインストールできます。 microshift.io # CRI-Oのインストール $ command -v subscription-manager &> /dev/null \ && subscription-manager repos --enable rhocp-4.8-for-rhel-8-x86_64-rpms $ sudo dnf install -y cri-o cri-tools $ sudo systemctl enable crio --now # MicroShiftのインストール $ sudo dnf copr enable -y @redhat-et/microshift $ sudo dnf install -y microshift ちなみに、UbuntuなどのDebian系へインストールしたい場合は、以下の手順でインストールすることができます。 いずれもCRI-Oを入れて、MicroShiftバイナリを配置し、起動する、という流れです。 参考サイト. microshift-on-jetson.md · GitHub # CRI-Oのインストール $ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list $ echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list $ curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key add - $ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add - $ apt-get update $ apt-get install cri-o cri-o-runc # MicroShiftのインストール $ export ARCH=arm64 $ export VERSION=$(curl -s https://api.github.com/repos/redhat-et/microshift/releases | grep tag_name | head -n 1 | cut -d '"' -f 4) $ curl -LO https://github.com/redhat-et/microshift/releases/download/$VERSION/microshift-linux-${ARCH} $ mv microshift-linux-${ARCH} /usr/local/bin/microshift; chmod 755 /usr/local/bin/microshift ## systemdで管理するようにする $ cat << EOF > /usr/lib/systemd/system/microshift.service [Unit] Description=MicroShift After=crio.service [Service] WorkingDirectory=/usr/local/bin/ ExecStart=/usr/local/bin/microshift run Restart=always User=root [Install] WantedBy=multi-user.target EOF $ systemctl enable crio --now $ systemctl enable microshift.service --now MicroShiftのバイナリをsystemdなりで起動すると、CRI-Oと連携してPodが起動してくる、という仕組みでインストールが走る感じですね。 最終的に以下のPodがRunningになれば正常にインストールできています。 $ oc get po -A NAMESPACE NAME READY STATUS kube-system console-deployment-57cdc94d5d-tsbzr 1/1 Running kube-system kube-flannel-ds-ch28c 1/1 Running kubevirt-hostpath-provisioner kubevirt-hostpath-provisioner-q75vd 1/1 Running openshift-dns dns-default-qjlfh 2/2 Running openshift-dns node-resolver-nq4jl 1/1 Running openshift-ingress router-default-6c96f6bc66-sv6wn 1/1 Running openshift-service-ca service-ca-7bffb6f6bf-r6z4n 1/1 Running ACMをインストール 次に、OpenShiftがインストールされた環境にて、Operatorを用いてACMをインストールしておきます。 ACMのインストール自体は超簡単で、OperatorHubから「Advanced Cluster Management」を検索してインストールボタンを押す、たったこれだけです!(使いたいバージョンがある場合はインストールボタンを押した後の画面で適宜選択してください) なお、本稿ではAWS上へOpenShift 4.11をインストールして構築しています。 ACMでMicroShiftを管理する 準備が整いましたので、ACMへMicroShiftを管理できる様にしてみます。 ①Hubクラスタのセットアップ インストール済みのOperatorのACMの画面を開き、「MultiClusterHub」インスタンスを作成します。ここでは、「インスタンスの作成」ボタンを押して、特に何も変更せず[作成]ボタンを押します。 すると、順次Podが起動し、OpenShiftのコンソール画面が更新されて、左メニューにクラスタ選択のメニューが追加されます。 ②MicroShiftをHubクラスタに登録するための認証情報の取得 HubクラスタへManagedクラスタを登録するのに必要な認証情報を発行します。 登録したいクラスタの名前でProject(Namespace)を作り、ACMのカスタムリソースであるManagedClusterリソースとKlusterletAddonConfigリソースを作成します。 $ export CLUSTER_NAME=device01 $ oc new-project ${CLUSTER_NAME} $ oc label namespace ${CLUSTER_NAME} cluster.open-cluster-management.io/managedCluster=${CLUSTER_NAME} # ManagedClusterリソースを作成 $ cat <<EOF | oc apply -f - apiVersion: cluster.open-cluster-management.io/v1 kind: ManagedCluster metadata: name: device01 spec: hubAcceptsClient: true EOF # KlusterletAddonConfigを作成 $ cat <<EOF | oc apply -f - apiVersion: agent.open-cluster-management.io/v1 kind: KlusterletAddonConfig metadata: name: device01 namespace: device01 spec: clusterName: device01 clusterNamespace: device01 applicationManager: enabled: true certPolicyController: enabled: false clusterLabels: cloud: auto-detect vendor: auto-detect iamPolicyController: enabled: false policyController: enabled: false searchCollector: enabled: true version: 2.5.0 EOF マニフェストをapplysすると、Hubクラスタに以下の2つのカスタムリソースが作成されます。 $ oc get klusterletaddonconfig device01 NAME AGE device01 29s $ oc get managedcluster device01 NAME HUB ACCEPTED MANAGED CLUSTER URLS JOINED AVAILABLE AGE device01 true また、MicroShift側でapplyする必要があるカスタムリソースとHubクラスタへ登録するための認証情報がSecretとして自動作成されますので、yamlファイルとして吐き出しておきます。 $ oc get secret ${CLUSTER_NAME}-import -n ${CLUSTER_NAME} -o jsonpath={.data.crds\\.yaml} | base64 --decode > klusterlet-crd.yaml $ oc get secret ${CLUSTER_NAME}-import -n ${CLUSTER_NAME} -o jsonpath={.data.import\\.yaml} | base64 --decode > import.yaml ③MicroShiftの環境をHubクラスタへ登録 ②で作成した klusterlet-crd.yaml と import.yaml をMicroShift上でoc applyし、KlusterletとAddon AgentをMicroShift環境へデプロイします。 なお、オープンソースのMicroShift上にデプロイするにはレッドハットカスタマーポータルのアカウントが必要です。購入したサブスクリプションを管理するアカウントと同じものを利用するか、Red Hat Developerプログラムや、30日間の試用版サブスクリプションを使うなどして、開発者用のレッドハットのコンテナレジストリ(registry.redhat.io)へログインできるように準備しておく必要があります。 詳細は以下のリンクをご参照ください。 access.redhat.com ②で出力したマニフェストをMicroShift側でapplyします。 $ oc apply -f klusterlet-crd.yaml $ oc apply -f import.yaml registry.redhat.ioへのImagePullSecretを指定します。 $ export RH_USERNAME=<レッドハットカスタマーポータルのアカウントのユーザ名> $ export RH_PASSWORD=<レッドハットカスタマーポータルのアカウントのパスワード> $ export EMAIL=<登録したメールアドレス> $ oc project open-cluster-management-agent $ oc create secret docker-registry open-cluster-management-image-pull-credentials \ --docker-server=registry.redhat.io \ --docker-username=${RH_USERNAME} \ --docker-password=${RH_PASSWORD} \ --docker-email=${EMAIL} $ oc secrets link klusterlet open-cluster-management-image-pull-credentials --for=pull $ oc secrets link klusterlet-registration-sa open-cluster-management-image-pull-credentials --for=pull $ oc secrets link klusterlet-work-sa open-cluster-management-image-pull-credentials --for=pull $ oc project open-cluster-management-agent-addon $ oc create secret docker-registry open-cluster-management-image-pull-credentials \ --docker-server=registry.redhat.io \ --docker-username=$RH_USERNAME \ --docker-password=$RH_PASSWORD \ --docker-email=$EMAIL $ oc secrets link cluster-proxy open-cluster-management-image-pull-credentials --for=pull $ oc secrets link klusterlet-addon-search open-cluster-management-image-pull-credentials --for=pull $ oc secrets link application-manager open-cluster-management-image-pull-credentials --for=pull $ oc secrets link klusterlet-addon-workmgr open-cluster-management-image-pull-credentials --for=pull MicroShift上に下記のPodが起動してきます。Runningとなるまで待ちましょう。 $ oc get po -A | grep open-cluster open-cluster-management-agent-addon application-manager-7488766d49-vs4f2 1/1 Running open-cluster-management-agent-addon cluster-proxy-proxy-agent-66dd8845b-ndzpw 2/2 Running open-cluster-management-agent-addon cluster-proxy-proxy-agent-66dd8845b-qm8ts 2/2 Running open-cluster-management-agent-addon klusterlet-addon-search-5bdfd9685-tc4br 1/1 Running open-cluster-management-agent-addon klusterlet-addon-workmgr-7c6b8679bd-vqbcc 1/1 Running open-cluster-management-agent klusterlet-54d4bfd556-zm7gr 1/1 Running open-cluster-management-agent klusterlet-registration-agent-557cb5bb4b-vtclx 1/1 Running open-cluster-management-agent klusterlet-work-agent-5598cdf789-lht8k 1/1 Running MicroShift側でklusterlet-registration-agent PodがRunningとなると、Hubクラスタの方からManagedクラスタのStatusがReadyへ変わるはずです。 アドオンも全てAvailableになったら完了です。 HubクラスタからManagedクラスタへアプリをデプロイしてみる HubクラスタでMicroShiftを管理できるようになったので、ACMを用いてアプリケーションをMicroShiftへデプロイしてみましょう。まずは、Hubクラスタ上で管理下のMicroShiftに任意のラベルを付与しておきます。 ◎Hubクラスタ側 $ kubectl label managedcluster device01 device=device01 このラベルはHubクラスタでアプリケーションの配置ポリシを定義する際に、どのクラスタへアプリケーションを配置するか判断するために使用されます。同じラベルを複数のMicroShiftクラスタへ付与しておけば、同じアプリケーションをそのラベルが付与される複数のMicroShiftへ一斉にデプロイできます。 ラベルを付与したら、今度はHubクラスタでSubscriptionを作成してみます。以下に参考として、 https://github.com/stolostron/application-samples のnginxをデプロイするマニフェストを記載しておきます。 ◎Hubクラスタ側 $ vi nginx-subscription.yaml apiVersion: v1 kind: Namespace metadata: name: nginx-sample --- apiVersion: app.k8s.io/v1beta1 kind: Application metadata: name: nginx-sample namespace: nginx-sample spec: componentKinds: - group: apps.open-cluster-management.io kind: Subscription descriptor: {} selector: matchExpressions: - key: app operator: In values: - nginx-sample --- apiVersion: apps.open-cluster-management.io/v1 kind: Subscription metadata: annotations: apps.open-cluster-management.io/git-branch: production apps.open-cluster-management.io/git-path: nginx apps.open-cluster-management.io/reconcile-option: merge labels: app: nginx-sample name: nginx-sample-subscription-1 namespace: nginx-sample spec: channel: ggithubcom-stolostron-application-samples-ns/ggithubcom-stolostron-application-samples placement: placementRef: kind: PlacementRule name: nginx-sample-placement-1 --- apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: labels: app: nginx-sample name: nginx-sample-placement-1 namespace: nginx-sample spec: clusterSelector: matchLabels: 'device': 'device01' $ oc apply -f nginx-subscription.yaml namespace/nginx-sample unchanged application.app.k8s.io/nginx-sample created subscription.apps.open-cluster-management.io/nginx-sample-subscription-1 created placementrule.apps.open-cluster-management.io/nginx-sample-placement-1 created MicroShift側を見てみると、Hubクラスタで指定した nginx-sample Namespaceにnginxが起動しているのがわかります。 ◎MicroShift側 $ oc get po -n nginx-sample NAME READY STATUS RESTARTS AGE nginx-sample-7667b4ff65-6dg4r 1/1 Running 0 3m35s nginx-sample-7667b4ff65-rwlpx 1/1 Running 0 3m35s nginx-sample-7667b4ff65-zvbng 1/1 Running 0 3m35s もちろん、Hubクラスタ側にはnginxは作成されていません。 ◎Hubクラスタ側 $ oc get po -n nginx-sample No resources found in nginx-sample namespace. ACMのGUIから、以下のようなトポロジービューでリソースの作成状況を確認することもできます。  まとめ 本稿では、Advanced Cluster Management for Kubernetseを使ってMicroShiftがインストールされたエッジデバイスへアプリケーションを展開する簡単な手順をご紹介しました。今回ご紹介した方法を基本として、例えばArgoCDとACMを連携させることでエッジデバイスに対してGitOpsでアプリケーションをリリースすることも可能になります。その辺りの話も近々したいと思います〜! 最後に... Save the date!!! 27th Jan ==> "OpenShift.Run 2023" 年明けやります!OpenShift.Run! まだOpenShift User Groupに入ってない人はぜひご参加の程よろしくお願いします! openshift.connpass.com また、OpenShift.Runに至る道のり…ということで、「トレラン!エブリデイOpenShift」を開催中です。初心者の方から上級者の方まで「実際に手を動かしながら OpenShift を楽しんで頂く」会として、ご自身のスピード感でじっくりトレランできます。こちらも奮ってご参加くださいませ〜 https://openshift.connpass.com/event/269428/