テクノロジー · 実用ガイド
Linux の「Address already in use」— kill や再試行の前に socket 所有者を証明する
ポート番号だけでは原因になりません。プロトコル、family、address、port または path、network namespace を保存し、その正確な tuple を所有する process または socket unit を証明してから、一つの所有境界だけを修正します。

ポート番号だけでは原因になりません。プロトコル、family、address、port または path、network namespace を保存し、その正確な tuple を所有する process または socket unit を証明してから、一つの所有境界だけを修正します。
EADDRINUSE は要求した address の bind 競合で、権限不足や存在しないローカル address とは別です。 TCP と UDP は別で、IPv4 と IPv6 の wildcard listener は設定により重なる場合があります。
1. 正確な bind tuple と失敗 syscall を保存する
TCP、UDP、UNIX socket、IPv4/IPv6、特定または wildcard address、port/path、process、container、service unit、network namespace を記録します。変更前に EADDRINUSE、EADDRNOTAVAIL、EACCES を区別します。
起動 command、設定、unit file、時刻を保存します。tuple と所有境界が分かる前に runtime を一括 kill、UNIX socket path を削除、reuse flag を有効化しません。
2. 正しい namespace で所有者を調べる
bind を試みた namespace 内で numeric な listening と bound-inactive socket を確認し、権限があれば local tuple、state、UID、inode、PID、command を記録して起動時間軸と比較します。
service process と socket unit の両方を確認します。socket activation では systemd が正しく listener を所有します。service が継承 descriptor を無視して再 bind すると競合します。
3. wildcard・activation・handoff 競合を分類する
特定 address と wildcard、IPv6 wildcard と IPv4、TCP と UDP、UNIX path と abstract socket を区別します。同じ番号だけで同じ socket と判断しません。
一時 socket で free port を調べて閉じ、後で bind すると、check と use の間に別 process が取得できます。実際の bind で atomic reservation または bounded retry が必要です。
4. 証明した所有境界を一つだけ修正する
不要な所有者は本来の supervisor で停止し、socket が閉じたことを確認して再起動します。socket unit が所有者なら service は継承 descriptor を使い、重複設定は一つの address と family に統一します。
SO_REUSEADDR は文書化された restart の範囲だけで使います。SO_REUSEPORT は全 listener が bind 前に参加し同一 UID 境界が適切な設計だけで使い、未知の所有者を隠しません。
5. 再起動して安定した所有を証明する
staging または管理された時間に clean start し、正確な tuple が期待する PID/unit と namespace に属すること、health または protocol response を確認し、本来の supervisor で stop/restart します。
高速再起動と並行起動を一回ずつ試します。明確な一所有者または設計済み reuse group、断続的 bind failure なし、stop 後の orphan listener なし、rollback 可能を合格条件にします。
