2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

raspberrypi5上にdocker構築してその上でWebサーバとdbサーバをたててみる

Last updated at Posted at 2025-01-09

raspberrypi上にdockerを構築してその上にWebサーバとdbサーバをたててみました。

raspberrypi5のセットアップ

インストール

Raspberry Pi Imager を https://www.raspberrypi.com/software からダウンロードし、PC にインストールする。

image.png

インストール設定

Raspberry Pi Imager を実行し、OS ボタンを押し、Raspberry Pi OS (64bit)を選択する。Choose Storage から micro-SD を選択し、進む。

「Would you like apply OS customization settings?」が表示されたら、Edit ボタンを押し、ID とパスワードを入力し、ホスト名も設定する。

さらに、「set locale settings」で国とタイムゾーンを選択し、「Save」をクリックする。

micro-SD へのインストールが完了したら、「continue」ボタンを押して Imager を閉じる。

ここで国の設定をしないとWI-FIの規格の違いで繋がらないことがある。
日本に住んでいる人はJPを選ぼう。

raspberrypi設定

有線マウスと有線キーボードを用意しておくとよい。

microSD をラズベリーパイに挿入し、電源ボタンを押す。
(type-cをさすと勝手に起動する)

一応raspiの設定(左上)を確認しておこう。国や言語が初期設定に戻っている場合がある。

Imager で設定行っても、再度設定するように求められることがある。

国、言語、タイムゾーンを選択する。

日本を選択した場合、言語は日本語になるが、その下に英語を使用するチェックボックスもある。
ネットワーク接続のIDとパスワードを入力し、ホスト名も設定する。

アップデートを実行

最新のパッケージをインストール

sudo apt-get update
sudo apt-get upgrade

OSのアップデート

sudo apt-get dist-upgrade

ラズベリーパイのファームウェアのアップデート

sudo rpi-update

設定終了後に再起動ボタンを押す。
これで Raspberry Pi 5 のセットアップは終了。

同一LAN内でssh接続出来るようにしよう

このraspiは将来サーバになる予定なので他のpcから操作できるようssh接続できるようにしたい。

raspberrypi側

userの確認

whoami

sudo(管理者権限)を与える

sudo gpasswd -a [ユーザー名] sudo

パスワードの変更をし、覚えておく
image.png

subnetを確認する

ifconfig

image.png

このような画面が出るので192.168.hoge.hogeの部分を覚える

sshを有効化

image.png

これにより同じLAN内でのssh接続が可能になる

接続元PCでの操作

ssh [ユーザー名]@[ipアドレス]

ファイアウォール設定

ufwのインストール

sudo apt-get install ufw

22番と80番の解放
理由としては
sshのポート番号が22番

後にwebで公開したいので80か443を空ける
httpでのWeb公開のポート番号が80番
もし証明書を発行してhttpsにする場合は443番をあける

sudo ufw allow 22
sudo ufw allow 80
sudo ufw reload

ファイヤーウォールの有効化

sudo ufw enable

確認

sudo ufw status

22と80だけ空いてればOK。

アカウントのパスワードを打つと、Are you sure you want to continue connecting (yes/no)?と聞かれるのでyes。

これによりssh接続が完了する

公開鍵認証を利用しよう

接続元PCでの操作

鍵作成

rsaは遅いし今後が心配なのでed25519を使用

ssh-keygen -t ed25519

鍵が生成される場所

C:\Users\hoge\.ssh

この「id_ed25519.pub」が公開鍵、「id_ed25519」が秘密鍵。

秘密鍵であるid_ed25519は絶対公開しないようにしよう

先ほどraspiにssh接続できるようになったので、ここからはlinuxコマンドで記述する

raspberrypi側での操作

.sshフォルダを作成する

mkdir .ssh

.フォルダのlsでの確認は

ls -a

でおこなう。

先ほど送った”id_ed25519.pub"を”authorized_keys"という名前に変更しつつ".ssh"に移動する。

mv id_ed25519.pub .ssh/authorized_keys

“.ssh”と”authorized_kyes”のパーミッションを変更する。

chmod 700 .ssh
chmod 600 .ssh/authorized_keys

600は-rw------で管理者のみ読み取り書き込みが可能で、700はxrw------で管理者の実行読み取り書き込みが可能。

公開鍵認証で接続

最後にsshd_configを修正して、ssh接続を有効にします。

nano /etc/ssh/sshd_config

以下の行のコメントアウトを削除して公開鍵認証を有効化し、パスワード認証を無効化する(後に外部接続するため、セキュリティ強化)。

AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
---------------------
PasswordAuthentication no

これで公開鍵認証での接続が可能になる。

接続元PCでの操作

PC側から以下のコマンドで、公開鍵認証でssh接続を確認。

ssh [ユーザ名]@[RaspberryPiのIP] -i 「C:\Users\[ユーザ名]\.ssh\id_ed25519」

configで接続を簡単にしよう

接続元PCでの操作

.ssh内にconfigを作成

cd C:\Users\hoge\.ssh
touch config

手動でもよい

記述方法

Host [好きな名前]
	HostName [RaspberryPiのIP]
	User [ユーザ名]
	Port 22
	IdentityFile 「C:\Users\[ユーザ名]\.ssh\id_ed25519」
	ServerAliveInterval 60

ServerAliveInterval 60は60秒ごとにサーバ側へセッションを送る。

こうすることですぐセッションタイムアウトが起きなくなる。

外部からssh接続出来るようにしよう

ルーターの設定

ラズパイでなくてもいいので同じネットワーク内のPCからブラウザにルーターのipを入力してルーターの設定画面を表示。

route

によってゲートウェイ(ルーター)のipアドレスを表示させる。

デフォルトゲートウェイとはpcにローカルipを振る役割をしている場所
windowsの場合

ifconfig

または
unix系の場合

ipconfig

から、192.168.hoge.hoge辺りを探してもよい。だいたい192.168.1.1とか

これをブラウザで検索

image.png

このような画面を開くことが出来る。

ユーザー名とパスワードが求められることがある。

ここにメーカー別の初期パスワードがまとめられている。
https://0017.org/1491.html#toc3

softbankはuser userであった。

ポートを触れるところがあるはずなので設定

設定項目

項目 記入事項
インターネット(WAN)側のポート 49152~65535の任意の番号
プロトコル TCP
返還後のLAN側のアドレス raspberrypiのipアドレス
返還後のLAN側のポート 22

ブラウザでHTTPプロトコルで通信する場合は80番ポート(HTTPSなら443)を使う。


通信設定(HTTP)

項目 記入事項
インターネット(WAN)側のポート 80
プロトコル TCP
返還後のLAN側のアドレス raspberrypiのipアドレス
返還後のLAN側のポート 80

0~1023:ウェルノウンポート (Well-Known Ports) – HTTP(80), HTTPS(443), SSH(22) などの主要プロトコルが使用。

1024~49151:登録済みポート (Registered Ports) – アプリケーションやサービスごとに登録されているポート。

49152~65535:動的ポートは、これらと競合しない使えるポート。

以下のように設定した
image.png

50000-50000というのは50000から50000番の範囲のポートを使うという意味である。

私の場合はraspberrypiのipアドレスが192.168.3.39であるためこう設定

外部からSSHが通るか確認

まず以下のページを開く
https://www.cman.jp/network/support/go_access.cgi

大きくグローバルIPアドレスが出てくるので覚える

ssh -p [上で決めたポート番号] [ラズパイのアカウント名]@[グローバルip]

[上で決めたポート番号]とは、自分の場合は50000番

家にいて外部から接続の試し方が分からないという人はスマホのデザリングからするのをおすすめする。

$ [アカウント名]@raspberrypi:~ $

と表示されたら外部から接続は完了である。

configに書きたい方へ

先ほど書いたconfigの続きに

Host [好きな名前]
	HostName [グローバルip]
	User [ユーザ名]
	Port [上で決めたポート番号]
	ServerAliveInterval 60

Dockerの構築

dockerのセットアップ

以下のコマンドでdockerをインストールできる

curl -sSL https://get.docker.com | sh

バージョンの確認

docker -v

以下のようにdockerのインストールが確認できる。

Docker version 27.4.1, build b9d17ea

docker環境の準備

作業用ディレクトリーの作成
raspi-dockerは任意のディレクトリー名に変えてよい

mkdir raspi-docker

ディレクトリーが作成できているかどうか確認

ls

ディレクトリーに移動

cd raspi-docker

Webサーバとdbサーバの構築(Node.jsとMySQL)

Dockerfileファイルの作成

touch Dockerfile

Dockerfileを開く

nano Dockerfile

Dockerfileの中身

FROM node:18

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "app.js"]

中身の解説

  • FROM node:18
    FROM

ベースとなるDockerイメージを指定。
node:18は、Node.jsの公式イメージでバージョン18を使用。
バージョン固定の重要性

node:18のようにバージョンを固定することで、後で環境が変わっても同じ状態を再現できる。
node:latestのようにlatestを使うと、後で異なるバージョンが使われる可能性がある。

  • WORKDIR /usr/src/app

コンテナ内で作業ディレクトリを設定。
以降のコマンド(COPYやRUNなど)は、このディレクトリを基準に実行される。
/usr/src/appは、アプリケーションのソースコードを配置するディレクトリとして一般的に使用される。
このパスは慣例的なもので、任意のパスでも可

  • COPY package*.json ./

ホストマシン(ローカル)のpackage.jsonとpackage-lock.jsonを、コンテナ内のカレントディレクトリ(/usr/src/app)にコピーする。
package*.jsonはワイルドカードで、package.jsonとpackage-lock.jsonの両方を対象にする。
この形式を使うことで、どちらか一方しか存在しない場合でもエラーを回避できる。

  • RUN npm install

コンテナのビルド時にコマンドを実行する。
ここではnpm installを実行し、package.jsonに記載された依存パッケージをインストールする。
インストールされたパッケージは/usr/src/app/node_modulesに格納される。
package.jsonが変更されない限り、このステップはキャッシュが使われる。

  • COPY . .

ホストマシンのカレントディレクトリ(.)を、コンテナ内のカレントディレクトリ(/usr/src/app)にコピーする。
左側の.はローカルのカレントディレクトリ。
右側の.はコンテナ内のカレントディレクトリ(WORKDIRで指定した/usr/src/app)。

  • EXPOSE 3000

コンテナがリッスンするポートを指定する。
この例では3000番ポートでアプリケーションが動作。

  • CMD ["node", "app.js"]

コンテナ起動時に実行するデフォルトのコマンドを指定。
ここではnode app.jsを実行してアプリケーションを起動。

docker-compose.ymlファイルの作成

touch docker-compose.yml

docker-compose.ymlを開く

nano docker-compose.yml

docker-compose.ymlの中身

version: '3.8'

services:
  node:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DB_HOST=db
      - DB_USER=${MYSQL_USER}
      - DB_PASSWORD=${MYSQL_PASSWORD}
      - DB_NAME=${MYSQL_DATABASE}

  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 5
¥
volumes:
  db_data:

中身の解説

  • version: '3.8'

docker-composeの仕様バージョンを指定している。

  • services:

複数のコンテナを「サービス」として定義する。ここではnode(Node.jsアプリ)とdb(MySQLデータベース)の2つを定義。
docker-compose upでこれらのサービスが一括で起動。

  • node:

nodeはNode.jsアプリケーションを動作させるためのサービス名。
この名前は自由に変更可能

  • build: .

コンテナはカレントディレクトリにあるDockerfileを使ってビルドされる。
. はカレントディレクトリを示し、そこにDockerfileがあることを前提としている。
もしDockerfileが別の場所にある場合は、build: ./path/to/dockerfileのように指定。

  • ports:
    - "3000:3000"

ホストの3000番ポートをコンテナの3000番ポートにマッピング。
外部(ホスト側)からコンテナの3000番ポートにアクセスできるようになる。

  • volumes:
    - .:/usr/src/app
    - /usr/src/app/node_modules

.:/usr/src/app: ホストのカレントディレクトリ(.)をコンテナの/usr/src/appにマウント。
これにより、ローカルでコードを変更すると、コンテナ内にもリアルタイムで反映される(ホットリロード)。

  • depends_on:
    db:
    condition: service_healthy

このサービスはdb(MySQLサービス)が正常に起動した後に起動することを示す。
service_healthyを条件として、dbがhealthcheckで「正常」と判定されたらnodeサービスが起動。
これにより、データベースが完全に立ち上がる前にアプリケーションが起動することを防ぐ。

  • environment:
    - DB_HOST=db
    - DB_USER={MYSQL_USER}
    - DB_PASSWORD={MYSQL_PASSWORD}
    - DB_NAME={MYSQL_DATABASE}

環境変数を設定する。
${}は.envファイルから値を取得。
DB_HOST=dbは、Node.jsアプリケーションがデータベースに接続する際のホスト名を指定。

  • image: mysql:8.0

Docker Hubからmysql:8.0の公式イメージを取得して使用。
8.0はMySQLのバージョン。

  • ports:
    - "3306:3306"

MySQLの標準ポート3306をホストとコンテナでマッピングする。
これにより、ホスト側からlocalhost:3306でMySQLに接続可能になる。

  • volumes:
    - db_data:/var/lib/mysql

db_dataという名前のボリュームを作成し、MySQLのデータを/var/lib/mysqlに保存する。
コンテナを停止・削除しても、データはボリューム内に保持される。

  • environment:
    - MYSQL_ROOT_PASSWORD={MYSQL_ROOT_PASSWORD}
    - MYSQL_DATABASE={MYSQL_DATABASE}
    - MYSQL_USER={MYSQL_USER}
    - MYSQL_PASSWORD={MYSQL_PASSWORD}

MySQLの初期設定を行う。
ルートパスワードやデータベース名、ユーザー名、パスワードは環境変数から取得される。

  • healthcheck:
    test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD"]
    interval: 10s
    timeout: 5s
    retries: 5

コンテナのヘルスチェックを設定する。
mysqladmin pingでMySQLが起動しているかを確認する。
interval: 10sは10秒ごとにチェックを行う。
timeout: 5sは応答を待つ時間。
retries: 5は失敗した場合のリトライ回数。
これはSQL接続のエラーが起きたためつけた。

  • volumes:
    db_data:

db_dataという名前のボリュームを作成する。
dbサービスで使用され、MySQLのデータを保存する。

app.jsファイルの作成

touch app.js

app.jsを開く

nano app.js

app.jsの中身

const mysql = require('mysql2');
const express = require('express');

const app = express();
const port = 3000;
const host = '192.168.x.x';  // 特定のIPアドレスで待ち受け

// MySQL接続設定
const connection = mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
});

// 接続確認
connection.connect(err => {
  if (err) {
    console.error('Error connecting to MySQL:', err);
    return;
  }
  console.log('Connected to MySQL database');
});

app.get('/', (req, res) => {
  res.send('Hello world!');
});

app.listen(port, () => {
  console.log(`App running on http://localhost:${port}`);
});

コードの説明

const mysql = require('mysql2');
const express = require('express');

mysql2をインポート
express:Node.jsのWebアプリケーションフレームワークをインポート

const app = express();
const port = 3000;
const host = '192.168.x.x';  // 特定のIPアドレスで待ち受け

app:Expressアプリケーションのインスタンスを生成。
port:サーバーがリッスンするポート番号を指定.。
host:サーバーの待ち受けIPアドレス。

const connection = mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
});

mysql.createConnection:MySQLへの接続を確立するための設定。
process.env:環境変数を参照して接続情報を取得。

connection.connect(err => {
  if (err) {
    console.error('Error connecting to MySQL:', err);
    return;
  }
  console.log('Connected to MySQL database');
});

connect:MySQLサーバーに接続

app.get('/', (req, res) => {
  res.send('Hello world!');
});

app.get:GETリクエストを受け取るルートを定義する。
ルート/にアクセスすると、Hello world!という文字列がブラウザに表示される。

app.listen(port, () => {
  console.log(`App running on http://localhost:${port}`);
});

listen:サーバーを指定したポートで起動。

Node.jsでMySQLを使うためのパッケージをインストール

npm init -y
npm install express mysql2

起動

docker compose up --build

ここで基本設定はおしまい

2
4
1

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
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?