コンテナ同士を繋ぐ
このラボは本物のVM上で動きます
この環境はPodではなく、KubeVirtが起動した仮想マシンです。Linuxカーネルが別に動き、systemdが実際にサービスを管理し、dockerは模倣ではなく本物のDockerエンジンです。docker runで起動したコンテナは実際にプロセスになり、docker execもdocker logsもそのまま動作します。
以前はこのラボがPodの中で動いていました。カーネル権限をすべて落とした環境だったため、コンテナを起動するステップが塞がれており、イメージアーカイブを自分で展開してみるという回り道で学んでいました。もう回り道は必要ありません。
知っておくべきことが2つあります。
- 最初の起動に1分ほどかかります。VMが起動してDockerをインストールするためです。Podのラボ(通常40秒)より遅くなります。
- ブラウザープレビューはありません。VMへの接続は、採点用のポート1つしか開いていません。Webサーバーを起動した場合は、VMの中で
curlを使って確認してください。
目標
ユーザー定義ネットワークで、コンテナ同士が名前で通信できるようにし、ネットワークが違うとお互いが見えないことを確認し、ポートをループバックにだけ開く習慣を身につけます。
なぜ重要なのか
コンテナネットワーキングの事故は、ほとんどが2つの誤解から生まれます。1つは、「コンテナの127.0.0.1はホストの127.0.0.1だろう」という思い込みで、もう1つは、「ポートを開けたのだからファイアウォールが防いでくれるだろう」という思い込みです。1つ目は、ネットワークネームスペースがループバックまで複製するという事実で、2つ目は、コンテナに向かうパケットがホストを最終的な宛先にしないという事実で説明されます。バインドアドレスを制限することが、最もシンプルで確実な制御だという結論が、ここから出てきます。
ステップ
/root/ops2を作成し、dk-netというユーザー定義ネットワークを作ります。nginx:1.27-alpineをdk-apiという名前でdk-netに接続し、バックグラウンドで実行します。alpine:3.20をdk-clientという名前で、同じdk-netに接続し、動き続けるように実行します。dk-clientの中から、コンテナ名でdk-apiにHTTPリクエストを送り、応答を/root/ops2/dns.txtとして保存します。nginxのデフォルトページが入っていれば構いません。dk-net2というネットワークを新しく作り、dk-lonelyコンテナを、そのネットワークにだけ接続して起動します。dk-lonelyからdk-apiに届かないことを確認し、/root/ops2/isolated.txtにunreachableと書きます。nginx:1.27-alpineをdk-pubという名前で起動し、コンテナの80番ポートを、127.0.0.1の8080番ポートにだけパブリッシュします。dk-lonelyを削除せずに、dk-netにも追加で接続したうえで、dk-apiという名前が解決されるかを確認します。/root/ops2/net.mdに、dk-api、dk-client、dk-lonely、dk-pubを1行ずつ書き、dk-lonelyの行には所属するネットワークの数を、dk-pubの行にはパブリッシュしたバインドアドレスとポートを、一緒に書きます。
参考
docker network connect <네트워크> <컨테이너>で、すでに起動しているコンテナにネットワークを追加します(プレースホルダーはネットワーク名とコンテナ名です)。docker exec dk-client getent hosts dk-apiで、名前解決だけを別に確認できます。- この環境はrootlessなので、1024未満のポートは開けません。8080を使います。
- よくある間違い1: ステップ3でalpineをそのまま起動すると、すぐに終了します。動き続けるコマンドを指定してください。
- よくある間違い2: ステップ6でバインドアドレスを省略すると、すべてのインターフェースに開放されます。採点では、これを失敗とみなします。
ユーザー定義ネットワークを作る
/root/ops2を作成し、dk-netというユーザー定義ネットワークを作ります。
ネットワークを扱うサブコマンドのグループがあります。デフォルトのブリッジを使わない理由は、名前解決のためです。
ネットワークにコンテナを接続する
nginx:1.27-alpineをdk-apiという名前でdk-netに接続し、バックグラウンドで実行します。
コンテナを起動するとき、どのネットワークに接続するかを指定できます。inspectのNetworkSettings.Networksで確認してください。
同じネットワークにもう1つ
alpine:3.20をdk-clientという名前で、同じdk-netに接続し、動き続けるように実行します。
2つ目のコンテナは、動き続けている必要があります。そうでないと、中でコマンドを実行できません。
名前でお互いを見つける
dk-clientの中から、コンテナ名でdk-apiにHTTPリクエストを送り、応答を/root/ops2/dns.txtとして保存します。nginxのデフォルトページが入っていれば構いません。
同じユーザー定義ネットワークにいれば、コンテナ名がそのままホスト名です。中からHTTPリクエストを送り、応答を保存してください。
別のネットワークは見えない
dk-net2というネットワークを新しく作り、dk-lonelyコンテナを、そのネットワークにだけ接続して起動します。dk-lonelyからdk-apiに届かないことを確認し、/root/ops2/isolated.txtにunreachableと書きます。
新しいネットワークにだけ接続したコンテナからアクセスを試し、結果を結論の単語で記録してください。
ホストにポートを開く
nginx:1.27-alpineをdk-pubという名前で起動し、コンテナの80番ポートを、127.0.0.1の8080番ポートにだけパブリッシュします。
バインドアドレスを省略すると、すべてのインターフェースに開放されます。ループバックに制限してください。1024未満のポートは、この環境では開けません。
すでに起動しているコンテナをネットワークに追加で接続する
dk-lonelyを削除せずに、dk-netにも追加で接続したうえで、dk-apiという名前が解決されるかを確認します。
コンテナを作り直さずに、ネットワークを接続するコマンドがあります。既存の接続は維持する必要があります。
到達関係のまとめ
/root/ops2/net.mdに、dk-api、dk-client、dk-lonely、dk-pubを1行ずつ書き、dk-lonelyの行には所属するネットワークの数を、dk-pubの行にはパブリッシュしたバインドアドレスとポートを、一緒に書きます。
各コンテナがどのネットワークにいくつ接続されているか、どのポートがどこに開いているかを、実際の値で書いてください。