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 の環境ですが、もうしばらく利用したいと思います。次のエントリは今回作成した環境を利用します。が、直接的・動作的には全く関係ないですが、好ご期待;-)。