11
2

More than 1 year has passed since last update.

NestJS v9 + TypeORM v0.3 + MySQL + Docker で開発環境を構築する

Last updated at Posted at 2022-09-18

はじめに

NestJS の環境を Docker コンテナを使って作成しようとしたところ、NestJS とTypeORM の最新バージョンが上がっていました。
せっかくなので、最新のバージョンを使いましたが、断片的な情報しかなくて結構苦労しました。

これから触る方に参考となればと思い、一通り全ての作業記録を載せておきます。
指定した主なバージョンは次のとおりです。
mac を使用していますが windows でも基本的には変わらないと思います。

ライブラリ バージョン
Node.js 16.17.0
NestJS 9.1.2
TypeORM 0.3.9
MySQL 8.0

参考記事
TypeORM 0.3系のマイグレーション
NestJSをTypeORM 0.3 で使う
NestJS公式 - Database
Dockerを利用してNestJS+TypeORM+MySQLの環境構築する
NestJSとDockerコンテナで立ち上げたMySQLサーバーを接続する
NestJS + TypeORM + MySQL を使ってテーブルを作ってみる
NestJS 入門コース3 DBとCRUD

1. 準備

1-1. NestJS のインストール

Node.js がインストールされていることが前提です(Node のインストールは省略します)。
手元のバージョンは次のとおりです(現在の LTS)。

$ node -v
v16.17.0

バージョンアップなどは次の記事を参照ください。
n (Node.js管理) のインストール手順

NestJS は次のコマンドでインストール(またはアップグレード)します。バージョンは 9.1.2 を指定しています(エラーが出たら sudo を付けて実行してみてください)。

$ npm i -g @nestjs/cli@9.1.2

なお、これを書いている時点では、$ npm i -g @nestjs/cli で v9.1.2 がインストールされます。

nest -v でバージョンの確認ができます。

$ nest -v
9.1.2

1-2. NestJS プロジェクト作成

適当なフォルダを選んで NestJS のプロジェクトを1つ作ります。
プロジェクト名を nest-docker-sample として次のコマンドを実行します。

$ nest new nest-docker-sample

コマンドを実行すると、どの package manager を使用するか聞かれますので、ここでは npm を選びます。
package-manager.png
しばらくすると、プロジェクトが作成されます。

2. Dockerfile と docker-compose.yml の作成

プロジェクトが作成されたら、ルートディレクトリ直下に3つのファイル(Dockerfile, docker-compose.yml, .dockerignore)を作成します(下図)。

nest-docker-sample
├──Dockerfile  # 作成
├──docker-compose.yml  # 作成
├──.dockerignore  # 作成
├──package.json
├──package-lock.json
└──(...先に作成したその他の nest のファイル)

参考記事
いまさらだけどDockerに入門したので分かりやすくまとめてみた

2-1. Dockerfile

2-1-1. 基本的な記載事項(最小限の内容)

Dockerfile に記載する基本的な内容は次のとおりです。
なお、この内容では、コンテナ内で git を使用することはできません。

Dockerfile
FROM node:16-alpine3.16
WORKDIR /api
COPY package*.json ./
RUN npm ci
COPY . .

指定している内容は、ざっと次のとおりです。

コマンド(命令) 概要 備考
FROM ベースイメージを指定します。 ここでは、Node.js の公式 Docker イメージを使用しています(OS は alpine※)。
WORKDIR コンテナ内での「コマンドの実行場所」を指定します。 ここでは /api と指定しています。
COPY 左側にコピー元(ホスト側)
右側にコピー先(コンテナ側)
のディレクトリを指定します。
COPY package*.json ./
コピー元の package*.json は、package.json と package-lock.json の2つのファイルです。
コピー先の ./ は上記の WORKDIR の直下(つまり /api/)です。
COPY . .
ホスト側に作成したファイルをコンテナにコピーしています。
RUN 実行するコマンドを指定します。 コンテナに COPY された package.json と package-lock.json を元にライブラリをインストールします。

※ alpine は厳密には OS そのものではないですが、ここでは OS と呼んでおきます(参考: Linuxディストリビューション)。

2-1-2. git をインストールする場合

コンテナ内でも git を使用する場合は、次のように記載してください(詳細は「5. Git について」参照)。

Dockerfile
FROM node:16-alpine3.16
RUN apk update && \
    apk add bash git make && \
    apk add --upgrade grep
RUN git clone https://github.com/awslabs/git-secrets /home/alpine/git-secrets
WORKDIR /home/alpine/git-secrets
RUN make && make install
WORKDIR /api
COPY package*.json ./
RUN npm ci
COPY . .

2-1-3. Nest CLI をインストールする場合

コンテナ内で nest g module などの nest のコマンドを実行する必要がある場合は、Nest CLI もインストールしておきます。
以下のように、npm ci && npm i -g @nestjs/cli@9.1.2 とすれば、Nest CLI もインストールされます。

Dockerfile
FROM node:16-alpine3.16
RUN apk update && \
    apk add bash git make && \
    apk add --upgrade grep
RUN git clone https://github.com/awslabs/git-secrets /home/alpine/git-secrets
WORKDIR /home/alpine/git-secrets
RUN make && make install
WORKDIR /api
COPY package*.json ./
RUN npm ci && \
    npm i -g @nestjs/cli@9.1.2
COPY . .

2-2. docker-compose.yml

docker-compose.yml には次のように記載します。

docker-compose.yml
version: '3.8'
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    ports:
      - 3000:3000
    tty: true
    volumes:
      - type: bind
        source: .
        target: /api
    depends_on:
      - db
  db:
    image: mysql:8.0
    restart: always
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: sample
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    volumes:
      - ./db/data:/var/lib/mysql

指定した内容をざっと書き出すと次のとおりです。

項目 内容 備考
version: Compose ファイルのバージョン です。 今は 3 とか 3.8 で良いようです。
service: 以下に、コンテナの定義を記載します。 ここでは、service 名apidb とした2つのコンテナを作成しています。
build: 指定された Dockerfile から、Docker イメージを作成します。 context: ワーキングディレクトリを指定
dockerfile: ドッカーファイルのファイル名(ディレクトリ)を指定
restart: コンテナの再起動について指定します。
ports: 左側にホスト側のポート、右側にコンテナ側のポートを指定します。 MySQL のホスト側の port を変えたい場合は、3307:3306 のように記載します(ここの修正のみでOKで、後掲の data-source.ts の修正は不要です。参考)。
tty: コンテナを起動させ続けるために記載します 参考:DockerのTTYって何?
volumes: ホスト側のデータと、docker コンテナ側のデータをバインドさせます。 ① long syntax
 type: マウントの種類を指定
 source: ホスト側ディレクトリを指定
 target: コンテナ側ディレクトリを指定
② short syntax
 左側: ホスト側のディレクトリを指定
 右側: コンテナ側のディレクトリを指定
environment: 環境変数を指定します。 MYSQL_DATABASE: DB 名
MYSQL_ROOT_PASSWORD: root のパスワード
MYSQL_USER: ユーザー名
MYSQL_PASSWORD: ユーザーのパスワード
depends_on: サービス間の依存関係を指定します。 api:
 depends_on:
  - db
この例では api より前に db が起動することになります。

コンテナが消えても DB の内容を保持できるように、ホスト側に /db というディレクトリを作成して、MySQL のデータを保存するようにしています。
保存場所については、Docker の volume に保存する方法もありますので、そのあたりは他のサイトなどで確認してみてください(ここでは行いません)。

docker-compose.yml 抜粋
    volumes:
      - ./db/data:/var/lib/mysql

<参考サイト>
Compose ファイル・リファレンス
docker-compose.ymlの書き方について解説してみた

2-3. その他のファイル

2-3-1. .dockerignore

.dockerignore ファイルには、Dockerのビルド時に無視するディレクトリ(ファイル)を指定します。

.dockerignore
.git/
node_modules/
db/

先述のとおり db/ には、MySQL のコンテナ内のデータを保存していますので、これを更に api コンテナ側に保存しないようにしています。

2-3-2. .gitignore に1行追加

.gitignore ファイルにも、/db を追加しておきます。

.gitignore
# compiled output
/dist
/node_modules
/db # これを追加

# 以下略

2-4. Docker の起動確認

プロジェクトのルートディレクトリに移動します。
次のコマンドで、docker を起動させます。

$ docker compose up -d

docker ps コマンドでコンテナが起動しているか確認します。

$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                               NAMES
78918ab18ad4   nest-docker-sample_api   "docker-entrypoint.s…"   36 seconds ago   Up 33 seconds   0.0.0.0:3000->3000/tcp              nest-docker-sample-api-1
3fdc62a476f7   mysql:8.0                "docker-entrypoint.s…"   36 seconds ago   Up 35 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   nest-docker-sample-db-1

確認のため、npm run start コマンドでサーバを起動してみます。
コンテナ内でコマンドを実行するので、頭に docker compose exec api を付けています(api は docker-compose.yml ファイルで指定した service名です。)。

$ docker compose exec api npm run start

無事に実行できれば、次のように表示されます。
npm-run-start.png
http://localhost:3000/ にアクセスして「Hello World!」が表示されればコンテナの起動は成功です。
HelloWorld_1.png
作業を続けるため、一旦、Ctrl + C でサーバを停止します。

3. VSCode Remote-Container

ここでは、VSCode Remote-Container を使用します。
特に必須の内容ではなく、コンテナ内に入ってコマンドが実行できれば良いので、不要な人は「4. TypeORM の導入」に進んでください。

参考記事
VSCode Remote Containerが良い
VS Code Remote - Containers を Docker Compose で使うのだー!
みんながきっと1万回は聞いている、VS Code Remoteでコンテナ開発をやる方法

3-1. コンテナでのコマンド実行方法の確認

コンテナでのコマンド実行方法は、いくつかあります。

① コンテナの外からコマンドを実行する場合(参考)
コンテナに対してコマンドを実行するには、実行したいコマンドの前に、docker compose exec <service名> と付ければ操作できます(servise名は docker-compose.yml で指定した名称となります)。
以下は、npm run start を実行する例です(ここでは採用しません)。

$ docker compose exec api npm run start

② コンテナに入ってコマンドを実行する場合(参考)
次のコマンドで、コンテナに入れば、docker compose exec api と頭に付けなくとも操作できます(ここでは採用しません)。

$ docker exec -it <コンテナID> sh

OS(Linuxディストリビューション) で ubuntu を使用する場合は、末尾は bash ですが、ここでは alpine を使用しているので sh となっています。

③ Remote-Container を使用する
ここでは、手軽にコンテナに入るために、Remote-Container を使用します。
導入方法は、次項以下のとおりです。

3-2. Remote-Container の導入

3-2-1. インストール

VSCode の拡張機能として、以下の Remote-Container をインストールします。

3-2-2. VSCode でコンテナを開く

① Remote-Container の使用
インストールが完了すると、VSCode の左下に緑のアイコンが表示されますので、これをクリックします。
remote1.png
② 操作の選択
選択肢が現れますので、Reopen in Container を選択します。
remote2.png
③ Remote-Container を実行するファイルを選択
From 'docker-compose.yml' を選択します。
remote3.png
④ service名を選択
service 名を聞かれますので、api を選択します。
この service 名は、docker-compose.yml で指定した service 名となります。
remote4.png
⑤ WorkSpace の選択(※自動で選択されなかった場合)
Workspace が存在しないというメッセージが出てきたら、Open Workspace をクリックします。
(※おそらく、Dockerfile の WORKDIR と、docker-compose.yml のservice 名が同じだとこの事象が生じてしまいます。)
remote5.png
フォルダーは /api を選択して、OK をクリックします。
この /api は、Dockerfile の WORKDIR で指定したディレクトリです。
remote6.png
初期設定は以上です。

3-2-3. 状態の確認と若干の補正

コンテナに入ると、次のような画面になっています。
remote7.png
① ターミナル
入力部分が 78918ab18ad4:/api# というようになっています。
これは <コンテナID>:<service名># の形式で、ここで直接コンテナに対してコマンドを打つことができます。

78918ab18ad4:/api#

なお「78918ab18ad4:/workdir#」となる場合もありますが、そちらも正常なので問題はありません。

② 作成されるファイル
Remote-Containerを導入すると、ルートの直下にディレクトリ .devcontainer と2つのファイルが作成されます。

nest-docker-sample
├─ .devcontainer
│   ├── devcontainer.json
│   └── docker-compose.yml
└──(...その他のファイル)

③ WorkSpace のディレクトリを修正(※自動で選択されなかった場合)
前項の「⑤ WorkSpace の選択(※自動で選択されなかった場合)」に当てはまった場合は、次のように修正しておきます(自動でディレクトリが選択される場合は不要です)。
devcontainer.json ファイルに "workspaceFolder" を指定するプロパティがあるので、ここを "/workspace" から "/api" に書き換えます。

.devcontainer/devcontainer.json(抜粋)
# 書き換え前
"workspaceFolder": "/workspace"
.devcontainer/devcontainer.json(抜粋)
# 書き換え後
"workspaceFolder": "/api"

/api は、Dockerfile の WORKDIR で指定したディレクトリです。

3-2-4. Remote-Container の終了と再実行

Remote-Container を終了するには、左下の緑の部分をクリックして、Close Remote Connection を選択します。
remote8.png
再度コンテナの中に入るには、左下の緑のアイコンをクリックして、Reopen in Container を選択します。
remote9.png

3-3. 拡張機能(ESLint, Prettier)をコンテナに追加する

コンテナ内に拡張機能を追加するには、次のように devcontainer.json ファイルの extensions に拡張機能の識別子を追加します。

.devcontainer/devcontainer.json(抜粋)
{
	// 
	"extensions": [
		"dbaeumer.vscode-eslint",
		"esbenp.prettier-vscode"
	]
	// 
}

拡張機能の識別子は、それぞれの拡張機能の画面の右下(下図赤枠のところ)に表示されていますので、それを使用します。
extensions.png

一度コンテナを立ち上げた後に拡張機能を追加した場合
私の場合、ESLint の警告(赤い波線)が表示されず不便であったため、後から extensions を追加しました。
その際に、ファイルを書き換えただけでは反映されなかったため、次のことを試すことで VSCode に反映されました(2つのうちどちらか不要かもしれません)。

docker compose down で一回コンテナを削除して、再度 Reopen in Container に入る。
②VSCode の Reload Window(Cmmand + shift + P で検索)で画面を再読み込みする。

参考
今回の設定を行うと、devcontainer.json の全体は次のようになります。

.devcontainer/devcontainer.json
{
	"name": "Existing Docker Compose (Extend)",
	"dockerComposeFile": [
		"../docker-compose.yml",
		"docker-compose.yml"
	],
	"service": "api",
	"workspaceFolder": "/api",
	"extensions": [
		"dbaeumer.vscode-eslint",
		"esbenp.prettier-vscode"
	]
}

4. TypeORM の導入

これから行う作業が完了した後の src ディレクトリは、おおよそ次のようにります。

📦src
 ┣ 📂entities
 ┃ ┗ 📜comment.entity.ts
 ┣ 📂migration
 ┃ ┗ 📜1663429464503-CommentMigration.ts
 ┣ 📜app.controller.ts
 ┣ 📜app.module.ts
 ┣ 📜app.service.ts
 ┣ 📜data-source.ts
 ┗ 📜main.ts

追加していくファイルは、①comment.entity.ts、②1663429464503-CommentMigration.ts(ファイル名は毎回異なる)、③data-source.ts の3つです。
また、app.module.ts を一部修正することになります。

4-1. TypeORM のインストール

次のコマンドで TypeORM のバージョンを指定してインストールします。

# npm install --save @nestjs/typeorm typeorm@0.3.9 mysql2

これを書いている時点では、typeorm@0.3.9 のところを typeorm というようにバージョンを指定しなくとも、同じバージョンの TypeORM がインストールされます。

次のコマンドで、インストールされた TypeORM のバージョンが確認できます。

# npm info typeorm version
0.3.9

参考までに、設定が完了した後の package.json を貼っておきます。

package.json
package.json
{
  "name": "nest-docker-sample",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/platform-express": "^9.0.0",
    "@nestjs/typeorm": "^9.0.1",
    "mysql2": "^2.3.3",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.2.0",
    "typeorm": "^0.3.9"
  },
  "devDependencies": {
    "@nestjs/cli": "^9.0.0",
    "@nestjs/schematics": "^9.0.0",
    "@nestjs/testing": "^9.0.0",
    "@types/express": "^4.17.13",
    "@types/jest": "28.1.8",
    "@types/node": "^16.0.0",
    "@types/supertest": "^2.0.11",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "28.1.3",
    "prettier": "^2.3.2",
    "source-map-support": "^0.5.20",
    "supertest": "^6.1.3",
    "ts-jest": "28.0.8",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "4.1.0",
    "typescript": "^4.7.4"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

4-2. Entity の作成

テーブル定義として、テスト用の Entity クラスを作成します。
以下のように、src/entities/ ディレクトリに comment.entity.ts というファイルを作成しました(中身は適当です)。
これを元に、DB にテーブルが作成されることになります。

src/entities/comment.entity.ts
import {
  Column,
  CreateDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class Comment {
  @PrimaryGeneratedColumn()
  id?: number;

  @Column()
  body: string;

  @CreateDateColumn()
  createdAt?: Date;

  @UpdateDateColumn()
  updatedAt?: Date;

  constructor(body: string) {
    this.body = body;
  }
}

4-3. DataSource の作成

TypeORM v0.3 では、データベースの接続を定義する DataSource ファイルを作成します。
TypeORM v0.2 においては、ormconfig.js のようなファイルを作成していました(現在は非推奨のようです。)。

src/ ディレクトリの直下に以下のように data-source.ts ファイルを作成します。
設定内容は、コード中のコメントのとおりです。

src/data-source.ts
import { Comment } from './entities/comment.entity';
import { DataSource } from 'typeorm';

export const AppDataSource = new DataSource({
  type: 'mysql', // MySQL の場合
  host: 'db', // docker-compose.yml で指定したコンテナの service 名
  port: 3306, // ポート番号
  username: 'user', // docker-compose.yml の MYSQL_USER
  password: 'password', // docker-compose.yml の MYSQL_PASSWORD
  database: 'sample', // docker-compose.yml の MYSQL_DATABASE
  logging: true, // コンソール画面に実行したSQLが表示される
  synchronize: false, // true にすると migration が自動で実行されます。
  entities: [Comment], // エンティティクラスを指定する(複数の場合はカンマで区切る)
  migrations: ['dist/migration/*.js'], // dist ディレクトリ内の js ファイルを指定する
});

参考サイト
npm - TypeORM

4-4. app.module.ts の修正

DataSource ファイルを読み込むために src/app.module.ts を編集します。

src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; // 追加
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppDataSource } from './data-source'; // 追加

@Module({
  imports: [TypeOrmModule.forRoot(AppDataSource.options)], // 修正
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

TypeOrmModule.forRoot() の引数には、DataSource から import した AppDataSource の option プロパティを指定します(AppDataSource.options)。

4-5. マイグレーションファイルの生成(migration:generate)

マイグレーションファイルの生成コマンド(migration:generate)も書き方が変わっています。

# npx typeorm-ts-node-commonjs migration:generate src/migration/CommentMigration -d src/data-source.ts

冒頭の npx typeorm-ts-node-commonjs migration:generate は共通です。
次の src/migration/CommentMigration は、マイグレーションファイルを作成するディレクトリ/ファイル名を指定しています。
最後の -d src/data-source.ts には、接続情報となる DataSource ファイルを指定しています。
この辺りは、冒頭にも紹介したこの記事を参考とさせていただいています。

コマンドを実行すると、ターミナルに次のような表示がされます。
migration_g2.png
無事に成功すれば、指定した src/migration/ フォルダに以下のようなマイグレーションファイルができていると思います。

src/migration/1663429464503-CommentMigration.ts
import { MigrationInterface, QueryRunner } from "typeorm";

export class CommentMigration1663489067218 implements MigrationInterface {
    name = 'CommentMigration1663489067218'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TABLE \`comment\` (\`id\` int NOT NULL AUTO_INCREMENT, \`body\` varchar(255) NOT NULL, \`createdAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updatedAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`DROP TABLE \`comment\``);
    }

}

4-6. マイグレーションの実行(migration:run)

4-6-1. 先にアプリをビルドする

dist の中身を書き換えないと、マイグレーションが実行されないので、実行前に一度ビルドします。
次のコマンドを実行します。

# npm run build

なお、ここではしませんが、npm run start などでサーバを立ち上げても、dist が更新されます(つまり、dist が更新できれば何でも良いです)。

4-6-2. migration:run

さて、いよいよ migration:run を実行します。
コマンドは、次のとおりです。

# npx typeorm-ts-node-commonjs migration:run -d src/data-source.ts

npx typeorm-ts-node-commonjs migration:run はコマンド実行時の共通部分です。
-d src/data-source.ts には、DataSource ファイルを指定します。

コマンドを実行すると、次のようにコンソール画面に表示されます。
migration_r.png
無事に実行できたら、サーバを立ち上げてみます。
エラーが起きなければ成功です。

# npm run start

4-7. DB を確認する

4-7-1. MySQL のコンテナに入る

テーブルが作成されているかの確認をしておきます。
Docker コンテナ内のターミナルでは実行できませんので、別途、新しいターミナルを起動させます。

docker ps コマンドで、実行中の MySQL のコンテナ ID を確認します。

$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                               NAMES
78918ab18ad4   nest-docker-sample_api   "docker-entrypoint.s…"   4 hours ago    Up 29 minutes   0.0.0.0:3000->3000/tcp              nest-docker-sample-api-1
3fdc62a476f7   mysql:8.0                "docker-entrypoint.s…"   4 hours ago    Up 30 minutes   0.0.0.0:3306->3306/tcp, 33060/tcp   nest-docker-sample-db-1

私の手元では、MySQL のコンテナIDは 3fdc62a476f7 なので、次のようにコマンドを実行することで、コンテナの中に入れます。

$ docker exec -it 3fdc62a476f7 sh

4-7-2. DB の内容を確認する

コンテナに入ったら、次のコマンドを実行して、MySQL の操作を開始します。

# mysql -u root -p

パスワードが求められるので、password と入力します。
いうまでもないですが、このパスワードは、docker-compose.yml の MYSQL_ROOT_PASSWORD で指定したものです。

無事に、MySQL に入れたら、show databases コマンドでデータベースの一覧を確認してみます。
次のように sample とあれば OK です。

> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sample             |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

use コマンドで、sample データベースを選択します。

> use sample;

show tables; コマンドで、テーブル一覧を確認します。
comment というテーブルがあれば OK です。

> show tables;
+------------------+
| Tables_in_sample |
+------------------+
| comment          |
| migrations       |
+------------------+
2 rows in set (0.01 sec)

最後に、comment テーブルの定義を確認します。
show create table <テーブル名> コマンドを実行します。
コマンドの末尾は、; ではなく \G とした方が見やすいです。

> show create table comment\G
*************************** 1. row ***************************
       Table: comment
Create Table: CREATE TABLE `comment` (
  `id` int NOT NULL AUTO_INCREMENT,
  `body` varchar(255) NOT NULL,
  `createdAt` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
  `updatedAt` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

以上の感じで、テーブルが作成されていれば成功です。

5. Git について

git をコンテナ内で動作させるのに苦労したため、作業記録を残しておきます。

5-1. git のみインストールした場合

次のように、apk update && apk add bash git として、git と bash をインストールするだけで、git の使用はできます。
bash をインストールするのは、これがないと git を動作させることができないためです。

Dockerfile
FROM node:16-alpine3.16
RUN apk update && \
    apk add bash git
WORKDIR /api
COPY package*.json ./
RUN npm ci
COPY . .

ただ、この場合、コンテナ内で git commit を実行しようとすると、次のようなエラーが生じます。

# git commit -m "test commit"
git: 'secrets' is not a git command. See 'git --help'.

これは、git-secrets がコンテナ内にインストールされていないためです。

※暫定処置
リスクが生じますが、コンテナ内で以下のコマンドを実行すれば commit 時に git-secrets を呼び出さないようにすることができます。

# rm -r .git/hooks

git-secrets は、AWS アクセスキーの遺漏を防ぐなどセキュリティ上、大事な役割を果たすものですので、この方法はあまり好ましくないと思われます。

5-2. git と git-secrets をインストールする場合

git と git-secrets をインストールする場合の Dockerfile です。
試行錯誤しましたが、これで git commit や git push などのコマンドを正常に実行することができます。

Dockerfile
FROM node:16-alpine3.16
RUN apk update && \
    apk add bash git make && \
    apk add --upgrade grep
RUN git clone https://github.com/awslabs/git-secrets /home/alpine/git-secrets
WORKDIR /home/alpine/git-secrets
RUN make && make install
WORKDIR /api
COPY package*.json ./
RUN npm ci
COPY . .

① git-secrets をインストールするために make のインストールが必要となります。
② git commit 時に grep でエラーを吐くので、grep のアップグレードも必要となります。

参考記事
moduscreate/alpine-git-secrets
[alpine] sh: make: not found
UbuntuからAlpineにイメージを移行して容量を減らす例
[RFC] Make it work with Alpine Linux / BusyBox grep

さいごに

NestJS と TypeORM v0.3 については、記事があまり見当たらないところなので、備忘として残しておきました。
Docker など、詳しい分野ではないので、間違い等があるかもしれません。
お気づきのことなどあれば、ご教示いただけると幸いです。

11
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
2