【ITニュース解説】Day 43: A Port Is Closed Until You Publish It, and an AZ Name Is Not an AZ
2026年09月17日に「Dev.to」が公開したITニュース「Day 43: A Port Is Closed Until You Publish It, and an AZ Name Is Not an AZ」について初心者にもわかりやすく解説しています。
ITニュース概要
Dockerでコンテナを公開するには、ホストとコンテナのポートを正確にマッピングする必要がある。ポート番号は独立し、ホスト側を別途指定しないと外部からアクセスできない。AWSの可用性ゾーン名はアカウントにより異なるため、エラーメッセージのゾーン名を鵜呑みにせず、AZ IDで確認すべきだ。複雑なAWS CLI引数にはJSON形式を使うと確実だ。
ITニュース解説
今回の解説では、システムを構築する上で遭遇する、見た目の「ラベル」と実際の「実体」が異なることによって生じる誤解と、その対処法について具体的に掘り下げていく。DockerのポートマッピングとAWSのアベイラビリティゾーンという二つの事例を通じて、その本質を理解することは、システムエンジニアを目指す上で非常に重要だ。
まずDockerのポートマッピングについて考えてみよう。Dockerコンテナは独立した環境でアプリケーションを実行するための技術で、ウェブサーバーのようなサービスは通常、特定のポート(例: HTTP通信なら80番ポート)で待ち受けている。しかし、このコンテナ内のポートは、コンテナが動作しているホスト(物理サーバーや仮想マシン)のポートとは直接紐付いていない。
例えば、docker run -d --name demo -p 6000:80 nginx:stableというコマンドは、NginxというウェブサーバーをDockerコンテナとして起動する。ここで重要なのは-p 6000:80という部分だ。これは「ホストの6000番ポートへのアクセスを、コンテナ内の80番ポートへ転送する」という意味になる。ホストの6000番ポートとコンテナの80番ポートは、完全に独立した二つの数字であり、たまたま同じ数字にすることもできるが、その必要はない。Nginx自身は、コンテナ内部の80番ポートで動作しており、ホスト側のポート番号が何であるかは意識していない。
もし-pオプションを指定せずにコンテナを起動した場合、そのコンテナはホストや同じDockerネットワーク内の他のコンテナからはアクセスできるが、外部からは一切アクセスできない。これは、コンテナが壊れているわけではなく、単に外部への扉が開かれていない状態だ。Dockerネットワークの役割はコンテナ同士の通信を制御することにあり、ポートマッピングはホストからコンテナへの外部アクセスを制御する、というようにそれぞれ異なる目的がある。Dockerファイル内でEXPOSE 80のようにポートを宣言する指示があるが、これは単に「このコンテナ内のアプリケーションは80番ポートで動くことを意図している」というドキュメントとしての意味合いが強く、実際にポートを公開する機能はないことに注意が必要だ。
さらに、ポートマッピングの際に127.0.0.1:6000:80のようにIPアドレスを指定すると、ホストのループバックアドレス(localhost)からのみアクセス可能になる。一方、単に-p 6000:80と指定した場合は、ホストのすべてのネットワークインターフェース(例えば、インターネットからアクセス可能なパブリックIPアドレスも含む)でそのポートが公開されるため、セキュリティの観点からも意識しておくべき点だ。
次に、AWSのアベイラビリティゾーン(AZ)の取り扱いについて見ていこう。AWSでEKS(Elastic Kubernetes Service)クラスターをプロビジョニングする際、どのアベイラビリティゾーンにリソースを配置するかを指定する必要がある。この記事の事例では、us-east-1eというAZ名を指定したところ、「Cannot create cluster because EKS does not support creating control plane instances in us-east-1e」というエラーが発生した。このエラーメッセージから、us-east-1eがサポートされていないAZだと解釈しがちだが、実はこれはアカウント固有の事情にすぎない。
AWSのドキュメントによれば、EKSのコントロールプレーンは特定のアベイラビリティゾーンID(例えばuse1-az3)には配置できないという制限がある。しかし、ユーザーがAWSコンソールやCLIで目にするus-east-1eのようなAZ名は、アカウントごとにランダムにAZ IDにマッピングされている。つまり、あるアカウントでus-east-1eがuse1-az3を指す場合でも、別のアカウントではus-east-1eが別のAZ ID(例えばuse1-az1)を指す可能性があるのだ。
このため、「us-east-1eを避ける」というルールは、その特定のアカウントでしか通用しない。汎用的なルールとして使うと、別のアカウントでは問題ないAZを避けてしまったり、逆に避けるべきAZを誤って使ってしまう可能性がある。このような状況を避けるためには、aws ec2 describe-availability-zones --query 'AvailabilityZones[].{Name:ZoneName,Id:ZoneId}'のようなコマンドを使って、AZ名とAZ IDの対応関係を動的に取得し、AZ IDに基づいて判断するのが正しいアプローチとなる。エラーメッセージは、目の前のアカウントの真実を教えてくれるが、それがシステム全体の普遍的なルールであるとは限らない、ということを強く示唆している。
AWS CLIのコマンド引数に関する注意点も挙げられる。特に、リスト(配列)を含む構造体を指定する際に、CLIの短縮記法が曖昧になる場合がある。例えば、--resources-vpc-config subnetIds=subnet-a,subnet-b,subnet-c,endpointPublicAccess=falseのように記述すると、カンマがサブネットIDの区切りなのか、次のフィールドの区切りなのか判別できず、パーサーが混乱することがある。このような場合、JSON形式で引数を指定することで、曖昧さを完全に排除できる。--resources-vpc-config "{\"subnetIds\":[$SUBNET_JSON],\"endpointPublicAccess\":false}"のように、引用符で囲み、内部でJSONの書式に従うことで、意図通りの設定を適用できる。AWS CLIのコマンドは、引数の形式が一貫していない場合が多いため、構造体の中にリストを渡す際には、JSON形式の使用を検討する習慣を身につけることが賢明だ。
その他の細かな点も見ておこう。EKSクラスターのバージョンを指定する際、1.29のように特定のバージョンをハードコードするのは避けるべきだ。Kubernetesは年間数回のマイナーリリースがあり、ハードコードされたバージョンはすぐに古くなってしまう。aws eks describe-cluster-versionsコマンドで現在利用可能なバージョンを動的に取得し、常に最新かつ推奨されるバージョンを使用することが推奨される。これは、AMI(Amazon Machine Image)やRDSのエンジンバージョンなど、AWSの他のサービスでも同様に適用できる習慣だ。
また、EKSクラスターのIAMロールにアタッチするサービスプリンシパルはeks.amazonaws.comである。AWSのサービスプリンシパルはサービスごとに異なり、lambda.amazonaws.comやec2.amazonaws.comなど様々な形式がある。正しいサービスプリンシパルを指定しないと、IAMロールが正しく機能せず、クラスターの操作ができなくなってしまう。
最後に、EKSクラスターがACTIVE状態になったとしても、それが「ワークロードを受け入れる準備ができた」ことを意味するわけではない点も重要だ。ACTIVEはクラスター自体が起動し、コントロールプレーンが動作していることを示すが、実際にアプリケーションを実行するためのノード(EC2インスタンスなど)がアタッチされていなければ、Podをスケジュールしても「Pending」状態のままで、実行されることはない。クラスターとノードは別々にプロビジョニングされるため、この点を理解しておく必要がある。
今日の事例が示す根本的な教訓は、「ラベルは、それが指し示すものそのものとは限らない」ということだ。ホストの6000番ポートとコンテナの80番ポートは、同じサービスへのアクセス経路を提供するが、異なる名前を持つ。us-east-1eとuse1-az3は同じアベイラビリティゾーンを指すが、その呼び方はアカウントによって異なる。システム開発において、エラーメッセージやドキュメントに書かれている情報が、自分の特定の設定に関するものなのか、それとも普遍的なシステムルールなのかを常に疑い、確認する習慣を持つことが、問題解決と学習の鍵となる。