Dockerって、動かすだけなら1日で覚えられるんですよね。

でも中身の理解は別で、「軽いVM」だと思ったまま使っている人が本当に多い。その誤解が、セキュリティ事故とビルド遅延の温床になります。今回は、「消したはずの秘密鍵が、レイヤに眠っている」話から、コンテナの正体が見えるものを8つ集めました。1つでも知らなかったら儲けものです。

① コンテナは、VMではなく「ただのプロセス」です

すべての出発点です。

コンテナの中でアプリを動かすと、Linuxのホストなら、psコマンドからそのプロセスが普通に見えます。仮想マシンのような「別のコンピュータ」は、どこにも存在しません。

コンテナの正体は、名前空間(見える世界の隔離)とcgroups(使える資源の制限)を着せられた、ホスト上の普通のプロセスです。

起動が一瞬なのも、オーバーヘッドが小さいのも、「隔離された起動済みOS」ではなく「隔離されたプロセス」だから。この一枚の絵が、以降の全部を説明します。

② 削除したファイルは、レイヤに残っています

セキュリティ事故に直結する話です。

COPY secret.key /app/
RUN build-with-secret
RUN rm /app/secret.key   # 消した…つもり

イメージはレイヤ(差分)の積み重ねでできています。後のレイヤでrmしても、それは「削除した」という差分が積まれるだけで、secret.keyを含むレイヤは、イメージの中にそのまま残っています。

イメージを展開すれば取り出せる。つまり配布した瞬間、秘密は漏れています。

対策は、秘密をレイヤに入れないこと。ビルド時シークレットの仕組み(RUN --mount=type=secret)やマルチステージビルドを使うんです。

③ latestは、「最新」という機能ではありません

image:latest と書くと最新版が来る——半分誤解です。

latestは、ただのデフォルトのタグ名です。「タグを省略したときに使われる名前」というだけで、最新版を指す保証も、自動更新される魔法もありません。push側がlatestを付け忘れれば、古いままです。

さらに実務では、latest運用は「どの版が動いているか分からない」という再現性の敵になります。

本番は、バージョンやダイジェストでピン留めする。latestは名前であって、約束ではないんです。

④ コンテナの中に、カーネルはありません

「UbuntuのコンテナはUbuntuが動いている」——半分だけです。

コンテナに入っているのは、ライブラリとコマンド群だけ。カーネルはホストのものを共有しています。だからコンテナ内で uname -r を打つと、ホストのカーネルバージョンが出ます。

ちなみにMacやWindowsのDocker Desktopでは、裏で小さなLinuxの仮想マシンが動いていて、そのカーネルを共有しています。

これが、①の「別のコンピュータではない」の証拠です。そしてこれが、コンテナが軽い理由であり、「カーネルに依存する機能はホスト次第」という制約の理由でもあるんです。

⑤ PID 1問題——コンテナの中の「1番」は特別です

コンテナで最初に起動したプロセスは、PID 1になります。この番号、特別扱いなんです。

PID 1は、シグナルのデフォルト動作が無効(明示的にハンドリングしないとCtrl+CやSIGTERMで止まらない)で、さらに孤児プロセスの後始末(回収)役を背負います。

普通のアプリはこの役目を想定していないので、「docker stopが10秒待って強制killになる」「ゾンビプロセスが溜まる」という症状が出ます。

対策は、軽量なinit(tiniなど)をPID 1に立てること。docker runの--initオプション一発で解決する、知ってるだけ得な話です。

⑥ ビルドキャッシュは、「行の順番」で決まります

Dockerfileのビルドが遅い——順番を見直すだけで数分が数秒になることがあります。

ビルドは命令ごとに上からキャッシュされ、どこかの行が変わると、それ以降は全部作り直しです。だから定石はこうなります。

COPY package.json ./     # 変わりにくいものを先に
RUN npm install          # ← ソース変更ではキャッシュが効く
COPY . .                 # 変わりやすいものは最後

ソースを1文字直すたびに依存の全インストールが走っていたら、それは順番の問題。「変わりにくい順に書く」がDockerfileの文法なんです。

⑦ コンテナ内のrootは、思ったより「本物」です

「コンテナの中だから、rootでも隔離されていて安全」——過信は禁物です。

既定の構成では、コンテナ内のrootは、ホストのrootと同じユーザーIDです。隔離の壁はありますが、ホストのディレクトリをマウントしていれば、そのファイルにはホストのroot権限で触れます。

だから定石は2つ。

  • アプリは非rootユーザーで動かす(DockerfileでUSER指定)
  • マウントは必要最小限に

「中だから大丈夫」ではなく「壁を薄くする設定をしていないか」で考えるんです。

⑧ コンテナは、「消える」前提で設計します

コンテナ内でファイルに書き込んだデータは、コンテナを消した瞬間に一緒に消えます。書き込み層は使い捨てです。

これは欠点ではなく思想で、「コンテナはいつでも作り直せる、状態を持たない実行単位」として扱うのが前提なんです。

残したいデータ(DBの実体、アップロードファイル、ログ)は、ボリュームとして外に出す。

「このコンテナ、今すぐ消して作り直しても大丈夫か?」——この問いにYESと言える設計が、コンテナらしい設計なんです。

番外編:手元で確かめられる小ネタ

レイヤの歴史を見る

docker history <image>

各レイヤが「どの命令で、何MB増えたか」の一覧が出ます。②の話も、肥大化の犯人も、ここで見つかります。

.dockerignoreを忘れずに
COPY . . の前に、.gitやnode_modulesを除外しておく。ビルドが速くなり、⑥のキャッシュも無駄に壊れなくなります。

「軽いイメージ」には流儀の違いがあります
超軽量イメージの代表Alpineは、標準Cライブラリが一般的なglibcではなくmuslです。軽さと引き換えに互換の罠があるので、「小さいから」だけで選ばないのが安全です。

RJCでも、コンテナと向き合っています

開発環境の再現性は、チーム開発の立ち上がり速度そのものなんですよね。⑧の「いつでも作り直せる」思想は、環境構築の属人化を消してくれます。

こういう仕組みの話を、Techチームで共有しながら開発しています。

よくいただくご質問

Q. まずどれから押さえるべきですか?
A. ②のレイヤかなと思います。秘密情報の扱いは、知らなかったでは済まない事故になるんですよね。

Q. VMとコンテナ、どう使い分ければいいですか?
A. ④が判断基準になります。カーネルごと分けたい(別OS・強い隔離)ならVM、同じカーネルでプロセスを隔離すれば足りるならコンテナ、ですね。

Q. イメージが肥大化します…
A. 番外編のdocker historyで犯人を特定して、⑥の順番整理とマルチステージビルドで絞るのが王道です。大きく削れることが多いです。

Q. 未経験からでも、分かるようになりますか?
A. なります。「コンテナ=衝立で仕切られた同じ部屋のプロセス」という絵が描ければ、挙動が全部その絵で説明できるんです。

「軽いVM」を卒業した日から、強くなります

今日の8つに共通していたのは、これでした。

コンテナの事故も遅さも、「別のコンピュータだと思っていた」誤解から生まれます。正体はプロセスで、イメージは差分の積み重ねで、カーネルは共有。

この3点が腑に落ちた人は、トラブルの原因を「Dockerの謎」ではなく「Linuxの仕組み」として調べられるようになるんですよね。

みなさんがコンテナで踏んだ事故、よかったら教えてください。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?