見出し画像

Dockerによるコンテナ化入門ガイド

この記事は弊社のフルスタックエンジニア:Ashish Dhakalが作成した記事です。英語版はこちらをご覧ください。
Medium

ソフトウェアを開発する際、異なるマシン間で一貫した環境を維持することは難しいことです。Dockerは、アプリケーションとその依存関係を軽量でポータブルなコンテナにパッケージ化することで、この問題を解決する強力なツールです。このガイドでは、DockerとDocker Composeの初心者向けに、MySQLデータベースに接続したNode.jsアプリケーションをDocker Composeを使ってコンテナ化し、マルチコンテナオーケストレーションする方法を説明します。

ドッカーとは?

Dockerは、コンテナと呼ばれる隔離された環境内でアプリケーションをビルド、デプロイ、実行できるプラットフォームです。コンテナは、アプリケーション、その依存関係、ライブラリ、設定ファイルなど、実行環境全体をバンドルします。これにより、アプリケーションは、開発マシンであろうと本番サーバーであろうと、どこにデプロイされても同じように実行されます。

Dockerを使う主なメリット

  • 異なるステージ(開発、テスト、本番)で一貫した環境を実現。

  • サービスの分離により、デバッグが容易になります。

  • 従来の仮想マシンよりも軽量で高速。

Docker Composeとは?

Docker Composeは、複数のDockerコンテナを単一のアプリケーションの一部として定義・管理するツールです。docker-compose.ymlファイルを使用して、アプリケーションが必要とするすべてのサービス(Webサーバ、データベースなど)を指定し、docker-compose upというコマンド1つで実行できるようにします。

Docker Composeの主な利点:

  • マルチコンテナアプリケーションの管理を簡素化。

  • .envファイルによる環境設定をサポート。

  • 複雑なマイクロサービスアーキテクチャの定義に便利。

コンテナ化アプリケーションの主な利点

技術的なステップに入る前に、アプリをコンテナ化する理由を簡単に探ってみよう:

  1. 一貫性: 環境(開発、ステージング、本番)に関係なく、アプリケーションが同じように実行されることを保証します。

  2. 依存関係の管理の簡素化: パッケージと依存関係はコンテナ内にインストールされるため、ホスト環境はクリーンな状態に保たれます。

  3. スケーラビリティとデプロイメント: Kubernetesやクラウドサービスのようなツールを使って、アプリケーションのスケーリングやデプロイが容易になります。

これらの利点を念頭に置いて、NodeJsアプリケーションのコンテナ化のセットアップを始めましょう。

ステップ1:プロジェクト・ディレクトリのセットアップ

まずプロジェクトフォルダを作成し、基本的なNode.jsアプリケーションを初期化します。次に、同じプロジェクトのルート・ディレクトリにDockerfileとdocker-compose.ymlファイルを作成します。

touch Dockerfile docker-compose.yml .env

.envの中に、必要な環境変数をすべて追加する:

PORT=8090
DB_HOST=db
DB_USER=root
DB_PASSWORD=password
DB_NAME=todo_db
DB_PORT=3306
ADMINER_PORT=5001
DIALECT=mysql

次に、Dockerfile内に以下の内容を追加する。

FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm install -g nodemon
EXPOSE 8090
CMD ["npx", "nodemon", "--watch", ".", "index.js"]

.ymlファイルを分解する

  1. FROM node:16: 使用するベースイメージを指定します。

  2. WORKDIR /app: コンテナ内の作業ディレクトリを設定します。以降のCOPYコマンドやRUNコマンドは、このディレクトリを基準に実行されます。

  3. COPY package*.json ./: package.jsonとpackage-lock.json(ある場合)をコンテナにコピーします。このステップは、ビルドキャッシュを最適化するために別個に行われるため、npmの依存関係が不必要に再インストールされることはない。

  4. npm installを実行する: 1package.jsonで指定された依存関係をすべてインストールする。

  5. COPY ..: すべてのアプリケーションファイルをコンテナ内の/appディレクトリにコピーする。

  6. RUN npm install -g nodemon: 開発中のライブリロードに使用されるnodemonをグローバルにインストールします。

  7. EXPOSE 8090: ポート8090を公開し、アプリケーションへの外部アクセスを許可する。

  8. CMD [「npx」, 「nodemon」, 「 - watch」, 「.」, 「index.js」]: コンテナ起動時に実行するコマンドを設定します。ここでは、nodemonがコードの変更を監視し、サーバを自動的に再起動します。

このDockerfileをセットアップした状態で、Docker Composeを使ってこのイメージを実行してみよう。

ステップ2:docker-compose.ymlファイルのセットアップ

コンテナは1つでも便利ですが、実際のアプリケーションでは複数のサービス(データベースなど)が必要になることがほとんどです。Docker Composeを使えば、マルチコンテナ・アプリケーションを定義・管理できる。この例では、以下を含むdocker-compose.ymlファイルを設定します:

  • Node.jsアプリケーションサービス

  • MySQLデータベースサービス

  • Adminer(データベース管理ツール)

docker-comppose.ymlに以下のコードを追加する。

version: '3.8'

services:
  # Node.js Application Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: nodejs-app
    restart: always
    ports:
      - ${PORT}:${PORT} # Map host port {PORT} to container port {PORT} for the Node.js server
    environment:
      DB_HOST: db
      DB_USER: root
      DB_PASSWORD: password
      DB_NAME: todo_db
    volumes:
      - .:/app # Mount the current directory to the container for hot-reload
      - /app/node_modules
    depends_on:
      - db

  # MySQL Database Service
  db:
    image: mysql:8.0
    container_name: mysql-db
    restart: always
    environment:
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
    ports:
      - ${DB_PORT}:${DB_PORT} # Map host port {DB_PORT} to container port 3306
    volumes:
      - db_data:/var/lib/mysql

  # Adminer Service for DB Management
  adminer:
    image: adminer
    container_name: adminer
    restart: always
    ports:
      - ${ADMINER_PORT}:8080 # Map host port {ADMINER_PORT} to Adminer’s internal port 8080
    depends_on:
      - db

# Define Volumes for Persistent Data Storage
volumes:
  db_data:

.ymlファイルを分解しよう

├── Version: We specify version 3.8 to use the latest features of Docker Compose.
├── Services: We defined 3 different services, `app`, `db`, `adminer`
│   └── app:
│   │    └── Uses the Dockerfile to build the image.
│   │    └── Sets environment variables for database connection.
│   │    └── Maps the current directory (.) to the /app directory inside the container, enabling hot-reloading.
│   └── db: Configures the MySQL database:
│   │    └── Uses the mysql:8.0 image.
│   │    └── Sets up environment variables for the database credentials and name.
│   │    └── Maps port 3306 for accessing the database.
│   └── adminer: Sets up Adminer:
│   │    └── Uses the adminer image.
│   │    └── Maps port 5001 for easy access to the database management interface.
└── Volumes: Volumes
    └── db_data: Defines a db_data volume for persistent MySQL storage.

ステップ3:コンテナのビルドと実行

Dockerfileとdocker-compose.ymlの準備ができたので、コンテナをビルドして実行してみよう。

Dockerイメージをビルドする

Dockerfileとdocker-compose.ymlがあるディレクトリに移動し、実行する:

docker-compose build

このコマンドは、docker-compose.ymlで定義されたイメージをビルドします。

Dockerコンテナの実行

docker-composeファイルで定義されたすべてのサービスを起動するには、次のコマンドを使用します:

docker-compose up

このコマンドは、Node.jsアプリ、MySQLデータベース、Adminerをスピンアップします。アクセスできます:

コンテナの停止

サービスを停止したい場合は、次のコマンドを使用する:

docker-compose down

これで、すべてのコンテナが潔く停止する。

結論

Dockerを使用してNode.jsアプリケーションをコンテナ化し、Docker Composeで管理することで、一貫した環境を維持し、複数のサービスを扱い、デプロイを効率化する簡単な方法を提供します。
Happy coding! 🎉