
メインの Linux で開発環境を整えてみた件 ② 〜 仮想環境とデータベース構築
前回まで、開発環境として VSCode をインストールし、実際に JavaScript で API を利用した簡単なクライアントアプリケーションを作成しました。
今回は、サーバーサイドのアプリケーションを作成するため、独学 & ChatGPT でデータベース環境を構築します。
Docker のインストール
Web アプリケーションの実行環境を構築するにあたり、MySQL のデータベースとサーバ環境での実行スクリプト (NODE.js または PHP) が必要なのですが、仮想環境として Docker 上で構築してみます。まずは Ubuntu にDocker をインストールするのに必要なパッケージを入れます。
// Docker を入れるのに必要なアプリを一括インストール
> sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
// GPG(GNU Praivacy Guard) パッケージをインストール
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
// Docker の公式リポジトリを Ubuntu のパッケージ管理システム(apt) に追加しています。
> sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
// Docker のインストール
> sudo apt-get update
// Docker の動作確認
> sudo apt-get install docker-ce
次に GPG(GNU Praivacy Guard) パッケージをインストール。具体的には下記コマンドによって、Docker の公式リポジトリの GPG 鍵が追加され、Docker パッケージが信頼できるものであることを検証します。これは Docker リポジトリからダウンロードされるパッケージが改ざんまたは不正なソースからインストールされないようにするためです。次に Docker の公式リポジトリを Ubuntu のパッケージ管理システム(apt) に追加しています。
最後に、Docker をインストールし動作確認をします。

Docker の環境構築 (docker-compose)
Docker のコンテナを管理するためのツールである Docker Compose を以下のコマンドでインストールします。
// Docker-compose のインストール
> sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
// アプリケーション実行権限がついていないため付与
> sudo chmod +x /usr/local/bin/docker-compose
// アプリケーションのバージョンの確認
> docker-compose --version
docker-compose version 1.29.2, build 5becea4c
次に、バックエンド環境を構成する docker-compose.yml と Dockerfile と呼ばれる構成ファイルを準備します。 今回は MySQL とサーバがバックエンドで連携する構成となるため、それに合わせて Apache2 (PHP) と Node.js 環境を準備します。なお、準備するファイルの中身やイメージのバージョンなどは Docker Hub だったり、YouTube の説明サイトだったりいくつか用意されていますが、細かい設定が必要になるため、ChatGPT とやり取りしながら完成に近づけるのが良いと思います。
// 今回準備したディレクトリ構成
// 上記 2つのファイルを配置したら、それぞれ app/html/config/logs のフォルダを作成する。
<project-root>
├── docker-compose.yml
├── Dockerfile
│
├── app/ # Node アプリのディレクトリ
├── html/ # PHP アプリのディレクトリ
│ ├── index.php
│ ├── info.php
├── config/ # Apache の設定ファイル
│ ├── 000-default.conf
├── logs/
上記のようなディレクトリ構成を作成し、docker-compose.yml のあるフォルダ上で > docker-compose up -d --build を実行します。これで事前に定義したファイルの構造に従い仮想環境が構築されます。


現時点で app フォルダ内に Node.js 起動ファイルを作成していないため、サービスはすぐ終了しますが、それ以外の Web(PHP) と MySQL は問題なコンテナが起動しているかと思います。
Web サーバーの動作確認
最初に作成した Web サーバー (PHP) の起動確認をするため、プロジェクトのルート内の "html" ディレクトリへ移動します。下記コマンドを実行して phpinfo.php というファイルが出来ていることを確認します。
// Webサーバー(PHP) 動作確認のためのコマンド
echo "<?php phpinfo();" > ./phpinfo.php

(残り2つのファイルは後ほど作成します)
次に、ブラウザを起動して、 アドレスに "http://localhost:8080/phpinfo.php" と入力し動作を確認します。下記のように PHP Version の情報ページが取得できれば、仮想 Web サーバーが動いている証拠となります。 (仮想 HTTP サーバーはポート8080 にマッピングされています)

データベースの構築
それぞれ起動を確認したら、MySQL (コンテナ名: mysql_server) を実行し、MySQL でテーブルを作成していきます。下記コマンドを実行し、仮想環境の中で MySQL を起動するのですが、その際に利用するユーザ名とパスワードは、docker-compose.yml で記載してあるものを使用します。
// コンテナの状況確認
> docker ps
// mysql_server コンテナで bash を使用してコマンドを実行する
> docker exec -it mysql_server /bin/bash
// コンテナ内で MySQL を起動する
# mysql -u rockstar -p

まずは、Docker で MySQL のコンテナ作成時に定義したデータベース(=test_db) があるかどうかを確認し選択する。最初はテーブルが無いので適当なテーブルを作成する。
=> 下記画像通り artists というテーブルを作成し、ID と artist というカラムのみ作成している。
// テーブルを作成する SQL
> CREATE TABLE test_db.artists (id INT AUTO_INCREMENT PRIMARY KEY, artist VRCHAR(32) );
// 作成したテーブルのカラムを表示
> SHOW COLUMNS FROM artists;
// テーブルにレコードを挿入
> INSERT INTO artists (id, artist) VALUES (null, '入力する内容');


テーブルを作成したのち、2件ほどレコードを挿入し、内容を確認する。

今回の記事ではデータベースのテーブルとデータ登録に関してはここまでとし、以降は実際に サーバーのスクリプト (今回は PHP を使用) してデータベースからデータを取得できるか確認してみます。
データベースを検索ツールの作成
前述した Web サーバーの動作確認をした phpinfo.php と同じディレクトリに、index.php というファイルを作成します。この時点でブラウザからアドレス欄に http://localhost:8080/idnex.php" と入力しても空白のまま何も表示されません。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Docker Test</title>
</head>
<body>
<table id="table">
<tr><td id=listTitle>List of Artist</td></tr>
<?php
// この中にデータベースを検索するためのコードを記載します
?>
</table>
</body>
</html>
次に上記コード内のコメント欄にある通り <?php - ?> の間の空白に PHP のコードを挿入します。このコードでは、Docker で作成した仮想の MySQL にて先程作成した artists テーブルの中身をそのままブラウザに表示されせてくれます。
<?php
try{
$user = 'rockstar';
$passwd = 'rockstar';
$opt = [
PDO::ATTR_ERRMODE=> PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES=> false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
$dbh = new PDO('mysql:host=mysql_server;dbname=test_db;charset=utf8', $user, $passwd, $opt);
$sql = 'SELECT * FROM artists';
// $stmt = $dbh->prepare($sql);
// $stmt->bindParam(":artist", $artist, PDO::PARAM_STR);
// $stmt->execute();
$stmt = $dbh->query($sql);
while ($row = $stmt->fetch()) {
echo "<tr><td>" . $row[str2html('artist')] . "</td></tr>";
}
$dbh = null;
} catch (PDOException $e) {
echo "Error:st " . $e->getMessage() . "<br>";
exit;
}
?>

簡単なアーチストの名前を登録するデータベースアプリでしたが、表示形式をテーブルで体裁を整え、ボタンを追加し、新規にテーブルにレコードを追加する機能を折りこみ、add.php として保存しました。
<?php
try{
$user = 'rockstar';
$passwd = 'rockstar';
$artist = $_POST['artist'];
if (empty($_POST['artist'])){
exit("Error: Artist is null\n");
}
$opt = [
PDO::ATTR_ERRMODE=> PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES=> false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
$dbh = new PDO('mysql:host=mysql_server;dbname=test_db;charset=utf8', $user, $passwd, $opt);
$sql = 'INSERT INTO artists (id, artist) VALUES (null,:artist)';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(":artist", $_POST['artist'], PDO::PARAM_STR);
$stmt->execute();
// $stmt = $dbh->query($sql);
$dbh = null;
} catch (PDOException $e) {
echo "Error:st " . $e->getMessage() . "<br>";
exit;
}
header('Location:./index.php');
exit;
?>
今回作成したコードを乗せておきます。実行経過は下記の通り、テキストにアーチストを入力して、「Add New Artist」ボタンをクリックすることで、一覧にアーチストが追加される仕組みになっています。

次回は、データベースとフロント & バックエンド両方を使用して、リモートで制御できる音楽プレーヤーを作成したいと思います。
なお、今回も勝手ながら参考にさせていただいたサイトや本などのリンクを紹介します。いずれも素晴らしい内容でした。