search
LoginSignup
0
Help us understand the problem. What are the problem?

posted at

updated at

DockerでVue+Node(Koa)+Nginx+MongoDB環境を作る

この記事のアピールポイント

  • 初心者に最適
  • フロントエンド開発者に最適

0.事前準備

インストール

以下のソフトウェアと環境のインストールが必要です。

  • Docker以及docker-compose(必須)
  • Docker图形化界面(なくてもよい)
  • Node.js(必須)
  • MongoDB图形化界面(なくてもよい)
  • yarn (なくてもよい,npm,pnpmを使っても構いません)
知識

Dockerコンテンツの説明と構築がメインとなりますので、
フロントエンドとバックエンド開発の説明は特にしません。
なので、以下の知識はあった方がいいです

  • Dockerの基礎知識
  • Mongodbの基礎知識
  • Nginxの基礎知識
  • フロントエンド(vue,react..),バックエンド(node,koa..)の基礎知識
環境
  • OS:Windows 10
  • エディター:VS Code
  • Node.js:v16.3.0
  • Docker:v20.10.13
demo

文章で作成したdemoはGitHubにアップロードしましたので、ご参照ください

1.フロントエンドの準備

ここはviteでvue3を作りますが、好きなJSフレームワークを使ってください
フロントエンドフォルダ参照

rootフォルダでfrontendフォルダを新規作成、viteを初期化

yarn create vite

好きなJSフレームワークを選択して、インストールしてください
いらないコンポーネントを削除して、Axiosをインストール

yarn add -D axios

App.vueで以下のコードを使ってください(ここでTSをつかいましたが、JSでも構いません)
フロントエンドを起動すると、Axiosを使うメソッドapi()はAPIをリクエストして、レスを画面にプリントします
/testはバックエンドが提供しているAPIアドレス(後で説明)

<template>
  <main>
    <div><strong>データ:</strong></div>
    <br />
    <div>{{ data }}</div>
  </main>
</template>

<script setup lang="ts">
import { ref } from "vue";
import axios from "axios";

const host: number = 7021;
interface IDocker {
  id: number;
}

// リクエスト
const data = ref<IDocker[]>();
const api = async (): Promise<void> => {
  await axios.get<IDocker[]>("/test").then((res): void => {
    console.log(res.data);
    data.value = res.data;
  });
};


api();
</script>

package.json

 "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview"
  },

フロントエンドの準備は完了

2.バックエンドの準備

ここでNode.jsのフレームワークKoa.jsとTSで構築しますが、好きなNode.jsフレームワークを使ってください
バックエンドフォルダ参照

rootフォルダでbackendフォルダを新規作成
Koa.js + TSの構築方法はこの記事に参照して作成しました

koaルートをインストール

yarn add koa-router

index.tsで以下のコードを使ってください
バックエンドを起動すると,testというAPIのルートを作成します
testがリクエストされたら,データベースからデータを取得して、レスとして返します

import Koa from "koa";
import Router from "koa-router";
import { connect, Schema, model } from "mongoose";

const app = new Koa();
const router = new Router();

const host: number = 7022;
const url: string = "mongodb://foo:foo@database:27017/docker";

// #################### データベース関連 ####################
const connectMongoDB = async (): Promise<void> => {
  await connect(url)
    .then((): void => {
      console.log("mongodb connect success");
    })
    .catch((): void => {
      console.log("mongodb connect failed");
    });
};

interface IDocker {
  id: number;
}

const schema = new Schema<IDocker>(
  { id: { type: Number, required: true } },
  { versionKey: false }
);

const dockerModel = model<IDocker>("tests", schema);

// #################### ルート関連 ####################
router.get("/test", async (ctx: Koa.Context): Promise<void> => {
  console.log("requested");
  await dockerModel.find({}, { _id: 0 }).then((res: IDocker[]): void => {
    console.log(res);
      
    ctx.body = {
      message: "取得成功",
      result: res,
    };
  });
});


// サーバー起動
connectMongoDB();
app.use(router.routes()).use(router.allowedMethods());
app.listen(host, async (): Promise<void> => {
  console.log(`backend on port ${host} 🚀`);
});
ご注意

定数urlのはデータベースのdockeコンテンツ内アドレスです(後で説明)

バックエンドの準備は完了

3.データの準備

ここでMongodbとそのGUIのMongoDBCompassを使います
データフォルダを参照

rootフォルダでdatabaseフォルダを新規作成して、databaseフォルダでjsファイルmongo-init.jsを新規作成\

mongo-init.jsとは

データベースへのアクセスは管理者IDとパスワードが必要です
本来はターミナルでコマンドでデータをinsertして、管理者IDとパスワードを追加しますが
このmongo-init.jsは、dockerコンテンツ起動の時に自動で必要なデータをinsert、管理員を追加する便利なスクリプトです
rootの管理員はDockerfile指定されましたので、ここで作ったのはCRUD管理員です\

以下のコードを使ってください、dockerコレクションのtestsテーブルに[{ id: 1 }, { id: 2 }]をinsertします。

// テーブル管理者とコレクションの作成
db.createUser({
  user: "foo",
  pwd: "foo",
  roles: [
    {
      role: "readWrite",
      db: "docker",
    },
  ],
});

// 先作ったdocker dbに切り替え
db = db.getSiblingDB("docker");

// コレクションを自動作成、データinsert
db.createCollection("tests");
db.tests.insertMany([{ id: 1 }, { id: 2 }]);

データの準備は完了

まとめ

ここまでのフォルダ構造
これからは以下のフォルダをコンテンツ化します

backend
├──node_modules
├── index.ts
├── tsconfig.json
├── yarn.lock
└── package.json

frontend
├── node_modules
├── public
├── src
├── vite.config.ts
├── tsconfig.json
├── yarn.lock
└── package.json
// 一部省略

database
└── mongo-init.js

4.フロントエンドのDockerfile

考え方

必要なフロントエンドファイルをコンテンツにコピー,コンテンツで必要な環境を用意,コピーした後でファイルをビルド、Nginxでビルドしたファイルをデプロイ

Step1 imageインストール

nodeとnginxのdocker imageをpull
pcで既にnodeとnginxのdocker imageがインストールされたらこのStepを無視

docker pull node
docker pull nginx
Step2 Nginx設定

frontendフォルダでnginxの設定ファイルdefault.confを新規作成
フロントエンドはport7021を使います\

server {
    listen       7021;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    location /test {
        proxy_pass  http://backend:7022;
    }
}
ご注意

proxy_passのはバックエンドのdockeコンテンツ内アドレスです(後で説明)\

Step3 Dockerfile作成

frontendフォルダでDockerfileを新規作成、以下のコードを使ってください\

# イメージ指定
FROM node:16.3.0

# 作者指定
LABEL maintainer="kensoz"

# ワークスペース指定
WORKDIR /usr/src/frontend

# package.jsonとyarn.lockコピー
COPY ["package.json", "yarn.lock", "./"]

# インストール
RUN yarn

# ファイルコピー
COPY . .

# ビルド
RUN yarn build

# イメージ指定
FROM nginx:latest

# コンテナ内のビルドしたdistフォルダをnginxへコピー
COPY --from=0 /usr/src/frontend/dist/ /usr/share/nginx/html/

# nginxコンフィグファイルコピー
COPY default.conf /etc/nginx/conf.d/default.conf

簡単に説明:
FROM node:16.3.0コンテンツで使うnode環境とそのバージョン指定
WORKDIR /usr/src/frontendコンテンツ内のフロントエンドのフォルダ(ワークスペース)
COPY ["package.json", "yarn.lock", "./"]ローカルのpackage.jsonやソースコードをコンテンツ内にコピー
RUN yarnコンテンツ内でフロントエンドをインストール
COPY . .インストールしたものを全部コンテンツ内にコピー
RUN yarn buildコンテンツ内でビルド
FROM nginx:latestコンテンツで使うnginx環境とそのバージョン指定
COPY --from=0 /usr/src/frontend/dist/ /usr/share/nginx/html/コンテンツ内で先ビルドしたdistファイルをコンテンツ内のnginxフォルダの中のhtmlフォルダにコピー(nginxの使い方はローカルと同じ)
COPY default.conf /etc/nginx/conf.d/default.confローカルのnginx設定ファイルをコンテンツ内にコピー\

フロントエンドDockerfile設定完了

5.バックエンドのDockerfile

考え方

必要なフロントエンドファイルをコンテンツにコピー,コンテンツで必要な環境を用意,コピーした後でファイルをビルド、その後サーバーを起動

Step1 Dockerfile

バックエンドはport7022を使います
すでにnodeのimageをインストールしましたので、imageのpullはいらないです
backendフォルダでDockerfileを新規作成、以下のコードを使ってください\

# イメージ指定
FROM node:16.3.0

# 作者指定
LABEL maintainer="kensoz"

# ワークスペース指定
WORKDIR /usr/src/backend

# package.jsonとyarn.lockコピー
COPY ["package.json", "yarn.lock", "./"]

# インストール
RUN yarn

# ファイルコピー
COPY . .

# ビルド
RUN yarn build

# ポートの解放
EXPOSE 7022

# コンテナ実行
ENTRYPOINT [ "yarn", "start" ]

簡単に説明:
FROM node:16.3.0コンテンツで使うnode環境とそのバージョン指定
WORKDIR /usr/src/backendコンテンツ内のバックエンドのフォルダ(ワークスペース)
COPY ["package.json", "yarn.lock", "./"]ローカルのpackage.jsonやソースコードをコンテンツ内にコピー
RUN yarnコンテンツ内でフロントエンドをインストール
COPY . .インストールしたものを全部コンテンツ内にコピー
RUN yarn buildコンテンツ内でビルド
EXPOSE 7022port7022を公開
ENTRYPOINT [ "yarn", "start" ]サーバーを起動

バックエンドDockerfile設定完了

6.データのDockerfile

Step1 imageインストール

データはport27017を使います
MongoDBのdocker imageをpull
pcで既にMongoDBのdocker imageがインストールされたらこのStepを無視

docker pull mongo
Step2 Dockerfile

databaseフォルダでDockerfileを新規作成、以下のコードを使ってください

# イメージ指定
FROM mongo:latest

# 作者指定
LABEL maintainer="kensoz"

# 管理者アカウント作成
ENV MONGO_INITDB_ROOT_USERNAME root

# 管理者パスワード作成
ENV MONGO_INITDB_ROOT_PASSWORD root

# 使う予定のデータベース名称
ENV MONGO_INITDB_DATABASE docker

# コンテナ起動の時、データベース管理者スクリプト実行
ADD mongo-init.js /docker-entrypoint-initdb.d/

簡単に説明:
FROM mongo:latestコンテンツで使うMongoDB環境とそのバージョン指定
ENV MONGO_INITDB_ROOT_USERNAMENV MONGO_INITDB_ROOT_PASSWORDコンテンツを起動すると、root管理員のIDとパスワードを指定
ADD mongo-init.js /docker-entrypoint-initdb.d/コンテンツを起動すると、先作ったスクリプトを自動で実行

データDockerfile設定完了

Tip

それぞれのフォルダで.dockerignoreファイルを作成して、不要なファイルとフォルダを無視にしましょう

node_modules;
dist.vscode;
logs;
coverage;
npm - debug.log;
yarn - debug.log;

7.docker-compose.yml

Step1 rootフォルダでdocker-compose.ymlを新規作成
version: "3.8"

# network
# コンテンツ内ネットワーク名称
networks:
  dockertest-network:
    driver: bridge

services:
  ### frontend #################
  # フロントエンド,ここの名称 frontend はコンテンツ内ネットワークでportとして使う
  frontend:
    container_name: depoly-frontend
    build:
      context: ./frontend
    ports:
      - 127.0.0.1:7021:7021
    restart: always
    depends_on:
      - backend
    networks:
      - dockertest-network

  ### backend #################
  # バックエンド,ここの名称 backend はコンテンツ内ネットワークでportとして使う
  backend:
    container_name: depoly-backend
    build:
      context: ./backend
    ports:
      - 127.0.0.1:7022:7022
    restart: always
    depends_on:
      - database
    networks:
      - dockertest-network

  ### database #################
  # データベース,ここの名称 database はコンテンツ内ネットワークでportとして使う
  database:
    container_name: depoly-database
    build:
      context: ./database
    ports:
      - "127.0.0.1:27017:27017"
    restart: always
    networks:
      - dockertest-network

簡単に説明:\

docker-compose.ymlを使うと、各プロジェクト(フロントエンド、バックエンド、データ)を連携して、コンテンツ内ネットワークを構築、このネットワークによってコンテンツ同士がアクセスできます。
本来データベースにアクセスする時、localhost:27017/みたいなurlを使いますが、コンテンツ内ではlocalhostがなくて、動的なportとなります。コンテンツ内の場合はdocker-compose.ymlで定義したコンテン名称をportとして使います。本記事はdatabaseを定義して、database:27017をデータベースのport urlとして使っています。

docker-compose.yml設定完了

8.dockerコンテンツ実行

rootフォルダで実行

docker-compose up -d

問題がなければ、dockerのGUIで以下のものが確認できます

スクリーンショット 2022-08-01 153410.jpg

9.検証

フロントエンド検証

http://localhost:7021/を起動すると、データが確認できます

スクリーンショット 2022-08-01 153444.jpg

バックエンド検証

dockerのGUIで,バックエンドのlogが確認できます
スクリーンショット 2022-08-01 153513.jpg

データ検証

MongoDBのGUIで,dockerデータベースなどが確認できます

スクリーンショット 2022-08-01 153553.jpg

10.最後

  • volumesは使っていないので、好きに追加してください
  • CD/CIは使っていないので、好きに追加してください.docker-compose up -dを実行すれば自動でデプロイできると思います。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?