はじめに
Docker の面白さ・便利さに気づき始めたので、他の人にも伝えるべく記事を書きます。
(2025/03/30 追記)
↓ 超勉強になった本。Docker のホストマシン上での動きが基礎から解説されています。まずこれを読みましょう。
実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本
docker 単体系コマンド(compose じゃないやつ)
# イメージ一覧
docker images
# コンテナ一覧
docker ps
docker ps -a
# 内部一覧
docker image inspect <イメージ名>
docker container inspect <コンテナ名>
docker volume inspect <ボリューム名>
# コンテナ全停止
docker stop $(docker ps -aq)
# イメージ・コンテナ・ボリューム一括全削除(ただし使用中のものは消せない)
docker system prune -a
# イメージ・コンテナ・ボリュームそれぞれ全削除
docker image rm $(docker image ls -aq)
docker container rm $(docker container ls -aq)
docker volume rm $(docker volume ls -q)
# 状態確認
docker system df
# Docker Hub からイメージを持ってくる
docker pull <イメージ名>
docker pull ubuntu:20.04
# 自分でイメージを作成する(Dockerfile と同階層でコマンドを実行)
docker build -t <任意のイメージ名> .
docker build -t my_image .
# イメージのレイヤー(構成要素)を確認
docker history <イメージID>
# イメージからコンテナを起動する(create + start)
docker run <イメージ名>
# ↓ これはすぐ停止状態になる(下のメモ参照)
docker run ubuntu:20.04
# ↓ これは起動状態を維持する
docker run -it ubuntu:20.04 bash
# ↓ これも維持
docker run --name <任意のコンテナ名> -p <任意のホスト側ポート番号>:<任意のコンテナ側ポート番号> <イメージ名>
docker run --name docker-getting-started -p 80:80 docker/getting-started
# コンテナを作るだけ(start待ち)
docker create <イメージ名>
docker create --name my_ubuntu_container ubuntu:20.04
# コンテナを一時停止・再開する
docker stop/start <コンテナ名>
docker start my_ubuntu_container
# 起動状態のコンテナの中に入る
# bash がダメなら sh など試す
docker exec -it <コンテナ名> bash
コンテナが run した瞬間停止状態になる理由
大事なコンテナ原則
・コンテナはメインプロセスを実行するために起動する
・メインプロセスが終了したコンテナは自動で停止する
(実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本より)
具体例として、「docker run ubuntu:20.04」でコンテナ作成&起動はされるが、メインプロセスを指定していないので終了扱いですぐ停止される。
一方「docker run -it ubuntu:20.04 bash」はメインプロセスとして「bash」を指定しているので、私たちがコンテナ内で bash 操作している間は停止しない。bash から exit したらメインプロセス終了で停止される。
nginx イメージとか、ものによってはデフォルトでメインプロセスが指定されているものもあり、そういうのは起動した瞬間停止されることがない。
オプション | 説明 |
---|---|
-d | --detach。デタッチモード。コンテナがバックグラウンド実行され、ターミナルはブロックされない |
-p | --publish。-p 5000:5001なら、ホストの5000番はコンテナ内の5001につながっている |
-f | --force。起動中のコンテナを、停止を経由せずいきなり消すときに使う |
--rm | コンテナが停止されたとき自動的にコンテナを削除する |
-e | 環境変数(例:-e PASSWORD=password) |
-v | ボリュームの設定(例:-v my-volume:/my-data) |
-it | --interactive と --tty。コンテナに入るときによく使う |
--network | 使用ネットワーク指定(例:--network networkname) |
Dockerfile と compose.yaml を動かしてみる
全体像はこちらのリポジトリを git clone して、docker compose build と docker compose up をしてご確認ください。
Dockerfile の内容
# FROM <イメージ名>
FROM node:17-alpine
RUN npm install -g nodemon
# これ以降コンテナ内では /app で作業する
WORKDIR /app
# ローカルの package.json を /app にコピー
COPY package*.json .
# /app で package*.json を参考にパッケージをインストール
RUN npm install
# ローカルのファイルを /app にコピー
COPY . .
# 使うポートを指定(任意)
EXPOSE 4000
# CMD で指定したコマンドは、上記のインストールなどが終わってから実行される
# RUN で指定するとインストール完了を待たずに実行されてしまう
CMD ["npm", "run", "dev"]
compose.yaml の内容
services:
backend:
# .yml ファイルから見て ./api にある Dockerfile をイメージとしてビルド
build: ./backend
# コンテナ名
container_name: backend_c
# ローカルポート:コンテナポート
# localhost:4000でコンテナの4000が見られる
ports:
- 4000:4000
volumes:
# ローカルファイル:コンテナファイル
# バインドマウントなのでこの2つは連動する
- ./backend/src:/app/src
environment:
# 環境変数は ./backend/src/db.js 内で使っている
ENV: env_value
POSTGRES_USER: p_username
POSTGRES_PASSWORD: p_password
POSTGRES_DB: p_database
depends_on:
# db のコンテナが起動してから backend が起動する
- db
links:
# depends_on とセット?(なくても動くような…)
- db
frontend:
build: ./frontend
container_name: frontend_c
ports:
- 3000:3000
volumes:
- ./frontend/src:/app/src
# --interactive
stdin_open: true
# --tty
tty: true
db:
# Dockerfile からビルドせずイメージ名を直接指定
image: postgres:latest
container_name: db_c
environment:
POSTGRES_USER: p_username
POSTGRES_PASSWORD: p_password
POSTGRES_DB: p_database
ports:
- 5432:5432
volumes:
# バインドマウント
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
# ボリュームマウント
- db_data:/var/lib/postgresql/data
# コンテナが常に再起動する(なくても動くような…)unless-stopped もある
restart: always
volumes:
db_data:
compose.yaml 起動系コマンド
# compose.yaml 起動系コマンド
# 起動準備をする
docker compose build
# 起動する
docker compose up
# 止める
docker compose stop
# 再開する
docker compose start
# 消す
docker compose down
# ファイル名指定(stop/start/down 時もファイル名を指定する)
docker compose -f docker-compose-one.yaml up
Dockerfile その他にできること紹介
RUN apt-get update && \
apt-get install -y curl && \
curl -sL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get upgrade -y && \
apt-get install -y nodejs && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# ↓ と同じ意味だが、横長で見づらいので「\」で改行する
RUN apt-get update && apt-get install -y curl && curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get upgrade -y && apt-get install -y nodejs && apt-get clean && rm -rf /var/lib/apt/lists/*
# RUN RUN RUN とするとレイヤー数が増えてイメージが大きくなるので && でつないでまとめる
# まとめておくと、2回目以降キャッシュで一部 RUN されない由来のエラーも回避できる
# インストールも「\」で改行できる
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
nodejs \
postgresql-client \
yarn
# app ユーザに /app の権限を付与し、root ユーザではなく app ユーザで作業する
RUN addgroup app && adduser -S -G app app
RUN chown -R app:app .
USER app
# root ユーザにも戻せる
USER root
# どちらの書き方でもいい
CMD ["npm", "run", "dev"]
CMD npm run dev
# CMD とどう違うのかわからない…
ENTRYPOINT [ "node", "main.js" ]
# ディレクトリ作成
RUN mkdir -p /home/app
# 環境変数設定
ENV FLASK_APP=app.py \
FLASK_RUN_HOST=0.0.0.0 \
FLASK_RUN_PORT=8000
compose.yaml その他にできること紹介
services:
service-1:
# Dockerfile の場所と名前を指定する
build:
context: service-1
dockerfile: Dockerfile.env
# コンテナ内で実行されているサービスが正常に動作しているか定期的に確認
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
interval: 5s
retries: 5
start_period: 15s
timeout: 5s
# docker compose watch すると指定のファイルに変更があった時 rebuild する
# 単純に down と up すればいいのでは感も
develop:
watch:
- path: ./service-1/package.json
action: rebuild
# Dockerfile の CMD や ENTRYPOINT の上書き
command: bundle exec rails s -p 3000 -b '0.0.0.0'
entrypoint: "/bin/sh -c 'npm install && npm run start'"
# 使用する .env を指定
env_file:
- ./service-1/dev.env
# 使うネットワークを指定
networks:
- coffee
# 使うネットワークを指定
# 普通に build と up すれば自動でネットワーク作成されるので、あえて指定するケースは少ないかも
networks:
coffee:
ipam:
driver: default
config:
- subnet: "192.168.92.0/24"
関連:その他の compose.yaml オプション
オプション名 | 内容 |
---|---|
configs:、secrets:、extends: | ファイルを指定し、ファイル内の環境変数?を使えるようにする |
sync、rebuild、sync+restartなど | 調べきれていない |
profiles: | 調べきれていない |
関連:compose.yaml
- composerizeで docker run コマンドから compose.yaml を作成できる
- ボリュームマウントのファイルの保存場所は \wsl.localhost のdocker-desctop-data 配下にある(気になる方はこちらのYoutubeを参照)
おわりに
Docker に関する知識を整理できてよかったです。
知らないオプション設定がたくさんあるのでまた必要に応じて勉強したい。
参考にさせていただいた記事
- Docker Crash Course Tutorial
- Docker In One Shot - Part 1 & 2
- Docker Compose will BLOW your MIND!! (a tutorial) / .yamlファイル例
- Run Docker in Windows - Setup, Docker Compose, Extensions
- Docker Compose Tutorial
- Docker Tutorial for Beginners
- Learn Docker in 1 Hour | Full Docker Course for Beginners
- Ultimate Docker Compose Tutorial
- Docker-compose tutorial
- DOCKER COMPOSE | Complete Guide with Hands-On Examples
- Docker Compose Tutorial for Beginners (Networks - Volumes - Secrets - Postgres - Letsencrypt)
など