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

TECH PLAY

Red Hat  - Open Innovation Labs

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

全900件

5月28日に Red Hat Tech Nightを開催いたします。 今回のイベントも、レッドハットのエンジニがが勝手に喋りたいことをLTしまくるという感じで進める予定です。完全に自己満足のためのイベントです(笑) LT一覧(順番や内容変更する可能性あり) 以下のようなLTを実施予定です。Ansible、Quarkus、Alibaba、OpenStack、OpenShift、Fedoraと盛りだくさん! 1: はじめてのPull Request - AWX編 by @saito_hideki 2: 5分で理解するQuarkus by @nobusue 3: 検討中(Camel 3 or Syndesis)by @tadayosi 4: multus-cniについて(仮) by @s1061123 5: Alibaba meets RedHat (詳細未定) by @mosuke5 6: マイラボをもっとゴージャスに!(仮) by toaraki 7: OpenShift の S2I (Source-to-Image) の内部動作について調査してみた件 by mamomamo 8: Ansible 2.8 x Windows(仮) by @hiyoko_taisa 9: OpenStackでなにか(仮) by tkajinam 10: OpenShift-SDNの話 by @orimanabu 11: オレにFedora 30の話をさせてくれ by @htaira ご参加方法 すでに一般参加枠が埋まっておりますが、リモート参加枠もございますので、ぜひご登録ください。 ossbyredhat.connpass.com ご参考 前回の様子は以下のTogetterまとめをご参照していただくと良いかと思います。 togetter.com 前回の舞台裏に関する記事は以下にございます。 rheb.hatenablog.com
Red Hatのさいとうです。 今月中に(おそらく)リリースされる予定の、Ansibleの最新バージョン2.8の新機能について、これから数回に分けて紹介しようと思います。 第1回として選んだのは Interpreter Discovery機能 です。 Interpreter Discovery機能 Ansibleは、モジュールから生成されたPythonの実行プログラムを、ターゲットホスト上に転送し、これをSSHログインして実行することで、ターゲットホストに対してユーザの追加やパッケージのインストールなどの、さまざまな操作を行います。 このときに利用されるPythonインタプリタは、インベントリファイルやPlaybookの変数( ansible_python_interpreter )にパスを設定することで、明示的に指定することができます。ちなみにデフォルトパスは /usr/bin/python です。 Ansible 2.8では、規定されたPythonインタプリタのリストから、ターゲットホストにマッチしたPythonインタプリタを見つけ出して、実行時に利用するというInventory Discovery機能が実装されました。ただし、Interpreter DiscoveryはターゲットホストがLinuxである場合にのみ機能します。 尚、 ansible_python_interpreter でパスが明示的に指定されている場合は、上記のリストにマッチするPythonインタプリタが存在した場合でも、この値でオーバーライドされて、実行時のパスとしては ansible_python_interpreter の値が採用されます。 Interpreter Discoveryの仕組み Interpreter Discoveryの挙動の指定 Interpreter Discoveryの挙動は、Ansibleの設定ファイル( ansible.cfg )の defaults セクションにある interpreter_python に、以下の4つのパラメータから1つを選んで指定することができます。 auto_legacy (Ansible 2.8のデフォルト値) auto (Ansible 2.12リリースでのデフォルト値となる予定...いつだよ) auto_legacy_silent (auto_legacyと同様の振る舞いだがWARNINGレベルのメッセージ出力されない) auto_silent(autoと同様の振る舞いだがWARNINGレベルのメッセージは出力されない) auto_legacy | auto_legacy_silent auto_legacyは、その名の通りAnsibleの過去のバージョンの挙動( /usr/bin/python を利用する)を踏襲しつつ、 /usr/bin/python が存在しなかった場合は、Interpreter Discovery機能で取得したPythonインタプリタのパスを利用する挙動となっています。 1.ターゲットとなるLinuxのディストリビューションとバージョンを取得します( gather_facts の前段で動作することになるため、別の仕組みでターゲットホストのOS情報を取得しています) 2. INTERPRETER_PYTHON_DISTRO_MAP で規定されているLinuxディストリビューションとバージョンから、デフォルト値となるPythonインタプリタを決める。バージョンマップは以下の通りです(CentOS8まだ出てないよ!とか、Fedoraはもう30だよ! とかいうのは気にしない...気にしない) centos: &id001 '6': /usr/bin/python '8': /usr/libexec/platform-python fedora: '23': /usr/bin/python3 redhat: *id001 rhel: *id001 ubuntu: '14': /usr/bin/python '16': /usr/bin/python3 3. INTERPRETER_PYTHON_DISTRO_MAP で規定されたPythonインタプリタが存在しなかった場合に備えて、 INTERPRETER_PYTHON_FALLBACK で規定されたPythonインタプリタ候補のパスをディスカバリして存在しないパスをフィルタしたリストを作成する。候補リストのフィルタリングはターゲットホスト上で command -v <パス> の実行可否で判断しています。リスト構造となっているので、これがそのままPythonインタプリタの優先順位となります。 - /usr/bin/python - python3.7 - python3.6 - python3.5 - python2.7 - python2.6 - /usr/libexec/platform-python - /usr/bin/python3 - python 4.1-3の処理が終わったところで、Pythonインタプリタのパスを決定します。まず、以前のバージョンとの互換性を保つために、 /usr/bin/python が存在していれば、最優先でこれを利用します。 /usr/bin/python が存在しなかった場合は、 INTERPRETER_PYTHON_DISTRO_MAP で選択されたパスが、更に INTERPRETER_PYTHON_DISTRO_MAP のパスも存在しなかった場合は、 INTERPRETER_PYTHON_FALLBACK でリストにある有効な最初のパスのPythonインタプリタが採用されます。 ちなみに、 INTERPRETER_PYTHON_DISTRO_MAP と INTERPRETER_PYTHON_FALLBACK の既定値は、 ansible-config list コマンドで確認することができますが、この値を ansible.cfg ファイル内で変更することはできません(いまのところ)。 auto | auto_silent auto_legacyの挙動と違うのは、 /usr/bin/python が存在していても無条件で採用しない点です。 INTERPRETER_PYTHON_DISTRO_MAP で取得されたPythonインタプリタのパスが存在している場合は、これが優先され、存在しなかった場合は INTERPRETER_PYTHON_FALLBACK を元に作成された有効なパスリストの優先順にしたがって、Pythonインタプリタのパスが決定されます。 テストしてみる それでは、Ansible 2.8.0rc2を使用して、Interpreter Discoveryの動きを見てみましょう。インベントリファイルで明示的に ansible_python_interpreter に /usr/libexec/platform-python を指定することなく、前述のルールにしたがって、Pythonインタプリタのパスをディスカバリしてくれます。 $ ansible rhel8 -i inventory -m ping tower | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" } まとめ Interpreter Discovery機能は非常に便利ですが、残念ながら INTERPRETER_PYTHON_DISTRO_MAP と INTERPRETER_PYTHON_FALLBACK は、設定ファイル( ansible.cfg )上で自由に編集することはできません。それでも、RHEL8やUbuntu18.04のように /usr/bin/python を持たない可能性のあるOSを、特別な設定をすることなく操作できるという点では、現状でも十分に利用価値があります。今後のエンハンスに期待しつつ、挙動を理解して有効に活用していきましょう。 次はどの新機能について書こうかなぁ...
Red Hatの森若です。 2019年5月7日に、Red Hat Enterprise Linux 8 がリリースされました。 Red Hat Enterprise Linux 8 概要 Red Hat Enterprise Linux 7 からの大きな違い 予測可能なリリースタイミング 同一ソフトウェアの複数バージョンを提供 Red Hat Insightsを同梱 Universal Base Imageの提供 まとめ Red Hat Enterprise Linux 8 概要 Red Hat Enterprise Linux 8 は以下のような特徴があります。 Fedora 28, linux 4.18 をベースとして開発されたエンタープライズむけOS x86_64 だけでなく ARM 64, Power, Zの4種類のアーキテクチャで動作 2029年5月までの10年間にわたる長期ライフサイクル パートナー各社との連携により、認定ハードウェア、認定仮想化環境、認定クラウド環境上でのサポートを提供 エンタープライズでの利用にあわせた、統合管理製品や高可用性クラスタなどを提供 Red HatのIaaS基盤、コンテナ基盤、ストレージ製品などの基盤となる Red Hat Enterprise Linux 7 からの大きな違い Server, HPC, Desktopなどの製品種別により異なっていたソフトウェアの配布方法を統一しました。RHEL 8の製品種別による差異は、サポートされるユースケースの違いです。 マイナーリリースを6ヶ月おきに出荷、メジャーリリースを3年おきに出荷します 同一ソフトウェアの複数バージョンを提供します 一部のmoduleはサポートが短期間です(2年、3年) moduleの仕組みを使い、RHELの10年ライフサイクルと同期しない、頻繁なアプリケーションの更新を提供します。 RHELにRed Hat Insightsを同梱し、自動的な診断サービスを利用できます Red Hat Enterprise Linux 8を簡単に紹介するスライドを以下に公開しています。 Red Hat Enterprise Linux 8 ご紹介 - Speaker Deck 今回Red Hat SummitでRHEL 8リリースとともに多数の発表がありました。以下に簡単にまとめます。 予測可能なリリースタイミング Red Hat Enterprise Linux 8 からは、マイナーリリースおよびメジャーリリースの出荷タイミングについてポリシーが変更されました。 access.redhat.com マイナーリリースを半年ごとに、メジャーリリースを3年おきに出荷します。このようにあらかじめ決まったタイミングでリリースを行うことで、事前にアップデートなどの計画を立てる際にマイナーバージョン出荷時期を折り込みやすくなります。 EUSは8.1, 8.2, 8.4, 8.6, 8.8 に出荷予定です。 RHEL8リリース予定 同一ソフトウェアの複数バージョンを提供 システム導入に最低限必要なパッケージを集めたBaseOSと、BaseOSを基盤として動作するパッケージを集めたApplication Streamsという仕組みを導入します。Application Streamsでは同一ソフトウェアの複数バージョンを並行して提供します。さらに頻繁に新しいバージョンのソフトウェアを提供します。Application Streamsで提供される一部のコンポーネントのライフサイクルはRHELの10年間ではなく、2年から5年の期間に設定されます。 これはRHEL 7までに存在した Software Collections および Developer Toolset の後継となるものです。1つのシステムに複数バージョンを同時にインストールすることはできませんが、利用方法にsclコマンドなどの特別な工夫は不要です。1つのシステム内で複数バージョンを併存させたい場合には、それぞれを独立したコンテナ内で利用します。 rheb.hatenablog.com access.redhat.com Red Hat Insightsを同梱 Red Hat Insights はSaaS型のシステム診断サービスです。典型的な設定上の問題や既知の脆弱性、ソフトウェア、ファームウェア、ISV製品の問題などを検出するだけでなく、これらに対して適切な対応方法を提示し、一部の問題については対応用のAnsible Playbookを生成する機能も提供します。 rheb.hatenablog.com 今回、Red Hat Enterprise Linux のサブスクリプションに Red Hat Insightsが同梱されることが発表されました。RHEL 8である必要はなくRed Hat Insigtsが対応しているバージョン(RHEL6, RHEL 7)で利用できます。既に Red Hat Insights をご利用のお客様は、今後サブスクリプションの更新をする必要がなくなります。 Universal Base Imageの提供 Universal Base Image は、Red Hat Enterprise Linux をベースとしたコンテナイメージです。このコンテナイメージは自由に加工・再配布が可能です。そのため、このイメージをベースとして自作のソフトウェアを含むコンテナイメージを実装して自由に配布・転載することも自由に可能です。 これは主にOSSプロジェクトやISVが自作プログラムをコンテナイメージで配布するために利用することを意図して作成されています。 yumにより追加のパッケージを導入することが可能ですが、UBI用のリポジトリで利用できるパッケージはRHELのパッケージ全てではなくサブセットが提供されています。もしあなたのソフトウェアに必要なパッケージが存在しない場合、Red Hat のBugzillaからパッケージ追加をリクエストすることが可能です。 UBIは、Red Hat製品でない各種コンテナ環境で実行しても特に費用はかかりません。さらにOpenShiftやRHELなど、コンテナ基盤となるRed Hat製品ではUBI部分までサポート対象となります。 今まで契約上の課題等のためにCentOSを利用してコンテナイメージを作成していた方は、UBIに乗り替えることでセキュリティfixがを早く受けとれます、Red Hat製品上でベースイメージ部分についてサポートを受けられるようになります。 www.redhat.com まとめ 2019年5月7日にRed Hat Enterprise Linux 8 がリリースされ、利用可能になりました 同梱ソフトウェアが更新・置き換え・撤廃されただけでなく、配布方法、リリース頻度、新しいソフトウェアの追加、Insightsによる診断サービスの同梱と、ソフトウェア以外の変更点が多数あります 同時に発表されたUniversal Base Imageはコンテナイメージでのソフトウェア配布に便利に利用できるだけでなく、Red Hat製品上ではサポートを受けられるため非常に有用です
Red Hat の杉村です。Ansible のテクニカルサポートエンジニアをしています。 RHEL8 がリリースされたということで、早速 Ansible から触ってみることにしました。最新のリリース版は 2.7.10 です。 RHEL8 は5台用意してみました。インベントリファイルを作ります。 [rhel8] 192.168.0.51 192.168.0.52 192.168.0.53 192.168.0.54 192.168.0.55 Ping モジュールを実行してみます。 $ ansible -m ping -i inventory.rhel8 -k rhel8 SSH password: 192.168.0.51 | FAILED! => { "changed": false, "module_stderr": "", "module_stdout": "/bin/sh: /usr/bin/python: そのようなファイルやディレクトリはありません\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127 } 192.168.0.53 | FAILED! => { "changed": false, "module_stderr": "", "module_stdout": "/bin/sh: /usr/bin/python: そのようなファイルやディレクトリはありません\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127 } 192.168.0.55 | FAILED! => { "changed": false, "module_stderr": "", "module_stdout": "/bin/sh: /usr/bin/python: そのようなファイルやディレクトリはありません\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127 } 192.168.0.52 | FAILED! => { "changed": false, "module_stderr": "", "module_stdout": "/bin/sh: /usr/bin/python: そのようなファイルやディレクトリはありません\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127 } 192.168.0.54 | FAILED! => { "changed": false, "module_stderr": "", "module_stdout": "/bin/sh: /usr/bin/python: そのようなファイルやディレクトリはありません\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127 } Python が入っていない!と怒られてしまいました。RHEL8 では、OS の制御用には platform-python を利用するようになっています。先ほどのインベントリファイルに追加しましょう。 [rhel8] 192.168.0.51 192.168.0.52 192.168.0.53 192.168.0.54 192.168.0.55 [rhel8:vars] ansible_python_interpreter=/usr/libexec/platform-python 今度は ping できました。 $ ansible -m ping -i inventory.rhel8 -k rhel8 SSH password: 192.168.0.54 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.0.51 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.0.52 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.0.55 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.0.53 | SUCCESS => { "changed": false, "ping": "pong" } Ping ができたということで、yum update もしてみます。プレイブックを書きました。 --- - hosts: rhel8 become: true tasks: - name: yum update yum: name: '*' state: latest 実行してみます。 $ ansible-playbook -i inventory.rhel8 rhel8_yum_update_playbook.yml -k -K SSH password: SUDO password[defaults to SSH password]: PLAY [rhel8] *********************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************* ok: [192.168.0.54] ok: [192.168.0.52] ok: [192.168.0.55] ok: [192.168.0.53] ok: [192.168.0.51] TASK [yum update] ****************************************************************************************************************************** changed: [192.168.0.51] changed: [192.168.0.54] changed: [192.168.0.55] changed: [192.168.0.52] changed: [192.168.0.53] PLAY RECAP ************************************************************************************************************************************* 192.168.0.51 : ok=2 changed=1 unreachable=0 failed=0 192.168.0.52 : ok=2 changed=1 unreachable=0 failed=0 192.168.0.53 : ok=2 changed=1 unreachable=0 failed=0 192.168.0.54 : ok=2 changed=1 unreachable=0 failed=0 192.168.0.55 : ok=2 changed=1 unreachable=0 failed=0 正しく yum update されていることが確認できました。 [sugimura@rhel8a ~]$ sudo yum history [sudo] sugimura のパスワード: Updating Subscription Management repositories. ID | コマンドライン | 日時 | 動作 | 変更さ ------------------------------------------------------------------------------- 2 | | 2019-05-08 11:20 | I, U | 70 1 | | 2019-05-08 08:02 | Install | 1335 EE 近いうちにリリースされる予定の Ansible 2.8 では、この ansible_python_interpreter を自動的に検出する機能が導入されることになっています。RHEL8 でも引き続き安心して Ansible をご利用ください。Happy Automation!
Red Hat の小林俊哉です。オープンソースのルールエンジン Drools についてのブログを始めました。HelloWorld、デシジョンテーブル、推論について、それぞれ短いエントリを書いています。この3本でちょうど入門に良いかもしれません! tokobayashi.hatenablog.com tokobayashi.hatenablog.com tokobayashi.hatenablog.com
Red Hatの森若です。今回はRed Hat Insightsをご紹介します。 サポートとナレッジベース Red Hatのサポート窓口では、日々多数の問題を取り扱っています。取り扱った問題について公開可能かつ有益な情報はナレッジベースに蓄積され、サブスクリプションを持っていれば カスタマーポータル からアクセスできます。 このナレッジベースは継続的に更新されており、アクセスが多いものなど一部は日本語訳も提供されています。 Red Hat Insights とは ナレッジベースには過去に発生して解決(または対策)した問題が記載されています。そこで、ナレッジベースの情報を元にシステムをチェックすることで、典型的な問題や過去に類似事象が発生した問題を発見することができれば、システムやサービスの停止など業務上の問題として顕在化する前の潜在的な問題に対処することができるかもしれません。 これをSaaSとして実現したのが Red Hat Insights です。ナレッジベースの記事をもとにRed Hatのエンジニアがルールを作成して自動的に診断を行います。診断結果のレポートを見て対応することができるように、具体的な対処方法が記載され、さらに一部のルールでは対処用のAnsible Playbookを生成できます。 様々なチェック項目がありますが、主に以下のようなものを調べます。 Red Hat製品(RHELだけでなく、Red Hat OpenStack PlatformやOpenShift Container Platform、Red Hat Virtualizationなど)の既知の問題とアップデート ISV製品やハードウェアのファームウェア 問題がある設定 問題がある設定とソフトウェアの組み合わせ ログや統計情報で出力された警告やエラー Insightsレポート例。opensshの設定上の問題に対して、パッケージの更新または設定の修正での対応を勧めている Red Hat Insightsのルールは公開されていませんが、サーバ、クライアントともにOSSとして開発されています。 github.com Red Hat Insights の使い方 Red Hat Insightsは RHEL 6.4以降、RHEL 7以降を対象として利用可能です。 評価用サブスクリプションを利用すると、既にsubscription-managerでシステムが登録されていれば 、以下のコマンドで利用をはじめられます。インターネット接続とカスタマーポータルへのアカウントとパスワードが必要ですが、何も問題がなければ登録作業は数分で終わります。 # yum install insights-client # insights-client --register 上記コマンドを実行後、 Red Hat Insights にアクセスすると登録されたシステムについて検出された問題が「アクション」タブに表示されます。登録したシステムはインベントリに一覧表示されます。 アクションタブ。アクションが種類やリスクなどで分類される プランナータブで対処についての計画をたてることができます。1つ以上のアクションをまとめて「プラン」を作成し、作業予定を作成します。 プランビルダー 作成したプランを表示すると「Playbook」タブでAnsibleのPlaybookをダウンロードできます。Playbookによる自動対応は全てのアクションをサポートしておらず、一部のアクションについてのみ利用できます。この例ではプランには3つのアクションが登録されているのですがPlaybook生成には2つだけ対応しています。 プランからPlaybook作成 Red Hat Insights のしくみ Red Hat Insightsのしくみについて見てみましょう。 Red Hat Insights概要図 insights-clientはRed Hat InsightsのAPIから、どうやって情報を収集するのか手順を取得し、実行して取得した結果を送信します。送信したくない情報があれば、insights-clientを実行する前に/etc/insights-client/insights-client.conf であらかじめ指定しておくことで、ファイルやコマンド実行結果、パターンやキーワードを含む情報は送られません。さらに送信された情報についても、古いデータは破棄されます。 Red Hat Insights が検出する問題の管理 Red Hat Insightsの「ルール」タブで概要を確認できるほか、既知の許容している問題についてはチェックの対象外にするなどの操作ができます。 まとめ Red Hat InsightsはRed HatのナレッジをもとにしたSaaS型のシステム診断サービス 一部アクションについては対応用のAnsible Playbook生成にも対応 おまけ Red Hat Insightsの簡単な紹介動画と、デモンストレーション動画を公開しています。 Red Hat Insightsご紹介 Red Hat Insightsデモンストレーション
Red Hat の杉村です。 若手エンジニア向けのメディアに記事を書きました。 Hello World からダイナミックインベントリの活用、Ansible Tower まで広く浅く解説してみましたのでご覧ください。 employment.en-japan.com
Red Hatの平です。2019年5月1日から和暦が「平成」から「令和」へ移行します。皆さんのシステムは「令和」対策お済みですか? Red Hatでは2019年4月9日に、RHEL5 / RHEL6 / RHEL7を対象に新元号「令和」対応の修正パッケージをリリースしました。 access.redhat.com 一概に新元号対応というと、いくつか関連する仕組みがあります。基本的にはLinuxでは西暦でも和暦でもなく、UNIXエポックと呼ばれる時間で動いています。これは1970年1月1日 0:00:00(UTC)から何秒進んだのかという累積時間であり、日本語の和暦で表現して欲しいユーザーが和暦に変換するように指示した時にはじめて和暦として扱われ変換されます。 その変換テーブルを持っている1つがglibcです。おおよそのRHELユーザーはglibcをアップデートする事で日常的に出てくる和暦を新元号「令和」へ変換できます。 気になる方は、まずはglibcのアップストリームのGitレポジトリをご覧ください。 https://sourceware.org/git/?p=glibc.git;a=blob;f=localedata/locales/ja_JP;hb=94e358f6d490650c714edb1ffc3a52f56ffe086e#l14967 令和対策済みかのチェックは簡単です。次のコマンドを実行して2019年5月1日が「平成31年」か「令和元年」どうか調べます。 [root@rhel7 ~]# LC_ALL=ja_JP.utf8 date +%EY -d 20190501 平成31年 令和対策済みの場合には、次のような結果になります。 [root@rhel7 ~]# LC_ALL=ja_JP.utf8 date +%EY -d 20190501 令和元年 [root@rhel7 ~]# LC_ALL=ja_JP.utf8 date +%EY -d 20190430 平成31年 RHEL7の場合、glibc-2.17-260.el7以降、RHEL6の場合、glibc-2.12-1.212.el6_10.2以降、RHEL5の場合、glibc-2.5-123.el5_11.5以降で対応しています。また、環境によってはC++の icu パッケージ、openjdk のパッケージも該当します。 Red Hat SatelliteとRed Hat Ansible Automateを使えば、100台だろうと、1000台だろうと今からでも間に合いますよ。Ansibleを使った代表的なPlaybookをご紹介します。 --- - hosts: all become: yes tasks: - name: Update glibc to latest version yum: name: glibc state: latest ※glibcをアップデートした後、システム再起動する方が望ましいです。
Red Hatの松田絵里奈です。 オープンソースルールエンジンのデファクトスタンダード「Drools」の商用版である「Red Hat Decision Manager」について記事を書いています。 バージョン7からルール再評価の仕組みが改良され、Property Reactiveがデフォルトになっていますが、 以前のバージョンとの違いについて解説しています。 qiita.com
Red Hat の杉村です。Ansible のテクニカルサポートエンジニアをしています。 Ansible Tower は upstream のプロジェクトとして開発されている AWX を元にしています。本記事では、AWX をインストールしてみた記録を紹介しようと思います。AWX についてはこちらをご覧ください。 AWX Project https://github.com/ansible/awx Minishift のインストールと設定 AWX はコンテナで動作します。インストールできる環境としては OpenShift, Kubernetes と Docker Compose がインストールドキュメントに記載されていますので、お気軽に試せる OpenShift の単一ノード版の Minishift を使ってみることにしました。macOS Mojave (10.14.4) + VirtualBox 6.0.4 で動かしてみましたが、他の環境の方は適宜読み替えてみてください。 macOS では brew から簡単にインストールすることができます。 $ brew cask install minishift … $ minishift version minishift v1.33.0+ba29431 VirtualBox もインストールしておいてください。VirtualBox で CentOS 7 が起動され、その中で Minishift が動作するようになっています。 起動前に VM の設定をします。CPU は 4core、メモリは 16GB 割り振ってみました。 $ minishift config set vm-driver virtualbox $ minishift config set cpus 4 $ minishift config set memory 16gb $ minishift addons install --defaults $ minishift addons enable admin-user 設定を確認します。 $ minishift config view - cpus : 4 - memory : 16gb - vm-driver : virtualbox $ minishift addons list - admin-user : enabled P(0) - admissions-webhook : disabled P(0) - anyuid : disabled P(0) - che : disabled P(0) - htpasswd-identity-provider : disabled P(0) - redhat-registry-login : disabled P(0) - registry-route : disabled P(0) - xpaas : disabled P(0) きちんと設定できていれば起動しましょう。ISO ファイルの取得などもありまして時間がかかります。 ​$ minishift start minishift start -- Starting profile 'minishift' -- Check if deprecated options are used ... OK -- Checking if https://github.com is reachable ... OK -- Checking if requested OpenShift version 'v3.11.0' is valid ... OK -- Checking if requested OpenShift version 'v3.11.0' is supported ... OK -- Checking if requested hypervisor 'virtualbox' is supported on this platform ... OK -- Checking if VirtualBox is installed ... OK -- Checking the ISO URL ... OK -- Checking if provided oc flags are supported ... OK -- Starting the OpenShift cluster using 'virtualbox' hypervisor ... -- Starting Minishift VM ......................... OK -- Checking for IP address ... OK -- Checking for nameservers ... OK -- Checking if external host is reachable from the Minishift VM ... Pinging 8.8.8.8 ... OK -- Checking HTTP connectivity from the VM ... Retrieving http://minishift.io/index.html ... OK -- Checking if persistent storage volume is mounted ... OK -- Checking available disk space ... 16% used OK -- Writing current configuration for static assignment of IP address ... OK -- OpenShift cluster will be configured with ... Version: v3.11.0 -- Copying oc binary from the OpenShift container image to VM ... OK -- Starting OpenShift cluster ................................ … I0402 04:28:53.052106 5652 interface.go:41] Finished installing "openshift-controller-manager" Adding default OAuthClient redirect URIs ... Adding centos-imagestreams ... Adding router ... Adding registry ... Adding sample-templates ... Adding persistent-volumes ... Adding web-console ... I0402 04:28:53.062807 5652 interface.go:26] Installing "centos-imagestreams" ... … I0402 04:29:07.271715 5652 interface.go:41] Finished installing "centos-imagestreams" "openshift-router" "openshift-image-registry" "sample-templates" "persistent-volumes" "openshift-web-console-operator" Server Information ... OpenShift server started. The server is accessible via web console at: https://192.168.99.101:8443/console 無事起動できました。ここで表示されたURLに admin/admin でアクセスしてみてください。 ここでは developer ユーザで AWX のインストールをするようにしたいと思います。権限を付与します。developer ユーザも最初から作られており、パスワードは任意の文字列になっています。いまは手元だけの環境なので特に設定していませんが、必要があればきちんと設定してください。 $ oc login -u admin -p admin --as=system:admin $ oc adm policy add-cluster-role-to-user cluster-admin developer --as=system:admin Minishift にプロジェクトを作ります。 $ oc new-project awx $ oc project awx Now using project "awx" on server "https://192.168.99.101:8443". DB 用にストレージを用意します。pvc.yml ファイルを作ります。 apiVersion: "v1" kind: "PersistentVolumeClaim" metadata: name: "postgresql" spec: accessModes: - "ReadWriteMany" resources: requests: storage: "20Gi" volumeName: pv0001 このファイルを適用して作ります。 $ oc create -f pvc.yml $ oc get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE postgresql Bound pv0001 100Gi RWO,ROX,RWX 10s これで準備は完了です。 AWX のインストール いよいよ本命 AWX のインストールをしていきます。執筆時点での最新リリースバージョンである 4.0.0 を指定しました。 $ git clone https://github.com/ansible/awx.git $ cd awx $ git checkout 4.0.0 $ cd installer $ cp inventory inventory.orig インストール先の情報を inventory ファイルに設定していきます。IPアドレスは minishift ip コマンドでわかります。openshift_token は、developer でログインして、右上の Copy Login Command から取得してください。コピーしてターミナルなどにペーストすると、このように文字列が出てくるようになっています。 oc login https://192.168.99.101:8443 --token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx これまで得た情報を元に、inventory ファイルを編集します。コメント行も多いですが、実際に設定した値を抜き出してみました。 $ grep -v "^#" inventory | grep -v "^$" localhost ansible_connection=local ansible_python_interpreter="/usr/bin/env python" [all:vars] dockerhub_base=ansible openshift_host=<IPアドレス>:8443 openshift_project=awx openshift_user=developer openshift_skip_tls_verify=True openshift_pg_emptydir=False openshift_token=<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> awx_task_hostname=awx awx_web_hostname=awxweb postgres_data_dir=/tmp/pgdocker host_port=80 pg_username=awx pg_password=awxpass pg_database=awx pg_port=5432 rabbitmq_password=awxpass rabbitmq_erlang_cookie=cookiemonster admin_user=admin admin_password=<パスワード> create_preload_data=True secret_key=awxsecret ここまで準備できたら、installer を実行します。Ansible のプレイブックになっています。 $ ansible-playbook -i inventory install.yml … PLAY RECAP ********************************************************************************************************************************* localhost : ok=36 changed=18 unreachable=0 failed=0 エラーなく終了したら、oc で確認してみてください。 $ oc status In project awx on server https://192.168.99.101:8443 https://awx-web-svc-awx.192.168.99.101.nip.io (redirects) to pod port http (svc/awx-web-svc) svc/awx-rmq-mgmt - 172.30.87.193:15672 statefulset/awx manages ansible/awx_web:4.0.0,ansible/awx_task:4.0.0,ansible/awx_rabbitmq:3.7.4,memcached:latest created 22 minutes ago - 1 pod svc/postgresql - 172.30.100.39:5432 dc/postgresql deploys registry.access.redhat.com/rhscl/postgresql-96-rhel7:latest deployment #1 deployed 23 minutes ago - 1 pod svc/rabbitmq (all nodes) ports 15672, 5672 statefulset/awx manages ansible/awx_web:4.0.0,ansible/awx_task:4.0.0,ansible/awx_rabbitmq:3.7.4,memcached:latest created 22 minutes ago - 1 pod View details with 'oc describe <resource>/<name>' or list everything with 'oc get all'. $ oc get all NAME READY STATUS RESTARTS AGE pod/awx-0 4/4 Running 0 18m pod/postgresql-1-mgfsr 1/1 Running 0 23m NAME DESIRED CURRENT READY AGE replicationcontroller/postgresql-1 1 1 1 23m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/awx-rmq-mgmt ClusterIP 172.30.87.193 <none> 15672/TCP 22m service/awx-web-svc NodePort 172.30.170.21 <none> 80:30026/TCP 22m service/postgresql ClusterIP 172.30.100.39 <none> 5432/TCP 23m service/rabbitmq NodePort 172.30.116.189 <none> 15672:32006/TCP,5672:32707/TCP 22m NAME DESIRED CURRENT AGE statefulset.apps/awx 1 1 22m NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfig.apps.openshift.io/postgresql 1 1 1 config NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD route.route.openshift.io/awx-web-svc awx-web-svc-awx.192.168.99.101.nip.io awx-web-svc http edge/Redirect None では実際にアクセスしてみましょう。TLS証明書の警告は出ますが、アクセスできるはずです。 https://awx-web-svc-awx.192.168.99.101.nip.io inventory ファイルで admin_password に設定したパスワードを使って、admin ユーザでログインできます。 無事インストールできたでしょうか。最後に確認として、Demo Job Template を動かしてみてください。 Ansible Tower はすぐ導入できないという場合でも、AWX をぜひ使ってみてください。Happy Automation!
Red Hatの佐藤匡剛です。 APIコンポーネントフレームワーク紹介記事 の第4回目(最終回)です。 前回 は、フレームワークの中核であるAPIのマッピング設定を詳しく見ました。今回はプロジェクトを完成させるためのインテグレーションテストについて説明します。 コンポーネントのインテグレーションテスト Camelコンポーネントは外部サービスとの連携を提供するコードですので、それをきちんとテストするとなると必然的にインテグレーションテストになります。したがって、インテグレーションテストを追加するまではプロジェクトが完成したとは言えません。 APIコンポーネントフレームワークは、インテグレーションテストまで自動で用意してくれています。 第2回 のところでビルド後に生成されるソースコードについて眺めましたが、そこでチラッと出てきたテストコードの出番です。 プロジェクトにインテグレーションテストを追加する もう一度 camel-hello-component/target/generated-test-sources/camel-component/ を見てみます。 camel-hello-component/target/ └── generated-test-sources/camel-component/ └── com/redhat/sample/camel/hello/ ├── HelloFileHelloIntegrationTest.java └── HelloJavadocHelloIntegrationTest.java 見て分かるように、APIクラス毎にインテグレーションテストが作成されています。camel-helloコンポーネントの例では、 hello-file と hello-javadoc に対してそれぞれ xxxxxIntegrationTest.java が生成されています。 試しに HelloFileHelloIntegrationTest.java を開いて見ましょう。コメントに指示が書いてあります。 /** * Test class for {@link com.redhat.sample.camel.hello.api.HelloFileHello} APIs. * TODO Move the file to src/test/java, populate parameter values, and remove @Ignore annotations. * The class source won't be generated again if the generator MOJO finds it under src/test/java. */ public class HelloFileHelloIntegrationTest extends AbstractHelloTestSupport { [ ... ] このテストクラスを src/test/java に移して、パラメータの値をセットし、 @Ignore を外せ、という指示です。また、ソースが src/test/java に移されると、次のビルドからは同じクラスは自動生成されないとも書いてあります。 指示通りに、2つのテストクラスを camel-hello-component/src/test/java に移します。 インテグレーションテストを完成させる src/test/java にテストを移したら、改めてテストクラスの中身を見てみます。 public class HelloFileHelloIntegrationTest extends AbstractHelloTestSupport { private static final Logger LOG = LoggerFactory.getLogger(HelloFileHelloIntegrationTest. class ); private static final String PATH_PREFIX = HelloApiCollection.getCollection().getApiName(HelloFileHelloApiMethod. class ).getName(); // TODO provide parameter values for greetMe @Ignore @Test public void testGreetMe() throws Exception { // using String message body for single parameter "name" final String result = requestBody( "direct://GREETME" , null ); assertNotNull( "greetMe result" , result); LOG.debug( "greetMe: " + result); } // TODO provide parameter values for greetUs @Ignore @Test public void testGreetUs() throws Exception { final Map<String, Object> headers = new HashMap<String, Object>(); // parameter type is String headers.put( "CamelHello.name1" , null ); // parameter type is String headers.put( "CamelHello.name2" , null ); final String result = requestBodyAndHeaders( "direct://GREETUS" , null , headers); assertNotNull( "greetUs result" , result); LOG.debug( "greetUs: " + result); } @Ignore @Test public void testSayHi() throws Exception { final String result = requestBody( "direct://SAYHI" , null ); assertNotNull( "sayHi result" , result); LOG.debug( "sayHi: " + result); } @Override protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() { // test route for greetMe from( "direct://GREETME" ) .to( "hello://" + PATH_PREFIX + "/greetMe?inBody=name" ); // test route for greetUs from( "direct://GREETUS" ) .to( "hello://" + PATH_PREFIX + "/greetUs" ); // test route for sayHi from( "direct://SAYHI" ) .to( "hello://" + PATH_PREFIX + "/sayHi" ); } }; } } AbstractHelloTestSupport は元々 src/test/java に生成されているインテグレーションテストの抽象ベースクラスです。すべてのテストクラスに共通の初期化処理やヘルパーメソッドを提供したい場合は、このベースクラスを使います。 とりあえず冒頭コメントの指示通り、 @Ignore を外してテストパラメータを適宜セットしましょう。 @Test public void testGreetUs() throws Exception { final Map<String, Object> headers = new HashMap<String, Object>(); // parameter type is String headers.put( "CamelHello.name1" , "Llama" ); // parameter type is String headers.put( "CamelHello.name2" , "Alpaca" ); final String result = requestBodyAndHeaders( "direct://GREETUS" , null , headers); assertNotNull( "greetUs result" , result); LOG.debug( "greetUs: " + result); } これでひとまず mvn test がパスするようになるはずです。 TIPS: 標準APIコンポーネントの使い方を知るには 少し脱線しますが、Camel標準のAPIコンポーネントの使い方を知りたいときにも、この自動生成されたテストケースが役に立ちます。Camelのコンポーネントはドキュメントがよく整備されていますが、それでも実際に使おうとすると、どのエンドポイントにどのオプションが必要かといった情報が足りないことがあります。 その場合、APIコンポーネントフレームワークを使ったコンポーネントであれば、このフレームワークから自動生成されたテストを見ることで、エンドポイント毎にどのオプションが最低限必要なのかが一目で分かります。例えば、camel-boxの box://files/downloadFile エンドポイントのテストは以下の通りです。 https://github.com/apache/camel/blob/camel-2.23.1/components/camel-box/camel-box-component/src/test/java/org/apache/camel/component/box/BoxFilesManagerIntegrationTest.java @Test public void testDownloadFile() throws Exception { final Map<String, Object> headers = new HashMap<>(); // parameter type is String headers.put( "CamelBox.fileId" , testFile.getID()); // parameter type is java.io.OutputStream ByteArrayOutputStream output = new ByteArrayOutputStream(); headers.put( "CamelBox.output" , output); // parameter type is Long headers.put( "CamelBox.rangeStart" , null ); // parameter type is Long headers.put( "CamelBox.rangeEnd" , null ); // parameter type is com.box.sdk.ProgressListener headers.put( "CamelBox.listener" , null ); final java.io.OutputStream result = requestBodyAndHeaders( "direct://DOWNLOADFILE" , null , headers); assertNotNull( "downloadFile result" , result); LOG.debug( "downloadFile: " + result); } fileId と output が最低限必要なのが分かるでしょうか。 テストケースに認証情報を渡す 後はAPIライブラリを本物のWebサービスのものに差し替え、ちゃんとしたテストケースをどんどん追加していくだけなのですが、そのために必要な最後のポイントはサービスの認証情報をどうやってテストケースに渡すか、です。 インテグレーションテストのベースクラス AbstractHelloTestSupport を改めて見てみます。 public class AbstractHelloTestSupport extends CamelTestSupport { private static final String TEST_OPTIONS_PROPERTIES = "/test-options.properties" ; @Override protected CamelContext createCamelContext() throws Exception { final CamelContext context = super .createCamelContext(); // read Hello component configuration from TEST_OPTIONS_PROPERTIES final Properties properties = new Properties(); try { properties.load(getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES)); } catch (Exception e) { throw new IOException(String.format( "%s could not be loaded: %s" , TEST_OPTIONS_PROPERTIES, e.getMessage()), e); } Map<String, Object> options = new HashMap<String, Object>(); for (Map.Entry<Object, Object> entry : properties.entrySet()) { options.put(entry.getKey().toString(), entry.getValue()); } final HelloConfiguration configuration = new HelloConfiguration(); IntrospectionSupport.setProperties(configuration, options); // add HelloComponent to Camel context final HelloComponent component = new HelloComponent(context); component.setConfiguration(configuration); context.addComponent( "hello" , component); return context; } テストのブート時に呼ばれる createCamelContext() メソッドを見ると、 test-options.properties ファイルからプロパティを読み込み、それをプロジェクトの xxxxxConfiguration クラスに適用しているのが分かります。 test-options.properties ファイルは、 camel-hello-component/src/test/resources/test-options.properties に見つかります。 つまり、実際のWebサービスとのインテグレーションテストに必要な認証情報などは、この test-options.properties ファイルにセットすればいいのです。(認証情報なので、ソースコードリポジトリにはコミットしないように注意しましょう。) 例えば、camel-google-driveの test-options.properties は以下の通りです。 https://github.com/apache/camel/blob/camel-2.23.1/components/camel-google-drive/src/test/resources/test-options.properties ##################################### ## Login properties for Google Drive Component ##################################### ## Application client id and secret clientId= clientSecret= applicationName=camel-google-drive/ 1.0 # accessToken= refreshToken= camel-google-driveコンポーネントをテストしたい開発者は、この空のプロパティに適切に自分のテスト用の認証情報をセットしてインテグレーションテストを実行します。 おわりに 以上、全4回でAPIコンポーネントフレームワークの使い方を一通り説明しました。実際にCamelコンポーネントを開発しようとすると、まだまだ知っておくべき知識が色々と出てくると思いますが、それはコンポーネント開発一般に必要な知識なので、また別の機会に解説したいと思います。 とりあえず、分からないことがあったらまずはCamelの標準コンポーネントのソースコードを眺めてみる、というのが次のステップです(Camelに限らずOSS一般に言えることですが)。 今回作成したcamel-helloコンポーネントのソースコードは、以下のGitHubリポジトリに上がっています。 https://github.com/tadayosi/camel-hello
Red Hatの佐藤匡剛です。 APIコンポーネントフレームワーク紹介記事 の第3回目です。 前回 はこのフレームワークを使って、簡単なコンポーネントを作成してみました。今回は、現実のWebサービスAPIをコンポーネントに取り込むための高度な設定について見ていきます。 高度なマッピング設定 前回眺めた camel-hello-component/pom.xml から始めます。 <!-- generate Component source and test source --> <plugin> <groupId> org.apache.camel </groupId> <artifactId> camel-api-component-maven-plugin </artifactId> <executions> <execution> <id> generate-test-component-classes </id> <goals> <goal> fromApis </goal> </goals> <configuration> <apis> <api> <apiName> hello-file </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloFileHello </proxyClass> <fromSignatureFile> signatures/file-sig-api.txt </fromSignatureFile> <!-- Use substitutions to manipulate parameter names and avoid name clashes <substitutions> <substitution> <method>^(.+)$</method> <argName>^(.+)$</argName> <argType>java.lang.String</argType> <replacement>$1Param</replacement> <replaceWithType>false</replaceWithType> </substitution> </substitutions> --> <!-- Exclude automatically generated endpoint options by name <excludeConfigNames>name-pattern<excludeConfigNames> --> <!-- Exclude automatically generated endpoint options by type <excludeConfigTypes>type-pattern<excludeConfigTypes> --> <!-- Add custom endpoint options to generated EndpointConfiguration class for this API <extraOptions> <extraOption> <type>java.util.List<String></type> <name>customOption</name> </extraOption> </extraOptions> --> <!-- Use method aliases in endpoint URIs, e.g. support 'widget' as alias for getWidget or setWidget <aliases> <alias> <methodPattern>[gs]et(.+)</methodPattern> <methodAlias>$1</methodAlias> </alias> </aliases> --> <!-- for some methods, null can be a valid input <nullableOptions> <nullableOption>option-name</nullableOption> </nullableOptions> --> </api> <api> <apiName> hello-javadoc </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloJavadocHello </proxyClass> <fromJavadoc> <!-- Use exclude patterns to limit what gets exposed in component endpoint <excludePackages>package-name-patterns</excludePackages> <excludeClasses>class-name-patterns</excludeClasses> <includeMethods>method-name-patterns</includeMethods> <excludeMethods>method-name-patterns</excludeMethods> <includeStaticMethods>use 'true' to include static methods, false by default<includeStaticMethods> --> </fromJavadoc> </api> </apis> <!-- Specify global values for all APIs here, these are overridden at API level <substitutions/> <excludeConfigNames/> <excludeConfigTypes/> <extraOptions/> <fromJavadoc/> <aliases/> <nullableOptions/> --> </configuration> </execution> </executions> </plugin> <apiName> | <proxyClass> | <fromSignatureFile> | <fromJavadoc> この箇所は前回説明した通りですが、マッピングの最も重要な設定です。 <apiName> hello-file </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloFileHello </proxyClass> <fromSignatureFile> signatures/file-sig-api.txt </fromSignatureFile> <apiName> ― エンドポイントURI scheme://apiName/methodName?option1=value1&...&optionN=valueN の apiName プレフィクス部分の定義。 <proxyClass> ― エンドポイントに対応するAPIクラス。 <fromSignatureFile> | <fromJavadoc> ― シグネチャの取得方法(シグネチャファイル or Javadoc)。 <substitution> APIメソッドの引数は、エンドポイントのオプションにマッピングされます。しかし、エンドポイントの apiName とAPIクラスとは1:1に対応するため、APIクラス内の複数メソッドで別々の型の引数に同じ名前が付いていた場合(ex. String date と Date date )にエンドポイントオプションの衝突が起きてしまいます。 <substitution> を使うと、正規表現を使って特定の引数を別の名前に置換して、名前の衝突を避けることができます。 <!-- Use substitutions to manipulate parameter names and avoid name clashes --> <substitutions> <substitution> <method> ^(.+)$ </method> <argName> ^(.+)$ </argName> <argType> java.lang.String </argType> <replacement> $1Param </replacement> <replaceWithType> false </replaceWithType> </substitution> </substitutions> <method> | <argName> ― 置換対象のメソッドと引数の名前。正規表現で指定する。 <argType> ― (オプション)特定の型の引数だけを対象にしたい場合に使う。正規表現で指定する。 <replacement> ― 置換後の引数名。正規表現のグループ( $1 、 $2 、…)を参照できる。 <replaceWithType> ― デフォルト(= false )は <argName> の正規表現からグループを参照するが、 true にすると代わりに <argType> のグループを参照できる。 <excludeConfigNames> | <excludeConfigTypes> エンドポイントオプションに含めたくない引数は、ここで正規表現を使って除外できます。 <!-- Exclude automatically generated endpoint options by name --> <excludeConfigNames> name-pattern <excludeConfigNames> <!-- Exclude automatically generated endpoint options by type --> <excludeConfigTypes> type-pattern <excludeConfigTypes> <excludeConfigNames> ― 除外する引数を引数名で指定。 <excludeConfigTypes> ― 除外する引数を型で指定。 <extraOption> メソッド引数に登場しないオプションを追加できます。 <!-- Add custom endpoint options to generated EndpointConfiguration class for this API --> <extraOptions> <extraOption> <type> java.util.List & lt ; String & gt ; </type> <name> customOption </name> </extraOption> </extraOptions> 用途としては、例えば、そのままオプションとして使うには生成が複雑なオブジェクトの引数を上の <excludeConfigNames> 、 <excludeConfigTypes> で除外し、代わりにその生成に必要なパラメータをこのカスタムオプションとして定義する、などです。 追加したカスタムオプションは、プロジェクトのEndpoint、Consumer、Producer各クラスの中で interceptProperties() メソッドをオーバーライドし、その中で実際にAPIメソッドに必要な引数に変換します。下はcamel-olingo4の例です。 https://github.com/apache/camel/blob/camel-2.23.1/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Endpoint.java @Override public void interceptProperties(Map<String, Object> properties) { // read Edm if not set yet properties.put(EDM_PROPERTY, apiProxy.getEdm()); // handle filterAlreadySeen property properties.put(FILTER_ALREADY_SEEN, configuration.getFilterAlreadySeen()); // handle keyPredicate final String keyPredicate = (String)properties.get(KEY_PREDICATE_PROPERTY); if (keyPredicate != null ) { // make sure a resource path is provided final String resourcePath = (String)properties.get(RESOURCE_PATH_PROPERTY); if (resourcePath == null ) { throw new IllegalArgumentException( "Resource path must be provided in endpoint URI, or URI parameter '" + RESOURCE_PATH_PROPERTY + "', or exchange header '" + Olingo4Constants.PROPERTY_PREFIX + RESOURCE_PATH_PROPERTY + "'" ); } // append keyPredicate to dynamically create resource path properties.put(RESOURCE_PATH_PROPERTY, resourcePath + '(' + keyPredicate + ')' ); } // handle individual queryParams parseQueryParams(properties); } <alias> APIのメソッドにエイリアスを設定できます。エイリアスを設定すると、エンドポイントの methodName の部分に元々のメソッド名とエイリアスのどちらも使えるようになります。 <!-- Use method aliases in endpoint URIs, e.g. support 'widget' as alias for getWidget or setWidget --> <aliases> <alias> <methodPattern> [gs]et(.+) </methodPattern> <methodAlias> $1 </methodAlias> </alias> </aliases> エイリアスを設定すると、例えば greetMe(...) 、 greetUs(...) 各メソッドに対して以下のようなエンドポイントを定義できる。 hello://hello-file/me hello://hello-file/us <nullableOption> null値がOKなオプションを指定できます。 <!-- for some methods, null can be a valid input --> <nullableOptions> <nullableOption> option-name </nullableOption> </nullableOptions> Javadoc固有の設定 最後に、Javadoc方式を採用した場合に固有の設定です。 <fromJavadoc> <!-- Use exclude patterns to limit what gets exposed in component endpoint --> <excludePackages> package-name-patterns </excludePackages> <excludeClasses> class-name-patterns </excludeClasses> <includeMethods> method-name-patterns </includeMethods> <excludeMethods> method-name-patterns </excludeMethods> <includeStaticMethods> use 'true' to include static methods, false by default <includeStaticMethods> </fromJavadoc> <excludePackages> | <excludeClasses> ― <proxyClass> で指定したAPIクラスからメソッドを読み込む際に、そのスーパークラスのメソッド読み込みを除外するための設定。パッケージまたはクラスを正規表現パターンで指定。 <excludePackages> のデフォルトは javax?\.lang.* 。 <includeMethods> ― APIの読み込みに明示的に含めるメソッドの正規表現パターン。 <excludeMethods> ― APIの読み込みから除外するメソッドの正規表現パターン。 <includeStaticMethods> ― staticメソッドを含めるかどうか。デフォルトは含めない(= false )。 グローバル設定 上記の設定パラメータは、 <api>...</api> で囲まれたエンドポイント毎に設定することもできますし、 <apis> の外に設定することでグローバルに適用することもできます。グローバルの設定は、エンドポイント毎の設定で上書きされます。 <configuration> <apis> <api> [...] <!-- エンドポイント固有の設定 --> </api> </apis> <!-- グローバル設定 --> <substitutions> ... </substitutions> <excludeConfigNames> ... </excludeConfigNames> <excludeConfigTypes> ... </excludeConfigTypes> <extraOptions> ... </extraOptions> <fromJavadoc> ... </fromJavadoc> <aliases> ... </aliases> <nullableOptions> ... </nullableOptions> </configuration> エンドポイント毎のConfigurationクラス ここまでのマッピング設定によってAPIから読み込まれた引数オプションは、コンポーネントプロジェクトの target/generated-sources/camel-component の下にエンドポイント毎のConfigurationクラスとして自動生成されます。 前回作成したcamel-helloサンプルプロジェクトを見ると、以下のConfigurationクラスが生成されています。これらのクラスは、上記のマッピング設定から毎回自動生成されるものなので、その後手動で編集する必要はありません(してはいけません)。 camel-hello-component/target/ └── generated-sources/camel-component/ └── com/redhat/sample/camel/hello/ ├── HelloFileHelloEndpointConfiguration.java └── HelloJavadocHelloEndpointConfiguration.java おわりに APIコンポーネントフレームワークでは、この道具立てで既存のAPIをコンポーネントにマッピングして取り込むことになります。すでに様々なAPIコンポーネントがこのフレームワークで作られていることから分かるように、よほどエキセントリックなAPIでない限りこのマッピング設定でAPIを取り込むことができます。 それでも実際にAPIをマッピングしようとして迷ったときは、このフレームワークを使って作られているCamel標準コンポーネント( 第1回 参照)のソースコードを参照するといいでしょう。 次回、最終回はインテグレーションテストを追加することで、APIコンポーネントのプロジェクトを完成させます。 次の記事 ― APIコンポーネントのテスト
Red Hatの佐藤匡剛です。 APIコンポーネントフレームワーク紹介記事 の第2回目です。 前回 はこのフレームワークが何なのかを説明したので、今回は実際にその使い方を説明します。 プロジェクトの生成 APIコンポーネントフレームワークを使ってカスタムコンポーネントを開発するには、まずMavenアーキタイプ camel-archetype-api-component でプロジェクトの雛形を生成します。 $ mvn archetype:generate \ -DarchetypeGroupId = org.apache.camel.archetypes \ -DarchetypeArtifactId = camel-archetype-api-component \ -DarchetypeVersion = 2.23.1 \ -DgroupId = com.redhat.samples \ -DartifactId = camel-hello \ -Dname = Hello \ -Dscheme = hello \ -Dversion = 1.0-SNAPSHOT \ -DinteractiveMode =false 以下のようなMavenマルチプロジェクトが生成されます。 name パラメータの文字列が xxxxxComponent 、 xxxxxConfiguration 、 xxxxxConsumer 、 xxxxxEndpoint 、 xxxxxProducer といったクラス名のプレフィックスになります。 scheme パラメータの文字列が生成されるコンポーネントのエンドポイントURIのスキーム名( "hello://..." )になります。 camel-hello/ ├── camel-hello-api/ │   ├── pom.xml │   └── src/main/java/com/redhat/sample/camel/hello/api/ │   ├── HelloFileHello.java │   └── HelloJavadocHello.java ├── camel-hello-component/ │   ├── pom.xml │   ├── signatures/ │   │   └── file-sig-api.txt │   └── src/ │   ├── main/ │   │   ├── java/com/redhat/sample/camel/hello/ │   │   │   ├── HelloComponent.java │   │   │   ├── HelloConfiguration.java │   │   │   ├── HelloConsumer.java │   │   │   ├── HelloEndpoint.java │   │   │   ├── HelloProducer.java │   │   │   └── internal/ │   │   │   ├── HelloConstants.java │   │   │   └── HelloPropertiesHelper.java │   │   └── resources/META-INF/services/org/apache/camel/component/ │   │   └── hello │   └── test/ │   ├── java/com/redhat/sample/camel/hello/ │   │   └── AbstractHelloTestSupport.java │   └── resources/ │   ├── log4j2.properties │   └── test-options.properties └── pom.xml プロジェクトは2つのサブプロジェクトで構成されています。 xxxxx-api ― (オプション)3rdパーティのJavaライブラリを直接使えない場合に、カスタムでAPIを用意するためのプロジェクト。REST APIの場合も生成したJavaクライアントをここに置く。必要無い場合は、ルートプロジェクトと一緒に削除して xxxxx-component プロジェクトだけを使う。 xxxxx-component ― 開発するコンポーネントの本体。 camel-hello-component/pom.xml を見ると、 camel-hello-api がdependencyに定義されています。3rdパーティのライブラリを使う場合は、このAPIプロジェクトを削除して代わりにライブラリのdependencyに置き換えます。 <dependency> <groupId> com.redhat.sample.camel.hello </groupId> <artifactId> camel-hello-api </artifactId> <version> 1.0-SNAPSHOT </version> </dependency> [...] <!-- Component API javadoc in provided scope to read API signatures --> <dependency> <groupId> com.redhat.sample.camel.hello </groupId> <artifactId> camel-hello-api </artifactId> <version> 1.0-SNAPSHOT </version> <classifier> javadoc </classifier> <scope> provided </scope> </dependency> 例えば、camel-twilioでは以下のようになっています。 https://github.com/apache/camel/blob/camel-2.23.1/components/camel-twilio/pom.xml <!-- Twilio Java SDK --> <dependency> <groupId> com.twilio.sdk </groupId> <artifactId> twilio </artifactId> <version> ${twilio-version} </version> </dependency> [...] <!-- Component API javadoc in provided scope to read API signatures --> <dependency> <groupId> com.twilio.sdk </groupId> <artifactId> twilio </artifactId> <version> ${twilio-version} </version> <type> javadoc </type> <scope> provided </scope> </dependency> ここで javadoc タイプのdependencyも登場していますが、なぜ必要かはこれから説明します。 ひとまずは camel-hello-api を使ってcamel-helloコンポーネントを完成させます。 APIとエンドポイントURIのマッピング 次にやることは、APIとCamelエンドポイントとのマッピングを設定することです。第1回に説明したように、APIコンポーネントのエンドポイントURIは基本的に以下の形式になります。 scheme://apiName/methodName?option1=value1&...&optionN=valueN 自動生成された camel-hello-api のAPIクラス HelloFileHello を見ると、以下の通りです。 public class HelloFileHello { public String sayHi() { return "Hello!" ; } public String greetMe(String name) { return "Hello " + name; } public String greetUs(String name1, String name2) { return "Hello " + name1 + ", " + name2; } } これを、以下のようなエンドポイントURIにマッピングします。 hello://hello-file/sayHi hello://hello-file/greetMe hello://hello-file/greetUs メソッド引数のマッピング APIメソッドの引数は、次のようにURIのオプションにハードコードして渡すこともできます。 hello://hello-file/greetUs?name1=Llama&name2=Alpaca しかし、たいていの場合は動的に値を渡したいと思うので、Camelメッセージのヘッダで渡します。 from( "direct:sayHello" ) .setHeader( "CamelHello.name1" , constant( "Llama" )) .setHeader( "CamelHello.name2" , constant( "Alpaca" )) .to( "hello://hello-file/greetUs" ); ヘッダ名は CamelXxxxx. + <引数名> です。 Xxxxx には、プロジェクト生成時に name パラメータで指定した文字列が入ります。 メッセージボディを直接引数に渡したい場合は、特別なURIオプション inBody を使います。 inBody の値には、ボディをどの引数に渡すかを引数名で指定します。 .to( "hello://hello-file/greetMe?inBody=name" ); これで greetMe メソッドの引数 name にメッセージボディが直接渡されます。 javadoc dependencyが必要な理由 第1回の記事で、APIコンポーネントフレームワークの要点はコード生成とリフレクションだと説明しました。このAPIメソッドからエンドポイントURIへのマッピングでリフレクションが使われるので、開発者がメソッド毎にいちいちエンドポイントの処理を手書きする必要がありません。しかし、メソッドの引数名は、Javaバイトコードの仕様上リフレクションで取得することができません。Javaの.classファイルには引数名の情報が残っていないからです。 そこで、dependencyのJARファイルとは別にAPIのシグネチャを取得する方法が必要です。APIコンポーネントフレームワークは2つの方法をサポートしています。 Javadocから取得する テキストファイルに書き出したシグネチャを読み込む そのため、1の方法を用いる場合に javadoc のdependencyが必要になるのです。 APIコンポーネントのマッピング設定 camel-hello-component/pom.xml を開いて、Mavenプラグインにマッピング設定を記述します。すでに様々なオプションがコメントアウトされた状態で出力されているので、これを眺めるだけでもどんなことができるのか、ある程度理解できると思います。 <!-- generate Component source and test source --> <plugin> <groupId> org.apache.camel </groupId> <artifactId> camel-api-component-maven-plugin </artifactId> <executions> <execution> <id> generate-test-component-classes </id> <goals> <goal> fromApis </goal> </goals> <configuration> <apis> <api> <apiName> hello-file </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloFileHello </proxyClass> <fromSignatureFile> signatures/file-sig-api.txt </fromSignatureFile> <!-- Use substitutions to manipulate parameter names and avoid name clashes <substitutions> <substitution> <method>^(.+)$</method> <argName>^(.+)$</argName> <argType>java.lang.String</argType> <replacement>$1Param</replacement> <replaceWithType>false</replaceWithType> </substitution> </substitutions> --> <!-- Exclude automatically generated endpoint options by name <excludeConfigNames>name-pattern<excludeConfigNames> --> <!-- Exclude automatically generated endpoint options by type <excludeConfigTypes>type-pattern<excludeConfigTypes> --> <!-- Add custom endpoint options to generated EndpointConfiguration class for this API <extraOptions> <extraOption> <type>java.util.List<String></type> <name>customOption</name> </extraOption> </extraOptions> --> <!-- Use method aliases in endpoint URIs, e.g. support 'widget' as alias for getWidget or setWidget <aliases> <alias> <methodPattern>[gs]et(.+)</methodPattern> <methodAlias>$1</methodAlias> </alias> </aliases> --> <!-- for some methods, null can be a valid input <nullableOptions> <nullableOption>option-name</nullableOption> </nullableOptions> --> </api> <api> <apiName> hello-javadoc </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloJavadocHello </proxyClass> <fromJavadoc> <!-- Use exclude patterns to limit what gets exposed in component endpoint <excludePackages>package-name-patterns</excludePackages> <excludeClasses>class-name-patterns</excludeClasses> <includeMethods>method-name-patterns</includeMethods> <excludeMethods>method-name-patterns</excludeMethods> <includeStaticMethods>use 'true' to include static methods, false by default<includeStaticMethods> --> </fromJavadoc> </api> </apis> <!-- Specify global values for all APIs here, these are overridden at API level <substitutions/> <excludeConfigNames/> <excludeConfigTypes/> <extraOptions/> <fromJavadoc/> <aliases/> <nullableOptions/> --> </configuration> </execution> </executions> </plugin> ひとまずポイントはここです。 <api> <apiName> hello-file </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloFileHello </proxyClass> <fromSignatureFile> signatures/file-sig-api.txt </fromSignatureFile> [...] </api> <apiName> でエンドポイントURIの apiName に当たる部分を定義します。 <proxyClass> でそのエンドポイントの下敷きとなるAPIクラスを指定します。先ほどAPIのシグネチャを読み込む方法が2通りあると言いましたが、 <fromSignatureFile> はファイルベースの方法です。 signatures/file-sig-api.txt を見るとこのようにシグネチャが定義されています。 public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2); シグネチャファイルでなくJavadocを使う場合は <fromJavadoc> を指定します。この場合、わざわざ自分でシグネチャを書く必要がないので、通常はこちらの方法がお勧めです。3rdパーティライブラリにJavadocがない、など特殊な場合にのみシグネチャファイルを使います。 <api> <apiName> hello-javadoc </apiName> <proxyClass> com.redhat.sample.camel.hello.api.HelloJavadocHello </proxyClass> <fromJavadoc> [...] </fromJavadoc> </api> とりあえず設定はこのままでも動くので、このまま進めます。 ConfigurationとEndpointの修正 ソースコードで最低限修正が必要なのは2箇所です。まずは camel-hello-component/src/main/java/com/redhat/sample/camel/hello/HelloConfiguration.java を開きます。 @UriParams public class HelloConfiguration { // TODO add component configuration properties } ここに、コンポーネントの設定に必要なパラメータを追加します。Webサービスであれば、最低でも接続に認証情報が必要になるはずです。そういった、ユーザがこのコンポーネントを使う際に設定すべきパラメータをここに追加します。とりあえず、今回はダミーのHello APIを呼び出すだけなのでこのままにします。 次に、 camel-hello-component/src/main/java/com/redhat/sample/camel/hello/HelloEndpoint.java を開きます。 @UriEndpoint (firstVersion = "1.0-SNAPSHOT" , scheme = "hello" , title = "Hello" , syntax= "hello:name" , consumerClass = HelloConsumer. class , label = "custom" ) public class HelloEndpoint extends AbstractApiEndpoint<HelloApiName, HelloConfiguration> { [ ... ] // TODO create and manage API proxy private Object apiProxy; [ ... ] @Override protected void afterConfigureProperties() { // TODO create API proxy, set connection properties, etc. switch (apiName) { case HELLO_FILE: apiProxy = new HelloFileHello(); break ; case HELLO_JAVADOC: apiProxy = new HelloJavadocHello(); break ; default : throw new IllegalArgumentException( "Invalid API name " + apiName); } } 重要なのは afterConfigureProperties() メソッドです。ここで、エンドポイント毎にAPIオブジェクトのインスタンスを生成し、 apiProxy フィールドに保持します。APIオブジェクトを生成する際にWebサービスへの接続が必要な場合は、ここで先ほど修正したConfigurationクラスから必要なパラメータを受け取って接続を行います。ここも、今回のサンプルではこのままにします。 ビルドと実行 プロジェクトが完成したら、以下を実行してビルド&インストールをします。 $ mvn clean install ビルドが成功すると、 camel-hello-component/target/ にソースコードが生成されているのが見つかります。 camel-hello-component/target/ ├── generated-sources/camel-component/ │ └── com/redhat/sample/camel/hello/ │ ├── HelloFileHelloEndpointConfiguration.java │ ├── HelloJavadocHelloEndpointConfiguration.java │ └── internal/ │ ├── HelloApiCollection.java │ ├── HelloApiName.java │ ├── HelloFileHelloApiMethod.java │ └── HelloJavadocHelloApiMethod.java └── generated-test-sources/camel-component/ └── com/redhat/sample/camel/hello/ ├── HelloFileHelloIntegrationTest.java └── HelloJavadocHelloIntegrationTest.java generated-sources の方は、Mavenの設定でビルド時に一緒にコンパイルされるようになっています。毎回ビルド時に自動生成されるものなので、ソースコードリポジトリにコミットする必要はありません。 generated-test-sources についても同様ですが、最終回のテストのところで詳しく説明します。 出来上がったコンポーネントは、標準のCamelコンポーネントと同じようにMavenのdependencyに追加して、Camelルートより実行してください。 <dependency> <groupId> com.redhat.sample.camel.hello </groupId> <artifactId> camel-hello </artifactId> <version> 1.0-SNAPSHOT </version> </dependency> 試しに次のような単体テストを実行してみましょう。 public class HelloTest extends CamelTestSupport { @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { @Override public void configure() throws Exception { from( "direct:sayHello" ) .setHeader( "CamelHello.name1" , constant( "Llama" )) .setHeader( "CamelHello.name2" , constant( "Alpaca" )) .to( "hello://hello-file/greetUs" ) .log( "${body}" ); } }; } @Test public void sayHello() throws Exception { template.sendBody( "direct:sayHello" , null ); } } 実行結果はこんな感じになります。 $ mvn test -Dtest = HelloTest ... [ amel -1 ) thread #1 - CamelHello] route1 INFO Hello Llama, Alpaca おわりに とりあえず動作するコンポーネントが完成しました。しかし、野生のWebサービスのAPIは千差万別であり、それを上手くコンポーネントに飼いならすには高度なマッピングの設定が必要不可欠です。 次回は、高度なマッピング設定の方法を説明します。 次の記事 ― APIコンポーネントフレームワークの高度な設定
Red Hatの佐藤匡剛です。 Apache Camelの APIコンポーネントフレームワーク について紹介します。このミニフレームワークは個人的にCamelのキラーフィーチャーだと思っているんですが、日本語はおろか英語でも開発者本人のブログかRed Hat Fuseの公式ドキュメントくらいしか紹介記事がありません。 http://planet.jboss.org/post/apache_camel_api_component_framework_or_how_i_learned_to_stop_worrying_and_love_writing_feature_rich_camel_components https://access.redhat.com/documentation/en-us/red_hat_fuse/7.2/html/apache_camel_development_guide/apicompframework Camelを使っていても、実は知らない方が多いのではないかと思います。 そこで、以下の全四部構成(予定)でAPIコンポーネントフレームワークの使い方を紹介したいと思います。 APIコンポーネントフレームワークとは何か(この記事) APIコンポーネントフレームワークを使ってみる APIコンポーネントフレームワークの高度な設定 APIコンポーネントのテスト APIコンポーネントフレームワークとは Camelでは個々の外部システムとの連携機能を提供するモジュールを コンポーネント と呼びます。APIコンポーネントフレームワークとは、連携先の外部サービス(Twitter、LinkedIn、Salesforce、etc.)がRESTやJava SDKの形で提供するAPIを元に、コンポーネントの雛形を生成してくれるCamelの一機能です。 実際のところ、Camelがインテグレーションフレームワークとして圧倒的優位にあるのは 300以上ある連携コンポーネント の数が大きいと思っていますが、APIコンポーネントフレームワークがコンポーネント開発を大幅に容易にすることでそれを支えています。Alpakkaなど、Camelと競合する魅力的なインテグレーションフレームワークもいくつかありますが、ぜひこのAPIコンポーネントフレームワークの仕組みも採用したらいいのになと思います。 なぜAPIコンポーネントフレームワークが必要か APIコンポーネントフレームワークを使わずとも、 Camelのカスタムコンポーネントを開発するのは簡単 です。しかし、内製の特定用途にフォーカスしたカスタムコンポーネントならいいですが、WebサービスのAPIを網羅した高品質なコンポーネントをフルスクラッチで開発しようとすると、REST APIやSDKライブラリのクラスをCamelコンポーネントとしてラップするための膨大な繋ぎのコードを書かねばならず、大変骨が折れます。 そうした高品質のコンポーネントをたくさん提供しなければならないという、Camelコミュニティにおける開発ニーズからAPIコンポーネントフレームワークは生み出されました。現時点で、このフレームワークを使って作られている標準コンポーネントには以下のものがあります。 camel-as2 camel-box camel-braintree camel-fhir camel-google-* camel-linkedin camel-olingo2 camel-olingo4 camel-twilio camel-zendesk APIコンポーネントフレームワークの仕組み Camelのコンポーネント開発の基本は、連携対象サービスのインタフェース(API)を以下のようなエンドポイントURIに落とし込むことです。 scheme://endpoint?option1=value1&...&optionN=valueN 例えばJMSブローカであれば、 myqueue という名前のキューを queue://myqueue のようなエンドポイントで指定できます。 最近のWebサービスは、たいていAPIがRESTやJava SDKライブラリの形で提供されています。Java SDKの場合は、APIとなるクラスとメソッドをエンドポイントにマッピングすることになります。RESTの場合は、いったんWADLやSwaggerからJavaクライアントを生成し、それをJava SDKと同様にAPIとして使います。 APIコンポーネントフレームワークのエッセンスは、ビルド時のコード生成と実行時のリフレクションです。それによって、SDKのクラスとメソッドを以下のようなエンドポイントURIに自動的にマッピングします。 scheme://apiName/methodName?option1=value1&...&optionN=valueN マッピングのカスタマイズは、プロジェクト pom.xml 内のMavenプラグインの設定で行います。 pom.xml 内にマッピングを定義するだけで、SDKが提供する幅広い機能を網羅的にサポートすることができます。 言ってしまえば、APIコンポーネントフレームワークは3rdパーティのJava SDKをCamelのエンドポイントとしてラップして、ルートの中で呼び出せるようにする仕組み、のようなものです。 おわりに 抽象的な話はここまでで終わりです。次の記事からは、このフレームワークを使って実際にAPIコンポーネントを作ってみましょう。 次の記事 ― APIコンポーネントフレームワークを使ってみる
Red HatでOpenShiftのサポートをしている id:nekop です。3年前くらいまでJBoss Middlewareを主に担当していたので久しぶりなサーバサイドJavaネタとなるのですが、QuarkusというKubernetesネイティブJavaアプリケーションフレームワークをリリースしました。 quarkus.io 読み方は「くぉーかす」です。キャッチコピーがSupersonic Subatomic Javaとなっているように、高速軽量コンパクトなランタイムがウリです。また、コンテナ化やクラスのHot reloading対応などの開発容易性も備えています。 現在ではJava EEのアプリケーションサーバ上へのパッケージ化されたアプリケーションのデプロイ、Spring Bootなどに代表されるfat jarを利用したよりモダンなデプロイの2つのデプロイ形態が広く利用されていますが、その次の世代となる軽量なバイナリを生成するネイティブコンパイル可能なデプロイ形態です。 サーバサイドアプリケーションはKubernetes上での実行に対応することを求められるようになってきていますが、KubernetesやFaaSといった実行プラットフォームにデプロイする場合に、通常のJava VMの起動時のCPUの利用量の大きさ、必要なメモリ量の大きさ、バイナリのサイズなどのオーバヘッドはかなり大きなペナルティとなってしまい、結果としてJavaが敬遠されてGoなどの他言語が採用される状況も増えてきました。この課題を解決するために誕生したのがQuarkusです。より詳細な背景については EmmanuelのWhy Quarkus というブログエントリに記述されています。 in.relation.to 従来のJava EEやSpring BootアプリなどではJava VMとライブラリとアプリで最小130MB程度、実用アプリだと200MBなどとなってしまっていました。Quarkusのgetting-startedをnativeコンパイルしたときに生成されるシングルバイナリのサイズは20MB程度です。このバイナリには標準のJava VMとは異なるVM実装であるSubstrate VMというものが含まれており、動作に別途Java VMがインストールされている必要はありません。このあたりについての詳細はGraalVMのドキュメント Ahead-of-time Compilation を参照してください。バイナリサイズの他にランタイムの起動速度、CPU利用量、メモリ利用量などもJava VMに比較するとほとんどの場合で数倍改善されています。 既に日本語でも以下の代表的な記事のほか、多くの紹介記事が出ています。このブログでも技術詳細などについて引き続きアップデートしていこうと思います。 Javaフレームワーク「Quarkus」登場。Javaコードからネイティブバイナリを生成し瞬時にJavaアプリが起動、コンテナへの最適化を実現。Red Hatがリリース - publickey https://www.publickey1.jp/blog/19/javaquarkusjavajavared_hat.html Quarkus: コンテナ上で Java アプリを高速起動する新しい手法のご紹介 - Yoshio Terada https://yoshio3.com/2019/03/11/try-quarkus/ また、Quarkusのリリースに伴い、fat jar形式のランタイムを提供する Thorntailの次期メジャーバージョン4.xの開発は終了 となりました。Thorntail 2.xについては引き続きメンテナンスは行われる予定です。
クラウドインフラ全般を担当しているソリューションアーキテクトの伊藤です。 はじめに OpenShiftを利用する際は様々な環境でデプロイすることができます。 以下の図のA. のようにオンプレミスでのデプロイは、コスト効率、柔軟性なインフラ構成、レガシーアプリケーションとの接続性といった観点で有利に働きます。 また他の構成として、マネージドサービスを利用することで早く、簡単にOpenShiftを利用することができます。 図のB-2. のようにいくつかのマネージドサービスを選択できます。 そして今回は上記図のA-4. の様に2019年1月にリリースされたRed Hat OpenStack Platform 14(RHOSP14)を使って、OpenShiftをデプロイしたいと思います。 Directorについて RHOSPにはDirectorと呼ばれるインフラをデプロイするためのツールが備わっています。 このDirectorはOpenStackをデプロイするのは勿論のこと、以下の4つのソフトウェアをデプロイすることが可能です。 ・OpenStack ・OpenShift ・Ceph Storage ・OpenShiftに付随するストレージとしてGluster Storage また、デプロイするサーバに割り当てるプロファイルを調整することで、 ・OpenStackのみをデプロイ ・OpenStackとCeph Storageをデプロイ ・OpenShiftのみをデプロイ ・OpenShiftとGluster Storageをデプロイ ・OpenStackとOpenShift、Ceph Storage、Gluster Storageをデプロイ といったサブスクリプションの所有状況やインフラ要件に応じて、デプロイをするソフトウェアを切り替えられます。 以下の図は例として ・赤い線でDirectorでOpenStackとCeph Storageをデプロイする ・緑の線でDirectorでOpenShiftとGluster Storageをデプロイする という例を示しました。 ・OpenShiftをDirectorからデプロイする手順 以下のOSP14のドキュメントでは、Directorでベアメタルにデプロイする方法とOpenStack上の仮想インスタンスへデプロイする方法が記載されています。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/installing_openshift_container_platform_on_bare_metal_using_director/ Directorでデプロイする際には以下の要素を抑えておきます。 ・コンポーザブルロール Directorによるデプロイでは役割を最初に定義します。役割をホストに割り当てることでデプロイする構成が決まります。 Composable Rolesと言い、OpenShiftをデプロイする際は通常、OpenShiftMaster, OpenShiftWorker, OpenShiftInfraという3つのロールを定義します。 ・Directorがデプロイに使用するコンテナレジストリ コンポーザブルロールにはそのロールが、どのソフトウェアを必要とするかを定義します。 Director環境下ではソフトウェアはコンテナによってパッケージングされます。ロールを定義するときに動作させるソフトウェアが決まるためロールに適したコンテナをコンテナレジストリに登録します。 ・DirectorがIPMIで制御可能なホストのリスト DirectorがOpenShiftをデプロイする先の物理サーバをjsonフォーマットで定義します。 IPMIのIPアドレス、アカウント情報、割り当てるプロファイルなどを記載します。 ・Directorが環境を理解するための構成ファイル environmentファイルと呼ばれているものになります。 ホスト名、VLAN、IPアドレスといったネットワーク構成、利用するストレージ構成、サーバ証明書、クラウドの名前まで環境ファイルで定義するものは多岐に渡ります。 定義した環境ファイルは、デプロイ時のコマンドにすべて記載します。 重要な要素はたった4つです! 手順 これから説明する手順は例となりますので、実際にデプロイする環境に合わせてご準備頂く必要があります。 ・Director(Undercloud)のセットアップ Red Hat OpenStack Platformの世界においては ・クラウド基盤利用者が実際に使うインフラソフトウェアがインストールされたサーバをOvercloud ・そのOvercloudをデプロイするためのサーバをUndercloud と言います。 まずDirectorでOpenShiftをデプロイするには、Director自体をセットアップしなくてはなりません。 RHEL7がインストールされたサーバを準備し、ドキュメントのようにDirectorをセットアップしていきます。 実際のところ、UndercloudのセットアップはOpenStackをデプロイする際と変わりません。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html/director_installation_and_usage/planning-your-undercloud echo "stack ALL=(root) NOPASSWD:ALL" | tee -a /etc/sudoers.d/stack && chmod 0440 /etc/sudoers.d/stack && su - stack mkdir ~/images && mkdir ~/templates sudo subscription-manager register sudo subscription-manager list --available --all --matches="Red Hat OpenStack" sudo subscription-manager attach --pool=Valid-Pool-Number-123456 sudo subscription-manager repos --disable=* --enable=rhel-7-server-rpms --enable=rhel-7-server-extras-rpms --enable=rhel-7-server-rh-common-rpms --enable=rhel-ha-for-rhel-7-server-rpms --enable=rhel-7-server-openstack-14-rpms --enable=rhel-7-server-rhceph-3-tools-rpms sudo yum update -y sudo yum install -y python-tripleoclient ceph-ansible rhosp-director-images rhosp-director-images-ipa libguestfs-tools OpenIPMI-tools reboot openstack tripleo container image prepare default --local-push-destination --output-env-file containers-prepare-parameter.yaml sudo openstack tripleo container image prepare -e ~/containers-prepare-parameter.yaml cp /usr/share/python-tripleoclient/undercloud.conf.sample ~/undercloud.conf #undercloud.confは環境に応じて変更してください openstack undercloud install これで/home/stack/stackrc というファイルが生成されたらDirectorのインストールが完了ですので、その後の各コマンドが動作するかご確認下さい。 ・コンポーザブルロールの定義 コンポーザブルロールを定義します。 openstack overcloud roles generate -o /home/stack/templates-ocp/openshift_roles_data.yaml OpenShiftMaster OpenShiftWorker OpenShiftInfra ・Directorにデプロイ対象のサーバを登録 スペックに合わせたフレーバーを作成し、それぞれにプロファイルを割り当てます。 OpenStackをデプロイする際とcapabilitiesを除いて変わりません。 instackenv.jsonの例: この例はOpenShiftWorker、OpenShiftMaster、OpenShiftInfraノードがそれぞれ3台です。 { "nodes":[ { "name": "worker001", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.131", "capabilities": "profile:OpenShiftWorker,boot_option:local,node:worker-0", "arch":"x86_64" }, { "name": "worker002", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.132", "capabilities": "profile:OpenShiftWorker,boot_option:local,node:worker-1", "arch":"x86_64" }, { "name": "worker003", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.133", "capabilities": "profile:OpenShiftWorker,boot_option:local,node:worker-2", "arch":"x86_64" }, { "name": "master001", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.141", "capabilities": "profile:OpenShiftMaster,boot_option:local,node:master-0", "arch":"x86_64" }, { "name": "master002", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.142", "capabilities": "profile:OpenShiftMaster,boot_option:local,node:master-1", "arch":"x86_64" }, { "name": "master003", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.143", "capabilities": "profile:OpenShiftMaster,boot_option:local,node:master-2", "arch":"x86_64" }, { "name": "infra001", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.151", "capabilities": "profile:OpenShiftInfra,boot_option:local,node:infra-0", "arch":"x86_64" }, { "name": "infra002", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.152", "capabilities": "profile:OpenShiftInfra,boot_option:local,node:infra-1", "arch":"x86_64" }, { "name": "infra003", "pm_type":"pxe_ipmitool", "pm_user":"root", "pm_password":"root", "pm_addr":"192.168.99.153", "capabilities": "profile:OpenShiftInfra,boot_option:local,node:infra-2", "arch":"x86_64" } ] } フレーバーとプロパティの登録をします。 openstack flavor create --id auto --ram 4096 --disk 40 --vcpus 1 --swap 500 m1.OpenShiftMaster openstack flavor create --id auto --ram 4096 --disk 40 --vcpus 1 --swap 500 m1.OpenShiftWorker openstack flavor create --id auto --ram 4096 --disk 40 --vcpus 1 --swap 500 m1.OpenShiftInfra openstack flavor set --property "capabilities:profile"="OpenShiftMaster" --property "capabilities:boot_option"="local" m1.OpenShiftMaster openstack flavor set --property "capabilities:profile"="OpenShiftWorker" --property "capabilities:boot_option"="local" m1.OpenShiftWorker openstack flavor set --property "capabilities:profile"="OpenShiftInfra" --property "capabilities:boot_option"="local" m1.OpenShiftInfra openstack overcloud node import ~/instackenv.json openstack overcloud node introspect --all-manageable --provide イントロスペクションを実施し、Directorが実際にデプロイ可能なホストと認識すると以下のように利用可能なステータスになります。 ・Directorが環境を理解するために構成ファイルを準備します テンプレートを生成します。 cd /usr/share/openstack-tripleo-heat-templates ./tools/process-templates.py -o ~/templates/ 以下のファイルを準備します /home/stack/openshift_env.yaml Parameter_defaults: # by default Director assigns the VIP random from the allocation pool # by using the FixedIPs we can set the VIPs to predictable IPs before starting the deployment CloudName: openshift.localdomain PublicVirtualFixedIPs: [{'ip_address':'10.0.0.200'}] CloudNameInternal: internal.openshift.localdomain InternalApiVirtualFixedIPs: [{'ip_address':'172.17.1.200'}] CloudDomain: openshift.localdomain ## Required for CNS deployments only OpenShiftInfraParameters: OpenShiftGlusterDisks: - /dev/vdb ## Required for CNS deployments only OpenShiftWorkerParameters: OpenShiftGlusterDisks: - /dev/vdb - /dev/vdc NtpServer: ["clock.redhat.com","clock2.redhat.com"] ControlPlaneDefaultRoute: 192.168.24.1 EC2MetadataIp: 192.168.24.1 ControlPlaneSubnetCidr: 24 # The DNS server below should have entries for resolving {internal,public,apps}.openshift.localdomain names DnsServers: - 10.0.0.90 OpenShiftGlobalVariables: openshift_master_identity_providers: - name: 'htpasswd_auth' login: 'true' challenge: 'true' kind: 'HTPasswdPasswordIdentityProvider' openshift_master_htpasswd_users: sysadmin: '$apr1$jpBOUqeU$X4jUsMyCHOOp8TFYtPq0v1' #openshift_master_cluster_hostname should match the CloudNameInternal parameter openshift_master_cluster_hostname: internal.openshift.localdomain #openshift_master_cluster_public_hostname should match the CloudName parameter openshift_master_cluster_public_hostname: public.openshift.localdomain openshift_master_default_subdomain: apps.openshift.localdomain Directorがデプロイに使用するコンテナレジストリ情報を生成します。 /home/stack/containers-prepare-parameter.yaml このファイルはUndercloudのインストール時に作成しています。 サブスクリプション管理のための環境ファイル /home/stack/rhsm.yaml resource_registry: OS::TripleO::Services::Rhsm: /usr/share/openstack-tripleo-heat-templates/extraconfig/services/rhsm.yaml parameter_defaults: RhsmVars: rhsm_repos: - rhel-7-server-rpms - rhel-7-server-extras-rpms - rhel-7-server-ose-3.11-rpms rhsm_pool_ids: "8a85f37c63842fef0166949e5f9c4be0" rhsm_method: "portal" rhsm_username: yourusername rhsm_password: yourpassword rhsm_autosubscribe: true Overcloudをデプロイします。 $ openstack overcloud deploy \ --stack openshift \ --templates \ -r /home/stack/openshift_roles_data.yaml \ -n /usr/share/openstack-tripleo-heat-templates/network_data_openshift.yaml \ -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml \ -e /usr/share/openstack-tripleo-heat-templates/environments/openshift.yaml \ -e /usr/share/openstack-tripleo-heat-templates/environments/openshift-cns.yaml \ -e /home/stack/openshift_env.yaml \ -e /home/stack/containers-prepare-parameter.yaml \ -e /home/stack/rhsm.yaml 確認 以下のようにデプロイしたOpenShift環境を確認することができます。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/installing_openshift_container_platform_on_bare_metal_using_director/#review_the_ocp_deployment まとめ ひと昔に比べてクラウドインフラを構築する敷居はDirectorを活用することでどんどん下がってきています。 Directorは内部でAnsibleを使いOpenStack、OpenShift、Ceph Storage、Gluster Storageをデプロイすることができます。 柔軟性を犠牲にすることなく高度なクラウドインフラをデプロイすることができるDirectorについて、お気軽に問い合わせ下さい。
クラウドインフラ全般を担当しているソリューションアーキテクトの伊藤です。 今回はRed Hat OpenStack Platform 14の新機能と改善ポイントについて紹介いたします。 OSP14のリリースノート全文は以下のURLをご参照下さい。 https://access.redhat.com/documentation/ja-jp/red_hat_openstack_platform/14/html-single/release_notes/ Red Hat OpenStack Platform 14の立ち位置 OpenStack Rockyをベースにバグ修正や安定化を行い、エンタープライズで利用することを想定した製品がOSP14です。 OpenStackは半年間隔のリリースが続いており、新機能や改善を繰り返しています。 この新機能や改善を早期に取り込んだものがOSP14であり利用者が早期にアップグレードを行うことを想定しているのでサポート期間が1年になります。 一方プロダクション環境でのユースケースでは長期利用、長期サポートが求められるため、 Red Hat OpenStack Platformではロングライフサポートが提供可能なバージョンがあります。 最新のロングライフリリースはOSP13です。OSPは長期サポートが提供され、最長で5年のサポート期間です。 どちらもバグ修正と安定化が行われ、利用者のユースケースやニーズに応じて利用するバージョンを選択できます。 2019年2月時点での最新のOSP14の立ち位置としては以上です。 upgrade path 注目ポイント ■OpenShiftをOSP14からデプロイ可能 ■vGPUをインスタンスに割り当てる機能 ■Ansible Networking ML2 プラグインを使用したマルチテナントBMaaS となります。次項から詳細に紹介します。 新機能 ■OpenShiftをOSP14からデプロイ可能 Red Hat OpenStack PlatformではDirectorと呼ばれるデプロイツールを使ってOpenStackやCeph Storageをデプロイしています。 このDirectorがOpenStackだけでなく、OpenShiftもデプロイすることが可能になりました。 というのがこのOSP14での新機能の趣旨です。 仮想化のオーバヘッドがないためコンテナアプリケーションがより多くのCPUパフォーマンスとより少ないネットワークレイテンシを得ることができます。 具体的には、OpenShift Container Platform 3.11を openshift-ansible というansibleプレイブックをDirectorが使用してデプロイします。 IPMIでコントロール可能な物理サーバが要件通りにネットワーク接続されている状態であれば、電源オフの状態からOpenShiftがインストールされ、 WEBUI/CLIが利用可能な状態までをコマンド1つでデプロイすることが可能になりました。 また、デプロイするだけでなく、コンテナアプリケーションのリソース要求に沿うようにOpenShiftのノードを追加と削除を行うことが可能です。 従来OpenStackとCeph Storageといったインフラ基盤の構築までをDirectorが行えていたところ、OpenShiftの構築が可能になったことから、 Kubernetesを利用したコンテナ開発、運用基盤という開発者のための環境をデプロイすることが可能になりました。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/installing_openshift_container_platform_on_bare_metal_using_director/ ■テスト環境のためのシングルノードのOpenStack All-in-one OpenStackと呼ばれるものです。Packstackでは実現できていましたが、Directorに移行してAll-in-one OpenStackは構築することができなくなっていました。 OSP14からはDirectorでAll-in-one OpenStackを構築することができるようになりました。この構成はテスト環境での利用を想定しています。 Technology Previewという立ち位置でサポートを行うことができませんが、テストのために使用することは可能です。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/quick_start_guide/ ■Skydive ソフトウェアデファインドネットワークという概念がネットワークに持ち込まれたころから、配線、ケーブリングといった物理ネットワーク、VLAN、SVIといった論理ネットワーク、そしてVXLAN、Geneveによるトンネリング、そして更に仮想ルータ、フローティングIPといったネットワークファンクションが実際にネットワークの世界に導入されています。 機能性、移行性が重視されていて、ネットワークを俯瞰することや、検証、トラブルシュートするということは難しくなってきています。 そこでこれらの問題を解決するためにSkydiveというプロジェクトがスタートし、OSP14では組み込まれています。 Skydiveは ・複雑なSDNネットワーク構成を見ること ・ネットワークが正しいことを検証すること ・パケットインジェクションやキャプチャなどを行いトラブルシュートすること という3つのネットワークの機能と、周辺システムとの連携を視野にいれたREST APIとWEBUIを備えています。 Technology Previewという立ち位置でサポートを行うことができませんが、テストのために使用することは可能です。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/use_skydive_for_openstack_network_analysis/ ■仮想インスタンス(VM)に関連する新機能 OSP14ではインスタンスに対していくつか細かい機能追加が実施されています。 ・ネットワーク送信/受信キューのサイズ変更 virtioドライバの送受信トラフィックのキューサイズを設定することが可能になりました。 これによりインスタンスが処理できるトラフィックが増加し、パフォーマンス改善が見込めます。 ・ネットワークSR-IOV trusted VF インスタンスを信頼することで、インスタンスからMACアドレス変更をすることが可能になりました。 Neutronでポート作成時に信頼するオプションを付与することでMACアドレスの変更を行い、プロミスキャスモードを有効にすることができます。 ・Nova 用 NFS バックエンド NFS エクスポートからコンピュートインスタンスをマウントして、インスタンス用に共有 NFS ストレージバックエンドを維持することができます。 この機能は、Glance および Cinder 用の NFS ストレージバックエンドと同じ仕組みで動作します。 ・Hugepagesの確保 DBインスタンスなど高いパフォーマンスが要求されるインスタンスに対して、Hugepagesを割り当てることが可能になりました。 ■vGPUをインスタンスに割り当てる機能 GPUを使用してAI/DLといった高度な解析を行うワークロードに対して、インスタンスにvGPUとしてGPUの論理リソースを割り当てることが可能になりました。 vGPUとしてリソースを分割することで、複数のインスタンスからGPUリソースを活用することができ、高価なGPUを共有することでコスト効率と利用効率の向上が見込めます。現在はvGPU GRID driverのみ利用可能です。 Technology Previewという立ち位置でサポートを行うことができませんが、テストのために使用することは可能です。 改善点 ■ Ansible Networking ML2 プラグインを使用したマルチテナントBMaaS 複数のテナントから独立したネットワーク上でベアメタルを扱うことができるようになりました。 OpenStack Ironicから払い出した物理サーバはテナントごとのネットワークに、接続されているスイッチのvlan変更で接続できるようになります。 vlan変更のコンフィグレーションはansible networking ML2プラグインにより実施されます。 ■Ansibleでのオーバークラウドのデプロイ OSP14以前はDirectorによって、OpenStackがデプロイされるときはDirectorのOpenStack Heatを使ったテンプレートを展開していくことでデプロイが行われていました。 このデプロイの方法は非常に複雑な階層が設けられており、トラブルシューティングには不向きでした。 今回OSP14からはOpenStack HeatとAnsibleで役割分担が行われました。 初期段階のノードのイメージ展開やネットワーク設定など足回りの構築はHeatを通して行われます。 後続のOpenStackソフトウェアの導入、テストといった動作はAnsibleを通して行われるようになりました。 ■ML2/OVSからML2/OVNへのマイグレーション OSP13からフルサポートとなったML2/OVNではOpenStackやOpenShiftといったソフトウェアのインスタンスが利用するネットワークを統合することができるようになりました。 従来と比較して技術的にはOVSを利用していることには変わりませんが、内部構造的にはOpenStackに依存しないSDNソリューションとなっています。 ML2/OVSとML2/OVNではOpenShiftとOpenStackを組み合わせた際のパフォーマンスと運用性が改善されています。 OSP14では、ML2/OVSを利用していたプライベートクラウドをML2/OVNにマイグレーションすることが可能になっています。 https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html-single/networking_with_open_virtual_network/ 最後に Red Hatでは社内にプライベートクラウド基盤の検証を行う環境を備えています。 プライベートクラウドを業務に取り入れるために、想定した業務フローとOpenStackが適合するか検証したいがテスト環境が無いといった、プライベート基盤構築を進めるにあたってのPoC環境についてもお気軽にご相談下さい。
暗号化スイートおよびプロトコルの設定 暗号はだんだん弱くなる 適切な設定は何か? crypto-policiesによる設定 crypt-policiesによるデフォルト設定はどう実装されているの? openssh serverの場合 openssl の場合 crypto-policies の注意点 まとめ 関連リンク 暗号化スイートおよびプロトコルの設定 TLSによる暗号化、sshでの暗号化、ストレージの暗号化 など、 RHELの中には「暗号化」を扱う場面が多数あります。これらで利用される暗号化のアルゴリズムやプロトコルをセキュリティポリシーにあわせて適切に設定するには専門知識が必要になります。 一言で「暗号化」と言いましたが、たとえばTLSは通信相手の認証も含むため、鍵交換、データの暗号化、署名、ハッシュといったステップがあり、それぞれにアルゴリズムの選択肢があります。これらをまとめた「暗号化スイート」を適切なものに設定する必要があります。 基本的には強度が高い(秘密の情報を知らない人が突破するのが困難な)暗号化スイートを指定することで安全性が上がりますが、いつも強度が高い暗号化スイートを選べるとは限りません。強度が低い暗号化スイートを使うことが必要となる典型的なケースは、フィーチャーホンや特定のアプライアンスなどの古い暗号化スイートしかサポートしていない機器との通信が必要な場合です。 TLSなどでは、実際のデータをやりとりする前に、互いに利用可能な暗号化スイートのリストを交換した上で、両方が利用可能な暗号化スイートから実際に利用する暗号化スイートを選択します。この選択の優先順位も設定により決まります。 暗号はだんだん弱くなる 暗号の強度はおおまかに言って「解読したり偽装したりするために必要な時間」を目安に考えられます。そのため攻撃方法の研究が進んだり、コンピュータの計算能力が向上していくことで暗号はだんだんと弱くなっていき、やがては実用上の意味がなくなります(暗号危殆化)。現在利用されている暗号化方式が危殆化する前に、より強い暗号化方式を考案、評価、標準化して一般に利用できるようにするため不断の努力が重ねられています。 たとえば開発当時に知られていた攻撃手法と標準的な計算機を使って攻撃すると解読に100万年かかるとされた暗号化方式であっても、年月とともに効果的な攻撃方法がみつかったり計算機が高速化することで1000年で解読できるようになることはごく普通に考えられます。この弱くなった暗号を数千台のクラスタで攻撃すると数ヶ月程度で攻撃が成功するため、実際的に暗号化の意味がなくなります。 強度が高い暗号化スイートは多くの場合暗号化・復号化にかかる計算時間も増えますので、計算時間と強度のバランスも利用するべき暗号化スイートの選択に影響します。 適切な設定は何か? 相互運用性とセキュリティ強度のバランスをどう調整するべきかは状況により異なります。 NISTなどの機関では実際的な攻撃がどの程度容易であるかを考慮して、特定の方式を含む暗号化スイートの利用禁止を宣言したり、システムの特性により利用するべき暗号化スイートのガイドを公開したりしています。各システムの運用管理者が個別に暗号化スイートについて取捨選択をおこなうことは困難ですので、多くの場合はガイドにあわせて設定することになります。 crypto-policiesによる設定 RHEL 8 では暗号化スイートの設定作業を簡単にするため crypto-policies という仕組みが導入されました。以下のソフトウェアについて、利用可能な暗号化スイートのデフォルト設定をまとめて行います。残念ながら暗号化を扱う全ての場面をサポートできてはいません(dm-cryptoでのストレージ暗号化など)が、主要なライブラリをカバーしています。 GnuTLS library OpenSSL library NSS library OpenJDK Libkrb5 BIND OpenSSH Libreswan RHEL 8.1リリースのタイミングで go言語および libsshにも対応する予定です。 crypto-policiesの利用方法は非常にシンプルです。 RHEL 8 betaのcrypto-policiesでは LEGACY, DEFAULT, FUTURE, FIPS の4種類のプロファイルが用意されています。/etc/crypto-policies/config に希望のプロファイル名を指定して、 update-crypto-policies コマンドをrootで実行します。これで上記のソフトウェア群について、デフォルトの暗号化スイートを設定できます。 /etc/crypto-policies/config # be applied by default to applications. The available policies are # restricted to the following profiles. # # * LEGACY: Ensures maximum compatibility with legacy systems (64-bit # security) # # * DEFAULT: A reasonable default for today's standards (112-bit security). # # * FUTURE: A level that will provide security on a conservative level that is # believed to withstand any near-term future attacks (128-bit security). # # * FIPS: Policy that enables only FIPS 140-2 approved or allowed algorithms. # # After modifying this file, you need to run update-crypto-policies # for the changes to propagate. # DEFAULT 通常は、DEFAULTプロファイルのままで特に何もせず利用するのがおすすめです。古い機器との接続が必要な場合や、高いセキュリティが必要な場合にはそれぞれLEGACY, FUTUREプロファイルをご利用ください。 crypt-policiesによるデフォルト設定はどう実装されているの? crypto-policiesパッケージはプロファイル毎に各ソフトウェア用の設定をあらかじめ持っています。update-crypto-policiesコマンドはプロファイル設定に従ってシンボリックリンクを切り替えるだけの単純なものです。 rpmパッケージには生成済みの設定とプロファイル切り替えのシェルスクリプトだけが含まれますが、この設定はポリシーをもとにスクリプトから生成されています。src.rpmかgitlabでホストされているupsreamプロジェクトから確認できます。独自にプロファイルを作成したい場合などはこちらを調査するのが良いです。もし一般的にサポートされるとよさそうなプロファイルがあれば、サポート窓口まで機能拡張リクエストを送っていただければと思います。 gitlab.com 各ソフトウェアのパッケージがcrypto-policiesを利用して暗号化スイートの設定をおこなっています。どのように設定を反映するかの詳細は各ソフトウェアにより変わり、デフォルトの設定ファイルでincludeするもの、サーバ起動時のオプションを変えるものなどがあります。 openssh serverの場合 systemdのsshd.service内で環境変数としてcrypto-policiesの設定をとりこみ、sshd実行時のコマンドラインオプションとして渡しています。コマンドラインオプションは設定ファイルより優先されるため、今までと同じ設定を /etc/ssh/sshd_config に書いていても動作への影響がありません。 /etc/sysconfig/sshd に CRYPTO_POLICY= と空文字列を指定することでcrypto-policiesのデフォルト設定を無視することができます。 /usr/lib/systemd/system/sshd.service より [Service] Type=notify EnvironmentFile=-/etc/crypto-policies/back-ends/opensshserver.config EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s openssl の場合 /etc/pki/tls/openssl.cnf 内で、crypto-policiesのポリシーをincludeしています。 [ crypto_policy ] .include /etc/crypto-policies/back-ends/opensslcnf.config crypto-policies の注意点 「RHEL 8でcrypto-policiesを使わない」という選択肢は存在しません。前述のとおり、暗号化を扱う各ソフトウェアのデフォルト設定でcrypto-policiesを参照しています。OpenSSH Serverをのぞけば一般的な設定手順でオーバーライドが可能ですので、必要な場合は個別にソフトウェアを設定します。 まとめ 組織のポリシーにあわせて暗号化の強度を考慮した設定をすることがあります。 RHEL 8 ではcrypto-policiesを利用することで、システム全体の暗号化の強度を簡単に調整できます。 RHEL 7 までと同じ手順で構築しても利用する暗号化スイートの設定が同一にならない場合があります。必要に応じて適宜オーバーライドしてご利用ください。 関連リンク fedoraproject.org gitlab.com access.redhat.com
Red Hatの梅野です。 前回の記事は、タスクのリストを表示させるために必要なソースをご紹介しました。 今回はタスクを実行するところをご紹介します。 タスクとは タスクにはいろいろな種類がありますが、全てのタスクの役割は同じで、「誰にアサインされたか」「いつからこの仕事を行ったか」「いつこの仕事を終えたか」を記録するものです。 タスクはアサインされた人しか実行できません。タスクのアサインは、Business Central上のプロセスを設計するツールより設定できます。 Taskのアサイン アクターのところに、Business Centralに登録してあるユーザを指定します。 アクターの人が病気等で仕事ができない状況の場合、仕事が止まることを意味します。そうすると困った状況になりますので、独裁的承認がどうしても必要等の特段の理由のない限り、ここはBusiness Centralに登録されているグループを指定しておくのが良いです。グループには複数のユーザーを登録することができます。 グループの指定の方法はまた別途ご紹介するとして、今回はシンプルにユーザをここで指定しておきます。 タスクの開始 タスクを開始するには、下記のような実装が必要です。 String SERVERURL = "http://localhost:8080/kie-server/services/rest/server"; String USER ="rhpamAdmin"; String PASSWORD = "PASSWORD"; MarshallingFormat FORMAT = MarshallingFormat.JSON; String CONTAINER = "Seal_1.0.0"; String ProcessID = "Seal.Seal_Process"; KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(SERVERURL, USER, PASSWORD); config.setMarshallingFormat(FORMAT); KieServicesClient client = KieServicesFactory.newKieServicesClient(config); ここまでは前回と同じです。(これ以降はこの共通部分は省略します) UserTaskServicesClient taskClient = client.getServicesClient(UserTaskServicesClient.class); taskClient.startTask(ContainerID, TaskID, UserID); ContainerID と TaskID と UserID は、前回紹介したTask Listから取得して渡してください。 TaskID はlongである必要があります。UserIDはこのタスクを実行するユーザーで、Business Centralで登録されている必要があります。TaskListが取れている時点でUserIDはわかっているかと思います。 タスクの終了 タスクを終了するには、下記のような実装が必要です。 taskClient.completeTask(ContainerID, TaskID, UserID, null); 何か残したい場合は、4つ目の引き数にMap<String, Object> 型で渡してあげるとtaskVariableとして記録されます。承認行為の時の申し送り的な使い方になります。 タスクを一気に終了 通常は、作業を開始するときにタスクの開始、作業を終了するときにタスクの終了を行い、そのタスクにどれだけの時間が掛かったのかを統計的に取得し、業務の効率化を目指すものです。なので、start / end を別個に呼ぶことが必要ですが、画面を一瞬見ればわかる等、人間側か2回アクションしたくないときもあります。その場合、下記のような実装をすることで、自動的にstart / end を呼んでくれ、1アクションで済むことがあります。 taskClient.completeAutoProgress(ContainerID, TaskID, UserID, null); Process Automation Managerの中では、あくまでも Start - End を記録します。このAPIを呼び出すと、後続にある停止すべきノードで止まります。停止すべきノードとは、Human TaskやEnd node等です。 これを行うと、各タスクのStart - End にかかる時間は数ミリ秒となり、人的作業でどれくらい掛かったかはわからなくなります。統計情報が必要な場合は、completeAutoProgress ではなく、startTaskとcompleteTaskを呼ぶように実装します。 使う上での注意 ご紹介したとおり、Process Automation Manager は、全てのタスクやノードにて、必ず「Start」「End」が記録されます。普段見ることは無いと思いますが、PAMが使用するDBの中の"nodeinstancelog" テーブルに全て記録されます。つまり、PAMというアプリケーションが毎回DBに記録に行くため、パフォーマンスはPersistenceであるDBの速度に大きく依存します。応答速度は超高速とは言えません。従って、同時接続数や必要な応答速度をよく検討した上で、マシンのスペックやサブスクリプションのCore数を決定する必要があります。 また、プロセス内での各タスクのトランザクションは保証されますが、RESTや他のDB等、外部連携タスクを利用した場合のXAには対応していません。なので、「サービス連携」をPAMで行おうとすると、commitに失敗した場合の復旧策は製品にはありません。PAMを「サービス連携基盤」と考えるのは間違った使い方になります。サービス連携でトランザクション保証が必要な場合は、Red Hat Process Automation ManagerではなくRed Hat Fuseを利用してください。 PAMはあくまでも、「申請・承認行為が必要なビジネスの流れにおいて、各案件の状態を一元的に管理する」という使い方になります。 次回はTaskをGroupでの指定した場合の方法をご紹介します。 うめの( id:mumeno )
Red Hatの梅野です。 前回の記事 は、プロセスをスタートさせるために必要なソースをご紹介しました。 今回は、タスクリストを取得することを紹介したいと思います。 タスクリストとは、「自分がやらなきゃいけない仕事の一覧」、「仕掛中の仕事の一覧」、「終わった仕事の一覧」みたいなことです。 プロセスとタスク まずはプロセスとタスクの違いです。 プロセスとタスク この絵で書かれている、連結された丸や四角の全体をプロセス、四角のものをタスクと言います。 プロセスをスタートさせるとプロセスインスタンスというのが作られ、プロセスインスタンスIDが割り当てられます。プロセスサービスに関する操作は全て、このプロセスインスタンスIDがキーになります。 jBPMでは、プロセス全体を扱うプロセスサービスと、その中のタスクを扱うタスクサービスの2つのサービスの組み合わせになっています。なぜこのようなアーキテクチャになっているかというと、一つのプロセスの中で同時並行で複数のタスクが実行される場合、一つのプロセスインスタンスIDだけでは取り扱いが難しくなるためです。ですので、プロセスインスタンスIDが紐付けられたタスクサービスに問い合わせ・指示を行う必要があります。 タスクリストの取出し方 Java client API でのソースです。 String SERVERURL = "http://localhost:8080/kie-server/services/rest/server"; String USER ="rhpamAdmin"; String PASSWORD = "PASSWORD"; MarshallingFormat FORMAT = MarshallingFormat.JSON; String CONTAINER = "Seal_1.0.0"; String ProcessID = "Seal.Seal_Process"; KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(SERVERURL, USER, PASSWORD); config.setMarshallingFormat(FORMAT); KieServicesClient client = KieServicesFactory.newKieServicesClient(config); UserTaskServicesClient taskClient = client.getServicesClient(UserTaskServicesClient.class); List<TaskSummary> tasks = taskClient.findTasksAssignedAsPotentialOwner(USER, 0, 10); TaskSummary ts = new TaskSummary(); for (int i=0; i < tasks.size(); i++) { ts = (TaskSummary)tasks.get(i); System.out.println("ID:" + ts.getId() + " status:" + ts.getStatus()); } ご覧いただくとおわかりかと思いますが、 KieServicesClient のインスタンス clientを作成するところまでは、前回のソースと全く同じです。 プロセスのスタートを行うときは、ProcessServiceClient のインスタンスを KieServicesClient から作りましたが、今回はUserTaskServiceClient をKieServicesClientから作っています。 今回はタスクリストを呼ぶのに、アサインされたユーザー名をキーとして作成したので findTasksAssignedAsPotentialOwner() を呼びましたが、他には findTasksAssignedAsBusinessAdministrator() findTasksByStatusByProcessInstanceId(); findTasksByVariable(); findTasksByVariableAndValue(); findTasksOwned(); のような取出し方もあり、目的にあったリストの取り出しが可能です。それぞれ、pageとpageSize を引数で指定できるので、大量のリストを取る必要がある場合は適切に指定します。 TaskListの戻り値 findTasksほにゃらら  で返されるのはTaskSummaryというクラスです。json で返されたデータをみると、このような情報が取れることがわかります。 { "id":21, "name":"FinanceCheck", "subject":"", "description":"", "status":"Reserved", "priority":0, "skipable":false, "actualOwner":"rhpamAdmin", "createdBy":"rhpamAdmin", "createdOn":1547705169785, "activationTime":1547705169785, "expirationTime":1547705169785, "processInstanceId":22, "processId":"Seal.Seal_Process", "containerId":"Seal_1.0.0", "parentId":-1 }, ... 戻り値はjson型もしくはXML型で受け取ることができます。 HTMLに表示するところでリストを表にすることで、「自分がやらなきゃいけない仕事一覧」が取得できます。 一番上にある"id" というのがtask ID になります。タスクに対する操作はtask IDを使用して行います。 日付はjava.util.Date型が文字列で返されます。 processInstanceIdというのが、このタスクに紐付いているProcessInstanceIDです。 次回はタスクを実行するところをご紹介します。 うめの( id:mumeno )