サイオステクノロジー(Tech.Lab)のブログ - TECH PLAY

TECH PLAY

サイオステクノロジー(Tech.Lab)

サイオステクノロジー(Tech.Lab) の技術ブログ

672

概要 今までの回で、プラットフォーム上でコンテナとVMを統合管理することが出来るOCP-Virt, SUSE-Virt についてご紹介しました。 紹介の中でも、簡易的にその他仮想化基盤との比較も行ってきました。 今回は、今までにご紹介したOCP-Virt, SUSE-Virt, 加えてvSphereを含めて3製品の比較について記載します。 vSphereについても、今までの回で軽く触れていますが改めて概要と特徴について簡単に触れておきたいと思います。 OCP-Virt, SUSE-Virt の概要については下記の記事をご覧ください。 OCP-Virtの概要は こちら SUSE-Virtの概要は こちら vSphereの概要と特徴 vSphereは、仮想化基盤として提供され複数のVMを実行して管理することができます。 リソース使用率の最適化、スケーラビリティの向上のため企業環境での広範な採用実績を持っています。 主な機能としては、以下があります。 ESXiホスト 物理サーバー上で動作するハイパーバイザーで、仮想マシンの実行環境を提供します vCenter Server 複数のESXiホストを集中管理するためのサーバーで、VMの管理、リソースの最適化などを行います vMotion 実行中のVMをダウンタイムなしで他のESXiホストに移動する機能です。この機能によりシステムのダウンタイムを最小化することができます。 DRS(Distributed Resource Scheduler) VMのリソース需要に応じて、リソースの負荷を自動的に分散させる機能です vSphere HA ESXiホスト障害時にVMを自動的に他のホストに移動させ、可用性を高める機能です vSphere Replication VMのデータを別の場所に複製し、災害復旧を実現するための機能です。この機能により、データセンターの障害に対して迅速に復旧が可能になります 主な特徴は、以下があります。 柔軟性とスケーラビリティ vSphereは、小規模から大規模な環境までスケーリングが可能で、リソースの追加や削減が簡単に行えます また、ハイブリッドクラウド環境にも対応しており、クラウドとオンプレミス環境を柔軟に組み合わせて運用できます 効率的なリソース管理 VMごとにリソースの割り当てや優先順位を設定し、リソースの効率的な利用が可能です 高可用性とフォールトトレランス 自動フェイルオーバー用の vSphere HA や予測障害検出用の Proactive HA など信頼性の高い仮想化基盤環境を提供します 簡単な管理インターフェース 直感的な管理インターフェースを提供し、管理者がvSphere ClientやvCenter Serverなどを通じて、VMやリソースを簡単に管理できるように設計されています 前提情報 本記事では、現時点で以下のバージョンを対象としています。 OpenShift Virtualization OpenShift v 4.17 OpenShift Virtualization v4.17.3 SUSE Virtualization harvester v 1.4.0 VMware vSphere VMware vSphere 8.0 OCP-Virt、SUSE-Virt、vSphere の比較 OCP-Virt、SUSE-Virt、vSphere の主な機能の比較を記載します。 比較区分は以下の通りです。 〇:機能が存在するあるいは、他のソリューションと比較し優れている △:オプションの機能と組み合わせて実現が可能、また機能はあるが他のソリューションと比較すると制限や制約が大きい ✕:機能がない   表1:OCP-Virt、SUSE-Virt、vSphere の比較表 大項目 中項目 小項目 OCP-Virt SUSE-Virt vSphere VM基本機能 VM操作 VMの作成 〇 〇 〇 VMの編集 〇 〇 〇 VMの削除 〇 〇 〇 VMのクローン 〇 〇 〇 リソース拡張(CPU/メモリ/ボリューム) 〇 ボリュームの削減はできない リソース拡張はVMの再起動が伴う 〇 ボリュームの削減はできない リソース拡張はVMの再起動が伴う 〇 ボリュームの削減はできない リソース拡張はVM無停止で可能 VM/ノード管理 VMの可用性 VMの自動復旧機能 〇 runStrategyで、VMの自動復旧機能を実現 〇 runStrategyで、VMの自動復旧機能を実現 〇 VMのライブマイグレーション 〇 〇 〇 クラスターノードの可用性 クラスターノードの自動復旧機能 △ Workload Availability *1でクラスターノードの自動復旧を実現 ✕ 手動で障害ノードを復旧するか、新規ノードを用意 ✕ ホストの自動復旧機能は提供されていない VM管理 テンプレート機能 〇 〇 〇 クォータ(リソース制限)の設定 〇 △ Rancherとの統合でnamespaceのクォータ設定を実現 〇 CPU/メモリ/ストレージ I/Oの上限を指定可能 ホスト名の名前設定の可否 〇 〇 〇 VM内部からホスト名を変更することも可能 認証 認証基盤連携 ユーザー認証基盤との連携機能 〇 〇 Rancherとの統合で、ユーザー認証基盤との連携を実現 〇 ネットワーク 負荷分散 複数VMへのアクセスの負荷分散 〇 Routeを使用してL7の負荷分散を実現 Metal LBを使用して、L2,L3の負荷分散を実現 〇 組み込みのHarvester LBを利用して、L4の負荷分散を実現 △ アドオン、または外部ソリューションとの組み合わせで負荷分散を実現 DNS設定 DNS設定 〇 〇 〇 Pod/VMのIP固定化 Pod/VMの静的IP 〇 VMに付与した2つ目のネットワークで静的IP設定が可能 〇 VMに付与した2つ目のネットワークで静的IP設定が可能 〇 モニタリング&ロギング モニタリング VM/クラスターノードの標準モニタリング(CPU/メモリ/IOPS) 〇 〇 〇 VM / クラスターノードの死活監視 〇 〇 〇 ロギング VM / クラスターノード のロギング 〇 △ 外部のログサーバーとの統合でログデータの保存を実現 〇 データ管理 スナップショット スナップショット 〇 〇 〇 バックアップ バックアップ △ OADP Operatorインストールで実現 〇 △ ホストのバックアップは可能 VMのバックアップは、VADP *2を使用して別バックアップツールと連携することで実現 スケジューリング スナップショットのスケジューリング ✕ 〇 〇 バックアップのスケジューリング △ OADP Operatorインストールで実現 〇 ✕ セキュリティ マルチテナント 異なるテナントごとにリソースを論理的に分離する機能 〇 OCPのプロジェクト機能を使用して テナントごとにリソースの分離、セキュリティの強化を実現 △ Kubernetes標準の機能で簡易的なリソース分離が可能。Rancherと統合することで十分なマルチテナント機能を実現 ✕ アクセス制限 VM間または外部へのアクセス制限 〇 OCPのネットワークポリシーを利用してアクセス制御を実現 〇 〇 RBACでのVM操作・管理の制御 〇 OCPのRBACを利用して、プロジェクトに対するユーザーの権限制御を実現 △ Rancherと統合しRBAC機能を活用してユーザーの権限制御を実現 〇 ストレージ ボリューム 永続ボリューム 〇 〇 〇 分散ストレージ △ ODFをインストールして分散ストレージを実現 〇 △ Storage vMotionに相当する機能 ✕ ✕ 〇 ボリューム形式の種類 – ブロック ファイル – ブロック ファイル – ブロック ファイル ストレージ バックエンドのストレージ対応種類 〇 多くのストレージベンダーのCSIプラグインが提供 〇 多くのストレージベンダーのCSIプラグインが提供 〇 クラスター管理 バージョンアップ バージョンアップのプロセスの容易さ 〇 簡単にバージョンアップすることが可能 バージョンアップ中にVMを停止する必要はない 〇 UIから簡単にバージョンアップすることが可能 バージョンアップ中にVMを停止する必要はない △ 事前準備、バージョンアップ作業が入る 対応プラットフォーム 対応プラットフォーム 対応プラットフォーム – オンプレミス AWS – オンプレミス Equinix – オンプレミス 多くのクラウドベンダー *3 *1 Workload Availability:Workload Availability for Red Hat OpenShift *2 VADP:VMware vStorage API for Data Protection *3 多くのクラウドベンダー:VMware Cloud on AWS、Azure VMware Solution、Google Cloud VMware Engine、Oracle Cloud VMware Solution に対応している   各製品の利用ケース どの仮想化基盤も基本的な機能の共通点が多く、優れた環境を提供しますが、それぞれが特定の利用ケースに適している場合があります。 OCP-Virtの利用ケース OpenShift(OCP) の機能を利用した効率的な運用 OpenShift(OCP) 側のセキュリティ、モニタリング、ロギング、ユーザー管理などの様々な機能をOCP-Virtでも利用できます。既存のコンテナ運用と統合して管理することで効率的な運用を実現できます 基盤となるノードの復旧対応の効率化 Workload Availability for Red Hat OpenShift機能を用いて構成するノードの自動復旧・自動追加機能を活用して柔軟なノード管理ができます RHEL OSの利用 多くのRHEL OSのVMを構成するユーザーは、ライセンス費用低減のメリットを享受できます SUSE-Virt利用ケース 標準のデータ管理機能 Harvester標準に備わっているスナップショット機能、バックアップ機能およびそれらのスケジューリング機能を使用して、安定したデータ管理機能を素早く実現できます Rancherとの統合 既存のKubernetesクラスターがあり、KubernetesクラスターとHarvesterをRancherで統合管理することができます Rancherと統合することにより、ユーザー認証基盤の連携、テナント管理、RBACなどの機能を一元的に管理することができます コストを抑えた仮想化基盤の利用 OSSの性質から基本的に無償で利用でき、大きな投資をせずに堅牢な仮想化基盤を必要とするユーザーに適しています vSphere利用ケース シンプルなネットワーク構成 vCenterでの包括的なvSwitchの管理などを実現できます。また複数のネットワーク構成をする際もシンプルな方法での構成を提供しています より広範なストレージ機器の利用 ストレージ機器の選定の幅が広いため、他の仮想化基盤に対応していないストレージ機器を使用したいユーザーに適しています バージョンアップ運用の負担軽減 Kubernetes環境のリリースの速さに追従する必要がないため、バージョンアップに係る運用面の負担を軽減できます まとめ 今回は、今までご紹介したOCP-Virt, SUSE-Virtと vSphere を含めて3製品の比較をしてみました。 基本的な機能についてはどの製品も提供していますが、利用ケースに応じた選定の一要素として、いくつか比較ポイントが見えました。 仮想化基盤を比較する上でこの記事が比較の参考になれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift Virtualization, SUSE Virtualization, VMware vSphere の比較 first appeared on SIOS Tech. Lab .
今号では、Linux におけるパーミッションについて説明します! パーミッションとは パーミッションとは、Linux におけるファイルやディレクトリに対する アクセス権限 のことです。 一般ユーザとして使用している場合、あまりパーミッションについて意識することは少ないかもしれませんが、普段利用しているすべてのファイルやディレクトリにパーミッションが設定されています。 「誰が」「どのような操作を」許可されているかを決める重要な仕組みであり、パーミッションが適切に設定されていないと 不正アクセス や データの改ざん 、 誤ってプログラムを実行してしまう 可能性があります。 なお、パーミッションはファイルを作成するごとに自分で設定する必要はなく、システム側の設定とアプリ側の設定を組み合わせた上で、それぞれデフォルトのパーミッションが割り振られます。 適宜、パーミッションを変更しながら運用していくことになります。 パーミッションの考え方 Linux では、ファイルやディレクトリのパーミッションは下記 3つのカテゴリに分けられます。 Owner (所有者) :ファイルを作成したユーザ Group (グループ) :Owner が所属するグループ Other (その他) :Owner 以外の全ユーザ また、各カテゴリに対して下記 3つの権限を設定できます。 r (読み取り) :ファイルの読み取り権限 w (書き込み) :ファイルの書き込み権限 x (実行) :ファイルの実行権限 (プログラムやスクリプトを実行する場合) パーミッションの確認方法 最も簡単なのは、 ls -l コマンドを実行してファイルの情報を表示する方法です。 $ ls -l test.txt -rw-r--r--. 1 ykaino ykaino-group 0 Mar 24 12:00 test.txt 出力された各内容を、それぞれ説明します。 -rw-r–r– :パーミッションを表す文字列 1 :リンク数。通常は 1となるが、ハードリンクがある場合は増加する ykaino :Owner。ファイルを作成したユーザ名 ykaino-group :group。Owner が所属するグループ名 1234 :ファイルサイズ (byte 単位) Mar 20 10:00 :ファイルの最終更新日時 example.txt :ファイル名 (ディレクトリの場合はディレクトリ名) 続いて、パーミッションを表す文字列について説明します。 上記で出力された文字列 ( -rw-r–r– ) を例にすると、 1文字目 (-):ファイルの種類。- は通常のファイル、d はディレクトリ、l はシンボリックリンクとなる 2~4文字目 (rw-):Owner (所有者) の権限。読み、書きは許可、実行は不可 5~7文字目 (r–):Owner がいるグループに所属する、他のユーザの権限。読みは許可、書き、実行は不可 8~10文字目 (r–):上記に該当しない他のユーザの権限。読みは許可、書き、実行は不可 なお、ls -l コマンドの他に、 getfacl コマンドを実行してファイルの情報を表示する方法もあります。 $ getfacl test.txt # file: test.txt # owner: ykaino # group: ykaino-group user::rw- group::r-- other::r-- デフォルトのパーミッション 上記の test.txt ファイルでは、ユーザに読み、書きの権限があり、グループおよびその他のユーザには読み取り権限のみが与えられていました。 これは、ファイルやディレクトリにデフォルトで設定されるパーミッションがあらかじめ決められているために上記のような結果となっています。 デフォルトのパーミッションは umask というパラメータで設定されます。 ls -l コマンドの実行結果では、各権限を r (読み取り)、w (書き込み)、x (実行) で表現しましたが、 umask では各権限を数値で表現します。 r (読み取り) :4 w (書き込み) :2 x (実行) :1 例えば、読み取りと書き込みの権限がある場合は 4 + 2 = 6 、読み取りと実行の権限がある場合は 4 + 1 = 5 のように考えます。 Linux ファイルシステムでは、ファイルの基本パーミッションが 666 (読み書きのみ、実行権限なし) 、ディレクトリの基本パーミッションが 777 (読み書き実行すべて可能) になっています。そこから umask の値を引き算して、最終的なパーミッションが決定します。 現在の umask の値は umask コマンドで確認できます。 # umask 0022 ファイルの場合は 666 から 022 を引いて 644 (Owner は読み、書き権限あり、グループおよびその他のユーザには読み取り権限あり) 、ディレクトリの場合は 777 から 022 を引いて 755 (Owner は読み、書き、実行権限あり、グループおよびその他のユーザには読み、実行権限あり) になります。 umask の値を一時的に変更する場合は umask コマンドを実行します。 $ umask 027 永続的に変更する場合は ~/.bashrc もしくは ~/.profile などのファイルに、下記の様な umask の設定を追加します。 umask 027 次号では、パーミッションの変更方法や、特殊なパーミッションについて説明します! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!ファイルのパーミッションについて1 first appeared on SIOS Tech. Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 Google は 3月の Pixel Feature Drop (Pixel 端末向けアップデート) で、Linux のネイティブアプリを導入しました。 グーグル、「Android」向けに「Linux」ターミナルを追加–まずは「Pixel」で導入 https://news.yahoo.co.jp/articles/d3473c2e2a2cd2d4e084b2e4b65d2d9953d0277f Google は、日本企業のサイバーセキュリティ意識の向上と専門人材の育成を支援する「Japan Cybersecurity Initiative」を立ち上げました。 日本のサイバーセキュリティの底上げに向けた産学官連携「Japan Cybersecurity Initiative」を設立 https://blog.google/intl/ja-jp/company-news/technology/cybersecurity-initiative/ 2025/3/19、FinOps Foundation の創始者が執筆した「クラウドFinOps 第2版 ー協調的でリアルタイムなクラウド価値の意思決定」の日本語書籍が出版されました。 国内初、Linux Foundation傘下のFinOps Foundationが公認した『クラウドFinOps 第2版 ー協調的でリアルタイムなクラウド価値の意思決定』の日本語書籍が本日出版 https://prtimes.jp/main/html/rd/p/000000133.000015260.html ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2025年3月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
サイオステクノロジーの菊地啓哉です。思ったより間が空いてしまったのですが、 前回 の記事の続きになります。 ECDSA や zk-STARK などでは有限体がベースにあるので、 前回 の体の話から、有限体の話に進んでいこうと思います。 自分が有限体について調べた時には、体の拡大に急に既約多項式が出てきて飲み込みにくいところがあったので、そのあたりに少しだけ間の内容を入れています。 数学に詳しくないエンジニアの体入門 数学に詳しくないエンジニアの有限体 巡回群 前回 も少し触れましたが、 巡回群 についてご紹介したいと思います。この群は、ただ1つの元で生成される群で、 mod n(nで割った余り)の中での足し算もこれの具体例の1つとなります。 例えば、単位元 e、生成元 g、要素数 4 の巡回群 G について考えると、 g ○ g = g 2 のように演算 ○ の繰り返しを累乗のように表現するなら G の元は のように表すことができます。これは整数の足し算の4で割った余りが元の数の4で割った余り同士の足し算(をさらに4で割った余り)と同じです。 13(4で割ると余り1)+ 22(4で割ると余り2) = 35(4で割ると余り3) 6(4で割ると余り2)+ 35(4で割ると余り3) = 41(4で割ると余り1) 有限体 有限体の性質 体のうち、元が有限個のものを 有限体(ゆうげんたい、Finite Field) と呼びます。話がとても難しくなってしまうので導出はしませんが以下のような性質を持ちます。 3点目については、有限群の性質から導けます。1点目と2点目は実力不足で分かりやすくまとめられなさそうなので諦めました(これは3点目のフェルマーの小定理にかけているわけではありません)。 有限体の例 mod 3 の足し算、掛け算で体を考えます。ここでは、mod 3 であることを忘れないように、下添え字の 3 をつけます。可換であることを踏まえて通常の計算と異なるのは、以下の3つです。 mod 3 だということを考えれば特に問題無いかと思います。 とても簡単ですが、「体の元から零元を除くと乗法に関して巡回群となる」について確認しておくと、 となるので、零元を除くと、乗法に関して元の数が2の巡回群となっていることがわかります。 なんで、こんな元の数が少ない体にしたかと言えば、後でこの体を拡大します。 有限体で方程式を解く 前回 の記事で、体の中で方程式を解くのが普通にやってるのと同じと書いたので、実数の世界で -2 と 1/2 が解の二次方程式を mod 3 の体で解いてみたいと思います。この二次方程式は次のように書けます。 これは、特に上に書いた計算を利用することで、1 3 + 2 3 = 0 3 、2 3 * 2 3 – 1 3 = 1 3 – 1 3 = 0 3 なので、 x = 1 3 , 2 3 と解くことができます。こういった具合に、有理数係数の方程式は割と有限体の方程式にそのまま考え直すことができます。ただし、0除算があってはいけないので、この mod 3 の体で考えるには分母が3の倍数の解があると上手くいきません。 この方程式の両辺を 2 3 倍して、式を展開してみましょう 当然と言えば当然ですが、最後の式を見ると、解と係数の関係が成り立っていることも見て取れると思います。 Bitcoin や Ethereum では、secp256k1 と呼ばれる楕円曲線(のパラメータ)を採用しているようで、そこでは有限体の元の数 p は 2 256 – 2 32 – 2 9 – 2 8 – 2 7 – 2 6 – 2 4 – 1 という、とても大きな値を使っています。 完全に余談ですが、ECDSAで楕円曲線上の点と点の足し算を定義して、その繰り返しとしてスカラー倍を定めているのに、表記によってはいつのまにか、スカラー倍の部分が分数で表現されていたりするのは、繰り返しの数を表す係数側が有限体の元であり、逆数は逆元を意味しているので、分数を計算すれば自然数になることなどを前提としていますね。 せっかく有限体の話を書いてきたので、要素数が素数の有限体を拡大するところに触れたいと思います。その前に少し寄り道をします。 有理数と平方根 前回の記事の群の例を見ていただくとわかると思いますが、群となれない理由としてありがちなのは、”逆元が存在すること”が満たされない、かなと思います。 中学で平方根(ルート)を学習された/されることと思いますが、そこで分母の有理化というものがあったと思います。逆元の存在とか、演算が閉じていることとか、そんなことと絡めて授業を受けたという方は恐らくいらっしゃらないとは思いますが、「2乗すると有理数になる」、「分母に平方根があっても分母を有理化できる」など、乗法について体となかなか相性の良い性質を持っています。有理数 a, b と素数 p で a +b√p で表されるような数について掛け算と割り算は以下のようになります。(ここでは素数である必要性はないのですが、 √p が確実に有理数でないようにわかりやすく素数としています) どちらの計算結果も「有理数 a, b と素数 p を用いて a +b√p で表される形」になっています。このことから、「なんか、平方根を使っていい感じの体を作れそうな空気」が出てきます。足し算引き算も問題無さそうなのはおわかりかと思いますのでスキップします。 mod 3 の体を拡大する 先ほどの mod 3 で考えていた体に √2 に相当する数 β を仲間に加えてみます。ここで、 β*β = β 2 = 2 3 です。また、 β 自体が mod 3 でどうなるかは考えず、その係数で mod 3 を考えます。別の表現をするなら、 1 3 + 2 3 = 0 3 の両辺に β を掛けて次の式が得られます。 この集合は、mod 3 の体の元 a, b を用いて、 a+bβ で表すことのできる 9個の元を作れることがわかります。また、この集合が体になることがわかります。 逆元がわかりにくいところだと、 となります。あと、有限体の性質のうち、零元を除いて乗法が巡回群となるということについて、ちょっと計算してみると、 のように、 1 3 + β を生成元にできることがわかります。(上の結果を見て想像できるように他にも生成元にできる元があります) ここでは、 mod 3 の有限体に β 2 = 2 3 となる元 β を加えて、新しい体を作りました。 これと同じように一般的には、既約多項式という「より低次の多項式で因数分解できない多項式」を使って、”既約多項式 = 0”で定義される新しい元( α とします)を定め、体を拡大します。また、その時、拡大前の体の元の数を p 、既約多項式の次数を n とすると、各 α k (k=0, 1, …, n-1) の係数が p 種類取り得るので、作られる体の元の数は p n となります。今回の例の β であれば、 β 2 = 2 3 の右辺が 0 になるように変形して既約多項式は β 2 + 1 3 となります。 先の例よりも次数が上の具体例として、これまで扱ってきた mod 3 の体に α 3 + 2 3 α + 1 3 = 0 3 で定められる α を追加すると、四則演算によって、 a + b α + cα 2 で表される 3 3 個の元ができ、それらによって、体が作られます。ここで、 a, b, c は mod 3の体の元で、1つ前の体と比べると、 cα 2 が増えた分、元の数が3倍になっています。 α の多項式の次数が2次以下となるのは α 3 = -2 3 α – 1 3 なので、 α の3次以上の項は次数を落とすことができることからわかります。 おわりに 前回同様、全く技術的なことには触れずに数学の体について書きました。駆け足ではありますが、有限体のがどのようなものか紹介しました。難しくならないようにできるだけ深入りせずにざっと書いてみましたが、いかがだったでしょうか。次はどのように有限体が使われているのか書ければ良いなと思っています。 ということで、今回はここで終わりとなります。 またかきます またね ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 数学に詳しくないエンジニアの 有限体 first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの遠藤です。今回はNext.js 15でApp Routerを利用した際のStatic Exportsについて整理します。 Static Exportsとは? Static Exportsは、build時に、アプリケーションを静的コンテンツとしてエクスポートできる機能です。Static Exportsを利用せずにNext.jsのアプリケーションを公開する場合はNode.jsランタイムが必要となりますが、Static Exportsを利用してbuildをかけた場合はクライアントサイドだけで動くコードが吐き出されるので、Node.js環境が必要なくなるのがメリットです。 Static Exportsのやり方 公式ガイド : https://nextjs.org/docs/app/building-your-application/deploying/static-exports next.config.jsにて output: ‘export’, の記述を追加すると、静的エクスポートを利用できるようになります。 import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "export", }; export default nextConfig; その後、 npm run build を実行すると、 out ディレクトリにHTML/CSS/JS assetsが作成されます。 Static ExportsでServer Componentsを利用した場合の挙動 名前にserverとついているためややこしいですが、Static ExportsでServer Componentsを使用することは可能です。ただ、注意点があり、ビルド時にServer Componentsが実行されて生成されたコンテンツに固定されます。 わかりやすく説明するために、ランダムに4桁の数字を返してくれるAPIのFetchのClient Components上で行った場合と、Server Components上で行った場合に分けて考えてみましょう。 通常のデプロイを利用してNode.jsサーバー上にデプロイ Client Components上で行った場合とServer Components上で行った場の両方でリクエストが来るたびにフェッチを行い、毎回ランダムな値(一回目 : 3592, 二回目 : 5285 …)を表示します。 Static Exportsを利用 Client Components上で行った場合 リクエストが来るたびにフェッチを行い、毎回ランダムな値(一回目 : 3592, 二回目 : 5285 …)を表示します。 Server Components上で行った場合 ビルド時にServer Componentsが実行されて一度フェッチが行われます。(値は6472)。サーバーを起動してリクエストを送ると以降6472だけ表示され続けられます。 Dynamic Routesの使用に制限がある Next.jsにはリクエストに応じて動的データからルートを作成してくれるDynamic Routesという機能があります。以下のように[slug]ディレクトリを作成することで使用することができます。 ルート URLの例 params app/blog/[slug]/page.js /blog/a { slug: 'a' } app/blog/[slug]/page.js /blog/b { slug: 'b' } app/blog/[slug]/page.js /blog/c { slug: 'c' } このDynamic Routesの機能ですが、リクエストごとにサーバーでルートを作成するといった機能のため、基本的にはStatic Exportsでは利用することが出来ません。 ただ、Dynamic Routesに、 generateStaticParams という関数を利用することで、ビルド時にfetchを行い、静的にルートを作成することができます。この機能を利用することで、Static Exportsを利用した場合でも静的にルートを作成したページに関してはアクセスできるようになります。 そのほかサポートされていない機能 Static Exportsではサーバーで動く機能は使用できないため、MiddlewareやServer Actionsといった機能を使用することが出来ません。2025/02の段階で使用できない機能は以下の機能です。 Dynamic Routes  with  dynamicParams: true Dynamic Routes  without  generateStaticParams() Route Handlers  that rely on Request Cookies Rewrites Redirects Headers Middleware Incremental Static Regeneration Image Optimization  with the default  loader Draft Mode Server Actions Intercepting Routes 公式ガイド : https://nextjs.org/docs/app/building-your-application/deploying/static-exports#unsupported-features まとめ 今回はNext.jsのStatic Exportsについてまとめました。特にServer Componentsについては曖昧な理解だったため今回実際にコードを書いて挙動を確認したことにより理解を確かにすることが出来ました。「Static ExportsでServer Componentsを利用しているのになぜbuildが通るんだろう?」といった疑問を持っていた方の助けになれば幸いです! ではまた~ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【Next.js】App Routerを利用した際のStatic Exportsについて整理する first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの和田です。今回はEthereumのウォレットアドレス(EOA)の本人確認をMetaMaskの署名機能を使って試したので、実装方法などを書いていきたいと思います。 署名の検証方法 署名の検証を実装するために、以下のツールを使用しました。 フレームワーク Next ライブラリ React Web3 ethers ブラウザ拡張機能 MetaMask 署名の検証プロセスは以下の手順で行います。 MetaMaskでウォレットを接続する MetaMaskで署名を作成する 署名とメッセージをサーバーに送信する サーバー側で署名を検証する クライアント側で署名の検証結果を受け取る 実装 それでは実装していきたいと思います。以下に実際に試したソースコードを記載します。 app/components/Web3Auth.tsx "use client"; import { useState, useEffect } from "react"; import Web3 from "web3"; declare global { interface Window { ethereum?: any; } } const Web3AuthClient = () => { const [account, setAccount] = useState<string | null>(null); const [message, setMessage] = useState<string>("Sign this message to login."); const [web3, setWeb3] = useState<Web3 | null>(null); const [recoveredAddress, setRecoveredAddress] = useState<string>(""); useEffect(() => { if (window.ethereum) { setWeb3(new Web3(window.ethereum)); } }, []); const connectWallet = async () => { if (!web3) { alert("MetaMaskをインストールしてください。"); return; } try { const accounts = await window.ethereum.request({ method: "eth_requestAccounts", }); setAccount(accounts[0]); } catch (error) { console.error(error); } }; const signMessage = async () => { if (!web3 || !account) return; try { const signedMessage = await web3.eth.personal.sign(message, account, ""); // API に署名データを送信して検証 const response = await fetch("/api/verify-signature", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, account, signature: signedMessage }), }); const result = await response.json(); if (result.verified) { alert("署名の検証に成功しました。"); setRecoveredAddress(result.recoveredAddress); } else { alert("署名の検証に失敗しました。"); } } catch (error) { console.error(error); } }; return ( <div className="p-4 border rounded shadow-md"> <h2 className="text-lg font-bold mb-2">Web3 認証</h2> {account ? ( <> <p> 接続したアカウント: <strong>{account}</strong> </p> <p> 復元されたアドレス: <strong>{recoveredAddress.toLowerCase()}</strong> </p> <button onClick={signMessage} className="px-4 py-2 bg-blue-500 text-white rounded mt-2"> 署名を検証する </button> </> ) : ( <button onClick={connectWallet} className="px-4 py-2 bg-green-500 text-white rounded"> ウォレットに接続する </button> )} </div> ); }; export default Web3AuthClient; app/api/verify-signature/route.ts import { NextRequest, NextResponse } from "next/server"; import { verifyMessage } from "ethers"; export async function POST(req: NextRequest) { try { const { message, account, signature } = await req.json(); if (!message || !account || !signature) { return NextResponse.json({ error: "Missing parameters" }, { status: 400 }); } const recoveredAddress = verifyMessage(message, signature); const isValid = recoveredAddress.toLowerCase() === account.toLowerCase(); return NextResponse.json({ verified: isValid, recoveredAddress }, { status: isValid ? 200 : 401 }); } catch (error) { console.error("Signature verification error:", error); return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } } app/page.tsx import Web3Auth from "./components/Web3Auth"; export default function Home() { return ( <div className="min-h-screen flex items-center justify-center bg-gray-100"> <Web3Auth /> </div> ); } 動作確認 上記で作成したアプリを動かしてみます。 npm run dev で起動し、 localhost:3000 にアクセスします。すると以下のような画面が表示されます。 ウォレットに接続するをクリックするとメタマスクのパスワードを聞かれるので入力してロック解除します。 すると以下のような画面が表示されます。メタマスクで選択されているアカウントが表示されています。 署名を検証するをクリックします。クリック後、以下のような署名要求のポップアップが表示されるので、確認をクリックします。 確認をクリック後、以下のように署名の検証結果が表示されます。 OKをクリックすると、以下のように復元されたアドレスが表示されます。サーバー側で署名から復元したアドレスと接続したアカウントのアドレスが一致していることが確認できました。 まとめ 今回は MetaMask の署名機能を利用して EOA の所有者を検証する簡単なアプリケーションを実装しました。署名の検証プロセスを通じて、EOA 所有者の本人確認を実現できることが確認できました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Ethereumウォレットアドレスの署名検証試してみた first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジー OSS サポート担当 山本 です。 今回も solr のお話です。 solr スキーマの数多ある “ フィルタ ” から、比較的効果が実感しやすいと思われる応用フィルタ Synonym (同義語・類義語) についてお話してみようと思います。 ■solr の Synonym ってどういうもの? Synonym は先述のとおり 同義語 または 類義語 を示す言葉です。 文字通り、同じような意味の言葉や似たような意味の言葉のことで、 例えば「青」と「ブルー」は同義語ですし、「お皿」と「プレート」は類義語と言えるでしょう。 ところで、改めてですが solr は インデックス という仕組みを使って 予め登録しておいた一連のデータ である ドキュメント から高速な 文字列検索 を行うことに特化した、全文検索 OSS です。 そう、solr はインデックスの 文字列検索 によってドキュメントを検索しています。 なので、当たり前と言えば当たり前ですがデフォルトでは 「 青 」で検索しても「 ブルー 」のドキュメントは 出てきません 。 でも、仮に自分が検索する側として考えてみてください。 例えばショッピングサイトで、「カーテン 青」で検索した場合と「カーテン ブルー」で検索した場合の検索結果が全く違っていたら? それらの検索結果で出てきたもの以外にも、「カーテン 藍色」「カーテン ネイビー」などで検索すると別の青色系カーテンのラインナップがあったりしたら? きっと不便と言うか機会損失というか、「いや、まとめて出してくれよ…」と思うことでしょう。 solr の Synonym は、こういった 同一の検索ワードとして扱ってほしい同義語・類義語の組 を 予め登録 しておくことで、検索ワードの同義語・類義語も一緒に検索できるようにする仕組みです。 Synonym はまた、「パソコン」と「PC」、「パーソナルコンピュータ」といったような 略記・略称・通称・正式名称 などが混在するドキュメント群をいい感じに検索できるようにするためなどにも使うことができます。 ■Synonym を使ってみる というわけで Synonym を試してみましょう。 今回も前回までで使用した環境 “test-new-core” に Synonym の設定を追加して試していきます。 (前回までの内容は省略するため、ベースとなるコアの作り方などのお話は以前の記事を参照してください。) Synonym を使うには、 Synonym 用の辞書 の作成をした上で、Synonym を使用するように スキーマファイルの設定を変更 する必要があります。 ■辞書の作成 まずは辞書を作ってみます。 例によってデモ用環境のコア “demo” にサンプルが入っているので、まずはこちらを確認してみましょう。 以下のコマンドで前回までに作成した環境を起動し、サンプルを手元の環境にコピーします。 ## (デモ用環境起動) $ podman start test-solr ## (Synonym 辞書サンプルのコピー) $ podman cp test-solr:/var/solr/data/demo/conf/synonyms.txt ./ 手元の環境にコピーした Synonym のサンプルファイル “ synonyms.txt ” を適当なテキストエディタで開き、まずは内容を確認してみます。 行頭が “#” の行はコメント行扱いとなるので、(ファイルの先頭のユーザ辞書の説明コメント部分を除くと) このファイルはこのような記述がされています。 #some test synonym mappings unlikely to appear in real input text aaafoo => aaabar bbbfoo => bbbfoo bbbbar cccfoo => cccbar cccbaz fooaaa,baraaa,bazaaa # Some synonym groups specific to this example GB,gib,gigabyte,gigabytes MB,mib,megabyte,megabytes Television, Televisions, TV, TVs #notice we use "gib" instead of "GiB" so any WordDelimiterGraphFilter coming #after us won't split it into two words. # Synonym mappings can be used for spelling correction too pixima => pixma ざっくりと 2種類の書式がありそうな、普通のテキストファイルであることがわかりますね。 それぞれの書式についてまず見ておきましょう。 [類義語A](,[類義語B],…) => [類義語C](,[類義語D],…) まず “=>” があるほうのこちらの書式ですが、 [類義語A] ( または [類義語B]…) を、[類義語C] ( および [類義語D]…) に変換する というものです。 例えば、上記のサンプルファイルの cccfoo => cccbar cccbaz は、「cccfoo」が「cccbar」+「cccbaz」に変換されるようにする記述です。(Synonym 処理後、 元の「cccfoo」は残りません 。) ※ 上記サンプルファイルの抜粋では 半角スペース 区切りで類義語を列挙していますが、 公式ドキュメント の Synonym の書式では “ , (カンマ) ” で分割するように記載されています。試したバージョンではいずれの記法でも機能しましたが、本記事では “ , (カンマ) ” 区切りで記載していきます。 つづいてもう片方の書式です。 [類義語E],[類義語F](,[類義語G],…) “, (カンマ)” 区切りでただ列挙するこちらの書式では、 列挙した類義語の いずれか が、列挙した類義語 全て に変換 されます。 例えば上記サンプルファイルの GB,gib,gigabyte,gigabytes は、「GB」「gib」「gigabyte」「gigabytes」のいずれも「GB」+「gib」+「gigabyte」+「gigabytes」に変換されるようにする記述になります。 さて、書き方はなんとなくわかったかと思いますので、試しに何か Synonym を追加してみましょう。 今回は果物の名前で試してみることにします。 今確認している、手元に持ってきた “synonyms.txt” の末尾に以下の記述を追加してみます。 ぶどう,葡萄,グレープ 林檎,アップル => りんご strawberry,苺 => ストロベリー,いちご 設定を追加したら、この “synonyms.txt” を “test-new-core” のディレクトリに配置します。 配置箇所はスキーマファイル “managed-schema.xml” から相対パスで指定できる場所なら大丈夫なはずですが、今回は “managed-schema.xml” と同じ conf 直下に配置しましょう。 $ podman cp ./synonyms.txt test-solr:/var/solr/data/test-new-core/conf/synonyms.txt これで Synonym 設定ファイルの準備は OK です。 ■Synonym フィルタの設定 次に、スキーマファイル “managed-schema.xml” に Synonym を使用する設定を追加します。 実験用コア “test-new-core” のスキーマファイル “managed-schema.xml” を一旦手元に持ってきて… (デモ用コンテナにはテキストエディタがないため) $ podman cp test-solr:/var/solr/data/test-new-core/conf/managed-schema.xml ./managed-schema.xml このスキーマで日本語解析の設定を行なっている部分の “<analyzer>” 要素の中に、Synonym を処理する “ synonymGraph ” の <filter> 要素を追加します。 ここで、この <filter> 要素を追加する位置は極めて重要 になりますが、今回は “cjkWidth” フィルタの後ろに置いてみましょう。 &ltfieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100"> &ltanalyzer> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &lt/fieldType> 設定を変更したら、この “managed-schema.xml” をコア “test-new-core” に戻します。 $ podman cp ./managed-schema.xml test-solr:/var/solr/data/test-new-core/conf/managed-schema.xml これで Synonym を使うように設定ができました。 ■設定の適用と Synonym 処理の確認 それでは、Synonym の処理を確認してみます。 変更したスキーマの設定を読み込むため、”test-new-core” をリロードします。 コマンドでリロードするなら以下のようなコマンドを $ curl -X POST http://(IP or ホスト名):8984/api/cores/test-new-core/reload 管理画面でリロードするなら “ Core Admin ” の画面から対象のコアを選択して、” Reload ” ボタンを押してください。 これで “test-new-core” で Synonym を処理する設定を適用できました。 早速、管理画面で試してみましょう。 “Core Selector” タブで test-new-core を選び、” Analysis ” を開いて、Synonym を適用した FieldType “text_ja” で先ほど追加した Synonym が処理されるのかを確認してみましょう。 ぶどう,葡萄,グレープ 「ぶどう」「グレープ」(と「葡萄」)のいずれを解析した場合でも、解析結果が「ぶどう」「葡萄」「グレープ」の3単語になることが確認できます。 林檎,アップル => りんご “=>” の左辺にある「林檎」(または「アップル」) を解析した場合、解析結果が “=>” 右辺の「りんご」になることが確認できます。 逆に、”=>” の右辺にある「りんご」を解析した場合は「りんご」のままです。 strawberry,苺 => ストロベリー,いちご “=>” の左辺にある「strawberry」(または「苺」) を解析した場合、解析結果は “=>” 右辺の「ストロベリー」「いちご」の2単語になることが確認できます。 逆に、”=>” の右辺にある「いちご」(または「ストロベリー」)を解析した場合は「いちご」(または「ストロベリー」)のままです。 このように、先にお話ししたとおりの結果になることが確認できるかと思います。 ということで、これで Synonym の設定方法は大丈夫そうですね。 ただし、 Synonym を追加した場合 (フィルタの追加などで解析方法を変更した場合)、当然ながら解析結果は変わります 。 そして、前回長々とお話ししたとおり、 solr の検索の要である インデックス は ドキュメントの登録時の解析結果 を元にしており、 後の設定変更には対応していません 。 このため、原則として Synonym を追加した場合 (勿論、他のフィルタを追加した場合などにも) は、登録済みのドキュメント・インデックスを一度削除して登録処理をやり直す 再インデックス が必要 になります。 ■Synonym とフィルタ順序 スキーマで “<filter>” 要素を追加する位置が重要 である、と先にお話ししましたが、こちらについて少し見てみましょう。 まず、今回行なった設定の状態で全角の「グレープ」と半角の「グレープ」をそれぞれ解析してみてください。 どちらも問題なく今回設定した Synonym により「ぶどう」「葡萄」「グレープ」の3単語に解析されるはずです。 では、”test-new-core” の “managed-schema.xml” で以下のように設定を変更してみてください。 (“synonymGraph” フィルタを、一行前の “cjkWidth” フィルタの前に持ってきます) #### 変更前 &ltfieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100"> &ltanalyzer> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &lt/fieldType> #### 変更後 &ltfieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100"> &ltanalyzer> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &lt/fieldType> 設定変更の後に “test-new-core” のリロードを行ったら、再度全角の「グレープ」と半角の「グレープ」をそれぞれ解析してみてください。 このとおり、半角の「グレープ」は今回設定した Synonym が適用されなくなっています。 なぜこのようなことになるかと言うと……  1. 解析処理は “managed-schema.xml” の 設定の上から順に 行われる  2. Synonym フィルタは日本語の半角文字と全角文字を区別している  3. 順序を入れ替えた “cjkWidth” フィルタが日本語の半角文字を全角文字に変換するフィルタだった ……からです。 このことからわかるように、 フィルタの設定順序は解析結果に大きく影響を与える 可能性があります。(これは即ち、検索結果がおかしくなる可能性があるということです。) そして、Synonym については Synonym フィルタを適用する時点での解析結果に合致させるように記述 しなければ効果がないということもわかるかと思います。 このため、Synonym を使いこなすには、もといフィルタを追加・変更する場合には、 事前に各フィルタの処理内容を把握しておくことが極めて重要 と言えます。 → Solr Reference Guide ■ちょっと高度な設定:インデックス登録時と検索時の解析方法を別々にする ここからは大分はみ出したお話しです。 まずは今回 Synonym に設定したこれをもう一度見てください。 ぶどう,葡萄,グレープ これは今回見てきたとおり「ぶどう」または「葡萄」「グレープ」を、これら3単語の全てを含むように変換する設定です。 ところで、solr は (解析結果で出てきた単語では) 原則 or 検索をします。 なので、よくよく考えてみると……  ・インデックス作成時にこの Synonym 処理をした場合、検索時には「ぶどう」「葡萄」「グレープ」のうちいずれか1つの単語が含まれていればよいため、検索時にはこの Synonym 処理をしなくても正常に意図したとおりの検索できる  ・検索時にこの Synonym 処理をしていれば、「ぶどう」「葡萄」「グレープ」のどれで検索しても、インデックスに「ぶどう」「葡萄」「グレープ」のいずれかを含むドキュメント全てに hit するため、インデックス作成時にこの Synonym 処理をしていなくても正常に意図したとおり検索できる ……ということで、実はインデックス時か検索時のどちらかでだけこの Synonym 処理をすれば事足りています。 特に、検索時だけ Synonym 処理をする場合は再インデックス処理の必要もなくなるので、Synonym 設定変更時の手間も減りそうです。(インデックスの容量削減も見込めます。) これを実現するための設定方法があるので、一応ここで紹介しておきます。 今回の設定変更を施した “test-new-core” の “managed-schema.xml” の変更例を見てみましょう。 #### 変更前 &ltfieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100"> &ltanalyzer> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &lt/fieldType> #### 変更後 &ltfieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100"> &ltanalyzer type="index"> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &ltanalyzer type="query"> &lttokenizer mode="search" name="japanese" userDictionary="lang/userdict_ja.txt" /> &ltfilter name="japaneseBaseForm"/> &ltfilter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/> &ltfilter name="cjkWidth"/> &ltfilter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/> &ltfilter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/> &ltfilter name="japaneseKatakanaStem" minimumLength="4"/> &ltfilter name="lowercase"/> &lt/analyzer> &lt/fieldType> 大規模に変更しているように見えますが、概ね <analyzer> ~ </analyzer> をコピーして 2つにしただけです。 <analyzer> にはそれぞれ “type” オプションを設定します。 “index” はインデックス時、”query” のほうは検索時の解析方法を設定 します。 この例では更に、”query” 側にだけ “synonymGraph” フィルタを設定しています。 折角なのでこの設定も一応試してみましょう。 “managed-schema.xml” の配置と設定のリロードを行なったら、例によって “Analysis” ページで確認していきます。 実はこのページ、左側がインデックス時の解析、右側が検索時の解析となっているため、この変更のチェックに最適だったりします。 このとおり、設定どおりに検索時にのみ Synonym 処理がされていることが確認できるかと思います。 ただ、解析方法を変えるということは言うまでもなく解析結果も変わるということです。 solr はインデックス時と検索時それぞれの解析結果をもって検索を行うため、これはつまり下手をすれば検索が機能しなくなる危険性があるということです。 例えば今回のこの Synonym 設定です。 林檎,アップル => りんご このセクションでの “managed-schema.xml” の設定下では、  ・インデックス時は Synonym 処理がされないので、インデックスには「林檎」や「アップル」で登録される  ・検索時には Synonym 処理されるので、「林檎」で検索しても「りんご」のインデックスを持つドキュメントしか出てこない (「林檎」で検索しているのに「林檎」のインデックスを持つドキュメントが出てこない) というおかしなことになってしまいます。 この解析方法の分割設定を実施したい場合、自分が何をしようとしているのか、本当に設定しても大丈夫なのかを十分に検討した上で、細心の注意を払い、入念に検証を行なった上で取り掛かることをおすすめします。 ■最後に 今回は solr の Synonym とフィルタ設定についてお話ししてみました。 ここまで数回に渡って solr についてお話しして何となく察してもらえたかと思いますが、 solr は導入して適当にデータを入れれば即便利!というもの ではなく 、 入念な準備と工夫 をすることで 検索時 の利便性・快適さ を提供できるツールです。 なので、solr が力を発揮するのは例えばマニュアルサイトや EC サイトなど、不特定多数の人が検索を行い得る環境であると言えるでしょう。 今回の一連の記事で一通りの基本的な要素をお話しできたかとは思いますが、他にもあいまい検索や N-Gram 検索を実装したりなど様々な設定・フィルタがありますので、気になった方は是非一度試して自分なりの最強の検索環境を作ってみてはいかがでしょうか。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Solr って何者?⑤:解析内容を調整する② (Synonym) first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの遠藤です。 前回はReact Router v7でMSWを利用する方法を整理しました。 2025-02-27 React Router v7のブラウザ開発環境でMSWを利用する方法 今回はNext.jsのApp routerでMSW(Mock Service Worker)を利用する方法について整理していきます。 はじめに 今回の内容は以下のDraft状態のmsw exampleのPull requestを参考に作成しています。 https://github.com/mswjs/examples/pull/101 記事執筆を行っている2025/03の段階ではDraftかつ、Next.js側の問題でブラウザ側でのHMR(Hot Module Replacement) の問題があることが以下のissueで言及されています。 https://github.com/mswjs/msw/issues/1644#issuecomment-2433234922 時間が経てば状況が変わることが予想されますので、そのときには本記事は参考程度にしていただき、上記のPull requestやissueの内容を確認していただければと思います。 MSWの準備を行う MSWを使用するために各種準備を行っていきます。Next.jsアプリは用意済みという前提で進めていきます。 MSWをインストールする 最初にMSWのインストールを行います。 npm install msw -D mockServiceWorker.jsをコピー MSWでは、worker scriptをアプリケーションのpulbicディレクトリに配置することでクライアント上でリクエストをキャッチできるようになります。こちらは以下の形でMSWのCLIを利用することで自分のディレクトリにworkerscriptである mockServiceWorker.jsがpublic直下に作成されます。 npx msw init ./public --save 統合モジュールを用意する server componentsとclient componentsで利用する統合モジュールを用意していきます。これらのファイルを配置するディレクトリとしてプロジェクトのrootディレクトリにmocksというディレクトリを用意してその中にファイルを配置していきます。 MSWのhandlersを定義する mockの内容となるMSWのhandlersをmocks/handlers.tsに定義します。 // mocks/handlers.ts import { graphql, http, HttpResponse } from "msw"; export type User = { firstName: string; lastName: string; }; export type Movie = { id: string; title: string; }; export const handlers = [ http.get<never, never, User>("<https://api.example.com/user>", () => { return HttpResponse.json({ firstName: "Sarah", lastName: "Maverick", }); }), graphql.query<{ movies: Array<Movie> }>("ListMovies", () => { return HttpResponse.json({ data: { movies: [ { id: "6c6dba95-e027-4fe2-acab-e8c155a7f0ff", title: "123 Lord of The Rings", }, { id: "a2ae7712-75a7-47bb-82a9-8ed668e00fe3", title: "The Matrix", }, { id: "916fa462-3903-4656-9e76-3f182b37c56f", title: "Star Wars: The Empire Strikes Back", }, ], }, }); }), ]; browser用の統合モジュールを作成する browser用(client component用)の統合モジュールをmocks/browser.tsに定義します。 // mocks/browser.ts import { setupWorker } from "msw/browser"; import { handlers } from "./handlers"; export const worker = setupWorker(...handlers); node.js用の統合モジュールを作成する node.js用(server component用)の統合モジュールをmocks/node.jsに定義します。 // mocks/node.ts import { setupServer } from "msw/node"; import { handlers } from "./handlers"; export const server = setupServer(...handlers); App routerでMSWを使用する ここからはapp以下で作業を進めていきます。 MSW用のProviderを作成する layout.tsxでMSW用のProviderをapp/mswProvider.tsxに定義します。このProviderで囲うことで、このProvider内のclient componentについてMSWを利用することが出来るようになります。 // app/mswProvider.tsx "use client"; import { handlers } from "@/mocks/handlers"; import { Suspense, use } from "react"; const mockingEnabledPromise = typeof window !== "undefined" && process.env.NODE_ENV === "development" ? import("@/mocks/browser").then(async ({ worker }) => { await worker.start({ onUnhandledRequest(request, print) { if (request.url.includes("_next")) { return; } print.warning(); }, }); worker.start(); console.log(worker.listHandlers()); }) : Promise.resolve(); export function MSWProvider({ children, }: Readonly<{ children: React.ReactNode; }>) { // If MSW is enabled, we need to wait for the worker to start, // so we wrap the children in a Suspense boundary until it's ready. return ( <Suspense fallback={null}> <MSWProviderWrapper>{children}</MSWProviderWrapper> </Suspense> ); } function MSWProviderWrapper({ children, }: Readonly<{ children: React.ReactNode; }>) { use(mockingEnabledPromise); return children; } layout.tsxでnode.js用の統合モジュールの呼び出しとmsw用のProviderでchildrenをラップする 続いてlayout.tsxにてserver側(Runtimeがnode.js)でMSWが利用できるようにします。また、先ほど作成したmsw用のProviderでchildrenをラップします。ここまで終われば準備完了です! // app/layout.tsx import type { Metadata } from "next"; import { Inter } from "next/font/google"; import { MSWProvider } from "./mswProvider"; if ( process.env.NEXT_RUNTIME === "nodejs" && process.env.NODE_ENV === "development" ) { const { server } = await import("@/mocks/node"); server.listen(); } const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={inter.className}> <MSWProvider>{children}</MSWProvider> </body> </html> ); } server component上でfetchを行ってみる ではまずはserver component上でfetchを行ってみましょう。app/page.tsxでhandlerで定義したapiを呼び出してみましょう。 // app/page.tsx import { User } from "@/mocks/handlers"; async function getUser() { const response = await fetch("<https://api.example.com/user>"); const user = (await response.json()) as User; return user; } export default async function Home() { const user = await getUser(); return ( <main> <p id="server-side-greeting">Hello, {user.firstName}!</p> </main> ); } 開発モードで起動して動作を確認してみると、handlerで定義したレスポンスが取れていることが確認できました! client component上でfetchを行ってみる 続いてclient component上でfetchを行ってみます。client componentとして実行されるように”use client”をつけてapp/movieList.tsxを作成します。 // app/movieList.tsx "use client"; import { Movie } from "@/mocks/handlers"; import { useState } from "react"; export function MovieList() { const [movies, setMovies] = useState<Array<Movie>>([]); const fetchMovies = () => { fetch("/graphql", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ query: ` query ListMovies { movies { id title } } `, }), }) .then((response) => response.json()) .then((response) => { setMovies(response.data.movies); }) .catch(() => setMovies([])); }; return ( <div> <button id="fetch-movies-button" onClick={fetchMovies}> Fetch movies </button> {movies.length > 0 ? ( <ul id="movies-list"> {movies.map((movie) => ( <li key={movie.id}>{movie.title}</li> ))} </ul> ) : null} </div> ); } page.tsxでmovieList.tsxを呼び出す そしたら作成したmovieList.tsxをpage.tsxに加えて動作を確認してみましょう。 // app/page.tsx import { User } from "@/mocks/handlers"; import { MovieList } from "./movieList"; async function getUser() { const response = await fetch("<https://api.example.com/user>"); const user = (await response.json()) as User; return user; } export default async function Home() { const user = await getUser(); return ( <main> <p id="server-side-greeting">Hello, {user.firstName}!</p> <MovieList /> </main> ); } ページを表示して 「Fetch movies」をクリックするとしっかりとclient component上でもfetch出来ていることを確認できました! まとめ 今回はNext.jsのApp routerでMSWを利用する方法についてまとめました。「はじめに」にも書きましたが、今回紹介した内容はDraftのPull requestを参考にさせていただいたものになっているので、本記事に関しては参考程度にしていただくのが良いかと思います。 ではまた~ 参考にさせていただいた記事 https://github.com/mswjs/msw/issues/1644 https://qiita.com/tarosuke777000/items/622e5ce3e3ace102560a ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Next.jsのApp routerでMSWをserver componentsとclient componentsで利用する方法 first appeared on SIOS Tech. Lab .
Entra Connectのパスワードの書き戻し(パスワードライトバック)とEntra IDのセルフサービスパスワードリセット(SSPR)を使用してEntra IDでユーザのパスワード変更、リセットを可能にする方法を紹介します。 Entra ConnectはActive Directory(AD)とEntra IDでユーザやグループ情報を同期するサービスです。 Entra IDでユーザのパスワード変更、リセットを可能にすることで、管理者への問い合わせやパスワードリセット作業が減り、人件コストを削減することができます。 今回紹介する方法により、Entra IDでユーザのパスワード変更、リセットを実施し、ADにパスワード情報を同期することができます。 使用環境 Image: Windows Server 2022 Datacenter – x64 Gen2 Size: Standard_D2as_v4 2vcpu 8GiB 前提 Active Directoryが構築済みであること (ドメイン名:example.com、管理者アカウント:EXAMPLE\azureuser) Active DirectoryにEntra ID同期対象のOUが含まれていること (OU名:Example Users) Entra Connectサーバが、ADサーバに対してドメイン参加済み (アカウント:EXAMPLE\exampleadmin)であること Entra IDのテナントが用意されていること Entra Connectのインストール インストール方法は過去の記事を参考にすることができます。当時はAzure Active Directory Connect (AADC)という名称でしたが、2025年2月現在はMicrosoft Entra Connect Sync (Entra Connect)となっています。また、Azure Active Directoryは、Microsoft Entra IDとなっています。 https://tech-lab.sios.jp/archives/21345 今回は以下の設定を実施します。 フォレスト(構成済みディレクトリ):example.com ドメインとOUのフィルタリングの同期OU:Example Users オプション機能にて、パスワードの書き戻しにチェックを入れて有効にします。 また、Entra IDでユーザの初回ログオン時にパスワード変更を必要としたい場合は、一時パスワードの同期を有効化する設定が必要です。設定方法は以下の記事を参考にしてみてください。 参考: https://blog.jbs.co.jp/entry/2024/09/30/115304 ユーザの確認 ADで以下のユーザを作成します。また、アカウントオプションで「ユーザーは次回ログオン時にパスワード変更が必要」とします。 UserPrincipalName 表示名 所属グループ 登録先OU 会社名 example_user01@example.com テスト ユーザ1 Group1 Example Users example.com example_user02@example.com テスト ユーザ2 Group1 Example Users example.com example_user03@example.com テスト ユーザ3 Group2 Example Users example.com example_user04@example.com テスト ユーザ4 Group2 Example Users example.com 過去記事 https://tech-lab.sios.jp/archives/21345 の「AADCの同期の方法」によりEntra IDとのアカウント同期を有効化します。 Microsoft Entra管理センターにログインし、ユーザが同期されることを確認します。 https://entra.microsoft.com/#home Entra IDからのSSPRは、「パスワードリセットのセルフサービスが有効」の項目で有効化することができます。 全てのユーザや特定のグループのユーザのみSSPRを有効にする設定が可能です。 参考: https://learn.microsoft.com/ja-jp/entra/identity/authentication/tutorial-enable-sspr SSPRの認証方法の設定は現在2通りの方法があります。 1: パスワードリセットの認証方法からリセットのために必要な方法の数および使用できる方法を設定する 2: 認証方法から、多要素認証(MFA)とSSPRの認証方法を構成する 1つ目の方法は、2025 年9月30日に非推奨となります。2025年2月現在は移行期間として、2通りの方法を選択できます。詳細は以下をご覧ください。 https://learn.microsoft.com/ja-jp/entra/identity/authentication/concept-authentication-methods-manage 今回は2つ目の方法で認証方法を構成します。Microsoft Authenticatorを使用できるように設定しています。 Entra IDからのパスワード変更を確認 テスト ユーザ1(example_user01)で https://www.microsoft365.com にサインインします。 ADおよびEntra IDではユーザの初回ログオン時にパスワード変更を必要とする設定にしているため、パスワードの更新が要求されます。パスワードを更新します。パスワードポリシーは、ADのパスワードポリシーに準拠します。 パスワードの更新後にADサーバのpowershellで以下のコマンドを実行します。distinguishedNameとPathが表示されると正しいパスワードが入力されていることになります。パスワードの変更がADに適用されていることを確認します。 参考: https://qiita.com/waokitsune/items/6dc37940095426485a57 > $de_ = New-Object System.DirectoryServices.DirectoryEntry( >> "LDAP://example.com", >> "example_user01", #ユーザID >> "NewPassword" #ユーザの更新後パスワード >> ) >> echo $de_ distinguishedName : {DC=example,DC=com} Path : LDAP://example.com Entra IDからのSSPRを確認する SSPRを確認するために、テスト ユーザ1(example_user01)で追加認証としてMicrosoft Authenticatorを設定しておきます。 Authenticatorの設定方法は以下の「Microsoft Authenticator の設定」を参考にしてみてください。 https://support.gluegent.com/hc/ja/articles/9434604489369–%E4%BB%98%E9%8C%B2-Microsoft-Authenticator-%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%96%B9%E6%B3%95 テスト ユーザ1(example_user01)のパスワード入力画面に戻り、パスワードを忘れた場合を選択します。 画面に従って、アカウントの回復のための認証を実施すると、パスワードリセット画面が表示されます。パスワードポリシーは、ADのパスワードポリシーに準拠します。 パスワードのリセットに成功すると、以下の画面が表示されます。 Entra IDからのパスワード変更を確認する手順と同様に、ADのpowershellで、パスワードの変更がADに適用されていることを確認します。 さいごに 今回は、Entra Connectのパスワードの書き戻し(パスワードライトバック)とEntra IDのセルフサービスパスワードリセット(SSPR)を使用してEntra IDでユーザのパスワード変更、リセットを可能にする方法を紹介しました。 Entra ConnectとEntra IDへの理解の一助になれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Entra Connect のパスワードライトバックとEntra IDのSSPRを使用してEntra IDでユーザのパスワード変更、リセットを可能にする first appeared on SIOS Tech. Lab .
はじめに こんにちはサイオステクノロジーの小野です。今回はOpenShift AIにデプロイしたLLMをVSCodeと連携させて、コード生成AIを利用する方法について解説します。また、VSCodeはOpenShift上で構築できるOpenShift Dev Spacesを利用します。これにより非接続環境でのコーディングでもAIによるコード支援を受けることができるようになります。 OpenShift Dev Spacesについて OpenShift上でアプリケーション開発を行う際に便利なツールとして、OpenShift Dev Spacesがあります。 OpenShift Dev SpacesはWeb ベースの統合開発環境 (IDE)です。クラウド上にデプロイされるので、利用するマシンに依存せずにどこでも利用できます。また、Devfileと呼ばれる開発環境を設定するファイルを利用してデプロイされるので、チーム内で開発環境の統合・共有がしやすくなります。 OpenShift Dev Spaces利用概要 本ブログの内容は下記章で構成されます: OpenShift Dev Spaces環境構築 OpenShift Dev Space利用手順 OpenShift Dev SpaceのVSCode拡張機能設定 OpenShift Dev SpacesとOpenShift AIの連携 最初にOpenShift Dev Spacesの構築手順について解説し、その操作方法について簡単に説明します。その後、Dev Spaces上のVSCodeにContinueという拡張機能を導入します。最後にContinueとOpenShift AIにデプロイしたLLMを連携させてコード支援機能が使えるようにする方法を解説します。 ローカルのVSCodeとOpenShift AIを連携させたい場合はDev Spacesの構築手順をスキップして、Continueの導入部分から参考にしてください。(リンク: Dev SpacesとOpenShift AIの連携 ) OpenShift Dev Space環境構築 OpenShift Dev Spacesの構築手順について説明します。 Openshift DevSpace前提条件 OpenShift:4.17 CPUアーキテクチャ:AMD64 OpenShift クラスターにサーバ証明書設定済み 参考: https://docs.redhat.com/ja/documentation/red_hat_openshift_dev_spaces/3.18/html/administration_guide/preparing-the-installation#supported-platforms Operatorインストール 最初にOpenShift Dev SpacesのOperatorをインストールします。 OperatorHubで「Dev Spaces」と検索してRed Hat OpenShift Dev Spacesをインストールします。 OpenShift Dev Spacesの詳細 インストール時の設定はデフォルトにします。 Operatorのインストール設定。今回はデフォルトでインストールする。 ステータスがSucceededになればインストール完了です。 ステータスがSucceededとなればOperatorインストール完了 CheCluster設定 次にDev spacesのCRを作成します。Red Hat OpenShift Dev Spaces instance Specificationのインスタンスを作成します。 Red Hat OpenShift Dev Spaces instance Specificationの作成 今回はデフォルトで設定します。設定の詳細は公式ドキュメントを参照してください。 https://docs.redhat.com/ja/documentation/red_hat_openshift_dev_spaces/3.18/html/administration_guide/configuring-devspaces#configuring-devspaces CheClusterの作成。今回はデフォルトで作成する。 管理コンソールアクセス CRが作成できたら、その詳細画面のRed Hat OpenShift Dev Spaces URLから管理コンソール画面に移動できます。 CheClusterの詳細画面から、Dev SpacesのWebコンソールへのURLを開く。 OpenShift Dev Spacesの管理コンソール画面 OpenShift Dev Space利用 ワークスペースの作成 VSCodeの環境を作成します。Select a SampleのEmpty Workspaceを選択します。 Select a SampleのEmpty Workspaceを選択する 作成が完了するまで待ちます。 作成完了まで待つ 作成が完了するとVSCodeの画面が表示されます。このVSCode上で作業を行います。 WorkSpaceの作成が完了するとVSCodeが表示される VSCode簡易操作 VSCodeの操作についてこれから簡単に説明します。すでに利用したことがある方は飛ばしてください。 Open Folderからフォルダを開けます。 Open Folderからフォルダが開ける 左上のメニューからFile > New Fileでファイル作成できます。 File > New Fileでファイル作成できる 左上のメニューからTeminal > New Terminalでターミナルを開くことができます。 Terminal > New Terminalからターミナルを開ける ターミナルが表示される VSCode拡張機能設定 普段私たちがデスクトップ上で利用しているVSCodeはMicrosoftがカスタマイズしたVSCodeになっています。しかし、Dev Spaces上のVSCodeはカスタマイズされていないVSCodeなのでいくつかの差異があります。一番の大きな違いとしてMicrosoft Marketplaceが入っていないので拡張機能を自分で導入する必要があります。 導入する手順としては最初に OpenVSXレジストリ から自分が利用したい拡張機能のVSIXファイルをダウンロードします。 OpenVSXに公開されているVSCodeの拡張機能 次にダウンロードしたVSIXファイルをワークスペースにアップロードします。 ダウンロードしたファイルをWorkspaceにアップロードする アップロードされた拡張機能ファイル アップロードしたら拡張機能のメニューの三点リーダーからInstall from VSIXを選択して、アップロードしたVSIXファイルを選択します。 Install from VSIXから拡張機能をインストール 選択するとアップロードした拡張機能が利用できるようになります。 利用できるようになった拡張機能 拡張機能を実際に利用した様子 Dev SpacesとOpenShift AIの連携 OpenShift AIにデプロイしたLLMを利用して、Dev Spacesにコードアシスタント機能を導入する方法を解説します。 以前の記事を参考にして、OpenShift AIにLLMをデプロイしておいてください。 OpenShift AIにLLMをデプロイしてみた Continueの導入 VSCode上でコードアシスタント機能を利用するにはContinue拡張機能をインストールする必要があります。Dev SpacesにはデフォルトでContinue拡張機能がインストールできるようになっているので、インストールします。なければ先ほどのようにOpenVSXレジストリからダウンロードしてください。 https://open-vsx.org/extension/Continue/continue Continue拡張機能をインストールする インストールすると左のメニューにContinueのアイコンが追加されます。 Continue拡張機能のメニュー ContinueとOpenShift AI連携 下の歯車マークを押すとContinueの設定ファイルが表示されます。 歯車マークから設定を行う この設定ファイルにOpenShift AIのLLMAPIの情報を記載します。まずmodelsに以下を上書きします。<タイトル名>にはContinueで表示される名前を入力し、<モデル名>にはOpenShift AIにデプロイしたLLMのモデル名を入力し、<APIのエンドポイント>はデプロイしたLLMのExtenalの方のエンドポイントを入力し、<APIのトークン>はデプロイしたLLMのAPIのトークンを入力してください。 { "title": "<タイトル名>", "model": "<モデル名>", "apiBase": "<APIのエンドポイント>/v1/", "provider": "openai", "apiKey": "<APIのトークン>" } また、tabAutocompleteModelに同様の設定を上書きすると、タブ補完でAIチャット機能を利用できるようになります。 modelsとtabAutocompleteModelを編集する 設定できたら、モデルとしてOpenShift AIにデプロイしたLLMが選択肢に出るようになります。 OpenShift AIにデプロイされたLLMが表示される 動作確認 動作確認としてPythonのHello Worldの書き方を聞いてみます。するとこのように回答してくれることが確認できます。 チャットボックスに質問してみた また、コード生成機能も試してみます。適当なファイルを作成して、Ctrl + Iを押して、どんなプログラムを書いてほしいか入力します。 素数を計算するコードを書いてもらうようにお願いしてみる すると自動的にコードを作成してくれることが確認できます。 コードを自動生成してくれる デプロイしたLLMが対応している場合、タブ補完機能も利用できます。 コードを書くと、自動的にコードの続きを提案してくれる タブ補完を続けると自動的にコードが完成する おわりに 以上の操作によりOpenShift Dev SpacesのVSCodeでAIによるコード支援を受けることができるようになりました。OpenShift AIにデプロイしたLLMはローカルLLMであるので、コード支援機能に対して秘密情報を入力したとしても外部に漏れる心配はありません。高いセキュリティを保ったままコード支援機能を利用できるのでぜひ構築してみてください。 参考 OpenShift Dev Spaces公式ドキュメント: https://docs.redhat.com/ja/documentation/red_hat_openshift_dev_spaces/3.18 https://developers.redhat.com/learn/openshift-ai/integrate-private-ai-coding-assistant-your-cde-using-ollama-continue-openshift-dev-spaces https://rheb.hatenablog.com/entry/2023/05/26/140300 https://ai-on-openshift.io/demos/codellama-continue/codellama-continue/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIとOpenShift Dev Spaces連携 ~コード生成AIで楽々開発~ first appeared on SIOS Tech. Lab .
こんにちは、OSSよろず相談室のSKです。 日々、多くのOSSに関するお問い合わせをいただく中で、今回は rsyslog に関するご相談がありました。 「特定のログファイルから ERROR を含むログだけを抜き出して、システムログ(/var/log/messages)に転送したい」 そんなニーズに対して、rsyslog の Ruleset 機能 を活用することで解決できました。 同じような要件でお困りの方もいるかもしれませんので、今回の対応内容を紹介します。 やりたいこと 以下のログファイルに記録されるログのうち “ERROR” という文字列を含むログが出力されたら、 /var/log/messages にも出力したい 常時 /var/log/messages に出力される OS や ネットワークなどシステム関連のログ出力はそのままにしたい。 対象のログファイル: /usr/local/share/oss-software/logs/system.log 実現方法 以下が ‘/etc/rsyslog.conf’ に追加した設定内容の全体です。 *.info;mail.none;authpriv.none;cron.none /var/log/messages module(load="imfile") input(type="imfile" File="/usr/local/share/oss-software/logs/system.log" Tag="oss-softError" Severity="info" Facility="local0" ruleset="extra-fileError") ruleset(name="extra-fileError") { if $msg contains 'ERROR' then { action(type="omfile" file="/var/log/messages") } } 1つずつ見ていきましょう。 /var/log/messages の既存設定は維持する *.info;mail.none;authpriv.none;cron.none /var/log/messages module ブロックで imfile モジュールのロード module(load="imfile") rsyslog には「モジュール」という概念があり、デフォルトではカーネルログや標準の syslog ログを処理する機能のみが有効になっています。 imfile は、ファイルを監視してログとして取り扱うためのモジュール です。 そのため、外部ログを rsyslog に取り込むためには、まずこのモジュールをロードする必要があります。 この行がないと、rsyslog は外部のログファイルを監視できません。 input ブロックで外部ログファイルの監視設定 テキストファイルを読み込む設定をします。ここで監視対象のログファイルを指定します。 どのログファイルを監視し、どのように処理するかを指定します。 input (type="imfile" …) typeに 2.でロードした imfile モジュールを指定します。 File="/usr/local/share/oss-software/logs/system.log" 監視対象のログファイルのパスです。 このファイルに新しいログが書き込まれると、rsyslogがその内容を取得して処理を行います。 Tag="oss-softError" ログのタグ(プレフィックス)を設定します。 このタグは、ログメッセージの識別に役立ちます。 ログメッセージの冒頭にこのタグが付加されて出力されます。 Severity="info" ログの重要度(Severity)を指定します。 rsyslogでは、ログの重要度(Severity)を指定することができます。 重要度には、 emerg, alert, crit, err. warning, notice, info, debug があります。 今回の設定では Severity=”info” となっているため、このログは「情報レベル」のログとして扱われます。 Facility="local0" ログの分類(Facility)を指定します。 この分類によって、ログを異なるファイルに振り分けたり、特定のフィルタを適用したりすることが可能になります。 今回の設定では、 local0 を使用しています。 これにより、local0.* のログを特定のファイルに保存したり、処理を分けたりすることができます。 ruleset="extra-fileError" 適用する Ruleset(処理ルール)を指定します。 ruleset は、特定のルールに基づいてログを処理するための仕組みです。 この設定では、 ruleset="extra-fileError" を指定しているため、このログは extra-fileError という名前のルールセットに従って処理されます。 extra-fileError というルールセットはこの後設定します。 Ruleset を定義 “ERROR” を含むログのみを /var/log/messages に出力するルールセットを定義します。 ruleset(name="extra-fileError") { if $msg contains 'ERROR' then { action(type="omfile" file="/var/log/messages") } } このルールセットでは、 if $msg contains 'ERROR' then という条件を設定し、ログメッセージに “ERROR” が含まれている場合に限り、 /var/log/messages に書き込むようにしています。 出力テスト /var/log/messages に、ERRORという文字を含むログだけが書き込まれるか、確認します。 echoコマンドで、/usr/local/share/oss-software/logs/system.logに書き込んでみます。 ERRORを含むログ出力   # echo "ERROR [Test] oss-software failed" | sudo tee -a /usr/local/share/oss-software/logs/system.log   →/var/log/messagesに以下が出力された 出力結果 Mar 13 09:52:31 ip-172-31-1-204 oss-softError ERROR [Test] oss-software failed Mar 13 09:52:31 : 日時 ip-172-31-1-204 : ホスト名 oss-softError : 2の(2)で設定したタグ ERROR [Test] oss-software failed : echoコマンドで指定した文字列 ERRORを含まないログ出力 # echo "$(date) INFO [Test] oss-software failed" | sudo tee -a /usr/local/share/oss-software/logs/system.log →/var/log/messagesに何も出力されない。 参考情報 Ruleset について詳しく知りたい方は、公式ドキュメントもご参照ください。 rsyslog / Multiple Rulesets in rsyslog RedHat社のロギング説明も合わせてご参照ください。 RedHat 8 / 第8章 ロギングの設定 まとめ 今回は、 rsyslog の Ruleset 機能 を活用することで、特定のログファイルから “ERROR” を含むログのみを抽出し、システムログ /var/log/messages に転送する方法をご紹介しました。 この設定を応用すれば、特定のエラーログだけをフィルタリングして通知したり、別のログファイルに転送したりすることも可能 です。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OSSサポートエンジニアの現場から!特定の条件のログを/var/logs/messagesにも出力したい first appeared on SIOS Tech. Lab .
佐賀大学では2000年より認証統情報の統合を進められており、 その成果を踏まえて2007年度から毎年統合認証に関するシンポ ジウムが開催されています。   2025年3月10日には「第17回 統合認証シンポジウム」が実施され、そこで弊社エンジニアの武井が登壇しました。 「Shibboleth IdP」 の紹介とShibboleth周辺の拡張ソリューションについて の説明を行い、ご参加いただいた方から多くのご質問をいただき、 興味関心を抱いていただけました。   <ご登壇者> ・「インターネットトラストが広げるデジタルサービス」   佐藤周行 様( 国立情報学研究所 ) ・「新学認に向けた中規模実証実験の取組み(仮)」   西村健 様(国立情報学研究所) ・「デジタル認証アプリを使ったマイナンバーカードの利活用推進について」   青野彰太朗 様(デジタル庁戦略組織グループ) ・「Shibboleth IdP WebAuthn authentication プラグインの紹介等」   大谷誠 様(佐賀大学)  ・「Shibboleth IdPの運用をもっと快適に!」   武井宜行(サイオステクノロジー株式会社)  ・「認証基盤の畳み方〜機構法人認証基盤への移行顛末〜」   田中昌二 様(東海国立大学機構) ・「大学の認証システム: これまでとこれから」   只木進一 様 (佐賀大学) 今回のシンポジウムでは学認からデジタル認証アプリを使ったマイ ナンバーカードの活用まで、幅広い題材の講演で終始学ぶことが多く、 有意義な時間を過ごせました。 また講演終了後は情報交換会が行われました。 普段接することができない方々との交流ができたため貴重な時間が 過ごせました。 今回の経験でさらに広がった知見を今後の活動に活かしていきたい と感じました。   関係者の皆様、 ご参加いただいた皆様、誠にありがとうございました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 第17回 統合認証シンポジウムで登壇しました first appeared on SIOS Tech. Lab .
始めに ども!最近は登壇資料を全力で作成しており、いろんなことが後回しになっている龍ちゃんです。3月に入ってしっかりブログ更新の手が止まってしまっていました。なので、直近の業務でブログ化できそうなところを書いていきます。 今回のお話は「Figmaで作成する図:スケジュール編」となります。 スケジュール時間経過:Figmaデザイン プレゼン資料からブログコンテンツまで、スケジュールを表現するコンテンツは、テンプレートとして所持しておいて損はありません。そんな「スケジュール」や「時間経過」を表現するコンポーネントのサンプルを貼っておきます。 今回使用しているフォントは以下の二つになります。一つは有料フォント(無料版あり)、一つは無料フォントとなります。 LINE Seed JP LINEで使われているフォント(セリフ体)商用無料で使えるため超おすすめ! ダウンロードはこちら ビルの谷間と高架下 BOOTHで販売されているとてもかわいい日本語フォント 無料版もあり (条件アリ) これは買う価値あり !! 上記二つは、僕のFigmaでは高頻度で登場しています。 多色・横並び こちらの図解で使用している色は以下になります。 説明 カラーコード 赤 #FD504F 緑 #5BB85A 黄 #F4C84C 青 #1898DA 文字色 #2C303A こちらは、最大4つの工程表現に向いています。これ以上色を使用すると目に優しくないかと考えています。色も単色ではなく、若干淡い色(マットな表現)を意識して作成しています。 上部の時間経過を表現しているコンポーネントの作成方法としては、フレーム内に先端と文字領域用のフレームを配置しています。 三角形の部分を「拡大・縮小」にしておくことで、大元のフレームを操作しても形が崩れずに遷移します。Figmaで四角形を描画して、描画ツールで直接点を編集すると簡単に図を接合することができます。 単色横並び こちらの図解で使用している色は以下になります。 説明 カラーコード 円・文字色 #6D49FF 横線 #A590FA 上部文字色 #2C303A こちらは、スケジュールよりもステップの表現に利用できます。もちろんスケジュールとしても表現することができますが、ステップなどの表現のほうが直感的に理解しやすいかと思います。 こちらは画面上部に配置し、下部にコンテンツを配置に向いています。WEBサイトのフォームなどでも使用することができる表現です。 単色縦並び こちらの図解で使用している色は以下になります。 説明 カラーコード 円・線・時間表現 #6D49FF 上部文字色 #2C303A こちらは一ページを割いて表示するコンテンツとなります。目次としても利用可能です。目次として利用する場合は、以下のように要素に透明化を入れることで、トピックを明確にすることができます。 おわり 今回は、Figmaでスケジュールや時間経過を表現するコンポーネントのサンプルを紹介しました。これらのデザインは、プレゼン資料やブログ記事など、様々な場面で活用できます。一つのテンプレートとして保存しておくことで、効率的な資料作成が可能になりますので、ぜひ参考にして自作のコンポーネントを作成してみてください! 生成AIを活用したコンテンツ作りにも、取り組んでいます。ぜひ閲覧してみてください。「 プレゼン資料が見違える!AI図解ツールNapkin AIの基本と実践的な使い方完全版 」 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Figmaプレゼン資料を爆速で作る!時系列デザインサンプル|カラーコード付き first appeared on SIOS Tech. Lab .
はじめに Kubernetes環境でのストレージ管理は、アプリケーションの可用性やスケーラビリティに大きく関わります。 本記事では、Kubernetes向けの代表的なストレージソリューションである ODF(Red Hat OpenShift Data Foundation)・Longhorn・MinIO の3つを紹介し、それぞれの特徴や用途について解説します。 各ストレージソリューションの概要 ODF(OpenShift Data Foundation) ODF(OpenShift Data Foundation)は、Red Hat OpenShift向けに最適化されたソフトウェア定義ストレージ(SDS)ソリューションです。 Cephを基盤とした分散ストレージを提供し、ブロック・ファイル・オブジェクトストレージのすべてをサポートします。 特徴 Cephベースの分散ストレージ :高可用性・スケーラビリティを備えた分散ストレージを提供 OpenShiftとの統合 :Red Hat OpenShift向けに最適化されており、簡単にセットアップ可能 マルチプロトコル対応 :ブロック(RBD)、ファイル(CephFS)、オブジェクト(S3互換)をサポート 大規模環境向け :商用サポートや監視機能が充実しており、大規模環境に適している 商用サポートや性能面からOpenShiftでの特に大規模な環境での利用が見込まれます。 Longhorn Longhornは、Rancherが開発した 軽量な分散ブロックストレージ ソリューションです。 Kubernetesクラスタ内で動作し、データの冗長化やスナップショット管理などの機能を提供します。 特徴 : Kubernetesネイティブ :すべての機能がKubernetes上で動作し、CSI(Container Storage Interface)を利用 軽量でシンプルな設計 :Cephのような大規模な構成不要で、小規模クラスタにも導入しやすい スナップショットとバックアップ機能 :データの保護や復元が簡単に行える オープンソース :完全にオープンソースで、誰でも利用可能 小規模から大規模の様々なKubernetes環境での利用が見込まれます。 MinIO MinIOは、 S3互換のオブジェクトストレージ を提供するオープンソースのストレージソリューションです。 Kubernetesクラスタ上で分散オブジェクトストレージをシンプルに構築できます。 特徴 : Amazon S3互換 :AWS S3 APIと高い互換性を持つ 高速なパフォーマンス :大量の小さなファイルや大きなデータセットの保存に最適 Kubernetesネイティブ :Helmチャートなどを用いたデプロイが容易 スケーラブル :ストレージノードを追加することで容易にスケール可能 Amazon S3互換のAPIを扱うことが可能であり、オブジェクトストレージとしての利用が見込まれます。 どのストレージが活用シーンに合っているか? RedHat環境やOpenShiftでの大規模環境なら ODF Rancher環境や軽量な分散ブロックストレージなら Longhorn S3との互換性や軽量なオブジェクトストレージが必要なら MinIO 組み合わせたハイブリッド運用も可能 それぞれのストレージもエンタープライズ版、商用サポートが有るため商用環境での有力な選択肢となってきます。 まとめ Kubernetes環境におけるストレージソリューションは多様で、用途に応じて適切な選択をすることが重要です。 本記事で紹介したODF・Longhorn・MinIOの特徴を理解し、最適なストレージを選択してください! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post コンテナプラットフォームで活用出来るストレージサービス(ODF / Longhorn / MinIO )とは? first appeared on SIOS Tech. Lab .
挨拶 最近は新しい登壇資料を準備して、頑張って執筆している龍ちゃんです。YouTubeやXなどで情報収集しながら、新しいAIツールを見つけたので使用レポートと具体的な使用方法、注意点などをまとめて書いていこうと思います。 今回のお話は「メモ帳と生成AI描画ツールが合体したツールNapkin AI」についてです。 Napkin AIとは Napkin AI はテキスト入力をするだけで、グラフや図解を自動生成してくれるAIツールになります。プレゼン資料の図解などで使用することができる、ちょっとおしゃれな図を生成してくれるのですごく助かります。 龍ちゃん 2025年3月12日時点で、beta版ですべての機能が無料で使用することができます。ぜひ試して!!! 描画画面 画面は海外のメモ帳みたいな雰囲気があります。マークダウン形式で入力することができます。 図の生成 テキストを入力したら、左側に生成ボタンが出てきます。 数秒の経過時間後、描画とポップアップにスタイルの提案が出力されます。 ポップアップの中から、スタイルを決定することで描画が確定します。描画後では、以下の設定を変更することができます。 項目 説明 Download ダウンロード設定を開くことができます。 Background Color 背景色の設定 Aspect Ration 描画の比率の設定 Change Style 描画図のスタイル変更 描画ダウンロード 描画のダウンロードでは「PNG・SVG・PDF」の項目から選択することができます。 透過PNGとSVGが選択することができるので素晴らしいです。 スタイルの選択 描画画面の右上の「Styles」から好きなスタイルを選択することができます。スタイルを限定しておくことで、統一感のある描画を生成することができます。 デフォルトで選択肢が15個もあるため、お気に入りのスタイルが見つかるかもしれません。 具体的な活用方法 ここまでは、「Napkin AI」のデフォルトの使用方法について解説してきました。実際に使用して登壇資料を3本ほど作成したので、具体的な使用感についてまとめていきます。Napkin AIを使用して作成した図に関しては、「 【GAS】Difyプロトタイプを本格業務アプリに!実践的な自動化 」で公開しています。 一部分だけ活用する 「Napkin AI」上でも編集をすることができます。ですが、SVGでエクスポートすることができるためFigma上で描画した情報を使用することができます。実際に登壇で使用する描画が以下になります。 だんだん小さくなる描画を「Napkin AI」で生成しています。このような描画は作成コストが高いので、さくっと描画してくれるのが助かります。 周りの装飾部に関しては、自前で作成しています。表現としてもバランスが良くなって個人的にお気に入りの一枚です。 図の参考にする こちらは、作成前にいったん作ってみるという使い方になります。スタイル選択では、いろいろな描画を見ることができます。生成AIからの出力なので、一度に複数パターンの描画を見ることができます。 その中からイメージに近いものを参考図として、Figmaで作成しました。以下の図を「Napkin AI」の出力を参考に作成しました。 終わり 今回は「Napkin AI」について紹介させていただきました。テキスト入力だけで素敵な図解を生成できる便利なツールなので、ぜひ皆さんも試してみてください。今後も新しいAIツールの紹介をしていきたいと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post プレゼン資料が見違える!AI図解ツールNapkin AIの基本と実践的な使い方完全版 first appeared on SIOS Tech. Lab .
Difyは。自身のプラットフォーム内に検索用データベースを持っています。デフォルトでは、Weaviateを使いますが、PostgreSQLやChromaなど多彩なデータベースに対応しています。そして、自プラットフォーム内に検索データベースを持つことで、別途検索データベースを用意することなく、LLMアプリの導入コストを抑えることができます。   しかしながら、Azure AI SearchやElastic Search、Vertex AI Searchなど自プラットフォーム外の検索サービスを使いたい場合もあると思います。既にこういったサービスで検索データベースを提供している場合はなおさらでしょう。これらのサービスは、お値段も少々高いですが、高機能ですし、エンタープライズ向けの検索データベースとしては広く使われていますし、こういったものを導入したいというニーズもあると思います。   Difyはこういったニーズにも対応しています。この自プラットフォーム外にある検索データベースのことをDifyでは「外部ナレッジベース」と呼びます。 システム構成 外部ナレッジベースを利用するためのシステム構成は以下のとおりです。 Difyが外部ナレッジベースにアクセスするためには、Difyの準拠するAPIの仕様に従わなければなりません。しかしながら、外部ナレッジベースは、そのサービスによって様々なAPIを持つので、この差分を吸収するために、Difyと外部ナレッジベースの間にプロキシのような役割を持つAPIを設ける必要があります。それが上図の「API」と書かれているコンポーネントになります。 このプロキシのような役割を持つAPIは独自に開発する必要があります。これをDifyでは「外部ナレッジベースAPI」と呼びます。 外部ナレッジベースAPI 外部ナレッジベースのAPIの仕様は以下のとおりです。 リクエスト ■ エンドポイント /retrieval ■ メソッド Post ■ ヘッダー Authorization: Bearer {APIキー} ■ ボディ { "knowledge_id": "{ナレッジを一意に識別するID}", "query": "{検索クエリ}", "retrieval_setting":{ "top_k": {上位何件を取得するか}, "score_threshold": {スコアの閾値} } } {APIキー}は外部ナレッジベースAPIの認証に使われるキーです。このキーは外部ナレッジベースAPIの管理者が発行します。 {ナレッジを一意に識別するID}は外部ナレッジベース内のナレッジを一意に識別するためのIDです。Difyで外部ナレッジベースを追加する際に任意の値を設定します。 {検索クエリ}は検索するためのクエリです。 {上位何件を取得するか}は検索結果の上位何件を取得するかを指定します。Difyで外部ナレッジベースを追加する際にこの値を設定します。 {スコアの閾値}は検索結果のスコアの閾値を指定します。スコアがこの閾値を超えるナレッジのみを取得します。Difyで外部ナレッジベースを追加する際にこの値を設定します。 レスポンス Difyは以下のようなレスポンスを受け取ることを期待します。 ■ ステータスコード 200 ■ ヘッダー Content-Type: application/json ■ ボディ { "records": [ { "metadata": { "path": "{ドキュメントへのパス}", "description": "{ドキュメントの説明}" }, "score": {検索スコア}, "title": "{ドキュメントのタイトル}", "content": "{ドキュメントの内容}" }, ...略... ] } {ドキュメントへのパス}は検索結果のナレッジが存在するドキュメントへのパスです。例えばAzure Blob Storageにドキュメントを格納する場合は、 `https://example.blob.core.windows.net/{コンテナ名}/{ファイル名}` のような形式になります。 {ドキュメントのタイトル}は検索結果のナレッジが存在するドキュメントの説明です。 {検索スコア}は検索結果のスコアです。 {ドキュメントのタイトル}は検索結果のナレッジが存在するドキュメントのタイトルです。 {ドキュメントの内容}は検索結果のナレッジが存在するドキュメントの内容です。 外部ナレッジベースを利用する 外部ナレッジベースにAzure AI Searchを利用する場合の実装や設定を紹介します。先の仕様に準拠すればElasticsearchでもなんでも大丈夫です。 APIの実装 外部ナレッジベースを利用するためのAPIは以下のような実装になります。 Python + Flaskですが、APIの仕様を満たしていればフレームワーク、開発言語は問いません。 import os from flask import Flask, request, jsonify, abort from azure.search.documents import SearchClient from openai import AzureOpenAI from azure.core.credentials import AzureKeyCredential from azure.search.documents.models import VectorizedQuery from dotenv import load_dotenv # .envファイルから環境変数を読み込む。 load_dotenv(verbose=True) # 環境変数から各種Azureリソースへの接続情報を取得する。 SEARCH_SERVICE_ENDPOINT = os.environ.get("SEARCH_SERVICE_ENDPOINT") # Azure AI Searchのエンドポイント SEARCH_SERVICE_API_KEY = os.environ.get("SEARCH_SERVICE_API_KEY") # Azure AI SearchのAPIキー SEARCH_SERVICE_INDEX_NAME = os.environ.get("SEARCH_SERVICE_INDEX_NAME") # Azure AI Searchのインデックス名 AOAI_ENDPOINT = os.environ.get("AOAI_ENDPOINT") # Azure OpenAI Serviceのエンドポイント AOAI_API_VERSION = os.environ.get("AOAI_API_VERSION") # Azure OpenAI ServiceのAPIバージョン AOAI_API_KEY = os.environ.get("AOAI_API_KEY") # Azure OpenAI ServiceのAPIキー AOAI_EMBEDDING_MODEL_NAME = os.environ.get("AOAI_EMBEDDING_MODEL_NAME") # Azure OpenAI Serviceの埋め込みモデル名 # ユーザーの質問に対してドキュメントをAzure AI Searchから検索する関数 def search(question): # Azure AI SearchのAPIに接続するためのクライアントを生成する search_client = SearchClient( endpoint=SEARCH_SERVICE_ENDPOINT, index_name=SEARCH_SERVICE_INDEX_NAME, credential=AzureKeyCredential(SEARCH_SERVICE_API_KEY) ) # Azure OpenAI ServiceのAPIに接続するためのクライアントを生成する openai_client = AzureOpenAI( azure_endpoint=AOAI_ENDPOINT, api_key=AOAI_API_KEY, api_version=AOAI_API_VERSION ) # Azure OpenAI Serviceの埋め込み用APIを用いて、ユーザーからの質問をベクトル化する。 response = openai_client.embeddings.create( input=question, model=AOAI_EMBEDDING_MODEL_NAME, dimensions=1536 ) # ベクトル化された質問をAzure AI Searchに対して検索するためのクエリを生成する。 vector_query = VectorizedQuery( vector=response.data[0].embedding, k_nearest_neighbors=3, # 初期値。後続の処理でretrieval_settingのtop_kで絞る。 fields="contentVector" ) # ベクトル化された質問を用いて、Azure AI Searchに対してベクトル検索を行う。 results = search_client.search( vector_queries=[vector_query], select=['id', 'content'] ) return results # Flaskアプリケーションの定義 app = Flask(__name__) # 外部ナレッジベースの検索APIを提供するエンドポイント @app.route('/retrieval', methods=['POST']) def retrieval(): # ヘッダーのAuthorizationをチェックする # Difyからの外部ナレッジベースのHTTPリクエストAPIキーが正しいかどうかを確認する # ここではとりあえず、APIキーが"your-api-key"であることをチェックする auth = request.headers.get("Authorization", "") if auth != "Bearer your-api-key": abort(401) body = request.get_json() if not body: return jsonify({"error": "JSON body required"}), 400 # リクエストボディから必要なパラメータを取得する。 knowledge_id = body.get("knowledge_id") query = body.get("query") retrieval_setting = body.get("retrieval_setting", {}) top_k = retrieval_setting.get("top_k", 3) score_threshold = retrieval_setting.get("score_threshold", 0.0) if not query or not knowledge_id: return jsonify({"error": "knowledge_id and query are required."}), 400 # search関数を用いて検索を実施する。questionはqueryに対応する。 results = search(query) records = [] count = 0 # 検索結果を変換して、score_threshold以上の結果をtop_k件まで抽出する。 for result in results: score = result.get('@search.score', 0) if score < score_threshold: continue if count >= top_k: break # 変換例: idをファイル名として利用(仮実装) record = { "metadata": { "path": f"https://example.blob.core.windows.net/knowledge/{result.get('id')}.txt", "description": "dify知識ドキュメント" }, "score": score, "title": f"{result.get('id')}", "content": result.get('content') } records.append(record) count += 1 return jsonify({"records": records}), 200 if __name__ == '__main__': # Flaskアプリを起動する app.run(host='0.0.0.0', port=5001) Difyの設定 それではDify側の設定を行います。 ■ 外部ナレッジAPIの追加画面を表示する 「ナレッジ」をクリックし(①)、「外部ナレッジAPI」をクリックします(②)。そして、「+外部ナレッジAPIを追加する」をクリックします(③)。 ■ 外部ナレッジAPIを追加する 「Name」には外部ナレッジAPIを識別する任意の名称を入力します(①)。「API Endpoint」には外部ナレッジAPIのエンドポイントを入力します(②)。「/retrieval」を除いたURLを入力します。「API Key」には外部ナレッジAPIのAPIキーを入力します(③)。最後に「セーブ」をクリックします(④)。 ■ 外部ナレッジベースを追加する画面を表示する 「外部ナレッジベースへの接続」をクリックします。 ■ 外部ナレッジベースを追加する 「外部ナレッジ名」には外部ナレッジベースを識別する任意の名称を入力します(①)。「ナレッジの説明」には外部ナレッジベースの説明を入力します(②)。「外部ナレッジAPI」には、先ほど追加した外部ナレッジAPIを選択します(③)。「ナレッジID」には外部ナレッジベース内のナレッジを一意に識別するIDを入力します(④)。「トップK」には検索結果の上位何件を取得するかを入力します(⑤)。「スコアの閾値」には検索結果のスコアの閾値を入力します(⑥)。最後に「繋ぐ」をクリックします(⑦)。 ■ チャットボットに外部ナレッジベースを接続する 外部ナレッジベースに接続するチャットボットを作成してみます。チャットボットの設定画面にて、コンテキストの「+追加」をクリックします。 ■ 外部ナレッジベースを選択する 先ほど作成した外部ナレッジベースを選択します(①)。そして、「追加」をクリックします(②)。 チャットフローの場合には、「知識取得」のブロックにて、同様の方法で外部ナレッジベースを選択します。 ■ 詳細な設定を行う 外部ナレッジベースを選択すると、詳細な設定が表示されます。Rerankモデルの利用や、検索結果の上位何件を取得するかやスコアの閾値を設定することができます。 ■ テストする チャットボットをテストしてみます。チャットボットに質問を投げて、外部ナレッジベースからの回答を確認します。 まとめ 外部の検索システムを利用することで、さらにDifyをパワーアップすることができます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Difyで外部の検索データベースを使う first appeared on SIOS Tech. Lab .
はじめに こんにちは!年度末で複数プロジェクトにてんやわんやのなーがです。皆さん生成AI使っていますか?DeepSeekやDifyなど最近は特に新しいAIサービスの大豊作となっています。前回はDifyの内容についてでしたが、今回はClaude Code使ってみたについて書こうと思います。 Claude Code Claudeは最近3.7がリリースされたのでご存知の方も多いと思います。 Claude Code は2週間前にリリースされたターミナル上でClaudeを使って自然言語コマンドを通じてより速くコーディングを支援するエージェント型コーディングツールです。実行には Anthropic API の クレジットが必要 です。(今回は初回登録で貰えたクレジットを使用しています) インストール こちら から。 npm install -g @anthropic-ai/claude-code 実行したいリポジトリで claude と入力します。 スタイルを訊かれるのでお好みのものを選択。 Enterを押して認証します。 認証が完了したら、フォルダ内のファイルが信頼できるか訊かれるのでEnter スラッシュを入力してコマンドを実行します。補完が表示されるので分かりやすいです。 最初に初期化すると CLAUDE.md が作成されます。 CLAUDE.md は開発ガイドラインと書いてあり、コードの内容を読み取った結果からビルド方法やコードスタイルが記載されています。 /init リポジトリの説明をしてもらうと、コメントを参照していますがかなり詳細に答えてくれてます。(塗りつぶしが多くてすみません…) また、あえて環境変数を使わずに書いていたのですが、修正案を提案してもらうとしっかり修正してくれました。 ! を使えばBashコマンドも実行できます。 バックスラッシュ \\ を使えば改行も出来ます。 config では詳細の出力やテーマ等を設定できます。 今回はやりませんでしたが、プルリクエストのレビューもやってくれるみたいです。 さいごに 今回はClaude Code使ってみたについて書きました。ターミナルでAIを実行して要約やリファクタリング出来るのは便利ですが、まだプレビュー版なので出来ることは少ないですが、興味のある方は試してみてください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Claude Code使ってみた first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジーの橋本です。 今回、調べてもイマイチわからなかったので実際に動作検証してみました。 今回のテーマは Ansible のモジュール「ansible.posix.selinux」を用いて RHEL 9 の SELinux を変更すると正しく変更してくれるか です。 結論は…タイトルにある通りです。 前提として RHEL 9 から SELinux の無効化方法が変更となっています。 【参考】RHEL9 での SELinux の無効化方法について 今回 SELinux を無効化する PlayBook は以下の通りかなりシンプルになります。 - name: Disable SELinux ansible.posix.selinux: state: disabled RHEL 9 サーバは現状 SELinux 有効化 (Enforcing) されています。 RHEL 9 サーバの現状設定 : getenforce # getenforce Enforcing # RHEL 9 で SELinux を無効化するには grubby --update-kernel ALL --args selinux=0 コマンドを実行する必要があります。 上記コマンドを実行した場合、「/etc/default/grub」ファイルあるいは 「grubby –info=ALL」の実行結果に「selinux=0」という記述が追記されます。 現状では SELinux に関わる記述は特にありません RHEL 9 サーバの現状設定 : grub # cat /etc/default/grub GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295" GRUB_TIMEOUT=0 GRUB_ENABLE_BLSCFG=true GRUB_DEFAULT=saved # # grubby --info=ALL index=0 kernel="/boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64" args="console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M $tuned_params" root="UUID=8b4a4ce6-cc11-42e3-afc4-bbb13f950d40" initrd="/boot/initramfs-5.14.0-362.13.1.el9_3.x86_64.img $tuned_initrd" title="Red Hat Enterprise Linux (5.14.0-362.13.1.el9_3.x86_64) 9.3 (Plow)" id="ffffffffffffffffffffffffffffffff-5.14.0-362.13.1.el9_3.x86_64" # PlayBook を実行する前に旧来のSELinux 設定ファイル (/etc/selinux/config) を見てみましょう。 RHEL 9 サーバの現状設定 : /etc/selinux/config # cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. # See also: # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/using_selinux/changing-selinux-states-and-modes_using-selinux#changing-selinux-modes-at-boot-time_changing-selinux-states-and-modes # # NOTE: Up to RHEL 8 release included, SELINUX=disabled would also # fully disable SELinux during boot. If you need a system with SELinux # fully disabled instead of SELinux running with no policy loaded, you # need to pass selinux=0 to the kernel command line. You can use grubby # to persistently set the bootloader to boot with selinux=0: # # grubby --update-kernel ALL --args selinux=0 # # To revert back to SELinux enabled: # # grubby --update-kernel ALL --remove-args selinux # SELINUX=enforcing # SELINUXTYPE= can take one of these three values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted # さて、上記 Playbook の実行です!! $ ansible-playbook -i hosts main.yml PLAY [all] ************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************** 金曜日 07 3月 2025 13:13:38 +0900 (0:00:00.035) 0:00:00.035 **************** ok: [172.31.15.211] TASK [oss_install : Disable SELinux] ************************************************************************************************************ 金曜日 07 3月 2025 13:13:41 +0900 (0:00:00.025) 0:00:02.937 **************** [WARNING]: SELinux state temporarily changed from 'enforcing' to 'permissive'. State change will take effect next reboot. changed: [172.31.15.211] PLAY RECAP ************************************************************************************************************************************** 172.31.15.211 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 金曜日 07 3月 2025 13:13:43 +0900 (0:00:01.561) 0:00:04.499 **************** =============================================================================== Gathering Facts -------------------------------------------------------------------------------------------------------------------------- 2.88s oss_install : Disable SELinux ------------------------------------------------------------------------------------------------------------ 1.56s $ 結論は…残念 /etc/selinux/config に設定が記述されてしまいました。 この状況でサーバ再起動をするとサーバが起動しない可能性があるので、 「ansible.posix.selinux」モジュールを利用して RHEL 9 の SELinux を無効化しない方がよさそうです。 # cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. # See also: # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/using_selinux/changing-selinux-states-and-modes_using-selinux#changing-selinux-modes-at-boot-time_changing-selinux-states-and-modes # # NOTE: Up to RHEL 8 release included, SELINUX=disabled would also # fully disable SELinux during boot. If you need a system with SELinux # fully disabled instead of SELinux running with no policy loaded, you # need to pass selinux=0 to the kernel command line. You can use grubby # to persistently set the bootloader to boot with selinux=0: # # grubby --update-kernel ALL --args selinux=0 # # To revert back to SELinux enabled: # # grubby --update-kernel ALL --remove-args selinux # SELINUX=disabled # SELINUXTYPE= can take one of these three values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted # 補足 ちなみに以下のように記述してもうまく行きませんでした。 - name: Disable SELinux ansible.posix.selinux: configfile: /etc/default/grub state: disabled 実行結果 # cat /etc/default/grub GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295" GRUB_TIMEOUT=0 GRUB_ENABLE_BLSCFG=true GRUB_DEFAULT=saved SELINUX=disabled # ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Ansible 検証「ansible.posix.selinux」モジュールで RHEL 9 の SELinux を無効化してはいけない ※2025/03 現在 first appeared on SIOS Tech. Lab .
概要 前回は、既存のコンテナプラットフォーム上でコンテナとVMを統合管理することが出来るOCP-Virtについてご紹介しました。今回も同じようにプラットフォーム上でコンテナとVMを統合管理することが出来るSUSE Virtualization(以降、SUSE-Virt)についてご紹介します。 前回の記事は こちら 今回紹介するSUSE-Virtは、クラウドネイティブ環境向けに設計されたHCIソリューションとなります。 本記事では、SUSE-Virtの基本的な概要からアーキテクチャ、VMの移行ツール、他の仮想化基盤との比較について解説します。 前提情報 本記事では、現時点で以下のバージョンを対象としています。 harvester v 1.4.0 SUSE-Virt とは SUSE-Virtは、ベアメタルサーバー上でKubernetesをベースとして構築されており、VMを簡易的に管理できるソリューションです。 HCIソリューションという枠組みのため、SANや外部の共有ストレージは不要となり、SUSE-Virtに備わっているストレージやネットワークの機能を利用することが可能です。 SUSE-Virtは以下の特徴を持っています。 構造がシンプル 従来のサーバー仮想化のシステム構成よりもシンプルで、必要なハードウェアの数も少なく済みます。 オープンソースであり、無料で利用可能 Kubernetes、KubeVirt、Longhorn、Grafana、PrometheusといったOSSで構成されており、無料で利用が可能です。 スケールアウトが容易 スモールスタートで始めて、必要に応じてサーバーを追加して拡張が可能です。将来の大規模なインフラ更改の必要がない点が特徴です。 SUSE-Virtにストレージが内蔵しており、冗長性を提供 SUSE-VirtはLonghorn によるストレージ管理を行っており、冗長性が担保されています。 SUSE-Virtが提供する機能としては下記が挙げられます。 Linux および Windows VMの作成と管理 Rancherとの統合によるインフラストラクチャの統合管理 SUSE-Virt アーキテクチャ SUSE-Virtは、Kubernetes環境上でVMの作成・管理を可能にするOSSのKubeVirtを元にして開発されています。KubeVirt は動作する基盤としてKubernetesを使用し、KubernetesのAPIを拡張することで、Kubernetes環境上へのVMの構成を実現しています。 VMを動作させる仕組みとしてはKVMを使用しています。 SUSE-Virtのコンポーネント KubeVirt:Kubernetes 上で KVM を使用して仮想化管理を提供 Longhorn:分散ブロック ストレージとアクセス頻度に応じて、データを最適な場所に配置するティアリング を提供 Kubernetes CNI:コンテナのネットワーク機能を抽象化し、IF仕様として切り出したもの Elemental for SUSE Linux Enterprise Micro 5.5:Kubernetes クラスターで OS メンテナンスを可能な限り排除するように設計された Linux ディストリビューション ベアメタルノードにインストールされるように設計されています。各ノードにKubeVirt、Longhornがインストールされ、KVM を使用した仮想化管理と分散ブロック ストレージをそれぞれ提供します。その上に仮想マシンを構築します。 ネットワークコンポーネント VM用に以下のネットワークが提供されます。 Management network:デフォルトの管理ネットワークとしてCanalを使用しています。これは、クラスターから直接使用できる組み込みネットワークです。デフォルトでは、VM の管理ネットワーク IP はクラスター ノード内でのみアクセス可能です。 VLAN:MultusおよびBridge CNI プラグインを活用して、カスタマイズされた L2 ブリッジ VLAN ネットワークを実装します。これにより、VM をホスト側のネットワークインターフェースに接続し、物理スイッチを使用して内部および外部ネットワークからアクセスできるようになります。 Image Source: https://docs.harvesterhci.io/v1.4/ VMの作成については、KubeVirtのアーキテクチャと同じです。流れとしては、VMを作成する際にvirt-apiを叩き、そのAPIはkubeletに問い合わせ、要求されたVirtual Machine Instances(VMI)をスケジューリングします。QEMU・libvirt はSUSE-VirtのVirtualMachineInstance(VMI)の中で実行しています。 Image Source: https://kubevirt.io/user-guide/architecture/ VMの移行ツールの紹介 SUSE-Virtでは、既存の利用している仮想化基盤からの移行を支援するためのアドオンが vm-import-controller として提供されています。vm-import-controllerは様々な仮想化基盤で稼働する VM を SUSE-Virt 上に移行するツールです。移行元として選択できる Provider は下記になります。 VMware vSphere OpenStack vm-import-controller は 以下の2つのCRDを提供します。 移行元の情報を定義する VmwareSource CRD, OpenstackSource CRD VMのインポート情報を定義する  VirtualMachineImport CRD このように、現行の仮想化基盤からの移行方式も用意されているため、SUSE-Virt への移行が簡単になっています。 その他仮想化基盤との比較 Red Hat OpenShift Virtualization (OCP-Virt) OCP-Virtは、OpenShift に含まれる機能でありコンテナプラットフォーム上でVMを構成することを可能にするオペレーターです。OCP-Virtも同様にKubeVirtを利用して、コンテナとVMを既存のOpenShift上で同時に管理することが可能です。主な違いとしては、SUSE-VirtはRancherと並列に統合されますが、OCP-VirtはOpenShiftに内包されるプラットフォームになっている点が挙げられます。必要なノード数や対応プラットフォームも異なっています。詳細については、OCP-VirtとSUSE-Virtを詳しく比較した記事を投稿予定ですので、是非そちらを読んでみてください。 VMware vSphere (vSphere) vSphereは、仮想化基盤といえば必ず名前が上がる製品であり、企業環境での広範な採用実績を持っています。幅広いハードウェアとの互換性、高度な機能(vMotion、Storage DRS、High Availabilityなど)、および堅牢なセキュリティを提供します。vSphereはサブスクリプションとして提供されますが、SUSE-Virtは無料で利用可能な点が異なります。前回のOCP-Virtでも取り上げたように、Sphereは仮想化に関しては非常に高い成熟度を持っていますが、SUSE-VirtはKubernetesネイティブな統合が簡単にできる点が強みとなります。 Proxmox Virtual Environment (Proxmox VE) Proxmox VEは、KVMとLinux Containers (LXC) をサポートするオープンソースの仮想化基盤です。ビルトインのクラスタリング機能を備えており、簡単にハイアベイラビリティ環境を構築できます。クラスタリングが可能で高可用性を提供できる点はSUSE-Virtと類似していますが、Kubernetesネイティブであるか否かといった点が違いになります。 まとめ SUSE-Virtの基本的な概要からアーキテクチャ、VMの移行ツール、他の仮想化基盤との比較について解説しました。 SUSE-VirtはKubernetesをベースに構築されたベアメタルサーバー上でVMを簡易的に管理できるHCIソリューションです。特徴として、構造がシンプルで、オープンソースで無料利用が可能、スケールアウトが容易、内蔵ストレージによる冗長性の提供が挙げられます。 参考文献 https://docs.harvesterhci.io/v1.4/ https://www.suse.com/ja-jp/products/rancher/virtualization/ https://kubevirt.io/user-guide/ https://www.suse.com/c/rancher_blog/comparing-hyperconverged-infrastructure-solutions-harvester-and-openstack/ https://www.infoq.com/jp/news/2021/07/suse-releases-harvester/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SUSE Virtualization とは? first appeared on SIOS Tech. Lab .
はじめに こんにちはサイオステクノロジーの小野です。 以前の記事 で、Azure OpenAIのLLMをLightspeedと連携する方法について解説しました。今回はOpenShift AIにデプロイしたLLMをLightspeedと連携させる方法について解説します。 OpenShift AIとOpenShift Lightspeed連携 OpenShift Lightspeeedを利用する上で、OpenShift AIのようなローカル環境にデプロイしたLLMと連携する場合と、Azure OpenAIのようなクラウド環境にデプロイされているLLMと連携する場合で次のような差異があります。 ローカル環境LLM メリット 公開LLMを利用することができるので幅広いモデルを選択することが可能です。また、ローカル環境にデプロイできるので、LLMに入力した情報が流出する心配がなくなります。リクエスト数の制限がないので何回でも質問ができます。 デメリット 公開LLMを一からデプロイする必要があるので手間がかかります。また、ローカルでLLMを動かすので、計算資源を用意する必要があります。 クラウド環境LLM メリット 高性能なLLMを簡単にデプロイできます。クラウド上で動作するので計算資源は用意しなくて済みます。 デメリット LLMを提供しているプロバイダによっては入力した情報の取り扱いについて気を付けなければなりません。また、リクエスト数や質問の長さによって従量課金となる場合があります。 OpenShift AIとOpenShift Lightspeeedを連携することによってローカルな環境でもOpenShiftに関するAIチャットアシスタント機能を利用することが可能です。 構築設定 今回はOpenShift AIにデプロイしたLLM( Mistral-7b-instruct-v0.3 )とOpenShift Lightspeedを連携します。 OpenShift AIにデプロイしたLLMのエンドポイントは外部公開用と内部公開用の2種類ありますが、Lightspeedとの連携上、外部公開用のエンドポイントを利用します。 前提条件 OpenShift AI構築済み Lightspeed Operatorインストール済み gpuインスタンス:g6.xlarge S3にLLMデータ保存済み OpenShift クラスタにサーバ 証明書設定済み OpenShift AI設定 OpenShift AIのLLMデプロイについては以前の記事を参考にしてください。 OpenShift AIにLLMをデプロイしてみた 今回はMistral-7b-instruct-v0.3というLLMモデルをデプロイします。 モデルサービングの設定を行う際のモデル名をLightspeed連携に用いるのでメモしてください。 Model deployment nameをLightspeed設定に用いる Lightspeed設定 Lighspeedの設定は以前の記事を参考にしてください OpenShift Lightspeedを構築してみた APIの認証情報をSecretとして作成します。<APIトークンの値>にはOpenShift AIにデプロイしたLLMのAPIトークンの値を入れて下さい。 apiVersion: v1 kind: Secret metadata: name: openshift-ai-api-keys namespace: openshift-lightspeed type: Opaque stringData: apitoken: <APIトークンの値> LightspeedのCRは以下のように設定します。<モデル名>にはOpenShift AIにデプロイしたLLMのモデル名を入力してください。デプロイした大元のモデル名ではないので注意してください(画像の例だと、〇test-mistral, ×Mistral-7b-instruct-v0.3)。<APIエンドポイント>にはデプロイしたLLMのExternalの方のエンドポイントを入力してください。 apiVersion: ols.openshift.io/v1alpha1 kind: OLSConfig metadata: name: cluster spec: llm: providers: - credentialsSecretRef: name: openshift-ai-api-keys models: - name: <モデル名> name: red_hat_openshift_ai type: rhoai_vllm url: <APIエンドポイント>/v1 ols: defaultProvider: red_hat_openshift_ai defaultModel: <モデル名> 動作確認 Lightspeeedの設定が完了した後、挨拶してみます。すると以下のように、返答してくれます。 OpenShift AIのLLMと連携したLightspeedがチャットに応答する 終わりに このようにOpenShift AIとOpenShift Lightspeeedを連携することで、任意のLLMを用いたAIチャットアシスタント機能を利用できます。また、ローカル環境のLLMを利用しているので、非接続環境でもAIチャットアシスタント機能を利用できます。 参考 Lightspeedの詳細: https://github.com/openshift/lightspeed-service?tab=readme-ov-file ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIとOpenShift Lightspeedを連携してみた first appeared on SIOS Tech. Lab .