[アドカレ2024]Docker,コンテナ入門_3層コンテナを体験してみました。

はじめに

こんにちは、「DENET ADVENT CALENDAR 2024」12月6日担当の山中です。

今回は、以前から気になっていた「コンテナ技術」に入門した際の内容を記事にしました。
具体的には Dockerfile を使用してフロントエンド、バックエンド、DBコンテナを構成、連携させてみた内容で、ほぼコピペで同じように3層コンテナを体験できると思うのでよければご参考いただければと思います。

事前知識

最初に、コンテナの基本的なイメージを掴むために、簡単な例を挙げて説明します。

コンテナとは

コンテナは、アプリケーションと、その設定や動作環境を1つのパッケージにまとめ、どこでも動作させられるようにした技術です。

コンテナを「弁当箱」に例えると分かりやすいかもしれません。

弁当箱には、ご飯、おかず、箸が一緒に入っています。
必要なものが全部そろっているので、どこに持って行っても同じように食べられます。

コンテナも同じで、アプリケーション(弁当)とその設定や動作環境(箸や調味料)をひとまとめにして、「どのサーバーに持っていっても動く状態」にしています。

このコンテナは、イメージと呼ばれる設計図のようなものから作成されます。

なぜ「コンテナ」が必要なのか

IT分野では、アプリケーションが「どこでも同じように動く」ことが非常に重要です。
しかし、従来の方法では以下のような問題が発生することがあります。

①開発環境では動くのに、実際のサーバーでは動かない。
②動作環境や設定の違いでサーバーごとに設定を変えるのが面倒。

こうした課題を解決し、同一の環境を手軽に準備するためにコンテナが必要とされています。

他にも以下のようなメリットがあります。
・ホストOS上のプロセスで動作するため軽量であり、数秒でコンテナの起動や終了が可能
・数秒でコンテナの起動や終了が可能なため、必要に応じて簡単にコンテナを増減できる
・コンテナは必要なものだけを含むため、サーバーのリソース消費に無駄がない
・上記メリットにより同一環境を手軽に用意できるため、開発、テスト、運用の効率化が可能など

このコンテナを簡単に管理するためのツール(プラットフォーム)として、Docker が存在します。

Docker とは

Docker はコンテナを簡単に作成・管理できるツール(プラットフォーム)です。
コンテナ技術を活用する第一歩としてよく選ばれます。

最近、Red Hat Enterprise Linux(RHEL)では Docker とほぼ同様に使用できる Podman の利用が推奨されているみたいです。

事前知識はここまでで、次は実際にコンテナを試してみた際の具体的な内容になります。

検証環境

  • AlmaLinux release 8.10
  • セキュリティグループ 22,80,3000 許可済み

手順

Docker 導入

Docker リポジトリ追加

最初に、Docker の公式リポジトリを追加します。

[root@con-test ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
repo の追加: https://download.docker.com/linux/centos/docker-ce.repo

追加後、リポジトリを確認します、docker-ce-stable が有効化されていればOKです。

[root@con-test ~]# dnf repolist docker*
repo id                                                     repo の名前                                                          状態
docker-ce-nightly                                           Docker CE Nightly - x86_64                                           無効化
docker-ce-nightly-debuginfo                                 Docker CE Nightly - Debuginfo x86_64                                 無効化
docker-ce-nightly-source                                    Docker CE Nightly - Sources                                          無効化
docker-ce-stable                                            Docker CE Stable - x86_64                                            有効化
docker-ce-stable-debuginfo                                  Docker CE Stable - Debuginfo x86_64                                  無効化
docker-ce-stable-source                                     Docker CE Stable - Sources                                           無効化
docker-ce-test                                              Docker CE Test - x86_64                                              無効化
docker-ce-test-debuginfo                                    Docker CE Test - Debuginfo x86_64                                    無効化
docker-ce-test-source                                       Docker CE Test - Sources                                             無効化

Docker インストール

公式リポジトリの追加が確認できたので Docker CE(Community Edition)をインストールします。

[root@con-test ~]# dnf install docker-ce docker-ce-cli containerd.io
Docker CE Stable - x86_64                                                                              789 kB/s |  66 kB     00:00
メタデータの期限切れの最終確認: 0:00:01 前の 2024年12月04日 13時29分26秒 に実施しました。
依存関係が解決しました。
=======================================================================================================================================
 パッケージ                         Arch            バージョン                                         リポジトリー              サイズ
=======================================================================================================================================
インストール:
 containerd.io                      x86_64          1.6.32-3.1.el8                                     docker-ce-stable           35 M
 docker-ce                          x86_64          3:26.1.3-1.el8                                     docker-ce-stable           27 M
 docker-ce-cli                      x86_64          1:26.1.3-1.el8                                     docker-ce-stable          7.8 M
依存関係のインストール:
 container-selinux                  noarch          2:2.229.0-2.module_el8.10.0+3926+f12484f5          appstream                  70 k
 fuse-common                        x86_64          3.3.0-19.el8                                       baseos                     21 k
 fuse-overlayfs                     x86_64          1.13-1.module_el8.10.0+3926+f12484f5               appstream                  69 k
 fuse3                              x86_64          3.3.0-19.el8                                       baseos                     54 k
 fuse3-libs                         x86_64          3.3.0-19.el8                                       baseos                     95 k
 libcgroup                          x86_64          0.41-19.el8                                        baseos                     69 k
 libslirp                           x86_64          4.4.0-2.module_el8.10.0+3926+f12484f5              appstream                  69 k
 slirp4netns                        x86_64          1.2.3-1.module_el8.10.0+3926+f12484f5              appstream                  55 k
弱い依存関係のインストール:
 docker-buildx-plugin               x86_64          0.14.0-1.el8                                       docker-ce-stable           14 M
 docker-ce-rootless-extras          x86_64          26.1.3-1.el8                                       docker-ce-stable          5.0 M
 docker-compose-plugin              x86_64          2.27.0-1.el8                                       docker-ce-stable           13 M
モジュールストリームの有効化中:
 container-tools                                    rhel8

トランザクションの概要
=======================================================================================================================================
インストール  14 パッケージ

ダウンロードサイズの合計: 103 M
インストール後のサイズ: 390 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
(1/14): fuse-common-3.3.0-19.el8.x86_64.rpm                                                            2.3 MB/s |  21 kB     00:00
(2/14): fuse3-3.3.0-19.el8.x86_64.rpm                                                                  4.6 MB/s |  54 kB     00:00
(3/14): fuse3-libs-3.3.0-19.el8.x86_64.rpm                                                             6.0 MB/s |  95 kB     00:00
(4/14): libcgroup-0.41-19.el8.x86_64.rpm                                                                10 MB/s |  69 kB     00:00
(5/14): container-selinux-2.229.0-2.module_el8.10.0+3926+f12484f5.noarch.rpm                           7.0 MB/s |  70 kB     00:00
(6/14): fuse-overlayfs-1.13-1.module_el8.10.0+3926+f12484f5.x86_64.rpm                                 6.4 MB/s |  69 kB     00:00
(7/14): slirp4netns-1.2.3-1.module_el8.10.0+3926+f12484f5.x86_64.rpm                                   7.9 MB/s |  55 kB     00:00
(8/14): libslirp-4.4.0-2.module_el8.10.0+3926+f12484f5.x86_64.rpm                                      6.6 MB/s |  69 kB     00:00
(9/14): docker-buildx-plugin-0.14.0-1.el8.x86_64.rpm                                                    49 MB/s |  14 MB     00:00
(10/14): docker-ce-cli-26.1.3-1.el8.x86_64.rpm                                                          56 MB/s | 7.8 MB     00:00
(11/14): docker-ce-rootless-extras-26.1.3-1.el8.x86_64.rpm                                              37 MB/s | 5.0 MB     00:00
(12/14): docker-ce-26.1.3-1.el8.x86_64.rpm                                                              38 MB/s |  27 MB     00:00
(13/14): containerd.io-1.6.32-3.1.el8.x86_64.rpm                                                        33 MB/s |  35 MB     00:01
(14/14): docker-compose-plugin-2.27.0-1.el8.x86_64.rpm                                                  22 MB/s |  13 MB     00:00
---------------------------------------------------------------------------------------------------------------------------------------
合計                                                                                                    42 MB/s | 103 MB     00:02
Docker CE Stable - x86_64                                                                               67 kB/s | 1.6 kB     00:00
GPG 鍵 0x621E9F35 をインポート中:
 Userid     : "Docker Release (CE rpm) <docker@docker.com>"
 Fingerprint: 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35
 From       : https://download.docker.com/linux/centos/gpg
これでよろしいですか? [y/N]: y
鍵のインポートに成功しました
トランザクションを確認しています
トランザクションの確認に成功しました。
トランザクションをテストしています
トランザクションのテストに成功しました。
トランザクションを実行しています
  準備中           :                                                                                                               1/1
  インストール中   : docker-compose-plugin-2.27.0-1.el8.x86_64                                                                    1/14
  scriptletの実行中: docker-compose-plugin-2.27.0-1.el8.x86_64                                                                    1/14
  scriptletの実行中: container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch                                           2/14
  インストール中   : container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch                                           2/14
  scriptletの実行中: container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch                                           2/14
  インストール中   : fuse3-libs-3.3.0-19.el8.x86_64                                                                               3/14
  scriptletの実行中: fuse3-libs-3.3.0-19.el8.x86_64                                                                               3/14
  インストール中   : containerd.io-1.6.32-3.1.el8.x86_64                                                                          4/14
  scriptletの実行中: containerd.io-1.6.32-3.1.el8.x86_64                                                                          4/14
  インストール中   : docker-buildx-plugin-0.14.0-1.el8.x86_64                                                                     5/14
  scriptletの実行中: docker-buildx-plugin-0.14.0-1.el8.x86_64                                                                     5/14
  インストール中   : docker-ce-cli-1:26.1.3-1.el8.x86_64                                                                          6/14
  scriptletの実行中: docker-ce-cli-1:26.1.3-1.el8.x86_64                                                                          6/14
[sss_cache] [sysdb_domain_cache_connect] (0x0010): DB version too old [0.23], expected [0.24] for domain implicit_files!
Higher version of database is expected!
In order to upgrade the database, you must run SSSD.
Removing cache files in /var/lib/sss/db should fix the issue, but note that removing cache files will also remove all of your cached credentials.
Could not open available domains
[sss_cache] [sysdb_domain_cache_connect] (0x0010): DB version too old [0.23], expected [0.24] for domain implicit_files!
Higher version of database is expected!
In order to upgrade the database, you must run SSSD.
Removing cache files in /var/lib/sss/db should fix the issue, but note that removing cache files will also remove all of your cached credentials.
Could not open available domains

  インストール中   : libslirp-4.4.0-2.module_el8.10.0+3926+f12484f5.x86_64                                                        7/14
  インストール中   : slirp4netns-1.2.3-1.module_el8.10.0+3926+f12484f5.x86_64                                                     8/14
  scriptletの実行中: libcgroup-0.41-19.el8.x86_64                                                                                 9/14
[sss_cache] [sysdb_domain_cache_connect] (0x0010): DB version too old [0.23], expected [0.24] for domain implicit_files!
Higher version of database is expected!
In order to upgrade the database, you must run SSSD.
Removing cache files in /var/lib/sss/db should fix the issue, but note that removing cache files will also remove all of your cached credentials.
Could not open available domains
[sss_cache] [sysdb_domain_cache_connect] (0x0010): DB version too old [0.23], expected [0.24] for domain implicit_files!
Higher version of database is expected!
In order to upgrade the database, you must run SSSD.
Removing cache files in /var/lib/sss/db should fix the issue, but note that removing cache files will also remove all of your cached credentials.
Could not open available domains

  インストール中   : libcgroup-0.41-19.el8.x86_64                                                                                 9/14
  scriptletの実行中: libcgroup-0.41-19.el8.x86_64                                                                                 9/14
  インストール中   : fuse-common-3.3.0-19.el8.x86_64                                                                             10/14
  インストール中   : fuse3-3.3.0-19.el8.x86_64                                                                                   11/14
  インストール中   : fuse-overlayfs-1.13-1.module_el8.10.0+3926+f12484f5.x86_64                                                  12/14
  scriptletの実行中: fuse-overlayfs-1.13-1.module_el8.10.0+3926+f12484f5.x86_64                                                  12/14
  インストール中   : docker-ce-3:26.1.3-1.el8.x86_64                                                                             13/14
  scriptletの実行中: docker-ce-3:26.1.3-1.el8.x86_64                                                                             13/14
  インストール中   : docker-ce-rootless-extras-26.1.3-1.el8.x86_64                                                               14/14
  scriptletの実行中: docker-ce-rootless-extras-26.1.3-1.el8.x86_64                                                               14/14
  scriptletの実行中: container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch                                          14/14
  scriptletの実行中: docker-ce-rootless-extras-26.1.3-1.el8.x86_64                                                               14/14
  検証中           : fuse-common-3.3.0-19.el8.x86_64                                                                              1/14
  検証中           : fuse3-3.3.0-19.el8.x86_64                                                                                    2/14
  検証中           : fuse3-libs-3.3.0-19.el8.x86_64                                                                               3/14
  検証中           : libcgroup-0.41-19.el8.x86_64                                                                                 4/14
  検証中           : container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch                                           5/14
  検証中           : fuse-overlayfs-1.13-1.module_el8.10.0+3926+f12484f5.x86_64                                                   6/14
  検証中           : libslirp-4.4.0-2.module_el8.10.0+3926+f12484f5.x86_64                                                        7/14
  検証中           : slirp4netns-1.2.3-1.module_el8.10.0+3926+f12484f5.x86_64                                                     8/14
  検証中           : containerd.io-1.6.32-3.1.el8.x86_64                                                                          9/14
  検証中           : docker-buildx-plugin-0.14.0-1.el8.x86_64                                                                    10/14
  検証中           : docker-ce-3:26.1.3-1.el8.x86_64                                                                             11/14
  検証中           : docker-ce-cli-1:26.1.3-1.el8.x86_64                                                                         12/14
  検証中           : docker-ce-rootless-extras-26.1.3-1.el8.x86_64                                                               13/14
  検証中           : docker-compose-plugin-2.27.0-1.el8.x86_64                                                                   14/14

インストール済み:
  container-selinux-2:2.229.0-2.module_el8.10.0+3926+f12484f5.noarch      containerd.io-1.6.32-3.1.el8.x86_64
  docker-buildx-plugin-0.14.0-1.el8.x86_64                                docker-ce-3:26.1.3-1.el8.x86_64
  docker-ce-cli-1:26.1.3-1.el8.x86_64                                     docker-ce-rootless-extras-26.1.3-1.el8.x86_64
  docker-compose-plugin-2.27.0-1.el8.x86_64                               fuse-common-3.3.0-19.el8.x86_64
  fuse-overlayfs-1.13-1.module_el8.10.0+3926+f12484f5.x86_64              fuse3-3.3.0-19.el8.x86_64
  fuse3-libs-3.3.0-19.el8.x86_64                                          libcgroup-0.41-19.el8.x86_64
  libslirp-4.4.0-2.module_el8.10.0+3926+f12484f5.x86_64                   slirp4netns-1.2.3-1.module_el8.10.0+3926+f12484f5.x86_64

完了しました!

インストールが完了したら Docker のバージョンを確認します。
Docker のバージョンが表示されていればインストールは完了です。

[root@con-test ~]# docker -v
Docker version 26.1.3, build b72abbb

Docker サービスの起動と自動起動設定

インストールが完了したら、Docker サービスの起動と自動起動を設定します。

[root@con-test ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.

Docker の起動と自動起動を確認します。

[root@con-test ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2024-12-04 13:32:08 JST; 13s ago
     Docs: https://docs.docker.com
 Main PID: 82291 (dockerd)
    Tasks: 8
   Memory: 41.3M
   CGroup: /system.slice/docker.service
           mq82291 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

12月 04 13:32:07 con-test dockerd[82291]: time="2024-12-04T13:32:07.922900218+09:00" level=info msg="Starting up"
12月 04 13:32:07 con-test dockerd[82291]: time="2024-12-04T13:32:07.967614512+09:00" level=info msg="Loading containers: start."
12月 04 13:32:08 con-test dockerd[82291]: time="2024-12-04T13:32:08.425985692+09:00" level=info msg="Loading containers: done."
12月 04 13:32:08 con-test dockerd[82291]: time="2024-12-04T13:32:08.451631236+09:00" level=info msg="Docker daemon" commit=8e96db1 con>
12月 04 13:32:08 con-test dockerd[82291]: time="2024-12-04T13:32:08.451758194+09:00" level=info msg="Daemon has completed initializati>
12月 04 13:32:08 con-test dockerd[82291]: time="2024-12-04T13:32:08.512322576+09:00" level=info msg="API listen on /run/docker.sock"

以下で「active (running)」となっていれば起動している事が確認できます。
「Active: active (running) since Wed 2024-12-04 13:32:08 JST; 13s ago」
以下で「enabled;」となっていれば自動起動が有効化されている事を確認できます。
「Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled;」

以上で Docker の導入が完了しました。
次はコンテナを用意していきます。

一般ユーザーが Docker を使うには、そのユーザーを docker グループに追加する必要があります。
今回は root ユーザーで作業しているため、こちらの設定は行っていません。

sudo usermod -aG docker $USER

コンテナ作成

以下の順でコンテナを作成していきます。

・フロントエンドコンテナ
・バックエンドコンテナ
・DBコンテナ

コンテナは Docker イメージという設計図から作成されます。
Docker hub から Docker イメージを取得すれば手早くコンテナを作成できますが、今回は Dockerfile を用意して1つずつ作成していきます。

フロントエンドコンテナ作成

最初に、フロントエンドコンテナを作成します。
frontend ディレクトリを作成します。

[root@con-test ~]# mkdir frontend
[root@con-test ~]# ll -d frontend
drwxr-xr-x 2 root root 6 12月  4 13:41 frontend

次に、frontend ディレクトリで簡単な HTML ファイルを作成します。

[root@con-test ~]# vim /root/frontend/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Frontend</title>
</head>
<body>
    <h1>Frontend is running!</h1>
</body>
</html>

続いて frontend ディレクトリでフロントエンドコンテナのイメージを作成するため Dockerfile を作成します。

[root@con-test ~]# vim /root/frontend/Dockerfile

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/

「FROM nginx:alpine」
軽量な NGINX(nginx:alpine イメージ)ベースの簡単な Web サーバーを構築します。

「COPY index.html /usr/share/nginx/html/」
先程作成した /root/frontend/index.html を NGINX のデフォルトの公開ディレクトリ /usr/share/nginx/html/ にコピーしています。

Dockerfile が作成できたので docker build コマンドを使用して
作成した Dockerfile から Docker イメージをビルドしていきます。
「-t」でイメージ名を指定しています。

[root@con-test ~]# docker build -t my-frontend /root/frontend
[+] Building 4.1s (7/7) FINISHED                                                                                        docker:default
 => [internal] load build definition from Dockerfile                                                                              0.1s
 => => transferring dockerfile: 94B                                                                                               0.0s
 => [internal] load metadata for docker.io/library/nginx:alpine                                                                   2.1s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => [internal] load build context                                                                                                 0.0s
 => => transferring context: 199B                                                                                                 0.0s
 => [1/2] FROM docker.io/library/nginx:alpine@sha256:41523187cf7d7a2f2677a80609d9caa14388bf5c1fbca9c410ba3de602aaaab4             1.6s
 => => resolve docker.io/library/nginx:alpine@sha256:41523187cf7d7a2f2677a80609d9caa14388bf5c1fbca9c410ba3de602aaaab4             0.0s
 => => sha256:b1f7437a6d0398a47a5d74a1e178ea6fff3ea692c9e41d19c2b3f7ce52cdb371 2.50kB / 2.50kB                                    0.0s
 => => sha256:da9db072f522755cbeb85be2b3f84059b70571b229512f1571d9217b77e1087f 3.62MB / 3.62MB                                    0.2s
 => => sha256:e10e486de1ab216956a771c782ef1adabef10b1bfd9a3765e14f79484784e9cd 4.06MB / 4.06MB                                    0.6s
 => => sha256:af9c0e53c5a430c700d068066f35cb313945c9917bee94108bae13a933f6b6b4 628B / 628B                                        0.3s
 => => sha256:41523187cf7d7a2f2677a80609d9caa14388bf5c1fbca9c410ba3de602aaaab4 10.36kB / 10.36kB                                  0.0s
 => => sha256:91ca84b4f57794f97f70443afccff26aed771e36bc48bad1e26c2ce66124ea66 11.25kB / 11.25kB                                  0.0s
 => => extracting sha256:da9db072f522755cbeb85be2b3f84059b70571b229512f1571d9217b77e1087f                                         0.1s
 => => sha256:b2eb2b8af93a0c4d2b5f5a70ed620869b406658462aba70b03f12f442aa40cc1 956B / 956B                                        0.5s
 => => sha256:e351ee5ec3d4f55b4e3fce972c2a34a5632ede02602dfbcad85afc539b486131 405B / 405B                                        0.5s
 => => extracting sha256:e10e486de1ab216956a771c782ef1adabef10b1bfd9a3765e14f79484784e9cd                                         0.1s
 => => sha256:471412c08d15ee3b0c86b86fe91a6dd0e17d1f4d1b6d83a7f68e9b709328bf3d 1.40kB / 1.40kB                                    0.8s
 => => sha256:fbbf7d28be71101773e4440c75dbbe7ed12767763fbb2e9c85a32a31f611169a 1.21kB / 1.21kB                                    0.7s
 => => sha256:a2eb5282fbec00fa3d13849dafbfd7f416b69059e527e5653b84f1d9245b8eb0 15.10MB / 15.10MB                                  0.9s
 => => extracting sha256:af9c0e53c5a430c700d068066f35cb313945c9917bee94108bae13a933f6b6b4                                         0.0s
 => => extracting sha256:b2eb2b8af93a0c4d2b5f5a70ed620869b406658462aba70b03f12f442aa40cc1                                         0.0s
 => => extracting sha256:e351ee5ec3d4f55b4e3fce972c2a34a5632ede02602dfbcad85afc539b486131                                         0.0s
 => => extracting sha256:fbbf7d28be71101773e4440c75dbbe7ed12767763fbb2e9c85a32a31f611169a                                         0.0s
 => => extracting sha256:471412c08d15ee3b0c86b86fe91a6dd0e17d1f4d1b6d83a7f68e9b709328bf3d                                         0.0s
 => => extracting sha256:a2eb5282fbec00fa3d13849dafbfd7f416b69059e527e5653b84f1d9245b8eb0                                         0.4s
 => [2/2] COPY index.html /usr/share/nginx/html/                                                                                  0.1s
 => exporting to image                                                                                                            0.0s
 => => exporting layers                                                                                                           0.0s
 => => writing image sha256:0ddf02aa6138b6c316b5947df99160d047a22a029e8b9dbff1578b66d09e06ca                                      0.0s
 => => naming to docker.io/library/my-frontend                                                                                    0.0s

イメージが作成されたら docker images コマンドを使用してイメージ一覧を確認します。
my-frontend イメージが作成されている事が確認できます。

[root@con-test ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
my-frontend   latest    0ddf02aa6138   About a minute ago   52.5MB

イメージの作成が確認できたので docker run コマンドを使用して my-frontend イメージからコンテナを作成していきます。
「-d」でコンテナをバックグラウンドで起動させ、
「--name」でコンテナ名を指定しています。
「-p」で 80番ポートのリクエストがフロントエンドコンテナに向くようにマッピングしています。

[root@con-test ~]# docker run -d --name frontend -p 80:80 my-frontend
b9ab79e88f2bba05ef63aa9c616c2df6b8fe2cae436f4f30093bd828669eae60

コンテナの識別IDが表示されたらOKです。

docker ps コマンドで作成されたコンテナを確認できるので frontend コンテナの作成を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED         STATUS         PORTS                NAMES
b9ab79e88f2b   my-frontend   "/docker-entrypoint.…"   4 minutes ago   Up 4 minutes   0.0.0.0:80->80/tcp   frontend

frontend コンテナの「STATUS」が「Up」と表示されていればOKです。

frontend コンテナの作成が確認できたのでブラウザ上からコンテナにアクセスして動作確認を行います。

ブラウザで http://<EC2のパブリックIP> にアクセスし、「Frontend is running!」が表示されれば成功です。

①フロントエンドコンテナ動作確認
①フロントエンドコンテナ動作確認

frontend コンテナのアクセスログを表示して、サーバ上でもアクセスに問題がない事を確認します。
docker logs コマンドを使用して frontend コンテナのアクセスログを確認できます。

[root@con-test ~]# docker logs frontend
{IP} - - [04/Dec/2024:04:59:18 +0000] "GET / HTTP/1.1" 200 160 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "-"
{IP} - - [04/Dec/2024:04:59:18 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://13.231.3.188/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "-"
2024/12/04 04:59:18 [error] 30#30: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 221.243.14.226, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "13.231.3.188", referrer: "http://13.231.3.188/"

GET リクエストでステータスコード:200 が出ていればOKです。
favicon.ico で 404 出ていますが、favicon.ico は用意していないのでこれは問題ないです。

フロントエンドコンテナの動作が確認できたので、次はバックエンドコンテナ(アプリケーションサーバ)を作成していきます。

バックエンドコンテナ作成

バックエンドコンテナ作成前にカスタムネットワークを作成しておきます。
後にコンテナ間を繋ぐのに必要になります。

[root@con-test ~]# docker network create my-network
6d4b7b3f66243d933d702180e2ffaa866d50a563b6ecf572be6fb4b8b6bd5762

frontend ディレクトリと同じ階層に backend ディレクトリを作成します。

[root@con-test ~]# mkdir /root/backend
[root@con-test ~]# ll -d /root/backend
drwxr-xr-x 2 root root 6 12月  4 14:08 /root/backend

backend ディレクトリで app.js を作成します。
フロントエンドとバックエンドを通信させるための処理を app.js に記載していきます。

[root@con-test ~]# vim /root/backend/app.js

const express = require('express');
const app = express();

app.get('/api/data', (req, res) => {
    res.json({ message: "Hello from Backend!" });
});

app.listen(3000, () => {});

「const express = require('express');」
「const app = express();」
アプリケーションフレームワーク Express のインポートと、Express インスタンスの定義を行っています。

「app.get('/api/data', (req, res) => {
res.json({ message: "Hello from Backend!" });
});」
/api/data 宛てにリクエストが来た時「Hello from Backend!」を返すようにしています。

「app.listen(3000, () => {});」
3000番ポートでバックエンドサーバを起動させています。

backend ディレクトリでバックエンドコンテナ用のイメージを作成するための Dockerfile を作成します。

[root@con-test ~]# vim /root/backend/Dockerfile

FROM node:16
WORKDIR /app
COPY . .
RUN npm install express
CMD ["node", "app.js"]

「FROM node:16」
Node.jsのバージョン16をベースイメージとして指定しています。

「WORKDIR /app」
コンテナ内の作業ディレクトリを /app に設定しています。

「COPY . .」
先程作成した app.js 等をバックエンドコンテナの /app ディレクトリにコピーしています。

「RUN npm install express」
express インストールしています。

「CMD ["node", "app.js"] 」
バックエンドコンテナが実行された際、Node.js で app.js を実行するように指定しています。
こちらでコンテナ内でバックエンドサーバが起動されます。

バックエンドコンテナ用の Dockerfile が作成できたのでビルドしていきます。

[root@con-test ~]# docker build -t my-backend /root/backend/
[+] Building 27.9s (9/9) FINISHED                                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                                              0.0s
 => => transferring dockerfile: 120B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/node:16                                                                        1.8s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => [1/4] FROM docker.io/library/node:16@sha256:f77a1aef2da8d83e45ec990f45df50f1a286c5fe8bbfb8c6e4246c6389705c0b                 21.4s
 => => resolve docker.io/library/node:16@sha256:f77a1aef2da8d83e45ec990f45df50f1a286c5fe8bbfb8c6e4246c6389705c0b                  0.0s
 => => sha256:c94b82f9827cab6e421b350965a9ef11b25b13ffbd1030536203d541f55dcbe2 2.00kB / 2.00kB                                    0.0s
 => => sha256:7e9bf114588c05b2df612b083b96582f3b8dbf51647aa6138a50d09d42df2454 17.58MB / 17.58MB                                  0.7s
 => => sha256:ffd9397e94b74abcb54e514f1430e00f604328d1f895eadbd482f08cc02444e5 51.89MB / 51.89MB                                  1.3s
 => => sha256:f77a1aef2da8d83e45ec990f45df50f1a286c5fe8bbfb8c6e4246c6389705c0b 776B / 776B                                        0.0s
 => => sha256:1ddc7e4055fdb6f6bf31063b593befda814294f9f904b6ddfc21ab1513bafa8e 7.23kB / 7.23kB                                    0.0s
 => => sha256:311da6c465ea1576925360eba391bcd32dece9be95960a0bc9ffcb25fe712017 50.50MB / 50.50MB                                  0.8s
 => => sha256:513d779256048c961239af5f500589330546b072775217272e19ffae1635e98e 191.90MB / 191.90MB                                3.0s
 => => sha256:ae3b95bbaa61ce24cefdd89e7c74d6fbd7713b2bcae93af47063d06bd7e02172 4.20kB / 4.20kB                                    1.1s
 => => extracting sha256:311da6c465ea1576925360eba391bcd32dece9be95960a0bc9ffcb25fe712017                                         4.2s
 => => sha256:0e421f66aff42bb069dffc26af6d132194b22a1082b08c5ef7cd69c627783c04 34.79MB / 34.79MB                                  1.9s
 => => sha256:ca266fd6192108b67fb57b74753a8c4ca5d8bd458baae3d4df7ce9f42dedcc1d 2.27MB / 2.27MB                                    1.6s
 => => sha256:ee7d78be1eb92caf6ae84fc3af736b23eca018d5dedc967ae5bdee6d7082403b 450B / 450B                                        1.9s
 => => extracting sha256:7e9bf114588c05b2df612b083b96582f3b8dbf51647aa6138a50d09d42df2454                                         0.6s
 => => extracting sha256:ffd9397e94b74abcb54e514f1430e00f604328d1f895eadbd482f08cc02444e5                                         3.3s
 => => extracting sha256:513d779256048c961239af5f500589330546b072775217272e19ffae1635e98e                                         9.5s
 => => extracting sha256:ae3b95bbaa61ce24cefdd89e7c74d6fbd7713b2bcae93af47063d06bd7e02172                                         0.0s
 => => extracting sha256:0e421f66aff42bb069dffc26af6d132194b22a1082b08c5ef7cd69c627783c04                                         1.8s
 => => extracting sha256:ca266fd6192108b67fb57b74753a8c4ca5d8bd458baae3d4df7ce9f42dedcc1d                                         0.1s
 => => extracting sha256:ee7d78be1eb92caf6ae84fc3af736b23eca018d5dedc967ae5bdee6d7082403b                                         0.0s
 => [internal] load build context                                                                                                 0.0s
 => => transferring context: 387B                                                                                                 0.0s
 => [2/4] WORKDIR /app                                                                                                            0.4s
 => [3/4] COPY . .                                                                                                                0.1s
 => [4/4] RUN npm install express                                                                                                 3.9s
 => exporting to image                                                                                                            0.2s
 => => exporting layers                                                                                                           0.1s
 => => writing image sha256:ce32f52d37a96926729f2c4fc3f40bd0d1f24bf1efe9ded7348b9681a2933876                                      0.0s
 => => naming to docker.io/library/my-backend                                                                                     0.0s

ビルドできたら作成されたイメージを確認します。
my-backend イメージが作成されているかと思います。

[root@con-test ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
my-backend    latest    ce32f52d37a9   53 seconds ago   916MB
my-frontend   latest    0ddf02aa6138   6 hours ago      52.5MB

作成した my-backend イメージから backend コンテナを起動していきます。

「--network my-network」で先程作成した my-network という名前の Docker ネットワークにこのコンテナを接続するように指定しています。

[root@con-test ~]# docker run -d --name backend --network my-network my-backend
7dbdb9b75c6232a0aca36a6d3afcb412d91207869ffc07b3498a0d9a88776e38

backend コンテナが作成された事を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                    NAMES
7dbdb9b75c62   my-backend   "docker-entrypoint.s…"   7 seconds ago   Up 5 seconds             backend
b9ab79e88f2b   my-frontend   "/docker-entrypoint.…"   6 hours ago      Up 6 hours      0.0.0.0:80->80/tcp       frontend

フロントエンドコンテナ再作成

フロントエンドからバックエンドにリクエストを向かせたいので
フロントエンドの nginx.conf と index.html を更新して再度ビルドします。

フロントエンドからバックエンドへの通信を行うため、バックエンドコンテナへのリバースプロキシを設定します。

nginx.conf を作成します。

[root@con-test ~]# vim /root/frontend/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen 80;  # HTTPリクエストをポート80で受け付け

        # 静的ファイルの提供設定
        location / {
            root /usr/share/nginx/html;
            index index.html;
        }

        # APIリクエストのリバースプロキシ設定
        location /api/ {
            proxy_pass http://backend:3000/; 
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
}

「proxy_pass http://backend:3000/;」
こちらでバックエンドコンテナにリクエストが向くように指定しています、コピペでOKです。

続いて index.html

[root@con-test ~]# vim /root/frontend/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Frontend</title>
</head>
<body>
    <h1>Frontend is running!</h1>
    <p>Data from backend: <span id="data"></span></p>
    <script>
        fetch('http://3.112.126.88:3000/api/data')
            .then(response => response.json())
            .then(data => document.getElementById('data').innerText = data.message)
            .catch(error => console.error('Error fetching data:', error));
    </script>
</body>
</html>

「fetch('http://3.112.126.88:3000/api/data')」
IPアドレスはEC2のパブリックIPです。
この行で、fetchを使い指定したURLにGETリクエストを送信させています。
こちらもIPアドレス以外コピペでOKです。

作成した nginx.conf をバックエンドコンテナにコピーさせたいので Dockerfile も更新します。

[root@con-test ~]# vim /root/frontend/Dockerfile

FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /usr/share/nginx/html/

nginx.conf, index.html の更新反映のため再度フロントエンドのイメージをビルドします。

[root@con-test ~]# docker build -t my-frontend /root/frontend/
[+] Building 1.6s (8/8) FINISHED                                                                                        docker:default
 => [internal] load build definition from Dockerfile                                                                              0.0s
 => => transferring dockerfile: 132B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/nginx:alpine                                                                   1.3s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => CACHED [1/3] FROM docker.io/library/nginx:alpine@sha256:41523187cf7d7a2f2677a80609d9caa14388bf5c1fbca9c410ba3de602aaaab4      0.0s
 => [internal] load build context                                                                                                 0.0s
 => => transferring context: 1.37kB                                                                                               0.0s
 => [2/3] COPY nginx.conf /etc/nginx/nginx.conf                                                                                   0.0s
 => [3/3] COPY index.html /usr/share/nginx/html/                                                                                  0.1s
 => exporting to image                                                                                                            0.1s
 => => exporting layers                                                                                                           0.0s
 => => writing image sha256:4dc2a9145221ed76743443f994a0e294d89484bfe673aa606cbb99629c9c1e16                                      0.0s
 => => naming to docker.io/library/my-frontend                                                                                    0.0s

ビルドが完了したら、
新規にフロントエンドコンテナを作成するため、現在のフロントエンドコンテナを削除します。

docker stop コマンドでコンテナを停止、
docker rm コマンドでコンテナを削除する事ができます。

フロントエンドコンテナ削除前

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                    NAMES
7dbdb9b75c62   my-backend   "docker-entrypoint.s…"   7 seconds ago   Up 5 seconds             backend
b9ab79e88f2b   my-frontend   "/docker-entrypoint.…"   6 hours ago      Up 6 hours      0.0.0.0:80->80/tcp       frontend

frontend コンテナを削除していきます。

[root@con-test ~]# docker stop frontend
frontend
[root@con-test ~]# docker rm frontend
frontend

フロントエンドコンテナが削除された事を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE        COMMAND                   CREATED         STATUS         PORTS     NAMES
7dbdb9b75c62   my-backend   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes             backend

frontend コンテナが削除されている事を確認できました。

更新した Docker イメージからフロントエンドコンテナを起動させます。
frontend コンテナも my-network に接続させます。

[root@con-test ~]# docker run -d --name frontend --network my-network -p 80:80 my-frontend
85082f66015b375ffb68550e4e656269451ec8185988abc96ff39de2513de1ce

フロントエンドコンテナの起動を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED         STATUS         PORTS                NAMES
85082f66015b   my-frontend   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   0.0.0.0:80->80/tcp   frontend
7dbdb9b75c62   my-backend    "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes                        backend

frontend コンテナの STATUS が Up となっているので無事起動しています。

フロントエンド→バックエンドの通信が通るか動作確認を行います。

まず docker exec コマンドを使用して frontend コンテナに接続します。

[root@con-test ~]# docker exec -it frontend sh
/ #

次に frontend コンテナから backend コンテナに curl コマンドを叩いてみます。

/ # curl http://backend:3000/api/data
{"message":"Hello from Backend!"}/ #

「"Hello from Backend!"」が確認できたらOKです。

フロントエンド→バックエンドの接続が確認できたので、最後にDBコンテナを作成していきます。

DBコンテナ作成

DBコンテナ用にディレクトリを用意していきます。

[root@con-test ~]# mkdir /root/db

DB用の初期化スクリプト作成します。
このスクリプトを使用することで、MySQLのデータベースとテーブルの初期設定を自動化できます。

[root@con-test ~]# vim /root/db/init.sql

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE messages (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255));
INSERT INTO messages (message) VALUES ('Hello from MySQL!');

「CREATE DATABASE testdb;」
testdb というデータベースを作成しています。

「USE testdb;」
作成した testdb に接続しています。

「CREATE TABLE messages (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255));」
messages という名前のテーブルを作成して

「INSERT INTO messages (message) VALUES ('Hello from MySQL!');
テーブル messages に、"Hello from MySQL!" というメッセージを持つ1行のデータを挿入しています。
これでテスト用のデータベースとテーブルを用意されるようになります。

DBコンテナ用に Dockerfile を作成します。

[root@con-test ~]# vim /root/db/Dockerfile

FROM mysql:8
ENV MYSQL_ROOT_PASSWORD=password
COPY init.sql /docker-entrypoint-initdb.d/

「FROM mysql:8」
MySQL 8 をベースにした公式イメージを使用します。

「ENV MYSQL_ROOT_PASSWORD=password」
root用のパスワードに password を指定しています。

「COPY init.sql /docker-entrypoint-initdb.d/」
先程作成した init.sql をDBコンテナにコピーします。

DB用の Dockerfile が用意できたのでビルドしていきます。

[root@con-test ~]# docker build -t my-mysql /root/db
[+] Building 16.0s (7/7) FINISHED                                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                                              0.0s
 => => transferring dockerfile: 126B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/mysql:8                                                                        1.9s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => [internal] load build context                                                                                                 0.0s
 => => transferring context: 215B                                                                                                 0.0s
 => [1/2] FROM docker.io/library/mysql:8@sha256:106d5197fd8e4892980469ad42eb20f7a336bd81509aae4ee175d852f5cc4565                 13.6s
 => => resolve docker.io/library/mysql:8@sha256:106d5197fd8e4892980469ad42eb20f7a336bd81509aae4ee175d852f5cc4565                  0.0s
 => => sha256:6f5cca38a221c35a53694cce3b34887a1cf73335b1c53075114a140a99de0b93 885B / 885B                                        0.4s
 => => sha256:1ecf42d360987627bcf76572ba479f3b5b0a5391a125801617909cc56e7cb22e 2.85kB / 2.85kB                                    0.0s
 => => sha256:3818a28b4a67a9efab3547df8a292de847636d5903f7705d4ccbe1d281b20133 6.48kB / 6.48kB                                    0.0s
 => => sha256:d7c84b66ede077e0a8717528112591fbfd5f3ced4040c124eb6659b3c14940d4 983.00kB / 983.00kB                                0.2s
 => => sha256:106d5197fd8e4892980469ad42eb20f7a336bd81509aae4ee175d852f5cc4565 2.60kB / 2.60kB                                    0.0s
 => => sha256:2c0a233485c3a7b6cab556a9a9c2916ca9a3afc8c46097ddfbe0af4fe120a50c 49.10MB / 49.10MB                                  1.0s
 => => sha256:299f6f88c6cfd0fdcd8f375f1c26bdd1d4f04eded1587b11419b7f8ae0934d3b 6.90MB / 6.90MB                                    0.6s
 => => sha256:d39eae8f992719502e3a1d7552504b1acad7bf67f068af86e0dec581ddad018f 2.61kB / 2.61kB                                    0.6s
 => => sha256:ec0557361569a8ecbc29bb910b4bde5cdaad19c06a71ae771a273afa01543d28 334B / 334B                                        0.8s
 => => sha256:f6d0f80cb1bedb26d1fbd402a1b7788789ef10b76310425c826d463cdcc034e9 47.56MB / 47.56MB                                  1.4s
 => => sha256:d496030b710c9fcd2314de6c4b1e7921739e9552cf0338ebd4b51de517252e01 321B / 321B                                        1.1s
 => => sha256:4d755d8c89d19d65a71254593f2410f5bc54a1b5cb51b4763665bbfd08f05451 66.96MB / 66.96MB                                  2.1s
 => => extracting sha256:2c0a233485c3a7b6cab556a9a9c2916ca9a3afc8c46097ddfbe0af4fe120a50c                                         2.5s
 => => sha256:699d8e3dc44b682de3b43954ad50435abff0302f59f790cbe032bb70f7edc214 5.33kB / 5.33kB                                    1.3s
 => => extracting sha256:6f5cca38a221c35a53694cce3b34887a1cf73335b1c53075114a140a99de0b93                                         0.0s
 => => extracting sha256:d7c84b66ede077e0a8717528112591fbfd5f3ced4040c124eb6659b3c14940d4                                         0.0s
 => => extracting sha256:299f6f88c6cfd0fdcd8f375f1c26bdd1d4f04eded1587b11419b7f8ae0934d3b                                         0.3s
 => => extracting sha256:d39eae8f992719502e3a1d7552504b1acad7bf67f068af86e0dec581ddad018f                                         0.0s
 => => extracting sha256:ec0557361569a8ecbc29bb910b4bde5cdaad19c06a71ae771a273afa01543d28                                         0.0s
 => => extracting sha256:f6d0f80cb1bedb26d1fbd402a1b7788789ef10b76310425c826d463cdcc034e9                                         1.5s
 => => extracting sha256:d496030b710c9fcd2314de6c4b1e7921739e9552cf0338ebd4b51de517252e01                                         0.0s
 => => extracting sha256:4d755d8c89d19d65a71254593f2410f5bc54a1b5cb51b4763665bbfd08f05451                                         7.5s
 => => extracting sha256:699d8e3dc44b682de3b43954ad50435abff0302f59f790cbe032bb70f7edc214                                         0.0s
 => [2/2] COPY init.sql /docker-entrypoint-initdb.d/                                                                              0.4s
 => exporting to image                                                                                                            0.0s
 => => exporting layers                                                                                                           0.0s
 => => writing image sha256:7a8ebfb14f601a08fe2a2c2a0f385709b33edc078a1c354c6e3eb895d01cef0c                                      0.0s
 => => naming to docker.io/library/my-mysql                                                                                       0.0s

作成されたイメージを確認します。

[root@con-test ~]# docker images my-mysql
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
my-mysql     latest    7a8ebfb14f60   About a minute ago   594MB

イメージの作成が確認できたのでDBコンテナを作成していきます。
DBコンテナも my-network に接続させます。
これにより、フロントエンド、バックエンド、DBコンテナが全て同じネットワーク構成になります。

[root@con-test ~]# docker run -d --name db --network my-network -e MYSQL_ROOT_PASSWORD=password my-mysql
10e31206c40fade9b1cd4c43c68108b036a23002fc4a0b6473cab7657793c473

DBコンテナが作成された事を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                 NAMES
10e31206c40f   my-mysql      "docker-entrypoint.s…"   12 seconds ago   Up 11 seconds   3306/tcp, 33060/tcp   db
e9e426feb80f   my-backend    "docker-entrypoint.s…"   17 minutes ago   Up 17 minutes                         backend
85082f66015b   my-frontend   "/docker-entrypoint.…"   32 minutes ago   Up 32 minutes   0.0.0.0:80->80/tcp    frontend

折角なので作成したDBコンテナに入ってみます。

[root@con-test ~]# docker exec -it db mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.4.3 MySQL Community Server - GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

testdb の作成を確認して

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

testdb に接続します。

mysql> use testdb;
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

テスト用の messages テーブルが作成されている事を確認し

mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| messages         |
+------------------+
1 row in set (0.00 sec)

messages テーブルの中身も見てみます。

mysql> select * from messages;
+----+-------------------+
| id | message           |
+----+-------------------+
|  1 | Hello from MySQL! |
+----+-------------------+
1 row in set (0.00 sec)

「Hello from MySQL!」が確認できたらOKです。
確認できたら「Ctrl+D」で抜けます。

バックエンドコンテナ再作成

バックエンドからDBに接続させるため、バックエンドの app.js と Dockerfile を編集します。

バックエンド更新 app.js

[root@con-test ~]# vim /root/backend/app.js

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

// CORSを許可
app.use(cors());

const db = mysql.createConnection({
    host: 'db',
    user: 'root',
    password: 'password',
    database: 'testdb',
    waitForConnections: true,
    connectionLimit: 10, // 最大接続数
    queueLimit: 0
});

// データ取得用のAPIエンドポイント
app.get('/api/data', (req, res) => {
    db.query('SELECT message FROM messages LIMIT 1', (err, results) => {
        if (err) {
            console.error('Database query failed:', err);
            res.status(500).send('Database query failed');
            return;
        }
        res.json({ message: results[0].message });
    });
});

// サーバーを起動
app.listen(3000, () => {});

「app.use(cors());」
CORSエラーを防ぐため追加しています。

「const db = mysql.createConnection({ ~」
こちらでデータベースコンテナのホスト名やユーザ名など指定しています。

「app.get('/api/data', (req, res) => { ~」
こちらで /api/data にリクエストが来た際にDBコンテナから値を取得するようにしています。
詳細割愛させてもらえればと思います、コピペでOKです。

バックエンド用の Dockerfile を編集します。

[root@con-test ~]#vim /root/backend/Dockerfile

FROM node:16
WORKDIR /app
COPY . .
RUN npm install express mysql2 cors
RUN apt-get update && apt-get install -y default-mysql-client
CMD ["node", "app.js"]

mysql2,cors ライブラリを追加して、MySQLクライアントツールをインストールするように更新しています。

ファイルを更新できたのでバックエンドの再ビルドを行います。

[root@con-test ~]# docker build -t my-backend /root/backend/
[+] Building 14.1s (10/10) FINISHED                                                                                     docker:default
 => [internal] load build definition from Dockerfile                                                                              0.0s
 => => transferring dockerfile: 196B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/node:16                                                                        1.1s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => [1/5] FROM docker.io/library/node:16@sha256:f77a1aef2da8d83e45ec990f45df50f1a286c5fe8bbfb8c6e4246c6389705c0b                  0.0s
 => [internal] load build context                                                                                                 0.0s
 => => transferring context: 1.05kB                                                                                               0.0s
 => CACHED [2/5] WORKDIR /app                                                                                                     0.0s
 => [3/5] COPY . .                                                                                                                0.0s
 => [4/5] RUN npm install express mysql2 cors                                                                                     4.4s
 => [5/5] RUN apt-get update && apt-get install -y default-mysql-client                                                           7.8s
 => exporting to image                                                                                                            0.6s
 => => exporting layers                                                                                                           0.5s
 => => writing image sha256:14250946b34e7de953912c7eea2edd497b16f124053c1b04335a8c58b8c2c511                                      0.0s
 => => naming to docker.io/library/my-backend                                                                                     0.0s

バックエンドコンテナの再作成を行うため、起動中のバックエンドコンテナを削除します。

[root@con-test ~]# docker stop backend
backend
[root@con-test ~]# docker rm backend
backend

バックエンドコンテナの削除を確認します。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                 NAMES
10e31206c40f   my-mysql      "docker-entrypoint.s…"   15 minutes ago   Up 15 minutes   3306/tcp, 33060/tcp   db
85082f66015b   my-frontend   "/docker-entrypoint.…"   47 minutes ago   Up 47 minutes   0.0.0.0:80->80/tcp    frontend

バックエンドコンテナを起動させます。

[root@con-test ~]# docker run -d --name backend --network my-network -p 3000:3000 my-backend
cf4b68392045963b8f339d15ef8d068df7acfb7fe099eed2fddfee7e0bc00f3f

これで、フロントエンド、バックエンド、DBコンテナが起動されている状態になりました。

[root@con-test ~]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                 NAMES
cf4b68392045   my-backend    "docker-entrypoint.s…"   32 seconds ago   Up 32 seconds                         backend
10e31206c40f   my-mysql      "docker-entrypoint.s…"   19 minutes ago   Up 19 minutes   3306/tcp, 33060/tcp   db
85082f66015b   my-frontend   "/docker-entrypoint.…"   50 minutes ago   Up 50 minutes   0.0.0.0:80->80/tcp    frontend

動作確認

サーバ上でフロントエンド→バックエンド→DBで接続できるか試してみます。

フロントエンド→バックエンド

フロントエンドに接続して

[root@con-test ~]# docker exec -it frontend sh
/ #

バックエンドに対して curl コマンドを叩きます。

/ # curl http://backend:3000/api/data
{"message":"Hello from MySQL!"}/ #

この時点で Hello from MySQL! が表示されてますが念のためバックエンド→DBも試していきます。
「Ctrl+D」で抜けます。

バックエンド→DB

バックエンドに接続して

[root@con-test ~]# docker exec -it backend bash
root@cf4b68392045:/app#

mysqlにログインします。

root@cf4b68392045:/app# mysql -h db -uroot -ppassword
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.4.3 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>

無事接続確認できました、「Ctrl+D」で抜けます。

最後に、ブラウザ上からフロントエンド→バックエンド→DBコンテナの連携を確認します。
ブラウザで http://<EC2のパブリックIP> にアクセスし、「Data from backend: Hello from MySQL!」が表示されれば成功です。

②DB動作確認
②DB動作確認

お疲れ様でした。
以上で、フロントエンド→バックエンド→DBコンテナを連携させる事ができました。

今回は、実際にコンテナを作成したり削除する事でコンテナが構成される流れや
コンテナならではの「起動の速さ」や「軽量で扱いやすい特長」を体感することができました。

この記事がエンジニア初学者の参考になれば幸いです。
ここまでお付き合いいただき、誠にありがとうございました。

引き続き、アドベントカレンダーをお楽しみください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA