0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINCRAFTAdvent Calendar 2024

Day 16

Webアプリ開発ほぼ未経験エンジニアがWebアプリの環境構築を試してみた

Last updated at Posted at 2024-12-15

はじめに

リンクラフト株式会社の竹内です。
リンクラフトアドベントカレンダーの16日目を担当します。

最近、Webアプリを開発するための環境構築を私的に試しましたので、今回はそちらの紹介をさせていただきます(無知レベルで構築していますので、いろいろ適切ではない部分もあるかと思いますが、そこはご容赦を)。

なぜ環境構築を試したのか

私は社会人になって以降、ずっとエンジニアとして活動してきたのですが、Webアプリの開発業務に携わる機会がほぼ無かったんですよね(バッチとかのバックエンド側の開発が主でして)。
長年経験してきてバックエンド一筋、はさすがに武器として貧弱と感じており、フロント側のことも基礎ぐらいは抑えておきたいと思ったのが発端になります。
さらに言うと、業務だとどうしてもアプリケーション(ビジネスロジックとか)の部分だけ意識をして開発を進めている節があり、今回良い機会だったので「どうせなら基盤となる環境の構築からやってみるかー!」というノリでお試しに至ったわけです。

開発環境が整った暁には、個人的に使えるWebアプリの開発も計画しているので、結構気合は入ってマス。

というわけで環境構築

では早速、手順の紹介を!・・・といきたいところですが
はじめに、構築するWebアプリのサーバー構成を紹介しておきます。
Dockerを用いて各サーバーをコンテナ化しています。

スクリーンショット 2024-11-30 15.18.03.png

各コンテナの概要は以下になります。

  • Vueコンテナ
    ユーザーからのリクエストを受けます。今回はフロントエンドにVue.jsを使います。

  • APIコンテナ
    DBサーバーを操作するためのAPIを提供します。Vueコンテナは本サーバーが提供するAPIを利用してデータベースを操作します。ORMライブラリであるSequelizeをインストールします。

  • DBコンテナ
    家計簿アプリのデータを保管するデータベースサーバーです。RDBMSはMySQLを使用します。

また、Dockerネットワーク(backend)を作成することで、コンテナ名でコンテナ間通信が行えるようにします。

Dockerのインストール

ここからが環境構築の手順となります。まずはDockerを入れないと始まらないので、インストールしていきます。手順は以下を参考にしました。

作業ディレクトリ準備

PCの任意ディレクトリに、アプリの資材を配置するための作業ディレクトリを作成します。
私はMacで作業しているのですが、個人ユーザーディレクトリ配下に作業ディレクトリを作成しました。
アプリ名はMoneyTracker(仮称)とし、作業ディレクトリ名に採用しています。

# ディレクトリ移動
$ cd /Users/[個人フォルダ]

# ディレクトリ作成
$ mkdir -p development/money_tracker/vue
$ mkdir -p development/money_tracker/api
$ mkdir -p development/money_tracker/db/logs
$ mkdir -p development/money_tracker/db/conf

# 設定ファイル、ログファイル生成
$ touch development/money_tracker/compose.yml
$ touch development/money_tracker/.env
$ touch development/money_tracker/db/logs/mysql-error.log
$ touch development/money_tracker/db/logs/mysql-query.log
$ touch development/money_tracker/db/logs/mysql-slow.log
$ touch development/money_tracker/db/conf/my.cnf

設定ファイル編集

compose.yml

作業ディレクトリ準備時に作成した、compose.yml(Dockerのコンテナ定義ファイル)を編集していきます。
最終的に、以下内容としました。

compose.yml
compose.yml
services:
  db:
    # 起動するイメージを指定
    image: mysql:8.0.32-debian
    platform: linux/amd64

    # 環境変数を設定
    environment:
      - MYSQL_ROOT_HOST=${DB_ROOT_HOST}
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}

    # ホスト側のポート:コンテナのポート
    ports:
      - '3306:3306'

    expose:
      - '3306'

    # ボリュームバインド
    volumes:
      - ${PWD_PATH}/db/conf:/etc/mysql/conf.d:ro
      - mysqldata:/var/lib/mysql/
      - ${PWD_PATH}/db/logs:/var/log/mysql/

    #使用するネットワーク
    networks:
      - backend

  api:
    image: node:14.21.2-buster
    build:
      context: .
      dockerfile: ./Dockerfile
    environment:
      - MYSQL_SERVER=db
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_DATABASE=${DB_NAME}
      - TZ=${TZ}
      - CHOKIDAR_USEPOLLING=true

    #コンテナを起動させ続けるよう設定
    tty: true

    ports:
      - '3000:3000'

    # ソースコードを格納するフォルダをマウント
    #(ホスト側の./apiをコンテナの/appにマウント)
    volumes:
      - ${PWD_PATH}/api:/app

    # 起動時のカレントフォルダを指定
    working_dir: /app

    # 起動後に実行するコマンドを指定
    command: sh -c "npm run dev"

    networks:
      - backend

    #依存関係(apiコンテナより先にdbコンテナが起動するように設定)
    depends_on:
      - db

  vue:
    image: node:14.21.2-buster
    build:
      context: .
      dockerfile: ./Dockerfile
    environment:
      - CHOKIDAR_USEPOLLING=true
    tty: true
    ports:
      - '8080:8080'
    volumes:
      - ${PWD_PATH}/vue:/app
    working_dir: /app/money-tracker
    command: npm run serve
    networks:
      - backend
    depends_on:
      - api

networks:
  backend:
    driver: bridge

volumes:
  mysqldata:

Dockerネットワーク(backend)については、networks:キーで指定しています。

compose.ymlの記述形式について詳しく知りたい方は、以下が参考になると思います。

my.cnf

MySQLで使用する文字コードや、ログ出力先の指定などをmy.cnfに追記していきます。
この設定ファイルは、コンテナ起動時にボリュームマウントによりDBコンテナ上に配置されます。

my.cnf
my.cnf
# MySQLサーバーへの設定
[mysqld]
# 文字コード/照合順序の設定
character-set-server = utf8mb4
collation-server = utf8mb4_bin

# タイムゾーンの設定
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# デフォルト認証プラグインの設定
default-authentication-plugin = mysql_native_password

# エラーログの設定
log-error = /var/log/mysql/mysql-error.log

# スロークエリログの設定
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 5.0
log_queries_not_using_indexes = 0

# 実行ログの設定
general_log = 1
general_log_file = /var/log/mysql/mysql-query.log

# mysqlオプションの設定
[mysql]
# 文字コードの設定
default-character-set = utf8mb4

# mysqlクライアントツールの設定
[client]
# 文字コードの設定
default-character-set = utf8mb4

my.cnfで設定できるシステム変数については、以下が参考になります。

.env

compose.yml内で参照する環境変数の設定を記述していきます。
具体的には、compose.ymlでMySQLの環境変数を設定している部分が、このファイルから具体的な値を取得していることになります。

.env
.env
PWD_PATH=/Users/[ユーザ名]/development/money_tracker
DB_ROOT_HOST=%
DB_NAME=money_tracker
DB_USER=[MySQLユーザ名]
DB_PASS=[MySQLパスワード]
TZ=Asia/Tokyo

Dockerコンテナの起動

ここで一度、Dockerコンテナを以下コマンドにて起動します。

# Dockerコンテナ起動
$ cd /Users/[ユーザ名]/development/money_tracker
$ docker-compose up -d

# コンテナの起動状態確認
$ docker-compose ps

起動状態を確認すると、起動しているコンテナがリスト表示されます。
この時点で表示されたのはDBコンテナとAPIコンテナで、Vueコンテナは表示されませんでした。すなわち、DBコンテナとAPIコンテナは起動できており、Vueコンテナは起動できていないことがわかります。

DBコンテナの準備

MySQL接続確認

起動済のDBコンテナにアクセスし、MySQLに接続できるか確認します。

# DBコンテナにアクセス
$ docker-compose exec db /bin/bash

#### ここからDBコンテナ内 ####
# MySQLに接続
$ mysql -u root -p

MySQL接続時にパスワードを聞かれますので、.envファイルで設定したパスワード(DB_PASS)を入力してEnterキーを入力します。

文字コード確認

接続成功したら、MySQLの文字コード設定について確認します。

#### DBコンテナ内 ####
# 文字コード確認
mysql> show variables like 'char%';

+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8mb3                        |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.04 sec)

my.cnfで指定した値になっていれば、正常に反映されていることになります。

データベース確認

続いて、データベースの状態を確認します。

#### DBコンテナ内 ####
# データベース確認
mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| money_tracker      |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.05 sec)

money_trackerというデータベースが存在していることが確認できます。
money_trackerの中身についても確認してみます。

#### DBコンテナ内 ####
# データベース切り替え
mysql> use money_tracker;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

# テーブル確認
mysql> show tables;
Empty set (0.00 sec)

money_trackerデータベースの中身は空です(テーブルは1つも存在しません)。

テーブルの作成は手作業でも可能ですが、今回はAPIコンテナからSequelizeのDBマイグレーション機能を使用して行いますので、ここで確認作業を終了します。

コンテナ切断

quitでMySQLを抜け、exitでDBコンテナも抜けます。

#### DBコンテナ内 ####
# MySQLログアウト
mysql> quit
Bye

# コンテナ切断
$ exit

APIコンテナの準備

パッケージインストール

続いて、APIコンテナで必要なパッケージをインストールしていきます。

Express

まずはexpress-generatorパッケージをインストールし、実行します。
Expressは、Node.jsで利用できるWebアプリケーションフレームワークです。

# APIコンテナにアクセス
$ docker-compose exec api /bin/bash

#### ここからAPIコンテナ ####
# express-generatorパッケージのインストール
$ npm install -g express-generator
$ express .

nodemon

次に、nodemonパッケージをインストールします。ソースコードを変更したときに、自動でサーバーを再起動してくれる便利なツールです。

#### APIコンテナ内 ####
# nodemonパッケージのインストール
$ npm install -D nodemon

Sequelize

さらに、Sequelizeに関連するパッケージをインストールします。その後、sequelize-cliを使用してSequelizeの初期化を行います。

#### APIコンテナ内 ####
# Sequelize関連のパッケージインストール
$ npm install mysql2 sequelize sequelize-cli

# Sequelizeの初期化
$ npx sequelize-cli init

設定ファイル編集

package.json

上記でインストールしたnodemonについては、開発環境でのみ使用するため、その設定を/app/package.jsonに反映します。"scripts"の部分に"dev"を追加します。

#### APIコンテナ内 ####
# package.jsonの編集
$ vi /app/package.json
package.json
package.json
{
  "name": "app",
  "version": "0.0.0",
  "private": true,
  "scripts": {
+   "dev": "nodemon ./bin/www",
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "^1.4.7",
    "cors": "^2.8.5",
    "debug": "^2.6.9",
    "express": "^4.16.4",
    "http-errors": "^1.6.3",
    "jade": "^1.11.0",
    "morgan": "^1.9.1",
    "mysql2": "^3.11.4",
    "sequelize": "^6.37.5"
  },
  "devDependencies": {
    "nodemon": "^3.1.7"
  }
}

config.json

上記でSequelizeの初期化を行った時に、/app/configconfig.jsonというJSONファイルが作成されていますが、それをconfig.jsに変更してJavascriptファイルにします。

#### APIコンテナ内 ####
# ファイル名変更
$ mv /app/config/config.json /app/config/config.js

そして、内容を以下のように書き換えます。

config.js
config.js
module.exports = {
  development: {
      username: process.env.MYSQL_USER,
      password: process.env.MYSQL_PASSWORD,
      database: process.env.MYSQL_DATABASE,
      host: process.env.MYSQL_SERVER,
      dialect: 'mysql',
  },
  test: {
      username: process.env.MYSQL_USER,
      password: process.env.MYSQL_PASSWORD,
      database: process.env.MYSQL_DATABASE,
      host: process.env.MYSQL_SERVER,
      dialect: 'mysql',
  },
  production: {
      username: process.env.MYSQL_USER,
      password: process.env.MYSQL_PASSWORD,
      database: process.env.MYSQL_DATABASE,
      host: process.env.MYSQL_SERVER,
      dialect: 'mysql',
  },
};

この書き換えにより、compose.ymlで設定した環境変数の値をそのままDB接続情報として使うことが可能となります。

index.js

上記でconfig.jsonconfig.jsにファイル名変更したので、app/models/index.jsを開き、const config =...の部分を修正します(config.jsonconfig.jsに変更)。

#### APIコンテナ内 ####
# index.jsの編集
$ vi /app/models/index.js
index.js
index.js
'use strict';

const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const process = require('process');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
- const config = require(__dirname + '/../config/config.json')[env];
+ const config = require(__dirname + '/../config/config.js')[env];

const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file => {
    return (
      file.indexOf('.') !== 0 &&
      file !== basename &&
      file.slice(-3) === '.js' &&
      file.indexOf('.test.js') === -1
    );
  })
  .forEach(file => {
    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

このファイルはSequelizeによるDBマイグレーション実行に参照されます(今回は、以降使用しません)。

コンテナ切断

exitでAPIコンテナを抜けます。

#### APIコンテナ内 ####
# コンテナ切断
$ exit

Vueコンテナの準備

コンテナ起動

本手順実行時点で、Vueコンテナは停止しています。
ここでは、docker-compose runを使ってvueコンテナを一時的に起動します。

# Vueコンテナの起動
$ docker-compose run --rm --no-deps vue /bin/bash

--rmは、コンテナ切断時に自動でコンテナを削除するオプションです。
--no-depsは、リンクしたサービスを起動しないようにするオプションです。compose.ymlでコンテナの依存関係を定義したため、本来であればVueコンテナが起動する前にAPIコンテナ(さらにその前のDBコンテナも)が立ち上がりますが、このオプションを設定することでVureコンテナのみ起動するようにしています。

パッケージインストール

Vue CLI

まずはvue-cliパッケージをインストールします。

#### Vueコンテナ内 ####
# vue-cliパッケージのインストール
$ npm install -g @vue/cli

インストール後、プロジェクトの作成を行います。

#### Vueコンテナ内 ####
# プロジェクトの作成
$ vue create money_tracker

プロジェクト作成にあたり、いくつか設定を問われるため、以下の通り選択し設定を進めます。

? Please pick a preset:
 → Manually select features を選択

? Check the features needed for your project:
 → Babel, Linter / Formatter, Router, Vuex を選択

? Choose a version of Vue.js that you want to start the project with
 → 2.x を選択

? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)
 → n を入力

? Pick a linter / formatter config:
 → ESLint with error prevention only を選択

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
 → Lint on save を選択

? Where do you prefer placing config for Babel, ESLint, etc.?
 → In dedicated config files を選択

? Save this as a preset for future projects? (y/N)
 → N を入力

? Pick the package manager to use when installing dependencies:
 → Use NPM を選択

完了すると以下メッセージが表示されます。

🎉  Successfully created project money_tracker.
👉  Get started with the following commands:

 $ cd money_tracker
 $ npm serve

Axios

Axiosは、Node.jsとブラウザのためのPromiseベースのHTTPクライアントです。REST-APIを実行したいときなどに、これを使うと実装が容易になるようです。

#### Vueコンテナ内 ####
# axiosパッケージのインストール
$ npm install axios

Vuetify

Vuetifyは整えられたマテリアルコンポーネント(誰にとっても分かりやすく使いやすいもの)を提供するVue UIライブラリです。後々使えそうなので、追加しておきます。

#### Vueコンテナ内 ####
# vuetifyの追加
$ vue add vuetify

ここでも設定について問われるため、以下の通り選択し設定を進めます。
? Choose a preset:
 → Default (recommended) を選択

以下のように表示されれば追加完了です。

✔  Successfully invoked generator for plugin: vue-cli-plugin-vuetify
vuetify  Discord community: https://community.vuetifyjs.com
vuetify  Github: https://github.com/vuetifyjs/vuetify
vuetify  Support Vuetify: https://github.com/sponsors/johnleider 

コンテナ切断

ここまで完了したら、exitでVueコンテナを抜けます。

#### Vueコンテナ内 ####
# コンテナ切断
$ exit

全てのコンテナを再起動

各コンテナのセットアップが一通り完了したので、一度コンテナを全て停止した後、再起動させます。

# 全てのコンテナを停止
$ docker-compose down

# コンテナ再起動
$ docker-compose up -d

# 起動状態確認
$ docker-compose ps

docker-compose ps実行時にVue, API, DBの全コンテナが表示されれば起動完了となります。

ブラウザアクセス確認

ブラウザから http://localhost:8080/ にアクセスします。
スクリーンショット 2024-12-01 1.51.45.png
このようにVue.jsの初期画面が表示されれば完了です!(お疲れ様でした!)
※私はここに至るまでに1週間かかりました←

開発計画しているアプリとは?

環境構築の手順としては以上となるのですが、冒頭にも書きました開発を計画しているアプリについても、おまけとして紹介させていただきます。
開発を計画しているアプリはズバリ、家計簿アプリになります。

家計簿アプリを題材に選定した背景は以下の通りです。


我が家の家計管理はずっとエクセルを用いてきたのですが、以下のような問題点も抱えていました。
  • オフライン(自宅PC)で管理・更新しているため、外出先とかでリアルタイムに更新できない
  • フォーマットを作成したのが私であり、妻から見るとフォーマットが分かりにくく入力のハードルが高い(らしい)
  • エクセルファイルの肥大化を回避すべく、年次でフォーマットを刷新(ファイルを新たに作成)しているが、地味に面倒
  • 収入や支出の項目が増減する度に、フォーマットを更新しなければならない

少し前から管理の方法は変えたいと思っており、Webアプリ化することで抱えている問題は概ね解決できそうだったので、今回の題材選定に至っています。


せっかく作るなら実用的なものが良く、使えるものを題材にした方が開発の熱量も上がると思いますし(希望的観測)。

現在、絶賛設計中なので、引き続き開発に取り組んでいけたらと思います(果たしていつ完成するやら)。

さいごに

いかがでしたでしょうか?
今回はWebアプリの環境構築について紹介させていただきました。
アプリの基盤部分に触れる機会が無かった私としては、Webアプリの仕組みを理解するには非常に役立ったので、ひとまず満足しています。
実際に操作して動作しているものを目の当たりにした方が理解は深まると思いますし、コンソールでコマンドをバチバチ叩いていると「やってる感」が出ます(笑)

実際に動かしながらWebアプリ開発を学んでみたいという方の参考になれば幸いです…!


一緒に働く仲間を募集中です!

リンクラフト株式会社では、組織拡大に伴い積極的な採用活動を行っています。
少しでも興味がある方はぜひご連絡ください。

▽会社ホームページ
https://lincraft.co.jp/
▽Instagram
https://www.instagram.com/lincraft.inc/
▽ご応募はこちらより
https://lincraft.co.jp/recruit

※カジュアル面談も受付中です。ご希望の方はHPのお問い合わせフォームよりご連絡ください。


0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?