Dockerとは?

新入社員のOZくんは、開発環境の構築で悩んでいました。そんな時、いつも優しく指導してくれるプロ太先輩が声をかけてくれました。

Docker導入のきっかけ

プロ太
プロ太

OZくん、環境構築でつまずいてる?

OZ
OZ

はい…。新しいプロジェクトに参加するたびに、色々なバージョンのNode.jsやPythonをインストールしないといけなくて…

あー、それDockerを使えば解決できるよ。うちのチームでも去年からDockerを本格導入して、みんな助かってるんだ。

Docker…ですか?コンテナ技術ってことは知ってるんですが、具体的にどう便利なんでしょうか?

開発現場でのBefore/After

じゃあ、具体的な例で説明するね。まずは環境構築の違いを見てみよう

Dockerを使わない場合

今はこんな感じで環境構築してます…

1.Node.jsのバージョン14が必要なプロジェクトA

> nvm install 14
> nvm use 14
> npm install
> npm run start

この一連のコマンドは、Node.jsの開発環境をセットアップし、プロジェクトを起動するためのものです。

1. nvm install 14
  • nvm: Node Version Managerの略で、Node.jsのバージョンを管理するためのツールです。
  • install 14: Node.jsのバージョン14をインストールするという意味です。つまり、あなたのコンピューターにNode.jsのバージョン14をダウンロードしてインストールします。
2. nvm use 14
  • use 14: インストールしたNode.jsのバージョン14を、現在使用しているバージョンに切り替えます。これ以降、ターミナルで実行するNode.jsやnpmコマンドは、バージョン14を使って実行されるようになります。
3. npm install
  • npm: Node Package Managerの略で、Node.jsのパッケージを管理するためのツールです。
  • install: プロジェクトのルートディレクトリにpackage.jsonファイルが存在する場合、そのファイルに記述されているパッケージをインストールします。つまり、プロジェクトに必要なライブラリやモジュールをダウンロードしてインストールします。
4. npm run start
  • npm run: package.jsonファイルのscriptsセクションに定義されたスクリプトを実行します。
  • start: scriptsセクションにstartという名前のスクリプトが定義されている場合、そのスクリプトを実行します。通常、startスクリプトは、開発サーバーを起動したり、アプリケーションを実行したりするためのコマンドが記述されています。
全体的な流れ
  1. Node.jsのインストール: まず、Node.jsのバージョン14をインストールします。
  2. バージョン切り替え: インストールしたバージョン14を、現在使用するバージョンに設定します。
  3. パッケージのインストール: プロジェクトに必要なパッケージをインストールします。
  4. アプリケーションの起動: package.jsonに定義されたstartスクリプトを実行し、アプリケーションを起動します。
注意点
  • ディレクトリ: このコマンドを実行する前に、プロジェクトのルートディレクトリに移動しておく必要があります。
  • グローバルインストール: npm installコマンドには、グローバルインストールとローカルインストールという2つの方法があります。この例では、ローカルインストールを行っています。

2.Python3.8が必要なプロジェクトB

> pyenv install 3.8.0
> pyenv local 3.8.0
> pip install -r requirements.txt
> python app.py
pyenv install 3.8.0
  • pyenv install: pyenvを使ってPythonのバージョンをインストールするコマンドです。
  • 3.8.0: インストールしたいPythonのバージョンを指定します。この場合、Python 3.8.0をインストールします。
pyenv local 3.8.0
  • pyenv local: 現在いるディレクトリで使用するPythonのバージョンを指定します。
  • 3.8.0: 使用するPythonのバージョンを3.8.0に設定します。つまり、このディレクトリ内でPythonコマンドを実行すると、自動的に3.8.0が使用されます。
pip install -r requirements.txt
  • pip: Pythonのパッケージ管理ツールです。
  • install: パッケージをインストールするコマンドです。
  • -r requirements.txt: requirements.txtというファイルに記載されているパッケージを全てインストールします。requirements.txtファイルには、プロジェクトで必要なパッケージとそのバージョンがリストアップされています。
python app.py
  • python: Pythonインタプリタを起動します。
  • app.py: 指定されたPythonスクリプト(この場合はapp.py)を実行します。
全体的な流れ
  1. Pythonのインストール: pyenvを使ってPython 3.8.0をインストールします。
  2. ローカル環境の設定: 現在いるディレクトリでPython 3.8.0を使うように設定します。
  3. 依存パッケージのインストール: requirements.txtに記載されたパッケージをインストールします。
  4. アプリケーションの実行: app.pyというPythonスクリプトを実行します。
このコマンド群が意味すること

この一連のコマンドは、Pythonプロジェクトの開発環境をセットアップし、アプリケーションを実行するためのものです。

  • pyenv: Pythonのバージョンを柔軟に管理することができます。
  • requirements.txt: プロジェクトに必要なパッケージを明確に管理できます。
  • app.py: 実際のPythonプログラムが入っているファイルです。

うんうん。大変だよね。で、別のプロジェクトで違うバージョンが必要になると…

そうなんです。バージョン切り替えが面倒で、たまに依存関係でエラーになったり…

Dockerを使う場合

じゃあ、Dockerを使った場合を見てみよう!

# どちらのプロジェクトも共通で
> docker-compose up

えっ、それだけですか!?

そう、これだけ!しかも、チーム全員が全く同じ環境で開発できるんだ

具体的なメリット解説

1.環境の統一が簡単

他のメンバーと環境の違いで困ることってありますか?

Dockerを使う前はよくあったよ。『私の環境では動くんですけど…』って会話

# docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app

この、docker-compose.ymlファイルさえあれば、誰の環境でも同じように動くんだ!

2.バージョン管理が楽

Node.jsとPythonのバージョンって、プロジェクトごとに違うんですよね?

Docker使えば、それも問題なし!

# プロジェクトA用のDockerfile
FROM node:14

# プロジェクトB用のDockerfile
FROM python:3.8

各プロジェクトのバージョンは、こうやってDockerfile内で完結する

開発効率アップ

開発効率は具体的にどれくらい変わるんですか?

数字で言うと…

  • 環境構築時間:1時間 → 10分
  • バグの再現性:環境依存で30%再現 → 100%再現
  • 新メンバーの参加:1日かかる → 30分で開発開始

実際の開発フロー

実際の開発ではどんな感じで使うんでしょうか?

こんな感じだよ

1.開発開始時

> git clone プロジェクト
> docker-compose up

このコマンドは、2つのステップに分かれており、それぞれ以下のことを行っています。

1. git clone プロジェクト

  • git clone: Gitというバージョン管理システムを使って、リモートリポジトリからプロジェクトをローカルにコピーするコマンドです。
  • プロジェクト: コピーしたいプロジェクトのURLやパスを指定します。

このコマンドを実行すると、指定されたプロジェクトのコードが、実行しているディレクトリ内にコピーされます。

2. docker-compose up

  • docker-compose: Docker Composeというツールで、複数のDockerコンテナをまとめて管理するためのものです。
  • up: Docker Composeで定義されたサービスを起動するコマンドです。

このコマンドを実行すると、docker-compose.ymlというファイルに記述された設定に基づいて、複数のDockerコンテナが作成され、起動します。

このコマンドの全体的な流れ

  1. プロジェクトの取得: Gitを使って、リモートのプロジェクトをローカルにコピーします。
  2. コンテナの起動: コピーしたプロジェクト内に存在するdocker-compose.ymlファイルを読み込み、その設定に基づいてDockerコンテナを起動します。

このコマンドの目的

一般的に、このコマンドは、Dockerを用いた開発環境を迅速に立ち上げるために使用されます。

  • プロジェクトのコード: Gitで管理されているプロジェクトのコードをローカルに取得します。
  • Dockerコンテナ: プロジェクトの実行に必要な環境(データベース、ウェブサーバーなど)をDockerコンテナとして用意し、一括で起動します。

例: あるWebアプリケーションの開発環境を立ち上げたい場合、以下のような手順になります。

  1. git clone https://github.com/example/my-web-app.git で、Webアプリケーションのコードをローカルにコピーします。
  2. cd my-web-app で、コピーしたディレクトリに移動します。
  3. docker-compose up で、Docker Composeの設定ファイルに基づいて、Webサーバー、データベースなどのコンテナを起動します。

2.依存関係の追加時

> docker-compose exec web npm install 新しいパッケージ

このコマンドは、Docker Composeで管理されている複数のコンテナの中から、webという名前のコンテナに接続し、その中でnpm installコマンドを実行して、新しいパッケージをインストールする、という一連の操作を行います。

各要素の解説

  • docker-compose exec: Docker Composeを使って、実行中のコンテナにコマンドを実行するサブコマンドです。
  • web: コマンドを実行したいコンテナの名前です。この場合、”web”という名前のコンテナが対象となります。
  • npm install: Node.jsのパッケージ管理ツールであるnpmを使って、新しいパッケージをインストールするコマンドです。
  • 新しいパッケージ: インストールしたいパッケージ名を指定します。例えば、「react」のようにパッケージ名を指定します。

3.データベースの追加時

# docker-compose.ymlに追記
services:
  db:
    image: postgres:13

このYAML形式で記述された部分は、Docker Composeの構成ファイルである docker-compose.yml に追加された、一つのサービスを定義しています。

  • services:
    • Docker Composeで定義するサービスの一覧を示すセクションです。
  • db:
    • サービスの名前です。この名前を使って、他のサービスから参照したり、docker-compose exec コマンドで指定したりします。
  • image:
    • このサービスで使用するDockerイメージを指定します。ここでは、PostgreSQLのバージョン13のイメージを使用することを意味します。
このコマンドによって何が起こるか

この追記により、docker-compose up コマンドを実行した際に、db という名前のPostgreSQLのデータベースコンテナが作成され、起動されます。

全体的なイメージ
  • docker-compose.yml は、複数のコンテナをまとめて管理するためのレシピのようなものです。
  • services セクションには、それぞれのコンテナの設定を記述します。
  • image は、コンテナのベースとなるイメージを指定します。
具体的な例

例えば、この docker-compose.yml ファイルに加えて、Webアプリケーションのサービスを定義すると、以下のようになります。

# docker-compose.ymlに追記

version: '3.7'
services:
  db:
    image: postgres:13
  web:
    build: .
    ports:
      - "5000:5000"
    depends_on:
      - db

この例では、PostgreSQLのデータベースとWebアプリケーションの2つのサービスが定義されています。depends_on を使うことで、Webアプリケーションのコンテナが起動する前に、必ずデータベースのコンテナが起動するように設定されています。

パフォーマンスの違い

でも、Dockerを使うと遅くなったりしないんですか?

そうだね。Dockerには便利なところがたくさんあるけれど、いくつかデメリットもあるんだ。

1. パフォーマンスの制約

まず、Dockerコンテナは、アプリを実行するのに必要な‘リソース’をホスト(元になるパソコン)と共有してるんだ。リソースっていうのは、コンピュータのCPU(処理する力)とか、メモリ(情報を一時的に保存する場所)のことだよ。

じゃあ、たくさんのコンテナを同時に動かすと、ホストのリソースを使いすぎて、パソコンが重くなっちゃうってことですか?

その通り!特に、たくさんの処理をするようなアプリをコンテナで動かすと、ホストのリソースを使い切って、コンテナの動作が遅くなったり、不安定になることがあるんだ。

2. データの保存が難しい

次に、Dockerコンテナは、一時的なデータを使うには便利だけど、長く保存しておきたいデータには少し不便なんだ。

一時的なデータってどういう意味ですか?

例えば、ゲームで言うと、途中で出てくる情報(スコアや画面の情報)は一時的なデータだよね。でもセーブデータはずっと保存しておきたいだろう?Dockerコンテナは一時的なデータ処理は得意だけど、保存しておくデータはホストの外部ストレージと接続する仕組みが必要なんだ。これが少し手間なんだよ。

3. セキュリティのリスク

セキュリティ面では、何かリスクはあるんですか?

Dockerコンテナは、ホストシステムと一部を共有しているから、コンテナ内に何か悪いものが入り込むと、ホストにも影響が出ることがあるんだ。

それはちょっと怖いですね…。便利だからといって、使い方には気をつけないといけないんですね。

そうだね!特にセキュリティ設定をしっかりすることが大事なんだ。Dockerの利便性を活かしながら、リスクも理解して、安全に使うことが大切だよ。

まとめ

Dockerを使うことで、プロジェクトごとに異なる環境設定や依存関係の問題を解決し、開発環境の構築が簡単かつ迅速になります。また、docker-compose.ymlDockerfile を用いることで、チームメンバー全員が同じ環境で開発できるため、「動作環境の違いによるエラー」を防止できます。これにより、プロジェクトの開発効率が向上し、新メンバーもスムーズに参加できるメリットが得られます。