Lightsailを構成するAWSサービスを考えてみた。

Amazon Lightsail は一般的なVPSサーバー(Virtual Private Server)であると思うのですが、構成としてはいくつかのAWSサービスをパッケージ化して提供しているものなのだと思います。どんなサービスで構成されているのかを考えてみました。なお、推測で書いておりますので、その点はご容赦ください。

Lightsailの構成を図にしてみると、こうなると思います。

メインはEC2(Elastic Compute Cloud)とEBS(Elastic Block Store)です。仮想サーバーはEC2で、ストレージはEBSを使用します。AZはアベイラビリティゾーンの略ですが、Lightsailのインスタンスは1つのAZにのみ作成とのことなので、冗長化という点では弱いです。

また、インターネットとの通信もできるのでIGW(インターネットゲートウェイ)があります。

ネットワークですが、これはVPC(Virtual Private Cloud)での制御になります。VPC内のサブネットは1つだけで、そのサブネットにデフォルトルートがIGWとなったルートテーブルが関連付けされています。このルートテーブルはメインとは別のものではないかと思います。

上記の図ではIPアドレスの記載をはしなかったのですが、VPCは /16 で作成して、その中に /20 のサブネットを作成した場合、ネットワーク的にはこんな感じになります。/24 のサブネットのほうがわかりやすいのですが、僕が利用しているLightsailが /20 のようでしたのであわせました。。

プライベートIPアドレスの他にパブリックIPアドレス(グローバルIPアドレス)があるのですが、これはIGWが持つものなのかもしれません。このあたりは不明瞭です。裏の仕組みはわからないのですが、このパブリックIPアドレスをEC2インスタンスにアタッチするとインターネットとの通信が可能になります。

この他にLightsailではファイアーウォールの機能があるのですが、これはセキュリティグループの機能が使われています。

DNS管理ですが、Lightsailで提供されるDNSサーバーに名前解決を委任すれば(ISP側のDNSサーバーにNSレコードを登録する必要があります)サブドメインでの運用ができます。

スナップショットもLightsailでは利用できます。スナップショットはS3(Simple Storage Service)を利用して複数のAZの複数の施設にバックアップをするのですが、LightsailではAZは1つなので別のAZにバックアップを作成するのかは不明です。なおスナップショットは課金の対象(1GB/月あたり0.05 USDかかる)になります。

AWSのEC2は停止していれば料金はかからないのですが、Lightsailの場合は停止していても料金が発生するので注意しましょう。

データ転送の従量制の料金ですが、インバウンドとアウトバウンドの両方のデータ転送が無料のデータ転送枠にカウントされます。データ転送枠の上限を超えた場合、アウトバウンドデータ転送のみが超過分として課金対象になります。AWSではAZ間の転送も従量課金の対象ですが、LightsailではAZ間の転送が発生しないのでアウトバウンドのみが課金になります。

Javaのrequest.getSession(false); がなぜかnullになってしまう。

JavaでServletプログラムを作成していてセッションを使っていたのですが、なぜか request.getSession(false); がnullになってしまう事象にあいました。

初回アクセス時
HttpSession session = request.getSession( true );

二回目以降
HttpSession session = request.getSession( false );

session.getAttribute("xxx"); でセッション属性を取得したいのだけれど、sessionがnullのため取得できない。。アレコレ悩みました。

今回のウェブサーバーは Nginx + Tomcat の構成(同一サーバーに相乗り)なのですが、Nginxの proxy_pass ディレクティブでTomcatへの転送先URLを指定しています。

proxy_pass http://localhost:8080/test/;

末尾の /test/ はウェブアプリケーションのコンテキストパスです。実際にServletにアクセスするURLは、以下のようにしています。

http://tomcat/sample/fwservlet

URL中の tomcat がドメインで fwservlet はServlet名です。Nginxを介さずに直接Tomcatにアクセスする場合は、このようになります(localhost はIPアドレスに読み替えてください)。

http://localhost:8080/test/sample/fwservlet

ここでNginxに向けてリクエストをするとダメなのだけれど、直接Tomcatに向けてリクエストをするとうまくいくことに気づきました。原因はNginxにあるのか?と思いつつも、Firefoxのデバッグモードでクッキーを見てみました。リクエストはNginxに向けて投げています。

これを見るとクッキーには JSESSIONID が設定されていることが確認できました。なので初回アクセス時に新規セッションは問題なく作成されているようです。そうすると、なぜ二回目以降のアクセスでこのセッションが取得できないのか?になるのですが、クッキーのPath属性を見ると /test となっています。

Path属性は「送信するURLにここで指定するパスが含まれている場合のみクッキーが送信される」ということになるのですが、Nginx向けのリクエストURLには /test はないです。直接Tomcatに向ける場合は含まれています。つまり、Nginxに向けて投げた場合、クッキーが送信されていないから request.getSession( false ); で JSESSIONID が取得できず、nullになってしまっていることがわかりました。

この解決策ですが、/test/ のコンテキストパスを変えるのはいまさらだとインパクトが大きい。なので web.xml のサーブレットマッピングをいじることで対応しました。リクエストURLに強引に /test のパスを含めるようなやり方です。

こんな感じです。


<servlet>
    <servlet-name>fwservlet</servlet-name>
    <servlet-class>sample.fwservlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>fwservlet</servlet-name>
    <url-pattern>/test/fwservlet</url-pattern>
</servlet-mapping>

JSPも同様に対応します。


<servlet>
    <servlet-name>nolist</servlet-name>
    <jsp-file>/sample/nolist.jsp</jsp-file>
</servlet>
<servlet-mapping>
    <servlet-name>nolist</servlet-name>
    <url-pattern>/test/nolist.jsp</url-pattern>
</servlet-mapping>

この設定をするとNginxへのリクエストURLは以下のように変わります。

http://tomcat/test/fwservlet

これでServletを動かすと request.getSession( false ); でセッションを取得することができるようになりました。