はじめに
この記事はDockerについて何もわからないLv.1のエンジニアが時代についていくために
Dockerでフロントエンド+バックエンド+DBの開発環境を構築してみようと思い立った顛末を記した記事です。
Dockerってなんだ?
まずDockerとはそもそも何なのか、
なんとなく下記のようなイメージを抱いていました。
- いわゆるコンテナ的なもの?
- アプリケーションの実行がお手軽にできる
- 開発環境構築が楽になるらしい
- 何もわからん!!!
Dockerとは
Docker社の開発したオープンソースのコンテナ型プラットフォーム。
Dockerを使用すると一台のPCで複数のコンテナ(アプリケーションの実行環境パッケージ)を立てて実行することができるようになるらしい。
つまり、お手軽にアプリケーションの実行環境を用意できるもの?
Dockerの用語たち
Dockerエンジン
色々な処理を行うDockerの本体のようなもの。
CLIとREST API、Dockerデーモンの3つで構成されていて
CLIでコマンドを打つとREST APIが叩かれてサーバー(Dockerデーモン)に処理内容を伝えてくれるらしい。
Dockerコンテナ
Dockerが実行するコンテナのこと。
そのままの名前。
Dockerイメージ
Dockerコンテナを実行するためのテンプレートのようなもの。
Dockerイメージを実行することでDockerコンテナを生成し、アプリケーションを実行させることができる。
Dockerレジストリ(後述)に登録されているイメージをPullして用意するほか、Dockerfile(後述)からビルドすることで自身でカスタマイズしたDockerイメージを用意することも可能。
つまり、流れとしてはこんな感じ?
DockerHub → (Pull) → Dockerイメージ → (実行) → Dockerコンテナ
Dockerfile → (ビルド) → Dockerイメージ → (実行) → Dockerコンテナ
Dockerレジストリ
作成したDockerイメージを保管するサービス。
Docker Hub(GitHub的なイメージ?)やAWS Elastic Container Registry等があり、公開されているイメージをPullして利用することもできる。
Dockerfile
Dockerイメージの設計ファイル。
Dockerfileを書くことで自身でカスタマイズしたDockerイメージを作成することができる。
Docker Compose
複数のDockerコンテナを操作するためのツール。
docker-compose.ymlという設定ファイルを定義することで複数コンテナの起動や停止、ビルド等をまとめて行うことができて便利らしい。
動かしてみよう
なんとな~~~くDockerについて理解を深めた(つもりになった)ところで実際に動かしてみることにします。
まずはDockerのインストールから。
Docker DesktopなるソフトウェアはGUIで色々操作ができるほか、インストールするとDockerエンジンやCLI、Docker Compose等をまとめてインストールしてくれるそうなのでDocker Desktopをインストールします。
利用にはDocker Hubのアカウントを作る必要があるそうなのでまずはアカウントを作成。
今回は個人利用目的なのでPersonalプランでアカウントを作り、早速Docker Desktop on Windowsをインストール。
nginxをDockerで動かしてみる
インストールが完了したら早速Dockerを動かしてみようということで、
nginxのDockerイメージからDockerコンテナを動かしてみます。
↓作業するディレクトリ構造はこんな感じです。
root
┣ index.html
┣ Dockerfile
┗ docker-compose.yml
Dockerfile
今回はとりあえず動かすだけなのでDockerfileをわざわざ作る必要もないですが、Dockerfileから作る流れを知るためにDockerfileから作ってみます。
# ベースとなるイメージを指定
# nginxが提供している最新バージョンのイメージを指定している
FROM nginx:latest
# 作業を行うディレクトリを指定
# nginxのイメージはこのディレクトリで色々作業するらしい
WORKDIR /usr/share/nginx
# ローカルのindex.htmlを/usr/share/nginx/html配下にコピーする
COPY ./index.html ./html
index.htmlの中身はどうでもいいので折りたたみます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>nginx × Dockerサンプル</title>
</head>
<body>
<h1>nginxをDockerで動かしてみるよ!!</h1>
</body>
</html>
Dockerfile(とindex.html)が書けたらDockerfileからイメージをビルドしてコンテナを実行します。
# Dockerfileから`nginx-sample-image`という名前でイメージをビルド
docker image build ./ -t nginx-sample-image
# nginx-sample-imageから`nginx-sample`という名前でコンテナを実行する
# -p 8080:80でホストPCの8080ポートとコンテナ上の80ポートを紐づけ(ポートフォワード)
docker run --name nginx-sample -p 8080:80 nginx-sample-image
http://localhost:8080 へアクセスしてみると・・・
無事コンテナを動かすことができました。
Docker Compose
Docker Composeでも動かしてみようということで、
docker-compose.ymlを作成します。
# docker-composeファイルのバージョン
version: '3'
# アプリケーションを構成するサービスの設定
services:
web:
# Dockerビルドの設定
build:
context: .
dockerfile: ./Dockerfile
# サービスで使用するポートを指定する
ports:
- 8080:80
docker-compose.ymlを作成したらイメージをビルドして実行します。
# docker-composeでDockerイメージをビルドする
docker-compose build
# Dockerコンテナを実行する
docker-compose up
Docker Composeでもコンテナを動かすことができました。
開発環境を作る
さて、Docker初心者がとりあえず触ってみた編を終えたところで
いよいよDockerを用いた開発環境を作っていきます。
DevContainer
VSCodeの拡張機能「Remote Development」を利用すると開発用DockerコンテナにVSCodeからアクセスし、コンテナ内のファイルを直接編集することができるようになります。
DevContainerを使うことでローカルPC上にライブラリや各種拡張機能等々が入り混じってごちゃついてしまう現象を解消することが可能となるらしく、便利そうなので利用してみます。
root
┣ frontend
┗ backend
フロントエンド
frontendディレクトリにひな型を作成します。
本当はDevContainerの中で作業を行うようにしたかったのですが、
DevContainerの中でうまいことcreate-react-appができなかったのであきらめてローカルで作りました。。。
# frontendのひな型を作成
cd frontend
npx create-react-app . --template typescript
# ローカルに不要なnode_modulesを消す
rm -r node_modules
バックエンド
backendディレクトリにひな型を作成します。
# backendのひな型を作成
cd backend
npm init -y
# 必要なパッケージをインストール
npm i -D typescript nodemon ts-node
npx tsc --init
mkdir src
touch src/index.ts
touch nodemon.json
# ローカルに不要なnode_modulesを消す
rm -r node_modules
tsconfing.jsonを適当に弄り、
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"skipLibCheck": true
}
}
ホットリロードの設定を行います。
{
"name": "backend",
"version": "1.0.0",
"description": "",
"devDependencies": {
"nodemon": "^3.0.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"scripts": {
"dev": "npx nodemon"
},
"keywords": [],
"author": "",
"license": "ISC"
}
{
"watch": ["src"],
"ext": "ts",
"exec": "npx ts-node ./src/index.ts"
}
DevContainer
各Dockerコンテナ用のDevContainer設定ファイルを追加します。
{
"name": "Frontend",
"dockerComposeFile": ["../docker-compose.yml"],
"service": "frontend",
"shutdownAction": "none",
"workspaceFolder": "/workspace/frontend"
}
{
"name": "Backend",
"dockerComposeFile": ["../docker-compose.yml"],
"service": "backend",
"shutdownAction": "none",
"workspaceFolder": "/workspace/backend"
}
DockerFile
各Dockerfileの設定を行います。
root
┣ frontend
┃ ┣ src
┃ ┣ public
┃ ┣ package.json
┃ ┣ tsconfig.json
┃ ┗ .devcontainer.json
┣ backend
┃ ┣ src
┃ ┣ nodemon.json
┃ ┣ package.json
┃ ┣ tsconfig.json
┃ ┗ .devcontainer.json
┗ docker
┣ frontend.Dockerfile
┣ backend.Dockerfile
┗ db.Dockerfile
FROM node:20
WORKDIR /workspace/frontend
COPY ../frontend/ ./
RUN npm install
# コンテナ起動時に実行するコマンド
CMD [ "npm", "start" ]
FROM node:20
WORKDIR /workspace/backend
COPY ../backend/ ./
RUN npm install
# コンテナ起動時に実行するコマンド
CMD ["npm", "run", "dev"]
dbはとりあえずMySQLの実行環境のみ用意(正直Dockerfileは要らない)。
FROM mysql:latest
docker-compose.yml
version: '3'
services:
# frontendの設定
frontend:
container_name: docker-sample-frontend
build:
context: .
dockerfile: ./docker/frontend.Dockerfile
environment:
# Reactのホットリロードを有効化するための設定
- WATCHPACK_POLLING=true
volumes:
# ルートディレクトリ配下をworkspace配下にマウントする
- .:/workspace:cached
# node_modulesは別ボリュームでマウントする
- frontend_node_modules:/workspace/frontend/node_modules
ports:
- '8080:3000'
# backendの設定
backend:
container_name: docker-sample-backend
build:
context: .
dockerfile: ./docker/backend.Dockerfile
environment:
# nodemonでホットリロードを有効化するための設定
- CHOKIDAR_USEPOLLING=true
volumes:
# ルートディレクトリ配下をworkspace配下にマウントする
- .:/workspace:cached
# node_modulesは別ボリュームでマウントする
- backend_node_modules:/workspace/backend/node_modules
ports:
- '3000:3000'
# dbの設定
db:
container_name: docker-sample-mysql
build:
context: .
dockerfile: ./docker/db.Dockerfile
ports:
- '3306:3306'
environment:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_USER: user
MYSQL_PASSWORD: password
TZ: Asia/Tokyo
volumes:
# MySQLのデータをボリュームにマウントする
- db-store:/var/lib/mysql
# ボリュームの設定、実行時に作ってくれる
volumes:
frontend_node_modules:
backend_node_modules:
db-store:
最終的に以下のようなディレクトリ構造になりました。
root
┣ frontend
┃ ┣ src
┃ ┣ public
┃ ┣ package.json
┃ ┣ tsconfig.json
┃ ┗ .devcontainer.json
┣ backend
┃ ┣ src
┃ ┣ nodemon.json
┃ ┣ package.json
┃ ┣ tsconfig.json
┃ ┗ .devcontainer.json
┣ docker
┃ ┣ frontend.Dockerfile
┃ ┣ backend.Dockerfile
┃ ┗ db.Dockerfile
┗ docker-compose.yml
開発用Dockerコンテナにアクセスする
さて、ここまで出来たら開発用コンテナにアクセスして開発してみましょう。
VSCodeからfrontendプロジェクトを開き、F1 >「Dev Containers: Reopen in Container」を選択するとfrontendコンテナにVSCodeからアクセスすることができます。
開発コンテナ frontendにアクセスできました。
これでコンテナ内のファイルを直接編集することができるようになります。
また、ソースコードはホストPCのディレクトリとマウントされているため、DevContainer内での変更内容はホストPCにもしっかり反映されます。
更に、DevContainerを起動すると、.devcontainer.jsonで指定したdocker-compose.ymlに基づいて(?)、関連するコンテナをまとめて起動してくれます。
今回であればfrontendのDevContainerの起動に合わせてbackend、dbのDockerコンテナも起動してくれます。
おわりに
さて、何とかDockerとDevContainerを用いてReact×TypeScript×MySQLの開発環境構築ができました。
・・・が、結局Dockerについて詳しくなれた気がしませんね。
調べれば調べるほどわからないことが増えていく不思議。
なんとかLv.1.1くらいにはなれたと信じて今後も勉強していきたいです。
参考