TT Lab
はじめる
学ぶ 学習パス コース

LFCS — Linux Foundation認定システム管理者

enable と start は別の問い — systemd・nginx・iptables・bond・chrony・podman

TT Labで続きを見る

一言でいうと

Linux管理の半分は、「今動くか」と「次回も動くか」を別々に問うことです。systemctl startとenable、sysctl -wと/etc/sysctl.d、iptables -Aとiptables-save、ip linkとnetplan。ペアごとに、前者は今、後者は次の起動です。LFCSは両方を要求し、このモジュールのラボは両方を採点します。

なぜ必要なのか

前のモジュール(lfcs-operating-systems、lfcs-networking)は、Podで動いていたため、ユニットファイルを書いてsystemd-analyze verifyで検証するところまでがすべてでした。タイマーが実際に動くか、nginxが本当にバックエンドへ渡すか、iptablesのルールがパケットを捨てるかは、見られませんでした。このモジュールは、Ubuntu 24.04のVMで、rootで動きます。採点ツールが、systemctl is-active、curl、iptables -S、/sys/class/net、sysctl -n、podman inspectで、今のシステムを見ます。

1つ、境界があります。VMは、外へはDNSとパブリックインターネットの80/443だけが開いていて、UDP 123は塞がれています。そのため、chronyはサーバーを知っていても同期できず、そのステップは、設定・サービスの状態・出力ファイルで採点します。そして、採点エージェントが8899/tcpで入ってくるので、iptablesのINPUTのデフォルトポリシーをDROPに変えたり、8899・22を塞いだりすると、その瞬間から採点が届かなくなります。

どう動くのか

タイマーは、サービスを呼び出すユニットです。systemd.timer(5)によると、.timerユニットは、Unit=を省略すると、名前が同じ.serviceを有効化します。OnBootSec=は、起動後の最初のタイミング、OnUnitActiveSec=は、そのサービスが最後に有効化されてからどれくらいごとか、です。呼び出される側は、systemd.service(5)のType=oneshotである必要があり、そうすることで「1回動いて終わる仕事」として扱われます。そして、enableは、[Install]節のWantedBy=timers.targetを見て、シンボリックリンクを作ることで、startは、今起動することです。--nowが、その2つを一度に行います。is-enabledとis-activeが、異なる答えを出しうるということが、このステップのすべてです。

リバースプロキシは、前で受けて後ろへ渡します。ngx_http_proxy_moduleのproxy_passが、その1行です。Ubuntuのパッケージは、sites-availableに設定を置き、sites-enabledのシンボリックリンクで有効にします。デフォルトのサイトも、default_serverで80を掴んでいるので、削除しないと、nginx -tが重複を拒否します。バックエンドはpython3 -m http.serverで十分ですが、手で&を付けて起動すると、セッションが切れたときに一緒に死にます。ユニットにして、systemdに掴ませます。

Netfilterは、テーブルとチェーンです。iptables(8)のnatテーブルはアドレスを書き換え、filterテーブルは通過・遮断を決めます。PREROUTINGはパケットが入ってきた直後(ルーティングの前)、INPUTはこのホスト宛てに来たもの、OUTPUTはこのホストが作ったものです。そのため、自分自身に送ったパケットはPREROUTINGを通りません。curl localhost:8080では、DNATを見られません。iptables-extensions(8)のDNATは、--to-destinationで宛先を変更し、REDIRECTはその特殊形です。DROPは応答なしで捨てるので、クライアントは拒否ではなくタイムアウトを見ます。ルールは再起動すると消え、iptables-saveの出力が、次の起動の材料です。Ubuntu 24.04のiptablesは、nf_tablesバックエンドの上で動いていることも、知っておきましょう。

ブリッジとボンド。ブリッジはソフトウェアのスイッチで、ボンドは複数のリンクを1つにまとめます。ip-link(8)でtype dummy|bridge|bondを作成し、masterでメンバーを入れます。カーネルのbondingドキュメントのactive-backupは、1つだけを使い、それが死んだら別のものに切り替わるモードなので、スイッチの設定が不要で、スレーブは入れる前にdownである必要があります。実際のNICが1つしかないVMでは、メンバーをdummyインターフェースで作ります。カーネルから見れば、本物のインターフェースです。同じ構成を宣言的に書くのが、netplan YAMLのbridges・bonds節で、このラボは/etc/netplanの外に置いて、適用しません。実際のNICを失うと、戻る道がないからです。

時刻とタイムゾーンは別のものです。カーネルの時計は常にUTCで、タイムゾーンは表示のルールです。timedatectlのset-timezoneが後者を変え、chrony.confのserver … iburstが前者を合わせます。iburstは、開始直後にパケットをまとめて送って、最初の同期を早めるオプションです。chronycのsourcesの最初の列が?なら、まだ応答を受け取っていないことで、このVMでは、それが正常です。

コンテナイメージはtarです。podman-import(1)は、tarball 1つを1層のイメージにします。Dockerfileもレジストリもなく、/bin/busybox1つでイメージになることを手で見ると、イメージとは何かが、頭に残ります。このラボのpodmanはrootで動き、podman-run(1)の--network noneで、ネットワーク設定なしで実行します。

sysctlは、2回行います。sysctl(8)の-wは今のカーネルを変更し、sysctl.d(5)のファイルは起動時に読み込まれます。sysctl --systemが標準のディレクトリを順に適用するので、ファイルを書いたあとにそれを実行すれば、今と次の起動が一緒に合います。ロードアベレージは、proc_loadavg(5)が説明するとおり、実行中または実行待ち(そしてディスクI/O待ち)のタスク数の平均で、CPUの数と比べて初めて意味が生まれます。

現場での姿

「cronに入れたのに動かない」のsystemd版が、「タイマーをstartしただけ」です。再起動後にsystemctl list-timersになければ、is-enabledから見ます。逆に、enableだけしてstartをしなければ、次の起動まで何も動きません。

「ファイアウォールのルールを入れたのに、再起動したら消えた」は、iptablesの古典です。ルールはカーネルメモリにあり、保存したファイルを起動時に復活させるのは、別のサービス(Ubuntuはiptables-persistentのrules.v4)の仕事です。ラボの最後に、iptables-saveをファイルに残す理由です。

ノードが「遅い」という報告を受けたら、uptimeのロードアベレージをnprocで割ります。4コアで4.0はいっぱいに埋まった状態で、1コアで4.0は3つが待っている状態です。topのwaが大きければディスク、stが大きければ、ハイパーバイザーの隣人がCPUを食っています。

次のラボですること

oneshotサービス + 1分タイマー(enable・start・ログ) → pythonバックエンドのユニット + nginxプロキシ(デフォルトサイトは無効化) → DNAT 8080→80と9999のDROP(8899・22はそのまま) + iptables-save → dummyの上のbr0・bond0とnetplanの文書 → chronyのサーバー・タイムゾーン・出力ファイル → git init・branch・--no-ffマージ → busybox tarをpodman importして実行 → sysctlファイル + --system → uptime・top・NPROC。ステップごとに「今」と「次の起動」の両方を押さえてください。採点ツールが、両方を見ます。