6月 282023
 

自分でも、強引な手法だなぁ。と、思ってしまいます。

まず、 Windows11 Pro 上で動作している Hyper-V サーバがあります。その下で FreeBSD/amd64 13.2-RELEASE が動作しております。

Hyper-V の母艦である Windows11 Pro は NotePC なので WiFi 使ったり RJ45 使ったり VPN 使ったりするので Hyper-V のサーバとクライアントの間の「仮想スイッチ」はブリッジ、それはつまりは仮想スイッチマネージャの「接続の種類」で[外部ネットワーク]を選択することはほぼ不可能(利用する物理ネットワークによって毎回変更する必要がある)なのであります。

母艦側で複数のネットワークアダプタを利用する場合は、どうしても NAT、それはつまりは[内部ネットワーク]をチョイスするしかないのであります。

Hyper-V の仮想スイッチが NAT になると、色々と制約を受けます。まず、 DHCP を克服する必要があります。これについてはウェブ上に、設定方法について、色々書かれたドキュメントがあるのでそちらを参考にしてください。

いろいろ設定すると Hyper-V のクライアント (俗に『仮想マシン』と、言いますな) は NAT 配下で、固定 IPv4 アドレスで動作させることが可能になりました。

Hyper-V の母艦からは仮想マシンに対して ssh などのアクセスができるようになります。が、当然リモートのマシンからは Hyper-V 管理下の仮想マシンへはアクセスできません。

あと、仮想マシンのネットワークは NAT が入るのでこれまた色々と制約受けます。上に書いた、外部からのアクセスができません。他に NFS マウントできません。 gif トンネル張れません。とか・・。

 
そもそも、 Hyper-V の母艦の外部のネットワークに IPv6 がない場合、仮想マシンは IPv6 を利用することができません。あれ? Hyper-V の NAT 仮想スイッチで IPv6 喋れるのか?

どうして仮想マシン側に IPv6 が欲しいのだ? -> だって、IPv4 は NAT なので上記の制約受けるじゃん。それなら、トンネルでも良いから IPv6 でどっかーんっ!! と抜けていきたいじゃん。

と、いうのが発想の原点にあります。

と、いうことで図を書いてみました。

簡単に説明します。

  • 真ん中に Windows11 Pro の Hyper-V サーバがいます
  • Windows11 Pro の Hyper-V サーバは上位のネットワークとは IPv4 アドレスのみが降ってくるネットワークに接続しています
  • Hyper-V 配下の仮想マシンは FreeBSD/amd64 13.2-RELEASE です
  • Hyper-V サーバと仮想マシンの間には NAT の仮想スイッチが入っています
  • NAT の仮想スイッチは仮想マシンが固定 IPv4 アドレスを利用できるようにしています

 
これが現状、フツーにできる Hyper-V 環境です。この状態で、仮想マシン側に IPv6 グローバルアドレスを付加して、IPv4 の NAT 超えをあきらめ、IPv6 で外部との通信をできるようにして色々楽しめる状態にします。

  • 仮想マシンの FreeBSD は wireguard で外部に接続します
  • wireguard で作成した VPN トンネルの中に gif トンネルを通します
  • 仮想マシンに IPv6 が通ったので様々通信ができるようになります

 
トンネルの多段ですね。
図の左側は VyOS と wireguard のサーバは別々に描かれていますが、最近の VyOS を使うと一個にまとめられると思います。僕の環境では未だに VyOS-1.1.8 を利用していますので wireguard は別サーバに構築しました。

 
wireguard と VyOS の置き場所によって仮想マシンの IPv6 の通信速度は圧倒的に変わります。色々考えてみてください;-)。

と、いうことで、次に設定を見ていきましょうか。

 
1. 仮想マシン側の wireguard の設定
今回、仮想マシンは FreeBSD/amd64 13.2-RELEASE なので wireguard は ports から簡単に入ります。 net/wireguard をインストールしましょう。もしかしたら wireguard-kmod-0.0.20220615_1 がインストールされるかもしれませんが、実際には利用しません。

wireguard-kmod-0.0.20220615_1 をインストールした場合には /boot/modules/if_wg.ko がインストールされますが 13.2-RELEASE からは OS 標準で /boot/kernel/if_wg.ko が用意されています。フツーに wireguard_enable=”YES” すると /boot/kernel/if_wg.ko が利用されます。

僕の環境では wireguard-2,1 、wireguard-kmod-0.0.20220615_1 、 wireguard-tools-1.0.20210914_1 がインストールされました。

次に設定です。

が、その前に、まず最初に wireguard では鍵のペアを作成する必要があります。

# cd /usr/local/etc/wireguard/
# wg genkey > server.key
# wg pubkey < server.key > server.pub
#
# wg genkey > client.key
# wg pubkey < client.key > client.pub
# 
# chmod 600 *.key 
#

 
サーバ側とクライアント側のキーの両方を作成しましたが、これを利用します。

続いて設定を見ていきます。今回は wireguard のトンネルを一個作成するだけですので wg0.conf のみです。複数に接続する場合は wg1.conf wg2.conf などと設定フアイルを複数書きます。

・/usr/local/etc/wireguard/wg0.conf

[Interface]
PrivateKey = 8LJDuAU9Ste2ySHRmgHnOAyk+E4ZMbw+vCBbMHXMbZU=
Address = 192.168.254.11/32

[Peer]
PublicKey = 17CucZLVbS1Jt/8LXREvrDGEnYunIA2RYYjlJhxftlk=
AllowedIPs = 192.168.254.1/32, 10.20.65.201/32
Endpoint = 10.20.65.15:51820

 
[Interface] の 設定は自分側の設定を記載します。

  • PrivateKey は作成した鍵ファイルの client.key の内容を記載します。
  • Address は wg0 インターフェイスに付加する IPv4 アドレスです。 wireguard で接続するためだけに利用するので /32 で指定します。ただ、サーバ側と同じレンジが良いでしょう。

続いて [Peer] の設定で、これは wireguard のサーバ側に関する設定になります。

  • PublicKey は server.pub の内容を記載します。
  • AllowedIPs は wireguard サーバの wg0 インターフェイスの IPv4 アドレスを記載します。
  • AllowedIPs にはもう一個 IPv4 アドレスを記載します。 gif トンネルの接続先 IPv4 アドレスを “,” で区切って記載します。詳細についてはあとで書きます。
  • Endpoint は wireguard が動作しているサーバの IPv4 アドレスと Port 番号を記載します。

 
だいたいこんな感じで良いと思います。非常に簡単な設定ですね。ただ、一点。 [Peer] 側の設定の AllowedIPs の設定がクセモノです。
AllowedIPs に wireguard サーバ側の wg0 インターフェースの IP アドレスを書いただけでは wireguard サーバとしか通信ができません。

『wireguard サーバ側で NAT の設定を入れてないから他のネットワークと通信できんのか?』と思い、wireguard サーバ側の設定を色々いじってしまうのですが、そうではなく、クライアント側がどこと通信したいのか、AllowedIPs に記載することにより通信が可能となります。

今回は wireguard トンネルを抜けいてったあと gif トンネルを張りたいので VyOS の IPv4 アドレスを AllowedIPs に追加しました。 10.20.65.0/24 と通信したい場合は AllowedIPs には wireguard サーバの wg0 インターフェースの IPv4 アドレスと 10.20.65.0/24 を追加で書けば良いです。

で、自動起動するように設定を書きます。 /boot/loader.conf に明示的に if_wg_load=”YES” と書かずともカーネルモジュールがロードされます。

・/etc/rc.conf

wireguard_enable="YES"
wireguard_interfaces="wg0"

 
これでクライアント側の設定は完了です。

次にサーバ側の設定を見ていきましょう。

 
2. wireguard のサーバ側の設定
上のほうでも書きましたが、 wireguard のサーバは自前で用意せずとも VyOS で利用可能です。 VyOS-1.3 以降から wireguard に対応したんだったかな? 詳細なバージョンは覚えていませんが・・。

今回、僕は wireguard サーバも FreeBSD 側で作成しました。インストールは ports からですが、クライアント側のと同様のモノをインストールしました。

鍵は既に作成したので、それを使いまわしましょう。すると、サーバ側で用意するのは設定フアイル一個のみです。

・/usr/local/etc/wireguard/wg0.conf

[Interface]
PrivateKey = aJbypbTUy5LB+EIPd6FHf25D2rbTw9l+x5o7fBLL+Ec=
Address = 192.168.254.1/24
ListenPort = 51820

[Peer]
PublicKey = F8kvub6jdPnl99rISnffYtilNVEswDUo+sqGWzc7FRY=
AllowedIPs = 192.168.254.11/32

 
[Interface] の 設定は自分側の設定を記載します。

  • PrivateKey は server.key の内容を記載します。
  • Address は wg0 インターフェイスに付加する IPv4 アドレスです。

続いて [Peer] の設定で、これは wireguard のサーバ側に関する設定になります。

  • PublicKey は client.pub の内容を記載します。
  • AllowedIPs は wireguard クライアントの wg0 インターフェイスの IPv4 アドレスを記載します。

 
以上で設定は完了です。 /etc/rc.conf にクライアントのと同じ設定を追加して wireguard を起動します。サーバ側とクライアント側の両方で service wireguard start を実行すると wg0 インターフェースが生えてきます。

双方の wg0 の IPv4 アドレスに ping を打ち、到達性を確認します。この時点で ping が当たらない場合は設定情報が間違っています。なおしてください。そもそも wireguard のサーバとクライアントの物理インターフェース間で通信できることを確認します。

 
双方の wg0 に付加された IPv4 アドレスに ping が当たるようになったら OK。クライアント側の [Peer] 設定の AllowedIPs に記載した VyOS の IPv4 アドレスに ping が当たることを確認します。
上にも書いた通り 10.2.65.201 だけでなく、もっと他のマシンにも接続したい場合はクライアント側で設定してみてください。

 
最後に wireguard の wg0 トンネルをぬけて gif トンネルを掘ります。 gif トンネルが掘れると Hyper-V の仮想マシンにはグローバルな IPv6 アドレスが付加されます。 IPv6 を利用することにより IPv4 で受けていた NAT の制約から開放されることになります。パチパチパチっ!!

と、いうことで IPv6 gif トンネルの設定については以前書いているのでそつらを参考にしてください。

IPv6 Over IPv4 トンネルを dtcp から VyOSへ。

 
移動する PC 上で Hyper-V を動かしたとき、その下で動作する仮想マシンはネットワーク的に色々な制約を受けるモノです。今回は多段トンネルでその問題を解決してみました。

  • 仮想マシンは NAT ネットワークで gif トンネルが利用できないので wireguard なトンネルを掘る
  • wg0 を抜けて gif トンネルを掘る
  • IPv4 は NAT ネットワークなので IPv6 の直アクセスで NAT 問題を回避
  • 仮想マシンに IPv6 アドレスが付加されたので仮想マシンのネットワークはもーサイコーっ!!

 
こんな感じの手順で今回の構成を構築しましたが、フツーここまでやる?

ってか、まあ、Hyper-V が動作するのは WindowsOS なので、ネットワーク的に色々な制約が多すぎてやりたいことができない。
ネットワークはトンネルで抜けて色々やりましょう。と、いう雰囲気ですが・・。

一点だけ。まだ検証してないし、計算が必要だと思うのですが・・。 MTU って、一体いくつになるの? f(^^;;。

4月 292023
 

以前のエントリで「Dockerを利用してWordPressを動作させます。それもブリッジを用いて。」や「AlmaLinux8 の VRF。」なんてのを書いていますが、それの改訂版です。

 
なんか、色々調べてみると Linux 方面では bridge を有効にするには全部で三つの方法があるのだそうな。

  • bridge-utils を使う
  • nmcli を使う
  • ip link set dev を使う

 
以前の経験から、古いアーキテクチャである bridge-utils は既に rpm にもなっていない。かつ、IPv6 通信ができない。と、いうことでもう利用してはいけないのであります。IPv6 通信ができない。と、いうのは上記のリンクにも書いています。

nmcli を利用すると、設定情報は Almalinux8 の場合は /etc/sysconfig/network-scripts/ 配下にファイルとして保存してくれるんだけど、これが Almalinux9 になると、保存先が変わって記載方法も変わるのであまり使いたくない・・。

直感的に『あぁ。設定しているなぁ。』と感じるのは ip link set dev なコマンド達でしょうか。今回はこれをメインで bridge 設定をしていきたいと思います。

 
がっ!!

まず、 VRF の設定をしてルーティングテーブルを複数持つ環境を構築し、Docker コンテナを NAT なしで起動するための bridge 化。そしてっ!! 以前利用していた bridge-utils を捨てたのは Docker コンテナで IPv6 を利用するため。

と、いう、これはまさしく地獄絵図;-P。

 
どんな状態になっているか?と、いうと・・。

$ nmcli dev status
DEVICE           TYPE      STATE            CONNECTION      
eth0             ethernet  接続済み         eth0            
eth1             ethernet  接続済み         eth1            
eth2             ethernet  接続済み         eth2            
eth3             ethernet  接続済み         eth3            
eth4             ethernet  接続済み         eth4            
br0              bridge    接続済み (外部)  br0             
br1              bridge    接続済み (外部)  br1             
br4              bridge    接続済み (外部)  br4             
mgmt0            vrf       接続済み (外部)  mgmt0           
lb0              vrf       管理無し         --              
docker0          bridge    接続済み (外部)  docker0         
docker_gwbridge  bridge    接続済み (外部)  docker_gwbridge 
veth32347c8      ethernet  管理無し         --              
lo               loopback  管理無し         --              

 
多少並び直していますが、インターフェースはこれだけあります。結構多いほうだと思います;-)。

一応、表にしてみました。今回は絵はナシで・・。

物理 IF VRF bridge IPv4 IPv6 説明
eth0 br0 192.168.22.0/24 2001:470:fe36:face::/64 外部からのアクセス用で Docker ホストとコンテナで同一セグメント
eth1 br1 192.168.52.0/24 2001:470:fe36:cafe::/64 DB アクセスなどのバックヤード用で Docker ホストとコンテナで同一セグメント
eth2 192.168.111.0/24 2001:470:fe36:111::/64 同一ネットワーク上の NFS サーバへのアクセス用
eth3 mgmt0 192.168.1.0/24 2001:470:fe36:1::/64 外部からの ssh などのメンテナンス用
eth4 lb0 br4 192.168.202.0/24 ロードバランサ配下のためなし ロードバランサ用閉域セグメントで Docker ホストとコンテナで同一セグメント

 
セグメントはそれぞれ記載しましたが、インターフェースにつける実際のアドレスは 218 です。 IPv4/IPv6 共に 218 を設定しています。

 
Docker ホストにはインターフェースが全部で 5 個。
VRF を設定するルーティングテーブルは全部で 3 個。 eth0,eth1,eth2 が所属する default のルーティングテーブル。 eth3 はメンテナンス用なので mgmt0。 eth4 はロードバランサセグメントなので lb0。

5 個のインターフェースの内、Docker コンテナでも同一セグメントを利用するために bridge が存在していますが、それは 3 個。
Docker コンテナのネットワーク接続は色々なパータンを想定。

  • Service-Segment への接続みのウェブサーバ
  • Service-Segment と Access-Segment への接続する WordPress 用サーバ
  • LB-Segment への接続のみの負荷分散を考慮したウェブサーバ
  • LB-Segment と Access-Segment への接続するウェブアプリケーションサーバ

 
Service-Segment は外部からの直接アクセスを想定。 Access-Segmen はバックヤードで DB 接続や tomcat への接続を想定。 LB-Segment はロードバランサ配下の閉域セグメント。

ロードバランサは上位に apache を用意しましたが、上位のロードバランサからの閉域セグメントとして VRF を設定して、かつ、それを bridge して Docker コンテナに直接アクセスするように設定しました。

それにしても、フツー、ここまでするかねぇ?! みたいな;-)。

 
では、実際に設定を見てい行きましょう。

まず、 /etc/sysconfig/network-scripts/ 配下の ifcfg-eth* のファイルですが、フツーの設定で問題ありません。ルーティングテーブルが存在するインターフェースの設定ファイルのみに GATEWAY= や IPV6_DEFAULTGW= を指定してあげてください。
rule-eth* や route-eth* は今回は用意しませんでした。

 
1. VRF の設定
VRF の設定は /etc/rc.local 内に記載します。

ip link add dev mgmt0 type vrf table 10
ip link set dev mgmt0 up
ip link set dev eth3 master mgmt0
ip link set dev eth3 up
ip route add default via 192.168.1.1 table 10
ip route add ::/0 via 2001:470:fe36:1::1 table 10

ip link add dev lb0 type vrf table 4
ip link set dev lb0 up
ip link set dev eth4 master lb0
ip link set dev eth4 up
ip route add default via 192.168.202.1 table 4

route delete default
route delete default
route delete default
route add default gw 192.168.22.1

route delete -host 192.168.1.1
route delete -host 192.168.202.1

ip route del ::/0 via 2001:470:fe36:1::1
ip route del ::/0 via 2001:470:fe36:face::1
ip route del 2001:470:fe36:1::1/64
route -6 add default gw 2001:470:fe36:face::1

sysctl -w net.ipv4.tcp_l3mdev_accept=1
sysctl -w net.ipv4.udp_l3mdev_accept=1

 
こんな感じでしょうか。/etc/iproute2/rt_tables に table 4 とか 10 の名前を書いても良いですが、数値で管理する場合は不要です。

ルーティング設定を色々いじっているのは、ルーティングテーブルが美しくならないのでコマンドで正しいルーティング情報にしているためです。

こうなっているのが美しいかなぁ・・。と、思っています。

$ ip route show
default via 192.168.22.1 dev eth0 
192.168.22.0/24 dev eth0 proto kernel scope link src 192.168.22.218 metric 100 
192.168.52.0/24 dev eth1 proto kernel scope link src 192.168.52.218 metric 101 
192.168.111.0/24 dev eth2 proto kernel scope link src 192.168.111.218 metric 102

$ ip route show table 10
default via 192.168.1.1 dev eth3 
broadcast 192.168.1.0 dev eth3 proto kernel scope link src 192.168.1.218 
local 192.168.1.218 dev eth3 proto kernel scope host src 192.168.1.218 
broadcast 192.168.1.255 dev eth3 proto kernel scope link src 192.168.1.218 
 
$ ip route show table 4
default via 192.168.202.1 dev eth4
broadcast 192.168.202.0 dev eth4 proto kernel scope link src 192.168.202.218 
local 192.168.202.218 dev eth4 proto kernel scope host src 192.168.202.218 
broadcast 192.168.202.255 dev eth4 proto kernel scope link src 192.168.202.218 

$ ip -6 route show
::1 dev lo proto kernel metric 256 pref medium
2001:470:fe36:111::/64 dev eth2 proto kernel metric 102 pref medium
2001:470:fe36:cafe::/64 dev eth1 proto kernel metric 101 pref medium
2001:470:fe36:face::/64 dev eth0 proto kernel metric 100 pref medium
fe80::/64 dev eth0 proto kernel metric 1024 pref medium
fe80::/64 dev eth1 proto kernel metric 1024 pref medium
fe80::/64 dev eth2 proto kernel metric 1024 pref medium
fe80::/64 dev eth3 proto kernel metric 1024 pref medium
default via 2001:470:fe36:face::1 dev eth0 metric 1 pref medium

$ ip -6 route show table 10
anycast 2001:470:fe36:1:: dev eth3 proto kernel metric 0 pref medium
local 2001:470:fe36:1::218:1 dev eth3 proto kernel metric 0 pref medium
anycast fe80:: dev eth3 proto kernel metric 0 pref medium
local fe80::8785:99b6:f03b:cf5e dev eth3 proto kernel metric 0 pref medium
multicast ff00::/8 dev eth3 proto kernel metric 256 pref medium
default via 2001:470:fe36:1::1 dev eth3 metric 1024 pref medium

$ ip -d link show type vrf
7: mgmt0:  mtu 65575 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 56:64:d2:f2:ee:55 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 1280 maxmtu 65575 
    vrf table 10 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
8: lb0:  mtu 65575 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 2e:68:9e:22:5f:0e brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 1280 maxmtu 65575 
    vrf table 4 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 

 
VRF しているインターフェースのルーティング情報が乗っていると削除して、正しいルーティング情報に直すので roure del したり route add しています。上記になっているのが、僕は一番美しいルーティングテーブルだと思っているのであります。
この辺り、nmcli だとちゃんとやってくれるのかなぁ?

 
VRF は eth0,eth1,eth2 の default テーブルと、eth3 の mgmt0 なテーブル、そして、eth4 のロードバランサ用テーブルと、合計三つのデーブルを作成しました。外部からアクセスすると、おのおののインターフェースから入って、入ってきたところから出ていきます。

 
さてと。 VRF で複数のルーティングテーブルがあると、例えば自分のサーバから外部のサーバに ssh したい場合、default のルーティングテーブルから出ていってしまいます。

本来、メンテナンス用の eth3 のインターフェースがあるのですが、VRF しているのでフツーに ssh するとへんなことになります。そんなときはインターフェース指定でコマンドを実行するのが良いですね。 そんなときに利用するのが if vrf exec コマンドです。

$ traceroute -n 192.168.1.217
traceroute to 192.168.1.217 (192.168.1.217), 30 hops max, 60 byte packets
 1  192.168.22.1  0.416 ms  0.460 ms  0.456 ms
 2  192.168.1.217  0.659 ms  0.654 ms *
$ ip vrf exec mgmt0 traceroute -n 192.168.1.217
traceroute to 192.168.1.217 (192.168.1.217), 30 hops max, 60 byte packets
 1  192.168.1.1  0.405 ms  0.323 ms  0.324 ms
 2  192.168.1.217  0.665 ms  0.668 ms  0.687 ms
$ ip vrf exec mgmt0 ssh 192.168.1.217
>

 
上のは default のルーティングテーブルの gateway である 192.168.22.1 経由で出ていきますが、 ip vrf exec “VRF インターフェース名” を付加してコマンドを打つと eth3 の VRF mgmt0 の gateway を経由して通信できます。 FreeBSD 的には setfib コマンドがありますが、それと同等機能ですね。

VRF の設定はこれにて完了。これは以前書いたものとほぼ一緒かな。

 
2. bridge の設定
次に Docker ホストと Docker コンテナの間で同一のセグメントを利用できるようにする bridge の設定をします。一番上に書きましたが「Dockerを利用してWordPressを動作させます。それもブリッジを用いて。」のエントリの改訂版になります。

bridge-utils はもう捨てて ip link set dev コマンドを利用して設定します。

まず、bridge インターフェースを生成するための docker network create コマンドの実行から。

# docker network create Service-Segment \
     -o "com.docker.network.bridge.name"="br0" \
     --driver=bridge \
     --subnet 192.168.22.0/24 \
     --gateway 192.168.22.218 \
     --ipv6 \
     --subnet 2001:470:fe36:face::/64 \
     --gateway 2001:470:fe36:face::218:1

# ifconfig br0 inet6 del fe80::1/64

 
もう bridge-utils を捨てたので docker network create で生成するネットワークは IPv4/IPv6 のデアルスタクに対応にします。コンテナも IPv4/IPv6 のデアルスタク対応です;-)。

docker network create で –ipv6 を指定するとリンクローカルアドレスに fe80::1 が自動的に付加されます。fe80::1 はコンテナが IPv6 を利用したときの gateway になるんだそうな。強引に付加されます。

bridge なネットワークなので複数の Docker ホストがあった場合、全ての Docker ホストがリンクローカルアドレスに fe80::1 を利用すると IPv6 duplicate address fe80::1 てな感じになり、同一セグメント上のサーバ間の通信ができなくなります。なので、ifconfig br0 inet6 del して削除します。そもそも既に由緒正しいリンクローカルアドレスが付加されているので fe80::1 はまるっきり不要です。

次に br0 と物理インターフェース eth0 を bridge します。

# ip link set dev br0 up
# ip link set dev eth0 promisc on
# ip link set dev eth0 up
# ip link set dev eth0 master br0
# ifconfig eth0 0.0.0.0 up
# ifconfig eth0 inet6 del 2001:470:fe36:face::218:1/64 up

# route add default gw 192.168.22.1 dev br0
# ip route del ::/0 via 2001:470:fe36:face::1
# route -6 add default gw 2001:470:fe36:face::1 dev br0

 
上から順に説明すると、

  • docker network create で生成した br0 を UP します
  • eth0 のプロミスキャス・モードを有効化します
  • eth0 を UP します
  • eth0 と br0 をブリッジ化します
  • br0 に IPv4/IPv6 アドレスが付加されるので eth0 側から削除します
  • 最後にルーティング情報を設定します

こんな感じでしょうか。

ロードバランサセグメント用の設定も書いておきます。

# docker network create LB-Segment \
    -o "com.docker.network.bridge.name"="br4" \
    --driver=bridge \
    --subnet 192.168.202.0/24 \
    --gateway 192.168.202.218

# ip link set dev br4 up
# ip link set dev eth4 promisc on
# ip link set dev eth4 up
# ip link set dev eth4 master br4
# ifconfig eth4 0.0.0.0 up

# ip link set dev lb0 up
# ip link set dev br4 master lb0
# ip link set dev br4 up
# ip route add default via 192.168.202.1 table 4

 
こちらは閉域ネットワークです。でもって IPv6 がないのでシンプルです。外部からロードバランサ経由でアクセスがあったものは default gateway に戻っていきます。
ちなみに eth4, br4 の brige インターフェースは lb0 という VRF でもあるわけですが、bridge 生成時に VRF を意識する必要は全くありません。すげ;-)。

ちなみに eth1, br1 の組み合わせも bridge して docker network で Access-Segment として create しますが、今回は割愛します。

 
bridge を終了するコマンドも記載しておきます。

# ip link set eth0 promisc off
# ip link set eth0 down
# ip link set dev eth0 nomaster
# ip link delete br0 type bridge

# docker network rm Service-Segment

# ifconfig eth0 192.168.22.218/24
# ifconfig eth0 inet6 add 2001:470:fe36:face::218:1/64

# route add default gw 192.168.22.1 dev eth0
# ip route del ::/0 via 2001:470:fe36:face::1
# route -6 add default gw 2001:470:fe36:face::1 dev eth0

# ping -q -c 3 192.168.22.1 > /dev/null 2>&1

 
こちらも一応、説明しておきます。

  • eth0 のプロミスキャス・モードをオフにします
  • eth0 を DOWN してから eth0 と br0 の bridge を削除します
  • br0 を削除するので docker network rm を実行します
  • eth0 に IPv4/IPv6 アドレスを付加します
  • ルーティング情報を更新します
  • 最後に ping を打つのは上位のルータが保持している古い MAC アドレスを書き換えるため

こんな感じでしょうか。

これで VRF でルーティングテーブルが個別なネットワークを bridge して Docker コンテナが利用できる環境が整いました。

 
3. IPv4/IPv6 デアルスタク対応コンテナの起動
最後に Docker コンテナの使い方について書いておきます。何回も書いている通り bridge-utils を捨てて ip link set dev コマンドに移行したので Docker コンテナは IPv4/IPv6 のデアルスタクで動作させられます。

起動はこんな感じで。もっと複雑な起動方法については「Dockerを利用してWordPressを動作させます。それもブリッジを用いて。」を参照してください。

$ docker run -d \
 --net=Service-Segment --ip=192.168.22.246 --ip6=2001:470:fe36:face::218:246 \
 -v /opt/docker/contents/web-service01/html:/var/www/html \
 -v /opt/docker/contents/web-service01/conf.d:/etc/httpd/conf.d \
 -v /opt/docker/contents/web-service01/logs:/var/log/httpd \
 --log-driver=syslog --log-opt syslog-facility=local3 --log-opt tag=docker/{{.Name}}/{{.ID}} \
 --name web-service01 \
 web-service01:1 /usr/sbin/httpd -DFOREGROUND
$
$ docker exec -it web-service01 /bin/bash
[root@3383ac655b6b /]# ifconfig eth0
eth0: flags=4163  mtu 1500
        inet 192.168.22.246  netmask 255.255.255.0  broadcast 192.168.22.255
        inet6 2001:470:fe36:face::217:246  prefixlen 64  scopeid 0x0
        inet6 fe80::42:c0ff:fea8:16f6  prefixlen 64  scopeid 0x20
        ether 02:42:c0:a8:16:f6  txqueuelen 0  (Ethernet)
        RX packets 43  bytes 4322 (4.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9  bytes 806 (806.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@3383ac655b6b /]# exit
$

 
Docker ホストと Docker コンテナの間に NAT が入ってない (それはつまりは docker0 インターフェースを利用していない) 純粋な IPv4/IPv6 アドレスを利用したコンテナへのアクセスができるようになりました。 docker0 インターフェースを利用してないので /etc/docker/daemon.json への ipv6 true や fixed-cidr-v6 の設定も不要です。

思う存分 IPv4/IPv6 デアルスタクな Docker コンテナを楽しめる環境が整いました;-)。

IPv4 は NAT だけど IPv6 は腐るほど持っているので、Docker コンテナでも IPv6 が利用できるほうが良いですよねぇ;-)。

ちなみにですが、拾ってきた Docker イメージのうち portainer, registry, docker-registry-frontend などは、根こそぎ IPv6 でのアクセスが可能です;-)。

 
さてと。今回のお題目。

ポリシールーティングではなく VRF してルーティングテーブルをわけてから bridge して Docker ホストと Docker コンテナで同一ネットワークを利用し、更に IPv4/IPv6 のデアルスタクで Docker コンテナを運用する。

と、いうのができました。僕としてはもう、ほぼほぼこれで満足です。最終目的かもしれないです。ふぅ。

まぁ、実装するのは簡単で、これを実運用に持っていくには対障害対応とか色々必要となってくるのですが、色々と設定が必要そうです。

あと、Swarm を利用を利用して、当該 の Docker ホストがダウンしたときはコンテナは移動し、ダウンした Docker ホストのネットワーク環境などを整え終わったら再度サービスに復活させるとかの対応も必要かも。

 
ひとまずこれでヨシとしよう。

ふぅ。楽しかった;-)。

3月 282023
 

三ヶ月に一回 Let’s Encrypt の証明書の更新があるわけだけど、今回はハマった・・。なのでちょっと書いておきます。

Let’s Encrypt の SSL 証明書更新後はちゃんと openssl コマンドを利用して確認するんだけど・・。

 
・https の確認

$ openssl s_client -connect running-dog.net:443 | openssl x509 -enddate | grep notAfter

 
・sendmail の確認

$ openssl s_client -connect mail.running-dog.net:587 -starttls smtp | openssl x509 -noout -dates

 
・imaps の確認

$ openssl s_client -connect mail.running-dog.net:993 | openssl x509 -noout -dates

 
まぁ、これらのコマンドを打って確認できるのは証明書の日付くらいか・・。サービスが実際に正常動作しているかは、やはり、ログを見ないと解らないか・・。

 
今回の Let’s Encryp の SSL 証明書更新後のハマりポイント。

 
1. Apple のメールアプリが imaps サーバに接続できなくなった
macOS や iOS などのメールアプリが根こそぎ imaps サーバに接続できなくなった。 macOS に Thunderbird をインストールしてそこから imaps サーバにアクセスすると特に問題なくアクセスできる・・。

macOS のメールアプリからアクセスすると、ログには以下のように残っていました。
あぁ・・。 moacOS 側のアプリのキャプチャ無くてすみません・・。

imapd-ssl[39496]: ip=[<略>], couriertls: connect: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher

 
なんか、おかしい・・。macOS 上の SSL 証明書を「キーチェーンアクセス」から削除してもダメ・・。

まぁ、ログを見ると cipher が足りない風な感じはしているのよねぇ・・。

と、いうことで Apple 製品の SSL 系 cipher についての記載を調べてみると以下の URL が見つかりました。

https://support.apple.com/ja-jp/guide/security/sec100a75d12/web

上記を読むと『 ECDHE_ECDSA_AES および ECDHE_RSA_AES』が必要なようです。僕は imap サーバに courier-imap を利用している(この記事の執筆時点にインストールされているバージョンは courier-imap-5.2.2 です)のだけど、この二つの cipher を /usr/local/etc/courier-imap/imapd-ssl の設定に追加しました。

こんな感じになりました。

TLS_CIPHER_LIST="ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES128-SHA:DES-CBC3-SHA:ECDHE_ECDSA_AES:ECDHE_RSA_AES"

 
随分と長くなりました。で Apple 製品のメールクライアントからアクセスすると無事に接続できるようになったのでありました。ふぅ・・。

 
2. sendmail が他のメールサーバから Relay を受け付けなくなった
imapd に接続できないのはまぁ、良いんだけど、こっちはダメージでかいですね。届くはずのメールが届かないのでおかしいなぁ・・。と、思っていたら sakura インターネットからのメールがエラーになっていて・・。

ログを確認すると、こんな感じ。

sm-mta[76876]: STARTTLS=server, error: accept failed=-1, reason=no shared cipher, SSL_error=1, errno=0, retry=-1, relay=<略>.sakura.ne.jp [<略>]

 
なんか、こちらも cipher が足りない感じ。orz

しょうがないので /etc/mail/sendmail.cf の O CipherList をちょっと変更。

#O CipherList=ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:
O CipherList=ALL
#O CipherList=ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:

 
当初設定したていたのはコメントアウトしてある一番上の行。どの cipher が足りないのか解らないので真ん中の O CipherList=ALL 行を有効にして全ての cipher で対応できるようにして、ログを確認。そーすると、ちらほらメールを受信し始めました。ふぅ。
で、更にログを眺めいてたら以下のログを発見。

sm-mta[33084]: STARTTLS=server, relay=<略>.sakura.ne.jp [<略>], version=TLSv1.2, verify=NO, cipher=ECDHE-ECDSA-AES256-GCM-SHA384, bits=256/256

 
なるほど。新たに ECDHE-ECDSA-AES256-GCM-SHA384 を追加する必要があるのね。と、いうことで O CipherList の設定は一番下の行にして、sendmail を再起動したら無事に復活したのでありました。

 
ふぅ。それにしても Let’s Encrypt の SSL 証明書を更新しただけで、メールの送受信ができなくなるとは恐ろしいことだぁ・・。

https は全然問題なかったのだが・・。

それにしも証明書の更新後の確認は日付だけでなく、ログの確認であるとか、実際にポートに接続して確認する必要があるかなぁ・・。今後の課題ですな。

 
と、いいつつ Let’s Encrypt だけでなく google や Apple は SSL 証明書の期限をさんが月にしよう。キャンペーンをしているけど・・。大変になる頻度が増えるかな。

1月 292023
 

タイトルが大げさですなぁ;-)。

前回のエントリで構築した VRF が動作する AlmaLinux 8.7 ですが、その AlmaLinux8 は実は Docker ホストとしても動作しています。

 
これも、以前のエントリで「Docker Registry を作る。」というのを書いていますが、このホストと同一となります。

 
今回はこの Docker ホストに Docker コンテナを複数起動して、外部からアクセスできる環境を構築します。
Docker コンテナに対して外部からアクセスするためのポート番号は 80 番 (別に 443 でも良いのだけど、証明書関係が面倒だったので、Port:80 で許してちょんまげ;-) とします。しかし、複数の Docker コンテナが全て Port:80 番で待ち受けるためには NAT 環境では無理です。

今回は Docker ホストとコンテナ間をブリッジで接続して、Docker ホストで利用している外部接続ネットワークをコンテナでもそのまま利用するようにします。

 
図はこんな感じ。

 
VMware ESXi に二つの仮想マシンが動作しています。一個は Docker ホストで、もう一個は FreeBSD が動作して MySQL のサービスを他の仮想マシンに提供しています。

 
で、せっかくなので Docker コンテナがただ HTML なコンテンツを垂れ流す環境を構築してもつまらいないので WordPress が動作する環境を構築したいと思います。
ネタが二つ分の量だけど、大丈夫かなぁ・・。

と、いうことで、まずは Docker ホストの準備から。

とはいいつつ、以前、Docker Registry を作った環境をそのまま利用しています。ただ、 dnf update しているので多少バージョンが上がっているかも;-)。

$ cat /etc/os-release 
NAME="AlmaLinux"
VERSION="8.7 (Stone Smilodon)"
ID="almalinux"
ID_LIKE="rhel centos fedora"
VERSION_ID="8.7"
PLATFORM_ID="platform:el8"
PRETTY_NAME="AlmaLinux 8.7 (Stone Smilodon)"
ANSI_COLOR="0;34"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:almalinux:almalinux:8::baseos"
HOME_URL="https://almalinux.org/"
DOCUMENTATION_URL="https://wiki.almalinux.org/"
BUG_REPORT_URL="https://bugs.almalinux.org/"

ALMALINUX_MANTISBT_PROJECT="AlmaLinux-8"
ALMALINUX_MANTISBT_PROJECT_VERSION="8.7"
REDHAT_SUPPORT_PRODUCT="AlmaLinux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.7"

$ rpm -qa | grep docker
docker-ce-20.10.22-3.el8.x86_64
docker-ce-rootless-extras-20.10.22-3.el8.x86_64
docker-scan-plugin-0.23.0-3.el8.x86_64
docker-ce-cli-20.10.22-3.el8.x86_64

 
いろいろ端折って、既に dockerd が起動しているものとして話を進めていきます。Docker のインストールと起動については他のサイトを参考にしてください。

 
1. Docker イメージの作成

$ docker search almaLinux
NAME                       DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
almalinux                  The official build of AlmaLinux OS.             102       [OK]       
<以下略>

$ docker pull almaLinux
Using default tag: latest
latest: Pulling from library/almalinux
<略>

$ docker image ls
REPOSITORY	TAG       IMAGE ID       CREATED        SIZE
almalinux       latest    acaca326f3b3   6 weeks ago    190MB

$ docker tag almalinux:latest almalinux8:1
$ docker image rm almalinux:latest

$ docker image ls
REPOSITORY	TAG       IMAGE ID       CREATED        SIZE
almalinux8      1         acaca326f3b3   6 weeks ago    190MB

$ docker run -it --name almalinux8 almalinux:1 /bin/bash
[root@b2db6f534790 /]# 

 
docker search で AlmaLinux を探して、オフィシャルサイトから pull して、 almalinux8:1 としてタグ付けしました。
このあと、docker run してコンテナの中に入って dnf update して、必要な rpm をインストールして httpd や php もインストールして、もとの Docker イメージを大幅に更新して tag 付けして Docker イメージを完成させます。

この辺り割愛しますが、各自で頑張って Docker イメージを作成してください;-)。

$ docker stop almalinux8
$ docker container commit almalinux8 almalinux8_wordpress:1
$ docker rm almalinux8

 
apache や php をインストールした新しい almalinux8_wordpress:1 という Docker イメージができました。このイメージをベースに色々やっていきましょう。

 
2. Docker コンテナで利用するネットワークの準備
次にネットワークの設定を行います。今回は複数の Docker コンテナに Dokcer ホストと同じセグメントを割り当てます。
僕の環境の AlmaLinux 8.7 は VMware ESXi 上で動作しています。そして、ネットワーク構成は前回の「AlmaLinux8 の VRF。」に記載してある以下の構成をそのまま利用します。

 
つまり、Service-segment 側はウェブアクセスのために利用し Access-Segment は MySQL アクセスで利用します。あ。MySQL サーバは 192.168.52.204 の FreeBSD 上で動作しています。

箇条書きにするとこんな感じ。

  • WordPress が動作する予定の Docker コンテナは外部からのアクセスは Port:80 で eth0 側に到達するように構築します。
  • その Docker コンテナは外部の MySQL サーバにアクセスするために eth1 のインターフェースを利用します。
  • Docker コンテナは二つのインターフェースを持ち、それぞれが Docker ホストからのブリッジで動作します。
  • 上記の図では、Server1 が Docker ホストで、Server3 が FreeBSD で MySQL サーバが動作しています。

 
と、いうような状況ですな。

その VMware ESXi が Docker ホストに接続するポートグループは「セキュリティ」において「無差別モード」「MACアドレレス変換」「偽装転送」の全てを『承諾』に設定します。eth0 と eth1 の二つのポートグループはブリッジインターフェースを利用するので無差別モード(俗に『プロミスキャスモード』と、言いますな)を有効にする必要があります。
VMware ESXi のネットワークの設定もちゃんとしましょう。

 
3. Docker network でネットワークの作成
と、いうことで Docker コンテナが利用する二つのネットワークを docker network コマンドで作成します。

$ docker network create Service-Segment \
     -o "com.docker.network.bridge.name"="br0" \
     --driver=bridge \
     --subnet 192.168.22.0/24 \
     --gateway 192.168.22.217

# brctl addif br0 eth0
# ifconfig eth0 0.0.0.0 up
# ip link set up dev br0
# route add default gw 192.168.22.1

$ docker network create Access-Segment \
     -o "com.docker.network.bridge.name"="br1" \
     --driver=bridge \
     --subnet 192.168.52.0/24 \
     --gateway 192.168.52.217

# brctl addif br1 eth1
# ifconfig eth1 0.0.0.0 up
# ip link set up dev br1

 
Docker ホストの eth0 の IP アドレスは 192.168.22.217 で、eth1 側は 192.168.52.217 です。

こちらも説明は箇条書きで。

  • eth0 の Service-Segment と eth1 の Access-Segment の Docker ネットワークを作成します。
  • このとき Docker ホストには docker0 というインターフェースが存在していますが、利用しないのでそのまま存在しつつ、無視して問題はありません。
  • NetworkManager でブリッジインターフェースの設定はしません。 /etc/sysconfig/network-scripts/ 配下に ifcfg-br0 などのファイルを置いてもなんの意味もありません。 docker network create コマンドを実行したときに付加するオプションである -o “com.docker.network.bridge.name”=”br0” があるので、既に br0 が存在しているとエラーになります。
  • –gateway オプションに指定する IP アドレスは Docker ホストの IP アドレスになります。
  • AlmaLinux 8.7 に bridge-utils の rpm はないようなのでソースからコンパイルしてインストールします。
  • brctl addif コマンドの実行や eth0 からアドレスを消して br0 にアドレスを付加するなどは全てコマンドで行います。
$ docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
039e8158c77b   Access-Segment    bridge    local
622593f73c12   Service-Segment   bridge    local
9eb6f5610d75   bridge            bridge    local
d30c681a9f92   host              host      local
afbbadaba67f   none              null      local

 
無事に作成できるとこんな感じでしょうか。
ifconfig -a したときには br0 と br1 に IP アドレスが付いていて、eth0 と eth1 には IP アドレスはついていない状態が正解です。

これで Docker ホストとコンテナで同一セグメントを利用する環境が整いました。次にコンテナを run してみましょうかねぇ;-)。

 
4. Docker コンテナの起動
まず、いきなり WordPress を動かすコンテナを起動するのではなく Docker ネットワークに接続するために docker run してみましょう。

$ docker run -d --restart always \
 --net Service-Segment --ip 192.168.22.222 \
 -v /var/www/html/wordpress:/var/www/html \
 -v /etc/httpd/wordpress/conf.d:/etc/httpd/conf.d \
 -v /var/logs/httpd/wordpress/logs:/var/log/httpd \
 --log-driver=syslog --log-opt syslog-facility=local3 --log-opt tag=docker/{{.Name}}/{{.ID}} \
 --name almalinux8_wordpress \
 -d almalinux8:2 /usr/sbin/httpd -DFOREGROUND

 
今回は箇条書きではなく、ベタガキで・・f(^^;;。
-p 0.0.0.0:80:80 というオプションは指定しません。これ付けると一個の Docker コンテナが Docker ホストの Port:80 を掴んでしまいます。
–net で接続する Docker ネットワークと –ip でDocker コンテナが使用する IP アドレスを指定します。今回は固定 IP アドレスで 192.168.22.222 を利用します。docker network のオプションではレンジとか CIDR を指定することができて DHCP みたいな利用形態もできますが、ここでは割愛します。自分で調べてください。
-v で Docker ホスト側のディレクトリをコンテナ側にマウントしています。 Docker イメージを色々なサービスで使い回すならこれらは外出しした方が良いかなぁ。と、僕は思ったので Docker イメージには組み込んでいません。自分・環境のお好みで設定してみてください;-)。
–log-driver=syslog は syslog 出力するための設定です。 /etc/rsyslog.conf には以下を記載してください。

local3.*      /var/log/docker/container.log

 
書いたあと rsyslogd を再起動して、ついでに mkdir /var/log/docker してください。

 
と、いうことで、ここまでは Docker コンテナをブリッジインターフェース経由で外部公開するための起動方法になります。
ただ、これだと MySQL サーバにアクセスできないので、起動した almalinux8_wordpress コンテナに eth1 を生やしてあげるコマンドを投入します。

$ docker network connect Access-Segment --ip 192.168.52.222 almalinux8_wordpress

$ docker exec -it almalinux8_wordpress /bin/bash
[root@64583900cb33 /]# ifconfig -a
eth0: flags=4163  mtu 1500
        inet 192.168.22.222  netmask 255.255.255.0  broadcast 192.168.22.255
        ether 02:42:c0:a8:16:de  txqueuelen 0  (Ethernet)
        RX packets 27884  bytes 2705253 (2.5 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 257  bytes 754283 (736.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163  mtu 1500
        inet 192.168.52.222  netmask 255.255.255.0  broadcast 192.168.52.255
        ether 02:42:c0:a8:34:de  txqueuelen 0  (Ethernet)
        RX packets 36681  bytes 4887852 (4.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 586  bytes 113982 (111.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
<以下略>
[root@64583900cb33 /]# exit

 
と、いう感じで docker network connect コマンドを実行したので Docker コンテナには二つのインターフェースができました。

eth0 側は Dockerホスト外部から httpd に対してアクセスができていると思います。コンテナ起動時に指定した -v /var/www/html/wordpress:/var/www/html のオプションがありますが、 Docker ホスト側の /var/www/html/wordpress/ ディレクトリ配下に WordPress のコンテンツ一式が既にインストールされていると想定しています。

裏を返すと /var/www/html/wordpress/ 配下のコンテンツを何個かの Docker コンテナに -v でマウントさせると Docker コンテナのみで冗長構成を組むことができるのですな。 eth0 側のインターフェースは docker run 時に –ip で指定する IP アドレスを変えつつ起動したあと DNS ラウンドロビンでも良いし、ロードバランサ配下のネットワークに置いても良い。今まで複数の物理や仮想マシンが担当していた部分を Docker コンテナでマカナエル。と、いうことですな。

あ。ちなみに、僕の場合は WordPress の初期環境一式は FreeBSD の ports からインストールして、 FreeBSD 上の /usr/local/www/wordpress/ ディレクトリごと tar でかためて持ってきました;-)。簡単に初期の環境が整うです。で、 IP アドレスにアクセスすると「さぁ。わーどぷれすをいんすとーるしましょうっ!!」みたいな画面がいきなりでます;-)。
あ。実はエラーになってそう簡単には出ないか・・f(^^;;。

 
そーそー。注意点が一個。 NetworkManager を利用しないでブリッジインターフェースの設定をしているので、サーバに再起動が入ると設定が全て飛んでしまいます。 Docker ネットワークの設定は Docker が覚えていてくれるんだけど、ブリッジを設定するためのコマンド brctl addif の設定は再起動で消えてしまうので /etc/rc.local などでリカバリーする必要があるです。

 
5. Docker コンテナ の WordPress 対応
僕は普段 FreeBSD 上で WordPress を動作させているので Linux 上で動作させるには随分難儀なことでして・・。

まずは Docker イメージを作成するとこでイメージに対して httpd とか php をインストールします。そのあと、AlmaLinux8 の rpm の httpd は mod_mpm_event.so で動作しているようで、これをひとまず mod_mpm_prefork.so に変更します。
Docker イメージ内の /etc/httpd/conf.modules.d/00-mpm.conf の設定ファイルの中で LoadModule mpm_event_module modules/mod_mpm_event.so の行をコメントアウトし LoadModule mpm_prefork_module modules/mod_mpm_prefork.so の行を有効化します。
これの変更で一回 docker container commit する必要がありますな。

次に Linux で WordPress を動作させるためには php-fpm というのを起動する必要があるのだそうな。と、いうことで、これも Docker イメージ内でちょっと細工をします。

mkdir /run/php-fpm と chown 48:48 /run/php-fpm ですね。一応、この二つのコマンドを Docker コンテナ内で実行し、docker container commit して環境を整えます。

ふぅ。これで準備整ったかな?と、いうことで、 WordPress が動作する Docker コンテナを起動するスクリプトのまとめとしましょう。

#!/bin/sh

docker run -d --restart always \
 --net Service-Segment --ip 192.168.22.222 \
 -v /var/www/html/wordpress:/var/www/html \
 -v /etc/httpd/conf.d/wordpress:/etc/httpd/conf.d \
 -v /var/logs/httpd/wordpress/logs:/var/log/httpd \
 --log-driver=syslog --log-opt syslog-facility=local3 --log-opt tag=docker/{{.Name}}/{{.ID}} \
 --name almalinux8_wordpress \
 -d almalinux8:2 /usr/sbin/httpd -DFOREGROUND

docker network connect Access-Segment --ip 192.168.52.222 almalinux8_wordpress

export CONTAINER_ID=`docker ps -a | grep " almalinux8_wordpress" | awk '{print $1}'`
export DOCKER_PID=`docker inspect --format '{{.State.Pid}}' $CONTAINER_ID`

sudo nsenter -t $DOCKER_PID -n route delete default
sudo nsenter -t $DOCKER_PID -n route add default gw 192.168.22.217 eth0
sudo nsenter -t $DOCKER_PID -n ping -c 3 192.168.22.217

sudo nsenter -t $DOCKER_PID -m -u -i -n -p -- /usr/sbin/php-fpm --nodaemonize &

 
こんな感じでしょうか。

ちょっと説明を。

  • docker run で Service-Segment の Docker ネットワークに接続し、固定 IP アドレスを利用します。
  • -v で Docker ホスト側に用意したコンテンツや設定ファイルを参照するようにします。
  • コンテナの syslog を Docker ホスト側に出力します。 docker run の説明はここまで。
  • 次に、起動した almalinux8_wordpress に対して、もう一個の Docker ネットワークを接続します。
  • その次は nsenter コマンド連発です;-)。 nsenter コマンドは docker exec しなくとも Docker ホスト側から Docker コンテナに対してコマンドを投入できるコマンドです。そのためには当該の Docker コンテナのプロセス番号が必要になるのでそれを取得します。
  • コンテナ内に eth0 と eth1 が存在するので default gateway を設定してあげます。一旦削除してから再度設定。みたいな感じです。
  • コンテナ内から Docker ホストに対して ping を打つのは、コンテナ起動ごとに MAC アドレスが書き換わるので、上位のルータに対して MAC アドレスの更新をする必要があるためです。ルータ側の MAC アドレス書き換えタイムアウトまで待っても良いですねぇ。根が短気な性分なものでして・・f(^^;;。
  • そして、最後の nsenter コマンドは Linux で WordPress を動かすための php のおまじない。 /usr/sbin/php-fpm を nsenter コマンドで起動してあげます。Docker コンテナ内に入って ps -ax すると httpd と php-fpm の二種類のプロセスが一個のコンテナ内で起動する状態となります。つまり、 php-fpm 専用コンテナは不要である。と、いうことです。
    例えば、(本来、動かす必要はないのだけど) zabbix_agent なども nsenter で動かすことができます。コンテナ自体が固定 IP を利用しているので Zabbix Agent のポートにもアクセスできるようになります。

 
これで Service-Segment 側に指定した IP アドレスにウェブブラウザからアクセスすると、WordPress の初期設定画面が表示できると思います。

データベースは MySQL ですが 192.168.52.204 で動作している MySQL サーバへのアクセスは eth1 側を抜けていくので WordPress の初期設定画面で IP アドレス・ユーザ名・パスワードを設定するとアクセスできると思います。
あ。当然、 MySQL 側ではデータベースとアクセス用のアカウントを作成しておいてください。ここでは割愛しています。

 
さてと。ここまで来てファイアーウォールの設定が一回も登場していません。Docker にはファイアーウォールは必須なので、Docker ホスト側で systemctl start firewalld は必須です。僕の場合は /etc/firewalld/direct.xml で設定していますが、 -i で指定するインターフェース名は eth0 と br0 、 eth1 と br1 の両方を記述する必要があるので、その点は注意してください。

 
あとは・・。

これで多分大丈夫だと思います。

起動する Docker コンテナは、コンテンツと設定ファイル、そして、ログ出力を -v で Docker ホスト側の情報をマウントしているので docker run 時に違うディレクトリを指定し、他にネットワーク、IP アドレスの設定を変えるだけで一個の Docker イメージで複数の、用途の違う Docker コンテナを起動して同じ仕事をしてくれるようにすることも可能です。んー。 Docker らしい使い方ぁ;-)。

 
Docker って、基本 NAT が当たり前で、ブリッジインターフェースを利用した環境で『コンテナに対して直接アクセス』。っての、google で検索してもネタ的に今のところはあまり多くないかな。
しかし、実際にコンテナ使い込むとコンテナごとにポート番号変えるのって、なんか納得いかなくて、その先に『こんなんじゃ実際のサービスに提供できないじゃん。』と、いうところからブリッジインターフェースでコンテナに直接アクセス、ロードバランサから見ると仮想マシンもコンテナも同一の扱いのほうが楽じゃん。と、いう発想があります。そのためにはやっぱりブリッジだよねぇ。みたいな。

 
それにしても、実際に調べてみると Linux の bridge-utils ツール群はヘボいですな。今回、実は IPv6 のことについて全く書いてないんですよ。 bridge-utils は IPv6 側の作りが甘いっ!!
Docker ホストの br0 から出ていく TCP パケットには eth0 の MAC アドレスとか Link Local アドレスが記載されていて、受け取った PC のほうは戻りパケットを送信側 (Docker ホストのこと) の eth0 の MAC アドレスとか Link Local アドレスに投げようとするので、Dockerホスト側の br0 の情報がないために宛先がなくて、実質的に通信できない。と、いう非常にお粗末な状態です。
Docker 自体は IPv6 が使えるかもしれないけど、Linux でブリッジを利用する場合には IPv6 は利用しないほうが良いですな。パケットキャプチャしないと原因が特定できない。ハマる前に IPv6 の利用は諦めたほうが良いかと。

 
と、いうことで、今回、 Docker コンテナをブリッジインターフェースで、Docker ホストと同一のネットワークで動作させる。と、いうことにチャレンジしてました。 VMware ESXi 上で複数の仮想マシンを起動するがごとく、Docker ホスト上で Docker コンテナをドドドと立ち上げることが可能になったので、サーバ資源がますますギューギュー使える状態になったでしょうかねぇ;-)。

 
このあと、docker swarm がまだ待っております。が、オーバーレイネットワークがちゃんと動いてくれてないのよ。とほほ・・。orz

1月 142023
 

このブログでは何回か VRF について書きました。 FreeBSD の VRFubuntu の VRF など。 FreeBSD のポリシールーティングのネタも書いたこともありました。

そのとき CentOS7 はカーネルがまだ VRF に対応していなくて、CentOS8 まで VRF は実質利用できない状態だったのだけど、今の時代、AlmaLinux8 を利用すればカーネル的に VRF が利用できるので、試してみました。

ubuntu のネットワーク設定より Red Hat Linux 系のネットワーク設定のほうが楽と、いうか、個人的にも直感的に設定できるような状態ですしね(^^;;。今回は由緒正しく /etc/sysconfig/network-scripts/ 配下のファイルを用意して VRF の設定をしてみたいと思います。

 
と、いうことでまずは構成図などを。



 
基本的に FreeBSD の VRF も同じ構成で組んでいます。セグメントは全部で 3 個。

  • Service-Segment: 外部からのアクセス用
  • Access-Segment: MySQL とか SNMP とかバックヤード系
  • mgmt: ssh でサーバにログインする用

 
今回のルーティングテーブルは合計二つ。Service-Segment と Access-Segment で一個のルーティングテーブル。 mgmt が VRF で設定するもう一個のルーティングテーブルになります。

FreeBSD で VRF するときに痛感したのですが、自分から出すパケットは default のルーティングテーブルからしか出ていきません。VRF で追加したルーティングテーブルの mgmt セグメントの 192.168.1.0/24 に ssh しようとしても default のルーティングテーブルから出ていきます。

例えば 192.168.52.201 で動作している MySQL にアクセスしようとした場合、default のルーティングテーブルから出ていくのですが Access-Segment で利用しているセグメントがローカルネットワークになっているのでそこから出ていきます。
MySQL サーバが 172.16.52.201 にあった場合、 default gateway の設定のある Service-Segment から出ていきますが、 MySQL のアクセスは Access-Segment から出ていきたいので route add -net 172.17.52.0/24 gw 192.168.52.1 とか Access-Segment にルーティング設定をしてあげる必要があります。

 
と、いうことで VRF を設定して本当に幸せになるのかよくわかりませんが、とりあえず設定して行ってみましょう。

上記の構成図に合わせて /etc/sysconfig/network-scripts/ にファイルを用意していきます。

ifcfg-eth0
ifcfg-eth1
ifcfg-eth2
ifcfg-vrf.eth2
route-vrf.eth2
route6-vrf.eth2

実際に中を見てみましょう。

Service-Segment: ifcfg-eth0

TYPE=Ethernet
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6ADDR=2001:470:fe36:face::217:1
IPV6_DEFAULTGW=2001:470:fe36:face::1
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPV6_PRIVACY=no
MACADDR=permanent
IPADDR=192.168.22.217
PREFIX=24
GATEWAY=192.168.22.1

 
Service-Segmet に接続する eth0 には default gateway を設定しています。

 
Access-Segment: ifcfg-eth1

TYPE=Ethernet
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6ADDR=2001:470:fe36:cafe::217:1
#IPV6_DEFAULTGW=2001:470:fe36:cafe::1
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPV6_PRIVACY=no
MACADDR=permanent
IPADDR=192.168.52.217
PREFIX=24
#GATEWAY=192.168.52.1

 
こちらは内部のアクセス用ネットワークなので、default gateway は設定していません。実際には route add -net でネットワークごとにルーティング情報を追加するんだろうなぁ。と、いう気配です。

 
mgmt: ifcfg-eth2

TYPE=Ethernet
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6ADDR=2405:6580:aa40::217:1
IPV6_DEFAULTGW=2405:6580:aa40::1
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eth2
DEVICE=eth2
ONBOOT=yes
IPV6_PRIVACY=no
MACADDR=permanent
IPADDR=192.168.1.217
PREFIX=24
GATEWAY=192.168.1.1

 
マネージメント用ネットワークで外部から ssh でログインするときに利用します。これが VRF を利用するインターフェースなので default gateway が設定してあります。でもって次のファイルも必要です。

 
mgmt-VRF: ifcfg-vrf.eth2

TYPE=Ethernet
DEFROUTE=yes
BOOTPROTO=none
IPADDR=192.168.1.217
PREFIX=24
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6ADDR=2405:6580:aa40::217:1
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=vrf.eth2
DEVICE=eth2
ONBOOT=yes
VRF=mgmt0

 
NAME= と VRF= で VRF で動作の設定です。ifconfig -a したときに mgmt0 というインターフェースが生えてきます。

 
mgmt-route-IPv4: route-vrf.eth2

ADDRESS=0.0.0.0
NETMASK=0.0.0.0
GATEWAY0=192.168.1.1

 
VRF 側の IPv4 のルーティングテーブルの設定です。

mgmt-route-IPv6: route6-vrf.eth2

::/0 via 2405:6580:aa40::1

 
こちらが VRF 側の IPv6 のルーティングの設定。

 
で、これで準備ができたので一応再起動してみます。がっ!!

これがまた正しく動作しないのですよなぁ・・。 orz。

 
と、いうことで、追加で /etc/rc.local に設定を記載して、ちゃんど動作するようにコマンドを羅列します。 orz

ip link add dev mgmt0 type vrf table 10
ip link set dev mgmt0 up
ip link set dev eth2 master mgmt0
ip addr add dev eth2 192.168.1.217/24
ip link set dev eth2 up
ip route add default via 192.168.1.1 table 10
ip route add ::/0 via 2405:6580:aa40::1 table 10

route delete default
route delete default
route add default gw 192.168.22.1

ip route del ::/0 via 2405:6580:aa40::1
ip route del ::/0 via 2001:470:fe36:face::1
route -6 add default gw 2001:470:fe36:face::1

sysctl -w net.ipv4.tcp_l3mdev_accept=1
sysctl -w net.ipv4.udp_l3mdev_accept=1

 
最後の sysctl コマンドは /etc/sysctl.conf に記載しても良いですね。
問題はその上です。

上から順に、

  • インターフェース mgmt0 を vrf として作成し table 10 とします
  • インターフェース eth2 と mgmt0 をくっつけます
  • table 10 (VRF 側) に default route を設定します
  • default のルーティングテーブルが壊れているようなので default gateway を二回削除してからつけ直します (ほんとうにこれしないとダメだった・・orz)

 
ルーティングの情報は IPv4 と IPv6 両方で実施します。これで大丈夫みたい。

確認方法は以下です。

# ip route show
default via 192.168.22.1 dev eth0 
192.168.1.1 dev eth2 proto static scope link metric 102 
192.168.22.0/24 dev eth0 proto kernel scope link src 192.168.22.217 
192.168.52.0/24 dev eth1 proto kernel scope link src 192.168.52.217 

# ip -6 route show
::1 dev lo proto kernel metric 256 pref medium
2405:6580:aa40::/64 dev eth2 proto kernel metric 102 pref medium
2001:470:fe36:face::/64 dev eth0 proto kernel metric 100 pref medium
2001:470:fe36:cafe::/64 dev eth1 proto kernel metric 101 pref medium

# ip route show table 10
default via 192.168.1.1 dev eth2 
broadcast 192.168.1.0 dev eth2 proto kernel scope link src 192.168.1.217 
local 192.168.1.217 dev eth2 proto kernel scope host src 192.168.1.217 
broadcast 192.168.1.255 dev eth2 proto kernel scope link src 192.168.1.217 

# ip -6 route show table 10
local 2405:6580:aa40::217:1 dev eth2 proto kernel metric 0 pref medium
local fe80::751c:3cc8:a2c0:2fcb dev eth2 proto kernel metric 0 pref medium
multicast ff00::/8 dev eth2 proto kernel metric 256 pref medium
default via 2405:6580:aa40::1 dev eth2 metric 1024 pref medium

# ip -d link show type vrf
6: mgmt0:  mtu 65575 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 12:c4:f9:dc:1f:bf brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 1280 maxmtu 65575 
    vrf table 10 addrgenmode none numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 

 
なんか良さげな感じがしています。

192.168.22.1 から eth2 のアドレスに対してアクセスした場合、戻りパケットはちゃんと eth2 から出ていきます。 19.268.1.50 から eth0 のアドレスに対してアクセスした場合、ちゃんと eth0 から戻っていきます。ある意味 VRF が機能している。と、いう感じです。やりたかったことはこれですね。

 
ただ、自分から出ていくパケットについてが問題です。default のルーティングテーブルから出ていくのが基本で、別のルーティングテーブルを利用したい場合は ping -I eth2 192.168.1.40 みたいにインターフェースを指定する必要があります。明示的にコマンドを打つなら良いですが、例えば php から MySQL にアクセスするために VRF 側のルーティングテーブルを利用して外に出ていきたい。などというのはほぼ不可能です。

使い方が非常に限られる VRF ですが、機能的には一応、動作する。と、いうことですなぁ。

 
さてと。今回構築したこの AlmaLinux release 8.7 の環境ですが、もうしばらく利用したいと思います。次のエントリは今回作成した環境を利用します。が、直接的・動作的には全く関係ないですが、好ご期待;-)。

9月 182022
 

自宅のデスクトップ機自宅サーバに HP ProDesk 405 SFF/CT を購入しました。時期的にデスクトップ機は G6 、自宅サーバは G8 というタイミングです。

で、この二台は AMD Ryzen7 PRO CPU が搭載されています。 BIOS (UEFI) メニューを見ると AMD DASH というのに対応しているようです。

そもそも “AMD DASH” とはなんぞや?

簡単に言うと iLO みたいにリモートで BIOS を管理でる機能らしい。あくまで『らしい』のであります;-)。

AMD DASH を利用するためには PC 側に AMD DASH で利用するための IPv4 アドレスの設定が必要です。これは iLO と一緒ですね。

そして、管理用のマネージャーが必要です。マネージャーは以下の URL にアクセスしてダウンロードすることができます。

https://developer.amd.com/tools-for-dmtf-dash/

『AMD MANAGEMENT CONSOLE』ってのがそれにあたります。

確認してみると Windows 用の GUI と CLI 、各種 Linux 対応の CLI がダウンロードできるようです。
まぁ、『手元の Linux で CLI』より『手元の Windows で GUI』のほうが楽だろうと思い AMC-setup-7.0.0.956-AMD.exe をダウンロードし、手頃な WindowsOS にインストールします。

これでマネージャー側の準備は完了。では早速、デスクトップ機にアクセスしてみることにしましょうっ!! ってんですが、これが大変。

PC 側で AMD DASH を有効にして IP を付加させるまでの工程は随分と苦労するので、今回はそちらをメインに書いてみます。

 
1. BIOS (UEFI 画面。以降 BIOS 画面と記載) で AMD DASH を有効化
その通りですね。 BIOS 画面で [詳細設定] -> [システムオプション] を選択して下から二番目にある「AMD DASH」にチェックを入れます。



 
2. UEFI ドライバーからの「他社製オプション ROM の管理」へアクセス
「AMD DASH」にチェックを入れたあと、次に BIOS 画面で [UEFI ドライバー] を選択し、そこに表示されている「他社製オプション ROM の管理」の項目を選択します。 選択したあと、保存して終了します。そのタイミングで再起動します。

再起動して起動してくるタイミングで F3 キーを押してください。画面の左下に以下のように表示され、その後「他社製オプション ROM の設定」画面が表示されます。

F9 はブートセレクト画面、 F10 は BIOS 設定画面が表示されますが、 F3 キーを押すと「他社製オプション ROM の管理」画面が表示されます。これは裏技か? どこにも書かれてないぞぉー。

 
3. AMD DASH のネットワークと認証設定
「他社製オプション ROM の管理」画面にはいりました。青ベースの画面になりますね。

僕の場合はオンボードの Realtek の NIC と PCI-e x16 スロットに HP 純正の Intel の 2Port NIC のカードが入っているので MAC アドレスが 3 個見えますが、ここから Realtek の NIC の設定画面に入ります。Realtek は一番下の NIC ですね。

NIC を選択すると設定画面に突入。

右上には「AMD DASH の設定をしているよー。」って、表示されています。

ネットワークの設定については、まぁ、ややこすぃーのでとりあえず DHCP の設定をしてから抜けます。
個別の IP アドレスを指定しても良いと思いますし VLAN-ID を設定しても良いと思います。が、一番最初は勝手がわからないので DHCP でアドレスを取得するようにします。
この画面、良く見てみるとネットワークの設定するところが二ケ所あるんですよ。どっちが AMD DASH 用か良くわからない。なので、両方のネットワーク設定で DHCP の設定としました。

Realtek RealManage Setup のところで Setup and Configuration の中に入ると Security 関係の ID とパスワードが求められます。これには Administrator/Realtek で認証が通過します。

AMD MANAGEMENT CONSOLE からアクセスする際の認証に利用されます。 Administrator/Realtek は default 値です。

完了したら「他社製オプション ROM の設定」画面を抜けて再起動します。

 
4. しかし、実際の IP アドレスの割当は?
今回はデスクトップ機の HP ProDesk 405 G6 SFF/CT 側で AMD DASH を設定したので、こちらを利用します。 PC 上で動作している OS は FreeBSD/amd64 13.1-RELEASE です。

まず、自分のネットワークの網内に dhcpd を起動します。 FreeBSD 的ですが tail -f /var/db/dhcpd/dhcpd.leases して、 Realtek の NIC がどの IPv4 アドレスを取得するか確認します。

PC の電源を入れた段階でただちに IPv4 が取得されると思います。

『オンボードの Realtek の NIC は FreeBSD でも利用するのに AMD DASH で IPv4 アドレス取得して FreeBSD でも IPv4 使うの、無理じゃね?』

となるのであります。

その昔、HP DL320G5p 辺りに iLO とオンボード NIC が一緒のポートで VLAN で IP アドレスを使い分けろ。とかいうのがありました。その後、この仕様はなくなり iLO と OS が利用する NIC は別ポートなのが主流になりましたが・・。

「他社製オプション ROM の設定」画面で VLAN の設定もできるので、そこで PC セグメントと AMD DASH 用管理セグメントを分けた VLAN-ID を設定する。と、いうのも一つの手ではあります。

と、いうことで、この部分の IP アドレスの使い分けが非常にややこしい。自宅に Cisco 891FJ があるとはいえ・・。既に VLAN を利用して自宅のネットワークを構築しているとはいえ・・。

 
と、いうことでオンボードの re0 は AMD DASH 専用ポートに、PCI-e の 2Port NIC を FreeBSD 側で利用 (em0・em1 で認識している)することにします。

FreeBSD ではオンボードの Realtek の NIC は /boot/kernel/if_re.ko では動作しません。 ports から net/realtek-re-kmod をイントールした /boot/modules/if_re.ko を利用する必要があります。

 
PC に電源を入れて DHCP で取得した IP アドレスに ping を打ち続けるのですが、 FreeBSD が起動して re0 が認識した時点で ping が止まります。 AMD DASH と FreeBSD の IP アドレスがグチャグチャになるのでしょうなぁ。

それにしても AMD DASH 対応の NIC のために FreeBSD の標準 if_re.ko では動作しないのかな?
まぁ、FreeBSD は em0 を利用して通信するので re0 を認識させる必要さえありません。

 
ちなみに、自宅サーバ側の HP ProDesk 405 G8 SFF/CT は VMware ESXi 7.0 が動作していますが、ESXi7 はそもそも Realtek の NIC を認識しないので、こちらは問題なく AMD DASH で利用できますね。ただ、もう ESXi7 が起動している状態なので AMD DASH の設定してませんが・・f(^^;;。

 
オンボードの Realtek NIC の IP アドレスの設定について FreeBSD のみで動作確認したので WindowsOS ではどういう振る舞いをするのか確認さえしていません。もしかしたらドライバが優秀なのかもしれませんが、僕は見ようとも思ってません;-)。

と、いうことで AMD DASH 用に IPv4 アドレスが付いたでしょうか?

では次に進みましょう;-)。

 
5. AMC Console を起動
Windows にインストールした AMD MANAGEMENT CONSOLE を起動します。
一番最初にセットアップ画面が表示され、認証用 IP とパスワードを指定するように求められます。先程の default 値の Administrator/Realtek を指定します。
次に AMD DASH 対応 PC をネットワークから探査します。一番左にある “DISCOVER” と書かれたアイコンをクリックします。

  • hostname
  • IP Address
  • TCP/IP Range
  • Active Directory

 
上記で探査可能ですが、dhcpd のログを確認して IPv4 アドレスは解っているので素直に IP Address で探査します。

探査できるとこんな感じです。

 
6. AMC Console を使い込んで行こう
一旦認識されると All Systems というコンピュータグループに登録されるので、確認します。
探査された PC の状況や BIOS の情報を表示してくれます。色々見て楽しんでください;-)。

あとは AMC Console の上のアイコンにあるメニューを順に確認していく。と、いう感じでしょうか。機能的に色々試す。と、いう感じです。

 
僕的には右から 4 番目の “REMOTE ACCESS” がえらい気になったですが・・。 iLO5 だと HTML5 コンソールとか起動して、 PC の画面が表示できるのですか、『AMD DASH もできるのかっ!?』うひっ!! ・・。 まぁ、甘かったですね・・。orz

ちょっと使ってみたのですが、 BIOS 設定など表示できるのはうれしいです。が、その程度かなぁ・・。 iLO にはほど遠いみたいな雰囲気でしょうか。まぁ、CPU メーカがここまでよくやった。うんうん。

 
あ。ここまで書いて、思い出したっ!! AMD DASH は iLO の対抗ではなかったですね。 Intel の vPro 対抗の機能だったっ!! 失礼しましたっ!!

と、いうことで機能的には Intel vPro と同等なのかな?

 
興味がある方は色々試してみてください。

上にも書いた通り、ネットワーク設定が通過できると比較的容易に遊べるようになるかと思われます。

 
このエントリは AMC Console の利用方法について記載したものではなく、どこにもドキュメントが無い AMD DASH を利用する PC 側のネットワーク設定について書かれたモノなのであります。なので AMC Console の Linux CLI とか Windows GUI とか、そんなのはどうでも良いことなのでありますっ!! ;-P。

 
(参考にしたサイト: https://www.reddit.com/r/Amd/comments/ism4wg/trying_out_dash_remote_access_on_a_thinkpad_t14s/)
どこにもドキュメントが無いないわけではなかった・・。ほっ。

10月 222021
 

以前のエントリで、FreeBSD の VRF (setfib) は正しく使えない。と、書いたことがありました。エントリ的には「FreeBSD でポリシールーティング。」と、いうヤツですね。

setfib 0 の中に setfib 1 のルーティング情報が載ってしまい、ルーティングテーブルがインターフェースと結びついていない。と、いうのが問題点だ。と、書いています。

しかし、設定の詳しい人に聞いてみるとちゃんとそーいう設定ができるらしいんですね。ちょっと、今更感満載なんですけども・・f(^^;;。
/etc/rc.conf に以下のように書くと良いみたいです。

#defaultrouter="192.168.22.1"
#ipv6_defaultrouter="2001:470:fe36:beef::1"

static_routes="0:vmx0 1:em0"
route_0="-net -inet default -gateway 192.168.22.1 -fib 0"
route_1="-net -inet default -gateway 192.168.1.1  -fib 1"

ipv6_static_routes="0:vmx0 1:em0"
ipv6_route_0="-net -inet6 default -gateway 2001:470:fe36:beef::1  -fib 0"
ipv6_route_1="-net -inet6 default -gateway 3ffe:6580:aa40::ffff:1 -fib 1"

ifconfig_vmx0="inet 192.168.22.20 netmask 255.255.255.0 fib 0"
ifconfig_em0="inet 192.168.1.20   netmask 255.255.255.0 fib 1"

ifconfig_vmx0_ipv6="inet6 2001:470:fe36:beef::20:1 prefixlen 64"
ifconfig_em0_ipv6="inet6 3ffe:6580:aa40::20:1      prefixlen 64"

 
defaultrouter の設定は必要ありません。
static_routes= と、 setfib が IPv6 対応になったので ipv6_static_routes= の二つのオプションがインターフェース名と setfib 番号を紐つけてくれます。そして、route_?= で default gateway を指定してあげれば良い。

この設定で起動したときのネットワークテーブルは以下の通り。

$ setfib 0 netstat -nr -f inet
Routing tables (fib: 0)
Destination        Gateway            Flags     Netif Expire
default            192.168.22.1       UGS         vmx0
127.0.0.1          link#1             UH          lo0
192.168.22.0/24    link#2             U           vmx0
192.168.22.20      link#3             UHS         lo0

$ setfib 1 netstat -nr -f inet
Routing tables (fib: 1)
Destination        Gateway            Flags     Netif Expire
default            192.168.1.1        UGS         em0
127.0.0.1          link#1             UH          lo0
192.168.1.0/24     link#2             U           em0
192.168.1.20       link#3             UHS         lo0

 
良い感じですねぇ。これで 192.168.1.30 辺りの PC から ping を打つと em0 から入ってきて、em0 から抜けていきます。良かったですねぇ。

 
しかし、問題なのは上記の設定を施したサーバ側です。

なんか、僕は思いっきり勘違いしていたか安直に考えすぎていました。 setfib した PC はなんでもかんでも setfib 0 側から出て行ってしまいます。これは想定していなかった・・。

em0 側に 192.168.1.0/24 が付いているのに、とある PC に対して ping 192.168.1.30 すると setfib 0 側、つまり、vmx0 側から出ていきます。
192.168.1.30 側では 192.168.22.20 に返すんだけど、返ってきていないことになっていて、到達性がない状態・・。orz

setfib を利用した VRF でルーティングテーブルが二つに分かれるのは良いんだけど、コネクテッドな IP アドレスに対するアクセスは setfib 0 のルーティングテーブルに関係なく、コネクテッドなインターフェースからパケットが出て行ってほしかった・・。

と、いうか、出ていくモノだと、思っていた。ここが、考えが甘かった点です・・。orz
うーむ・・。世間一般の VRF って、こーいう仕様なのか?

sysctl でコネクテッドな IP アドレスの場合はコネクテッドなインターフェースからパケットが出ていく。と、いうオプションはないものかのぉ・・。orz

 
この仕様のおかげで色々なものが動作しない・・。今悩んでいるのは MRTG。
ウェブ UI は setfib 0 を向いているんだけど、MRTG で情報を取得したいのは em0 なコネクテッドな IP アドレスを持つ宛先。 em0 側はそもそも LAN-ZONE でメンテナンスインターフェースという想定だしねぇ・・。

setfib 1 snmpwalk -v2c -c ICMPv6 192.168.1.30 system

 
これは動くんだけど、 MRTG.cfg に 192.168.1.30 にアクセスする設定を書いた mrtg を動作させようとしても動かない・・。

setfib 1 /usr/local/bin/mrtg /pathto/MRTG.cfg

 
mrtg は setfib 1 を無視して setfib 0 側から出ていくようです。まぁ、perl の内部構造に対して setfib 1 を食わせてあげないとどうしようもない状態かな。

似たようなのに httpd と MySQL の関係もありますな。 httpd は vmx0 側に開いているのは良いことで、別のサーバのコネクテッドな IP アドレスを持つ mysqld へのアクセスは em0 側で行いたい。だけど setfib 0 側から mysqld へのアクセスが出ていくのでこれはアクセスできんぞぉ・・

ansible も動かなくなった・・。AWX と ansible-playbook の関係も似たようなもん。もう、ヒサンすぎる・・。 orz

NFS マウントも /etc/fstab 内ではできなくて、 /etc/rc.clocal 内で setfib 1 mount_nfs -o tcp -o rw hoge と記載すると良いよ。なんてのが、どこかのフォーラムに書かれていたなぁ。 /etc/fstab が setfib に対応していない。

 
と、いうことでやっぱり FreeBSD の VRF は利用するのをやめる予感。

今のように出ていくパケット (established なパケット。と、いう意味かな) は何でもかんでも setfib 0 から出ていく。と、いうのとは別に、コネクテッドな IP アドレスの場合はコネクテッドなインターフェースからパケットが出ていく。と、いうオプションを用意してくれても良いと思うのだけどなぁ・・。

やっぱり pf のポリシールーティングに戻るかねぇ・・。

 
と、いうか、最後に書くんだけど、ネットワーク構成がまちがっている。と、いうことかな。

  • setfib 0 : em0 : サービス提供用ネットワーク
  • setfib 0 : em1 : バックヤード用ネットワーク
  • setfib 1 : em2 : ssh でのメンテナンス専用ネットワーク

 
FreeBSD で setfib な VRF を利用するにはこのように三つのネットワークが必要で「バックヤード用ネットワーク」は MRTG とか snmp、MySQL へのアクセス、と、いう感じでその目的をにして、「ssh でのメンテナンス専用ネットワーク」はリモート管理用に setfib をわけてあげる。と、いう感じですかねぇ。

1月 062021
 

以前のエントリで、「Nginx + quiche パッチで HTTP/3 にチャレンジ。」と、いうのを書いています。このエントリの『続編』を書いてみたいと思います。

と、いうのも色々あったからです。

簡単に書くと、あっという間にこのエントリは終わってしまいますf(^^;;。
ネタ的なモノを箇条書きにしてみると

  • nginx + quiche パッチでは SSI は動作しません
  • nginx + quiche パッチを利用した場合 RTMP モジュールが利用できないです

の二つになります。これが解れば詳細はどうでもいー。と、いう人はここでおしまいです。
『なんで?』と思った方は読み進んでくださいf(^^;;。

 
まず、上の部分の SSI についてですが、perl による index.cgi で SSI で吐き出すことと同じ動作をするモノを作成すると、無事に動作します。

以下はサンプルです。これは index.cgi 。

#!/usr/local/bin/perl
use strict;
print "Content-type: text/html\n\n";
print "<html>\n<head>\n";
print "<META HTTP-EQUIV=\"Content-type\" CONTENT=\"text/html;charset=utf-8\">\n";
print "<TITLE>IPv6 HTTP/3 Access Web page.</TITLE>¥n";
print "</head>\n<body>\n";

print "<br><h2>Hello HTTP/3 World.</h2><hr>\n";

my $word = "";
if ($ENV{'REMOTE_ADDR'} =~ /:/) {
    $word  = "===> ";
    $word .= "$ENV{'REMOTE_ADDR'} から IPv6 パケットを受け取りました。";
} else {
    $word  = "===> ";
    $word .= "$ENV{'REMOTE_ADDR'} から IPv4 パケットを受け取りました。";
}
print "$word<br><hr>\n";;

print "===> Protocol: $ENV{'SERVER_PROTOCOL'}<br>\n<hr>";
print "===> Access Port: $ENV{'SERVER_PORT'}<br>\n<hr>";

exit;

 
似たようなのを index.shtml と access.cgi でやるとこんな感じ。

こちらは index.shtml。

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-type" CONTENT="text/html;charset=utf-8">
<TITLE>IPv6 HTTP/3 Access Web page.</TITLE>
</HEAD>
<BODY>
<ht>
Hello HTTP/3 World.<br>
<hr>
<!--# include file="./access.cgi"-->
<hr>
</BODY>
</HTML>

 
こちらは access.cgi。

#!/usr/local/bin/perl
use strict;
print "Content-type: text/html\n\n";
my $word = "";
if ($ENV{'REMOTE_ADDR'} =~ /:/) {
    $word  = "===> ";
    $word .= "$ENV{'REMOTE_ADDR'} から IPv6 パケットを受け取りました。";
} else {
    $word  = "---> ";
    $word .= "$ENV{'REMOTE_ADDR'} から IPv4 パケットを受け取りました。";
}
print "$word<br><hr>\n";;
print "===> プロトコル: $ENV{'SERVER_PROTOCOL'}<br>\n<hr>\n";
print "===> アクセスポート: $ENV{'SERVER_PORT'}<br>\n";
exit;

 
index.html (index.shtml) に include があると、 Nginx + quiche パッチではまともに動作しないようです。 quiche パッチを詳しく追ってはいないのですが、どうやら include 部分がそげ落ちているようです・・。 orz

まぁ、今の段階では SSI を利用しないコンテンツを用意する必要がありそうです。

 
二個目。

テレワークなどで、PC にカメラを接続する機会が多いのですが、せっかく購入したカメラ。もっと色々な用途で使ってみたい。などと思うわけです。 USB Video Class 、俗に USB な UVC カメラを FreeBSD に接続し、 webcamd や obs-studio をインストールして『ストリーミングなどしてみんべ。』などと思うわけです。
このブログでも以前に「NotePCに付いているカメラを FreeBSD で使う。」と、いうのを書いていたりしますが;-)。

更に一歩進んで obs-studio をイントールした場合、配信先に RTMP サーバが必要になります。
Nginx はモジュールとして RTMP モジュールや Stream・Stream SSL モジュールなどを利用可能ですが、HTTP/3 を有効にする quiche パッチを適用した Nginx ではこれらのもジュールは利用できません。

以下は nginx.conf の設定の抜粋です。

load_module /usr/local/libexec/nginx/ngx_stream_module.so;
load_module /usr/local/libexec/nginx/ngx_rtmp_module.so;

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        access_log /var/log/nginx/access_rtmp.log;

        application webcam {
            live on;
            record off;
            wait_video on;
        }
    }
}

 
load_module のところで早くもエラーが出ます。

# service nginx start
Performing sanity check on nginx configuration:
nginx: [emerg] dlopen() "/usr/local/libexec/nginx/ngx_stream_module.so" failed (/usr/local/libexec/nginx/ngx_stream_module.so: Undefined symbol "SSL_set_tlsext_host_name") in /usr/local/etc/nginx/nginx.conf:7
nginx: configuration file /usr/local/etc/nginx/nginx.conf test failed

 
もしくは

# service nginx start
Performing sanity check on nginx configuration:
nginx: [emerg] dlopen() "/usr/local/libexec/nginx/ngx_rtmp_module.so" failed (/usr/local/libexec/nginx/ngx_rtmp_module.so: Undefined symbol "HMAC_CTX_new") in /usr/local/etc/nginx/nginx.conf:7
nginx: configuration file /usr/local/etc/nginx/nginx.conf test failed

 
みたいな感じ。

最初、どうして、SSL 系でエラーが出るのか解らなかったのですが、ports の www/nginx/Makefile とかソースを眺めていたら解りました。以前のエントリで、Nginx + quiche パッチを適用する場合 configure オプションに –with-openssl=/usr/ports/www/nginx-http3/quiche/deps/boringssl を指定しているんですね。
RTMP や Stream モジュールを利用する場合、ベタな openssl のソースのパスを指定する必用があるのですが、 quiche パッチを適用した場合、quiche 独自の SSL のコードを参照する必用があるので、 RTMP や Steram モジュールのコンパイルが通ったとしても、いざ動作させようとすると色々とシンボル名がなかったりするのですな。

 
と、いうことで、 Nginx に quiche パッチを適用した場合は、 HTTP/3 でのアクセス可状態なサーバで、SSI を利用しないウェブサーバとして利用するみとになります。

あ。Nginx + quiche パッチを適用したウェブサーバでも HTTP/2 や HTTP/1.1 、そして HTTP/1.0 (今では w3m くらいか?) でアクセスがあった場合 (それは、つまりは TCP でアクセスがあった場合かぁ?) には SSI は動作します。あくまで HTTP/3 でアクセスがあった場合のみ SSI の記述がある index.html がまともに表示されない状態になります。

SSI 使ったり RTMP・Strerm モジュールを利用したい場合は別にコンパイルしたサラの Nginx を用意する必用があります。 quiche パッチを適用しない Nginx では SSI や RTMP のサーバとして利用できるので、仮想マシンやコンテナで別立てするのがよろしいかと思われます。

 
ちなみに、Firefox は 72 から、 macOS や iPhone は Safari 14 から HTTP/3 がサポートされるようになりました(詳細については gugu ってください;-)。 macOS や iOS から HTTP/3 でアクセスできるようになると、ウェブサーバ担当者としてもいよいよ HTTP/3 の設定をしてサーバを起動してみたくなりますなぁ;-)。 ファイアーウォールの UDP Port:443 を開けるときが、今っ!! 来ましたっ!! ;-)。

1月 092020
 

2020 年の 正月に ports を csv update したら Firefox72 が降って来ていたので、そのまま FreeBSD/amd64 12.1-RELEASE にインストール。
しかし、ハタと考えてみた。『Firefox って 72 から HTTP/3 をサポートしたんじゃなかったけっ?』
果たして about:config で確認してみると

network.http.http3.enabled

と、いうのがあるではないかっ!! これをすかさず true にして google などを確認してみる。

HTTP/3 というのは、チョー簡単に言うと UDP で SSL 通信を行うものであります。詳細についてはウェブで情報を探してください;-P。
ファイアーウォールなどで UDP の 443 ポートなんてのは中々開いているものではないので、自宅なり、オフィスなりのファイアーウォールをまず先に確認してみましょう。

 
しかし、自分でも UDP:443 で通信するサーバを構築してみたい。色々探してみると apache24 はまだ、未対応ですが、 nginx は対応パッチが出ているようです。

まずは以下の URL にアクセス。

https://blog.cloudflare.com/experiment-with-http-3-using-nginx-and-quiche/

 
ここに記載されている git からパッチを取ってきて nginx のソースにパッチを当てて make しても良いんだけど、configure のオプションがややこすぃー。せっかく FreeBSD が手元にあるので ports の nginx に quiche パッチを適用してサーバ環境を構築してみましょう。

と、いうのが今回の趣旨です。ひと足お先に HTTP/3 を体験してみましょう。

このブログでは以前に apache24 で HTTP/2+TLSv1.3 対応にするエントリを書いていますが、今回は nginx のエントリになります。

 
1). ports の準備
以下に手順を書いてみます。

# cd /usr/ports/www/
# cp -pr nginx nginx-http3
# cd nginx-http3/
# git clone --recursive https://github.com/cloudflare/quiche
# make patch

 
原本となる /usr/ports/www/nginx/ は一応残しておいて nginx-http3/ というディレクトリで作業を始めます。
git から quiche を一式持ってきて、ports 的には make patch まで走らせます。make patch 時に make config が走ると思いますがお好みの設定で、絶対に忘れてはいけないオプションが HTTP_SSL と HTTPV2 です。 default で [X] になっていると思うんですけどね。

 
2). パッチ適用

# cd work/nginx-1.16.1/
# patch -p01 < ../../quiche/extras/nginx/nginx-1.16.patch
# cd ../..

 
nginx-1.16 用の quiche パッチなので、最新の ports ツリーであれば容易に適用できます。

 
3). ports の Makefile の編集
www/nginx-http3/Makefile を編集します。上記 URL では configure オプションが記載されていますが、それを FreeBSD の ports に書いて上げます。

diff -ur Makefile.orig Makefile
--- Makefile.orig       2020-01-03 12:00:17.947717000 +0900
+++ Makefile    2020-01-03 12:01:29.885305000 +0900
@@ -53,6 +53,9 @@
 
 HAS_CONFIGURE= yes
 CONFIGURE_ARGS+=--prefix=${ETCDIR} \
+               --with-http_v3_module \
+               --with-openssl=/usr/ports/www/nginx-http3/quiche/deps/boringssl \
+               --with-quiche=/usr/ports/www/nginx-http3/quiche \
                --with-cc-opt="-I ${LOCALBASE}/include" \
                --with-ld-opt="-L ${LOCALBASE}/lib" \
                --conf-path=${ETCDIR}/nginx.conf \

 
さーっ!! 準備ができたのでいよいよ make だぁっ!! などと思っては行けません。 quiche 側のソースコードのコンパイルには rust の cargo build を実行するので、なんとっ!! ここへ来て、 rust をインストール必要があります。
Firefox を自前でコンパイルする人は既に rust はインストール済みだと思われるため簡単ですが、持っていない人は /usr/ports/lang/rust/ を make install しましょう。速いマシンでも 30 分くらいかかると思いますけど。

 
rust のインストールが終わったらいよいよ nginx を make install します。

 
以上で HTTP/3 対応 nginx のインストールが完了しました。めでたしめでたし。

 
4). nginx.conf の設定
nginx.conf の設定は抜粋のみです。

user  www;
worker_processes  4;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  16;
}

http {

    autoindex off;

    server {
        listen [::]:443 quic reuseport;
        listen [::]:443 ssl  http2;
        listen      443 quic reuseport;
        listen      443 ssl  http2;

        server_name         nx.icmpv6.org;

        access_log  /var/log/nginx/access_nx_icmpv6_org.log;

        location / {
            root   /usr/local/www/nginx;
            index  index.html index.shtml index.php;
            allow  all;
        }

        ssl_certificate     /usr/local/etc/letsencrypt/live/nx.icmpv6.org/cert_chain.pem;
        ssl_certificate_key /usr/local/etc/letsencrypt/live/nx.icmpv6.org/privkey.pem;

        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_session_cache   shared:SSL:1m;
        ssl_session_timeout 5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        add_header alt-svc 'h3-23=":443"; ma=86400';

        http3_max_concurrent_streams 128;
        http3_max_requests           1000;
        http3_max_header_size        16k;
    }
}

 
listen は計 4 行ありますが、HTTP/3 で接続する場合には 443 quic reuseport の行が利用されます。 HTTP/3 に対応していないブラウザでは HTTP/2 で待ち受けるので、その設定は 443 ssl http2 になります。

そして、IPv6/IPv4 のデアルスタクです。

HTTP/2 も HTTP/3 も SSL が必須なので証明書を準備しましょう。 SSL 関連の設定もお忘れなく。

 
5). 実際に起動してみる
まず、何はなくとも以下のコマンドを叩いて確認。

$ netstat -an | grep 443
tcp4       0      0 *.443                  *.*                    LISTEN     
tcp6       0      0 *.443                  *.*                    LISTEN     
udp4       0      0 *.443                  *.*                    
udp4       0      0 *.443                  *.*                    
udp6       0      0 *.443                  *.*                    
udp6       0      0 *.443                  *.*
$
# tcpdump -i em0 udp port 443

 
うぉー。udp4,6 で port:443が開いているっ!!
tcpdump を起動して、UDP の port:443 でパケットが流れているか、確認ができます。
また、nginx のアクセスログで "GET / HTTP/2.0" は TCP Port:443 の接続になります。 "GET / HTTP/3" が UDP の Port:443 の接続になります。
上記の nginx の設定ではもう HTTP/2 か HTTP/3 の接続になりますな。高級なブラウザの場合は HTTP/2 か HTTP/3で、 w3m でアクセスするとようやっと "GET / HTTP/1.0" でのアクセスになります。

 
あとは nginx の root パスにドカドカコンテンツを置いていけば良いと思われます。

しかし、 netstat -an で UDP port:443 を確認して待受状態になっているにも関わらず接続できない場合があります。
サーバ側で tcpdump で確認してみると、クライアント側からアクセスがあるだけで、サーバ側からの応答がない場合が・・。しかし、とあるタイミングでは接続できるので・・。今の所 nginx を再起動してみたりと、いう運用ですかねぇ。

あと、Firefox72 は HTTP/3 で接続できなかった場合 HTTP/2 や HTTP/1.1 にフェイルオーバーしません。 HTTP/3 の応答が無くともずっと待っている状態になります。 about:config の HTTP/3 のタイムアウト設定も見当たらないし・・。

 
と、いうことで、今から遊ぶには十分に楽しい HTTP/3 です。FreeBSD では ports を利用すると Firefox72 は使えるわ、 nginx は ports にパッチを当てるだけで configure オプションに悩まなくて済むわ。比較的容易に、そして十分に楽しめること間違いなしです。

ここいらで UDP の世界にどっぷりとハマってみるのも良いのではないでしょうか;-)。

9月 152019
 

わけあって ansible を触るようになりました。ネットワーク機器の設定を自動更新できたら良い感じー。みたいな雰囲気で。

で、話のテンポはサササっと行くのですが、Cisco スイッチとかにアクセスする場合、 ssh ではなく今でも telnet を利用している人(会社)は多いかな?
エッジスイッチなんてのはグローバルアドレスが付いてないので外部から攻撃される心配ないし、パケットをキャプチャされることもないので『telnet でじゅーぶん。』みたいな。

そうなるといつまで経っても telnet を利用してしまうわけですが、 ansible が Cisco のネットワーク機器にアクセスするときには ios_command というモジュールを利用すると便利なのですが、こいつは ssh にしか対応してないので、それを使わず telnet モジュールでシコシコ tasks: を並べていく必要があるんですけども。

以下は telnet モジュールを利用した場合の標準的な playbooks の書き方です。

- name: send configuration commands to IOS
  telnet:
    user: admin
    password: cisco
    login_prompt: "Username: "
    prompts:
      - "[>|#]"
    command:
      - terminal length 0
      - show running-config
      - configure terminal
      - hostname ios01
    register: result

  - name: debug
    debug:
      msg: "{{ result }}"

 
この通りにやっても動かないことが多々ある。debug: を指定して output の中を見てももーぐちゃぐちゃ。初めて ansible をテスト的に利用してみると

『ansible ってこんなダサいの? perl の Net::Telnet 使ったほうがよっぽどいーじゃん。』

とかになってしまうのであります。

 
ansible の telnet モジュールがまともに動かない。答えを先に書くと、その原因は “#” にあります。

以下、Cisco 機器のネットワークインターフェースの設定だとします。

interface GigabitEthernet4
  description # VLAN1 Network #
 no ip address
!

 
description に “#” を使っていると telnet モジュールはプロンプトだと勘違いして処理がそこで止まります。
show interfaces status や show interfaces description ・ show running-config など何一つまともに動きません。

telnet モジュールの prompts: はプロンプトの “#” のみを見ているのでは無く Cisco ルータから出力された全ての “#” を見て動作しています。ヘボ過ぎる・・。 orz

telnet モジュールを利用した場合、出力された内容に “#” があるとまともに動作しません。ではどうやって対応するか? 以下は Cisco ルータの場合の対応策です。

- name: send configuration commands to IOS
  telnet:
    user: admin
    password: cisco
    login_prompt: "Username: "
    prompts:
      - "[o|)][>|#]"
    command:
      - terminal length 0
      - show running-config
      - configure terminal
      - hostname ios01
    register: result

  - name: debug
    debug:
      msg: "{{ result }}"

 
prompts: に指定する文字が一文字だからダメで、二文字にマッチさせると何とか無事に動作するようになります。二文字でマッチできない場合はもう一文字追加で;-)。

上記の prompts: の設定では、本スト名が cisco の場合、プロンプトは以下になります。

cisco>
cisco>enable
cisco#
cisco#configure terminal
cisco(coinfig)#interface gigabitEthernet4
cisco(config-if)#

 
つまり、ホスト名の最後の一文字と “#” を組み合わせた “o#” と、いう prompts: 、あと configure terminal 時にはプロンプトの前に “)” がつくので “)#” にマッチするように prompts: を記述します。

これで show running-config したときに設定中に “#” があっても無事に動作するようになります。

 
ansible で telnet モジュールを利用する場合には prompts: に設定した文字列に十分に注意しましょう。 prompts: に指定する文字は register: に出力される前に吸収されてしまいます。