Unboundのインストールした時のメモ

はじめに

 Unbound1 をソースファイルからデプロイした際のメモをざっくりと書いていきます。もし、少しでも参考となれば嬉しいです。気付いたところがあれば都度更新予定です。

動作環境

今回は、手元のVMに Ubuntu 24.04 をインストールし、その上でUnboundをデプロイしています。
リソースは、1ソケット1コア、メモリ4GBです。
利用人数は、100人ほどを想定しています。過少に見積もっていますが、自宅で100人が使うことはないですし、もう少し設定値を上げればさらに多くの利用者を捌ける想定です。
メモリ4GBも Ubuntu の推奨要件を満たすためで、Raspberry Pi のような1GBでも安定して動作するようになっています。私は Raspberry Pi で動かしています。

構築

ディレクトリとユーザ作成

ファイルを配置するディレクトリの作成とUnboundを操作するユーザを作成します。
Docsにも以下のような記載があり、Unboundの管理するためにユーザを作成し、ログインシェルは"/usr/sbin/nologin"を指定します。

By default Unbound assumes that a user named unbound exists. You can add this user with an account management tool available on your system; on Linux this is usually useradd.
引用元:Installation — Unbound 1.24.2 documentation

### "-p"で再帰的にディレクトリを作成
$ sudo mkdir -p /var/unbound/{etc,dev,var/log,usr/local/etc/unbound,usr/local/sbin}

$ sudo groupadd unbound
$ sudo cat /etc/group
unbound:x:1001:

### "-g"で特定のグループに所属、"-d"でホームディレクトリ指定、"-s"でログインシェルを指定
$ sudo useradd -g unbound -d /var/unbound -s /usr/sbin/nologin unbound
$ sudo cat /etc/passwd
unbound:x:1001:1001::/var/unbound:/usr/sbin/nologin

パッケージをインストール

Docs2 に記載されている必要なパッケージをインストールします。

$ sudo apt install build-essential libssl-dev libevent-dev libexpat1-dev
$ sudo apt-get install bison flex

ソースファイルからデプロイ

$ cd /opt
$ sudo wget https://github.com/NLnetLabs/unbound/archive/refs/tags/release-1.24.2.tar.gz
$ sudo tar xzf release-1.24.2.tar.gz
$ cd unbound-release-1.24.2/

$ sudo ./configure --prefix=/var/unbound/usr/local \
  --with-chroot-dir=/var/unbound \
  --with-libevent

$ sudo make
$ sudo make install

$ sudo /var/unbound/usr/local/sbin/unbound -V
Version 1.24.2

Configure line: --prefix=/var/unbound/usr/local --with-chroot-dir=/var/unbound --with-libevent
Linked libs: libevent 2.1.12-stable (it uses epoll), OpenSSL 3.0.13 30 Jan 2024
Linked modules: dns64 respip validator iterator

BSD licensed, see LICENSE in source package for details.
Report bugs to unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues

デバイスファイル作成とユーザと所有者の変更

$ sudo mknod -m 644 /var/unbound/dev/null c 1 3
$ sudo mknod -m 644 /var/unbound/dev/random c 1 8
$ sudo mknod -m 644 /var/unbound/dev/urandom c 1 9
$ sudo chown -R unbound:unbound /var/unbound

systemd-resolvedの停止と自動起動の無効化

既存のサービスと重複するので、"systemd-resolved"は停止します。
Docs3では、インターネットへの接続が切断されないようにファイルを書き換える方法が記載されていますが、パッケージのインストールとソースファイルのダウンロードが完了しているので、インターネットへ接続できなくても問題ありません。時刻同期に失敗することが問題の場合は、やり方を考える必要がありそうです。
事前に時刻同期先を手元で動作しているNTPサーバ宛に変更することで、インターネットへ接続できなくても時刻同期が外れることはないかもしれません。

$ lsof -i:53
COMMAND   PID            USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
systemd-r 567 systemd-resolve   14u  IPv4   6649      0t0  UDP _localdnsstub:domain
systemd-r 567 systemd-resolve   15u  IPv4   6650      0t0  TCP _localdnsstub:domain (LISTEN)
systemd-r 567 systemd-resolve   16u  IPv4   6651      0t0  UDP _localdnsproxy:domain
systemd-r 567 systemd-resolve   17u  IPv4   6652      0t0  TCP _localdnsproxy:domain (LISTEN)

$ sudo systemctl stop systemd-resolved
$ sudo systemctl disable systemd-resolved
$ systemctl status systemd-resolved
<停止していることを確認>

$ lsof -i:53
<出力なし>

コンフィグファイルの編集

コメントアウトで記載している内容は補足程度で記載しています。設定値は手元の環境に合わせて変更します。

$ sudo cp /var/unbound/usr/local/etc/unbound/unbound.conf /var/unbound/etc/
$ sudo vi /var/unbound/etc/unbound.conf

server: 
    #出力するログの詳細度
    verbosity: 1

    #統計情報の取得間隔(0は起動から再起動まで)
    statistics-interval: 0
    #累積統計を有効にする(再起動した場合は統計情報はクリアされる)
    statistics-cumulative: yes

    #CPUのコア数(=Socket*Core)
    num-threads: 1

    #問い合わせを待ち受けるIPアドレス(手元の環境に合わせて変更)
    interface: 127.0.0.53
    interface: <listen ip address>

    #クエリを受けたIPアドレスから返す(DSRでLBを使っていたり特殊な構成の場合は"yes")
    interface-automatic: no

    #同時に保持できる外部への問い合わせるポート数("num-queries-per-thread"の2倍)
    outgoing-range: 2048

    #TCP接続数の最大値(DoT/DoHを利用する場合はもう少し多い方がいいかも)
    outgoing-num-tcp: 200
    incoming-num-tcp: 200

    #ネットワークのバッファサイズ(パケットドロップしないようにする受け皿)
    so-rcvbuf: 4m
    so-sndbuf: 4m

    #EDNS0で相手に伝達するUDP応答パケットサイズの最大値(1232でパケットドロップが発生する場合は1220にする)
    #1232バイト=1280バイト(IPv6の最小MTU) - 40バイト(IPv6ヘッダ) - 8バイト(UDPヘッダ)
    edns-buffer-size: 1232
    #クライアントへのUDP返信パケットサイズの最大値(edns-buffer-sizeと同値)
    max-udp-size: 1232

    #問い合わせの応答内容を処理できるサイズ(これより大きなサイズは破棄)
    msg-buffer-size: 65532

    #問い合わせに対して回答した内容を保持するサイズ(クライアントから問い合わせにヒットするものがあればキャッシュから返答)
    msg-cache-size: 64m

    #"num-threads"の値に近くなる2の累乗
    msg-cache-slabs: 2

    #1スレッドで保持する外部問い合わせ中リクエスト数("outgoing-range"の半分)
    num-queries-per-thread: 1024

    #データ(レコード)を保持
    rrset-cache-size: 128m
    #"num-threads"の値に近くなる2の累乗
    rrset-cache-slabs: 2

    #問い合わせに対して回答した内容を保持する時間の最大値(低くいと頻繁に外部へ問い合わせる)
    cache-max-ttl: 86400

    #"num-threads"の値に近くなる2の累乗
    infra-cache-slabs: 2

    #外部問い合わせにダウンしていなかったり応答速度が速いなど最適なホストを保持する数
    infra-cache-numhosts: 5000

    do-ip4: yes
    #IPv6を利用する環境であれば"yes"にする
    do-ip6: no
    do-udp: yes
    do-tcp: yes

    #外部への問い合わせを最初からTCPを利用する(FWなどでUDPがブロックされている場合は"yes")
    tcp-upstream: no

    #問い合わせを許可するセグメントを制限(127.0.0.53がないと自分からの名前解決ができない)
    access-control: 127.0.0.53/32 allow
    access-control: 192.168.1.0/24 allow
    access-control: 0.0.0.0/0 refuse

    #chrootのディレクトリを指定(環境に合わせて変更)
    chroot: "/var/unbound"
    #Unboundを管理するユーザ
    username: "unbound"
    #作業ディレクトリのパス(環境に合わせて変更)
    directory: "/var/unbound"

    #Unboundのログ格納場所(syslogを利用する場合は不要)
    logfile: "/var/unbound/var/log/unbound.log"
    #syslogを利用する(他のログと混在しないよう"no"にした方がいいかも)
    use-syslog: no
    #ログ出力にUTC-ASCIIタイムスタンプの形式を利用する(どっちでも)
    log-time-ascii: yes
    #ISO8601形式を利用する(どっちでも)
    log-time-iso: no
    #プロセスIDを記載する場所
    pidfile: "/var/unbound/etc/unbound.pid"

    #問い合わせの応答にバージョンや識別子を隠す(内部利用であれば気にしなくてもいいが、情報を隠す方が無難)
    hide-identity: yes
    hide-version: yes

    #クライアントからの極端に小さかったり大きいサイズで要求する問い合わせを拒否
    harden-short-bufsize: yes
    harden-large-queries: yes

    #権威DNSからの応答に含まれる信頼できない情報を無視(スプーフィング対策)
    harden-glue: yes

    #DNSSEC署名が存在すべきゾーンからの応答に署名がない場合は破棄
    harden-dnssec-stripped: yes

    #権威サーバからの応答で再帰的な名前解決の際に、正しい宛先であることを確認(キャッシュポイズニング対策)
    #問い合わせが増えるため負荷や応答速度が少し増加し、閲覧不可となった宛先があれば、"no"にする(セキュリティ強度の上げ過ぎ)
    harden-referral-path: yes

    #DNSSEC検証で情弱なアルゴリズムへのダウングレートを防止
    harden-algo-downgrade: yes

    #最小限の情報のみ上位DNSへ問い合わせる(プライバシー保護)
    qname-minimisation: yes

    #問い合わせる際に、ドメイン名の大文字・小文字をランダムに入れ替えて、正しい相手からの応答であることを確認する(RFC4343  キャッシュポイズニング対策)
    use-caps-for-id: yes

    #有効期限が残り10%以下で問い合わせが来た場合、バックグラウンドで更新する
    prefetch: yes
    #有効期限が残り10%以下で問い合わせが来た場合、DNSSECの鍵情報も同様にプリフェッチする
    prefetch-key: yes

    #問い合わせの応答からAUTHORITY, ADDITIONALセクションを省略して返す
    minimal-responses: yes

    #DNSSEC検証を有効にする
    module-config: "validator iterator"

    #DNSSECルートトラストアンカーファイルのパス
    auto-trust-anchor-file: "/var/unbound/usr/local/etc/unbound/root.key"

    #DNSSEC検証結果が失敗でも結果をクライアントに返答する(キャッシュポイズニング対策)
    val-permissive-mode: no

    #キャッシュが切れても暫定で古いキャッシュを返す
    serve-expired: no

    #DNSSEC公開鍵をメモリに保持できる容量
    key-cache-size: 64m
    #"num-threads"の値に近くなる2の累乗
    key-cache-slabs: 2
    #存在しないドメインやレコードが存在しない情報をメモリに保持できる容量
    neg-cache-size: 4m

#Unboundをコントローラで管理する設定(今回はローカルからの操作を想定)
remote-control: 
    control-enable: yes
    control-interface: 127.0.0.1 
    control-port: 8953

    server-key-file: "/var/unbound/etc/unbound_server.key"
    server-cert-file: "/var/unbound/etc/unbound_server.pem"
    control-key-file: "/var/unbound/etc/unbound_control.key"
    control-cert-file: "/var/unbound/etc/unbound_control.pem"

forward-zone:
        name: "."
        #アドレスはISPから周知されているDNSやpublicのDNSを指定
        forward-addr: <DNSのIPアドレス>

コントローラの証明書を作成

$ sudo /var/unbound/usr/local/sbin/unbound-control-setup -d /var/unbound/etc
setup in directory /var/unbound/etc
Certificate request self-signature ok
subject=CN = unbound-control
removing artifacts
Setup success. Certificates created. Enable in unbound.conf file to use

$ sudo chown -R unbound:unbound /var/unbound/etc

root.key (DNSSECルートトラストアンカー) の作成

$ sudo -u unbound /var/unbound/usr/local/sbin/unbound-anchor -a /var/unbound/usr/local/etc/unbound/root.key

confファイルの記法チェック

$ sudo /var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf
unbound-checkconf: no errors in /var/unbound/etc/unbound.conf

起動と停止

### "-c"でconfファイルを指定して起動
$ sudo /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf
$ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf status
version: 1.24.2
verbosity: 1
threads: 1
modules: 2 [ validator iterator ]
uptime: 17 seconds
options: reuseport control(ssl)
unbound (pid 10261) is running...

### "-c"でconfファイルを指定して停止
$ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stop
ok

### エラーは unbound-control で操作するための 127.0.0.1:8953 へ接続できないためで、停止しているので接続できないのは問題なし
$ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf status
[1772258159] unbound-control[10292:0] error: connect: Connection refused for 127.0.0.1 port 8953
unbound is stopped

systemdの設定

ファイルの作成

systemdで起動する際のシェルスクリプトとサービスファイルを作成します。

$ sudo tee /var/unbound/usr/local/sbin/unbound_start.sh <<EOF
#!/bin/sh
/var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d
EOF

$ sudo chmod +x /var/unbound/usr/local/sbin/unbound_start.sh
$ sudo chown unbound:unbound /var/unbound/usr/local/sbin/unbound_start.sh

### 内容が多いのでviコマンドなどで作成しても可
$ sudo tee /etc/systemd/system/unbound-chroot.service <<EOF
[Unit]
Description=Unbound DNS Server in chroot
After=network.target

[Service]
Type=simple
User=unbound
Group=unbound
DynamicUser=no
NoNewPrivileges=true
SupplementaryGroups=
ExecStartPre=/var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf
ExecStart=/var/unbound/usr/local/sbin/unbound_start.sh
ExecStop=/var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stop
Restart=always
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_NET_BIND_SERVICE CAP_SYS_CHROOT
AmbientCapabilities=CAP_SETGID CAP_SETUID CAP_NET_BIND_SERVICE CAP_SYS_CHROOT

[Install]
WantedBy=multi-user.target
EOF

ネットワークバッファ制限値の変更

今回の想定している利用規模では、変更する必要はありませんが、Unboundの起動時に警告が出るため変更しています。出力される警告は動作に影響はありませんので、気にならない方や余計な設定変更はしたくない場合、変更は不要です。
規模が大きい場合は変更し、さらに大きい場合は、"8388608(8MB)"またはそれ以上にすることを検討します。

$ sudo vi /etc/sysctl.conf
+ net.core.rmem_max = 4194304
+ net.core.wmem_max = 4194304

$ sudo sysctl -p
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304

起動

$ sudo systemctl daemon-reload
$ sudo systemctl enable unbound-chroot.service
$ sudo systemctl start unbound-chroot.service
$ sudo systemctl status unbound-chroot.service
● unbound-chroot.service - Unbound DNS Server in chroot
     Loaded: loaded (/etc/systemd/system/unbound-chroot.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-02-28 06:29:56 UTC; 12min ago
    Process: 10761 ExecStartPre=/var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf (code=exited, status=0/SUCCESS)
   Main PID: 10763 (unbound_start.s)
      Tasks: 2 (limit: 4603)
     Memory: 87.7M (peak: 87.9M)
        CPU: 1.165s
     CGroup: /system.slice/unbound-chroot.service
             tq10763 /bin/sh /var/unbound/usr/local/sbin/unbound_start.sh
             mq10764 /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d

Feb 28 06:29:56 <hostname> systemd[1]: Starting unbound-chroot.service - Unbound DNS Server in chroot...
Feb 28 06:29:56 <hostname> unbound-checkconf[10761]: unbound-checkconf: no errors in /var/unbound/etc/unbound.conf
Feb 28 06:29:56 <hostname> systemd[1]: Started unbound-chroot.service - Unbound DNS Server in chroot.

### ログで起動を確認
$ sudo tail /var/unbound/var/log/unbound.log
Feb 28 06:29:56 unbound[10664:0] notice: init module 0: validator
Feb 28 06:29:56 unbound[10664:0] notice: init module 1: iterator
Feb 28 06:29:56 unbound[10664:0] info: start of service (unbound 1.24.2).

状態確認

プロセス確認

systemdで起動するようにした際に、起動スクリプトにバックグラウンドで起動するように記載したので、起動シェルスクリプトとバックグラウンド起動の二つが出力されます。

$ ps aux | grep unbound
unbound   15985  0.0  0.0   2328   832 ?      Ss   Feb28   0:00 /bin/sh /var/unbound/usr/local/sbin/unbound_start.sh
unbound   15986  0.0  2.8  11032  19300 ?     S    Feb28   0:50 /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d

chroot確認

PIDは、確認した起動プロセスを指定します。 chrootで指定したディレクトリが表示されることを確認する。

$ sudo ls -l /proc/<PID>/root
lrwxrwxrwx 1 unbound unbound 0 Feb 28 06:51 /proc/15986/root -> /var/unbound

DNSSEC動作確認

失敗する場合は、以下のような結果となります。"status"が「SERVFAIL」となります。
最初の数回ほどタイムアウトする原因はわかりません。単純に時間がかかっているのかも。

$ sudo dig @127.0.0.53 +dnssec sigfail.verteiltesysteme.net
;; communications error to 127.0.0.53#53: timed out

; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @127.0.0.53 +dnssec sigfail.verteiltesysteme.net
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 32565
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;sigfail.verteiltesysteme.net.  IN      A

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Sat Feb 28 06:10:40 UTC 2026
;; MSG SIZE  rcvd: 57

成功する場合は、失敗の際と異なり、"status"が「NOERROR」となります。
また、"flags"に「ad」が表示され、"ANSWER SECTION"にはRRSIGレコードが返されます。

$ sudo dig @127.0.0.53 +dnssec sigok.verteiltesysteme.net
;; communications error to 127.0.0.53#53: timed out

; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @127.0.0.53 +dnssec sigok.verteiltesysteme.net
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47080
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;sigok.verteiltesysteme.net.    IN      A

;; ANSWER SECTION:
sigok.verteiltesysteme.net. 1795 IN     CNAME   sigok.rsa2048-sha256.ippacket.stream.
sigok.verteiltesysteme.net. 1795 IN     RRSIG   CNAME 13 3 1799 202603001000000 20260210000000 46187 verteiltesysteme.net. **********************************
sigok.rsa2048-sha256.ippacket.stream. 59 IN A   123.234.56.36
sigok.rsa2048-sha256.ippacket.stream. 59 IN RRSIG A 8 4 60 202603001040000 20260131040002 46460 rsa2048-sha256.ippacket.stream. ************************************

;; Query time: 245 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Sat Feb 28 06:10:24 UTC 2026
;; MSG SIZE  rcvd: 555

性能確認

以下のコマンドを実行し、統計情報を出力します。

$ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stats_noreset

unbound.confで設定した制限に抵触した通信が増えている場合は、起動直後であれば何らかの不具合が生じていると見るべきです。

total.num.queries_ip_ratelimited=0  #攻撃(怪しい問い合わせ)対策に抵触した問い合わせの数

どの程度のキャッシュがヒットしているかなどを確認できます。

  • 問い合わせ数:728(total.num.queries) = 404(total.num.cachehits) + 324(total.num.cachemiss)

  • キャッシュヒット率:404(total.num.cachehits) / 728(total.num.queries) * 100 = 55%

  • 外部への問い合わせ数:324(total.num.cachemiss) = 322(total.num.recursivereplies) + 2(total.num.queries_discard_timeout)

total.num.queries=728  #DNSに来た問い合わせの総数
total.num.cachehits=404  #キャッシュにヒットした数
total.num.cachemiss=324  #キャッシュにヒットしなかった数(=外部への問い合わせた数)
total.num.recursivereplies=322  #外部への問い合わせからの応答数
total.num.queries_discard_timeout=2  #タイムアウトにより破棄された問い合わせの数

"total.requestlist.max"は"num-queries-per-thread"で指定した値の1/3までは安全、半分を超えると注意が必要かも。

total.requestlist.max=13  #同時処理した最大問い合わせの数
total.requestlist.overwritten=0 #処理しきれずに破棄した問い合わせの数
total.requestlist.exceeded=0 #処理しきれずに破棄した問い合わせの数

平均値が中央値の10倍を超えると一部の問い合わせに時間がかかっているかタイムアウトの可能性があるので、"forward-addr"の宛先DNSを変更してみたり、"serve-expired"を"yes"にしてみる。動作と体感に大きな問題がなければ無視してもいいと思います。

total.recursion.time.avg=0.021824  #キャッシュにヒットせず外部への問い合わせからの応答速度の平均値(s)
total.recursion.time.median=0.0064  #キャッシュにヒットせず外部への問い合わせからの応答速度の中央値(s)

参照

  1. Unbound by NLnet Labs — Unbound 1.24.2 documentation
  2. 日本Unboundユーザー会
  3. 最適化の方法 - 日本Unboundユーザー会
  4. Howto Optimise - Unbound
  5. Unboundの紹介とその運用
  6. DNSキャッシュサーバ 設計と運用のノウハウ
  7. キャッシュDNSのDNSSEC対応
  8. DNSのRFCの歩き⽅方

Ansible開発環境のセットアップ

はじめに

Ansibleで構成管理を変更する際には事前に動作確認をします。実際に運用されている環境に合わせて検証するために、手元の環境を運用環境に合わせます。PythonやAnsibleのバージョンで異なる組み合わせを用意する場合、venvではなくpyenv1を利用します。また、pyenv-virtualenv2プラグインで特定のPythonバージョンを元にAnsible実行環境を用意します。
今回は、Ansibleの開発環境を用意するために自分のメモ用として残しつつ、他の方にもためになるようならば嬉しい限りです。

環境構築

pyenvのインストール

早速、pyenvをインストールしていきます。
手順は、GitHubのREADME3に記載されていますので、そちらも確認してみてください。

$ cd $HOME
$ curl -fsSL https://pyenv.run | bash

pyenv用にシェル環境を設定します。
一部のシステムでは手順が異なるようですので、ご注意ください。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc

シェルの再起動をします。

$ exec "$SHELL"

pyenvのwiki4を参照し、Pythonのビルド依存関係をインストールします。
Python3.14 以降では、"libzstd-dev"もインストールする必要があるそうです。

$ sudo apt update; sudo apt install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl git \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

インストールしたpyenvのバージョンを確認をします。

$ pyenv --version
pyenv 2.6.12

pyenvの動作確認

実際に、pyenvがどのように動くのかを見てみます。
以下のコマンドでpyenvにインストール可能なリストを表示します。出力結果が多いため一部省略しています。

$ pyenv install --list
  3.11.12
  3.11.13  #<--インストール対象
  3.11.14
  3.12.10
  3.12.11
  3.12.12  #<--インストール対象

例として、Python 3.11.13Python 3.12.12をインストールします。手元の環境に合わせて必要なパッケージをインストールしてください。

$ pyenv install 3.11.13
Downloading Python-3.11.13.tar.xz...
-> https://www.python.org/ftp/python/3.11.13/Python-3.11.13.tar.xz
Installing Python-3.11.13...
Installed Python-3.11.13 to /home/username/.pyenv/versions/3.11.13

$ pyenv install 3.12.12
Downloading Python-3.12.12.tar.xz...
-> https://www.python.org/ftp/python/3.12.12/Python-3.12.12.tar.xz
Installing Python-3.12.12...
Installed Python-3.12.12 to /home/username/.pyenv/versions/3.12.12

作業フォルダを作成します。
フォルダ名は任意で大丈夫です。

$ cd $HOME
$ mkdir pyenv-test

準備ができましたので、pyenvでPythonのバージョンがどのように変化するかを確認していきます。
まずは、グローバルのPythonバージョンを確認します。特に指定をしなければ、グローバルのバージョンが適用されることになります。 環境によってはPythonのバージョンが異なるかもしれませんが、以下の出力と異なる場合であっても問題ありません。

$ cd $HOME
$ python3 --version
Python 3.10.12

次は先ほどインストールしたPython 3.11.13に切り替えてみます。バージョンを切り替える際は、作業ディレクトリに移動してから実施します。

$ cd pyenv-test
$ pyenv local 3.11.13
$ python3 --version
Python 3.11.13

では、作業ディレクトリはそのままに、次はPython 3.12.12に切り替えてみます。

$ pyenv local 3.12.12
$ python3 --version
Python 3.12.12

pyenv-virtualenvでAnsible用環境を用意

Pythonのバージョンの切替が確認できたところで、次は特定のPythonのバージョンでAnsible専用環境を用意します。今回は、Python 3.11.13ansible [core 2.17.6]で環境を作成します。必要なコレクションがあればそちらもインストールしてください。リモートリポジトリにプロジェクトが存在する場合は、クローンすることで作業準備完了となります。

$ cd $HOME
### コマンドは、「pyenv virtualenv <インストールしたPythonのバージョン> <任意の名前>」で実行
$ pyenv virtualenv 3.11.13 ansible_pj_env_3-11
$ pyenv versions
* system (set by /home/username/.pyenv/version)
  3.11.13
  3.11.13/envs/ansible_pj_env_3-11
  3.12.12
  ansible_pj_env_3-11 --> /home/username/.pyenv/versions/3.11.13/envs/ansible_pj_env_3-11

$ cd pyenv-test
$ pyenv local ansible_pj_env_3-11
$ python3 --version
Python 3.11.13

$ python -m pip install --upgrade pip
$ pip install ansible-core==2.17.6
$ ansible --version
ansible [core 2.17.6]
  config file = None
  configured module search path = ['/home/username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/username/.pyenv/versions/3.11.13/envs/ansible_pj_env_3-11/lib/python3.11/site-packages/ansible
  ansible collection location = /home/username/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/username/.pyenv/versions/ansible_pj_env_3-11/bin/ansible
  python version = 3.11.13 (main, Nov  1 2025, 18:59:08) [GCC 11.4.0] (/home/username/.pyenv/versions/3.11.13/envs/ansible_pj_env_3-11/bin/python)
  jinja version = 3.1.6
  libyaml = True

### 必要なコレクションをインストール
### git clone でブランチをダウンロード

ansible-core をインストールした環境(ansible_pj_env_3-11)からpyenv local --unsetで抜けてから、別環境に切り替えます。 すると、ansible-core がインストールされていない環境になったので、ansibleコマンドが見つかりませんと表示されました。ansible_pj_env_3-11にはansibleコマンドが存在することも記載されてますね。
このように、環境を汚さずに、バージョンによって環境を簡単に切替られるのはとても便利ですね。

$ pyenv local --unset
$ python3 --version
Python 3.10.12

$ pyenv local 3.12.12
$ python3 --version
Python 3.12.12
$ ansible --version
pyenv: ansible: command not found

The `ansible' command exists in these Python versions:
  3.11.13/envs/ansible_pj_env_3-11
  ansible_pj_env_3-11

Note: See 'pyenv help global' for tips on allowing both
      python2 and python3 to be found.

Proxmox-VE を bonding(Active-Backup)でネットワークの冗長化

はじめに

 前回の記事 では、Bonding(LACP)を試してみましたが、LACP対応スイッチが用意できない場合もあります。そのような場合について、Docsには以下のような記載があります。雑に訳すと、「LACP対応スイッチがないなら、Active-Backupを使用してな」ということ。今回は、LACPとは異なるActive-Backupを試してみようと思います。

If your switch supports the LACP (IEEE 802.3ad) protocol, then we recommend using the corresponding bonding mode (802.3ad). Otherwise you should generally use the active-backup mode.
引用元:Linux Bond1

LACPとActive-Backupの違いについて、比較は以下の通りになります。

比較項目 LACP Active-Backup
利用目的 負荷分散と冗長化 冗長化
LACP対応スイッチ 必要 不要
スイッチの設定 必要 不要
帯域 束ねたリンクの合計 単一リンク分

検証環境

Proxmox-VE 8.3(以降、Proxmox と記載) とLACP未対応スイッチを使用しており、相互を2本のLANケーブルで接続しています。
注意点として、今回記載した内容はリモートでの作業を想定していないので、実施の際は作業順序やコンソール接続可能な状態にしておくことを忘れないように。手順や順序を誤るとどこからも接続できなくなります。

設定(Proxmox)

/etc/network/interfaces を以下のように編集していきます。以下は例ですので、NICIPアドレスは環境に合わせて書き換えてください。

iface eno1 inet manual
iface eno2 inet manual

auto bond0
iface bond0 inet manual
        bond-slaves eno1 eno2 ### bondingとして扱う物理NIC
        bond-miimon 100 ### bondingのリンク状態を監視する間隔(ms)
        bond-mode active-backup ### active-backupとして動作

auto vmbr0
iface vmbr0 inet static
        address 192.168.1.100/24 ### bridgeに割り当てるIPアドレス(ホストにアクセスするIPアドレス)
        gateway 192.168.1.254
        bridge-ports bond0 ### bridgeと紐づけるインターフェース
        bridge-stp off
        bridge-fd 0

状態確認(正常時)

すべてのインターフェースがUPしており、「/proc/net/bonding/bond0」の出力内容はLACPと少し異なり、比較的シンプルな内容で、これは面白い気づきになりました。

# ip link show eno1
2: eno1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff
    altname enp5s0f0
# ip link show eno2
3: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff permaddr aa:aa:aa:aa:aa:a9
    altname enp5s0f1

# ip link show bond0
9: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff

# ip link show vmbr0
10: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff

# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.12-4-pve

Bonding Mode: fault-tolerance (active-backup)   ###active-backupで動作
Primary Slave: None
Currently Active Slave: eno1  ###現在Activeなリンク
MII Status: up
MII Polling Interval (ms): 100 ###リンクの監視間隔
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0

Slave Interface: eno1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:a8
Slave queue ID: 0

Slave Interface: eno2
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:a9
Slave queue ID: 0

状態確認(異常時)

今回もケーブルを実際に抜線してどのように状態が変化するのかを見てます。事前の状態を見て、"eno1"がActiveなので、ここは"eno1"を抜線してみます。

# ip link show eno1
2: eno1: <NO-CARRIER,BROADCAST,MULTICAST,SLAVE,UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff
    altname enp5s0f0
# ip link show eno2
3: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff permaddr aa:aa:aa:aa:aa:a9
    altname enp5s0f1

# ip link show bond0
9: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff

# ip link show vmbr0
10: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:a8 brd ff:ff:ff:ff:ff:ff

# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.12-4-pve

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: None
Currently Active Slave: eno2 ###Activeなリンクが切り替わった(eno1→eno2)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0

Slave Interface: eno1
MII Status: down ###Statusがdownに変化
Speed: Unknown ###状態がUnknownになった
Duplex: Unknown ###状態がUnknownになった
Link Failure Count: 1 ###カウントが上がった
Permanent HW addr: aa:aa:aa:aa:aa:a8
Slave queue ID: 0

Slave Interface: eno2
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:a9
Slave queue ID: 0

動作確認(断時間の計測)

前回同様、pingを打ち続けてケーブルを抜線した際の断時間を計ります。抜線するケーブルはbond内のActiveな状態の方を抜線します。
結果は、やはり1秒以内で疎通が復旧しているので、今回もデフォルトで問題ないかもしれません。気になるのは、LACPで計測した時より、断時間が0.2秒ほど短い点です。スイッチ側との兼ね合いもあっての断時間なのかもしれません。内容はともあれ、良い気づきになりました。

・0.1秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.100 ping statistics ---
500 packets transmitted, 497 received, 0.6% packet loss, time 51905ms
rtt min/avg/max/mdev = 0.185/0.468/0.506/0.039 ms

・0.01秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.100 ping statistics ---
500 packets transmitted, 475 received, 5% packet loss, time 8009ms
rtt min/avg/max/mdev = 0.177/0.460/0.493/0.037 ms

Proxmox-VE を LACP + bonding でネットワークの冗長化

はじめに

巷で話題のProxmox-VEと呼ばれる仮想化プラットフォームを用意する際に、手元で用意してすぐに壊すのであれば、ネットワーク冗長化は不要ですが、直近で壊す予定がない場合は、ネットワーク冗長化はしておいて損はないと考えています。今回は、LACP (IEEE 802.3ad) を用いたbondingによる冗長化について記載していきます。

検証環境

Proxmox-VE 8.3(以降、Proxmox と記載) と Cisco Catalyst Switch(以降、Switch と記載) を使用しており、相互を2本のLANケーブルで接続しています。
注意点として、今回記載した内容はリモートでの作業を想定していないので、実施の際は作業順序やコンソール接続可能な状態にしておくことを忘れないように。手順や順序を誤るとどこからも接続できなくなります。

画像1.1.構成

冗長設定

それぞれ、ProxmoxとSwitchでの設定について記載します。

Proxmox

package

事前準備として、"ifupdown2"がインストールされていることを確認します。7.0以降ではデフォルトでインストールされているそうです。
"ifupdown2"をインストールすることで、GUIからネットワークの設定を反映する際に、再起動が不要になります。

With the recommended ifupdown2 package (default for new installations since Proxmox VE 7.0), it is possible to apply network configuration changes without a reboot.
If you change the network configuration via the GUI, you can click the Apply Configuration button. This will move changes from the staging interfaces.new file to /etc/network/interfaces and apply them live.
引用元:Live-Reload Network with ifupdown21

> apt list --installed | grep ifupdown2
ifupdown2/now 3.2.0-1+pmx11 all [installed,local]

configure

以下のようにProxmoxでbondingを利用する際、SwitchでLACP (IEEE 802.3ad) をサポートしている場合はこれを使用することを推奨しているため、LACP (IEEE 802.3ad) を使用します。またサポートしていない場合には、active-backupを使用しましょう。

If your switch supports the LACP (IEEE 802.3ad) protocol, then we recommend using the corresponding bonding mode (802.3ad). Otherwise you should generally use the active-backup mode.
引用元:Linux Bond2

/etc/network/interfaces を以下の通りに編集していきます。以下は例ですので、環境に合わせて書き換えてください。

auto lo  
iface lo inet loopback

# physical on-bording device
iface eno1 inet manual
iface eno2 inet manual

# virtual bonding device
auto bond0
iface bond0 inet manual
        bond-slaves eno1 eno2 # bondingとして扱う物理NIC
        bond-miimon 100 # bondingのリンク状態を監視する間隔(ms)
        bond-mode 802.3ad # LACPとして動作
        bond-xmit-hash-policy layer2+3

# virtual bridge device
auto vmbr0
iface vmbr0 inet static
        address 192.168.1.30/24 # bridgeに割り当てるIPアドレス(ホストにアクセスするIPアドレス)
        gateway 192.168.1.254
        bridge-ports bond0 # bridgeと紐づけるインターフェース
        bridge-stp off
        bridge-fd 0

"ifupdown2"をインストールすることで、GUIからネットワークの設定を反映する際に、再起動が不要になりますが、今回は、CUIでネットワーク設定を変更したので、以下のコマンドで設定を反映します。

If you made manual changes directly to the /etc/network/interfaces file, you can apply them by running ifreload -a
引用元:Live-Reload Network with ifupdown23

# ifreload -a

状態確認(正常時)

正常な状態の例を記載します。

### 物理NICの状態
# ip link show eno1
4: eno1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff
# ip link show eno2
5: eno2 <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff permaddr aa:aa:aa:aa:aa:4d

### bondの状態
# ip link show bond0
11: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff

### ブリッジの状態
# ip link show vmbr0
14: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff

### bondの状態
# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.12-4-pve

Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer2+3 (2)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0

802.3ad info
LACP active: on
LACP rate: slow
Min links: 0
Aggregator selection policy (ad_select): stable
System priority: 65535
System MAC address: aa:aa:aa:aa:aa:4c
Active Aggregator Info:
        Aggregator ID: 1
        Number of ports: 2
        Actor Key: 9
        Partner Key: 67
        Partner Mac Address: bb:bb:bb:bb:bb:46

Slave Interface: eno1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:4c
Slave queue ID: 0
Aggregator ID: 1
Actor Churn State: none
Partner Churn State: none
Actor Churned Count: 0
Partner Churned Count: 0
details actor lacp pdu:
    system priority: 65535
    system mac address: aa:aa:aa:aa:aa:4c
    port key: 9
    port priority: 255
    port number: 1
    port state: 61
details partner lacp pdu:
    system priority: 32768
    system mac address: bb:bb:bb:bb:bb:46
    oper key: 67
    port priority: 128
    port number: 3
    port state: 61

Slave Interface: eno2
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:4d
Slave queue ID: 0
Aggregator ID: 1
Actor Churn State: none
Partner Churn State: none
Actor Churned Count: 0
Partner Churned Count: 0
details actor lacp pdu:
    system priority: 65535
    system mac address: aa:aa:aa:aa:aa:4c
    port key: 9
    port priority: 255
    port number: 2
    port state: 61
details partner lacp pdu:
    system priority: 32768
    system mac address: bb:bb:bb:bb:bb:46
    oper key: 67
    port priority: 128
    port number: 4
    port state: 61

状態確認(異常時)

ここでは2本のLANケーブルのうち(eno1側)を抜線後の状態を記載していまので、参考にしてください。
抜線した物理NICは、DOWNしていますが、仮想インターフェースはUPのままになっています。bond状態確認では、スレーブインターフェースとしての抜線したポートがdownしています。

### 物理NICの状態
# ip link show eno1
4: eno1: <NO-CARRIER,BROADCAST,MULTICAST,SLAVE,UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff
# ip link show eno2
5: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff permaddr aa:aa:aa:aa:aa:4d

### bondの状態
# ip link show bond0
11: bond1: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff

### ブリッジの状態
# ip link show vmbr0
14: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:aa:aa:aa:aa:4c brd ff:ff:ff:ff:ff:ff

### bondの状態
# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.12-4-pve

Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer2+3 (2)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0

802.3ad info
LACP active: on
LACP rate: slow
Min links: 0
Aggregator selection policy (ad_select): stable
System priority: 65535
System MAC address: aa:aa:aa:aa:aa:4c
Active Aggregator Info:
        Aggregator ID: 1
        Number of ports: 1
        Actor Key: 9
        Partner Key: 67
        Partner Mac Address: bb:bb:bb:bb:bb:46

Slave Interface: eno1
MII Status: down <--リンクダウン検知で"down"に変化
Speed: Unknown <--リンクダウン検知で"Unknown"に変化
Duplex: Unknown <--リンクダウン検知で"Unknown"に変化
Link Failure Count: 1 <--リンクダウン検知でカウンタが増加
Permanent HW addr: aa:aa:aa:aa:aa:4c
Slave queue ID: 0
Aggregator ID: 1
Actor Churn State: none
Partner Churn State: none
Actor Churned Count: 0
Partner Churned Count: 0
details actor lacp pdu:
    system priority: 65535
    system mac address: aa:aa:aa:aa:aa:4c
    port key: 0
    port priority: 255
    port number: 1
    port state: 61
details partner lacp pdu:
    system priority: 32768
    system mac address: bb:bb:bb:bb:bb:46
    oper key: 67
    port priority: 128
    port number: 3
    port state: 61

Slave Interface: eno2
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:aa:aa:aa:aa:4d
Slave queue ID: 0
Aggregator ID: 1
Actor Churn State: none
Partner Churn State: none
Actor Churned Count: 0
Partner Churned Count: 0
details actor lacp pdu:
    system priority: 65535
    system mac address: aa:aa:aa:aa:aa:4c
    port key: 9
    port priority: 255
    port number: 2
    port state: 61
details partner lacp pdu:
    system priority: 32768
    system mac address: bb:bb:bb:bb:bb:46
    oper key: 67
    port priority: 128
    port number: 4
    port state: 61

Switch

コンフィグを以下の通りに記載します。こちらも例ですので、環境に合わせて書き換えてください。

!
interface Port-channel2
 switchport access vlan 10
 switchport mode access
!
!
interface GigabitEthernet1/0/3
 switchport access vlan 10
 switchport mode access
 channel-protocol lacp
 channel-group 2 mode active
!
interface GigabitEthernet1/0/4
 switchport access vlan 10
 switchport mode access
 channel-protocol lacp
 channel-group 2 mode active
!

動作確認

冗長化したそれぞれのProxmoxノード間でpingを打ち続けた状態でLANケーブルを抜線した際の影響を確認してみました。結果を見ると、当然のことながら間隔が短い方はパケットロス率が高いことが分かります。検証で利用する分には問題なく、あくまで疎通がこれくらいの影響というだけで、実際にVMLinuxコンテナ上でアプリケーションを動作させた場合の影響は環境によると思われます。また、外部ストレージを利用する場合はどのような影響があるのか検証してみる必要がありそうです。

・0.1秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 496 received, 0.8% packet loss, time 51919ms
rtt min/avg/max/mdev = 0.166/0.448/0.696/0.059 ms

・0.01秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 444 received, 11.2% packet loss, time 8005ms
rtt min/avg/max/mdev = 0.166/0.439/0.491/0.063 ms

おまけ

bond-miimon の監視間隔を短くした場合の断時間

以下の結果より、bond-miimon のパラメータを"10"に変更し、0.01秒間隔でpingを打った場合に多少変化はありましたが、それ以外は大きな変化はありませんでした。いずれの場合においても、疎通断から1秒以内に復活しているため、このパラメータが運用において大きな役割を果たしているとは言えないと感じました。bond-miimon のパラメータを小さくすることで多少リソースが消費されてしまうこと考えると、無理に小さくせずに公式の例にあるように、"100"で問題ないと思いました。

bond-miimon のパラメータを"100"から"10"に変更

・0.1秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 496 received, 0.8% packet loss, time 51901ms
rtt min/avg/max/mdev = 0.169/0.426/0.512/0.076 ms

・0.01秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 475 received, 5% packet loss, time 8011ms
rtt min/avg/max/mdev = 0.184/0.429/0.495/0.054 ms

bond-miimon のパラメータを"100"から"50"に変更

・0.1秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 491 received, 1.8% packet loss, time 51907ms
rtt min/avg/max/mdev = 0.172/0.460/0.534/0.051 ms

・0.01秒間隔でpingを打ち続けた場合の影響

--- 192.168.1.30 ping statistics ---
500 packets transmitted, 443 received, 11.4% packet loss, time 7990ms
rtt min/avg/max/mdev = 0.176/0.447/0.518/0.052 ms

Nutanix CE 2.1 AOS 6.8.1 aCLIでLACPを設定

はじめに

前回に続き、今回は Nutanix CE の初期構築時にCLIでLACPの設定をしていきます。前回の記事では、リンクは1本で繋いでいることを想定しています。しかし、リンクを2本繋いでいる場合では、LACPの設定なしに接続はできません。
Nutanix CE では10GbEリンクを使用することを推奨していますが、手元に1GbEしかない場合や環境を用意することが面倒な場合(私ですね)は、リンクを束ねて帯域を増やすことを推奨しています。

If 10 GbE or faster uplinks are available, Nutanix recommends that you use them instead of 1 GbE uplinks.
If you must use only 1GbE uplinks, add them into a bond to increase bandwidth and use the balance-TCP (LACP) or balance-SLB bond mode.
引用元:AHV 6.8 - Host Network Management1

環境

シンプルにスイッチ1台とサーバ1台間を2本の1GbEリンクで束ねていきます。スイッチはCiscoCatalystを使用しています。

設定(サーバ側)

設定はCVMで実施しますので、AHVからCVMへSSHしておきます。また、aCLIコマンドを使用するため Acropolis が起動している必要があります。クラスタが起動していれば Acropolis も起動しているので作業の際はクラスタを起動しておきます。
以下の出力のように初期構築時に作成される vs0 にはすべてのNIC(例:eth0~eth5)が紐づいています。手元の環境でLACPとして扱うインターフェースを絞ります。設定後は、vs0 に紐づく uplink_list が少なくなっていることが分かります。

### 設定前の状態
nutanix@CVM$ acli net.get_virtual_switch vs0
config {
  cluster_configuration_list {
    cluster_uuid: "00062254-83be-d3da-1b06-************"
    default_uplink_grouping: "kMixed"
    host_configuration_list {
      config_failed: False
      host_uuid: "2e178a51-916c-408c-bcf4-************"
      internal_bridge: "br0"
      route_table: 1000
      uplink_list: "eth0"
      uplink_list: "eth1"
      uplink_list: "eth2"
      uplink_list: "eth3"
      uplink_list: "eth4"
      uplink_list: "eth5"
    }
  }
  default: True
  description: "Default Virtual Switch"
  lacp_config {
    lacp: False
  }
  logical_timestamp: 1
  mtu: 1500
  name: "vs0"
  nic_team_policy: "kActiveBackup"
  partially_done: False
  vswitch_uuid: "229028f8-4c09-4dd4-abd7-************"
}

### 設定コマンド(acli net.update_virtual_switch vs0 host_uplink_config="{<host_uuid>:[<NIC>,<NIC>]}")
nutanix@CVM$ acli net.update_virtual_switch vs0 host_uplink_config="{2e178a51-916c-408c-bcf4-************:[eth0,eth1]}"

### 設定後の状態
nutanix@CVM$ acli net.get_virtual_switch vs0
config {
  cluster_configuration_list {
    cluster_uuid: "00062254-83be-d3da-1b06-************"
    default_uplink_grouping: "kMixed"
    host_configuration_list {
      config_failed: False
      host_uuid: "2e178a51-916c-408c-bcf4-************"
      internal_bridge: "br0"
      route_table: 1000
      uplink_list: "eth0"
      uplink_list: "eth1"
    }
  }
  default: True
  description: "Default Virtual Switch"
  lacp_config {
    lacp: False
  }
  logical_timestamp: 1
  mtu: 1500
  name: "vs0"
  nic_team_policy: "kActiveBackup"
  partially_done: False
  vswitch_uuid: "229028f8-4c09-4dd4-abd7-************"
}

vs0 に紐づくNICの絞り込み後は、net.update_virtual_switchでLACPの設定を行います。

### vs0 のLACP設定
nutanix@CVM$ acli net.update_virtual_switch vs0 bond_type=kBalanceTcp lacp_fallback=true lacp_timeout=kFast

nutanix@CVM$ acli net.get_virtual_switch vs0
config {
  cluster_configuration_list {
    cluster_uuid: "00062254-83be-d3da-1b06-************"
    default_uplink_grouping: "kMixed"
    host_configuration_list {
      config_failed: False
      host_uuid: "2e178a51-916c-408c-bcf4-************"
      internal_bridge: "br0"
      route_table: 1000
      uplink_list: "eth0"
      uplink_list: "eth1"
    }
  }
  default: True
  description: "Default Virtual Switch"
  lacp_config {
    lacp: True
    lacp_fallback: True
    lacp_timeout: "kFast"
  }
  logical_timestamp: 5
  mtu: 1500
  name: "vs0"
  nic_team_policy: "kBalanceTcp"
  partially_done: False
  update_in_progress: False
  vswitch_uuid: "229028f8-4c09-4dd4-abd7-************"
}

設定(スイッチ側)

スイッチのコンフィグを記載しておきます。設定する際は、AHVノードに接続する推奨構成があるようで、Cisco Catalyst では以下のように記載されています。

Cisco Catalyst:
no port-channel standalone-disable
**Fallback mode is enabled by default
引用元:How to Enable, Disable, and Verify LACP on AHV hosts2

!
interface Port-channel1
 switchport access vlan 10
 switchport mode access
 no port-channel standalone-disable
!
!
interface GigabitEthernet1/0/1
 switchport access vlan 10
 switchport mode access
 channel-protocol lacp
 channel-group 1 mode active
!
interface GigabitEthernet1/0/2
 switchport access vlan 10
 switchport mode access
 channel-protocol lacp
 channel-group 1 mode active
!

正常に接続できていることを確認します。手元のPCからCVMへPingを打ってみたり、SSHやブラウザからWeb管理画面にログインをしてみてください。

#show etherchannel summary
Flags:  D - down        P - bundled in port-channel
        I - stand-alone s - suspended
        H - Hot-standby (LACP only)
        R - Layer3      S - Layer2
        U - in use      f - failed to allocate aggregator

        M - not in use, minimum links not met
        u - unsuitable for bundling
        w - waiting to be aggregated
        d - default port

        A - formed by Auto LAG


Number of channel-groups in use: 1
Number of aggregators:           1

Group  Port-channel  Protocol    Ports
------+-------------+-----------+-----------------------------------------------
1      Po1(SU)         LACP        Gi1/0/1(P)      Gi1/0/2(P)

#show etherchannel port-channel
Port-channel: Po1    (Primary Aggregator)

------------

Age of the Port-channel   = 0d:0h:23m:58s
Logical slot/port   = 12/1          Number of ports = 1
HotStandBy port = null
Port state          = Port-channel Ag-Inuse
Protocol            =   LACP
Port security       = Disabled
Standalone          = Enabled (independent mode)

Ports in the Port-channel:

Index   Load   Port        EC state        No of bits
------+------+------+------------------+-----------
  0     00     Gi1/0/1     Active             0
  0     00     Gi1/0/2     Active             0

Time since last port bundled:    0d:00h:29m:21s    Gi1/0/1
Time since last port Un-bundled: 0d:0h:53m:46s    Gi1/0/2

追記(2024/11/10)

設定コマンドを実行した際に設定が反映されるまでに少し時間がかかります。その際にタスク状況が確認できるコマンドを以下に記載しています。

### タスク実行状況確認
nutanix@CVM$ ecli task.list include_completed=false
Task UUID       Parent Task UUID        Component       Sequence-id     Type    Status  Creation Time(UTC)        Completion Time(UTC)

参考資料

  1. AOS 6.8 - Acropolis Command-Line Interface (aCLI)
  2. Nutanix CE よろず相談所

Nutanix CE 2.1 AOS 6.8.1 インストールのメモ

1. はじめに

 以前、Nutanix Meetup に参加した際にHCI(ハイパーコンバージドインフラストラクチャー)がどのようなものかやその良さを伺う機会があり、自宅でも環境構築を試みましたが、途中でつまずいてそれっきりになっていました。。。 今回、会社の検証環境でリソースが不足した際に簡単に環境を拡張できるものはないかと考えた際に Nutanix Meetup で聞いた内容を思い出し、HCI製品の Nutanix なら実現できるのではないかと思いました。 後、ご自宅でヤギを飼っている方ともお話をさせていただいた際に、「自宅で試してみます!」と言ったのにやっていなかったことに罪悪感を持っていたので、再挑戦することにしました。

2. 環境

 今回は、 以下の手元の環境で Nutanix CE 2.1 をシングルクラスタで構築します。シングルクラスターで構築した場合、既存クラスタから3ノードや4ノードへ拡張することができないことに留意ください。 ストレージは4枚のうち、2枚はRAID1、残り2枚は非RAID構成で、すべてRAIDコントローラに接続した状態です。 ストレージは注意点があり、ハードウェア要件 の「Storage devices, Hot Tier Flash」で 少なくとも1枚の200GB以上の非NVNe SSDが必要と記載があります。

  • CPU:Intel(R) Xeon(R) 4コア

  • メモリ:64GB

  • ストレージ1(データ用):SATA HDD 2TB (RAID1)

  • ストレージ2(ハイパーバイザー用):SAS HDD 300GB

  • ストレージ3(CVM用):SATA SSD 500GB

  • NIC:1Gbps

3. 事前準備

3-1. アカウント作成

 Nutanix CE はコミュニティ版としてお試しで提供されており、利用するには My Nutanix のアカウントが必要です。公式サイト の右上にあるログインからアカウントを作成します。 アカウント作成でも注意点があり、登録するメールアドレスはGメールやYahoo!メールなどのアドレスは使用できないため、独自に用意したメールアドレスを登録する必要があります。

3-2. Nutanix CE イメージのダウンロード

 アカウント作成で登録したメールアドレスを このサイト で入力し、メールアドレスに届いたリンクからイメージダウンロードのページへアクセスします。 「Installer ISO」の下にあるリンクをクリックして、イメージをダウンロードします。

3-3. ブートUSBメモリの作成

 RufusでブートUSBメモリを作成します。中のデータを書き換えても問題ないUSBメモリを用意して、ダウンロードしたイメージをUSBメモリに焼きます。イメージは6GBちょっとあるので、8GBのUSBメモリがあれば問題ないと思います。下の画像のように、デバイスUSBメモリ、ブートの種類を右の選択をクリックして、ダウンロードしたイメージを指定します。

画像3.1.Rufus

4. インストール

4-1. 起動順序の変更

 BIOSから起動順序をUSBメモリが一番になるように変更します。BIOSへの入り方は機器によって異なるため手元の環境を調べたうえで作業をしてみてください。

4-2. 初期設定

 インストール先の指定やハイパーバイザーとCVMのネットワーク設定を行います。設定項目を移動する際はTabキー、設定項目をすべて埋めて次のページへ移動する際は「Next Page」へ移動して、Spaceキーで決定します。Enterキーではありません!Spaceキーを押してください!ここでEnterキーを押してしまうと、最初の起動からやり直しなので注意してください。
検証として利用する分にはディスク選択はデフォルトのままでもOKだと思いますが、ハードウェア要件 に沿って選択するなら以下の通りになると思います。

  • Hypervisor Boot:32GB以上の SATA DOM または M.2 SSD または SATA SSD/HDD

  • CVM Boot:200GB以上の非NVNe SSD

  • Data:500GB以上のHDDまたはSSD

ハイパーバイザーとCVMのネットワーク設定は、ホスト(以降、AHVと記載)とCVMのIPアドレスが同じセグメントかつインターネットに接続できるセグメントであるポイントを押さえていれば問題ありません。DNSの設定がないことに疑問を持つかもしれませんが、後で設定するタイミングがありますので、安心してください。

画像4.1.初期設定

4-3. ライセンスへの同意

 CE EULA の内容を十字キーで操作し、最後まで移動&確認する必要があります。最後まで移動&確認できていない場合、インストールできません。 内容に同意できれば、Tabキーで移動し、「I accept the end user license agreement. 」にチェックをします。
最後に「Start」に移動して、Spaceキーを押してください。Enterキーではありません!Spaceキーを押してください!

画像4.2.ライセンス画面

4-4. インストールと再起動

 インストール後にブートUSBメモリを外してから、「Y」を入力&Enterキーで再起動を実施します。

画像4.3.再起動

再起動後、以下の画像のようにログイン画面が表示されるとインストール完了です。 インストール完了後、初回は localhost と表示されますが、以降は NTNX-****** と表示されます。原因は不明ですが、どちらもAHVへログインすることに変わりはありません。

画像4.4.ログイン画面

5. クラスタの作成と設定(シングル)

 ここでは、公式の Get Started に沿って記載しますので、不明点や分かりにくい場合は公式サイトを確認ください。それでも解決の糸口が見つからない場合は、コミュニティで質問すると専門の方が問題解決に向けて助けてくださると思います。

5-1. CVMへログイン

 手元のPCからTeraTermPuTTyなどでCVMへSSHやコンソールからAHVへログイン後にCVMへSSHしてログインする方法のどちらかで接続します。 ログインする際は、AHVとCVMでそれぞれ以下の通りとなり、ユーザ名が異なる点に留意してください。

  • AHV ユーザ名:root、パスワード:nutanix/4u

  • CVM ユーザ名:nutanix、パスワード:nutanix/4u

5-2. クラスタの作成

 今回はシングルクラスタで構成するため「--redundancy_factor=1」が必要となり、複数ノードで構成する場合は不要です。CVMのIPアドレスは、インストール時の初期設定した値を入力してください。

$ cluster -s <CVM_IPアドレス> --redundancy_factor=1 create

5-3. クラスタの設定

 クラスタの名前やIPアドレスDNS、NTPを設定していきます。
初めにクラスタの名前を設定します。こちらは任意の名前で問題ありません。

$ ncli cluster edit-params new-name=<クラスタ名>

DNSの設定をします。このDNSはインターネットに接続した際に名前解決を行うフルリゾルバまたはキャッシュDNSサーバを指します。デフォルトで、Googleの提供するパブリックキャッシュDNSサーバ「8.8.8.8」と「8.8.4.4」が設定されていますので、必須設定ではありません。手元にDNSサーバがあり、デフォルト設定を削除したい場合のコマンドも一緒に記載します。

### DNSサーバの追加 ###
$ ncli cluster add-to-name-servers servers=<DNSサーバ>
### DNSサーバの削除 ###
$ ncli cluster remove-from-name-servers servers=8.8.8.8,8.8.4.4

クラスタIPアドレスはインストール時に設定したAHVとCVMのIPアドレスと同じセグメント内のIPアドレスを使用します。当然ですが、他のIPアドレスと重複しないようにしてください。

$ ncli cluster set-external-ip-address external-ip-address=<クラスタ_IPアドレス>

NTPの設定は、デフォルトで NTP Pool Project の「1.pool.ntp.org」と「0.pool.ntp.org」が設定されています。DNS同様、手元にNTPサーバがあり、デフォルト設定を削除したい場合のコマンドも一緒に記載します。

### NTPサーバの追加 ###
$ ncli cluster add-to-ntp-servers servers=<NTPサーバ>
### NTPサーバの削除 ###
$ ncli cluster remove-from-ntp-servers servers=0.pool.ntp.org,1.pool.ntp.org

5-4. クラスタの起動

$ cluster start

クラスタを削除する場合

### クラスタの停止 ###
$ cluster stop

This operation will stop the Nutanix storage services and any VMs using Nutanix storage will become unavailable. Do you want to proceed? (I agree/[N]): I agree <--「I agree」を入力

### クラスタが停止していることを確認
The state of the cluster: stop

### クラスタが停止コマンドによって停止していることを確認
2024-09-21 10:36:01,475Z INFO MainThread cluster:2193 Cluster has been stopped via 'cluster stop' command, hence stopping all services.
2024-09-21 10:36:01,475Z INFO MainThread cluster:3465 Success!

### クラスタの削除 ###
$ cluster destroy

This operation will completely erase all data and all metadata, and each node will no longer belong to a cluster. Do you want to proceed? (Y/[N]): Y <--「Y」を入力

### クラスタが削除成功したことを確認
2024-09-21 11:00:33,856Z INFO MainThread cluster:3465 Success!

5-4. Webコンソール接続

 ブラウザを開いて、「 https://<CVMのIPアドレス>:9440 」にアクセスします。SSL証明書の警告が表示されますが、確認してアクセスします。初回ログイン時は、ユーザ名:admin、パスワード:nutanix/4u でログインします。

画像5.1.Webコンソールログイン画面

ログイン後、初期パスワードを変更するように求めらます。変更後のパスワードは 画像5.2. の下に青文字で記載されている要件に沿ったものを設定します。

画像5.2.初期パスワード変更画面

初期パスワード変更ができると、再度ログイン画面に遷移するので、変更後のパスワードでログインします。

画像5.3.初期パスワード変更後のWebコンソールログイン画面

事前準備で作成した My Nutanix アカウントの情報を入力します。NEXT username は、My Nutanix アカウントを作成した際に登録したメールアドレスを入力します。この時、CVMからインターネットに接続できる状態であることを確認してください。

画像5.4.Nutanixアカウント認証画面

ホーム画面が表示されるとインストールは完了です。

画像5.5.ホーム画面

参考資料

STPにおけるMACアドレス比較のポイント

1. はじめに

 STPでルートブリッジ、ルートポートや指定ポートを決定する基準の中でブリッジプライオリティとMACアドレスを合わせて構成されたブリッジIDを比較して選定することがあります。
デフォルトの設定から変更してない場合、ブリッジプライオリティが同じである可能性は十分あり、MACアドレスを比較することになります。 そんな時、「MACアドレスってどうやって比較するんだ?」となり、検索した際にYahoo!知恵袋で以下の回答が記載されていました。

(一部抜粋)
001dは同じなので省きます。
9とcですが、10進数に治すと9はそのまま9で、cは12です。

既に5桁目でcの方が大きいので上の方が小さいです。
引用元:すみません質問です今CCNA対策でSTPのところをやってまして1

そこで実際にこの回答が正しいことを「Packet Tracer2」を使用して調査したので、その内容と結果を記載していきます。 気になる方は実際に手元の自分の環境で本当に同じようになるのか試してみてください。

2. 構成

 今回は、Packet Tracer でL2SW(2960-24TT)3台を輪(以降、ループと記載)になるように結線します。 論理構成図を少し変わった書き方をしましたが、物理構成図と一緒に載せましたので、参考にしていただければと思います。

画像2.1.STP検証_Packet Tracer

画像2.2.STP検証_物理構成

画像2.3.STP検証_論理構成

3. 内容

3.1 準備

 実際に機器設定も含めて検証してみた内容を記載をしていきます。今回は、STPでルートブリッジを選定する際のプロセスで解説します。
まず設定について、3台のL2SWへの設定ですが、3台とも以下のコンフィグで検証をしています。特に複雑な設定は行わず、VLANインターフェース作成とVLANを物理ポート割り当てる以外は、デフォルトのままで実施しました。

(省略)
!
spanning-tree mode pvst
spanning-tree extend system-id
!
interface FastEthernet0/1
 switchport access vlan 10
!
interface FastEthernet0/2
 switchport access vlan 10
!
(省略)
!
interface Vlan10
 no ip address
!
(省略)

設定後は、L2SWをループするように画像2.2. のようにケーブルで接続します。SW同士を接続するので使用するケーブルは、「copper crossover cable(銅クロスケーブル)」を使用します。なぜ、クロスケーブルを使用するのかはここでは説明を省きます。気になる方は、MDIとMDI-Xについて調べてみてください。

3.2 ルートブリッジの選定

 STPではツリー構造となる起点のSWを選定し、これをルートブリッジと呼びます。ルートブリッジの選定には、ブリッジID(ブリッジプライオリティ+MACアドレス)を比較し、最も小さいSWがルートブリッジになります。ブリッジプライオリティは、デフォルト値が「32768」となっており、すべてのSWがデフォルト値である場合、次の比較対象としてMACアドレスを見ていきます。
各L2SWに設定したVLANに割り当てられたMACアドレスを確認します。コマンドは「show interfaces vlan <VLAN番号>」を実行し、以下の画像3.1. のように表示されたMACアドレスを確認します。ここでの注意点は、物理ポートのMACアドレスではなく、VLANのMACアドレスを確認します(画像3.2. )。

画像3.1.MACアドレスの確認

画像3.2.物理ポートとVLANインターフェースのMACアドレス

各SWのMACアドレスを確認できたら、実際に比較していきます。比較対象は「SW0:0000.0c27.6801」、「SW1:0002.17a9.2601」、「SW2:000a.f33a.dc01」になります。画像3.3. にあるようにMACアドレスは左から比較していきます。左から見ていくと、左から3つは同じ「0」が並んでおり、4つ目から値に差分があります。よって、「SW0:0」、「SW1:2」、「SW2:a」を比較していきます。

画像3.3.MACアドレスの比較

MACアドレスは16進数で構成されており、アルファベットが含まれますが、数字とアルファベットの比較をどのように行うのか説明します。
比較対象を絞るために「SW0:0」と「SW1:2」を最初に見ていきます。数字の比較はどちらが小さいのかは言うまでもなく、「SW0:0」になります。
続いてアルファベットが含まれている「SW0:0」と「SW2:a」を比較します。比較するには、16進数で表現された「SW2:a」を10進数に変換します。10進数変換後は、「SW2:10」になります。これで数字の比較が可能になり、「SW0:0」と「SW2:10」のどちらの値が小さいかというと「SW0:0」になりますので、SW0がルートブリッジに決定されます。SW0が実際にルートブリッジになっていることを確認します(画像3.4.)。

画像3.4.ルートブリッジの確認

4. 結果

 結論、最初の記事であった回答が正しいことがわかりました。本記事とは別に3回ほど環境を変えて試してみましたが、結果はすべて想定通りになりました。MACアドレスの比較では16進数から10進数に変換してから比較することでどちらが対象になるのか判明します。今回は、STPのルートブリッジ選定まででしたが、ルートポートや指定ポートを選定する際にもブリッジIDを元にMACアドレスの比較をすることがあります。気になる方は、この後の流れについても確認してみてください。

参考資料