🐳

Docker で React + TypeScript の開発環境

commits13 min read

サマリー

Docker Desktop (docker デーモン)を起動させておいて…

zsh
% git clone https://github.com/sprout2000/react-ts.git
% cd react-ts
% docker-compose up

localhost:3000 を開きましょう。これだけです。

ローカルに Node.js がインストールされていなかったり、インストールされていてもこのコンテナで利用されているバージョンとは異なっていたりしても同じ(仮想)環境でプロジェクトが起動します。

https://github.com/sprout2000/react-ts

このコンテナの実行を停止するには以下のようにしてください。

bash
^C  # <-- Ctrl+C を打鍵してコンテナを停止

Gracefully stopping... (press Ctrl+C again to force)
Stopping app ... done

# コンテナの削除
$ docker-compose down

Docker Desktop のインストール

公式ドキュメントに従ってインストールしましょう。

https://docs.docker.com/desktop/windows/install/

https://docs.docker.com/desktop/mac/install/

Windows 版のほうはちょっとややこしいですね。
macOS 版は Apple Silicon 向けも用意されてます。

スクリーンショット 2021-08-07 12.41.44.png

WSL2 を利用する場合

Windows Subsystem for Linux 上に Docker エンジン (docker-ce) をインストールする場合は、以下の記事を参照してください。

https://zenn.dev/sprout2000/articles/95b125e3359694

docker-compose の利用

1. React + TypeScript アプリを作成

おなじみ create-react-app を利用します。

https://ja.reactjs.org/docs/create-a-new-react-app.html
zsh
% npx create-react-app myapp --template typescript --use-npm
npx: 67個のパッケージを3.091秒でインストールしました。

Creating a new React app in /Users/zenn/Downloads/myapp.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template-typescript...

# ~ 省略 ~

We suggest that you begin by typing:

  cd myapp
  npm start

Happy hacking!

% cd myapp

2. docker-compose.yml の作成

プロジェクトフォルダ (myapp) 直下に docker-compose.yml を作成します。

https://docs.docker.jp/compose/compose-file.html
docker-compose.yml
version: '3' #1
services: #2
  app: #3
    container_name: react-app-container #4
    image: node:14-alpine #5
    volumes:
      - ./:/app #6
    working_dir: /app #7
    command: sh -c "npm install && npm start" #8
    ports:
      - '3000:3000' #9
    environment:
      - CHOKIDAR_USEPOLLING=true #10
  • #1: docker-compose.yml のシンタックスバージョンを指定します。

https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-versioning/
  • #2: このエントリ以下が 1 つのサービス (Node.js サーバ) となります。
  • #3: このエントリ以下が1つのコンテナとなります。
  • #4: コンテナの名前です。
  • #5: コンテナを作成するベースイメージ(ここでは node@14 の軽量版)を指定します。バージョンの一覧はこちら
  • #6: ホスト側のパス ./ をコンテナ側のパス /app にマウントします。
  • #7: コンテナ実行時のカレントディレクトリです。通常は #6 のコンテナ側パスと同じです。
  • #8: 上記のカレントディレクトリで実行するコマンドを指定します。
  • #9: HOST:CONTAINER - ホスト側のポート 3000 へ、コンテナ側のポート 3000 (create-react-app の出力先) を晒します。
  • #10: create-react-app のホットリロードが機能しないとき(まれによくある)のためにこの環境変数を設定しておきます。

3. docker-compose の実行

では、さっそくコンテナを作成・起動しましょう。

zsh
% docker-compose up -d

Creating network "myapp_default" with the default driver
Creating react-app-container ... done

-d オプションを使用しているため、バックグラウンドでコンテナが作成・起動されます。
この過程のログを確認するには docker-compose logs を利用します。

zsh
% docker-compose logs -f

Attaching to react-app-container
# ~ 中略 ~
react-app-container | > react-scripts start
react-app-container |
react-app-container | ℹ 「wds」: Project is running at http://172.22.0.2/
react-app-container | ℹ 「wds」: webpack output is served from
react-app-container | ℹ 「wds」: Content not from webpack is served from /app/public
react-app-container | ℹ 「wds」: 404s will fallback to /
react-app-container | Starting the development server...
react-app-container |
react-app-container | Compiled successfully!
react-app-container |
react-app-container | You can now view myapp in the browser.
react-app-container |
react-app-container |   Local:            http://localhost:3000
react-app-container |   On Your Network:  http://172.22.0.2:3000
react-app-container |
react-app-container | Note that the development build is not optimized.
react-app-container | To create a production build, use yarn build.
react-app-container |

-f オプションを使っているため、logs コマンドはログを表示し続けます。
ログ画面を終了するには Ctrl+C を打鍵してください。

Compiled successfully! と表示されたので、http://localhost:3000 をブラウザで開きましょう。

スクリーンショット 2021-08-07 12.31.43.png

ちなみにダッシュボード (GUI) から見るとこんな感じです。

4. コンテナの情報を確認する

現在のコンテナの稼働状況を確認するには、docker-compose ps コマンドを用います。

zsh
% docker-compose ps
       Name                      Command               State                   Ports
----------------------------------------------------------------------------------------------------
react-app-container   docker-entrypoint.sh sh -c ...   Up      0.0.0.0:3000->3000/tcp,:::3000->3000/tcp

react-app-container という名前のコンテナが3000番ポートUp(稼働中) であることが分かります。

また、このコンテナを作成するにあたって、Docker レポジトリからプルして来た(= docker-compose.ymlimage エントリに指定した)イメージも docker-compose images コマンドで確認できます。

zsh
% docker-compose images
     Container        Repository      Tag        Image Id       Size
----------------------------------------------------------------------
react-app-container   node         14-alpine   7a0c075c0bf6   115.9 MB

node:14-alpine というイメージをレポジトリからプルして来て、react-app-container というコンテナを作成しています。

上の2つのコマンドは docker コマンドでも代替できます。

zsh
% docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                                       NAMES
16739540c42e   node:14-alpine   "docker-entrypoint.s…"   14 minutes ago   Up 14 minutes   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   react-app-container

% docker images
REPOSITORY   TAG         IMAGE ID       CREATED      SIZE
node         14-alpine   7a0c075c0bf6   4 days ago   116MB

5. コンテナを停止・削除する

docker-compose stop コマンドでコンテナを停止させます。

zsh
% docker-compose stop
Stopping react-app-container ... done

% docker-compose ps
       Name                      Command               State    Ports
---------------------------------------------------------------------
react-app-container   docker-entrypoint.sh sh -c ...   Exit 0

コンテナも削除する場合は、docker-compose down コマンドを入力します(稼働中のコンテナにもこのコマンドを適用することができます)。

zsh
% docker-compose down
Removing react-app-container ... done
Removing network myapp_default

% docker-compose ps
Name   Command   State   Ports
------------------------------

また、--volumes オプションを追加することでコンテナが利用していたデータボリュームも削除することができます。

zsh
# コンテナを停止し、コンテナとデータボリュームも削除
% docker-compose down --volumes

Stopping react-app-container ... done
Removing react-app-container ... done
Removing network myapp_default

--volumes オプションを追加しても、コンテナを作成するためにプルして来たイメージは削除されません。
これを削除するには、別途 docker rmi コマンドを利用してください。

zsh
% docker-compose down --volumes
% docker images

REPOSITORY   TAG         IMAGE ID       CREATED      SIZE
node         14-alpine   7a0c075c0bf6   4 days ago   116MB

% docker rmi node:14-alpine

参考にさせていただきました

https://nulab.com/ja/blog/typetalk/docker-tutorial-local-environment-team/

Docker イメージの作成と Docker Hub へのプッシュ

では、この React + TypeScript 開発環境を独自イメージとしてビルドし、Docker Hub へプッシュしてみましょう。

1. Dockerfile の作成

Docker イメージを作成するための設定ファイル、Dockerfile をプロジェクトディレクトリへ作成します。なお、Dockerfile については公式チュートリアル(日本語)でとても分かりやすく解説されているので参考にしましょう。

https://docs.docker.jp/get-started/part2.html#
Dockerfile
#1
FROM node:14-alpine
#2
WORKDIR /app
#3
COPY package.json .
COPY package-lock.json .
#4
RUN npm install
#5
COPY . .
#6
EXPOSE 3000
#7
ENV CHOKIDAR_USEPOLLING=true
#8
CMD [ "npm", "start" ]
  • #1 FROM: ベースとなるイメージを指定します。
  • #2 WORKDIR: コンテナ上でのワーキングディレクトリを指定します。
  • #3 COPY: 依存パッケージをインストールするために package.json とロックファイルをイメージのファイルシステム上にコピーします。
  • #4 RUN: イメージのファイルシステム内でコマンドを実行します。
  • #5 COPY: 残りのソースコードをホスト上からイメージのファイルシステム上にコピーします。
  • #6 EXPOSE: 実行時にコンテナが特定のポートをリッスンするよう Docker に通知します。
  • #7 ENV: 実行時の環境変数を指定します。
  • #8 CMD: コンテナ内でコマンドを実行します。JSON 文字列なのでシングルクォートは使えません。

2. .dockerignore の作成

イメージに含めたくないファイルやフォルダを .dockerignore ファイルに指定します。
ここでは、とりあえず node_modules のみを指定しておきます。

.dockerignore
node_modules

3. Docker イメージのビルド

では、さっそくイメージをビルドしましょう。

zsh
# カレントディレクトリをビルド
% docker build -t your_docker_id/react-ts .

-t オプションでタグ名を指名します。Docker Hub のアカウント名と一致するスコープを与えておかないと後でプッシュできません。

zsh
% docker build -t sprout2000/react-ts .
[+] Building 40.5s (12/12) FINISHED
 => [internal] load build definition from Dockerfile                                           0.0s
 => => transferring dockerfile: 241B                                                           0.0s
 => [internal] load .dockerignore                                                              0.0s
 => => transferring context: 2B                                                                0.0s
 => [internal] load metadata for docker.io/library/node:14-alpine                              2.3s
 => [auth] library/node:pull token for registry-1.docker.io                                    0.0s
 => [1/6] FROM docker.io/library/node:14-alpine@sha256:8c94a0291133e16b92be5c667e0bc35930940d  0.0s
 => [internal] load build context                                                              6.9s
 => => transferring context: 214.49MB                                                          6.8s
 => CACHED [2/6] WORKDIR /app                                                                  0.0s
 => [3/6] COPY package.json .                                                                  0.1s
 => [4/6] COPY package-lock.json .                                                             0.0s
 => [5/6] RUN npm install                                                                     19.8s
 => [6/6] COPY . .                                                                             5.3s
 => exporting to image                                                                         6.0s
 => => exporting layers                                                                        6.0s
 => => writing image sha256:23bf6274f0c792aa0e929752f48474466690b20e220196ced7aa6d41239d1d64   0.0s
 => => naming to docker.io/sprout2000/react-ts                                                 0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

docker images コマンドで結果を確認します。

zsh
% docker images

REPOSITORY             TAG         IMAGE ID       CREATED              SIZE
sprout2000/react-ts    latest      23bf6274f0c7   About a minute ago   576MB
node                   14-alpine   7a0c075c0bf6   4 days ago           116MB

バージョン番号を指定しないでビルドしたため、latest が自動的に割り振られました。

4. コンテナの作成と実行

上で作成した Docker イメージからコンテナを作成・実行します。

zsh
% docker run --rm -d -p 3000:3000 --name myapp your_docker_id/react-ts
  • --rm: コンテナを終了させると、そのコンテナ自身も自動的に削除されます。
  • -d: バックグラウンドでコンテナを実行します。
  • -p ホストのポート:コンテナのポート: ホストのポート 3000 に入ってくるトラフィックを、コンテナのポート 3000 へ転送します。
  • --name: コンテナの名前を指定します(省略化)。

docker ps コマンドで確認しましょう。

zsh
% docker ps -a

CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                                       NAMES
afb4b7b2407f   sprout2000/react-ts   "docker-entrypoint.s…"   6 seconds ago   Up 5 seconds   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   myapp

localhost:3000 へアクセスすると、React アプリが起動していることを確認できると思います。

5. コンテナの停止

コンテナの作成・実行が確認できたので、このコンテナを停止します。
--name オプションを指定していたので、その名前でコンテナを特定できます。

zsh
% docker stop myapp
zsh
% docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

--rm オプションが与えられていたので、コンテナそのものも削除されました。

6. Docker Hub へプッシュする

事前に Docker Hub アカウントの作成を完了させてください。

まず Docker Hub へログインし...

zsh
% docker login

上で作成したイメージをプッシュします。

zsh
% docker push your_docker_id/react-ts

ダッシュボードや Web でもプッシュされたイメージを確認することができます。

リモートへの反映には少し時間がかかる場合があります。

GitHubで編集を提案

Discussion

ログインするとコメントできます