ELBはなんでもロードバランスできると聞いたのでFTPしてみる

はじめに
----

真面目に AWS を使わずに生きてきたので、ずっと ELB は HTTP のためのものだと思い込んでいました。
ところが、実際はプロトコルは TCP であれば問題なく、またポートも広く扱えるものであった様です。

- [Amazon Web Services ブログ: Amazon Elastic Load Balancing](http://aws.typepad.com/aws_japan/amazon-elastic-load-balancing/)

ということで、ELB を使って FTP サーバをロードバランスしてみることは可能なのか、確認してみます。

**なお、あくまでバランシングのテストなので、クラスタ内でのデータ共有/同期については後の課題として棚上げしています。**

**ELB は TCP でのラウンドロビンのため、FTP のコントロールセッションとデータセッションが異なるインスタンスにふられる可能性があるというご指摘を某所より頂戴しました。**

EC2
----

まずは、検証用の FTP サーバをセットアップします。
手軽に済ませるために、Amazon Linux の EC2 インスタンスを立ち上げ、vsftpd をセットアップします。

### vsftpd をインストール

```shell-session
$ sudo yum install -y vsftpd
```

### vsftpd の設定

```
$ sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.orig
$ sudo vi /etc/vsftpd/vsftpd.conf
$ sudo diff -u /etc/vsftpd/vsftpd.conf.orig /etc/vsftpd/vsftpd.conf
--- /etc/vsftpd/vsftpd.conf.orig        2015-09-18 13:02:11.388207227 +0000
+++ /etc/vsftpd/vsftpd.conf     2015-09-18 13:09:43.896253557 +0000
@@ -9,7 +9,7 @@
 # capabilities.
 #
 # Allow anonymous FTP? (Beware - allowed by default if you comment this out).
-anonymous_enable=YES
+anonymous_enable=NO
 #
 # Uncomment this to allow local users to log in.
 local_enable=YES
@@ -32,14 +32,14 @@
 #
 # Activate directory messages - messages given to remote users when they
 # go into a certain directory.
-dirmessage_enable=YES
+dirmessage_enable=NO
 #
 # The target log file can be vsftpd_log_file or xferlog_file.
 # This depends on setting xferlog_std_format parameter
 xferlog_enable=YES
 #
 # Make sure PORT transfer connections originate from port 20 (ftp-data).
-connect_from_port_20=YES
+connect_from_port_20=NO
 #
 # If you want, you can arrange for uploaded anonymous files to be owned by
 # a different user. Note! Using "root" for uploaded files is not
@@ -53,7 +53,7 @@
 #
 # Switches between logging into vsftpd_log_file and xferlog_file files.
 # NO writes to vsftpd_log_file, YES to xferlog_file
-xferlog_std_format=YES
+xferlog_std_format=NO
 #
 # You may change the default value for timing out an idle session.
 #idle_session_timeout=600
@@ -78,8 +78,8 @@
 # predicted this attack and has always been safe, reporting the size of the
 # raw file.
 # ASCII mangling is a horrible feature of the protocol.
-#ascii_upload_enable=YES
-#ascii_download_enable=YES
+ascii_upload_enable=YES
+ascii_download_enable=YES
 #
 # You may fully customise the login banner string:
 #ftpd_banner=Welcome to blah FTP service.
@@ -93,8 +93,8 @@
 # You may specify an explicit list of local users to chroot() to their home
 # directory. If chroot_local_user is YES, then this list becomes a list of
 # users to NOT chroot().
-#chroot_local_user=YES
-#chroot_list_enable=YES
+chroot_local_user=YES
+chroot_list_enable=YES
 # (default follows)
 #chroot_list_file=/etc/vsftpd/chroot_list
 #
@@ -116,4 +116,13 @@

 pam_service_name=vsftpd
 userlist_enable=YES
-tcp_wrappers=YES
+tcp_wrappers=NO
+
+pasv_enable=YES
+pasv_addr_resolve=YES
+pasv_address=52.69.XXX.YYY
+pasv_min_port=60001
+pasv_max_port=60010
+use_localtime=YES
+force_dot_files=YES

```

### /etc/vsftpd/chroot_list

空のファイルを作ります。

```
$ sudo touch /etc/vsftpd/chroot_list
```

### ユーザ追加

```
$ sudo adduser ftp-test
$ sudo passwd ftp-test
```

### vsftpd 起動

```
$ sudo chkconfig vsftpd on
$ sudo chkconfig --list vsftpd
$ sudo /sbin/service vsftpd start
```

### セキュリティグループ

ポート 21, 60001 - 60010 に対するアクセスを許可します。

### 接続テスト

```
$ ftp ftp-test@52.69.XXX.YYY
Connected to .52.69.XXX.YYY
220 (vsFTPd 2.2.2)
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> put ~/test.txt ./test.txt
local: /Users/koshigoe/test.txt remote: ./test.txt
229 Entering Extended Passive Mode (|||60003|).
150 Ok to send data.
100% |****************************************************************************************************************************|     5       13.48 KiB/s    00:00 ETA
226 Transfer complete.
5 bytes sent in 00:00 (0.13 KiB/s)
```


ELB
---

### 基本的な設定

プロトコル TCP なリスナーを必要なポートの分だけ追加します。
リスナーのポートは範囲指定はできない様なので、21 と PASV 用の 60001 - 60010 を一つずつ追加します。

### セキュリティグループ

ポート 21, 60001 - 60010 に対するアクセスを許可します。

### vsftpd の pasv_address を変更する

pasv_address を ELB の DDNS に変更します。

```
$ sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.rev1
$ sudo vi /etc/vsftpd/vsftpd.conf
$ sudo diff -u /etc/vsftpd/vsftpd.conf.rev1 /etc/vsftpd/vsftpd.conf
--- /etc/vsftpd/vsftpd.conf.rev1        2015-09-18 13:59:17.089150026 +0000
+++ /etc/vsftpd/vsftpd.conf     2015-09-18 14:01:18.005173450 +0000
@@ -120,7 +120,7 @@

 pasv_enable=YES
 pasv_addr_resolve=YES
-pasv_address=52.69.XXX.YYY
+pasv_address=FTP-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com
 pasv_min_port=60001
 pasv_max_port=60010
 use_localtime=YES
```

### vsftpd を再起動

```
$ sudo /sbin/service vsftpd restart
```

### 接続テスト

```
$ ftp ftp-test@FTP-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com
Trying 52.68.XXX.YYY...
Connected to ftp-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com.
220 (vsFTPd 2.2.2)
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||60002|).
150 Here comes the directory listing.
-rw-r--r--    1 501      501            18 Mar 04  2015 .bash_logout
-rw-r--r--    1 501      501           176 Mar 04  2015 .bash_profile
-rw-r--r--    1 501      501           124 Mar 04  2015 .bashrc
-rw-r--r--    1 501      501             5 Sep 18 13:42 test.txt
226 Directory send OK.
ftp> put ~/test.txt test2.txt
local: /Users/koshigoe/test.txt remote: test2.txt
229 Entering Extended Passive Mode (|||60001|).
150 Ok to send data.
100% |****************************************************************************************************************************|     5       36.71 KiB/s    00:00 ETA
226 Transfer complete.
5 bytes sent in 00:00 (0.15 KiB/s)
```

### ロードバランス

同じ様に EC2 で vsftpd をセットアップし、InService になったら接続を確認します。
同じアドレスで異なるインスタンスに接続できる事が確認できました。

```
$ ftp ftp-test@FTP-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com
Trying 52.68.XXX.YYY...
Connected to ftp-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com.
220 (vsFTPd 2.2.2)
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||60005|).
150 Here comes the directory listing.
-rw-r--r--    1 501      501            18 Mar 04  2015 .bash_logout
-rw-r--r--    1 501      501           176 Mar 04  2015 .bash_profile
-rw-r--r--    1 501      501           124 Mar 04  2015 .bashrc
226 Directory send OK.
ftp> ^D
221 Goodbye.
$ ftp ftp-test@FTP-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com
Trying 52.68.XXX.YYY...
Connected to ftp-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com.
220 (vsFTPd 2.2.2)
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||60007|).
150 Here comes the directory listing.
-rw-r--r--    1 501      501            18 Mar 04  2015 .bash_logout
-rw-r--r--    1 501      501           176 Mar 04  2015 .bash_profile
-rw-r--r--    1 501      501           124 Mar 04  2015 .bashrc
-rw-r--r--    1 501      501             5 Sep 18 13:42 test.txt
-rw-r--r--    1 501      501             5 Sep 18 14:13 test2.txt
226 Directory send OK.
ftp> ^D
221 Goodbye.
```


まとめ
---

- 小一時間かからず FTP サーバをロードバランスできました
- FTP サーバの運用経験がないため、本当に妥当で安定した運用になるのかは分かりません


疑問
----

- PASV モード用のポートはどの程度開放するものなのでしょうか
- この方法で安定した運用は可能なのでしょうか
- AWS での冗長化は ELB に任せたら良いと考えてしまっていいものでしょうか


参考
----

- [Amazon Linuxにvsftpをセットアップする方法 ‹ 技術の犬小屋](http://promamo.com/?p=3067)