Ubuntu16.04でLXDを使用してNginxとHAProxyで複数のWebサイトをホストする方法

提供:Dev Guides
移動先:案内検索

序章

Linuxコンテナは、名前空間やコントロールグループなどのLinuxカーネルセキュリティ機能を使用して、システムの他の部分から分離されたプロセスのグループです。 これは仮想マシンに似た構造ですが、はるかに軽量です。 追加のカーネルを実行したり、ハードウェアをシミュレートしたりするオーバーヘッドはありません。 これは、同じサーバー上に複数のコンテナーを簡単に作成できることを意味します。 Linuxコンテナーを使用すると、オペレーティングシステム全体の複数のインスタンスを同じサーバー上で制限して実行したり、システムの他の部分に影響を与えることなく、アプリケーションとその依存関係をコンテナーにバンドルしたりできます。

たとえば、サーバーがあり、クライアント用にWebサイトを含むいくつかのサービスを設定しているとします。 従来のインストールでは、各WebサイトはApacheまたはNginxWebサーバーの同じインスタンスの仮想ホストになります。 ただし、Linuxコンテナーでは、各Webサイトは独自のWebサーバーを備えた独自のコンテナーで構成されます。

LXD を使用して、これらのコンテナーを作成および管理できます。 LXDは、コンテナーのライフサイクル全体を管理するハイパーバイザーサービスを提供します。

このチュートリアルでは、LXDを使用して、同じサーバーに2つのNginxベースのWebサイトをインストールし、それぞれが独自のコンテナーに限定されます。 次に、リバースプロキシとして機能する3番目のコンテナにHAProxyをインストールします。 次に、インターネットから両方のWebサイトにアクセスできるようにするために、トラフィックをHAProxyコンテナにルーティングします。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • チュートリアルUbuntu16.04を使用した初期サーバーセットアップに従って構成された1つのUbuntu16.04サーバー、sudo非rootユーザーとファイアウォール。
  • 2つの完全修飾ドメイン名(FQDN)。各DNS AレコードはサーバーのIPアドレスを指しています。 これを構成するには、チュートリアルDigitalOceanを使用してホスト名を設定する方法に従ってください。
  • 必要に応じて、チュートリアル DigitalOceanブロックストレージ入門に従って、20GB以上のブロックストレージを追加します。 これを使用して、コンテナに関連するすべてのデータを保存できます。

ステップ1—ユーザーをlxdグループに追加する

root以外のユーザーアカウントを使用してサーバーにログインします。 この非ユーザーアカウントを使用して、すべてのコンテナ管理タスクを実行します。 これを機能させるには、最初にこのユーザーをlxdグループに追加する必要があります。 次のコマンドでこれを行います。

sudo usermod --append --groups lxd sammy

サーバーからログアウトして再度ログインすると、新しいSSHセッションが新しいグループメンバーシップで更新されます。 ログインすると、LXDの構成を開始できます。

ステップ2—LXDの構成

LXDを使用するには、適切に構成する必要があります。 最も重要な構成の決定は、コンテナーを格納するためのストレージバックエンドのタイプです。 LXDに推奨されるストレージバックエンドはZFSファイルシステムであり、事前に割り当てられたファイルに保存されるか、 BlockStorageを使用して保存されます。 LXDでZFSサポートを使用するには、zfsutils-linuxパッケージをインストールします。

sudo apt-get update
sudo apt-get install zfsutils-linux

これをインストールすると、LXDを初期化する準備が整います。 初期化中に、ZFSストレージバックエンドの詳細を指定するように求められます。 事前に割り当てられたファイルを使用するか、ストレージをブロックするかによって、次の2つのセクションがあります。 ケースに適した手順に従ってください。 ストレージメカニズムを指定したら、コンテナのネットワークオプションを構成します。

オプション1-事前に割り当てられたファイルを使用する

以下の手順に従って、事前に割り当てられたファイルを使用してコンテナーを保管するようにLXDを構成します。 まず、次のコマンドを実行して、LXD初期化プロセスを開始します。

sudo lxd init

次の出力に示すように、いくつかの情報を入力するように求められます。 ループデバイスと呼ばれる、事前に割り当てられたファイルの推奨サイズを含む、すべてのデフォルトを選択します。

OutputName of the storage backend to use (dir or zfs) [default=zfs]: zfs
Create a new ZFS pool (yes/no) [default=yes]? yes
Name of the new ZFS pool [default=lxd]: lxd
Would you like to use an existing block device (yes/no) [default=no]? no
Size in GB of the new loop device (1GB minimum) [default=15]: 15
Would you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes
Warning: Stopping lxd.service, but it can still be activated by:
  lxd.socket
LXD has been successfully configured.

推奨サイズは、サーバーの使用可能なディスク容量から自動的に計算されます。

デバイスを構成したら、ネットワーク設定を構成します。これについては、次のオプションのセクションで説明します。

オプション2–ブロックストレージの使用

ブロックストレージを使用する場合は、LXDの構成で指定するために、作成したブロックストレージボリュームを指すデバイスを見つける必要があります。 DigitalOceanコントロールペインlのVolumesタブに移動し、ボリュームを見つけて、 More ポップアップをクリックし、Configをクリックします。指示

ボリュームをフォーマットするコマンドを見て、デバイスを見つけます。 具体的には、sudo mkfs.ext4 -Fコマンドで指定されたパスを探します。 次の図は、ボリュームの例を示しています。 下線が引かれている部分だけが必要です。

この場合、ボリューム名は/dev/disk/by-id/scsi-0D0_Volume_volume-fra1-01ですが、異なる場合があります。

ボリュームを特定したら、端末に戻り、次のコマンドを発行してLXD初期化プロセスを開始します。

sudo lxd init

一連の質問が表示されます。 次の出力に示すように、質問に答えてください。

OutputName of the storage backend to use (dir or zfs) [default=zfs]: zfs
Create a new ZFS pool (yes/no) [default=yes]? yes
Name of the new ZFS pool [default=lxd]: lxd

既存のブロックデバイスの使用についてプロンプトが表示されたら、yesを選択し、デバイスへのパスを指定します。

Output of the "lxd init" commandWould you like to use an existing block device (yes/no) [default=no]? yes
Path to the existing block device: /dev/disk/by-id/scsi-0DO_Volume_volume-fra1-01

次に、残りの質問にデフォルト値を使用します。

Output of the "lxd init" commandWould you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes
Warning: Stopping lxd.service, but it can still be activated by:
  lxd.socket
LXD has been successfully configured.

プロセスが完了したら、ネットワークを構成します。

ネットワーキングの構成

初期化プロセスでは、次の図のような一連の画面が表示されます。これらの画面では、コンテナのネットワークブリッジを構成して、コンテナがプライベートIPアドレスを取得し、相互に通信し、インターネットにアクセスできるようにします。

各オプションにはデフォルト値を使用しますが、IPv6ネットワーキングについて尋ねられた場合は、このチュートリアルでは使用しないため、いいえを選択します。

ネットワーク構成が完了すると、コンテナを作成する準備が整います。

ステップ3—コンテナの作成

LXDの構成に成功しました。 ストレージバックエンドの場所を指定し、新しく作成されたコンテナのデフォルトのネットワークを構成しました。 lxcコマンドを使用して、いくつかのコンテナーを作成および管理する準備が整いました。

インストールされている利用可能なコンテナを一覧表示する最初のコマンドを試してみましょう。

lxc list

次の出力が表示されます。

Output of the "lxd list" commandGenerating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init
To start your first container, try: lxc launch ubuntu:16.04

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

lxcコマンドがLXDハイパーバイザーと通信するのはこれが初めてであるため、出力は、コマンドがLXDとの安全な通信のためにクライアント証明書を自動的に作成したことを示します。 次に、コンテナを起動する方法に関する情報が表示されます。 最後に、コマンドはコンテナの空のリストを表示します。これは、まだ作成していないために予想されます。

3つのコンテナを作成しましょう。 Webサーバーごとに1つ作成し、リバースプロキシ用に3つ目のコンテナーを作成します。 リバースプロキシの目的は、インターネットからの着信接続をコンテナ内の正しいWebサーバーに転送することです。

lxc launchコマンドを使用して、web1という名前のUbuntu16.04(ubuntu:x)コンテナーを作成して起動します。 ubuntu:xxは、Ubuntu16.04のコードネームであるXenialの最初の文字のショートカットです。 ubuntu:は、LXDイメージの事前構成されたリポジトリーの識別子です。

lxc image list ubuntu:を実行すると、利用可能なすべてのUbuntuイメージの完全なリストを見つけることができ、lxc image list images:を実行すると他のディストリビューションを見つけることができます。


次のコマンドを実行して、コンテナを作成します。

lxc launch ubuntu:x web1
lxc launch ubuntu:x web2
lxc launch ubuntu:x haproxy

コンテナを作成するのはこれが初めてなので、最初のコマンドはインターネットからコンテナイメージをダウンロードし、ローカルにキャッシュします。 次の2つのコンテナは、大幅に高速に作成されます。

ここでは、コンテナweb1の作成からのサンプル出力を見ることができます。

OutputCreating web1
Retrieving image: 100%
Starting web1

3つの空のバニラコンテナを作成したので、lxc listコマンドを使用してそれらに関する情報を表示しましょう。

lxc list

出力には、各コンテナーの名前、現在の状態、IPアドレス、タイプ、およびスナップショットが作成されているかどうかを示すテーブルが表示されます。

出力

+---------+---------+-----------------------+------+------------+-----------+
|  NAME   |  STATE  |         IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| haproxy | RUNNING | 10.10.10.10 (eth0)    |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web1    | RUNNING | 10.10.10.100 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web2    | RUNNING | 10.10.10.200 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+

コンテナ名とそれに対応するIPv4アドレスをメモします。 サービスを構成するためにそれらが必要になります。

ステップ4—Nginxコンテナを構成する

web1コンテナーに接続して、最初のWebサーバーを構成しましょう。

接続するには、lxc execコマンドを使用します。このコマンドは、コンテナーの名前と実行するコマンドを取得します。 次のコマンドを実行して、コンテナに接続します。

lxc exec web1 -- sudo --login --user ubuntu

--文字列は、lxcのコマンドパラメータがそこで停止し、残りの行がコンテナ内で実行されるコマンドとして渡されることを示します。 コマンドはsudo --login --user ubuntuで、コンテナー内の事前構成されたアカウントubuntuのログインシェルを提供します。

注: root としてコンテナーに接続する必要がある場合は、代わりにコマンドlxc exec web1 -- /bin/bashを使用できます。


コンテナ内に入ると、シェルプロンプトは次のようになります。

Outputubuntu@web1:~$

コンテナ内のこのubuntuユーザーは、sudoアクセスを事前設定しており、パスワードを指定せずにsudoコマンドを実行できます。 このシェルは、コンテナの範囲内に制限されています。 このシェルで実行するものはすべてコンテナーに残り、ホストサーバーにエスケープできません。

コンテナ内のUbuntuインスタンスのパッケージリストを更新して、Nginxをインストールしましょう。

sudo apt-get update
sudo apt-get install nginx

このサイトのデフォルトのWebページを編集して、このサイトがweb1コンテナでホストされていることを明確にするテキストを追加してみましょう。 ファイル/var/www/html/index.nginx-debian.htmlを開きます。

sudo nano /var/www/html/index.nginx-debian.html

ファイルに次の変更を加えます。

編集されたファイル/var/www/html/index.nginx-debian.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx on LXD container web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

ファイルを2か所で編集し、特にon LXD container web1というテキストを追加しました。 ファイルを保存して、エディターを終了します。

次に、コンテナからログアウトして、ホストサーバーに戻ります。

logout

web2コンテナに対してこの手順を繰り返します。 ログインしてNginxをインストールし、ファイル/var/www/html/index.nginx-debian.htmlを編集してweb2に言及します。 次に、web2コンテナを終了します。

curlを使用して、コンテナー内のWebサーバーが機能していることをテストしてみましょう。 前に示したWebコンテナのIPアドレスが必要です。

curl http://10.10.10.100/

出力は次のようになります。

Output of "curl http://10.10.10.100/" command<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx on LXD container web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

curlコマンドとそのIPアドレスを使用して、2番目のコンテナーもテストし、正しくセットアップされていることを確認します。 両方のコンテナを設定したら、HAProxyの設定に進むことができます。

ステップ5—HAProxyコンテナを設定する

これらのコンテナの前にプロキシとしてHAProxyを設定します。 これがどのように機能するかについてさらに背景が必要な場合は、チュートリアルHAProxyと負荷分散の概念の概要を確認してください。 使用するドメイン名に基づいて、トラフィックを各コンテナに転送します。 次の構成例では、ドメインexample.comを使用します。これは、このチュートリアルのようなドキュメント用の特別予約ドメインです。 ホスト名example.comおよびwww.example.comで最初のWebサイトを利用できるようにします。 2番目のWebサイトはwww2.example.comになります。 これらのドメイン名の代わりに独自のドメイン名を使用してください。

haproxyコンテナにログインします。

lxc exec haproxy -- sudo --login --user ubuntu

インストールパッケージのリストを更新し、HAProxyをインストールします。

sudo apt-get update
sudo apt-get install haproxy

インストールが完了したら、HAProxyを設定できます。 HAProxyの設定ファイルは/etc/haproxy/haproxy.cfgにあります。 お気に入りのテキストエディタでファイルを開きます。

sudo nano /etc/haproxy/haproxy.cfg

まず、defaultsセクションにいくつかの変更を加えます。 forwardforオプションを追加して、Webクライアントの実際のソースIPを保持し、http-server-closeオプションを追加して、セッションの再利用と待ち時間の短縮を可能にします。

/etc/haproxy/haproxy.conf

global
...
defaults
    log global
    mode    http
    option  httplog
    option  dontlognull
    option    forwardfor
    option    http-server-close
    timeout connect 5000
    timeout client  50000
    timeout server  50000
...

次に、2つのバックエンドコンテナを指すようにフロントエンドを構成します。 次のようなwww_frontendという新しいfrontendセクションを追加します。

/etc/haproxy/haproxy.conf

frontend www_frontend
    bind *:80      # Bind to port 80 (www) on the container

    # It matches if the HTTP Host: field mentions any of the hostnames (after the '-i').
    acl host_web1 hdr(host) -i example.com www.example.com
    acl host_web2 hdr(host) -i web2.example.com

    # Redirect the connection to the proper server cluster, depending on the match.
    use_backend web1_cluster if host_web1
    use_backend web2_cluster if host_web2

aclコマンドは、Webサーバーのホスト名と一致し、要求を対応するbackendセクションにリダイレクトします。

次に、Webサーバーごとに1つずつ、2つの新しいbackendセクションを定義し、それぞれweb1_clusterweb2_clusterという名前を付けます。 次のコードをファイルに追加して、バックエンドを定義します。

/etc/haproxy/haproxy.conf

backend web1_cluster
    balance leastconn
    # We set the X-Client-IP HTTP header. This is useful if we want the web server to know the real client IP.
    http-request set-header X-Client-IP %[src]
    # This backend, named here "web1", directs to container "web1.lxd" (hostname).
    server web1 web1.lxd:80 check

backend web2_cluster
    balance leastconn
    http-request set-header X-Client-IP %[src]
    server web2 web2.lxd:80 check

balanceオプションは、負荷分散戦略を示します。 この場合、接続数を最小限に抑えます。 http-requestオプションは、実際のWebクライアントIPでHTTPヘッダーを設定します。 このヘッダーを設定しなかった場合、Webサーバーはすべての接続の送信元IPとしてHAProxy IPアドレスを記録するため、トラフィックの発信元を分析することがより困難になります。 serverオプションは、サーバーの任意の名前(web1)を指定し、その後にサーバーのホスト名とポートを指定します…

LXDはコンテナにDNSサーバーを提供するため、web1.lxdweb1コンテナに関連付けられたIPに解決されます。 他のコンテナには、web2.lxdhaproxy.lxdなどの独自のホスト名があります。

checkパラメータは、HAPRoxyにWebサーバーでヘルスチェックを実行して、それが使用可能であることを確認するように指示します。

構成が有効であることをテストするには、次のコマンドを実行します。

/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c

出力は次のようになります

出力

Configuration file is valid

新しい構成を読み取るようにHAProxyをリロードしてみましょう。

sudo systemctl reload haproxy

次に、ホストに戻るためにコンテナからログアウトします。

logout

ポート80で受信した接続を他の2つのコンテナー内の適切なWebサーバーに転送するリバースプロキシとして機能するようにHAProxyを構成しました。 haproxyが実際にリクエストを正しいWebコンテナに転送できることをテストしてみましょう。 次のコマンドを実行します。

curl --verbose --header 'Host: web2.example.com' http://10.10.10.10

これにより、HAProxyにリクエストが送信され、HTTP hostヘッダーが設定されます。これは、HAProxyが接続を適切なWebサーバーにリダイレクトするために使用する必要があります。

出力は次のようになります

Output of "curl --verbose --header 'Host: web2.example.com' http://10.10.10.10" command...
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
> 
...
< 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web2!</title>
<style>
...

HAProxyはリクエストを正しく理解し、それをweb2コンテナに転送しました。 そこで、Webサーバーは、以前に編集したデフォルトのインデックスページを提供し、テキストon LXD container web2を表示します。 それでは、外部リクエストをHAProxyにルーティングして、世界中が私たちのWebサイトにアクセスできるようにしましょう。

ステップ6—着信接続をHAProxyコンテナに転送する

パズルの最後のピースは、リバースプロキシをインターネットに接続することです。 インターネットからポート80で受信する可能性のある接続をhaproxyコンテナに転送するようにサーバーを設定する必要があります。

HAProxyはコンテナにインストールされ、デフォルトではインターネットからアクセスできません。 これを解決するために、接続を転送するiptablesルールを作成します。

iptablesコマンドには、サーバーのパブリックIPアドレス(your_server_ip)とhaproxyコンテナーのプライベートIPアドレス(your_haproxy_ip)の2つのIPアドレスが必要です。 、lxc listコマンドで取得できます。

次のコマンドを実行して、ルールを作成します。

sudo iptables -t nat -I PREROUTING -i eth0 -p TCP -d your_server_ip/32 --dport 80 -j DNAT --to-destination your_haproxy_ip:80

コマンドの内訳は次のとおりです。

  • -t natは、natテーブルを使用していることを示します。
  • -I PREROUTINGは、ルールをPREROUTINGチェーンに追加することを指定します。
  • -i eth0は、ドロップレットのデフォルトのパブリックインターフェイスであるインターフェイスeth0を指定します。
  • -p TCPは、TCPプロトコルを使用していることを示しています。
  • -d your_server_ip/32は、ルールの宛先IPアドレスを指定します。
  • --dport 80:宛先ポートを指定します。
  • -j DNATは、宛先NAT(DNAT)へのジャンプを実行することを示しています。
  • --to-destination your_haproxy_ip:80は、リクエストをHAProxyを使用してコンテナのIPアドレスに送信することを示しています。

IPTablesの詳細については、IptablesFirewallの仕組みおよびIPtablesEssentials:一般的なファイアウォールルールとコマンドをご覧ください。

最後に、このiptablesコマンドを保存して、再起動後に再適用できるようにするには、iptables-persistentパッケージをインストールします。

sudo apt-get install iptables-persistent

パッケージをインストールすると、現在のiptablesルールを保存するように求められます。 現在のすべてのiptablesルールを受け入れて保存します。

2つのFQDNを設定している場合は、Webブラウザを使用して各Webサイトに接続できるはずです。 やってみよう。

2つのWebサーバーが実際にインターネットからアクセス可能であることをテストするには、次のようにcurlコマンドを使用してローカルコンピューターからそれぞれにアクセスします。

curl --verbose --header 'Host: example.com' 'http://your_server_ip'
curl --verbose --header 'Host: web2.example.com' 'http://your_server_ip'

これらのコマンドは、サーバーのパブリックIPアドレスへのHTTP接続を確立し、手順5で行ったように、HAProxyが要求を処理するために使用する--headerオプションを使用してHTTPヘッダーフィールドを追加します。

最初のcurlコマンドの出力は次のとおりです。

Output*   Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
    body {
...

2番目のcurlコマンドの出力は次のとおりです。

Output*   Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web2!</title>
<style>
    body {
...

どちらの場合も、正しいWebサイトが表示されます。

結論

HAProxyがトラフィックを転送する、それぞれ独自のコンテナ内に2つのWebサイトを設定しました。 このプロセスを複製して、それぞれが独自のコンテナーに限定された、さらに多くのWebサイトを構成できます。

MySQLを新しいコンテナに追加してから、WordPressなどのCMSをインストールして各Webサイトを実行することもできます。 このプロセスを使用して、古いバージョンのソフトウェアをサポートすることもできます。 たとえば、CMSのインストールにPHP5などの古いバージョンのソフトウェアが必要な場合は、Ubuntu 16.04で利用可能なパッケージマネージャーのバージョンをダウングレードする代わりに、コンテナー(lxc launch ubuntu:t)にUbuntu14.04をインストールできます。

最後に、LXDは、コンテナーの完全な状態のスナップショットを作成する機能を提供します。これにより、バックアップを作成し、後でコンテナーをロールバックすることが容易になります。 さらに、LXDを2つの異なるサーバーにインストールすると、それらを接続して、インターネットを介してサーバー間でコンテナーを移行することができます。