現場のリアルな課題:ターミナルで数十個のコンテナを管理する限界
Dockerを使い始めた頃は、誰もがdocker run、docker ps、docker logsといったおなじみのコマンドからスタートしたはずです。VPS上で静的配信用のNginxと軽量なNode.jsアプリを1つ動かす程度であれば、何の問題もありませんでした。
しかし、プロジェクトの規模が拡大すると話は一変します。MySQLやRedis、Celery worker、RabbitMQなど次々とコンテナを追加することになります。そしてある日の夜、クライアントから「サイトで502 Bad Gatewayエラーが出ている」と連絡が入り、慌ててサーバーにSSH接続することになります。
ここでお決まりの作業が始まります。停止したコンテナを探すためにdocker ps -aを実行すると、画面いっぱいに複雑なテキスト情報が流れます。目を凝らしてハッシュIDを探し出し、docker logs -f [id]にコピー&ペーストしてログを確認し、さらにdocker inspectで内部ネットワークのIPアドレスを調べる……といった具合です。
さらに、狭いターミナル画面上で目まぐるしく数値が更新されるdocker statsの出力を追うのは非常に骨が折れます。一瞬の油断で本番環境のデータコンテナを誤って削除するコマンドを叩いてしまえば、バックアップからの復旧で徹夜する羽目になりかねません。
なぜ純粋なCLI運用が次第にボトルネックになるのか?
Docker CLIは、自動化スクリプトやCI/CDパイプラインでの利用に非常に適しています。しかし、緊急のデバッグ作業や日常的なステータス確認においては、主に以下の3つの問題が顕著になります:
- 全体の状況を把握しづらい: CLIはテキストを1行ずつ順番に出力するため、サーバー上で15〜20個のコンテナが稼働している場合、どのサービスがメモリの80%を消費しているのか、不要なボリュームが残っていないか、ポート競合が起きていないかを即座に把握するのは困難です。
- トラブルシューティングに時間がかかる: コンテナ内のシェルに入るには、コンテナ名やIDを確認して
docker exec -it [id] /bin/shを実行する必要があります。同僚に共有するためにログを抽出するだけでも複数のコマンドをパイプで繋ぐ手間が生じ、障害発生時のダウンタイムが長引く原因になります。 - 権限管理のリスク: Docker CLIを操作するには、通常ユーザーを
dockerグループに追加する必要があり、これは実質的にroot権限を与えることと同等です。テスターやジュニアエンジニアにログ閲覧だけを許可したい場合でも、誤ってdocker rm -fなどを実行してしまうリスクが常に付きまといます。
現在主流のDocker管理アプローチ
インフラの規模に応じて、システム管理者は一般的に以下の3つのアプローチを検討します:
- Bashスクリプトとエイリアスの併用: 例えば
dps='docker ps --format ...'のようなエイリアスを作成する方法です。手軽でリソースを消費しないメリットがありますが、あくまで一時しのぎに過ぎず、ターミナル依存は解消されず、設定した本人以外には扱いづらいという側面があります。 - KubernetesやRancherの導入: 数十台規模のノードで構成される分散システムには最適解です。しかし、小規模なVPS(2 vCPU、メモリ4GB程度)1〜2台で運用する場合、メインのアプリケーションを動かす前にコントロールプレーンだけでリソースを使い果たしてしまいます。
- Docker Engine上でPortainer CEを運用: これが最もバランスの取れたアプローチです。Portainer自体が非常に軽量なコンテナ(メモリ消費量は100MB未満)として動作し、Dockerソケットに直接接続することで、CLIで行っていたあらゆる操作を直感的なWeb UIに変換してくれます。
Ubuntu 24.04 LTS (Noble Numbat) での詳細なインストール手順
以下に、公式のDockerリポジトリから安定版のDocker Engineを導入し、Portainer CEを構築する手順を解説します。
ステップ1:旧パッケージの削除と公式Docker Engineのインストール
Ubuntu 24.04のデフォルトのaptリポジトリにはdocker.ioパッケージが用意されていますが、新機能のアップデートが遅れる傾向があります。まずは既存の旧パッケージをクリーンアップします:
sudo apt remove -y docker.io docker-doc docker-compose podman-docker containerd runc
sudo apt update
sudo apt install -y ca-certificates curl gnupg
キーリング用ディレクトリを作成し、Dockerの公式GPGキーをダウンロードします:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Dockerのリポジトリをaptのソースリストに追加します:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
Docker Engine、CLI、containerd、およびComposeプラグインを一括でインストールします:
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Dockerサービスが自動起動し、正常に稼働していることを確認します:
sudo systemctl status docker --no-pager
ステップ2:sudoなしでDockerを実行できるようにユーザー権限を設定
デフォルトでは、Dockerコマンドを実行するたびにsudoを付与する必要があります。作業効率を高めるため、現在のユーザーをdockerグループに追加します:
sudo usermod -aG docker $USER
newgrp docker
テスト用コンテナを実行して動作を確認します:
docker run --rm hello-world
ターミナルに「Hello from Docker!」と出力されれば、Docker Engineの環境構築は完了です。
ステップ3:Portainer Community Editionの起動
まず、独立した専用ボリュームを作成します。このボリュームにより、Portainerをアップデートしてもアカウント情報、環境設定、構成履歴が保持されます:
docker volume create portainer_data
続いて、Portainer CEコンテナを起動します:
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
指定した主要なパラメータの意味は以下の通りです:
-p 9443:9443:ブラウザから管理画面にアクセスするためのHTTPSポート。-p 8000:8000:将来的に複数のリモートサーバーを管理する際、Edge Agentとの接続に使用するTCPポート。--restart=always:サーバーの再起動時やサービス異常終了時に、Portainerが自動で再起動するように設定。-v /var/run/docker.sock:/var/run/docker.sock:ホストのDockerデーモンのソケットをコンテナにマウントし、Portainerがホスト上のコンテナを検出・制御できるように設定。
この構成は、メモリ2GBのVPSおよびUbuntu 24.04のステージングサーバーの両方で検証済みです。AppArmorの互換性問題やネットワークブリッジの競合なども発生せず、すべてのプロセスがスムーズに動作しています。
ステップ4:adminアカウントの作成と初期設定
ブラウザを開き、以下のアドレスにアクセスします:
https://<サーバーのIPアドレス>:9443
Portainerは自己署名証明書(オレオレ証明書)を使用しているため、ブラウザにセキュリティ警告が表示されます。その場合は、詳細設定(Advanced)をクリックし、続行する / サイトに移動する(Proceed)を選択してください。
初期セットアップ画面が表示されたら、adminアカウントのパスワードを設定します(12文字以上が必須)。注意:Portainerにはセキュリティ上のタイムアウト機能があり、起動後5分以内にパスワードを設定しないとロックされます。制限時間を過ぎてしまった場合は、ターミナルでdocker restart portainerを実行してタイマーをリセットしてください。
ログインに成功したら、local環境を選択します。ダッシュボードが開き、以下の機能にすぐアクセスできます:
- コンテナ一覧: Running、Stopped、Unhealthyなどのステータスが一目で分かり、Start/Stop/Restartなどの操作ボタンも横に配置されています。
- リアルタイムログ:
grepの構文を覚えていなくてもエラーキーワードで即座に検索でき、自動スクロール機能も備わっています。 - コンソール: ブラウザのタブ上から直接コンテナ内の
/bin/shや/bin/bashシェルにアクセスできます。 - 統計情報(Stats): 各コンテナのCPU、メモリ、ネットワークI/Oの推移グラフが1秒ごとにリアルタイム更新されます。
本番運用で押さえておくべき実践ポイント
Portainerをパブリックサーバーで実際に運用する際は、以下の2つのセキュリティ・保守対策を講じることを推奨します:
- ポート9443の保護: このポートをインターネット全体に公開したままにしないでください。UFWファイアウォールを使用して制限し、特定の固定IPのみアクセスを許可します(
sudo ufw allow from <あなたのIPアドレス> to any port 9443 proto tcp)。ドメイン経由でアクセスする場合は、Nginx Proxy ManagerやCloudflare Tunnelを介して2要素認証(2FA)を設定するのが安全です。 - 不要なリソース(Dangling Images & Volumes)の定期削除: 新しいコードをビルドするたびに、タグのない不要なDockerイメージ(dangling)が蓄積しがちです。管理画面のImagesを開き、UnusedでフィルタリングしてRemoveをクリックするだけで、10GB〜30GBもの無駄なディスク領域を簡単に解放できます。

