序章
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:x
のx
は、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
ファイルに次の変更を加えます。
<!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
オプションを追加して、セッションの再利用と待ち時間の短縮を可能にします。
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
セクションを追加します。
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_cluster
とweb2_cluster
という名前を付けます。 次のコードをファイルに追加して、バックエンドを定義します。
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.lxd
はweb1
コンテナに関連付けられたIPに解決されます。 他のコンテナには、web2.lxd
やhaproxy.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つの異なるサーバーにインストールすると、それらを接続して、インターネットを介してサーバー間でコンテナーを移行することができます。