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

TECH PLAY

Red Hat  - Open Innovation Labs

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

全900件

Red Hatの森若です。 この記事は Red Hat Advent Calendar 2023 の21日目です。 デバッグなどのためにsystemdのservice unitで起動されるプロセスにstraceを仕掛けたいとき、ちょっとしたハマり所があるのでその説明とワークアラウンドを紹介します。 目次 実行中のserviceをstraceする 実行開始からserviceをstraceする Type=forking 時の問題 参考文献 おまけの宣伝 実行中のserviceをstraceする この場合は特にハマるところはありません。 既に実行中のプロセスへのstraceは、cgroupで関連するプロセス一覧が管理されているので、それを利用します。関連する全てのプロセスを指定し、 -f でforkも追跡することで、関連する全プロセスを指定します。 serviceに対応するcgroupを確認する。 $ systemctl show dbus-broker.service |grep ControlGroup= ControlGroup=/system.slice/dbus-broker.service または $ systemctl status dbus-broker.service |grep CGroup CGroup: /system.slice/dbus-broker.service cgroupの cgroup.procs を利用してstrace の -p オプションに関連プロセスを指定する # strace -fttTvyy -s 4096 -o /tmp/dbus.strace -p $(tr \\n , < /sys/fs/cgroup/system.slice/dbus-broker.service/cgroup.procs) 実行開始からserviceをstraceする 実行開始直後の初期化なども観測対象にする場合、起動時に straceの子プロセスとしてプログラムを実行開始します。 つまり以下のように指定して実行します。以下で説明しますが一部で問題が発生します。 ExecStart=/usr/bin/strace -fttTvyy -s 4096 -o /tmp/strace.log もとのコマンド… Type=forking 時の問題 systemdのservice unitにはType という属性がありsimple, oneshot, forkingなどいくつかの種類にわかれています。 Type=forking の場合にはExecStartの書き換えだけでは期待通りに動作しません。 systemctl start foobar.service としたあとしばらく activating状態で動作し、起動に失敗したとして終了します。 まずType=forkingの通常の動作について紹介します。この場合systemdが直接実行する「起動プロセス」と実際にサービスを提供する「サービスプロセス」が別になっています。 Type=forkingの通常の動作 上図のように、systemdは起動プロセスの実行終了をもって、service unitがactiveになったとみなします。 ExecStartにstraceを付与した時の動作 単純にExecStartの先頭にstraceを付与した場合、上図のようになります。straceは起動プロセスとサービスプロセスの両方をトレースしてログを出力し続けます。起動プロセスは終了し、サービスプロセスも通常どおりサービスを提供します。 このときsystemdの視点では実行したプロセス(strace)が終了しないので、起動処理が完了しません。デフォルトでは1分30秒でsystemdはservice unitの起動が失敗したと判断し、シグナルを送信して関連するプロセスを停止します。これがさきほどの終了の原因です。 ここまでわかれば対策は単純です。 Type=forking を Type=simple のように変更します。 Type=simpleの場合、最初のfork実行時点でactiveとなり、プログラムが終了するとサービスがinactiveになります。 さて Type=oneshot では、長時間動作するサービスプロセスにあたるものはなく、プロセスもタイムアウトより早く終了することが求められます。straceは全プロセス終了にともない早く終了します。そのため本来は類似の問題はほぼ発生しません。 ただし Type=forking を指定するべきアプリケーションに誤って Type=oneshot が指定されている場合があり、そのような場合には同様の問題が発生します。 Type=notify のときには、systemdへ通知を送るプロセスが MainPIDと別のプロセスになるため、 NotifyAccess=all を追加します。 参考文献 詳しくは以下のman pagesに記載があります。 systemd.service systemd.exec strace おまけの宣伝 systemdの思想と機能 ―Linuxを支えるシステム管理のためのソフトウェアスイート 本日発売です
この記事は、「Red Hat Advent Calendar 2023」20日目の記事です。 Windowsの文字化け問題 AnsibleでWindowsノードを管理していると、特にwin_shellモジュールでコマンドを実行した際などの実行結果が時折文字化けしてしまうケースがあります。こうなってしまうと、実行結果が正しく読み取れず、Windows自動化の障壁となってしまいます。 なぜ文字化けが発生するのか Ansibleでは、WinRM経由でWindowsに接続しますが、その際の新規セッションに対してはUTF-8を利用するよう指定して接続します。これは、通常のWindowsモジュールの実行であれば問題は発生しません。 https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/connection/winrm.py#L474-L477 # open the shell from connect so we know we're able to talk to the server if not self.shell_id: self.shell_id = protocol.open_shell(codepage= 65001 ) # UTF-8 display.vvvvv( 'WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) しかし、Shift_JISのような別の文字エンコーディングをデフォルトで利用しており、win_shellやwin_commandのようなPowerShell上でコマンドを実行するモジュールを利用する場合、実行されるコマンドはデフォルトの文字エンコーディングを利用するため、実行結果はShift_JISで返却されます。そのため、Ansibleに渡される実行結果はUTF-8でなくなり、文字化けが発生します。 対処方法 上記のような想定していない文字化けに対処するため、win_shellモジュールなどでは「output_encoding_override」オプションが利用できます。 ansible.windows.win_shell module – Execute shell commands on target hosts — Ansible Documentation このオプションでは、返却された実行結果を指定した文字エンコーディングで上書きして解釈します。基本的に、Windows上で [System.Text.Encoding]::GetEncodings() を実行した際に返却される「Name」の文字エンコーディング(Shift_JISであればshift_jis)を指定できます。 PS C:\Users\hiyoko> [System.Text.Encoding]::GetEncodings() CodePage Name DisplayName -------- ---- ----------- 37 IBM037 IBM EBCDIC (US - カナダ) 437 IBM437 OEM アメリカ合衆国 500 IBM500 IBM EBCDIC (インターナショナル) 708 ASMO-708 アラビア語 (ASMO 708) 720 DOS-720 アラビア語 (DOS) 737 ibm737 ギリシャ語 (DOS) 775 ibm775 バルト言語 (DOS) 850 ibm850 西ヨーロッパ言語 (DOS) 852 ibm852 中央ヨーロッパ言語 (DOS) 855 IBM855 OEM キリル 857 ibm857 トルコ語 (DOS) 858 IBM00858 OEM マルチリンガル ラテン I 860 IBM860 ポルトガル語 (DOS) 861 ibm861 アイスランド語 (DOS) 862 DOS-862 ヘブライ語 (DOS) 863 IBM863 フランス語 (カナダ) (DOS) 864 IBM864 アラビア語 (864) 865 IBM865 北欧 (DOS) 866 cp866 キリル言語 (DOS) 869 ibm869 ギリシャ語, Modern (DOS) 870 IBM870 IBM EBCDIC (多国語ラテン 2) 874 windows-874 タイ語 (Windows) 875 cp875 IBM EBCDIC (ギリシャ語 Modern) 932 shift_jis 日本語 (シフト JIS) 936 gb2312 簡体字中国語 (GB2312) 949 ks_c_5601-1987 韓国語 950 big5 繁体字中国語 (Big5) 1026 IBM1026 IBM EBCDIC (トルコ語ラテン 5) 1047 IBM01047 IBM ラテン-1 1140 IBM01140 IBM EBCDIC (US - カナダ - ヨーロッパ) 1141 IBM01141 IBM EBCDIC (ドイツ - ヨーロッパ) 1142 IBM01142 IBM EBCDIC (デンマーク - ノルウェー - ヨーロッパ) 1143 IBM01143 IBM EBCDIC (フィンランド - スウェーデン - ヨーロッパ) 1144 IBM01144 IBM EBCDIC (イタリア - ヨーロッパ) 1145 IBM01145 IBM EBCDIC (スペイン - ヨーロッパ) 1146 IBM01146 IBM EBCDIC (UK - ヨーロッパ) 1147 IBM01147 IBM EBCDIC (フランス - ヨーロッパ) 1148 IBM01148 IBM EBCDIC (インターナショナル - ヨーロッパ) 1149 IBM01149 IBM EBCDIC (アイスランド語 - ヨーロッパ) 1200 utf-16 Unicode 1201 utf-16BE Unicode (Big-Endian) 1250 windows-1250 中央ヨーロッパ言語 (Windows) 1251 windows-1251 キリル言語 (Windows) 1252 Windows-1252 西ヨーロッパ言語 (Windows) 1253 windows-1253 ギリシャ語 (Windows) 1254 windows-1254 トルコ語 (Windows) 1255 windows-1255 ヘブライ語 (Windows) 1256 windows-1256 アラビア語 (Windows) 1257 windows-1257 バルト言語 (Windows) 1258 windows-1258 ベトナム語 (Windows) 1361 Johab 韓国語 (Johab) 10000 macintosh 西ヨーロッパ言語 (Mac) 10001 x-mac-japanese 日本語 (Mac) 10002 x-mac-chinesetrad 繁体字中国語 (Mac) 10003 x-mac-korean 韓国語 (Mac) 10004 x-mac-arabic アラビア語 (Mac) 10005 x-mac-hebrew ヘブライ語 (Mac) 10006 x-mac-greek ギリシャ語 (Mac) 10007 x-mac-cyrillic キリル言語 (Mac) 10008 x-mac-chinesesimp 簡体字中国語 (Mac) 10010 x-mac-romanian ルーマニア語 (Mac) 10017 x-mac-ukrainian ウクライナ語 (Mac) 10021 x-mac-thai タイ語 (Mac) 10029 x-mac-ce 中央ヨーロッパ言語 (Mac) 10079 x-mac-icelandic アイスランド語 (Mac) 10081 x-mac-turkish トルコ語 (Mac) 10082 x-mac-croatian クロアチア語 (Mac) 12000 utf-32 Unicode (UTF-32) 12001 utf-32BE Unicode (UTF-32 ビッグ エンディアン) 20000 x-Chinese-CNS 繁体字中国語 (CNS) 20001 x-cp20001 TCA 台湾 20002 x-Chinese-Eten 繁体字中国語 (Eten) 20003 x-cp20003 IBM5550 台湾 20004 x-cp20004 TeleText 台湾 20005 x-cp20005 Wang 台湾 20105 x-IA5 西ヨーロッパ言語 (IA5) 20106 x-IA5-German ドイツ語 (IA5) 20107 x-IA5-Swedish スウェーデン語 (IA5) 20108 x-IA5-Norwegian ノルウェー語 (IA5) 20127 us-ascii US-ASCII 20261 x-cp20261 T.61 20269 x-cp20269 ISO-6937 20273 IBM273 IBM EBCDIC (ドイツ) 20277 IBM277 IBM EBCDIC (デンマーク - ノルウェー) 20278 IBM278 IBM EBCDIC (フィンランド - スウェーデン) 20280 IBM280 IBM EBCDIC (イタリア) 20284 IBM284 IBM EBCDIC (スペイン) 20285 IBM285 IBM EBCDIC (UK) 20290 IBM290 IBM EBCDIC (日本語カタカナ) 20297 IBM297 IBM EBCDIC (フランス) 20420 IBM420 IBM EBCDIC (アラビア語) 20423 IBM423 IBM EBCDIC (ギリシャ語) 20424 IBM424 IBM EBCDIC (ヘブライ語) 20833 x-EBCDIC-KoreanExtended IBM EBCDIC (韓国語 Extended) 20838 IBM-Thai IBM EBCDIC (タイ語) 20866 koi8-r キリル言語 (KOI8-R) 20871 IBM871 IBM EBCDIC (アイスランド語) 20880 IBM880 IBM EBCDIC (キリル言語 - ロシア語) 20905 IBM905 IBM EBCDIC (トルコ語) 20924 IBM00924 IBM ラテン-1 20932 EUC-JP 日本語 (JIS 0208-1990 および 0212-1990) 20936 x-cp20936 簡体字中国語 (GB2312-80) 20949 x-cp20949 韓国語 Wansung 21025 cp1025 IBM EBCDIC (キリル言語 セルビア - ブルガリア) 21866 koi8-u キリル言語 (KOI8-U) 28591 iso-8859-1 西ヨーロッパ言語 (ISO) 28592 iso-8859-2 中央ヨーロッパ言語 (ISO) 28593 iso-8859-3 ラテン 3 (ISO) 28594 iso-8859-4 バルト言語 (ISO) 28595 iso-8859-5 キリル言語 (ISO) 28596 iso-8859-6 アラビア語 (ISO) 28597 iso-8859-7 ギリシャ語 (ISO) 28598 iso-8859-8 ヘブライ語 (ISO-Visual) 28599 iso-8859-9 トルコ語 (ISO) 28603 iso-8859-13 エストニア語 (ISO) 28605 iso-8859-15 ラテン 9 (ISO) 29001 x-Europa ヨーロッパ 38598 iso-8859-8-i ヘブライ語 (ISO-Logical) 50220 iso-2022-jp 日本語 (JIS) 50221 csISO2022JP 日本語 (JIS 1 バイト カタカナ可) 50222 iso-2022-jp 日本語 (JIS 1 バイト カタカナ可 - SO/SI) 50225 iso-2022-kr 韓国語 (ISO) 50227 x-cp50227 簡体字中国語 (ISO-2022) 51932 euc-jp 日本語 (EUC) 51936 EUC-CN 簡体字中国語 (EUC) 51949 euc-kr 韓国語 (EUC) 52936 hz-gb-2312 簡体字中国語 (HZ) 54936 GB18030 簡体字中国語 (GB18030) 57002 x-iscii-de ISCII デバナガリ文字 57003 x-iscii-be ISCII ベンガル語 57004 x-iscii-ta ISCII タミール語 57005 x-iscii-te ISCII テルグ語 57006 x-iscii-as ISCII アッサム語 57007 x-iscii-or ISCII オリヤー語 57008 x-iscii-ka ISCII カナラ語 57009 x-iscii-ma ISCII マラヤラム語 57010 x-iscii-gu ISCII グジャラート語 57011 x-iscii-pa ISCII パンジャブ語 65000 utf-7 Unicode (UTF-7) 65001 utf-8 Unicode (UTF-8) もし実行結果が文字化けしてしまって困っている時には、上記オプションを試してみてください。 Happy Automation!
※この記事は Red Hat Advent Calendar 2023 の 18日目の記事です。 qiita.com Red Hatのソリューションアーキテクトの井上たかひろです。 Red Hat SSO(Single sing-on)改めRed Hat build of Keycloakが2023年11月にGAになりました。 この記事では、Red Hat SSOからRed Hat build of Keycloakでの主な変更点とマイグレーション情報について記載します。 Red Hat SSOからRed Hat build of Keycloakでの主な変更点 Keycloakがメジャーになりすぎたためや、Red Hat SSOの製品名称がバクっとしてて何かわかりづらかったなどの理由がありやなしやで、 製品名称がRed Hat build of Keycloakになりました。 Keycloakは、2023年4月にCNCFでIncubating Projectで採択されてもっと利用が増えそうな点なども考慮すると、アップストリームのプロジェクト名と製品名が同じなのは、わかりやすくて良いかなと個人的には思っています。 www.cncf.io そして、Red Hat SSOからRed Hat build of Keycloakの主な変更点は以下となります。 項目 Red Hat SSO Red Hat build of Keycloak ソフトウェア構成 ランタイムにJBoss EAPを採用 ランタイムにQuarkusを採用 バージョンアップ間隔 v7.xでは、v7.1からv7.2等 マイナーバージョンアップは約年1回 Keycloakと同じバージョン管理 22→24などで、バージョンアップは年2回を想定 サブスクリプション JBoss EAP(JBCS)に含まれる Red Hat Runtimesに含まれる OpenShiftに含まれる Red Hat Runtimesに含まれる OpenShiftに含まれる サポート構成やソフトウェア構成に関する情報は以下をご確認ください。 Red Hat build of Keycloak Supported Configurations Red Hat build of Keycloak Component Details サブスクリプションに関する情報は以下をご確認ください。 Subscriptions or Entitlements Requirements for Red Hat build of Keycloak サブスクリプションに関しては、JBoss EAPに含まれなくなっている点はご注意ください。 Red Hat build of Keycloak 22の新機能や機能強化 ランタイムがQuarkusになったことで、起動時間の短縮、処理性能向上、メモリリソース効率、コンテナ化がより容易になったなどのメリットも得られています。 OpenShift Operatorについては、作り直しされており、Operator成熟モデルがPhase4のDeep Insightになっています。 詳細は、Red Hat build of Keycloak 22のリリースノートをご確認ください。 Chapter 1. Red Hat build of Keycloak 22.0 Red Hat build of Keycloak 22.0 | Red Hat Customer Portal Red Hat SSOからRed Hat build of Keycloakへのマイグレーション ランタイムが、JBoss EAPからQuarkusに変わったため、起動方法や定義部分で大きな変更があり、この対応のためマイグレーションガイドをRed Hat build of Keycloakのマニュアルで整備されています。 access.redhat.com マイグレーションガイドは、Red Hat Single Sing-on 7.6からのVMでのデプロイメント、OpenShift Operatorでのデプロイメントなどのデプロイメント別のマイグレーションや、カスタムプロバイダーやカスタムテーマの以降についても記載があります。 また、カスタムプロバイダーについては、Quarkus3.x系をベースにしているため、Java EE から Jakarta EE(Jakarta EE 10) への移行が必要となります。 最後に 簡単ではありますが、Red Hat SSOからのRed Hat build of Keycloakの変更点やマイグレーション情報について、ご紹介しました。 ランタイムがQuarkus変わる大きな変更ですが、Quarkusは環境変数で構成情報(管理者情報、DB接続情報など)を渡せるので、検証したりするのがより簡単になったなぁと思います。 QuarkusのDev UI利用 などはこれからの検討なのですが、その機能が使えるようになると、内部の動きもわかりやすくなるなと感じています。
※この記事は Red Hat Advent Calendar 2023 の 16日目の記事です。 qiita.com こんにちは。レッドハットでクラウドインフラを生業にしている宇都宮(うつぼ)です。 早速ですがストレージに関する問題です。 問題 アリスはオンプレミスで展開された OpenShift(または Kubernetes)クラスタの管理者です。 クラスタには1つ 10TiB ものデカすぎる PV があります。この PV のバックエンドはブロックストレージで、Thin-provisioned な論理ボリュームを使っています。 ストレージの管理者であるボブからは「もうストレージの容量がなくなりそうだから、この PV から容量を返してくれ」と言われています。 クラスタ管理者のアリスは、このデカすぎる PV を使うキャロルにこの話をして、PV 内に溜め込んだ不要なファイルを消してもらうことになりました。 キャロルからは、「仰せの通りファイルを消した、3分の1 くらいになった」と報告を受けました。 アリスはこれで一件落着と枕を高くして寝ました。しかし翌日ボブからは「もう本当にまずい!早く容量を返してくれ!」と言われ、困惑しています。 さて、なぜでしょうか。なお、ボブもキャロルも嘘はついていないものとします。 解答 簡単ですね。正解は、 ファイルを消してもファイルシステムは勝手に縮まないし、ファイルシステムが縮まなければボリュームサイズも減らないから です。 これは別に Kubernetes とかに限った話ではありません。一般的な Linux サーバでも同じ現象は起こります。 そもそも上の問題で一番ダメなのは 10TiB の PVC を許しているところで、OpenShift かストレージ側で Quota をかけて制限すべきです。 ですが、ブロックストレージだとファイルシステムでファイルを消したら自動で空いた容量がストレージに帰っていくなんてことは無いので、アリスもぐっすり寝てる場合ではありません。 Space Reclamation と PV 一度使ったけど空いた容量をストレージ側に返すことを、Space Reclamation と言います。 シックプロビジョニングではまず出てきませんが、シンプロビジョニングではおなじみの概念です。 シンプロビジョニングは「自分が必要な容量だけ使うべき」なポリシーですので、「必要なくなって取りすぎた容量は返すべき」だからです。 通常の Linux で Space Reclamation するには、 fstrim コマンドを実行してファイルシステムの使っていない領域を開放します。その後はストレージ側でそれを回収します。 それでは Kubernetes PV の場合は?わざわざ Pod や Worker ノードに入って fstrim を実行する?そんな運用ありえないですよね。 PV の場合は、CSI (Container Storage Interface) Add-on を使って Reclaim することができます。 ReclaimSpaceJob というカスタムリソースを使います。Reclaim はそんなに常時やるものではないので、単発で Job 的に使います。 github.com ODF で PV の Space Reclamation を試してみる Red Hat OpenShift Data Foundation(ODF)はこれに対応しているので、実際やってみましょう。 ODF がインストールされたクラスタで適当なアプリを作って 50GiB PVC をアタッチします。 Pod からは /dev/rbd0 として見えます。この時点ではほとんど空っぽ。 sh-4.4$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop1 7:1 0 512G 0 loop rbd0 252:0 0 50G 0 disk /mnt nvme0n1 259:0 0 100G 0 disk |-nvme0n1p1 259:1 0 1M 0 part |-nvme0n1p2 259:2 0 127M 0 part |-nvme0n1p3 259:3 0 384M 0 part `-nvme0n1p4 259:4 0 99.5G 0 part /dev/termination-log sh-4.4$ df -h /mnt Filesystem Size Used Avail Use% Mounted on /dev/rbd0 49G 24K 49G 1% /mnt ODF のダッシュボードで見ても、ほとんど使われていない初期状態です。 ここで 10GiB のダミーファイルを書き込みます。10GiB 増えています。(当たり前) sh-4.4$ dd if=/dev/random of=/mnt/10G.dat bs=1M count=10240 10240+0 records in 10240+0 records out 10737418240 bytes (11 GB, 10 GiB) copied, 81.0443 s, 132 MB/s sh-4.4$ sh-4.4$ df -h /mnt Filesystem Size Used Avail Use% Mounted on /dev/rbd0 49G 11G 39G 21% /mnt ODF では三重でレプリケーションされるので、ダッシュボードで見ると 3倍の 30GiB ほどが増えていることがわかります。 それでは Pod でファイルを削除します。10GiB 減ります。 sh-4.4$ rm -f /mnt/10G.dat sh-4.4$ sh-4.4$ df -h /mnt Filesystem Size Used Avail Use% Mounted on /dev/rbd0 49G 24K 49G 1% /mnt ODF では、全然減ってません。 さてここで ReclaimSpaceJob を作って Reclaim してみましょう。 apiVersion: csiaddons.openshift.io/v1alpha1 kind: ReclaimSpaceJob metadata: name: reclaim-odf-pvc namespace: test spec: target: persistentVolumeClaim: odf-pvc これを実行すると、次のようになります。 減っている! ODF の中で動く Ceph のブロックデバイス(RBD)は、シンプロビジョニングで作られます。 この ReclaimSpaceJob によって、アプリ Pod と同じノードで動く CSI driver が fstrim を実行します。Ceph RBD は sparse なイメージファイルなので、ゼロ領域は自動的に Ceph のプールに返されます。 CSIドライバのログより Space Reclamation はスケジュールするともっと楽 ad hoc に Reclaim するなら ReclaimSpaceJob を作りますが、定期的に実行するようスケジュールしておくとよいです。 ReclaimSpaceCronJob というカスタムリソースでスケジュールを設定できるのですが、対象の PVC に annotation を追加することで代用できます。 # oc annotate pvc odf-pvc "reclaimspace.csiaddons.openshift.io/schedule=@weekly" -n test persistentvolumeclaim/odf-pvc annotated 上の @weekly の部分は Cron と同じ書き方でもOKです。毎週金曜日の深夜0時に実行するなら、 0 0 * * 5 みたいな感じですね。 これでアリスもボブも枕を高くしてぐっすり眠れることでしょう。 まとめ クラウド環境で Space Reclamation しないとマズい、ということはほとんど無いと思いますが、冒頭の問題のようにオンプレミス環境だったら意外とあるかもしれません。 ストレージはあって当然使えて当然、とお思いの方もいるかもしれませんが、いやいや結構中の人は色々と工夫と苦労をしているんですね。 今回は ODF で確認しましたが、他のストレージの CSI はどうなのでしょう。すみません私もわかりません。色々と試してみるとよいのではないかなと思います。 というわけで、今回はここまで。
Red Hatの織です。本記事はAWS Containers Advent Calendar 2023の12/15のエントリーです。 内容としてはAmazon Linux 2023でPodmanを動かしてみました、という話です(AWSのコンテナ関連サービスを使ってなくて申し訳ありません...)。一言でまとめると、現状いろいろパッケージが足りないため、頑張ってコンパイルしていくhard wayな感じです。男らしくmainブランチのHEADをごりごりとビルドしていきます。 いろいろコンパイル rpmがあるものについてはそれを活用します。 sudo dnf install -y git golang runc cni-plugins gpgme-devel 作業ディレクトリを作成しておきます。 mkdir work cd work 最低限必要なソースコードをgit cloneします。 git clone https://github.com/containers/podman.git git clone https://github.com/containers/conmon.git git clone https://gitlab.freedesktop.org/slirp/libslirp.git git clone https://github.com/rootless-containers/slirp4netns.git conmon Podman(およびCRI-O)のコンテナモニター (コンテナプロセスのsubreaperとして動きます、containerdにおけるshim+αに相当します) であるconmonをコンパイルします。 cd conmon sudo dnf install -y \ gcc \ git \ glib2-devel \ glibc-devel \ libseccomp-devel \ make \ pkgconfig \ runc make sudo make install cd .. slirp4netns rootless実行するときのユーザーランドネットワーキングで使用するslirp4netnsをコンパイルします...が、その前提となるlibslirpをまず作ります。 cd libslirp sudo dnf install -y meson ninja-build meson build ninja -C build sudo ninja -C build install cd .. 次にslirp4netnsをビルドします。 cd slirp4netns sudo dnf -y install autoconf automake libcap-devel ./autogen.sh LDFLAGS='-Wl,-R/usr/local/lib64' ./configure make sudo make install cd .. podman 本題のpodmanをビルドします。 cd podman make sudo make install cd .. 最低限の設定ファイルを作っておきます。 sudo mkdir /etc/containers cat <<END | sudo tee /etc/containers/policy.json { "default": [ { "type": "insecureAcceptAnything" } ] } END 動作確認 まずはHello Podman Worldしてみましょう。 [ec2-user@ip-10-0-1-189 ~]$ podman run quay.io/podman/hello Trying to pull quay.io/podman/hello:latest... Getting image source signatures Copying blob d08b40be6878 done | Copying config e2b3db5d4f done | Writing manifest to image destination !... Hello Podman World ...! .--"--. / - - \ / (O) (O) \ ~~~| -=(,Y,)=- | .---. /` \ |~~ ~/ o o \~~~~.----. ~~ | =(X)= |~ / (O (O) \ ~~~~~~~ ~| =(Y_)=- | ~~~~ ~~~| U |~~ Project: https://github.com/containers/podman Website: https://podman.io Documents: https://docs.podman.io Twitter: @Podman_io いい感じですね。次はNginxを起動します。 [ec2-user@ip-10-0-1-189 ~]$ podman run -d -p 8080:80 docker.io/library/nginx Trying to pull docker.io/library/nginx:latest... Getting image source signatures Copying blob 84b1ff10387b done | Copying blob 1f7ce2fa46ab done | Copying blob 9ea27b074f71 done | Copying blob 9b16c94bb686 done | Copying blob c6edf33e2524 done | Copying blob 9a59d19f9c5b done | Copying blob 517357831967 done | Copying config a6bd71f48f done | Writing manifest to image destination 3c1cb97dd6d3525383db7202c455817e3a635ae21e5205aa6fdfad1e528fd8ea さらにNginx Podにアクセスしてみます。 [ec2-user@ip-10-0-1-189 ~]$ curl -q -s -o /dev/null -w '%{http_code}\n' http://localhost:8080 200 rootlessコンテナへのネットワークアクセスも問題なさそうです。 おまけ 最近のPodmanは、OCIランタイムとしてcrunを、ネットワークプラグインとしてnetavarkを使うことが多いです。これらもビルドして使ってみます。 crun git clone https://github.com/containers/crun.git cd crun sudo dnf install -y make python git gcc automake autoconf libcap-devel systemd-devel yajl-devel libseccomp-devel pkg-config libgcrypt-devel go-md2man glibc-static python3-libmount libtool golang-github-cpuguy83-md2man ./autogen.sh ./configure make -j sudo make install cd .. netavark git clone https://github.com/containers/netavark.git cd netavark curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env" sudo dnf install protobuf-devel protobuf-c-devel make sudo make install cd .. aardvark git clone https://github.com/containers/aardvark-dns.git cd aardvark-dns make sudo make install cd .. 動作確認 まず、以前の設定(CNIプラグインで実行していたコンテナ等)をクリアしておきます。 podman system reset 今のバージョンだと、crunとnetavarkがあればデフォルトでそちらを使うようになっていますので、これで準備は完了です。 念のため以下のコマンドで確認しておきます。 $ podman info -f json | jq -r '.host.ociRuntime.path, .host.networkBackendInfo.path' /usr/local/bin/crun /usr/local/libexec/podman/netavark あとは上でやったのと同じようにPodを起動してみましょう (結果は省略)。 最後に Amazon Linux 2023でPodmanを動かしてみました。いろんな部品をコンパイルしないといけないのでちょっと面倒ですね...
Red Hat のソリューションアーキテクトの瀬戸です。 概要 以前jpackageを使ったクライアントアプリケーションのパッケージングの方法についてまとめました。 rheb.hatenablog.com その時にmsi形式でパッケージングをしましたが、このmsiという拡張子のついたファイルは何なのでしょうか? msiはWindows上で実行できるファイルの中で、ソフトウェアのインストールに使えるファイルにつけられる拡張子です。Microsoft Windows Installerの略となっています。 特別な拡張子が割り当てられているだけではなく、中に含まれるファイルの実行時のオプションや内容が仕様で決められており、Windows ServerのActive Directoryを使用することでクライアントサイドのWindowsに自動的にソフトウェアをインストールすることに使う事ができます。 なぜmsi形式のファイルが作れると嬉しいかというと、この形式であればWindowsのアプリケーション管理機能に乗せて一元管理ができるからですね。 クライアントPCが数千台あったとしても1台ずつインストールをしていく必要はなくなります。 普段から企業内でIT管理者をやっておりActive Directoryを触っている人からは常識なのですが、一般的な開発者はなかなかActive Directoryに触れる機会がないので、機能の紹介を兼ねて設定方法を説明していきます。 環境の説明 今回はWindows Server 2022を使って試していきます。 サーバー、クライアントの準備 AWS上のWindows Server 2022 Data Center Editionと、オンプレのWindows 11 Professional Editionを利用しました。 *1 Home EditionではActive Directory(ドメイン)に参加できないのでご注意ください。 また、Active Directoryについては設定済みとし、クライアントPCはすでにActive Directory(ドメイン)に参加しているものとしています。 *2 使用するアプリケーション(msiファイル)の準備 jpackageを使用して準備しました。オプションは次の通りです。 > jpackage --type msi --icon shadowman.ico --vendor "red hat" --app-version 1.0 --win-menu --win-shortcut --input .\target --win-upgrade-uuid 2bc2b28e-5b34-45e3-9e4f-11e87d88f7cb --name clientexample --main-class com.redhat.clientexample.App --main-jar clientexample.jar 自動インストール用を想定しているため、デフォルトでサイレントインストールになるように指定をしています。どういう意味を持つのかの詳細は前回までの記事を参照してください。 rheb.hatenablog.com rheb.hatenablog.com 実際に設定をする 次のような手順で行っていきます。 共有フォルダにmsiファイルを設置する GPO(グループポリシーオブジェクト)でソフトウェアのインストールの設定を行う GPO(グループポリシーオブジェクト)をドメインに割り当てる 共有フォルダにmsiファイルを設置する サーバーのフォルダを共有します。このフォルダはクライアント側からアクセスできるように設定されている必要があります。クライアント側からアクセスできれば良いので、NAS等を使って別途構築してある場所でも大丈夫です。 今回はEveryone向けに読み取り権限を付けて共有します。 ファイル共有設定 アクセス権の設定 ネットワーク越しに参照できることを確認します。 ネットワーク越しの確認 これでインストールするmsiファイルの設置は終わりました。 GPO(グループポリシーオブジェクト)でソフトウェアのインストールの設定を行う ファイル名を指定して実行から mmcを実行することでMMC(Microsoft Management Console)が起動します。 MMCのファイルメニューからスナップインの追加と削除を選択することでGPOの管理画面を開くことができます。 ファイル名を指定して実行 MMCの初期画面 初期画面には何もないので、ファイルのスナップインの追加と削除を選択します。 GPOのファイルメニュー 引き続きグループポリシーの管理を選択して追加します。次のように選択すればOKです。 スナップインの追加と削除 ソフトウェアを配布したいドメインの中のグループポリシーオブジェクトのフォルダを選択します。 GPOの管理画面 右クリックから新規を選択します。 GPOの新規作成 新しいGPOの名前を指定します。今回はソフトウェア配布と付けています。 新しいGPOに名前を付ける 作成されました。 GPOの作成 作成したGPOを右クリックメニューから編集します。 ソフトウェア配布の編集 グループポリシー管理エディタが開くので、コンピューターの構成→ポリシー→ソフトウェアの設定→ソフトウェアインストールを選択します。 グループポリシー管理エディタ 右クリックからNew->Packageを指定してください。 ソフトウェアインストールの選択 ファイルのダイアログが開くのでそのまま指定したいところですが、ローカルディスクのファイルを指定するとエラーメッセージが表示されます。クライアントから表示できるネットワークドライブ上のファイルのUNC *3 を指定する必要があります。ファイルダイアログからネットワークファイルを探して指定することでもUNCと解釈されます。 ローカルファイルの指定 ローカルファイルを指定したときのエラー ネットワークフォルダの指定時のパス 引き続き、デプロイ方法を指定します。 デプロイ方法は詳細設定を指定します。ここで割り当てを選んでしまった場合はクライアントの状況によってインストールできないことがあります。 デプロイ方法の指定 詳細設定を選択してOKを押すと追加の設定画面が表示されます。割り当てを指定したあとにプロパティを開いても同じ画面を表示することができます。 こちらから、展開の詳細設定⇒詳細設定オプションのこのパッケージを展開するときは言語を無視するをチェックします。jpackageでは現時点では言語の指定が出来ないため、日本語Windowsにインストールしたい場合はこちらを有効にする必要があります。 詳細設定画面 詳細設定オプション これでインストールするパッケージの指定が完了です。 完了後画面 今回は追加で、セキュリティーフィルターの処理で、インストールしたいPCを直接選択しています。実運用環境では対象となるPCのグループを指定することになるのではないかと思います。 インストールしたいPCの指定 GPO(グループポリシーオブジェクト)をドメインに割り当てる ここまで出来たら、最後にインストール処理を行いたいドメインに対してGPOのリンクを行います。 ドメインを選択して、既存のGPOのリンクから作成したGPOを選択します。 GPOのリンク これでクライアントへの配布が行われるようになります。 ただし、GPOはクライアントに即座に反映されるわけではなく、組織の設定により遅延して反映されます。十分な時間を置いた後にクライアントPCを再起動するとソフトウェアが配布されているはずです。 *4 デスクトップ上にアイコンがでてくる 当然プログラムの追加と削除にもでてくる まとめ Active Directoryを使用したWindowsクライアントへのアプリケーションの配布方法の手順を説明してきました。 JavaはWindows/Linux/Macのどこでも動くということもあり、Windows固有の情報についてJava開発者は疎くなりがちです。そのため、Windows上でのクライアント開発を行っても配布方法がわからないなどで.net等に後れを取っているのではないかと感じます。 実際にはWindows Serverが標準的な配布の仕組みを持っており、msi形式のアプリケーションを配布できるので、特に問題は発生しないです。 Windows/Unix/Macで動作するアプリケーションが作れますので、ぜひ使用をご検討ください。 Windows インストーラー - Win32 apps | Microsoft Learn Active Directory Domain Services の概要 | Microsoft Learn *1 : つまり、そこらへんに転がってた自宅のPC *2 : つまり、一般的な企業でPCが管理されている状態 *3 : \\からはじまるやつ *4 : テスト目的などで強制的にGPOを適用したい場合はgpupdateというコマンドがあります。
はじめに Loki について クエリの種類 Log クエリ Metric クエリ OpenShift Logging としての構築 Operator の導入 Loki のデプロイ Cluster Logging として利用する 簡単なアクセス確認 Web Console からのアクセス CLI からのアクセス アクセス方法の確認 Metric クエリを呼び出してみる LogCLI おわりに はじめに Red Hat Advent Calendar 2023 の 12月14日の記事です。OpenShift Cluster Logging で Loki が利用できるようになってからしばらく時間が経ち、段々と利用されつつあるのではないかと思います。 本記事では、OpenShift Cluster Logging (Loki) を OpenShift Web Console からではなく、あえて CLI 経由でアクセスしてみます。 Loki について grafana.com Loki は Grafana Loki という名称で、Prometheus からインスパイアされたスケーラビリティ、可用性、マルチテナントに対応したログ収集システムです。 他のログシステムと異なり、ログ自身にはインデックスを持たず、メタデータのみをインデックス化して管理します。 ログはメタデータとしてラベルを持つことで管理されます。同じラベルをもつログのセットを Log Stream と呼びます。 ログデータは圧縮され、オブジェクトストレージに格納されるためログデータを効率よく保持できる仕組みとなっています。 クエリの種類 Loki の検索は LogQL を利用します。OpenShift の Web Console から呼び出すときに使います。格納されたログから特定のメッセージなどを絞り込んで見る際に利用します。LogQL は 2つの種類があり、それぞれ Log クエリと Metric クエリに別れます。 Log クエリ ログデータを返却します。ログメッセージの絞り込みなどで目的のエラー情報などを検索するときに活躍します grafana.com Metric クエリ Log クエリの拡張版でログの検索結果をベースに演算することが目的です。 grafana.com OpenShift Logging としての構築 まずは製品ドキュメントに従いながら、Loki を利用した Logging を構築していきます。 まずは Operator の導入から。Operator は Loki Operator と OpenShift Cluster Logging Operator の 2 つが必要となります。それぞれをインストールします。 Operator の導入 Loki Operator をインストールする Namespace の作成 $ cat << EOF | oc create -f - apiVersion: v1 kind: Namespace metadata: name: openshift-operators-redhat annotations: openshift.io/node-selector: "" labels: openshift.io/cluster-monitoring: "true" EOF Cluster Logging Operator をインストールする Namespace の作成 $ cat <<EOF | oc create -f - apiVersion: v1 kind: Namespace metadata: name: openshift-logging annotations: openshift.io/node-selector: "" labels: openshift.io/cluster-monitoring: "true" EOF OpenShift Cluster Logging 用の OperatorGroup と Subscription を作成する OperatorGroup の作成 $ cat <<EOF | oc create -f - apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: cluster-logging namespace: openshift-logging spec: targetNamespaces: - openshift-logging EOF 続いて、Subscription を作成します。 $ cat <<EOF | oc create -f - apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: cluster-logging namespace: openshift-logging spec: spec: channel: stable-5.8 installPlanApproval: Automatic name: cluster-logging source: redhat-operators sourceNamespace: openshift-marketplace startingCSV: cluster-logging.v5.8.0 EOF 次に、Loki Operator をインストールします。Cluster Logging Operator 同様に Subscription を作成します。 $ cat << EOF | oc create -f - apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: loki-operator namespace: openshift-operators-redhat spec: channel: stable-5.8 installPlanApproval: Automatic name: loki-operator source: redhat-operators sourceNamespace: openshift-marketplace EOF Loki のデプロイ Loki は Object Storage を必要とします。今回の構築環境は AWS を利用しているので、適当に AWS S3 のバケットを作成して利用します。 Object Storage へのアクセス情報は Secret を利用して指定するため、接続情報を以下のように用意します。 $ cat <<EOF | oc create -f - apiVersion: v1 kind: Secret metadata: name: logging-loki-s3 namespace: openshift-logging stringData: access_key_id: <ACCESS KEY> access_key_secret: <ACCESS_KEY_SECRET> bucketnames: <BUCKET_NAME> endpoint: https://s3.ap-southeast-2.amazonaws.com region: ap-southeast-2 EOF 次に、LokiStack Custom Resource を作成します。今回作成する LokiStack のサイズは 1x.small とします。 $ cat <<EOF | oc create -f - apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki # 1 namespace: openshift-logging spec: size: 1x.small #2 storage: schemas: - version: v12 effectiveDate: '2022-06-01' secret: name: logging-loki-s3 #3 type: s3 #4 storageClassName: gp3-csi #5 tenants: mode: openshift-logging EOF パラメタの簡単な説明 logging-loki という名前を使用してください。 Loki の展開サイズを選択してください。 ログストレージに使用するシークレットを指定してください。 対応するストレージタイプを指定してください。 一時的なストレージに既存のストレージクラスの名前を入力してください。最適なパフォーマンスを得るためには、ブロックストレージを割り当てるストレージクラスを指定してください。クラスタで利用可能なストレージクラスは、oc get storageclasses コマンドを使用してリストアップできます。 Cluster Logging として利用する デプロイした Loki を OpenShift Cluster Logging として利用します。 $ cat << EOF | oc create -f - apiVersion: logging.openshift.io/v1 kind: ClusterLogging metadata: name: instance namespace: openshift-logging spec: logStore: type: lokistack lokistack: name: logging-loki collection: type: vector EOF docs.openshift.com 簡単なアクセス確認 Web Console からのアクセス ここまでで、Loki が利用できるようになっているはずなので、Web Console からも簡単に確認してみます。 Web Console の Administrator の画面から、 Observe > Logs を選択すると画面が表示されます。 Logs CLI からのアクセス ここで本題です。今回 CLI アクセスを試すきっかけとなったのは、実は OpenShift Web Console からはまだ Metric クエリを実行することができません。そのため、Metric クエリを実行するにはどうしても CLI 経由での呼び出しが必要となります。 アクセス方法の確認 Loki へのアクセスは Route 経由で行います。 $ oc get route -n openshift-logging NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD logging-loki logging-loki-openshift-logging.apps.samplecluster.sandboxABCDE.opentlc.com logging-loki-gateway-http public reencrypt None 呼び出し方を確認するため、試しに Route にアクセスしてみます。Loki は OpenShift による認証を利用しているため、OpenShift のユーザーのトークンを利用してアクセスしてみます。 $ curl -k -s -H 'Authorization: Bearer <TOKEN>' https://logging-loki-openshift-logging.apps.samplecluster.sandboxABCDE.opentlc.com { "paths": [ "/api/logs/v1/{tenant}/*" ] } {tenant} を指定する必要がありそうです。テナントとは何でしょうか。実は、OpenShift Cluster Logging では Loki のマルチテナント機能を利用して、infrastracture ログ、application ログ、audit ログを分けて格納しています。 そのため、ここでいう {tenant} は infrastructure 、 application 、 audit となります。 Loki の API のパスは製品ドキュメントに記載があり以下のようになっています。パスの最後にある query_range は呼び出すAPIにより代わりますが、今回は Metric クエリを呼び出すのでこちらを利用します。 GET /loki/api/v1/query_range これを合わせると次のようなURLを呼び出すことで、 curl でアクセスできることがわかります。 https://logging-loki-openshift-logging.apps.samplecluster.sandboxABCDE.opentlc.com/api/logs/v1/{tenant}/loki/api/v1/query_range grafana.com Metric クエリを呼び出してみる LogQL は空白やシングルクォートなども含むため、URLエンコードした形で指定します。curl コマンドではパラメタ指定によりURLエンコードを行うことはできますが、予めエンコードしておきます。 今回テストするのは次の Metric クエリです。 Namespace 毎に log_type=infrastructure のログ数をカウントするというものです。 sum by (kubernetes_namespace_name) (count_over_time({ log_type="infrastructure" } [5m]) ) curl コマンドにすると以下のような感じです。 $ curl -G -k -s -H 'Authorization: Bearer sha256~_hJqP4Ksy5Opcs1_37s2fC2_XFXWigO6iXJEDBpM_nA' https://logging-loki-openshift-logging.apps.samplecluster.sandboxABCDE.opentlc.com/api/logs/v1/infrastructure/loki/api/v1/query_range --data 'query=sum%20by%20(kubernetes_namespace_name)%20(count_over_time(%7B%20log_type%3D%22infrastructure%22%20%7D%20%5B5m%5D)%20)' --data-urlencode step=2m --data-urlencode start=1702467769 --data-urlencode end=1702471369 呼び出し結果 { "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "kubernetes_namespace_name": "openshift-apiserver" }, "values": [ [ 1702469160, "1" ], [ 1702469280, "1" ], [ 1702469400, "5" ], [ 1702469520, "4" ], [ 1702469640, "4" ], [ ... うまく取得できたようです。 LogCLI 次に、Loki の CLI LogCLI でのアクセスを試します。 コマンドは、以下のページを参考に予め準備してください。 grafana.com 環境変数で接続先と認証情報を設定します。呼び出したいテナント毎に呼び出し先は変えてください。 $ export LOKI_BEARER_TOKEN="<TOKEN>" $ export LOKI_ADDR=https://logging-loki-openshift-logging.apps.samplecluster.sandboxABCDE.opentlc.com/api/logs/v1/infrastructure コマンドを実行します。OpenShift の証明書は自己署名証明書を利用しているため、TLSのチェックはスキップするようにします。 $ logcli query --tls-skip-verify 'sum by (kubernetes_namespace_name) (count_over_time({ log_type="infrastructure" } [5m]) )' 出力結果が取得できました。 curl で取得したときと異なり、result が抽出されてます。 [ { "metric": { "kubernetes_namespace_name": "openshift-apiserver" }, "values": [ [ 1702470154, "4" ], [ 1702470168, "4" ], [ 1702470182, "4" ], [ 1702470196, "4" ], [ 1702470210, ... おわりに 今回は、CLI を用いて Loki へのアクセスをしてみました。これにより現在は Web Console から利用できない Metric クエリの結果を取得できることが試せました。 まだ発展途上のコンポーネントではありますが、こういった形でログの解析ができるようになっていくとログを利用した運用や調査などが進みそうです。
Red Hatの織です。本記事はRed Hat Advent Calendar 12/5分の記事です (遅くなってしまいました)。また、Advent Calendar 12/3の「 libkrunで遊ぶ 」の続編でもあります。 Transparent Socket Impersonation libkrunでのネットワーク通信は、Transparent Socket Impersonation (TSI) という仕組みを使っています(直訳すると「透過的なソケットのなりすまし」)。TSIはlibkrun以外では聞いたことがないので、おそらく一般的な用語ではなくて、libkrun特有の概念ではないかと思います。TSIの仕組みによって、仮想インターフェース (virtio-net) を使わずにネットワーク通信ができるようになります (ただしAF_INTのSOCK_DGRAMおよびSOCK_STREAMの通信のみ)。 TSI概要 libkrunでは、ゲストOSのカーネルおよびFirmwareに相当する libkrunfw というコンポーネントがあります。libkrunのゲストOS内のプロセスが発行したシステムコールは、libkrunfwが処理します。 プロセスが通信を行う際はソケットAPIを使うことが多いと思いますが、ソケット関連のシステムコールもlibkrunfwによって処理されます。 libkrunfwのLinuxカーネルには、「タイプがSOCK_DGRAMもしくはSOCK_STREAMのAF_INETソケットはAF_TSIに変換する」という パッチ が当たっています。したがって、該当するソケット通信は全て、(クライアントはAF_INETとして通信しているつもりですがカーネル内ではAF_INETではなく)AF_TSIとして処理されます。 AF_TSIはAF_INETとAF_VSOCKの両方を透過的に処理できるような構造になっており、libkrunfwカーネルはゲスト内のプロセスが出すAF_INETのソケット通信をAF_VSOCKに偽装します。この仕組みを使うことで、ゲスト内のプロセスからのAF_INETのソケットは、virtio-vsockデバイスを経由し、VMM(以下、「VMM」と「libkrun」は同じ意味で書いています)をプロキシーとすることで、外と通信できるようになります。 libkrun TSI networking overview 突然AF_*のような用語が出てきました。AFはアドレスファミリー(Address Family)を表しており、ネットワークアドレスの種類と思ってください。AF_INETはおなじみのIPv4での通信を表します。AF_VSOCKは、仮想環境においてゲストとホストの間でのソケット通信をするためのアドレスファミリーです。典型的な使用例としては、ゲストエージェント(例えばVMware Tools的なもの)とホストとの通信が挙げられます。VSOCKは、最近ではコンテナ環境などいろんな場所で使われています。 また、 SOCK_DGRAM = UDP通信 SOCK_STREAM = TCP通信 を意味する、と思ってください。 詳細 「AF_INETとAF_VSOCKの両方を透過的に処理できる」「AF_INETのソケット通信をAF_VSOCKに偽装」の実装についてもう少し踏み込んでみましょう。以下では、「ゲストOS内のクライアントプロセスが、外部のサーバーに対してconnect(2)で接続し、write(2)で何かデータを書く」というユースケースを想定します。 tsi_sock構造体 Linuxカーネルでは、アドレスファミリーごとに、*_sockという構造体を用意しています。まずはAF_TSIの通信を表現するためのsock構造体( struct tsi_sock )を見てみましょう。 struct tsi_sock { /* sk must be the first member. */ struct sock sk; struct socket *isocket; // inet通信用ソケット struct socket *vsocket; // vsock通信用ソケット struct socket *csocket; // VMM制御用ソケット(VMM内にinet-vsockプロキシーのエントリ追加依頼等で使用、これもvsock) unsigned int status; u32 svm_port; u32 svm_peer_port; struct sockaddr_in *bound_addr; struct sockaddr_in *sendto_addr; }; sock構造体の中にAF_INET通信用、AF_VSOCK通信用のsocket構造体を持つことで、場面に応じてそれぞれどちらの通信でも表現できるようになっていることがわかります。 connect(2)時の動き 外部のIPアドレスに接続する際に呼ばれる、connect(2)システムコールの処理を見てみましょう。libkrun仮想マシン内のプロセスがconnect(2)を呼び出すと、libkrunfwのカーネル内ではtsi_connect()がその処理を担当します。tsi_connect()はおおまかに次のような処理の流れになっています。 static int tsi_connect ( struct socket *sock, struct sockaddr *addr, int addr_len, int flags) { ... tsk = tsi_sk (sock->sk); isocket = tsk->isocket; vsocket = tsk->vsocket; ... if (isocket) { ... err = isocket->ops-> connect (isocket, addr, addr_len, flags & ~O_NONBLOCK); ... } if (vsocket) { ... if (!tsk->svm_port) { if ( tsi_create_proxy (tsk, vsocket->type) != 0 ) { err = - EINVAL ; goto release; } } ... err = tsi_control_sendmsg (tsk->csocket, TSI_CONNECT, ( void *)&tc_req, sizeof ( struct tsi_connect_req)); ... err = tsi_control_recvmsg (tsk->csocket, TSI_CONNECT, ( void *)&tc_rsp, sizeof ( struct tsi_connect_rsp)); ... err = kernel_connect (vsocket, ( struct sockaddr *)&vm_addr, sizeof ( struct sockaddr_vm), 0 ); ... tsk->status = S_VSOCK; } ... } 今考えているユースケースでは、ゲスト→ホスト→外部という通信を想定しており、ゲストからの直接のconnectはできないため( 前回 の記事で確認したように、libkrunはvirtio-netは使っておらず、ゲスト内ではループバックインターフェースしか持っていません)、 if (isocket) の節は飛ばして if (vsocket) のif節に入ります。 この中では、おおまかに VMMに対してINET-VSOCKプロキシーをするためのエントリー作成する ( tsi_create_proxy() ) VMM内のINET-VSOCKプロキシー経由で外部サイトにconnectする ( tsi_control_sendmsg() でTSI_CONNECTする) という処理をしています。 INET-VSOCKプロキシーは、libkrun上では VsockMuxer および TcpProxy という構造体で表現されています。VsockMuxerがプロキシー全体を管理しており、プロキシーの各エントリーがTcpProxy、という役割になっています。 VsockMuxer構造体 pub struct VsockMuxer { cid: u64 , host_port_map: Option < HashMap < u16 , u16 >> , queue: Option < Arc < Mutex < VirtQueue >>> , mem: Option < GuestMemoryMmap > , rxq: Arc < Mutex < MuxerRxQ >> , epoll: Epoll, interrupt_evt: EventFd, interrupt_status: Arc < AtomicUsize > , intc: Option < Arc < Mutex < Gic >>> , irq_line: Option < u32 > , proxy_map: ProxyMap, reaper_sender: Option < Sender < u64 >> , } VsockMuxerには proxy_map というフィールドがあります。ProxyMap型のこのフィールドは、中身はHashMapです。dstポートとsrcポートをビットシフトして連結した値をプロキシーエントリーの "ID" とし、これをキーとして指定するとHashMapからTcpProxyが取り出せる、という作りになっています。 ProxyMap pub type ProxyMap = Arc < RwLock < HashMap < u64 , Mutex < Box < dyn Proxy >>>>> ; TcpProxy構造体 pub struct TcpProxy { id: u64 , cid: u64 , parent_id: u64 , local_port: u32 , peer_port: u32 , control_port: u32 , fd: RawFd, pub status: ProxyStatus, mem: GuestMemoryMmap, queue: Arc < Mutex < VirtQueue >> , rxq: Arc < Mutex < MuxerRxQ >> , rx_cnt: Wrapping < u32 > , tx_cnt: Wrapping < u32 > , last_tx_cnt_sent: Wrapping < u32 > , peer_buf_alloc: u32 , peer_fwd_cnt: Wrapping < u32 > , push_cnt: Wrapping < u32 > , pending_accepts: u64 , } 1.の処理(tsi_create_proxy())は、 TSI_PROXY_CREATE というメッセージを、制御用VSOCKソケット(csocket)を使ってVMMに対して送信し、この後connectするために使用するプロキシーエントリーの作成を依頼します。 このVSOCKメッセージを受けたVMMは、 VsockMuxer. send_dgram_pkt() @src/devices/src/virtio/vsock/muxer.rs VsockMuxer. process_proxy_create() @src/devices/src/virtio/vsock/muxer.rs という流れで処理が進み、TcpProxyのエントリーを作成後proxy_mapに格納します。 2.の処理では、 TSI_CONNECT というメッセージを、制御用VSOCKソケット(csocket)を使ってVMMに送信し、プロセスからのconnect(2)をlibkrunに代替してもらうよう依頼します。 このVSOCKメッセージを受けたVMMの中では、 VsockMuxer. send_dgram_pkt() @src/devices/src/virtio/vsock/muxer.rs VsockMuxer. process_connect() @src/devices/src/virtio/vsock/muxer.rs TcpProxy. connect() @src/devices/src/virtio/vsock/tcp.rs nix:: connect() @src/sys/socket/mod.rs libc:: connect() @/src/unix/mod.rs という流れで最終的にconnect(2)システムコールを呼び出します。 write(2)時の動き Linuxカーネルにおいて、ソケットに対してwrite(2)した場合、 socket_file_ops の .write_iter() メンバ関数が呼ばれます。 static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .read_iter = sock_read_iter, .write_iter = sock_write_iter, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_sock_ioctl, #endif .mmap = sock_mmap, .release = sock_close, .fasync = sock_fasync, .sendpage = sock_sendpage, .splice_write = generic_splice_sendpage, .splice_read = sock_splice_read, .show_fdinfo = sock_show_fdinfo, }; さらにその後、 sock_write_iter() → sock_sendmsg() → sock_sendmsg_nosec() → sock->ops->sendmsg() という流れになり、最終的に struct proto_ops のメンバ関数 sendmsg() が呼び出されます。AF_TSIの場合は tsi_stream_sendmsg() (TCPの場合) もしくは tsi_dgram_sendmsg() (UDPの場合) が呼ばれることになります。ここではTCPを想定して tsi_stream_sendmsg() を見ていきましょう。 static int tsi_stream_sendmsg ( struct socket * sock, struct msghdr * msg, size_t len) { struct sock * sk = sock -> sk; struct tsi_sock * tsk; struct socket * isocket; struct socket * vsocket; int err; lock_sock (sk); tsk = tsi_sk (sock -> sk); isocket = tsk -> isocket; vsocket = tsk -> vsocket; pr_debug ( "%s: s=%p vs=%p is=%p st=%d \n " , __func__, sock, vsocket, isocket, tsk -> status); switch (tsk -> status) { case S_HYBRID: err = - EINVAL; break ; case S_INET: err = isocket -> ops -> sendmsg (isocket, msg, len); break ; case S_VSOCK: err = vsocket -> ops -> sendmsg (vsocket, msg, len); pr_debug ( "%s: s=%p vs=%p is=%p st=%d exit \n " , __func__, sock, vsocket, isocket, tsk -> status); break ; } release_sock (sk); return err; } connect(2)時にtsk->statusに S_VSOCK を入れているので、ここではvsocketを使って vsocket->ops->sendmsg() でデータを送信していることがわかります。VSOCKでのsendmsg()では、最終的に VIRTIO_VSOCK_OP_RW というメッセージをVMMに対して依頼します。 このVSOCKメッセージを受けたVMMでは、以下の流れで処理が進み、最終的にsend(2)を使ってファイルディスクリプタにデータを書き込みます。 VsockMuxer. send_stream_pkt() @src/devices/src/virtio/vsock/muxer.rs VsockMuxer. process_stream_rw() @src/devices/src/virtio/vsock/muxer.rs TcpProxy. sendmsg() @src/devices/src/virtio/vsock/tcp.rs nix:: send() @src/sys/socket/mod.rs libc:: send() @src/unix/mod.rs まとめ というわけで、libkrunのゲスト内のプロセスから外部のIPアドレスに対してソケット通信をする様子を追いかけてみました。libkrunではvirtio-netを使用しないため、ゲストはループバックインターフェースしか持っていません。しかし、TSIの巧妙な仕組みによってINET通信をVSOCKに変換し、VMM内に持つINET-VSOCKプロキシーを介して、ゲスト↔VMMはVSOCKを、VMM↔外部はINETを使って通信する様子がわかりました。
こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 前回に引き続き、今回もOpenShift Virtualization(OCP Virt)について紹介していきたいと思います。 環境の構築やインストールに関しては前回の記事を参照下さい。 rheb.hatenablog.com この記事ではWindows ServerをOCP Virt上でVMとして構築し、関連してContainerized Data Importer(CDI)やDataVolumeについて紹介したいと思います。 Windows Serverの構築 Red HatはWindows Serverを実行する仮想化ソフトウェアについて Microsoftとパートナー であり、OCP Virtも複数バージョンのWindows Serverの実行をサポートしています。 access.redhat.com 今回はWindows Server 2022をOCP Virtで実行したいと思います。 まずはOCPコンソールのカタログから対象のバージョンを選び、設定のカスタマイズを行なっていきます。 前回の記事でRHEL9のVMを起動した際はOCP Virtをインストールした時点でOSのイメージがOCP環境上に準備されていましたが、Windows Serverを利用する場合はOSのISOファイルを準備する必要があります。 まず以下のサイトからISOをダウンロードするためのURLをコピーしておきます。 www.microsoft.com 画像のように"Boot from CD"にチェックを入れ、CD sourceとして"URL"を選択、そして"Image URL"にコピーしておいたURLを貼り付けます。 あとはそのままの設定でVMを作成しましょう。 しばらくするとVMが起動しOSのセットアップが開始されます。 OCP VirtではVNCコンソールを利用できるためここから設定を進めていきます。 設定が完了すると無事にWindows Serverを起動することができました。 QEMU Guest Agentのインストール Windows Server起動後、VMの管理を円滑に行うためQEMU Guest Agentをインストールしたいと思います。 ドキュメントに関しては以下を参照下さい。 access.redhat.com ファイルエクスプローラーを開き画面左側から"virtio-win" CDドライブを選択します。 "guest-agent"フォルダを開き、中にあるインストーラーを実行するとQEMU Guest Agentをインストールすることができます。 PowerShellから net start コマンドを実行するとQEMU Guest Agentの実行を確認できます。 リモートデスクトップ接続 起動したVMに対し、手元の環境(Mac)からRDPで接続してみたいと思います。 まずはVNCコンソールからサーバーマネージャーを開き、リモートデスクトップを有効化しておきます。 その後コンソールをVNCコンソールから"Desktop viewer"に切り替え、"Create RDP Service"を実行します。 これにより type: NodePort のServiceが新たに作成され、VMが起動するベアメタルNodeのIPを通じてクラスター外部からのRDP接続が可能となりました。 ただし今回も前回同様にAWS上のベアメタルサーバーを利用しているため、手元の環境から上記のアドレスに直接のアクセスはできません。 そのためPublic Subnet上で踏み台サーバーを構築し、ポートフォワードを行うことで手元の環境からアクセスを可能としました。またAWSのSGについても適宜設定変更をしておきます。 ssh -i ~/.ssh/cluster-key ec2-user@{踏み台のパブリックIP} -L 3389:10.0.68.1:31183 無事手元の環境からアクセスすることができました。 Containerized Data Importer(CDI) / DataVolume について 今回はVMを作成するタイミングでコンソールからISOファイルのURLを指定しましたが、実際のファイルのダウンロードや、ダウンロード先としてのPVの作成などはDataVolumeと呼ばれるCRや、それを管理するContainerized Data Importer(CDI) Operatorにより行われます。 CDI OperatorはOCP VirtのOperatorをインストールし、HyperConverged CRを作成するとOpenShift環境にインストールされます。 DataVolume CRを作成すると、OSイメージをダウンロードするためのImporter Podと保存用のPVが作成されます。 指定したURLからOSイメージのダウンロードが完了するとImporter Pod等のリソースは削除され、VMを起動するためのVirt Launcher Podに先ほどのPVがアタッチされ、そこからOSの起動を可能としています。 DataVolumeによるOSイメージを含むPVの作成はURLを指定してダウンロードする以外にも、 利用者の端末からのアップロードや、既存のPVからのコピー、PVのSnapshotsからの作成、さらにはコンテナ化されたOSイメージの利用と複数の方法を取ることができます。 例えば、前回の記事ではRHEL9のVMを起動しましたが、この場合はOSイメージがVolumeSnapshotsとして保存されており、そこからPVが作成されVirt Launcher Podにアタッチされていました。 openshift-virtualization-os-images NameSpaceを見るとVolumeSnapshotsとしてCentOS StreamやFedora、そしてRHELのイメージが存在しているのがわかります。 # oc get volumesnapshots -n openshift-virtualization-os-images NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE centos-stream8-c323729af4d6 true centos-stream8-c323729af4d6 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-a71a0072-a2e9-42f3-a54b-e480b3a2fe2d 20h 20h centos-stream9-e5a8aee22808 true centos-stream9-e5a8aee22808 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-2f4aea79-e29e-44c1-8fc5-a1e13babf7d4 20h 20h centos7-680e9b4e0fba true centos7-680e9b4e0fba 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-2126c3be-bb95-43d0-ad77-b9fee8486a4c 20h 20h fedora-498bd939ff7a true fedora-498bd939ff7a 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-d774d73a-1c11-4572-bb84-024fb8770bd4 20h 20h rhel8-3d8ef774e232 true rhel8-3d8ef774e232 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-d74e8c7d-f401-4bee-a14f-17e99c33d413 20h 20h rhel9-1467c655829b true rhel9-1467c655829b 30Gi ocs-storagecluster-rbdplugin-snapclass snapcontent-08727a8b-75f4-4b0b-b0d8-0b073e30cfc3 20h 20h さて、ではこのDataVolumeがいつ定義され作成されるのかというと、実はVirtualMachine CRを作成する際にDataVolumeTemplateとして設定が行われています。先ほどWindows Severを起動したyamlを見てみると以下のような記載となっています。 apiVersion: kubevirt.io/v1 kind: VirtualMachine ---snip--- spec: dataVolumeTemplates: - apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: annotations: cdi.kubevirt.io/storage.bind.immediate.requested: 'true' creationTimestamp: null name: win2k22-kvirt spec: source: blank: {} storage: resources: requests: storage: 30Gi - metadata: creationTimestamp: null name: win2k22-kvirt-installation-cdrom spec: source: http: url: >- https://go.microsoft.com/fwlink/p/?LinkID=2195280&clcid=0x411&culture=ja-jp&country=JP storage: resources: requests: storage: 30Gi .spec.dataVolumeTemplates の中に二つのDataVolume設定があり、一つは空のボリュームとして、もう一つがOSイメージをインストールするボリュームとしてGUIで入力したURLが記載されているのがわかります。 最初にVirtualMachine CRを作成するタイミングでこれらのDataVolumeも作成され一連のPVが準備されたのでした。 まとめ 今回はOCP Virt上でWindows Serverを起動し、そこへのアクセスや、OSイメージをPVとして準備する仕組みについてご紹介しました。また別の記事にてOCP Virtに関する別のトピックについて紹介していきたいと思います。
Red Hatでコンサルタントをしている織です。本記事ではibkrunについて紹介します。Red Hat Advent Calender 2023の12/3のエントリです (だいぶ過ぎてますが、空いたままだったので急遽埋めました)。 libkrunについては、inductorさんによる Kernel/VM探検隊online part2 の 講演 が有名かもしれません。本記事(および続編...を書く予定です)では、別の観点でlibkrunをご紹介できればと思います。 libkrunとは libkrun とは動的ライブラリとして提供される仮想マシンモニター(VMM)です。とても簡単に言うと、このライブラリを使うとプロセスをLinux KVMの仮想マシンとして隔離した状態で実行することができます。CのAPIを提供していますが、中の実装はほとんどRustで書かれています。Firecrackerやrust-vmmのコードも取り込んでいます。 可能な限り軽量かつシンプルな実装を目指しており、使用している仮想デバイスも最小限です。 virtio-console virtio-vsock (specialized for TSI, Transparent Socket Impersonation) virtio-fs virtio-baloon (only free-page reporting) virtio-rng virtio-block (for AMD SEV) libkrunを動かしてみる さっそく使ってみましょう。最近のFedoraだと、必要なコンポーネントは全てrpmで提供されています。以下の検証はFedora 38が稼働するノートPCで行いました。 $ sudo dnf install -y libkrun libkrun-devel libkrunfw 最小限のコードは以下のような感じになります。 #include <libkrun.h> void main() { char *const envp[] = {0}; int ctx_id = krun_create_ctx(); krun_set_vm_config(ctx_id, 1, 512); krun_set_root(ctx_id, "rootfs"); krun_set_exec(ctx_id, "/bin/bash", 0, &envp[0]); krun_start_enter(ctx_id); } minimal.c として保存し、コンパイルします。 $ gcc -o minimal miniaml.c -lkrun rootfs というディレクトリを掘って、そこにLinuxとして稼働できる最小限のファイルツリーを作ります。まずはfedoraイメージでコンテナを実行します。 $ podman run --name fedora fedora uname コンテナのファイル群をrootfs以下にコピーします。 $ mkdir rootfs $ podman export fedora | tar xf - -C rootfs また、後の実験で使ういくつかのファイルもコピーしておきます。 $ sudo cp /etc/resolv.conf ./rootfs/etc/ $ sudo cp /usr/sbin/ip ./rootfs/usr/sbin/ $ sudo cp /lib64/libbpf.so.1 ./rootfs/lib64/ $ sudo cp /lib64/libmnl.so.0 ./rootfs/lib64/ これで準備は整いました。libkrunをリンクした実行ファイル minimal を実行すると、rootfs以下のファイルを使って仮想マシンが作られ、その中でプロセスが起動します。 $ ./minimal bash-5.2# minimal.cの krun_set_exec() で呼び出したbashが起動しました。minimalの中では、Fedora 39 のコンテナイメージのファイルを使った仮想マシンが動いています。 bash-5.2# cat /etc/fedora-release Fedora release 39 (Thirty Nine) NICは何もついていません。 bash-5.2# /usr/sbin/ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever が、外と通信はできてしまいます。まずはminimalの中からインターネットにアクセスしてみます。 bash-5.2# curl ftp.jaist.ac.jp lrwxrwxrwx 1 ftp ftp 17 Feb 15 2016 debian -> pub/Linux/debian/ lrwxrwxrwx 1 ftp ftp 27 Feb 15 2016 debian-backports -> pub/Linux/debian-backports/ lrwxrwxrwx 1 ftp ftp 20 Feb 15 2016 debian-cd -> pub/Linux/debian-cd/ drwxr-xr-x 30 ftp ftp 32 May 16 2021 pub lrwxrwxrwx 1 ftp ftp 36 Feb 15 2016 raspbian -> pub/Linux/raspbian-archive/raspbian/ lrwxrwxrwx 1 ftp ftp 17 Feb 15 2016 ubuntu -> pub/Linux/ubuntu/ また、minimalを実行したKVMホストからminimalの中にアクセスしてみましょう。 まずはminimalの中で、ポート34000番でWebサーバを起動します。 bash-5.2# python3 -m http.server 34000 Serving HTTP on 0.0.0.0 port 34000 (http://0.0.0.0:34000/) ... 次に別のターミナルを開き、KVMホストから該当ポートにアクセスします。 $ curl localhost:34000 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Directory listing for /</title> </head> <body> ... libkrunが外と通信する仕組みについては、 日を改めて紹介したいと思います こちら に書きました。 Podmanのコンテナを仮想マシンで隔離して実行する 最近のFedoraでは、Podmanを実行する際のOCIランタイムとしてcrunを使用します。crunは、コンテナ実行時に run.oci.handler というアノテーションが渡されると、その情報に応じて実行するハンドラを切り替える仕組みを持っています。この仕組みを使うことで、crunはコンテナを実行する際に、dlopen(3)でlibkrun.soをロードしlibkrunの仕組みを使ってコンテナプロセスを起動します。 $ podman run -d \ -v /dev/kvm:/dev/kvm \ -p 8080:80 \ --annotation=run.oci.handler=krun \ --name nginx nginx これで、nginxのコンテナがKVM仮想マシンの中に隔離された状態で起動しました。 $ curl localhost:8080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } ... プロセスIDから見える情報を確認してみます。 $ pid=$(podman inspect nginx | jq '.[].State.Pid') $ ps -p ${pid} f PID TTY STAT TIME COMMAND 2839261 ? Ssl 0:01 [libcrun:krun] /docker-entrypoint.sh nginx -g daemon off; なんとなくlibkrunを使って実行されている感があります。 このPIDで使用しているファイルディスクリプタを確認すると、実際KVM仮想マシン内で実行されていることを確認することができます。 $ ls -l /proc/${pid}/fd | grep kvm lrwx------. 1 ori ori 64 Dec 9 01:24 19 -> anon_inode:kvm-vm lrwx------. 1 ori ori 64 Dec 9 01:29 29 -> anon_inode:kvm-vcpu:0 lrwx------. 1 ori ori 64 Dec 9 01:29 31 -> anon_inode:kvm-vcpu:1 lrwx------. 1 ori ori 64 Dec 9 01:29 33 -> anon_inode:kvm-vcpu:2 lrwx------. 1 ori ori 64 Dec 9 01:29 35 -> anon_inode:kvm-vcpu:3 lrwx------. 1 ori ori 64 Dec 9 01:29 37 -> anon_inode:kvm-vcpu:4 lrwx------. 1 ori ori 64 Dec 9 01:29 39 -> anon_inode:kvm-vcpu:5 lrwx------. 1 ori ori 64 Dec 9 01:29 41 -> anon_inode:kvm-vcpu:6 lrwx------. 1 ori ori 64 Dec 9 01:29 43 -> anon_inode:kvm-vcpu:7
こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 過去に何度かこのブログの中でOpenShift Data Scienceについて取り上げてきましたが、 直近のリリースバージョンであるv2.4から機械学習における分散学習を実現する機能がTech Previwとして追加されました。 access.redhat.com 今回はこちらの機能をデプロイしてみてどういった仕組みで分散学習を実現しているのか見ていきたいと思います。 なおTech Preview機能についての制約については こちら を参照下さい。 またプロダクトの正式名称がRed Hat OpenShift Data Science(RHODS)からRed Hat OpenShift AI(RHOAI)に変更となりました。 ドキュメントなどまだ直っていない部分もありますが今後はこちらの名称を使っていきたいと思います。 そもそもRHOAIがどういった製品なのか、等については過去のブログにまとめてあるためこちらも合わせて参照下さい。 rheb.hatenablog.com rheb.hatenablog.com rheb.hatenablog.com CodeFlare Projectについて 分散学習に関する機能は CodeFlare と呼ばれるOSSプロジェクトの中で開発が進められています。 CodeFlareプロジェクトには複数のコンポーネントで構成されます。 ・CodeFlare SDK: Code Flareの各ツールをPythonで利用するためのSDK。 ・MCAD: 学習のバッチ処理を行うためジョブのキューイングとディスパッチ。 ・InstaScale: ジョブ要求に応じてオンデマンドにクラスタにGPUノードを追加。 ・KubeRay: K8s上に分散処理を行うためのRayクラスタを構築。 以下では順番を追って、インストール方法から各コンポーネントがどのように動作するのか見ていきたいと思います。 Operatorのインストール まずOpenShiftコンソールのOperatorHubより最新のOperatorをインストールします。 CodeFlare関連の機能は最新のv2.4よりTPの対象となるため正しいバージョンをインストールできているか確認しましょう。 Operatorのインストールが完了したら必要なコンポーネントをインストールするためDataScienceCluster(DSC) CRを作成します。 Operatorのバージョンがv1.xの時はKFDef CRを作成し、インストール対象のコンポーネントを選択していましたが、v2からはこのDSCにて設定するよう変更となりました。 デフォルトの設定では .spec.components.codeflare.managementState がRemovedになっているため、画像の通りManagedに変更します。同じく .spec.components.ray.managementState についてもManagedとしましょう。 設定したDSCを作成すると必要なコンポーネントがOpenShiftにインストールされます。 Ray Clusterの定義と立ち上げ CodeFalreでは分散学習用の基盤としてOSSの Ray をOpenShift環境で立ち上げます。Rayは汎用的な分散処理を実現するOSSのフレームワークであり、複数のサーバーリソースをまとめることで、機械学習の各タスク(前処理、ハイパーパラメーターサーチ、学習、推論、等)における処理を効率化することが可能となります。 Ray自体はコンテナ環境以外でも利用することが可能ですが、 KubeRay Operator を利用することでKubernetes環境でも利用することができます。 CodeFlareを利用する場合、このKubeRay Operatorも自動でインストールされます。 まずユーザーが行うことはCodeFlare SDKを使用し、必要なRay Clusterのリソースを定義することです。 SDKについては pip install codeflare-sdk でインストールできます。 PythonスクリプトとしてRay Clusterの情報を定義し、その情報をMCADに対して送信します。 こちらのリポジトリ にCodeFlareを試すためのサンプルNotebookファイルがあります。 以下はそこから一部抜粋、改変したコードとなります。 # CodeFlare SDKのインポート from codeflare_sdk.cluster.cluster import Cluster, ClusterConfiguration from codeflare_sdk.cluster.auth import TokenAuthentication # OpenShiftへのログイン情報定義とログイン auth = TokenAuthentication( token = "SHA256...", # oc whoami -t の実行結果 server = "https://api.sample.openshiftapps.com:6443", # OpenShift APIサーバーのURL skip_tls=False ) auth.login() # Ray Clusterの定義 cluster = Cluster(ClusterConfiguration( name='raytest', namespace='default', # Ray Clusterが立ち上がるNameSpace num_workers=2, # Ray Clusterを構成するWorker Podの数 # Rayの各Workerに割り当てるリソース (CPU/Memory/GPU) min_cpus=1, max_cpus=1, min_memory=4, max_memory=4, num_gpus=0, image="quay.io/project-codeflare/ray:latest-py39-cu118", # Worker Podのイメージ instascale=False # InstaScaleの利用有無 )) # Cluster情報のMCADへの送信 cluster.up() cluster.wait_ready() # 作成されたRay Clusterの表示 cluster.details() SDKを通じてOpenShiftにログインし、clusterオブジェクトの中で必要なリソースの定義を行っています。 SDKの詳細な利用方法については以下のページを参照下さい。 project-codeflare.github.io ここからRay Clusterの立ち上げが開始します。 OpenShift内に先ほど定義したRay Clusterを立ち上げるのに十分なリソースがある場合、すぐに作成が始まりますが、そうでない場合Clusterの立ち上げリクエストはMCADの中でキューイングされた状態となります。 この時に活躍するのがCodeFlareのコンポーネントの一つであるInstaScaleです。 上記のコードの中でclusterオブジェクトの定義の中でInstaScaleを有効にすると不足するリソース分のNodeをOpenShiftクラスターに自動で追加することができます。 Ray Clusterを作成するのに必要なWorker Nodeを動的にOpenShiftに追加し、ジョブ実行が完了したら追加したNodeを自動で削除することが可能となります。オンデマンドに追加Nodeを調達できるパブリッククラウド環境で有効な機能と言えるでしょう。 RHOAIのv2.4ではInstaScaleがTPの対象機能となっていないため、ここでは概念の紹介のみに留めたいと思います。 access.redhat.com Ray Clusterが作成されると cluster.details() からUIへのアクセスが可能となります。 分散学習の実行 作成したRay Clusterの上で学習を実行するには大きく2つの方法があります。 a. CodeFlare SDKを通じてDDPJobを定義し実行する b. Rayライブラリを使用し学習を実行する 今回は一つ目のCode Flare SDKが提供する DDPJobDefinition クラスでジョブの定義を行います。 こちらのNotebookファイル からジョブの定義方法を見てみましょう。 from codeflare_sdk.job.jobs import DDPJobDefinition # ジョブの定義 jobdef = DDPJobDefinition( name="mnisttest", script="mnist.py", # 学習実行用のスクリプト scheduler_args={"requirements": "requirements.txt"} # 学習時の引数 ) # ジョブの実行 job = jobdef.submit(cluster) DDPJobDefinition の中で学習用のスクリプトであるmnist.pyと、Rayの各Worker Podで追加でインストールするライブラリをrequirements.txtとして渡しています。 これにより必要な依存関係のインストールを行なった上でジョブを実行します。 DDPJobDefinitionではTorchXが提供するDDP(Distributed Data Parallel)の仕組みを活用しており、Ray Clusterの各Worker上にデータをシャードするデータパラレルな分散学習を実現します。 pytorch.org ジョブの実行状況についてはRayのダッシュボードや、 job.status() により確認できます。 ジョブが完了したら cluster.down() にて作成したRay Clsuterを削除します。 これでCodeFalreを利用した分散学習の一連のプロセスが完了しました。 もう一つの方法であるRayの提供するライブラリを利用する方法については、 こちら を参考にしてみて下さい。 まとめ 今回はOpenShift AIでTech PreviewとなったCodeFlareによる分散学習についてご紹介しました。LLMをはじめとした大規模モデルの活用や、そのファインチューニングのニーズが増えるにつれ、こうした機能へのニーズはより高まってくると思われます。今後も機能のアップデートなど紹介していきたいと思います。
目次 目次 はじめに プラットフォーム まずはインストールするプラットフォームを選択する any platformとbaremetalの意味とちょっとした歴史的経緯 インストール方式 IPIとUPIは何が違うのか その他のインストール方式 SNO(Single Node OpenShift) Assisted Installer Agent-based installer インターネット非接続環境 インストールパターンと難易度について まとめ はじめに はじめまして、Red HatでOpenShift Container Platformのテクニカルサポートの野間です。 Red Hat Advent Calendar 2023 の12/7の記事になります。別で OpenShift Advent Calendar 2023 もありますね、どちらも楽しんでください。 OCP4.1がGAされた2019年に入社し、この製品と4年をともに過ごしました。現在ではマイナーバージョンも4.14まで更新され、あわせてインストール可能なプラットフォームやインストール方式も増えました。製品も成長したなあ、とふと 公式ドキュメントのinstallingの項目 を確認すると、、、ぶっちゃけ多すぎて読む気なくしません?同じ内容で日本語訳も読める こちらのドキュメントページ ではsingle-pageでの表示もできるのですが、インストールのページをsingle-pageで開くと、量が多すぎて私のPCのブラウザが固まります。試してみる場合は注意してください。 ソフトウェア利用の最初の一歩であるインストールがこんなに複雑ではやる気がなくなってしまいます。とうわけでユーザーが少しでも回れ右をしないように、必要な前提知識を整理してみます。 プラットフォーム まずはインストールするプラットフォームを選択する プラットフォームを決定しないことには始まらないので、まずプラットフォームを選択しましょう。4.14時点でOpenShiftはAWS、Azure、vShereなど 10のプラットフォーム をサポートしています。 インストールドキュメントが肥大化している一番の理由は、実はプラットフォーム毎に手順が存在しているためです。よく読むと、それぞれのプラットフォーム独自の手順以外は、同じ内容が記載されています。ひとつのプラットフォームを選択したら、ほかの手順は読む必要はありませんので、ドキュメントボリュームに気後れする必要はありません。 any platformとbaremetalの意味とちょっとした歴史的経緯 プラットフォームのany platformとbaremetalについて補足します。any platform(日本語ドキュメントでは「任意のプラットフォーム」)はその名前の通りプラットフォームを選ばないインストール方法です。たとえばvSphereのVMをany platform方式でインストールしたり、もしくはドキュメントに記載のないプラットフォームに使うことができます。昔はbaremetalとして記載されていたのですが、仮想環境でも使用できることから正確性のために、4.6からany platformに変更されました。以降のbaremetalは、名称のとおり物理サーバーを想定した方法になっています。そのような経緯から今も混同されていることがありますので、注意してください。 インストール方式 IPIとUPIは何が違うのか もっともスタンダードなインストール方式はIPI(Installer Provisioned Infrastructure)とUPI(User Provisioned Infrastructure)の2種類です。凄くザツに説明すると、「自動でおまかせ」モードと「イチからDIY」モードです。 IPIでは、インストーラーにinstall-config.yamlファイルを読み込ませるだけで済みます。この方法では、必要なインフラをプラットフォームの機能と連携して自動的に構成します。例えばAWSでIPIを使用すると、ノード(EC2)はもちろん、Route 53のレコード登録やネットワークも作成してくれます。インストール後も引き続きプラットフォームと連携するため、OpenShiftの機能をフル利用できる構成です。 UPIは基本的にインフラをユーザー側で用意して構成します。そのため当然ですがIPIと比べて手間や知識が必要となります。利点は、IPIでは構成できない細かいカスタマイズが可能になるという点です。そのため、基本的にはIPIで構成し、譲歩できないカスタマイズ要件が存在するユースケースではUPIを使う選択が一般的かと思います。インストールの簡単さとカスタマイズ性はトレードオフになると考えています。 その他のインストール方式 IPIとUPI以外の以下のインストール手順はドキュメントは、プラットフォームに関わらず独立した項目になっています。下記の説明とともにリンクをご覧ください。 SNO(Single Node OpenShift) 基本的には複数のノードで構成することが通常のOpenShiftですが、なんと一台でも作れてしまいます。想定されるユースケースは通信事業系のエッジコンピューティングや、導入として小さいリソースで検証するような場合です。当然ですが一台なのでHA(高可用性)機能は切り捨てられています。サポートされるプラットフォームなどに制限があるため、条件についてはドキュメントのRequirementsをご覧ください。 Assisted Installer オンプレミス環境限定となりますが、Web上で対話式で設定できる支援サービスによりインストールできます。もう一つの利点ですが、bootstrap nodeが必要ありません。そのため、オンプレミス環境で課題となりがちなbootstrap用のリソース確保が不要となります。また、前述のSNOも構成できます。 Agent-based installer Assisted Installerは素晴らしい、しかし僕らが求めているオンプレ環境はインターネットに接続しないクローズド環境なんだ、というあなたにはAgent-based installerがあります。bootstrap不要、 SNOにも対応というAssitsted Installerの利点をいかしつつも、CLIで完全ローカルに構成することができます。比較的新しいインストール方式で4.12からGAとなっており、まだまだ機能強化が予定されています。 インターネット非接続環境 Agent-basedでも少し触れましたが、インターネットに接続しない閉じられたネットワーク環境での構成、つまり「インターネット非接続環境」が求められるケースがあります。英文ドキュメントやナレッジではdisconnected network、 restricted network もしくはair-gapped networkと呼ばれることもあります。 IPIやUPIでも可能であり、各プラットフォームの項目に restricted network として別項で手順が記載されています。ただ、これだけでは手順は不足しており、事前にミラーレジストリホストを準備しておく必要があります。通常はクラスタがイメージなどのコンテンツをインターネットから取得するため、その代替をネットワーク内に構築する必要があるということです。ミラーの作成方法は幾通りかあるため ドキュメントのDisconnected installation mirroringの項目 を確認し作成してください。 インストールパターンと難易度について インストールについての一通りを説明しましたが、組み合わせることでパターンは無数に存在します。選択肢が多いことはよいことですが、インストールの難易度(手間や事前知識)に差があることも留意してください。 例えばAWSのようなクラウドプロバイダープラットフォームのIPIであればinstallerをダウンロードし、install-config.yamlを作成し実行するだけです。作業自体は慣れれば10分もかかりません。しかし、any platform方式のインターネット非接続環境となると、ユーザーがノードやネットワークおよびミラーレジストリホストを構築する必要があり、事前知識や手間が大きく異なります。あまり事例の無い組み合わせのレアなユースケースの場合は、蓄積されたナレッジも少ないため思わぬ落とし穴にはまるかもしれません。もちろん構成の選定はシステムの要件が基になるべきですが、まずは簡素な構成/方式からステップアップしていくことをおすすめいたします。 まとめ まずはサポートされているプラットフォームを選ぼう 次にインストール方式を選ぼう。簡単なのはIPI、カスタマイズしたいならUPI。その他の方式も選べるよ インストール方式で手間や事前知識は大きく異なるので、例えばインターネット非接続環境のような条件付き構成は難易度が高くなることに注意しよう
Red Hat Advent Calendar 2023 の12/6の記事です。 Red Hatの小島です。 AWS/Azure/GCPなどのパブリッククラウド上で提供している従量課金制のRHELには、Red Hat Satelliteで管理するためのサブスクリプションが含まれているため、無料でRed Hat Satelliteを利用できるようになっています。本記事では、Red Hat Satelliteでこれら従量課金制のRHELを管理するためのポイントをご紹介します。 前置き Red Hat Satelliteのサブスクリプション Red Hat Satellite利用時のポイント Extended Update Support (EUS)の利用 参考情報 前置き AWS/Azure/GCPなどのパブリッククラウド上で提供される従量課金制のRHELを利用する場合、RHELを提供している各クラウドベンダーが運用している Red Hat Update Infrastructure (RHUI) という、クラウド環境専用のRHELリポジトリを参照してRHELのパッケージのダウンロード/インストール/アップデートができるように予め設定されています。そのため、利用者は、クラウドベンダーが運用するRHUI経由でRHELパッケージを参照することが基本となります。 ただし、RHUIを利用してRHELのパッケージ管理をする場合、以下のような要件に対応するための標準機能はありません。 予めテスト済みのパッケージを利用させるための、特定の日時におけるパッケージリポジトリのスナップショット作成 グループ化されたRHELサーバーを対象とした、一括アップデート これらの要件に対応させるためには、RHELなどのパッケージリポジトリ管理やリモート実行機能を持つRed Hat Satelliteを使ったRHELの管理が効果的となります。Red Hat Satelliteを使ったRHELのアップデートの概要については、下記の記事をご参照ください。 rheb.hatenablog.com Red Hat Satelliteのサブスクリプション 従量課金制のRHELを利用する環境でRed Hat Satelliteを利用したい場合、Red Hat SatelliteのサブスクリプションをRed Hatにリクエストします。このとき、Red Hatのアカウントを持っていなければ、 Red Hatのカスタマーポータル からRed Hatアカウントを無料で作成していただき、作成いただいたRed HatアカウントにRed Hat Satelliteのサブスクリプションを紐づけることになります。 Red Hat Satellitenのサブスクリプションのリクエスト先は、 Red Hatカスタマーサービス となります。Red Hat カスタマーサービスでは、Red Hatのアカウントや請求、登録、サブスクリプション関連のお問い合わせに対応しています。 これによって、「Red Hat Satellite Infrastructure Subscription」というRed Hat Satellite専用のサブスクリプション(SKU: MCT3718)が割り当てられます。このサブスクリプションには、Red Hat Satelliteだけでなく、Red Hat Satelliteを実行するための専用のRHELサブスクリプションも含みます。このサブスクリプションを入手することで、Red Hat SatelliteをRHELにインストールして使うことができるようになるほかに、Red Hatがカスタマーポータル上で提供しているナレッジベースも見ることができるようになります。また、このサブスクリプションを利用して、Red Hat SatelliteがRed HatのCDNからRHELパッケージをダウンロードできるようにするためのマニフェストを作成します。 Red Hat Satellite利用時のポイント Red Hat Satelliteをクラウド環境で利用する場合、DHCPサービスを利用したPXEによるプロビジョニングは利用不可などの制限事項があります。こうした情報については、AWSやAzure上でのRed Hat Satelliteデプロイガイドをご参照ください。 access.redhat.com access.redhat.com Red Hat Satelliteで従量課金制のRHELを管理する場合、Simple Content Access (SCA)を有効にする必要があります。SCAはサブスクリプションの利用を簡単にするために、サブスクリプションの必要本数を管理・強制する機能が失われるオプションです。SCAによって、従量課金制のRHELサーバーに(Red Hatが発行する)RHELのサブスクリプションを都度割り当てることなく、Red Hat Satelliteで管理できるようになります。SCAは、Red Hatアカウントを新しく作るときはデフォルトで有効になっています。 昔からRed Hatアカウントを持っていて、SCAが有効になっていない場合は、 Red Hat Subscription Management から有効にできます。また、Red Hat SattelliteにRed Hatサブスクリプションをインポートして、RHELなどのパッケージをRed HatのCDNからダウンロードするために利用するマニフェストでも、 SCAはデフォルトで有効 になっています。そのため、今から従量課金制のRHELを作って、Red Hat Satelliteで管理しようとする場合、SCAの設定について特に変更する必要はありません。 SCAについては、下記のブログもご参照ください。 rheb.hatenablog.com Red Hat Satelliteが提供するRHELリポジトリだけを利用させる場合、従量課金制のRHELがRHUIを利用するための設定を削除しておきます。この設定は、各クラウドベンダーが提供するパッケージによってインストールされている場合、 yum remove コマンドで削除できます。RHUIを利用する設定に戻すときのことも考えて、これらのパッケージを予め yum download コマンドでダウンロードしておいてもいいでしょう。AWS/Azure/GCPの場合の例を記載しておきます。 AWS $ sudo yum download rh-amazon-rhui-client $ sudo yum remove rh-amazon-rhui-client Azure (XにはRHELのメジャーリリースの番号(7, 8, 9など)が入ります) $ sudo yum download rhui-azure-rhelX $ sudo yum remove rhui-azure-rhelX GCP (XにはRHELのメジャーリリースの番号(7, 8, 9など)が入ります) $ sudo yum download google-rhui-client-rhelX $ sudo yum remove google-rhui-client-rhelX また、これらのRHELをRed Hat Satelliteに登録して利用する際に、RHELのSubscription Managerによってリポジトリ設定が無効化されているため、Red Hat Satelliteのリポジトリ利用が有効にならない場合があります。このときは、 subscription-manager コマンドを利用して、リポジトリ設定を有効化します。 $ sudo subscription-manager config --rhsm.manage_repos=1 なお、Red Hat SatelliteがRed Hat CDNからダウンロードするRHELパッケージと、RHUI経由でダウンロードできるRHELパッケージは同じものです。Red Hatは パッケージブラウザのWebページ で各RHELパッケージのSHA-256を公開しているため、それらの値と sha256sum コマンドの実行結果を照らし合わせることで確認できるようになっています。 $ sha256sum XXX.rpm そのため、クラウドベンダーがRHUI経由でダウンロードできるようにしているRHELパッケージについては、Red Hat Satellite経由でダウンロードして利用したとしても、クラウドベンダーのサポートを受けることができます。Red Hat Satelliteを利用する環境でのユースケースについて、問い合わせ先は下記のようになります。 問い合わせ先が クラウドベンダー : クラウドベンダーが提供するRHELと、RHUI経由で提供しているパッケージのインストール/利用/設定 問い合わせ先が Red Hat : Red Hat Satelliteのインストール/利用/設定やRed Hat SatelliteへのRHEL登録 Extended Update Support (EUS)の利用 2023年12月時点では、AWSとAzureの従量課金制RHELには、RHEL8.8やRHEL9.2など特定のマイナーリリースにおいて EUS という延長サポートが無料で利用できるようになっています。GCPの従量課金制RHELにはEUSは付いていません。EUSを利用することで、マイナーリリース間のアップグレード頻度を下げて、アプリケーションのテスト期間を十分に取ることができるようになります。 AWSやAzureのRHEL EUSの利用方法については、下記をご参照ください。なお、AWSについては、2023年12月時点でRHEL8.6, 8.8, 9.0, 9.2のEUSが利用できるようになっています。RHEL7のEUSについてはすでに終了していますので、ご注意ください。 access.redhat.com learn.microsoft.com 一方で、従量課金制のRHELユーザーが利用できるRed Hat Satelliteのマニフェストには、RHELのEUSは含まれていません。そのため、Red Hat SatelliteがRed Hat CDNからダウンロードできないようになっています。EUSのパッケージをRed Hat Satellite上のリポジトリとして利用できるようにするには、手元にダウンロードしたEUSのパッケージをRed Hat Satelliteにインポートするといった工夫が必要になってきます。 上記のガイドに従って利用できるようにしたRHEL EUSのリポジトリについては、 reposync コマンドで丸ごとダウンロードできます。 --download-metadata オプションを指定することで、 エラータ などのメタデータもダウンロードします。下記は、RHEL9 EUSリポジトリを有効化したAWS上のRHEL9サーバーで、RHEL9 EUSのBaseOS, AppStreamリポジトリのパッケージをダウンロードする reposync コマンドの実行例です。 $ sudo reposync -p <ダウンロード先となるディレクトリのPATH> --download-metadata \ --repoid=rhel-9-baseos-eus-rhui-rpms --repoid=rhel-9-appstream-eus-rhui-rpms reposyncについては、下記のナレッジもご参照ください。 access.redhat.com これによって、「rhel-9-baseos-eus-rhui-rpms」と「rhel-9-appstream-eus-rhui-rpms」ディレクトリが作成され、その中に、EUSリポジトリに含まれるパッケージとメタデータが保存されます。これらのディレクトリをRed Hat Satelliteにインポートして、EUSのリポジトリとして作成します。この場合、Red Hat SatelliteではカスタムRPMリポジトリとして扱われます。インポートには、パッケージの手動アップロードのほかに、外部リポジトリのURLとして http(s):// と file:// を指定する方法があります。 file:// を指定する場合は、Red Hat Satelliteサーバーの /var/lib/pulp/sync_imports/ ディレクトリーの下に「rhel-9-baseos-eus-rhui-rpms」と「rhel-9-appstream-eus-rhui-rpms」ディレクトリをコピーしておく必要があります。 これらの具体的な手順については、下記をご参照ください。 access.redhat.com このようにリポジトリを作成してRed Hat Satellite上で公開し、RHELをRed Hat Satelliteに登録すると、Red Hat Satellite上で登録したRHELの情報(インストール済みのパッケージや、インストール可能な更新パッケージなど)が確認できるようになり、グループ化されたRHELサーバーへの一括アップデートのリモート実行もできるようになります。これらの具体的な手順については、「参考情報」に記載しているRed Hat Satelliteのドキュメントをご参照ください。 参考情報 access.redhat.com access.redhat.com
さてさて。今年も残るところあとわずかですね~⛄🎅 OpenShift Advent Calendar 2023 の6日目は、OpenShiftの技術営業のフリをしている北山からお届けしますー。 今年も日々の提案ナレッジをお届けっ!!と思ったのですが、今回はちょうど cdCon Japan に参加する機会を頂いたので、現地レポートをお送りします。 ところで皆様は、 Open Source Summit Japan 2023 に参加されたことはありますでしょうか?? クラウドネイティブ界隈だとCNCFのKubeConが有名どころですが、Open Source SummitもLinux Foundationによって開催されているオープンソースの国際イベントの一つです。毎年欧州や北米と合わせ、日本でも開催されている貴重なイベントで、2023年はお台場(Ariake Central Tower Hall & Conference)で行われました。実は毎年、名だたる国産SI企業様と並んでRed Hatもスポンサーしてるんですよっ!? その併設イベントとして、今年もcdCon Japanを始めとするいくつかのイベントが同じ場所で開催されました。   Hyperledger Member Summit Tokyo : エンタープライズグレードのブロックチェーン技術に関するイベント cdCon Japan : 継続的デリバリーに関するイベント OpenSSF Day Japan : オープンソースセキュリティに関するイベント Open Compliance Summit : コンプライアンスに関するイベント 今回紹介する cdCon は、Linux Foundaionの傘下にあるContinuous Delivery Foundation(CDF)によって運営されているカンファレンスです。 Continuous Delivery Foundation(CDF)のプロジェクト CDFは、継続的インテグレーションや継続的デリバリー(CI/CD)の発展に伴い、プロジェクト開発者やエンドユーザー、またベンダー間の中立的なコラボレーションを促進して、CI/CDの業界仕様を推進した団体です。 2023/12時点でCDFがホストしているオープンソースプロジェクトには、以下のものがあります。 詳細: Continuous Delivery Landscape いつの間にか増えてきましたねぇ~。これらのプロジェクトの選定は、CDFの技術概要委員会(TOC)によって採択されています。 このプロジェクトを見ると「OpenShift GitOpsでも利用されているArgoCDはないの?」と思う方もいらっしゃるかもしれませんが、 ArgoCDはCNCFに寄贈 され、2022/12にGraduated Projectとして認定されています。 このようにオープンソースプロジェクトひとつとっても、CNCFやCDFなど、どこの団体に所属するのかといった議論だけでなく、cdConとは別にArgoConやFluxConというようにプロジェクト独自のカンファレンスを行う道もあります。それぞれプロジェクトのイロがありつつも、GitOpsはContinuous Deliveryには欠かせない技術要素としてcdConのセッションにもよくでてきます。 たとえば、Red HatのKevinのセッションでは、Quarkus製のレーシングゲームが紹介され、会場みんなでArgoCDを使用したリリースを体験しました。 cdCon Japan 2023の気になったセッション さて。参加したセッションの中から気になった以下のセッションについて、簡単にメモ。 注1. 資料の利用規約を配慮し、今回は下記よりpdfを直接DLください。 注2. 本編のPipelineは「Tekton Pipelines」= CRD: Pipelinesを示します。 "Pipeline as Code" Journey Date: Monday, December 4 • 16:10 - 16:40 Presenter: Jun Makishi & Kasuki Aizawa, NTT Communication Agenda Link: https://sched.co/1TzRl Presentaion: "Pipeline as Code" Journey セッション概要 NTT Communicationさんの中で使われているTekonパイプラインを管理するために Pipeline as Code を実装されたお話です。 ここでは docomo business RINK というサービスを安定的にデプロイするための「パイプライン」を動的に提供するSREとしての取り組みを発表いただきました。 Journey 1 : Pipeline as Code the moderate way ここまでは、SREチームが標準的なPipelineを提供することを前提とした運用。 Step#0: First development flow of Pipeline as Code SRE側で標準的なPipelineを作成し、プルリクエストでの変更によってパイプラインを管理。アプリケーション側でPipelineRunを実行。 Problem: Disturbing application team’s activity ただし、Pipelineの作成が失敗するとアプリケーション側でPipelineRunが実行できずスタックしてしまう。 Step#1: Pipeline end-to-end testing そのため、パイプライン実行確認専用のパイプラインテスト環境を作成。 Problem: Firefighting pipeline troubles 異なるアプリケーションでは異なるパイプライン構築が必要であり、個別カスタマイズを要求されるとPipeline開発者に依存してしまう。 Step#2: Scaled pipeline with standardization パイプライン作成のスタンダード化やオンボーディングを各チームで実施。チームビルディングによって対応。 Journey 2: Pipeline as Code the hard way ここからは、SREチームがPipeline Template生成ツール管理し、各アプリケーションチーム側でPipelineを生成する運用。 Problem: One-size-fill-all Pipeline すべてのアプリケーションチームが標準Pipelineに異なるパラメーターを入れると、パラメーターが多すぎる Step#3: Composable pipeline テンプレートとして CUE Lang を使い、Pipelineそのものを生成できる「Composable pipeline」の仕組みを構築 Pipeline generation at glance 「Composable pipeline」の仕組みによって、Pipeline生成の役割はアプリケーションチーム側に移譲。 アプリケーションチームは必要なタスクを選ぶだけで、それに応じたPipelineを生成できる。 Implementing packages with tests SREチームは「Composable pipeline」の仕組みをテストするために、期待するマニフェストと、CUEによって生成されたマニフェストを比較してテスト。 Problem: unstable packages 一つの環境でテストしていたため、異なるKubernetesバージョンやクラウドAPIによるテストカバレッジが少なかった。 Step#4: Pipeline package testing Golangによるテストツールを作成し、異なるKubernetes APIのテストができる用にテストカバレッジを増強。 Demo 最後にDEMOの実施。近日Demoコードを公開予定!! Conclusion CUE Langだとメンテナンスできる人も限られるため、今後はCUEではなくYAMLで対応できるように検討。TektonもカスタムOperatorで拡張していくことを検討。 My impressions "Pipeline as Code"という概念は知っていたものの、実際にTekton Pipelinesを使ってプロジェクトを回している話は初めてだったので、個人的に色々学ぶことができました。またマニフェスト生成方法に関しても、普段はKustomizeやHelm Chartに慣れてしまっていましたが、CUE Langを使っていたのが興味深かったです。 すでに「Composable pipeline」の仕組みである、Adaptersが以下に公開されていたので、ソースコードをいくつかのぞいて見てました。(あくまで見たただけで、すいませんwww) いくつかのAdapters(Task生成用かな?)からPipelineの中でやりたいTaskを選んで、CUEでコンパイルをすればPipelineが生成されるのかな?と妄想。 https://github.com/qmonus/official-cloud-native-adapters/tree/main/docs/cicd 例: official-cloud-native-adapters/pipeline/scan/trivyGcp.cue package trivyGcp import ( "strings" "qmonus.net/adapter/official/pipeline:utils" "qmonus.net/adapter/official/pipeline/tasks:trivyImageScanGcp" ) DesignPattern: { name: "imageScan:trivyGcp" pipelineParameters: { image: string | *"" shouldNotify: bool | *false } let _imageName = strings.ToLower(pipelineParameters.image) _scanTask: string if pipelineParameters.image != "" { _scanTask: { utils.#concatkebab input: [_imageName, "image-scan-gcp"] }.out } if pipelineParameters.image == "" { _scanTask: "image-scan-gcp" } … 社内ツールだけではもったいないと思ってしまうほどちゃんとドキュメント化もされていたので、SREのオンボーディングの取り組みが素晴らしいなぁと思った次第です。 Tektonの中にも Pipeline as Code の仕組みがありTektonHubからPipelines生成ができるので、今後はこうしたツールに置き換わるのかなー。とも期待。 cdCon含め、それぞれの業界標準や規則、ガバナンスを確認するCI/CDパイプラインが整ってくると、日本のExcel $ 目grep 文化も減るのにな~。と改めて感じたところでした。 おしまい。 さいごに 色々宣伝を。。。 Pipelines with Tekton 今回紹介したTektonのスキルテストが開始されました。是非CDFでもGraduatedプロジェクト認定されている「Tekton」をこれから使っていく方は是非挑戦してみてください。 https://cd.foundation/blog/2023/12/03/new-skillcred-pipelines-with-tekton/ CNCF Annual Survey 毎年CNCFから提供されるAnnual Surveyですが、日本の回答率が毎年そんなに多くないようです。是非この機会に回答を~。 https://www.research.net/r/S5BY23R Kubernetesマイクロサービス開発の実践 なんとなんと、LINEヤフー株式会社 黒帯の早川さんが執筆した書籍が2023/12/19に発売されます🎉🎉🎉 既存アプリを、Kubernetesにリフトしていくぞ!!という方向けのノウハウがギッシリ詰まった必読図書です。 https://amzn.asia/d/9vD3LGe Kubernetes CI/CDパイプラインの実装 Tekton & Argo の使い方や仕組みを執筆しました!! なお、だいぶまえ(藁 是非Tekton & Argo(GitOps)の勉強などにご活用ください!! https://www.amazon.co.jp/dp/4295012750 Re: おしまい。
OpenShift Ingress Controllerの負荷分散について 目次 OpenShift Ingress Controllerの負荷分散について 目次 はじめに OpenShift Ingress Controllerとは デフォルトの負荷分散 The Power of Two Choices in Load Balancing の要約 負荷分散のベストプラクティス まとめ 参考文献 はじめに OpenShift Advent Calendar 2023 の記事です。 OpenShift や Kubernetes を利用して Web サービスを構築する場合、デプロイした Pod は OpenShift Cluster の外部からアクセスできるようにする必要があります。Cluster の外部からアクセスできるようにする方法は Node Port などいくつか用意されていますが、HTTP や HTTPS、WebSocket を利用してアクセス可能な Web サービスをデプロイする場合、OpenShift では Ingress Controller が候補として上がりやすいのではないでしょうか。また、Web サービスを提供する Pod は 1 台ではなく、可用性や性能要件を考慮して 2 台以上で構成されることが一般的です。 このとき、 Ingress Controller では複数の Pod に対して用意されたいくつかの分散方式に従ってリクエストを分散します。本記事では、OpenShift Ingerss Controller のデフォルトの負荷分散の方式について振る舞いについてみていきます。 OpenShift Ingress Controllerとは OpenShift Container Platformクラスタを作成する際、Cluster 上で実行される Pod および Service はそれぞれ独自のIPアドレスが割り当てられます。これらのIPアドレスは、OpenShift Cluster 上で実行されている他の Pod や Service からアクセス可能ですが、Cluster 外部のクライアントからはアクセスできません。Ingress OperatorはIngressController APIを実装し、OpenShift Container Platform Cluster の Service への外部アクセスを可能にする責任を担うコンポーネントです。 Ingress Operatorは、外部クライアントが Service にアクセスできるようにし、ルーティングを処理する1つまたは複数の HAProxy ベースの Ingress Controller をデプロイおよび管理することを実現します。 Ingress Operatorを使用して、OpenShift Container Platformの Route および Kubernetes の Ingress リソースを指定してトラフィックをルーティングできます。 Ingress Controller 内の設定、たとえば endpointPublishingStrategy タイプの定義や内部負荷分散の可能性など、Ingress Controller エンドポイントを公開する方法が提供されます。 デフォルトの負荷分散 ここで本題です。OpenShift では定義する Route 毎に荷分散の方式を Annotation haproxy.router.openshift.io/balance で指定することができます。デフォルトは random *1 です。バックエンドの Pod の状況をみて負荷分散をしたいと考えるケースでは、このランダムというデフォルトは少し微妙に感じるかもしれません。 少し古い記事ですが、HAProxy の random のアルゴリズムについて HAproxy のブログ記事として掲載されています。 www.haproxy.com この記事では HAProxy の random のアルゴリズムはバックエンドのサーバーからランダムに選んだ2つのバックエンドのうち、コネクション数が最小のものを選択するという振る舞いをすると記載しています。これはどういうことでしょうか。記事の要約を次に記載していきます。 The Power of Two Choices in Load Balancing の要約 ブログ記事では HAProxy で利用可能な Power of Two Random Choices (以下、Power of Two) というアルゴリズムについて記載しています。Power of Two は 2つのランダムなサーバーを選び、最もアクティブな接続が少ないサーバーを選択することで、各リクエストにどのサーバーが応答するかを決定する方法を採用しています。このアルゴリズムの特徴を示すため、HAProxy で利用可能な負荷分散アルゴリズムと比較しどのような結果がもたらされるかを示しす検証結果を掲載しています。 対象となっているのは以下の4つのアルゴリズムです。 - Round Robin - Least Connections - Random - Power of Two 検証をするにあたり、コンディションを以下のように変更しています。 外部からの負荷がなく、CPUも専有して利用できる状態 アプリケーションが CPU を共有できる状態 アプリケーションが CPU を共有できる状態でかつ、他からもCPUが奪われるような状態 結論として、今回の測定状況では、Round Robin は芳しくない成績となり、一方で Least Connections がベストで次に Power of Two が状況に左右されず良い結果をもたらしてます。Random は結果が安定せず測定毎に大きく結果にばらつきが出ています。 しかしながら、複数の Load Balancer が存在する場合、Least Connections は分散先のサーバーへの負荷に他のLoad Balancer で負荷分散されようとしているアクセスは考慮されないため、期待しない結果となるケースが存在するとまとめています。 負荷分散のベストプラクティス OpenShift に話を戻すと、デフォルトの構成において、Ingress Controller は 2 つの Pod から構成されます。また、Ingress Controller の前段にはロードバランサーが存在します。すべてのケースについてではありませんが、HAProxy のブログの検証結果を考慮すると、Power of Two (HAProxy でいう random) が良い結果をもたらす可能性が高いと言えるのではないでしょうか。 まとめ OpenShift では Route を定義すると Ingress Controller (HAProxy) の負荷分散アルゴリズムとして Random がデフォルトで設定されます。HAProxy の Random はランダムに選んだ2つの Pod から最もアクティブな接続が少ない方を選択する方式でした。これによる検証結果は状況に左右されにくいことと、HAProxy が複数台になる場合つまり、Ingress Controller の Pod が 2 台以上の場合に期待した結果が得られそうであることがわかりました。 そのため、OpenShift Ingress Controller のデフォルトの負荷分散アルゴリズム Random は微妙な選択肢ではなく、適切な負荷分散を実現できる選択であることがわかりました。 参考文献 docs.openshift.com docs.openshift.com www.haproxy.com *1 : OpenShift 4.14 現在
Cloud製品を担当しているソリューションアーキテクトの輿水です。 OpenShift Advent Calendar 2023 の12/3の記事です。昨年も紹介したのですが、今年も紹介します。たぶん濃い内容のエントリーが続いてると思うので、箸休め的にお読みください。 All learning | Red Hat Developer というサイトにハンズオン(英語)があり、その一部を日本語に翻訳して、自己学習型OpenShiftハンズオン環境として提供し始めましたと昨年記事を書きました。1年経過した現在では、翻訳分に加え独自に作成したコースも増えております。 自己学習型OpenShiftハンズオンを行うために、ご用意いただくのはブラウザ(Firefox,Chrome)のみです。指定のURLにアクセスしコースをlaunchすると、環境がデプロイされて、演習内容と操作用ターミナルがセットされた環境が使用可能になります。コースをlaunchするために何かしらのアカウントを作る必要はありません。このハンズオンの長所と短所は以下の通りで、 Developer Sandbox for Red Hat OpenShift のように同じ環境を長期間継続して使えるものではなく、単発のものです。しかしながら、何度でも使えるので1回目はただただコピペで進む、2回目はコマンドの意味を考えつつ実行するなど、繰り返し学習することができます。 長所 ブラウザ(Firefox,Chrome)があれば試せます アカウント作成不要です コマンドはコピー&ペースト可能です cluster-admin権限あり 何度でも実施可能です、回数制限等はありません 短所 都度環境をデプロイするので、環境が準備されるまで10〜30分程度待つ必要があります 環境は一定時間(殆どの場合60分)が経過すると自動的に削除されます 削除された後、再度デプロイしても、それまでに行った操作は保存されません(新しい環境になります) 学習コースの内容は、基本的にまだ殆どOpenShiftを触ったことがない初学者向けで、OpenShiftの基本的な操作を手順通りに実行して、理解を深めてゆく内容になっています。 現在用意されている各ハンズオンへのリンクは下記のgithubにあります。 昨年とgithubのレポジトリが変わりまして、今後はこちらが正となります。 OpenShiftハンズオンへようこそ github.com それではコースの紹介を。 OpenShiftを初めて触る人向けコース OpenShiftを初めて触る方には以下の4コースがおすすめです。まずこの4コースを学習してから他のコースを試してみることをオススメします。 OpenShiftクラスタにOpenShift Command Line Tool(ocコマンド)とWebコンソールでログインするところから始め、CLIやGUIでのプロジェクトの作成、既存イメージやGithubにあるソースを利用してアプリケーションをデプロイする方法を学びます。デプロイされたアプリケーションの外部公開を行ってインターネット経由でアプリケーションにアクセスします。永続ボリュームを使用するようにデプロイメントを変更し、OpenShiftにおける永続ボリューム(Persistent Volume)の動作について確認します。また、アプリケーションをデプロイする過程で、様々なリソースが作成されるので、リソースの操作方法を学びます。 Deploying Applications From Images (Japanese) 概要:イメージを利用してアプリケーションをデプロイします コマンドラインインターフェースを使用してログインし、ocコマンドで新しプロジェクトを作成します Webコンソールでログインしてquay.ioにあるイメージを使ってアプリケーションをデプロイします Webコンソールでアプリケーションをスケーリングします ocコマンドでselectorを利用して特定のラベルを持つリソースを表示します ocコマンドでリソースの詳細を表示します ocコマンドで再度アプリケーションをイメージからデプロイします Deploying Applications From Source (Japanese) 概要:ソースからアプリケーションをビルドしてデプロイします コマンドラインインターフェースを使用してログインし、ocコマンドで新しプロジェクトを作成します Webコンソールでログインして、ソースコードをs2iを利用してビルドし、アプリケーションをデプロイします Webコンソールで、アプリケーションのビルドのログを確認します 既に実行されているアプリケーションをocコマンドでリビルドします OpenShift Persistent Volume (Japanese) 概要:OpenShiftの永続ボリュームについて学習します ocコマンドで新規プロジェクトを作成し、アプリケーションをデプロイします アプリケーションが永続ストレージを利用するよう設定します Persistent Volume Clame と Persistent Volumeについて理解します 永続ボリュームの動作を確認します Manage Resource Objects (Japanese) 概要:OpenShiftの様々なリソースオブジェクトについて理解します 様々なリソースオブジェクトを表示します リソースオブジェクトについて詳細な説明を表示します oc editコマンドでリソースオブジェクトを編集します oc createでリソースオブジェクトを作成します oc replaceとoc patchコマンドについて学びます oc labelコマンドでラベルを設定します リソースオブジェクトを削除します その他、 Getting Started と銘打った、ArgoCDやTektonを使ってみるコースも準備しておりますので、お手軽にご利用下さい。 Login to an OpenShift cluster (Japanese) (OpenShiftクラスター上でのユーザー切り替え) 概要: ユーザーの切り替えやロール設定を行います Transferring Files in and out of Containers (Japanese) (コンテナとローカルマシン間のファイルのコピー) 概要: 実行中のコンテナとローカルマシンの間でファイルをコピーします Getting Started with ArgoCD and OpenShift GitOps Operator (Japanese) (ArgoCDを使ってみよう) 概要: ArgoCDを利用してOpenShiftのGitOpsを体験します Working with Kustomize (Japanese) 概要: ArgoCDを利用してKustomizeを利用してアプリケーションをデプロイします Working with Helm (Japanese) 概要: Argo CDを利用してHelmチャートをデプロイします Getting Started with OpenShift Pipelines (Japanese) (Tektonを使ってみよう) 概要: OpenShift Pipelines を使用してアプリケーションのデプロイを自動化する方法を学習します Getting Started with OpenShift Serverless (Japanese) 概要: クラウドネィティブな開発モデルを提供する OpenShift Serverless の使用方法の基本を学習します その他の諸々コース OpenShift Logging (Japanese) 現在、OpenShiftではLokiおよびVectorの使用が標準となっています。このコースは従来のElasticSeach、Fluentd、Kibanaを使用する内容ですが、ログ集約の動作を体験するということで提供しています。Fluentdがノードとコンテナのログを収集しElasticSeachに書き込み、Kibanaが視覚化します。管理者権限のあるクラスタを使ってのハンズオンですので、管理者としてOperatorのインストールから実施します。なお、この環境ではモニタリング機能はOFFになっているため、モニタリングは実施できません。 概要:OpenShiftのログ集約機能を体験します ロギングの対象となるアプリケーションをデプロイします Elasticsearch Operatorをインストールします Cluster Logging Operatorをインストールします Logging CustomResourceを作成します kibanaを利用してログを表示します Red Hat Service Interconnectを使ったネットワーク構築 他とはちょっと異なるハンズオンで、今年の夏にGAとなりました、L7アドレッシングとルーティングにより異なる環境間でのアプリケーションとサービスの接続を可能にするRed Hat Service Interconnectという製品について体験いただけるコースです。Red Hat Service InterconnectはOSSのskupperに基づいています。 シナリオは、パブリッククラウドのOpenShiftクラスタ上で動作するウェブフロントエンドサービスと、プライベートデータセンターのOpenShiftクラスタ上で動作するPostgreSQLデータベースと決済処理サービスがあり、この間を接続してウェブフロントエンドサービスがPostgreSQLデータベースと決済処理サービスを使えるようにする、という内容です。Red Hat Service Interconnectを使うと「skupperのデプロイ(ルータのイニシャライズ)」「token作成」「tokenを使ってのリンク作成」「公開したいサービスのexpose」のわずか4ステップで実現可能です。 お試し環境を用意するのが面倒そうですが、このハンズオンなら即、体験できます。 このように、地味にコンテンツが増えたりしますので、冒頭に記載したGitHubでたまに確認いただけると幸いです。 お知らせ 12月11日〜12日に開催される CloudNative Days のプレイベントとして、ハンズオンWeekが開催されます。その一貫で、上記の自己学習型ハンズオン環境を使ったハンズオンを下記日程で実施します。通常時は、環境のデプロイに20分くらいかかるのですが、このもくもく会では、環境をあらかじめ作成しておき即起動するように準備しておりますので、ストレスなくハンズオンを始められます。この機会に是非ともご参加ください。 ▼CNDTスペシャル - OpenShift超基礎編ハンズオンもくもく会 openshift.connpass.com ▼CNDTスペシャル - Red Hat Device Edgeで俺だけの最強のOSイメージを構築! openshift.connpass.com それでは、ちょっと早いですが、みなさま良いXmasを!
Red Hatでソリューションアーキテクトをしている田中司恩( @tnk4on )です。 本記事は Red Hat Advent Calendar 2023 の2日目の記事です。 早いものでもう12月ですが、個人的には今年はPodmanづくしの年でした。 この記事を書いている時点で実はまだPodman祭りの最中で、これから Podmanウェビナー とPodmanハンズオン2回があります。 その合間に息抜きがてらアドベントカレンダーへの参加で記事を書きました。 もちろんPodmanネタですが、今回はWindowsユーザー待望のHyper-Vを使ってPodman machineを実行する方法を解説します。 追記(2024/4/16): containers.conf を使った設定方法を追記しました -目次- Windows上のPodman machine Hyper-Vを使ったPodman machineの実行 Podmanのインストール Hyper-V機能の有効化 Podman machineの作成と実行 Hyper-V版Podman machineのポートフォワード Tips まとめ [宣伝] Podmanの技術書 Podman Advanced Pod-01:DockerからPodmanへの移行 Windows上のPodman machine WindowsのPodman machineのアーキテクチャー Linux以外のOS(WindowsとmacOS)上でPodmanを実行するには仮想マシンを使う必要があります。 Podmanではこれを Podman machine と言う機能で実現しています。 LinuxでもPodman machineを使用できますが、ほとんどの場合はLinuxの実行環境を持たないWindowsとmacOS向けです。 Windows版PodmanではこれまではWSL2のみがPodman machineの実行環境として提供されていました。 Podman v4.8.0 からはHyper-Vが新しい実行環境として追加されました。 Windows版Podman machineのアーキテクチャーを比較すると、WSL2とHyper-VではPodman machineの実行元ホストOSが異なります。 WSL2ではWindowsの機能として組み込まれた WSL2-Linux-Kernel を用いてWindows上で仮想マシンなどの管理オーバーヘッド無しにLinuxのコマンドを透過的に実行できます。 対して、Podman machineのデフォルト実行OSであるFedora CoreOSは完全に独立したOSとしての実行が前提で、それは Ignition を用いた初期構成を行う必要があるためです。 そのためWSL2版Podman machineはFedora CoreOSではなく通常のFedoraをホストOSとして採用していました。 これにはデメリットがあり、OSが通常版のFedoraのため長期的な運用をする場合には一般的な仮想マシン運用と同様にOSのアップデートなどを手動で行う必要があります。 また、WSL2版のPodman machineを構成方法も既存のLinuxの知見で十分実現ができたとしても *1 、Fedora CoreOSのIgnitionを使ったコードによる構成管理の方がスマートです。 Hyper-V版の登場によりようやく本来の形式のPodman machineがWindows上で実行できるようになりました。次項ではHyper-Vを使ったPodman machineの実行方法を解説します。 Hyper-Vを使ったPodman machineの実行 まず、前提条件としてHyper-Vを実行できるWindows環境が必要です。Windows Homeエディションは対象外となります。Podmanは最新のv4.8.0以上をご利用ください。 作業手順は下記の通りです。 Podman CLIのインストール Hyper-V機能の有効化 Podman machineの作成と実行   Podmanのインストール Windows版Podmanのインストーラーは Podmanの公式サイト またはPodmanのGitHubリポジトリの リリースページ から入手してください。 Podman CLIを公式サイトからダウンロードする Podman CLIのインストーラーを実行してウィザードを進めます。 Podman CLIのインストール Podman CLIのインストール進捗 ウィザードが完了すると再起動を求められるのでOSを再起動します。 インストール完了後に再起動を実行する OS起動後、自動的にPodman CLIインストーラーの画面が立ち上がるので画面を閉じてインストールは完了です。 インストールの完了 Hyper-V機能の有効化 「スタートメニュー>コントロールパネル>Windowsの機能の有効化または無効化」 を開きます 「Hyper-V」にチェックを入れOKを押します。 Hyper-V機能の有効化 有効化が完了したらOSを再起動します。 機能の有効化後、再起動を実行する Podman machineの作成と実行 ここからはWindowsターミナルで作業を行います(コマンドプロンプトでも構いません)。 Windowsターミナルを実行するときは必ず 管理者モード で起動してください。 podman info コマンドを実行すると provider がデフォルトで wsl になっていることが確認できます。また、Podman CLIのインストール直後にPodmanコマンドを実行するとまだPodman machine(実行エンジン)が起動していないため接続エラーが表示されます。 PS C:\Users\user> podman info OS: windows/amd64 provider: wsl version: 4.8.0 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: Get "http://d/v4.8.0/libpod/_ping": dial unix /run/podman/podman.sock: connect: A socket operation encountered a dead network. 次にHyper-V版のPodman machineをインストールするための事前設定を行います。 CONTAINERS_MACHINE_PROVIDER 環境変数に hyperv をセットします。再度 podman info コマンドを実行すると provider が hyperv に変更されたことが確認できます。この状態でPodman machineの作成を実行します。 PS C:\Users\user> $env:CONTAINERS_MACHINE_PROVIDER="hyperv" PS C:\Users\user> podman info OS: windows/amd64 provider: hyperv version: 4.8.0 ... (参考)コマンドプロンプトの場合の環境変数のセット方法は下記の通りです。 >set CONTAINERS_MACHINE_PROVIDER=hyperv 環境変数を使用せず、設定を固定化したい場合は containers.conf に記載します。 containers.conf の作成場所は %APPDATA%\containers\containers.conf になります。 下記の内容を追記してください。 [machine] provider="hyperv" Podman machineの作成は podman machine init コマンドを実行します。 この処理の中で、Hyper-V向けのFedora CoreOSイメージのダウンロード、展開、初期設定が自動で行われます。初回実行時はインターネットからイメージをダウンロードするので環境によっては時間がかかります。2回目以降はローカルにキャッシュされたイメージがあれば再利用します。 PS C:\Users\user> podman machine init Machine init complete To start your machine run: podman machine start PS C:\Users\user> Podman machineの作成が完了したらPodman machineの起動を行います。 podman machine start コマンドを実行します。 PS C:\Users\user> podman machine start Starting machine "podman-machine-default" Machine "podman-machine-default" started successfully Podmanの初回起動時にWindowsセキュリティのポップアップが表示されるのでこれを許可します。 Windowsセキュリティのポップアップを許可する ここからはPodmanコマンドが自由に実行できるようになります。 podman version コマンドの実行結果はこちら。 PS C:\Users\user> podman version Client: Podman Engine Version: 4.8.0 API Version: 4.8.0 Go Version: go1.20.5 Git Commit: c4dfcf14874479e34b3f312f089fc5840e306258 Built: Tue Nov 28 03:37:20 2023 OS/Arch: windows/amd64 Server: Podman Engine Version: 4.7.2 API Version: 4.7.2 Go Version: go1.21.1 Built: Tue Oct 31 23:32:01 2023 OS/Arch: linux/amd64 Podman hello worldの実行 PS C:\Users\user> podman run --rm quay.io/podman/hello Trying to pull quay.io/podman/hello:latest... Getting image source signatures Copying blob sha256:d08b40be68780d583e8c127f10228743e3e1beb520f987c0e32f4ef0c0ce8020 Copying config sha256:e2b3db5d4fdf670b56dd7138d53b5974f2893a965f7d37486fbb9fcbf5e91d9d Writing manifest to image destination !... Hello Podman World ...! .--"--. / - - \ / (O) (O) \ ~~~| -=(,Y,)=- | .---. /` \ |~~ ~/ o o \~~~~.----. ~~ | =(X)= |~ / (O (O) \ ~~~~~~~ ~| =(Y_)=- | ~~~~ ~~~| U |~~ Project: https://github.com/containers/podman Website: https://podman.io Documents: https://docs.podman.io Twitter: @Podman_io Podman machineの作成後はHyper-Vマネージャー上で仮想マシンの状態が確認できます。 「Windowsツール > Hyer-Vマネージャー」を実行します。 Hyper-Vマネージャーの実行 Hyper-V版Podman machineのポートフォワード コンテナでポート公開を行うとPodman machineが自動でポートフォワードの設定を行いコンテナと通信ができます。この時、内部では gvproxy コマンドが自動的にポートフォワードを行います。 PS C:\Users\user> podman run -d --name nginx -p 8080:80 docker.io/library/nginx Trying to pull docker.io/library/nginx:latest... Getting image source signatures Copying blob ... b4c66afa83782df8ea85bcd8631fc7e81e37721dfba97ff1a6e7382d9476885a PS C:\Users\user> PS C:\Users\user> curl http://localhost:8080 StatusCode : 200 StatusDescription : OK Content : <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ... ポート公開の初回実行時は gvproxy に対してWindowsセキュリティのポップアップが表示されるのでこれを許可します。 `gvproxy`のWindowsセキュリティのポップアップを許可する gvproxy を使ったポートフォワードのアーキテクチャーは下記の通りになります。 Hyper-V版Podman machineのポートフォワードのアーキテクチャー なお、Podman v4.7.0でWindows向けのポートフォワード機能の修正が行われ、WSL2では gvproxy の代わりに wslrelay が使われるようになりました。 *2 Tips Hyper-V版のPodman machineを使う上でのポイントをいくつかまとめました。 Podman machineの作成時は必ずターミナルを管理者モードで起動する 一般ユーザーで実行した場合は正常にPodman machineの作成が行えません Podman machineの起動は podman machine start コマンドを使用する Hyper-Vマネージャー上で起動した場合は正常にPodman machineが使用できません 停止はHyper-Vマネージャーで行っても問題ありません Podman machineの初回起動後は仮想スイッチの変更は可能ですが、非推奨 仮想スイッチを外部公開に切り替えるとポート公開を使用する時にgvproxyが正常に作動せず、コンテナが起動できません 仮想マシンにホストネットワークと同じIPアドレスをアサインしたい要望がある場合は、Podman machineを使わずにFedoraなどを使う方が良いでしょう コンシューマー向けのHyper-VではGPUパススルーが使えない PodmanでGPUを使う用途がある場合はWSL2版を使いましょう まとめ Podman v4.8.0からHyper-V上でPodman machineを使うことができます。 CONTAINERS_MACHINE_PROVIDER を hyperv にセットして podman machine init を行うことでHyper-Vをバックエンドに使ったPodman machineが作成されます Podman machineの起動後はWSL2版と同様にPodmanコマンドの実行やポートフォワードが使用できます。 実際に使うユーザー目線ではPodmanを実行するバックエンドの技術はWSL2でもHyper-Vでもどちらでも構わないといったところですが、使用目的に応じて選択肢が増えたのでこれからも色々試してみてそれぞれの利点を深掘りしていこうと思います。 [宣伝] Podmanの技術書 Podman Advanced Pod-01:DockerからPodmanへの移行 Podmanの技術書を書いて個人出版しました。Amazon Kindleストアと技術書典で電子書籍として購入できます。 Podman Advanced Pod-01:DockerからPodmanへの移行 https://www.amazon.co.jp/dp/B0CP8Y54CB Podmanイン・アクションには書いていないDockerからの移行方法やPodman machine、Podman Desktopの詳細な解説をしています。Podmanイン・アクションの次の一冊としてご活用ください。 *1 : https://github.com/containers/podman/blob/main/pkg/machine/wsl/machine.go *2 : Implement automatic port reassignment on Windows by n1hility · Pull Request #19557 · containers/podman https://github.com/containers/podman/pull/19557
※この記事は OpenShift Advent Calendar 2023 の 2日目の記事です。 qiita.com こんにちは。レッドハットでクラウドインフラを生業にしている宇都宮(うつぼ)です。 なんだか久しぶりな感じがしますが、今回は Red Hat OpenShift Container Platform(OCP)の設計的な話をします。 OCP のノード構成と言えば Control Plane(いわゆる Master)x 3台 Worker x 2台以上 Infra x 2台以上 と3種類のノードを分けるのが標準です。 しかしこんなにマシンを用意したくないぜというケースもあります。そんなあなたに紹介する3ノードクラスタです。 3ノードクラスタの特徴 3ノードクラスタについては、結構前に試された記事があります。が、それ以来あまり触れられていません。ですのでベタベタ触れていきます。 参考: https://rheb.hatenablog.com/entry/openshift42-3node-baremetal 3ノードクラスタは、Control Plane と Worker と Infra で分かれて動くものを1台に全部突っ込んだノード 3 台で構成するクラスタです。 これによってマシンの数を減らすことができ、 マシンの管理が楽になる IP アドレスリソースを節約できる インストールが早い、アップデートも早い インストール後にクラスタサービス(Router や Monitoring など)を Infra ノードに移動させる必要がない といったメリットが得られます。個人的にはクラスタサービスを Infra ノードに移動させる手間が無いのは嬉しいと感じます。 事前検証や PoT/PoC などでちょっと OpenShift 試したいという場合にぴったりですし、本番用途でも全く問題なく使えます。 3ノードクラスタの注意点 一方でもちろん注意すべきデメリットもあります。 マシン1台あたりの CPU/Memory リソースは増える Control Plane と Worker と Infra の全部が1つになるのですから、各々必要な CPU/RAM リソースも積算しなくてはなりません。これによってマシンに求められるリソースは大きくなります。 特に、標準的な構成では Infra ノードで動いていた Logging や Monitoring、OpenShift Data Foundation のような CPU/Memory intensive なコンポーネントも、3ノードクラスタだとコミコミになるので、結構リソースが必要になってきます。 マシン障害時のインパクトは大きい これは宿命みたいなものですが、みんな3台に同舟しているので、1台ズドンと落ちると Control Plane のコンポーネントもユーザーアプリケーションもクラスタサービスも、みんな影響を受けます。 1台落ちたくらいで OpenShift のサービスが止まるわけではないですが、多少の degradation は発生し得ます。ものによっては残ったノードに再スケジュールするような動きも走るので、あらかじめノードのリソースは余裕を持たせておくよう注意しましょう。 サブスクリプション費用 ここはエンジニアブログですが、私はプリセールスなので費用的な話もしておきます。 ご存知の方も少なくないと思いますが、基本的に OCP のサブスクリプションは、Worker ノードが持つ CPU コアの数を対象にチャージすると言われます。 ここで言う Worker ノードとは、 "ユーザアプリケーションが稼働するノード" ということです。したがって、3ノードクラスタでは、3ノード全てがチャージ対象となります。 それでは 3ノードクラスタの場合、Control Plane や Infra コンポーネントが使う分の CPU コアはチャージ対象外になるのでしょうか? 答えは NO です。どのコンポーネントがどれだけ CPU を使うかは関係なく、 あくまでマシンが持つ CPU コアで決めます。 これらを踏まえると、3ノードクラスタはサブスクリプション的には損に思えます。サブスクリプションではマシンが持つ CPU 全体がチャージされるのに、ユーザアプリケーションが使えるのは、Control Plane や Infra コンポーネントで使われる分を除いた分だからです。 この認識は正しく、基本的に Worker ノードと Control Plane または Infra を同舟させるのは、サブスクリプションとしては損をします。基本的には。 しかし例外があり、それがベアメタル OCP の場合です。 ベアメタル OCP 向けサブスクリプションはお得 ベアメタル OCP とは、仮想マシンではなく物理サーバに直接 OCP をインストールしたクラスタのことです。 OCP のサブスクリプションは基本的に CPU コア課金ですが、ベアメタル OCP の場合のみ適用できるソケット課金のサブスクリプションもあります。 これは、 1 台の物理サーバがもつ CPU 合計 2 ソケットまで、かつ合計 64 コア(x86_64 では 128 スレッド)まで 適用できるサブスクリプションです。 例えば 2 ソケット / 48コアのマシンを使う場合を考えます。 コア課金のサブスクリプションは 2コア単位で販売しているので、 48 コア分購入するには、24個のサブスクリプションをオーダーすることになります。これは結構な金額になります。 しかしソケット課金のサブスクリプションの場合は、1個で済みます。 いやいやソケット課金のサブスクリプションは単価が高いんでしょ?と思われるでしょう。確かにコア課金のものよりも単価は高いです。が、全体を積み重ねるとかなり得になっています。 大人の事情で詳しくは書けないのですが、1ノードあたり 16 コア前後がコア課金とソケット課金の分岐点、とだけ言っておきます。 なお、仮想マシンの OCP の場合はソケット課金は使えず、基本のコア課金となりますので、標準構成の方がサブスクリプション的にはお得になります。 OpenShift のサブスクリプションについては、こちらのサイトに細かく記載されています。 www.redhat.com 3ノードクラスタはベアメタルで、ベアメタルは 3 ノードクラスタで 前述の通り、3ノードクラスタではマシン1台あたりの CPU/Memory リソースは増えます。どれだけユーザアプリケーションを動かすか、どれだけ Infra コンポーネントを動かすかで変わりますが、4コアや8コアで済むケースは多くないでしょう。 積み重ねた結果、上記の分岐点を超えるようであれば、ベアメタル OCP は有力な選択肢になります。 反対に、ベアメタル OCP を作ることが前提の場合は、3 ノードクラスタをベースにして、必要に応じて Worker を増やしていく考えがよいでしょう。 また、ベアメタル OCP では OpenShift Virtualization という OCP 上で仮想マシンを動かす機能もサポートします。これを使っていろいろやる話はここでは省きますが、私はどこまで行ってもインフラ小僧なので物理サーバを触るのは楽しいです。ベアメタルはいいもんだぞ。ベアメタルは楽しいぞ。 というわけで、やけに生々しい話でしたが、今回はここまで。
Red Hat のテクニカルサポートエンジニアの田中です。 ここしばらくのバージョンの Red Hat OpenStack Platform(以降 RHOSP)では Director を使用して OpenStack クラスタをデプロイします。 Director は Upstream では TripleO(OpenStack-On-OpenStack)と呼ばれており、まずアンダークラウドと呼ばれる1台構成の OpenStack クラスタを作り、アンダークラウドの Heat や Ironic、Neutron といった機能と Ansible/Puppet などの構成管理ツールを活用してオーバークラウドと呼ばれる OpenStack クラスタをデプロイします。 OpenStack で OpenStack を管理することによって一元的かつフレキシブルに OpenStack クラスタのライフサイクルを管理できるのが Director の魅力......なのですが、OpenStack クラスタを 2 つ作る必要があったり、ノードの構成やネットワークの構成、各コンポーネントの設定などカスタマイズの幅が非常に広かったりと、初めて OpenStack を触る人にとっては少し難しい仕組みであるのも事実です。 弊社ではデプロイの手順を説明をした Installing and managing Red Hat OpenStack Platform with director というドキュメントがあるのですが、どのような構成・設計にも対応できるよう汎用的な書かれ方をしており、初めて Director を触る人にとっては少し難しく感じるでしょう。 本記事は、物理サーバマシン1台と RHOSP のサブスクリプションさえあればコピペで RHOSP 17.1 のデプロイができる手順を公開し Director の理解のとっかかりとしていただければ、というのがコンセプトです。 RHOSP 17 以降では RHOSP 16 以前と比較して一部手順に違いあるので、RHOSP 16 以前は触れたことがありこれから RHOSP 17 の導入を検討している人にも有用な内容かと思います。 お手軽な検証環境の構築手順として参考にしていただくのも良いでしょう。 ただし本手順および本手順で構築された環境は Red Hat としては サポート対象外 であることにご留意ください。 本手順で作成される環境の構成は非サポート構成であり、また、弊社がサポートしていないサードパーティのソフトウェアなども手順中で使用しているためです。 Director による RHOSP 17.1 デプロイの流れ RHOSP 17.1 をデプロイする場合、手順は大きく分けて以下のようになるかと思います。 ノード構成やネットワーク構成の設計 サーバやネットワークの用意 アンダークラウドマシンへの RHEL 9.2 インストール アンダークラウドのインストール(openstack undercloud install コマンド) オーバークラウドのデプロイ ネットワーク情報のプロビジョン(openstack overcloud network provision コマンド) VIP 情報のプロビジョン(openstack overcloud network vip provision コマンド) オーバークラウドのノード情報のインポート(openstack overcloud node import コマンド・openstack baremetal introspection コマンド) オーバークラウドノードのプロビジョン(openstack overcloud node provision コマンド) オーバークラウドのデプロイ(openstack overcloud deploy コマンド) 本手順の前提条件 本記事の手順の前提条件は以下です。 十分なスペックの物理マシンがあること。私の環境では以下のスペックのマシンを用意しました。 CPU : Intel(R) Xeon(R) Gold 6130 CPU × 2 ソケット (合計 64 スレッド) メモリ : 187GB ストレージ : HDD 1.7 TB Red Hat Customer Portal のアカウントがあること 必要なノード数分の有効な RHOSP サブスクリプションがあること(サブスクリプションは別途購入が必要です) インターネットにアクセス可能であること(Proxy を経由する必要がある場合は、http_proxy、https_proxy、no_proxy 等の設定がハイパーバイザーとアンダークラウドで必要になります) マシンスペックについては参考までに私の環境で OpenStack をデプロイした直後のメモリとストレージの使用状況を以下に示します。 # df -h / Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg01--root 1.7T 78G 1.6T 5% / # free -h total used free shared buff/cache available Mem: 187Gi 79Gi 45Gi 21Mi 62Gi 106Gi Swap: 4.0Gi 0B 4.0Gi また繰り返しとなりますが、本手順および本手順で構築された環境は Red Hat としては サポート対象外 であることにご留意ください。 1. ノード構成やネットワーク構成の設計 今回は物理サーバマシン1台を用意し、その上に Qemu/KVM で以下の仮想マシンを作成して RHOSP をデプロイします。 HA(High Availability)の動作が確認できるようにコントローラノードは 3 台、インスタンスのマイグレーションができるようにコンピュートノードは 2 台としてみました。 マシンスペックに自信がない場合はそれぞれ 1 台構成としてデプロイするとリソースが節約できるでしょう。 アンダークラウドノード:1 台 オーバークラウドのコントローラノード:3 台 オーバークラウドのコンピュートノード:2 台 RHOSP 17.1 のデフォルトでは、用途ごとに ctlplane, External, InternalAPI, Storage, StorageMgmt, Tenant といった異なるネットワークが必要になります。 ctlplane ネットワークは主にデプロイに使用されるネットワークで、本ネットワークを介して PXE ブートや OS イメージデータの転送などが行われます。 External ネットワークはデプロイ完了後にオーバークラウドの OpenStack のパブリックエンドポイントが配置されるネットワークであり、ユーザはこのネットワークから OpenStack にアクセスします。 Tenant ネットワークはテナントネットワーク(プライベートネットワーク)を介したインスタンス間の通信に使用されるネットワークで、インスタンスから送信されたパケットは Geneve などのプロトコルでトンネリングされこのネットワークを通ります。 これらのネットワークには物理的に異なるネットワークを用意することもできますし、VLAN で物理ネットワークを分離して割り当てることも出来ます。 本手順では以下のふたつの Libvirt の仮想ネットワークを作成し、br-external ネットワークの上には VLAN で複数のネットワークを乗せることにします。 br-provisioning ctlplane 192.168.24.0/24 VLAN なし br-external External 10.0.0.0/24 VLAN なし InternalAPI 172.16.2.0/24 VLAN:20 Storage 172.16.1.0/24 VLAN:30 StorageMgmt 172.16.3.0/24 VLAN:40 Tenant 172.16.0.0/24 VLAN:50 2. サーバやネットワークの用意 まずは用意した物理サーバに Linux を入れましょう。私の環境では RHEL 8.5 を入れました。検証していませんが CentOS Stream 8 でも動くかと思います。 用意した物理 Linux サーバに必要なパッケージをインストールします。 ※必要なパッケージはディストリビューションやバージョンにより異なる場合があります。 # dnf install -y libvirt python3 curl virt-install qemu-kvm libgcrypt libguestfs-tools-c RHOSP のノードの NTP 時刻同期先となれるよう chronyd をセットアップしておきます。 ※外部にアクセス可能な NTP サーバあればそちらを使用しても構いません。 # sed -i "s/^#local /local /" /etc/chrony.conf # echo "local stratum 10" >> /etc/chrony.conf # echo "allow 10.0.0.0/24" >> /etc/chrony.conf # echo "allow 192.168.24.0/24" >> /etc/chrony.conf # systemctl restart chronyd # systemctl enable chronyd LIbvirt の仮想ネットワークを作成します。 # systemctl start libvirtd # cat << EOF > br-provisioning.xml <network> <name>br-provisioning</name> <bridge name='br-provisioning' zone="libvirt"/> <forward mode='nat'> <nat> <port start='1024' end='65535'/> </nat> </forward> <ip address='192.168.24.254' netmask='255.255.255.0'/> </network> EOF # virsh net-define br-provisioning.xml # virsh net-autostart br-provisioning # virsh net-start br-provisioning # rm -f br-provisioning.xml # cat << EOF > br-external.xml <network> <name>br-external</name> <bridge name='br-external' zone="libvirt"/> <forward mode='nat'> <nat> <port start='1024' end='65535'/> </nat> </forward> <ip address='10.0.0.1' netmask='255.255.255.0'/> </network> EOF # virsh net-define br-external.xml # virsh net-autostart br-external # virsh net-start br-external # rm -f br-external.xml アンダークラウドノードを作ります。 空の仮想マシンを作って後で RHEL をインストールしても良いのですが、今回は RHEL 9.2 の KVM ゲストイメージを元に仮想マシンを作ってしまいましょう。 Red Hat Customer Portal にログインし RHEL 9.2 の KVM ゲストイメージをダウンロードします。 ※イメージのダウンロードにはカスタマーポータルのアカウントとサブスクリプションが必要です。 Download Red Hat Enterprise Linux -> Red Hat Enterprise Linux 9.2 KVM Guest Image ダウンロードした RHEL 9.2 イメージを使ってアンダークラウドノードを作成します。 virt-customize コマンドではイメージをカスタマイズして root ユーザのパスワードに「p@assword」を設定しています。これはお好きなパスワードに差し替えていただいて構いません。 # mv <ダウンロードしたイメージ> /var/lib/libvirt/images/rhel-9.2-x86_64-kvm.qcow2 # qemu-img create -f qcow2 /var/lib/libvirt/images/director.qcow2 120G # virt-filesystems --long --parts --blkdevs -h -a /var/lib/libvirt/images/rhel-9.2-x86_64-kvm.qcow2 # virt-resize --expand /dev/sda4 /var/lib/libvirt/images/rhel-9.2-x86_64-kvm.qcow2 /var/lib/libvirt/images/director.qcow2 # virt-customize -a /var/lib/libvirt/images/director.qcow2 --root-password password:p@assword --uninstall cloud-init # virt-install --name director --memory 24576 --vcpus 8 --disk /var/lib/libvirt/images/director.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole オーバークラウドノードも作成します。 オーバークラウドノードの OS はオーバークラウドのデプロイ時に自動でストレージに書き込まれますので、ここでは空の qcow2 イメージを作り仮想マシンを作ります。 # qemu-img create -f qcow2 /var/lib/libvirt/images/controller0.qcow2 100G # virt-install --name controller0 --memory 32768 --vcpus 8 --disk /var/lib/libvirt/images/controller0.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole # qemu-img create -f qcow2 /var/lib/libvirt/images/controller1.qcow2 100G # virt-install --name controller1 --memory 32768 --vcpus 8 --disk /var/lib/libvirt/images/controller1.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole # qemu-img create -f qcow2 /var/lib/libvirt/images/controller2.qcow2 100G # virt-install --name controller2 --memory 32768 --vcpus 8 --disk /var/lib/libvirt/images/controller2.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole # qemu-img create -f qcow2 /var/lib/libvirt/images/compute0.qcow2 50G # virt-install --name compute0 --memory 16384 --vcpus 4 --disk /var/lib/libvirt/images/compute0.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole # qemu-img create -f qcow2 /var/lib/libvirt/images/compute1.qcow2 50G # virt-install --name compute1 --memory 16384 --vcpus 4 --disk /var/lib/libvirt/images/compute1.qcow2 --import --os-variant rhel-unknown --network network=br-provisioning --network network=br-external --noautoconsole オーバークラウドノードのデプロイ時には、アンダークラウドが IPMI(BMC)経由でオーバークラウドノードを PXE ブートし、OS イメージを書き込みます。 今回オーバークラウドノードは仮想マシンなので vbmc を使用させていただき仮想の BMC を作成します。 OS を再起動しても vBMC が自動で立ち上がるように systemd のサービスも併せて作ります。 ファイアウォールの穴あけも行います。 # pip3 install --upgrade pip # pip3 install virtualbmc # vbmcd # vbmc add controller0 --port 6230 --username admin --password p@assword # vbmc add controller1 --port 6231 --username admin --password p@assword # vbmc add controller2 --port 6232 --username admin --password p@assword # vbmc add compute0 --port 6233 --username admin --password p@assword # vbmc add compute1 --port 6234 --username admin --password p@assword # vbmc start controller0 # vbmc start controller1 # vbmc start controller2 # vbmc start compute0 # vbmc start compute1 # pkill vbmcd # cat << EOF > /etc/systemd/system/vbmcd.service [Unit] After = libvirtd.service After = syslog.target After = network.target Description = vbmc service [Service] ExecReload = /bin/kill -HUP $MAINPID ExecStart = /usr/local/bin/vbmcd --foreground ExecStartPost = /usr/local/bin/vbmc start controller0 ExecStartPost = /usr/local/bin/vbmc start controller1 ExecStartPost = /usr/local/bin/vbmc start controller2 ExecStartPost = /usr/local/bin/vbmc start compute0 ExecStartPost = /usr/local/bin/vbmc start compute1 Group = root PrivateDevices = False PrivateNetwork = False PrivateTmp = False PrivateUsers = False Restart = on-failure RestartSec = 2 Slice = vbmc.slice TasksAccounting = True TimeoutSec = 120 Type = simple User = root [Install] WantedBy = multi-user.target EOF # systemctl daemon-reload # systemctl enable --now vbmcd # vbmc list # firewall-cmd --zone libvirt --add-port 6230-6234/udp --permanent # firewall-cmd --zone libvirt --add-service ntp --permanent # firewall-cmd --reload 3. アンダークラウドマシンへの RHEL 9.2 インストール 通常はサーバを用意した後アンダークラウドマシンへ RHEL 9.2 のインストールが必要です。 今回は上の手順で RHEL 9.2 インストール済みの仮想マシンを作成済みなのでこの手順はスキップします。 4. アンダークラウドのインストール(openstack undercloud install コマンド) まずは以下のコマンドでアンダークラウドの仮想マシンのコンソールを開き、ログインしましょう。 virsh console コマンド実行後 Enter キーを叩くとログインプロンプトが表示されます。 パスワードは上の手順の virt-customize で設定したものになります。 # virsh console director -> user : root -> password : p@assword ホスト名や IP アドレスの設定などをします。 eth0 が br-provisioning、eth1 が br-external につながっています。 eth0 は後の undercloud インストール時に自動で IP アドレスが設定されますので、ここでは eth1 だけ IP アドレスを設定します。 # hostnamectl set-hostname undercloud.example.com # hostnamectl set-hostname --transient undercloud.example.com # nmcli c mod "Wired connection 2" connection.id "eth1" # nmcli c mod eth1 ipv4.method manual ipv4.address 10.0.0.254/24 ipv4.dns 10.0.0.1 ipv4.gateway 10.0.0.1 # nmcli c up eth1 # nmcli c del "Wired connection 1" # echo 192.168.24.1 `hostname` >> /etc/hosts # timedatectl set-timezone Asia/Tokyo 必要なパッケージのダウンロードができるように、RHOSP のサブスリプションのアタッチをし、リポジトリを有効化します。 RHOSP 17.1 は RHEL 9.2 の上でしかサポートされないので、マイナーバージョンを 9.2 に固定することも忘れないようにしましょう。 次にパッケージのインストールと、RHEL 9.2 の最新バージョンへのアップデートをします。 # subscription-manager register # subscription-manager attach --pool=XXXXXXX # subscription-manager release --set=9.2 # subscription-manager release # subscription-manager repos --disable=* # subscription-manager repos \ --enable=rhel-9-for-x86_64-baseos-eus-rpms \ --enable=rhel-9-for-x86_64-appstream-eus-rpms \ --enable=rhel-9-for-x86_64-highavailability-eus-rpms \ --enable=openstack-17.1-for-rhel-9-x86_64-rpms \ --enable=fast-datapath-for-rhel-9-x86_64-rpms # dnf install -y python3-tripleoclient crudini ipmitool # dnf update -y stack ユーザを作成します。 以降アンダークラウドノードでは基本的に root ユーザで作業をすることはなく、stack ユーザで作業することになります。 下記の passwd コマンドでは stack ユーザのパスワードを「p@assword」に設定しています。これもお好きなパスワードに差し替えていただいて構いません。 # useradd stack # echo p@assword | passwd --stdin stack # echo "stack ALL=(root) NOPASSWD:ALL" | tee -a /etc/sudoers.d/stack # chmod 0440 /etc/sudoers.d/stack パッケージのインストール・アップデートをしたので、一度アンダークラウドノードを再起動しておきましょう。 # reboot 再起動が問題なく完了したことを確認したら、ctrl+] キーを叩き virsh console から抜けます。 以降はアンダークラウドノードへは SSH で接続します。 SSH 鍵を作成していない場合は ssh-keygen で作っておきましょう。 ssh-copy-id 実行時のパスワードは上の passwd コマンドで設定したものになります。 # echo 10.0.0.254 undercloud director >> /etc/hosts # ssh-keygen # もしまだ SSH キーを作成していない場合 # ssh-copy-id stack@director # password : p@assword # ssh stack@director 必要な作業ディレクトリを作ります。 image ディレクトリにはオーバークラウドの OS イメージなどを、templates ディレクトリにはオーバークラウドの設定に使用するテンプレートファイルなどを後に配置します。 $ mkdir ~/images $ mkdir ~/templates RHOSP 12 以降、RHOSP の各サービス(nova-api、neutron-api など)はコンテナ化されております。 これらのコンテナイメージをプル(ダウンロード)するための設定ファイルを作成します。 ファイル名は任意ですが、一般的には「containers-prepare-parameter.yaml」です。 $ openstack tripleo container image prepare default \ --local-push-destination \ --output-env-file containers-prepare-parameter.yaml 本ファイルには弊社コンテナレジストリからコンテナイメージをプルするために認証情報を記載する必要があります。 ただしユーザIDとパスワードを平文で記載するのは避けたいので、以下の記事を参考にレジストリサービスアカウント(認証トークン)を作成しましょう。 レジストリーサービスアカウントの作成 これにより Red Hat カスタマーポータルのユーザIDやパスワードを記載することなくコンテナイメージのプルをすることができます。 作成したレジストリサービスアカウントのユーザIDとパスワードを以下のコマンドで「containers-prepare-parameter.yaml」に記載します。 <username> と <password> の箇所をレジストリサービスアカウントのユーザIDとパスワードに置き換えて以下のコマンドを実行してください。 $ cat << EOF >> containers-prepare-parameter.yaml ContainerImageRegistryCredentials: registry.redhat.io: <username>: <password> EOF アンダークラウドのインストールは undercloud.conf という設定ファイルに基づいて行われます。 以下のコマンドでは undercloud.conf を編集しています。もちろん vi などのテキストエディタで編集していただいても構いません。 ちなみにここで設定している 10.0.0.1 はハイパーバイザーの IP アドレスです。 $ cp /usr/share/python-tripleoclient/undercloud.conf.sample ~/undercloud.conf $ crudini --set undercloud.conf DEFAULT container_images_file /home/stack/containers-prepare-parameter.yaml $ crudini --set undercloud.conf DEFAULT local_interface eth0 $ crudini --set undercloud.conf DEFAULT overcloud_domain_name example.com $ crudini --set undercloud.conf DEFAULT undercloud_nameservers 10.0.0.1 $ crudini --set undercloud.conf DEFAULT clean_nodes true $ crudini --set undercloud.conf DEFAULT generate_service_certificate true $ crudini --set undercloud.conf DEFAULT undercloud_ntp_servers 10.0.0.1 $ crudini --set undercloud.conf ctlplane-subnet masquerade true $ crudini --set undercloud.conf ctlplane-subnet dns_nameservers 10.0.0.1 いよいよアンダークラウドのインストールです。 1時間程度かかる場合もあるので気長に待ちましょう。 $ openstack undercloud install インストールが成功すると以下のような出力がされます。 ######################################################## Deployment successful! ######################################################## Writing the stack virtual update mark file /var/lib/tripleo-heat-installer/update_mark_undercloud ########################################################## The Undercloud has been successfully installed. Useful files: Password file is at /home/stack/tripleo-deploy/undercloud/tripleo-undercloud-passwords.yaml The stackrc file is at ~/stackrc Use these files to interact with OpenStack services, and ensure they are secured. ########################################################## インストールが成功すると、ホームディレクトリ直下に stackrc というファイルが作成されます。 本ファイルには、アンダークラウドの OpenStack へのアクセスに必要な情報(エンドポイントの URL やユーザID・パスワードなど)が格納されています。 CLI でアンダークラウドの OpenStack にアクセスして操作するには、以下のように stackrc を読み込んでからコマンドを実行する必要があります。 $ source stackrc $ openstack endpoint list 5. オーバークラウドのデプロイ ここからはオーバークラウドのデプロイになります。 5-a. ネットワーク情報のプロビジョン(openstack overcloud network provision コマンド) ネットワーク構成(MTU、VLAN ID、IP アドレスレンジ、デフォルトゲートウェイなど)の設定とプロビジョンを行います。 設定を記載するファイルである network_data.yaml のサンプルがあるので、今回はそれをそのまま使用します。 IP アドレスレンジの変更や VLAN ID の変更などのカスタマイズをしたい場合は本ファイルを編集することになります。 $ cp /usr/share/openstack-tripleo-heat-templates/network-data-samples/default-network-isolation.yaml /home/stack/templates/network_data.yaml $ #vim /home/stack/templates/network_data.yaml $ openstack overcloud network provision \ --output /home/stack/templates/overcloud-networks-deployed.yaml \ /home/stack/templates/network_data.yaml $ openstack network list $ openstack subnet list 上記の openstack overcloud network provision で /home/stack/templates/overcloud-networks-deployed.yaml というファイルが作成されます。 本ファイルは後の openstack overcloud deploy 実行時に使用します。 なお分かりづらいのですが、ここではアンダークラウドの Neutron にネットワークの情報を登録しているだけであり、実際にそのネットワーク上に何かインタフェースの作成や IP アドレスの設定をしているわけではありません。 5-b. VIP 情報のプロビジョン(openstack overcloud network vip provision コマンド) 次にオーバークラウドノードが持つ VIP の情報の設定とプロビジョンを行います。 コントローラノードは 3 台の冗長構成を取ることが一般的ですが、この 3 台のうち 1 台が代表して VIP を持ち、クライアント等はこの VIP に対してアクセスすることになります。 ここではその VIP の設定を行います。 本手順でもやはりサンプルの設定ファイルをそのまま使います。 カスタマイズしたい場合は設定ファイルを編集しましょう。 $ cp /usr/share/openstack-tripleo-heat-templates/network-data-samples/vip-data-default-network-isolation.yaml /home/stack/templates/vip_data.yaml $ #vim /home/stack/templates/vip_data.yaml $ openstack overcloud network vip provision \ --stack overcloud \ --output /home/stack/templates/overcloud-vip-deployed.yaml \ /home/stack/templates/vip_data.yaml $ openstack port list 上記の openstack overcloud network vip provision で /home/stack/templates/overcloud-vip-deployed.yaml というファイルが作成されます。 本ファイルは後の openstack overcloud deploy 実行時に使用します。 ここでもやはりアンダークラウドの Neutron に VIP の情報を登録しているだけであり、実際にどこかのインタフェースで IP アドレスの設定をしているわけではありません。 5-c. オーバークラウドのノード情報のインポート(openstack overcloud node import コマンド・openstack baremetal introspection コマンド) まずはオーバークラウドノードにデプロイする OS のイメージなどを登録しておかないといけないので以下の手順を実行しましょう。 本手順で /var/lib/ironic/images/overcloud-hardened-uefi-full.raw というファイルが作成され、このイメージが後の手順でオーバークラウドノードのストレージに書き込まれることになります。 $ source ~/stackrc $ sudo dnf install rhosp-director-images-uefi-x86_64 rhosp-director-images-ipa-x86_64 -y $ for i in /usr/share/rhosp-director-images/ironic-python-agent-latest.tar /usr/share/rhosp-director-images/overcloud-hardened-uefi-full-latest.tar; do tar -xvf $i -C ~/images; done $ openstack overcloud image upload --image-path ~/images/ $ ls -l /var/lib/ironic/images $ ls -l /var/lib/ironic/httpboot 次に、オーバークラウドノードの情報をアンダークラウドの Ironic に登録します。 ここで登録した情報を元に、後の手順で IPMI のアクセスや PXE ブートなどが行われ、OS イメージの書き込みなどががされることになります。 オーバークラウドノードの NIC の MAC アドレスなどを確認しないといけませんので、アンダークラウドノードからログアウトしてハイパーバイザーに戻りましょう。 $ exit ノードの登録には以下のような情報が必要になります。 オーバークラウドノードの IPMI の IP アドレス、ポート番号、ユーザID、パスワード オーバークラウドノードの ctlplane ネットワークに接続されている NIC の MAC アドレス など 今回の手順の場合、IPMI の情報は上の vbmc で設定した情報となります。 MAC アドレスは virsh dumpxml や virsh domiflist コマンドなどで確認できます。 こうして確認した情報をテキストエディタでファイルに書いていくのですが、今回はコピペで動くことがテーマなので、以下のコマンドを実行しましょう。 必要な情報が全て書き込まれた nodes.yaml ファイルが作成されます。 # cat << EOF > nodes.yaml nodes: - ports: - address: $(virsh dumpxml controller0|xmllint --xpath "//interface/source[@network='br-provisioning']/parent::*/mac/@address" - |cut -d'"' -f2) physical_network: ctlplane name: "controller0" arch: "x86_64" pm_type: "ipmi" pm_user: "admin" pm_password: "p@assword" pm_addr: "192.168.24.254" pm_port: "6230" - ports: - address: $(virsh dumpxml controller1|xmllint --xpath "//interface/source[@network='br-provisioning']/parent::*/mac/@address" - |cut -d'"' -f2) physical_network: ctlplane name: "controller1" arch: "x86_64" pm_type: "ipmi" pm_user: "admin" pm_password: "p@assword" pm_addr: "192.168.24.254" pm_port: "6231" - ports: - address: $(virsh dumpxml controller2|xmllint --xpath "//interface/source[@network='br-provisioning']/parent::*/mac/@address" - |cut -d'"' -f2) physical_network: ctlplane name: "controller2" arch: "x86_64" pm_type: "ipmi" pm_user: "admin" pm_password: "p@assword" pm_addr: "192.168.24.254" pm_port: "6232" - ports: - address: $(virsh dumpxml compute0|xmllint --xpath "//interface/source[@network='br-provisioning']/parent::*/mac/@address" - |cut -d'"' -f2) physical_network: ctlplane name: "compute0" arch: "x86_64" pm_type: "ipmi" pm_user: "admin" pm_password: "p@assword" pm_addr: "192.168.24.254" pm_port: "6233" - ports: - address: $(virsh dumpxml compute1|xmllint --xpath "//interface/source[@network='br-provisioning']/parent::*/mac/@address" - |cut -d'"' -f2) physical_network: ctlplane name: "compute1" arch: "x86_64" pm_type: "ipmi" pm_user: "admin" pm_password: "p@assword" pm_addr: "192.168.24.254" pm_port: "6234" EOF 作成したファイルをハイパーバイザーからアンダークラウドにコピーし、 # scp nodes.yaml stack@director: アンダークラウドでこれをインポートします。 openstack baremetal node list でインポートしたオーバークラウドノードの情報が確認でき、各ノードの Provisioning State が managable になれば成功です。 # ssh stack@director $ source ~/stackrc $ openstack overcloud node import --validate-only ~/nodes.yaml $ openstack overcloud node import ~/nodes.yaml $ openstack baremetal node list 次にイントロスペクションと呼ばれる処理を実行します。 これにより、オーバークラウドノードが PXE ブートで起動し、ironic-python-agent と呼ばれるプログラムが実行され、オーバークラウドノードのマシンスペックなどの情報が収集され、アンダークラウドノードの Ironic に収集された情報が登録されます。 10 分程度時間がかかる場合があるのでしばらく待ちましょう。 この時オーバークラウドノードのコンソールを見てみると PXE ブートしている様子や ironic-python-agent が動いている様子が確認できて面白いかもしれません。 成功すれば各ノードの Porvisioning State が availabe になり、オーバークラウドのデプロイに使用できる状態になります。 $ openstack overcloud node introspect --all-manageable --provide $ openstack baremetal node list Qemu/KVM で作成した仮想マシンはデフォルトでは legacy-BIOS ブートをするので、アンダークラウドの Ironic でもそのように設定します。 $ openstack baremetal node list -f value -c UUID| while read NODE; do openstack baremetal node set --property capabilities="boot_mode:bios,$(openstack baremetal node show $NODE -f json -c properties | jq -r .properties.capabilities | sed "s/boot_mode:[^,]*,//g")" $NODE;done 5-d. オーバークラウドノードのプロビジョン(openstack overcloud node provision コマンド) ここではオーバークラウドノードに OS のデプロイやネットワークインタフェースの設定などを行います。 オーバークラウドノードのネットワーク設定を定義するカスタムネットワークインタフェーステンプレートファイルを作成します。 本ファイルではオーバークラウドノードのどのインタフェースにどのネットワークを割り当てるかや、Neutron のプロバイダーネットワークの提供に必要な Open vSwitch のブリッジの定義などをします。 また本ファイルは Jinja2 形式になっており、ロールやネットワークごとにループを回したり、IP アドレスレンジなどの情報を変数から取得したり出来ます。 これもサンプルとなるファイルが /usr/share/ansible/roles/tripleo_network_config/templates 配下にいくつか存在するのですが、残念ながら今回の手順のネットワーク構成に合致するものはないので、手動で作成します。 以下の設定では nic1(eth0)に ctlplane ネットワークの IP アドレスを設定し、nic2(eth1)を Open vSwtich のブリッジにつなぎ External ネットワークの IP アドレス設定や InternalAPI/Storage/StorageMgmt 用の VLAN インタフェースを作成しています。 $ cat << EOF > ~/templates/two_interfaces.j2 --- {% set mtu_list = [ctlplane_mtu] %} {% for network in role_networks %} {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} {%- endfor %} {% set min_viable_mtu = mtu_list | max %} network_config: - type: interface name: nic1 mtu: {{ ctlplane_mtu }} use_dhcp: false addresses: - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }} routes: {{ ctlplane_host_routes }} - type: ovs_bridge name: {{ neutron_physical_bridge_name }} dns_servers: {{ ctlplane_dns_nameservers }} domain: {{ dns_search_domains }} {% if 'External' in role_networks %} mtu: {{ external_mtu }} use_dhcp: false addresses: - ip_netmask: {{ external_ip }}/{{ external_cidr }} routes: {{ external_host_routes }} {% endif %} members: - type: interface name: nic2 mtu: {{ min_viable_mtu }} primary: true {% for network in role_networks if network != 'External' %} - type: vlan mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} addresses: - ip_netmask: {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} {% endfor %} EOF 次に overcloud-baremetal-deploy.yaml と呼ばれるファイルを作成します。 本ファイルでは、各ロールのノード数や、どのベアメタルノードにどのロールやホスト名を割り当てるかを定義しています。 上で作成した two_interfaces.js への参照もあることにも注目してください。 またデフォルトでは Swift のデータ格納先に使用されるコントローラノードの /srv パーティションのサイズが小さいので、30GB へ拡張しています。 $ cat << EOF > /home/stack/templates/overcloud-baremetal-deploy.yaml - name: Controller count: 3 defaults: networks: - network: ctlplane vif: true - network: external subnet: external_subnet - network: internal_api subnet: internal_api_subnet - network: storage subnet: storage_subnet - network: storage_mgmt subnet: storage_mgmt_subnet - network: tenant subnet: tenant_subnet network_config: template: /home/stack/templates/two_interfaces.j2 default_route_network: - external ansible_playbooks: - playbook: /usr/share/ansible/tripleo-playbooks/cli-overcloud-node-growvols.yaml extra_vars: growvols_args: > /=8GB /tmp=1GB /var/log=10GB /var/log/audit=2GB /home=1GB /srv=30GB /var=100% instances: - hostname: overcloud-controller-0 name: controller0 - hostname: overcloud-controller-1 name: controller1 - hostname: overcloud-controller-2 name: controller2 - name: Compute count: 2 defaults: networks: - network: ctlplane vif: true - network: internal_api subnet: internal_api_subnet - network: tenant subnet: tenant_subnet - network: storage subnet: storage_subnet network_config: template: /home/stack/templates/two_interfaces.j2 instances: - hostname: overcloud-novacompute-0 name: compute0 - hostname: overcloud-novacompute-1 name: compute1 EOF 必要な情報が一通り揃ったので、ノードのプロビジョンを行います。 これにより、オーバークラウドノードが PXE ブートし、ironic-python-agent と呼ばれるプログラムが実行され、オーバークラウドノードのストレージに OS イメージが書き込まれます。 また Ansible でネットワークの設定やパーティションの拡張なども行われます。 本コマンドで作成された /home/stack/templates/overcloud-baremetal-deployed.yaml ファイルは後の openstack overcloud deploy で使用します。 $ openstack overcloud node provision \ --stack overcloud \ --network-config \ --output /home/stack/templates/overcloud-baremetal-deployed.yaml \ /home/stack/templates/overcloud-baremetal-deploy.yaml 成功すれば以下のコマンドでオーバークラウドノードの情報を確認することができるようになります。 オーバークラウドノードに割り当てられた IP アドレスも確認でき、 ssh tripleo-admin@<IP-address> コマンドで SSH ログインが可能です。 $ metalsmith list 5-e. オーバークラウドのデプロイ(openstack overcloud deploy コマンド) この手順が最後の手順になります。 この手順でオーバークラウドノードに Nova や Cinder、Neutron といった OpenStack のコンポーネントがデプロイされます。 オーバークラウドのデプロイには内部的に Heat が使用されます。 そのためオーバークラウドの設定のカスタマイズ等には Heat の環境ファイルと呼ばれるものを作成します。 以下の手順では必要最低限の環境ファイルを作成しています。 実際の環境ではカスタマイズすべき点がたくさんあるはずですので、必要な設定の数や環境ファイルの数はもっと多くなるでしょう。 $ cat << EOF > /home/stack/templates/my-environment-file.yaml parameter_defaults: ComputeParameters: KernelArgs: "tsx=off" CloudDomain: "example.com" EOF $ cat << EOF > /home/stack/templates/inject-trust-anchor-hiera.yaml parameter_defaults: CAMap: undercloud-ca: content: | $(awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' /etc/pki/ca-trust/source/anchors/cm-local-ca.pem |sed 's/^/ /g') EOF 以下のコマンドでオーバークラウドのデプロイを行います。 これまでの手順で作成されたファイルを参照していることに注目してください。 これらの環境ファイルの設定を元にオーバークラウドに Nova や Neutron などといったコンポーネントがデプロイされます。 数時間かかる場合があるので気長に待ちましょう。 $ openstack overcloud deploy --templates \ -n /home/stack/templates/network_data.yaml \ -e /home/stack/templates/overcloud-baremetal-deployed.yaml \ -e /home/stack/templates/overcloud-networks-deployed.yaml \ -e /home/stack/templates/overcloud-vip-deployed.yaml \ -e /home/stack/containers-prepare-parameter.yaml \ -e /home/stack/templates/inject-trust-anchor-hiera.yaml \ -e /home/stack/templates/my-environment-file.yaml \ --ntp-server 192.168.24.254 デプロイが完了すると、ホームディレクトリ直下に overcloudrc というファイルが作成されます。 本ファイルには、オーバークラウドの OpenStack へのアクセスに必要な情報(エンドポイントの URL やユーザID・パスワードなど)が格納されています。 CLI でオーバークラウドの OpenStack にアクセスして操作するには、以下のように overcloudrc を読み込んでからコマンドを実行する必要があります。 $ source overcloudrc $ openstack endpoint list 実際にインスタンスを作成してみる OpenStack がデプロイ出来たので実際にインスタンスを作成してみましょう。 詳細は割愛しますが、以下の一連のコマンドではインスタンス作成に必要な仮想ネットワークやフレーバーなどを作成し、インスタンスを作成しています。 イメージにはテスト用の OS である CirrOS を使用しています。 $ curl -L -O https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img $ source overcloudrc $ openstack image create --public cirros-0.6.2 --file cirros-0.6.2-x86_64-disk.img --disk-format qcow2 $ openstack flavor create --public --ram 1024 --disk 1 --vcpus 1 small $ openstack security group create my_security_group $ openstack security group rule create my_security_group --protocol icmp $ openstack security group rule create my_security_group --protocol tcp --dst-port 22 $ openstack keypair create my_keypair > ~/.ssh/instance.key $ chmod 400 ~/.ssh/instance.key $ openstack network create external_network --external --provider-network-type flat --provider-physical-network datacentre $ openstack subnet create external_subnet --network external_network --dhcp --allocation-pool start=10.0.0.150,end=10.0.0.200 --gateway 10.0.0.1 --subnet-range 10.0.0.0/24 $ openstack network create private_network $ openstack subnet create --network private_network --subnet-range 192.168.0.0/24 private_subnet $ openstack router create my_router $ openstack router set --external-gateway external_network my_router $ openstack router add subnet my_router private_subnet $ openstack server create --flavor small --image cirros-0.6.2 --network private_network --security-group my_security_group --key-name my_keypair my_instance $ openstack floating ip create external_network --floating-ip-address 10.0.0.160 $ openstack server add floating ip my_instance 10.0.0.160 $ openstack server show my_instance 上記手順でインスタンスが作成できたら、以下のコマンドで SSH 接続が可能です。 $ ssh -i ~/.ssh/instance.key cirros@10.0.0.160 ※2023/12/22 追記:ログインユーザが間違っておりましたので正しいユーザ cirros へ変更しました。 おわりに 必要最小限のカスタマイズで OpenStack をデプロイしてみましたが、それでも複雑で長い手順であることがわかるかと思います。 まずは上記手順を実際に試してみてデプロイの流れを掴んでみるのがとっかかりとして良いかと思います。 大まなか手順がつかめたらネットワーク構成をカスタマイズしてみる、ノード構成を変更してみる、設定変更を加えてみるなどするとより理解が深まるかもしれません。 より深く知りたいところがあれば弊社の Installing and managing Red Hat OpenStack Platform with director や その他の RHOSP のドキュメント も参考にしてみてください。 例えばセキュリティに関する強化をしたい場合は Hardening Red Hat OpenStack Platform 、IPv6 を使いたい場合は Configuring IPv6 networking for the overcloud 、外部の Ceph ストレージと連携したい場合は Integrating the overcloud with an existing Red Hat Ceph Storage Cluster など、目的に応じてデプロイメントに関する手順が各ドキュメントに点在していることにもご注意ください。 本ブログの手順で一度デプロイできたら RHOSP のドキュメントの一覧 を眺めてみて、どこに何の説明がありそうかの土地勘を掴んでいただくと、必要な設定手順を見つけやすくなるかと思います。 また弊社のドキュメントの説明だけではよくわからないという場合は、アップストリームの TripleO のドキュメント なども読んでいただくと、同じ事柄が弊社のドキュメントとは違う言葉・文章で説明されていて理解が深まることがあるかと思います。 また本手順で実行した openstack overcloud deploy などのコマンドはシェルスクリプトのファイルに書いていただき、設定ファイルやテンプレートファイルと併せて git で管理しておくと、バージョン管理や環境を跨いでの再利用などがしやすく良いでしょう。 もし手順中のどこかのコマンドでエラーが発生した場合は トラブルシュートのためのドキュメント を参考にトラブルシュートしてみてください。 なお本手順では KVM 仮想マシンを作りその上に OpenStack を構築しましたが、これと同じことを自動で行ってくれる infrared というツールもあります。デプロイ手順を確認するよりも実際に動く環境が欲しいという場合はこちらを利用すると良いでしょう。infrared については次回以降また取り上げることができればと考えています。 なお本記事では Director(TripleO)でのデプロイ手順を紹介いたしましたが、次のメジャーリリースである RHOSP 18 では OpenStack のコントロールプレーンのコンポーネントがベアメタルではなく OpenShift 上で動く構成となったことにより、Director の廃止が決まっております。RHOSP 18 でのデプロイ手順は Development Preview という扱いで リリース されており、 デプロイの手順のドキュメント も公開されておりますので、先駆けて確認したい方はぜひこちらのページをご確認ください。 本記事が Director の理解の一助になることを願います。
※2023年12月8日追記 記事タイトルに番号を振りました。 OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (1) <= 本記事 OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (2) こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 今回はOpenShift上でVMを構築し管理するOpenShift Virtualizationについて紹介したいと思います。 OpenShift VirtualizationはOSSの Kubevirt をOpenShiftの機能の一つとして提供しているものです。 Kubevirtは2016年にRed Hatがプロジェクトを開始しOSSとして公開され、その後CNCFプロジェクトの一部となりました。現在はCNCFの中でIncubatingプロジェクトの一つとして位置付けられています。 そんなKubevirtですが今年に入り7月にバージョン1.0がリリースされました。 OSSプロジェクトとして安定、成熟してきており、ユーザーとしてもAppleやGoldman Sachs、NVIDIAなどの企業が名前を連ねています。 今年4月にアムステルダムで行われたOpenShift Commons Gatheringの中でもKubevirtについてRed HatとNVIDIAの方が実施したセッションが公開されているため興味がある方はご覧になってみて下さい。 www.youtube.com またアップストリームの利用例だけでなく、OpenShift Virtualizationとしての利用も昨今増えつつあります。今年開催されたRed Hat Summitの中でもこうしたユーザー事例がいくつか取り上げられていますのでこちらも興味があればご覧下さい。 www.youtube.com 以降では、OpenShift Virtualizationを利用するメリットと、どのような仕組みでVMが起動するのかと、実際の利用方法を紹介していきたいと思います。 OpenShift Virtualizationを利用するメリット OpenShift VirtualizationやKubevirtについて、そもそもなぜコンテナ環境上でVMを立てるのか、という点に疑問がある方もいるんじゃないかと思います。 ここについて理由は様々考えられますが、例えばシステムの大部分をコンテナ化しているが、一部についてはパッケージソフトウェアなどを利用しておりコンテナ化が難しくVMが残ってしまう、といったケースなどが考えられます。 勿論この時、既存のVM管理の仕組みを継続して使い続けることも考えられますが、ワークロードのほとんどがコンテナということであればKubernetesの仕組みを利用してVMを管理するという選択肢も出てくると考えられます。 OpenShift Virtualizationを利用してOpenShift環境上にVMを立てる場合、コンテナ基盤ならではの様々なメリットを受けることができます。 ネットワークと名前解決 VMで利用するネットワークは、OpenShiftで利用するCNI(デフォルトではOVN-Kubernetes)を通じて提供されます。 作成したVM上でホストされるアプリケーションには、Podと同様に、ServiceやRouteを通じてクラスタ内外からアクセスすることができます。そのため、同じクラスタ上のPodからVM上のアプリにアクセスする際にVMのIPアドレスを意識してアクセスするという必要が無くなります。 またVMへのアクセスを特定のPodからのみに制限したい場合には、NetworkPolicyを利用することができます。 Probe Podと同様にVMでもReadinessProbeやLivenessProbeを活用したアプリの正常性確認を行うことができます。TCPやHTTPのProbeに加え、ゲストOSにqemu-guest-agentをインストールし有効化しておくことでexecコマンド実行によるProbeも利用することができます。 ストレージ VMで利用するディスクはCSIを通じてPVとして提供されます。この時PVのアクセスモードとしてReadWriteOnce(RWO)やReadWriteMany(RWX)を選択することができますが、RWXを選択することでクラスタを構成するベアメタルノード間でVMのライブマイグレーションを実行することが可能となります。これにより例えばクラスタのアップグレードを行うような場合でも、その上で動くVMは無停止でアプリを実行することができます。ライブマイグレーションはOpenShift Virtualizationを利用する上で重要な機能となるため、利用するストレージがRXWに対応しているか確認すると良いでしょう。 その他にも利用するストレージの機能として提供されている場合、CSIを通じてVMのスナップショットを作成することもできます。 OpenShiftに統合されたVM管理コンソール OSSのKubevirtではVMの運用をCLIやyamlファイルを適用することで実施しますが、OpenShift VirtualizationではOpenShiftコンソールの一部としてGUIを利用することができます。 そのため基本的な運用についてはGitOpsと組み合わせ自動化し、アドホックな操作についてはGUIで実施するなど、状況に応じて使い分けることができます。 ここで挙げた以外にも便利なポイントはありますが、それらについては適宜紹介していければと思います。 コンテナ基盤上でVMが動く仕組み ここからはそもそもどうやってコンテナ基盤上でVMが動いているのかを解説していきたいと思います。 OpenShift Virtualizationでは、これまでRHEL等で実現していたのと同様に、KVMを利用しVMを作成し、管理します。そのため必要なコンポーネント(QEMU、libvirtなど)は変わりませんが、一部はPodとして動作することとなります。 まず以下にKubevirt Operatorがインストールされた状態を示します。 KubevirtのAPIを提供するVirt API Serverと、制御を行うVirt Controller、そしてVMを起動する各Worker Node上にはDaemonsetとしてVirt HandlerというPodが起動します。 VMを作成するため、まずVirtualMachineオブジェクトを作成します。VirtualMachineを作成すると、VMの実際の状態を表すVirtualMachineInstanceというオブジェクトが自動的に作成され、それを元にVirt Launcherと呼ばれるPodがWorker Nodeにスケジュールされ起動します。Virt Launcherは起動するVMと1:1の関係となります。 通常のPodと同様にkube-schedulerによりスケジューリングされるため、NodeSelectorやAffinity、Taint/Tolerentを設定することで、結果としてVMが起動するNodeをコントロールすることができます。 このVirt Launcherの中ではVMの操作に必要なlibvirtdやQEMUが実行されます。(上図では別々のコンテナのように見えますが、実際はVirt launcherコンテナの中でまとめて実行されます。) 各コンポーネントの役割については以下を参照下さい。 access.redhat.com Virt Launcher Podが起動すると、起動したNodeの情報をVirt ControllerがVMIに対し追記します。ここまで完了すると、以降のVMIの変更はkubeletではなく、DaemonSetとして配置されたVirt Handlerにより監視され、Virt Handlerを経由しVirt Launcherに情報が渡されます。Virt Launcherは定義されたVMIの状態と一致するよう、libvirtのAPIを使用しVMの操作を行います。 ここまででコンテナ基盤上でVMを起動することができました。 VMを削除する場合、作成したVirtualMachineオブジェクトを削除します。するとそれに伴いVMIオブジェクトも削除され、Virt Handlerがその削除を検知し、対象のVirt Launcher Podの削除を行います。 OpenShift Virtualizationのインストールと準備 ここからはOpenShift上でOpenShift Virtualizationをインストールし、VMを起動したいと思います。 OpenShift Virtualizationを利用する場合、ベアメタルノードが必要となります。これまではオンプレミス環境でのベアメタルノードしかサポートの対象となりませんでしたが、最新のバージョンである4.14からはAWSのベアメタルノードも利用可能となりました。 docs.openshift.com 今回はAWS上にIPIでクラスターをインストールし、ノードの一つをベアメタルノード(インスタンスタイプ: c5.metal)とします。ノード間のライブマイグレーションを試したい場合は2つ以上のベアメタルノードを準備しましょう。 クラスターインストール手順は割愛しますが、今回検証を行ったクラスターの各ノードのスペックは以下の通りです。 Master Node: m6i.xlarge * 3 Infra Node: なし Worker Node: m5.2xlarge * 3 + c5.metal * 1 OpenShift Data Foundationのインストール AWSではEFSを使うことでRWXなPVを利用することができますが、OpenShift VirtualizationではEBS/EFSの利用は サポートされていません 。そのためOpenShift Data Foundationをインストールし、RWXとして利用可能なStorageClassを準備したいと思います。 まずはOperator HubからODFを探しインストールしましょう。 ODFのインストールが完了するとStorageSystemの作成が要求されます。 Deploymentタイプとして"Full deployment"、バッキングストレージとして"gp3-csi"を選択します。 次に容量とノードの選択です。今回は検証用途となるため最小容量であるノードごと0.5TiBを選択し、デプロイ対象のノードを3つ選択します。 残りの設定項目はデフォルトのままStorageSystemを作成します。 しばらくすると必要なリソースが作成されODFで追加されたStorageClassが利用可能となります。 # oc get storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE gp2-csi ebs.csi.aws.com Delete WaitForFirstConsumer true 4h gp3-csi (default) ebs.csi.aws.com Delete WaitForFirstConsumer true 4h ocs-storagecluster-ceph-rbd openshift-storage.rbd.csi.ceph.com Delete Immediate true 11m ocs-storagecluster-ceph-rbd-virtualization openshift-storage.rbd.csi.ceph.com Delete Immediate true 11m ocs-storagecluster-cephfs openshift-storage.cephfs.csi.ceph.com Delete Immediate true 11m openshift-storage.noobaa.io openshift-storage.noobaa.io/obc Delete Immediate false 10m この時デフォルトのStorageClassが"gp3-csi"のままとなっているため、annotationを変更し"ocs-storagecluster-ceph-rbd-virtualization"をデフォルトのStorageClassとします。 kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: ocs-storagecluster-ceph-rbd-virtualization --- (略) --- annotations: description: Provides RWO and RWX Block volumes suitable for Virtual Machine disks storageclass.kubevirt.io/is-default-virt-class: 'true' storageclass.kubernetes.io/is-default-class: 'true' # 追加 --- (略) --- "gp3-csi"の方のannotationも忘れずに変更しておきましょう。 OpenShift VirtualizationのインストールとVMの作成 続いてOpenShift VirtualizationをOperator Hubからインストールしましょう。 インストールが完了すると HyperConverged というリソースの作成を求められます。 OpenShift VirtualizationではKubevirt Operatorだけでなく、VM管理に必要な複数のOperatorをインストールします。それらをまとめて設定し、管理するためのリソースがHyperConvergedです。 ここではデフォルトの設定のまま作成を行います。 HyperConvergedを作成し必要なリソースがデプロイされるとOpenShiftのコンソールからVirtualizationのタブを開くことができるようになります。 この時Overview画面の右上からVMの操作やSSHに使用する"virtctl"CLIのダウンロードをすることができるので、自身の環境に合うものをダウンロードし設定しておきましょう。 # curl -L -O https://hyperconverged-cluster-cli-download-openshift-cnv.apps.{クラスター名}.{ベースドメイン}/amd64/linux/virtctl.tar.gz # tar xvf virtctl.tar.gz -C /usr/local/bin VMの起動はこのvirtctlを使用するか、yamlを書いてデプロイするか、GUIを使うかから選択できます。 今回は手軽に実行するためにGUIからVMを起動したいと思います。画面左のタブから、Virtualization => Catalog を選択するとデフォルトで利用可能なVMのテンプレートが表示されるので、RHEL9のテンプレートを選択します。 Customize VirtualMachineを選択しVMのカスタマイズを行います。 ここで起動するVMの様々なパラメーターを設定することが可能です。LinuxについてはCloud-initスクリプトを使い起動時の設定を行うことができます。 今回はパスワードでSSHするためcloud-initに以下の設定を追加しました。検証以外の用途で使う場合は必ずSSHの公開鍵を登録するようにしましょう。 userData: |- #cloud-config user: cloud-user password: akabo-blog chpasswd: { expire: False } ssh_pwauth: true #追加 設定が完了したので"Create VirtualMachine"を押しVMを作成します。しばらく待つとVMが起動します。 それではこのVMに対しSSHしましょう。 以下のコマンドを実行します。"oc login"した状態で"virtctl ssh"を使用するとポートフォワードにより対象のVMへSSHできます。 # virtctl ssh --namespace test-kvirt2 --username cloud-user rhel9-akabo The authenticity of host 'vmi/rhel9-akabo.test-kvirt2 (<no hostip for proxy command>)' can't be established. ED25519 key fingerprint is SHA256:VRcNfaQ39FemkRzpzWACaAXgp1ROzwuYBwNFbxCQ4Xw. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'vmi/rhel9-akabo.test-kvirt2' (ED25519) to the list of known hosts. cloud-user@vmi/rhel9-akabo.test-kvirt2's password: Register this system with Red Hat Insights: insights-client --register Create an account or view all your systems at https://red.ht/insights-dashboard [cloud-user@rhel9-akabo ~]$ 無事SSHすることができました。 今回はこのVM上でnginxを起動し、Routeからアクセスしてみたいと思います。 VMにSSHした状態で以下を実行します。 ## rootユーザーになりsubscription-managerに登録 # sudo su- # subscription-manager register ## nginxのインストールと起動 # yum install -y nginx # systemctl enable --now nginx ## 確認 # systemctl status nginx ここまでできたらSSHを抜け、Service、Routeを作成します。 Serviceは"virtctl expose"で簡単に作成できます。 # virtctl expose vmi rhel9-akabo --name vm-svc --port 27017 --target-port 80 Service vm-svc successfully exposed for vmi rhel9-akabo # oc get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE vm-svc ClusterIP 172.30.11.182 <none> 27017/TCP 25s # oc expose svc/vm-svc route.route.openshift.io/vm-svc exposed 公開されたRouteにアクセスすると無事VM上でホストされるnginxにアクセスできました。 まとめ 今回はOpenShift Virtualizationについて紹介しました。ベアメタルサーバーの準備など、試すのには若干のハードルがありますが、機能としては非常に面白いんじゃないかと思います。 またより詳しい機能の紹介などしていければと思います。