0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Windows】Virtualbox上のCentOSにDockerでNginxを立てExpressにアクセスした時のネットワークを図解してみた

Last updated at Posted at 2022-10-05

はじめに

アプリケーションの開発は普段やっているが、その際にはあまりインフラに関しては意識しないで開発している事が多かった。今回は少しネットワークがどうなっているか?が気になって図解してみたので、その備忘録を残す(理解に誤り等があればご指摘いただけると幸いです)。

ネットワークの基本的な概念

いきなりどのようなネットワークになっているのか?を見ていく前に、ネットワークに関する重要そうな概念について理解を深めてみた。

IPアドレス(IPv4)

ネットワーク内の住所。ネットワーク機器やPCなどネットワークにつながっている端末の場所を特定するための値。グローバルIPとプライベートIPがある。

表記は192.168.56.2のように10進数表記で4つの区切りで示される。コンピュータ内では2進数として扱われている。
image.png

サブネットマスク

ネットワークの範囲を定義するために使用する値。ネットワークを示す際にはこのサブネットマスクをIPアドレスとくっつけた表記がされる。具体的には、

192.168.56.2/24

のようにIPアドレス+サブネットマスクのような表記で、これをCIDR表記という。

サブネットマスクはネットワークの範囲(サブネット)を指定するためのものだが、仕組みとしては以下の図の通りで、ネットワーク部(同一ネットワーク内で固定で同じになるIPアドレスの部分)とホスト部(ネットワーク内で端末などでそれぞれ異なる値になるIPアドレスの部分)がどこになるか?を数値で表現するものになる。
image.png

なので上記の図のように、192.168.56.0/24というCIDRの場合、IPアドレスを2進数で表記した時の左から24桁(bit)分は固定部=ネットワーク部になり、可変部=ホスト部は2進数の残りの8桁(bit)分になる。つまり2の8乗=256パターンのIPアドレスを指定できるネットワーク、という事になる。ただし、192.168.56.0と192.168.56.255はそれぞれネットワークアドレス・ブロードキャストアドレスになるので使用できず、実際に使えるIPの範囲は1~254の254通りになる(2^8-2=254)。

サブネットマスクでよく見るのは、以下の3パターン。

CIDR形式 IPアドレス形式 IPアドレス形式を2進数にすると
/8 255.0.0.0 11111111 00000000 00000000 00000000
/16 255.255.0.0 11111111 11111111 00000000 00000000
/24 255.255.255.0 11111111 11111111 11111111 00000000

※サブネットをIPアドレス形式で書く場合、1になっている部分がサブネットマスクを意味するので上記の表のようなアドレスになる。もし/1なら10000000 ...(0が24個)なので10進数表記をするなら128.0.0.0というサブネットマスクになる。

サブネットを作成する具体的な場面としては、インターネットからアクセスできるパブリックなサブネットと、インターネットからアクセスできないプライベートなサブネットを作成することで、プライベートなネットワーク(サブネット)はセキュリティが高いというような状態が作れる事(役割をネットワークごとに区切る)。サブネットが違うネットワークは直接通信できないので、ルーターやネットワーク機器を使用してネットワークを切り替えて通信する必要がある。

AWSだと以下のような形で、VPC内にパブリックサブネットとプライベートサブネットがある構成がよく見られるだろう(パブリックサブネットaはIP10.0.1.1~10.0.1.254までの254通りのIPを持つサブネットで、プライベートサブネットaはIP10.0.2.1~10.0.2.254までの254通りのIPを持つサブネット)。
image.png

※サブネットというとサブのネットという意味で、VPCを作成する時にVPC自体はサブじゃなくね?となったが、VPCそのものもサブネットという言い方をし、VPC内にサブネットマスクで新しく区切って定義したネットワークもサブネットという言い方をするみたい。

ローカル環境の全体構成のイメージ

image.png

実際のアクセスの経路

起点はブラウザ(Chrome)で、終点はNode.js Expressのアプリケーションサーバー。その経路としては、

  1. Chrome
  2. Virtualbox内のDockerで立っているNignx
  3. Virtualbox内のNode.js Express

という経路になる。

実際に上記の経路でアクセスした際のは以下の図の通り。

  1. Chrome
    image.png
  2. Nginx
    image.png
  3. Express
    image.png

以下では上記の経路の詳細を見ていきたいと思う。

アクセスの経路を詳細に追っていく

Chrome → Nignx

まず、https://example.com/というパスでアクセスしていたが、example.comというドメインは実際には存在しないドメイン。今回はWindowsのhostsファイルを利用して、なんちゃってDNSを利用してIPアドレスを解決している。

ファイルの中身は以下のようになっている(一部抜粋)。

user@DESKTOP-PS112J6 MINGW64 ~
$ cat /c/Windows/System32/drivers/etc/hosts
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
...

# localhost name resolution is handled within DNS itself.
#       127.0.0.1       localhost
#       ::1             localhost

192.168.56.2       example.com

続いて192.168.56.2というIPアドレスが何者か?だが、VirtualBox上でip addrコマンドを実行すると分かる。

study@localhost:~/workspace/openid-connect (aws-iam-federation *)
$ ip addr
...
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:b1:62:72 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.2/24 brd 192.168.56.255 scope global noprefixroute enp0s8
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:feb1:6272/64 scope link 
       valid_lft forever preferred_lft forever
...

192.168.56.2/24というのがあるが、上記のサブネットマスクで見たように、これはCIDR表記のIPアドレスで、192.168.56.0~192.168.56.255というIPアドレスの範囲のサブネット(192.168.56.0/24というサブネット)に属している1つのアドレス。では192.168.56.0/24というサブネットはどこから出てきたのか?(誰が作った者なのか?)という疑問が出てくるが、これはVirtualBoxのホストオンリーアダプターによって作成されたものになる(以下の図を参照)。
image.png

まず、IPアドレスのルール同様、192.168.56.0と192.168.56.255はそれぞれネットワークアドレス・ブロードキャストアドレスであり、利用できない。なので、実際に192.168.56.0/24というサブネットで利用可能なIPアドレスは192.168.56.1~192.168.56.254までになる。

そして、ホストオンリーアダプターとはホストOS(Windows)→ゲストOS(VirtualBox上のCentOS)との通信を可能にするもので、やっている事はどうやらゲストOSとホストOSを共通のネットワーク(今回だと192.168.56.0/24)に属させるというものと考えていいだろう(ホストOSと接続するにはホストオンリーアダプターを使うを参照)。そのゲストOS・ホストOS両方が属するネットワーク=ホストOSの方でもIPアドレスが割り振られる、という事になるがそのIPアドレスが192.168.56.1というものになる。

それは実際にWindows上のcmdでipconfigコマンドを実行すると確かめられる。

windowsのcmd
C:\Users\user>ipconfig

Windows IP 構成

...

イーサネット アダプター VirtualBox Host-Only Network:

   接続固有の DNS サフィックス . . . . .:
   リンクローカル IPv6 アドレス. . . . .: fe80::e186:8563:7ab9:2c23%20
   IPv4 アドレス . . . . . . . . . . . .: 192.168.56.1
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .:

...

192.168.56.2の方の正体についてはまだ触れていなかったが、これはゲストOS(CentOS)に割り振られた192.168.56.0/24内のIPアドレス。

つまり、192.168.56.0/24内には以下の2つのIPアドレスを持つ機器が接続されているのと同じ状態になっている。
image.png

したがって、Chrome → Nignxとアクセスする時には、IPアドレスでアクセス経路を見ると、

  • Chrome = Windows = ホストOS = 192.168.56.1 → Nignx = VirtualboxのCentOS = 192.168.56.2

というアクセスになる。そのため、実際のアクセスの経路で見たNignxのアクセスログの方に192.168.56.1というのが出力されていた。

Nignx

今回はDockerのNginxをdocker composeで立てていたが、DockerはDockerで独自のネットワークを持つ。が、今回はdocker-compose.yamlの方でportsを指定しているので、DockerのネットワークとCentOSのネットワークで通信できるようになっており、利用時には特に気にしないでいいようになっている。

docker-compose.yaml
version: '3.9'
services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - 443:443
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx

上記のように設定すると、公式のShort syntaxに以下のように記載されている通り、ホスト(CentOS)のあらゆるIP(127.0.0.1など)からDockerのネットワーク内のポート443(Nginx)にアクセスする事ができるので、ChromeからNignxにアクセスする際、example.com(httpsのデフォルトのポートは443なので省略されている) → 192.168.56.2:443 → 0.0.0.0:443 → Docker内のNginxという経路でアクセスできている。

Specify the host IP address to bind to AND both ports (the default is 0.0.0.0, meaning all interfaces): (IPADDR:HOSTPORT:CONTAINERPORT). If HOSTPORT is empty (for example 127.0.0.1::80), an ephemeral port is chosen to bind to on the host. (両方のポートにバインドするホストIPアドレスを指定します(デフォルトは0.0.0.0、つまりすべてのインターフェイスを意味します)。(ipaddr:hostport:containerport) を指定します。HOSTPORT が空の場合 (たとえば 127.0.0.1::80) は、そのホストのエフェメラルポートがバインド先として選択されます。)

ちなみに、DockerのNginxのIPアドレスは以下のように確かめられる。

study@localhost:~/workspace/openid-connect (aws-iam-federation *)
$ docker container exec -it nginx /bin/sh
# hostname -I
172.19.0.2 

Nginx → Node.js Express(アプリケーションサーバー)

この経路はいわゆるリバースプロキシと呼ばれる部分で、Nginxに来たアクセスをNginxの設定(nginx.conf)の設定でプロキシ(他の所に中継)する事でExpressというアプリケーションサーバーへのアクセスが実現されている部分。

Nginxの設定の中身は以下のようになっている(locationディレクティブの設定は一部省略している)。

nginx.conf
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/nginx/conf.d/ssl/server.crt;
    ssl_certificate_key /etc/nginx/conf.d/ssl/server.key;

    location / {
        # 省略
        proxy_pass http://192.168.56.2:3000;
    }

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
}

proxy_passというディレクティブがポイントで、これによりNginxに来たアクセス(リクエスト)はNginxを中継してhttp://192.168.56.2:3000というIP・ポートに届くようになる。

経路のまとめ

上記の詳細を踏まえて全体の流れを整理すると、結局Chromeからのリクエストは以下のようにしてExpress(アプリケーションサーバー)に届いていたという事が分かる。

  1. Chrome:example.comにアクセス(ポートはhttpsデフォルトの443)
  2. Windows:hostsファイルのDNSで192.168.56.2にアクセス(ポートは443)
  3. VirtualBox:ホストオンリーアダプターのネットワーク内の192.168.56.1→192.168.56.2へのアクセス
  4. CentOS:192.168.56.2:443へのアクセスは、Dockerのネットワークに中継されて、Dockerのネットワーク上に存在するNginxへアクセス
  5. Nignx:プロキシの設定により自身に来たアクセスを中継し、192.168.56.2:3000にアクセス
  6. Express:最終的にアクセス(リクエスト)が届く

まとめとして

今回、普段あまり意識していないネットワーク(インフラの側面)についてアプリケーションエンジニアとして理解を深めてみて、色々な仕組みでアプリケーションサーバーにリクエストが届くようになっているんだなとしみじみ思った。本番環境だともっと複雑になると思うが、これをきっかけにインフラ面も理解を深めていきたいと思った。

上記の構成で実際に設定したコードは以下。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?