タグ: 開発環境

  • Dockerの辛いところ|20年現場で見てきた「便利だけど困る」7つの落とし穴

    Dockerの辛いところ|20年現場で見てきた「便利だけど困る」7つの落とし穴

    「Dockerさえ入れれば全部解決する」

    そんな期待を胸にDockerを導入したものの、気づけば新たな悩みと格闘している…。開発の現場でこんな経験をしたことはないでしょうか。

    前回の記事でDockerのメリットをお伝えしましたが、20年以上エンジニアとして様々な現場を見てきた私としては、正直に言わなければならないこともあります。Dockerは確かに革命的な技術ですが、「銀の弾丸」ではありません。

    この記事では、Dockerを実際に使い込んでいく中で遭遇する「辛いところ」を率直にお伝えします。これからDockerを導入しようとしている方も、すでに使っていて困っている方も、事前に知っておくことで対策が立てやすくなるはずです。

    辛いところ1:Mac・Windowsだと動作が遅い

    Dockerの最大の落とし穴のひとつが、Mac・Windows環境での動作速度です。

    「軽量で高速」がDockerの売りのはずなのに、実際に使ってみると「なんか遅い…」と感じる方は多いのではないでしょうか。特に開発中にファイルを編集するたびに反映が遅かったり、ビルドに時間がかかったりすると、せっかくの開発効率が台無しです。

    なぜ遅くなるのか

    根本的な原因は、DockerがLinuxのカーネル機能を前提としているところにあります。

    LinuxマシンでDockerを動かす場合、コンテナはホストOSのカーネルをそのまま使うため、オーバーヘッドはほぼありません。しかしMacやWindowsの場合、Dockerを動かすためにLinux VMを内部で立ち上げており、その上でコンテナが動いています。

    特に問題になるのが、ホストマシンとコンテナ間のファイル同期です。開発時には自分のエディタでコードを編集し、それをコンテナ内のアプリケーションで動かすわけですが、このファイル同期処理が意外と重いのです。MacのファイルシステムとLinuxのファイルシステムを橋渡しするために、変換処理が都度走ることになります。

    対処法

    Windows環境の場合、WSL2(Windows Subsystem for Linux 2)を活用し、ソースコードをWSL2側のファイルシステムに置くことで大幅に改善できます。Linux側にファイルを置けば変換処理が不要になるからです。

    Mac環境では、Docker Desktopの設定でCPUやメモリの割り当てを増やす、あるいはボリュームマウント時に「cached」や「delegated」オプションを使うことで、多少の改善が見込めます。

    ただし、これらは根本解決ではありません。本当にパフォーマンスが必要な場面では、Linux環境での開発を検討するのも選択肢のひとつです。

    辛いところ2:ボリュームマウントの権限問題

    「Permission denied」

    Dockerを使っていると、このエラーに何度も遭遇することになります。特にLinux環境でDockerを使う場合、ボリュームマウント時の権限問題は避けて通れません。

    何が起きているのか

    ホストマシンのディレクトリをコンテナにマウントする際、ファイルの所有者情報(UID/GID)がそのまま引き継がれます。問題は、ホストで使っているユーザーとコンテナ内のユーザーのUID/GIDが一致しないケースです。

    たとえば、ホストでUID=1000のユーザーとして作業していて、コンテナ内ではrootユーザー(UID=0)で動作している場合、コンテナ内で作成されたファイルはホスト側から見るとrootの所有物になり、一般ユーザーでは編集できなくなってしまいます。

    興味深いことに、Docker Desktop for MacやWindowsではこの問題が発生しにくいです。内部でうまくハンドリングしてくれているようですが、Linux環境では自分で対処する必要があります。

    対処法

    よく使われる対処法は、docker run時に「-u」オプションでユーザーを指定するか、/etc/passwdと/etc/groupを読み取り専用でマウントしてホストのユーザー情報を共有する方法です。

    Dockerfileでユーザーを作成し、そのユーザーで実行するように設計しておくことも有効です。ただし、環境ごとにUID/GIDが異なる場合は、ビルド時に引数として渡すなどの工夫が必要になります。

    正直なところ、この問題に対する「これだ」という万能解はありません。プロジェクトの状況に応じて最適な方法を選ぶしかないのが現状です。

    辛いところ3:気づいたらディスクが満杯

    「なんかPCの容量がないな…」と思って調べてみたら、Dockerが数十GBを占有していた。そんな経験をした方も多いのではないでしょうか。

    なぜ容量を食うのか

    Dockerはイメージのレイヤー構造を採用しており、効率的に容量を節約できる仕組みになっています。しかし実際の運用では、様々な「ゴミ」が蓄積していきます。

    まず、使われなくなったイメージ(dangling image)です。同じタグで何度もビルドを繰り返すと、古いイメージはタグを失い「none」という状態で残り続けます。次に、停止したままのコンテナ。明示的に削除しない限り、ディスク上にデータが残ります。そしてビルドキャッシュ。ビルド高速化のためにキャッシュされたレイヤーが積み重なっていきます。

    さらにWindowsの場合、やっかいな問題があります。Dockerの仮想ディスク(ext4.vhdx)は自動的に拡張されますが、中身を削除しても自動的には縮小されません。つまり、一度膨らんだ仮想ディスクは手動で圧縮しない限りそのままなのです。

    対処法

    定期的なお掃除が必要です。まずは「docker system df」で現状を確認しましょう。「docker system prune」で未使用のコンテナ、ネットワーク、イメージを一括削除できます。ボリュームも含めて削除したい場合は「–volumes」オプションを付けます。

    Windowsの場合は、さらに仮想ディスクの圧縮も必要です。Docker Desktopを停止した状態で、PowerShellの「Optimize-VHD」コマンドを使って圧縮できます(Hyper-Vが必要)。

    私の経験では、月に一度くらいはお掃除の時間を取るようにしています。自動化したい場合は、CI/CDパイプラインに組み込むか、cronで定期実行するのも手です。

    辛いところ4:ネットワークとポートの罠

    Dockerのネットワーク周りは、初心者にとってかなりの鬼門です。「繋がらない」「意図せず公開されていた」など、トラブルの温床になりがちです。

    よくあるトラブル

    まず、EXPOSEに関する誤解。Dockerfile内でEXPOSEを書いても、それだけではポートは外部に公開されません。単なるドキュメント的な意味しかなく、実際に公開するには「docker run -p」で明示的に指定する必要があります。

    逆に危険なのが、ポートマッピングのデフォルト挙動です。「-p 8080:80」のように指定すると、デフォルトでは全てのインターフェース(0.0.0.0)に対してポートが公開されます。ファイアウォールで閉じているつもりでも、Dockerは独自のiptablesルールを設定するため、ufwなどの設定を迂回してしまいます。

    公衆WiFiに繋いだ状態で開発用コンテナを立ち上げていたら、LAN内の他の端末からアクセスできてしまった…という怖い話も実際にあります。

    対処法

    ローカル開発では「-p 127.0.0.1:8080:80」のように、必ずlocalhostを指定するようにしましょう。docker-compose.ymlでも「ports: “127.0.0.1:8080:80″」と書けます。

    また、依存サービスの起動順序にも注意が必要です。docker-composeのdepends_onは起動順序を制御しますが、サービスが「使える状態になったか」までは保証しません。アプリ起動時にデータベースがまだ準備中…というケースは珍しくありません。dockerizeなどのツールを使って、依存サービスの起動を待つ仕組みを入れることをおすすめします。

    辛いところ5:学習コストが意外と高い

    「Dockerは簡単」という評判を聞いて始めてみたものの、覚えることが多くて挫折しそうになる。これも多くの人が経験することです。

    覚えなければならないこと

    Dockerを使いこなすには、最低限以下の知識が必要になります。

    Dockerの基本概念(イメージ、コンテナ、レイヤー)、Dockerfileの書き方、docker-compose.ymlの記法、ネットワークの仕組み、ボリュームとデータ永続化、そしてLinuxの基礎知識。特にLinuxに馴染みがない方にとっては、コンテナ内でのデバッグ作業がかなりハードルが高く感じるでしょう。

    さらに本番環境での運用を考えると、セキュリティ設定、リソース制限、ログ管理、オーケストレーション(Kubernetes等)といった知識も必要になってきます。

    対処法

    一度に全部を覚えようとしないことが大切です。まずは「docker run」と「docker-compose up」だけで動かせる環境を用意し、実際に使いながら少しずつ理解を深めていきましょう。

    既存のdocker-compose.ymlを読み解くところから始めるのも良いアプローチです。先人が作った設定を眺めながら「なぜこう書いてあるんだろう」と調べていくと、実践的な知識が身につきます。

    辛いところ6:LinuxベースであることのしがらみがLinux以外では制限になる

    DockerはLinuxのカーネル機能をベースにした技術です。この事実が、いくつかの制限を生み出しています。

    異なるOS間の制約

    Linux上でWindowsコンテナを動かすことはできませんし、その逆もできません(Docker Desktop for Windowsでは切り替えは可能ですが、同時には使えません)。これは、コンテナがホストOSのカーネルを共有する仕組みだからです。

    また、仮想マシンと比較すると分離レベルが低いという特性があります。コンテナ同士、あるいはコンテナとホストの間で完全な分離ができているわけではありません。セキュリティ要件が厳しい環境では、この点が問題になることもあります。

    対処法

    マルチOSでのテストが必要な場合は、DockerではなくVMを併用する必要があります。

    セキュリティ面では、信頼できるベースイメージを使う、不要なパッケージを入れない、rootユーザーで実行しないといった基本的な対策を徹底することが重要です。より高い分離が必要な場合は、gVisorやKata Containersといったサンドボックス技術の導入も検討に値します。

    辛いところ7:「私のPCでは動きます」問題の変形版が起きる

    皮肉なことに、Dockerは「環境差異問題を解決する」ために生まれた技術なのに、Docker環境特有の「動かない」問題が新たに発生することがあります。

    Dockerならではの罠

    ローカルでは動くのにCI/CDで失敗する、開発環境では動くのに本番で動かない。原因を調べると、Dockerイメージのバージョン違い、ベースイメージの更新、ビルドキャッシュの有無、ネットワーク設定の違いなどが見つかります。

    また、Dockerを使いこなす知識がないまま複雑な構成を組むと、問題が発生したときの調査が困難になります。「どのコンテナで何が起きているのか」を追うのは、慣れていないとかなり大変です。

    対処法

    イメージのタグは「latest」を避け、明示的にバージョンを固定しましょう。CI/CDとローカルで同じDockerfileを使い、ビルド手順を統一することも重要です。

    そして何より、Dockerの仕組みをしっかり理解することです。ブラックボックスのまま使っていると、いざというときに手も足も出なくなります。

    まとめ:それでもDockerを使うべき理由

    この記事では、Dockerの「辛いところ」を7つ紹介しました。

    Mac・Windowsでの速度問題、権限周りのトラブル、ディスク容量の肥大化、ネットワークの罠、学習コスト、Linux依存の制約、そして新たな「動かない」問題。なかなか手強い課題が並んでいます。

    それでも、私は断言します。Dockerは使うべきです。

    なぜなら、これらの辛さを差し引いても、Dockerがもたらすメリットのほうが圧倒的に大きいからです。環境構築が数分で終わる、チーム全員が同じ環境で開発できる、本番環境との差異がなくなる。20年前の「手順書地獄」を知る身としては、これらの恩恵は何物にも代えがたいものです。

    そして、辛さの多くは「知っていれば対処できる」ものばかりです。この記事を読んだあなたは、すでに多くの落とし穴を知っています。それだけで、かなり有利なスタートを切れるはずです。

    まだDockerを触ったことがない方は、まずDocker Desktopをインストールして、「docker run hello-world」を実行するところから始めてみてください。すでに使っている方は、この記事で紹介した対処法をぜひ試してみてください。

    トラブルに遭遇するたびに少しずつ理解が深まり、気づけばDockerなしでは開発できない体になっているはずです。私がそうであったように。

  • Docker入門|20年現場で見てきた環境構築の変遷と始め方

    Docker入門|20年現場で見てきた環境構築の変遷と始め方

    「手順書通りにやったのに動かない」「自分のPCでは動くのに、他の人の環境だとエラーになる」

    開発の現場でこんな経験をしたことはないでしょうか。私は20年以上エンジニアとして様々な現場を見てきましたが、環境構築にまつわるトラブルは本当に多く、時には丸一日を費やすこともありました。

    Dockerは、こうした「環境の違いによる問題」を根本から解決するために生まれた技術です。この記事では、Dockerの基本概念から実際の使い方まで、初心者の方にもわかりやすく解説します。

    Dockerとは何か?一言で理解する

    Dockerとは、アプリケーションの実行環境をまるごとパッケージ化して、どこでも同じように動かせる仕組みです。

    たとえば、あなたが作ったWebアプリがあるとします。このアプリを動かすには、特定のバージョンのNode.jsが必要で、データベースも必要で、いくつかのライブラリも必要です。従来は、これらを一つひとつ手作業でインストールして設定していました。

    Dockerを使えば、これらの「アプリを動かすために必要なもの一式」をひとつの箱(コンテナ)にまとめられます。この箱さえあれば、WindowsでもMacでもLinuxでも、同じようにアプリが動きます。

    なぜDockerが必要になったのか?昔の開発現場の話

    Dockerの価値を理解するには、Dockerがなかった時代の苦労を知るのが一番です。

    手順書地獄の時代

    10〜15年ほど前、新しいプロジェクトに参加すると、まず渡されるのが「環境構築手順書」でした。ひどいときには50ページ以上あり、「このソフトをインストールして、この設定ファイルをこう書き換えて、この環境変数を設定して…」と延々と続きます。

    しかも、この手順書通りにやっても動かないことが珍しくありませんでした。なぜなら、手順書を作った人のPCと自分のPCでは、すでにインストールされているソフトのバージョンが違ったり、OSの設定が微妙に異なったりするからです。

    「私のPCでは動きます」問題

    開発中によく起きたのが、「自分の環境では正常に動くのに、他の人の環境やサーバーにデプロイすると動かない」という問題です。

    原因を調べると、Javaのバージョンが8と11で違っていたとか、ライブラリのマイナーバージョンが違っていたとか、そういった些細な差異が原因でした。本番リリース直前に発覚して、深夜まで対応に追われたことも一度や二度ではありません。

    Dockerが解決したこと

    Dockerは、この「環境の差異」という根本的な問題を解決しました。アプリケーションと、それを動かすために必要な環境をすべてひとまとめにして配布できるようになったのです。

    開発者のPCで動いたコンテナは、テスト環境でも本番環境でも、まったく同じように動きます。「環境が違うから動かない」という言い訳が通用しなくなった代わりに、環境構築で苦しむ時間が劇的に減りました。

    Dockerの基本概念を押さえる

    Dockerを使いこなすために、まず3つの重要な概念を理解しましょう。

    イメージ(Image)

    イメージは、コンテナを作るための「設計図」です。

    たとえば「Python 3.11がインストールされたLinux環境」や「nginx(Webサーバー)が設定済みの環境」といった、特定の状態を記録したものがイメージです。

    イメージ自体は読み取り専用で、変更することはできません。イメージをもとにコンテナを作成して使います。

    コンテナ(Container)

    コンテナは、イメージから作られた「実際に動く環境」です。

    イメージが設計図だとすれば、コンテナはその設計図から建てられた家のようなものです。同じ設計図(イメージ)から、何個でも家(コンテナ)を建てることができます。

    コンテナは起動したり停止したり、中でコマンドを実行したりできます。不要になったら削除して、また必要になったらイメージから新しく作れます。

    Dockerfile

    Dockerfileは、イメージを作るためのレシピです。

    「Ubuntu をベースにして、Node.js をインストールして、このアプリのコードをコピーして、このコマンドで起動する」といった手順をテキストファイルに記述します。このDockerfileがあれば、誰でも同じイメージを作成できます。

    Docker Hub

    Docker Hubは、イメージを共有するためのサービスです。GitHubのDocker版と考えるとわかりやすいでしょう。

    公式のイメージ(nginx、MySQL、Pythonなど)が多数公開されており、自分でゼロから作らなくても、必要なイメージをダウンロードしてすぐに使えます。

    Dockerを実際に動かしてみよう

    概念を理解したら、実際に手を動かしてみましょう。

    Docker Desktopのインストール

    まずはDocker Desktopをインストールします。WindowsでもMacでも、公式サイトからインストーラーをダウンロードして実行するだけです。

    Docker Desktop公式サイト

    インストールが完了したら、ターミナル(Windowsならコマンドプロンプト、Macならターミナル)を開いて、以下のコマンドを実行してください。

    docker --version

    バージョン情報が表示されれば、インストール成功です。

    最初のコンテナを起動する

    では、実際にコンテナを起動してみましょう。以下のコマンドを実行してください。

    docker run hello-world

    初回は「hello-world」というイメージをDocker Hubからダウンロードするため、少し時間がかかります。成功すると、「Hello from Docker!」から始まるメッセージが表示されます。

    これだけで、あなたは初めてのDockerコンテナを起動できました。

    Webサーバーを立ち上げてみる

    もう少し実用的な例として、Webサーバー(nginx)を起動してみましょう。

    docker run -d -p 8080:80 nginx

    このコマンドを実行したら、ブラウザで http://localhost:8080 にアクセスしてください。「Welcome to nginx!」というページが表示されるはずです。

    たった1行のコマンドで、Webサーバーが立ち上がりました。従来であれば、nginxをダウンロードして、設定ファイルを編集して、サービスを起動して…という作業が必要でしたが、Dockerならこれだけです。

    覚えておきたい基本コマンド5つ

    Dockerを使う上で、最低限覚えておきたいコマンドを紹介します。

    1. docker run
    イメージからコンテナを作成して起動します。

    docker run イメージ名

    2. docker ps
    現在動いているコンテナの一覧を表示します。

    docker ps

    停止中のコンテナも含めて表示するには -a オプションをつけます。

    docker ps -a

    3. docker stop
    コンテナを停止します。

    docker stop コンテナID

    4. docker rm
    停止したコンテナを削除します。

    docker rm コンテナID

    5. docker images
    ダウンロード済みのイメージ一覧を表示します。

    docker images

    まずはこの5つを覚えておけば、基本的な操作はできるようになります。

    実務ではDockerがどう使われているか

    Dockerは学習用のツールではなく、実際の開発現場で幅広く使われています。ここでは代表的な活用シーンを紹介します。

    開発環境の共有

    チーム開発では、全員が同じ環境で作業することが重要です。Dockerを使えば、Dockerfileとdocker-compose.yml(複数のコンテナを管理する設定ファイル)をリポジトリに含めておくだけで、新しくプロジェクトに参加したメンバーも docker compose up の一発で開発環境が整います。

    「環境構築に3日かかる」というプロジェクトが、「5分で開発開始できる」プロジェクトに変わります。

    CI/CDパイプライン

    GitHub ActionsやCircleCIなどのCI/CDツールでも、Dockerは欠かせません。テストを実行する環境をDockerで統一することで、「ローカルではテストが通るのにCIでは失敗する」という問題を防げます。

    本番環境への展開

    AWSのECS(Elastic Container Service)やEKS(Elastic Kubernetes Service)、Google CloudのCloud Runなど、主要なクラウドサービスはDockerコンテナをそのままデプロイできる仕組みを提供しています。

    開発環境で動作確認したコンテナを、そのまま本番環境にデプロイできるため、「本番だけで起きる謎のバグ」が大幅に減ります。

    まとめ:Dockerは現代の開発に欠かせないスキル

    この記事では、Dockerの基本概念から実際の使い方までを解説しました。

    Dockerを学ぶことで得られるメリットを改めて整理すると、環境構築の時間が劇的に短縮される、「自分の環境では動く」問題から解放される、チームでの開発環境を簡単に統一できる、本番環境との差異によるトラブルが減る、といった点が挙げられます。

    20年前の開発現場を知る身としては、Dockerの登場は本当に革命的でした。環境構築に費やしていた膨大な時間を、本来の開発作業に使えるようになったのですから。

    まずは今回紹介した基本コマンドを実際に試してみてください。そこから徐々にDockerfileの書き方やDocker Composeの使い方を学んでいけば、開発効率は確実に向上します。

    次のステップとしては、Docker Composeを使った複数コンテナの管理や、実際のアプリケーションをDockerで動かす方法を学ぶことをおすすめします。