「イメージとコンテナって何が違うの?」で止まっている方へ。Dockerを"最低限動かす"ところまでを実務目線で整理しました。用語の地図から、既存イメージの起動、自作アプリのイメージ化、docker compose、AWS ECRへのpushまで、コピペで試せる断片と早見表を用意しています。
01なぜコンテナ? — 「どこでも同じに動く」を軽量に
「自分の PC では動くのに、サーバに載せたら動かない」。原因の多くは、OS・ライブラリ・言語のバージョンといった環境の差です。コンテナは、アプリと「それが動くのに必要なもの一式(依存関係)」をまとめて箱に詰め、どの環境でも同じ状態で動かす仕組みです。
よく比較されるのが仮想マシン(VM)です。VM は App ごとに OS(Guest OS)を丸ごと積むため重く、起動も分単位。コンテナはホスト OS のカーネルを共有し、その上でプロセスを隔離して動かすため軽く、起動は秒単位です。
- 可搬性:開発・検証・本番で同じイメージを使い回せる(環境差を潰せる)
- 軽量:OS を共有するぶん VM より小さく・速い。1台で多数動かせる
- 隔離:プロセス・ファイル・ネットワークが分離され、互いに干渉しにくい
- 使い捨て:壊れたら捨てて作り直す。「直す」より「入れ替える」文化に合う
02用語の地図 — まずこの7語だけ
最初のつまずきは、だいたい用語です。細かい定義は後回しで、次の対応関係だけ押さえれば読み書きできます。
| 用語 | これは何か | ひとことで |
|---|---|---|
| イメージ (image) | アプリ+依存関係を固めた「設計図・ひな形」。読み取り専用 | 料理のレシピ |
| コンテナ (container) | イメージから起動した「実行中の実体」。何個でも作れる | レシピで作った料理 |
| レジストリ (registry) | イメージを保管・共有する場所。Docker Hub や Amazon ECR | レシピの本棚 |
| Dockerfile | イメージの作り方を書いたテキストの手順書 | レシピの書き方 |
| レイヤ (layer) | イメージを構成する差分の積み重ね。命令ごとにできてキャッシュされる | ミルフィーユ |
| ボリューム (volume) | コンテナを消しても残る永続データの置き場 | 外付け倉庫 |
| ネットワーク (network) | コンテナ同士を繋ぐ仮想ネットワーク。名前で解決できる | 内線電話 |
03最小操作 — 8個のコマンドで一巡する
Docker Desktop などをインストールすれば、次のコマンドだけで「起動→確認→中に入る→止める→消す」が一巡します。まずは丸ごとコピペで手を動かしてみてください。
docker run -d --name web -p 8080:80 nginx # イメージからコンテナを起動(-d=バックグラウンド)
docker ps # 起動中のコンテナ一覧(-a を付けると停止中も表示)
docker images # ローカルにあるイメージ一覧
docker logs -f web # ログを追いかける(-f=follow、Ctrl+C で抜ける)
docker exec -it web sh # 動いているコンテナの中に入る(対話シェル)
docker stop web # コンテナを止める
docker rm web # 止めたコンテナを削除する
docker pull nginx:1.27 # イメージだけ取得しておく(起動はしない) -d(detach)を付けないとターミナルが占有されます。試すときは付けておくと楽です--nameを付けると、以後 ID ではなく分かりやすい名前で操作できますexec -it ... shで入れない場合はbashを試す。軽量イメージには bash が無いことがあります
docker ps -a で「今どんなコンテナが居るか」を確認する癖を付けると、状態を見失いません。04ユースケース1:既存イメージをそのまま動かす
一番多い使い方が「公開されているイメージをそのまま動かす」です。Web サーバやデータベースは、自分で作らずに公式イメージを使うのが基本です。
# nginx を 8080 番で公開する(-p ホスト側:コンテナ側)
docker run -d -p 8080:80 --name web nginx
# → ブラウザで http://localhost:8080 が開けば成功
# 環境変数を渡し(-e)、データを永続化する(-v):PostgreSQL の例
docker run -d --name db \
-e POSTGRES_PASSWORD=YOUR_PASSWORD \
-e POSTGRES_DB=appdb \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
postgres:16 -p 8080:80:左がホスト(自分の PC)、右がコンテナ内のポート。ここを取り違えると繋がりません-e KEY=VALUE:設定を環境変数で注入する。イメージ内に設定を焼き込まないのがコツ-v pgdata:/var/lib/postgresql/data:名前付きボリューム。コンテナを消してもデータは残るので、DB は必ずボリュームに載せます
-e POSTGRES_PASSWORD=... に本物のパスワードを直書きしたコマンドは、シェル履歴やログに残ります。実運用では .env ファイルやシークレット管理(AWS なら Secrets Manager/SSM パラメータストア)を使い、リポジトリには絶対にコミットしないでください。05ユースケース2:自分のアプリをイメージ化する
自作アプリを配れる形にするには、Dockerfile に「作り方」を書いてイメージ化します。命令は上から順にレイヤとして積まれます。
# Dockerfile(Node アプリの例)
FROM node:20-slim # 1) 土台にするベースイメージ
WORKDIR /app # 2) 作業ディレクトリ(無ければ作られる)
COPY package*.json ./ # 3) 依存定義だけ先にコピー(キャッシュを効かせる)
RUN npm ci --omit=dev # 4) 依存をインストール(ビルド時に実行)
COPY . . # 5) 残りのソースをコピー
EXPOSE 3000 # 6) 使うポートの明示(ドキュメント目的)
CMD ["node", "server.js"] # 7) 起動時に実行する既定コマンド ビルドして動かします。-t は名前とタグ、末尾の . は「今のディレクトリをビルド文脈にする」意味です。
docker build -t app:1.0 . # イメージを app:1.0 として作る
docker run -d -p 3000:3000 app:1.0 イメージに入れる必要のないものは .dockerignore で除外します。これだけでビルドは速く、イメージは小さく、事故も減ります。
# .dockerignore(イメージに含めないもの)
node_modules
.git
.env
*.log COPY package*.json → RUN npm ci → COPY . . の順番がポイントです。依存が変わらなければ 3〜4行目のレイヤはキャッシュが再利用され、ソースを直すたびに毎回インストールが走るのを防げます。06ユースケース3:複数コンテナを compose でまとめる
「web と db を毎回2回 docker run する」のは面倒です。compose.yaml に構成を書けば、一発で立ち上げ・停止できます。ローカル開発環境の定番です。
# compose.yaml(web + db の最小構成)
services:
web:
build: . # 同じ場所の Dockerfile からビルド
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:YOUR_PASSWORD@db:5432/appdb
depends_on:
- db # db を先に起動
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: YOUR_PASSWORD
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata: # 名前付きボリュームの宣言 docker compose up -d # 定義したサービスをまとめて起動
docker compose logs -f # 全サービスのログをまとめて追う
docker compose down # まとめて停止・削除(-v を付けるとボリュームも消える) - サービス名(上の例では
db)がそのままホスト名になります。web からdb:5432で DB に届くのはこのため build:の代わりにimage:を書けば、ビルド済みイメージをそのまま使えますdocker compose down -vはボリュームごと削除します。開発中のデータを消したくないときは-vを付けないこと
07ユースケース4:AWS へ — ECR に push して動かす
作ったイメージを AWS で動かすには、まず Amazon ECR(AWS のプライベートなイメージ置き場)に push します。手順は「ログイン → タグ付け → push」の3ステップです。
# 0) 変数(自分の値に置き換え。ACCOUNT は12桁のAWSアカウントID)
ACCOUNT=123456789012
REGION=ap-northeast-1
REPO=myapp
REGISTRY=$ACCOUNT.dkr.ecr.$REGION.amazonaws.com
# 1) ECR にログイン(発行されるトークンは12時間有効)
aws ecr get-login-password --region $REGION \
| docker login --username AWS --password-stdin $REGISTRY
# 2) リポジトリを作成(初回のみ)
aws ecr create-repository --repository-name $REPO --region $REGION
# 3) ローカルイメージに ECR 用のタグを付ける
docker tag app:1.0 $REGISTRY/$REPO:1.0
# 4) push する
docker push $REGISTRY/$REPO:1.0 レジストリの URL は必ず <aws_account_id>.dkr.ecr.<region>.amazonaws.com の形です(例:123456789012.dkr.ecr.ap-northeast-1.amazonaws.com)。ここがタグと1文字でもずれると push は通りません。
push したイメージを実際に動かす受け皿は、用途で選びます。
| サービス | 位置づけ | 向いている場面 |
|---|---|---|
| Amazon ECS | コンテナのオーケストレーション。「どこで・何個・どう配置するか」を管理する | 複数コンテナを本番で継続運用したいとき |
| AWS Fargate | サーバ(EC2)を管理せずコンテナを動かす実行基盤。ECS/EKS と組み合わせて使う | サーバの面倒を見たくない・素早く始めたいとき |
| AWS App Runner | ソースやイメージから直接 Web アプリを公開できるマネージド。2026年時点で新規顧客の受付は終了(既存顧客のみ継続利用可) | 新規は ECS + Fargate を軸に検討 |
08つまずきポイントと事故らないコツ
- イメージ肥大化:巨大イメージは pull も build も遅い。slim/alpine 系のベース+
.dockerignore+マルチステージビルドで削る - レイヤキャッシュ切れ:変わりやすいファイル(ソース)を先に
COPYすると、以降のキャッシュが毎回無効化される。依存定義を先にコピーする - root で動かす:既定は root。侵入時の被害が大きいので、専用ユーザーを作って
USERで切り替える - secrets の埋め込み:パスワードやトークンを Dockerfile や
ENV、イメージ内に焼き込まない。イメージを覗けば見えてしまう - latest タグ地雷:latest は中身が変わる。本番は固定タグ(バージョンやコミットハッシュ)で再現性を確保
- arm64/amd64 の食い違い:Apple Silicon で作ったイメージが x86 の本番で動かない、が典型。
--platformで明示する
# root を避ける:専用ユーザーを作って切り替える
RUN useradd -m appuser
USER appuser
# ビルド時にプラットフォームを固定する(Apple Silicon → x86 本番向け)
docker build --platform linux/amd64 -t app:1.0 . .env は Git にもイメージにもコミットしないこと。うっかり COPY . . で .env ごと入ってしまう事故は .dockerignore で防げます。09早見表 — コマンド逆引き+Dockerfile命令
やりたいことからコマンドを引く逆引き表です。まずはここだけブックマークすれば十分に戦えます。
| やりたいこと | コマンド |
|---|---|
| イメージから起動する | docker run -d -p 8080:80 nginx |
| 動いている一覧を見る | docker ps(-a で停止中も) |
| ログを見る | docker logs -f <名前> |
| コンテナの中に入る | docker exec -it <名前> sh |
| 止める / 消す | docker stop <名前> → docker rm <名前> |
| イメージを作る | docker build -t app:1.0 . |
| 不要物を掃除する | docker system prune(未使用を一括削除) |
| 複数まとめて起動 | docker compose up -d |
| まとめて停止・削除 | docker compose down |
| ECR にログイン | aws ecr get-login-password ... | docker login ... |
Dockerfile の主な命令もまとめておきます。この9個で大半のイメージは書けます。
| 命令 | 役割 | 例 |
|---|---|---|
| FROM | 土台にするベースイメージを指定 | FROM python:3.12-slim |
| WORKDIR | 作業ディレクトリを設定(無ければ作成) | WORKDIR /app |
| COPY | ホストからイメージへファイルをコピー | COPY . . |
| RUN | ビルド時にコマンドを実行(レイヤになる) | RUN pip install -r requirements.txt |
| CMD | 起動時に実行する既定コマンド | CMD ["python","app.py"] |
| ENTRYPOINT | 常に実行する固定コマンド | ENTRYPOINT ["/entry.sh"] |
| EXPOSE | 使うポートの明示(ドキュメント目的) | EXPOSE 8000 |
| ENV | 環境変数を設定 | ENV TZ=Asia/Tokyo |
| USER | 実行ユーザーを切り替え | USER appuser |
docker inspect の JSON 整形)/curl 実践リファレンス(コンテナの疎通確認)。基礎はクラウドエンジニアの教科書へ。10よくある質問(FAQ)
docker と docker compose の使い分けは?
単発のコンテナは docker run、web+db のように複数コンテナを毎回まとめて起動したいときは compose.yaml に書いて docker compose up が基本です。compose はローカル開発環境の再現に向いています。本番のオーケストレーションは Amazon ECS などに任せる、という住み分けが一般的です。
latest タグを使ってはいけないのですか?
とりあえず動かすだけなら便利ですが、latest は「その時点の最新」を指すため中身が知らないうちに変わり、「昨日は動いたのに」が起きやすくなります。本番や共有環境では 1.0 や Git のコミットハッシュなど固定タグを付け、再現性を確保するのがおすすめです。
イメージが大きくなりすぎます。どう小さくしますか?
定石は4つです。(1) slim/alpine 系の軽いベースイメージを使う、(2) .dockerignore で node_modules や .git を除外する、(3) RUN をまとめてレイヤ数を減らす、(4) マルチステージビルドでビルド用の道具を捨て、成果物だけ最終イメージに残す、です。
ECR に push できません(denied と出ます)。
多くは認証切れです。ログイントークンは12時間で失効するので、aws ecr get-login-password ... | docker login ... をやり直してください。加えて、リージョン・アカウントID・リポジトリ名がタグ(<acct>.dkr.ecr.<region>.amazonaws.com/<repo>)と一致しているか、対象リポジトリへの IAM 権限があるかも確認します。
Dockerからコンテナ運用、ECS/FargateでのAWS本番展開まで、EMWは札幌から伴走しています。「基礎からコンテナを学びたい」「自社の構成をどう載せ替えるか相談したい」——そんな方はお気軽にどうぞ。
相談する