M.C.P.C. (Mamesibori Creation Plus Communication)

印刷屋から五反田のWeb屋に転職したCLのブログです。

CentOS 6にSSHトンネリングしてNFSv4で共有

AWSCentOS 6を立てて、NFSv4サーバを設置、別のCentOS 6からSSHでトンネリングしてNFSv4でマウントするというシナリオです。

想定される状況としては、「すでに稼働中のWebサーバを、物理的につながっていない別のサーバに移転しなくてはならないのだけれども、DNSの切替がスムーズにいかないことが予想されるので、先にコンテンツだけ移転先のサーバにNFSサーバを立ててあらかじめコピーしておき、その後Webサーバのファイルシステムを移転先のNFSサーバに切り替える」というものです。

  • 移転先のNFSサーバへは2049/TCPでアクセスしない(新旧サーバ間の通信はインターネット経由なので平文が流れるNFSは通したくない)
  • Webサーバから22/TCPSSHトンネリングにて、セキュアな通信路を確保したうえで、2049/TCP(NFS)を通します。

IPで見た方が分かりやすいので、以降リアルIPそのままです。これ書いた後サーバは停止していますので今はつながらないです、あしからず。出てくるIPは、AmazonAWSから付与されたIPと、spmodeから付与されたIPです。

  • 10.146.70.17:Webサーバ(NFSクライアント)
  • 10.128.3.242:移転先サーバ(NFSv4サーバ)
  • 1.72.4.106:操作しているSSHコンソールのIP

移転先サーバ(NFSv4サーバ)のインストール・設定・起動

nfs-utilsをインストールします。依存関係に現れている、rpcbindは、CentOS 5ではportmapとなっていたパッケージですので、注意してください。

[root@ip-10-128-3-242 ~]# yum install nfs-utils
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * atomic: www4.atomicorp.com
 * base: www.ftp.ne.jp
 * elrepo: ftp.osuosl.org
 * epel: mirror01.th.ifl.net
 * extras: www.ftp.ne.jp
 * updates: www.ftp.ne.jp
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package nfs-utils.x86_64 1:1.2.3-26.el6 will be installed
--> Processing Dependency: nfs-utils-lib >= 1.1.0-3 for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: keyutils >= 1.4-4 for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: rpcbind for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libtirpc for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libgssglue.so.1(libgssapi_CITI_2)(64bit) for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libgssglue for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libevent for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libtirpc.so.1()(64bit) for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libnfsidmap.so.0()(64bit) for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libgssglue.so.1()(64bit) for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Processing Dependency: libevent-1.4.so.2()(64bit) for package: 1:nfs-utils-1.2.3-26.el6.x86_64
--> Running transaction check
---> Package keyutils.x86_64 0:1.4-4.el6 will be installed
---> Package libevent.x86_64 0:1.4.13-4.el6 will be installed
---> Package libgssglue.x86_64 0:0.1-11.el6 will be installed
---> Package libtirpc.x86_64 0:0.2.1-5.el6 will be installed
---> Package nfs-utils-lib.x86_64 0:1.1.5-4.el6 will be installed
---> Package rpcbind.x86_64 0:0.2.0-9.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================
 Package           Arch       Version          Repository  Size
================================================================
Installing:
 nfs-utils         x86_64     1:1.2.3-26.el6   base       316 k
Installing for dependencies:
 keyutils          x86_64     1.4-4.el6        base        39 k
 libevent          x86_64     1.4.13-4.el6     base        66 k
 libgssglue        x86_64     0.1-11.el6       base        23 k
 libtirpc          x86_64     0.2.1-5.el6      base        78 k
 nfs-utils-lib     x86_64     1.1.5-4.el6      base        67 k
 rpcbind           x86_64     0.2.0-9.el6      base        51 k

Transaction Summary
===============================================================
Install       7 Package(s)

Total download size: 640 k
Installed size: 1.7 M
Is this ok [y/N]: y
Downloading Packages:
...
Installed:
  nfs-utils.x86_64 1:1.2.3-26.el6

Dependency Installed:
  keyutils.x86_64 0:1.4-4.el6          libevent.x86_64 0:1.4.13-4.el6
  libgssglue.x86_64 0:0.1-11.el6       libtirpc.x86_64 0:0.2.1-5.el6
  nfs-utils-lib.x86_64 0:1.1.5-4.el6   rpcbind.x86_64 0:0.2.0-9.el6

Complete!

設定します

[root@ip-10-128-3-242 ~]# vi /etc/idmapd.conf
[General]
#Verbosity = 0
# The following should be set to the local NFSv4 domain name
# The default is the host's DNS domain name.
#Domain = local.domain.edu
Domain = dtpwiki.jp
...
[root@ip-10-128-3-242 ~]# vi /etc/sysconfig/nfs
#
# Define which protocol versions mountd
# will advertise. The values are "no" or "yes"
# with yes being the default
#MOUNTD_NFS_V2="no"
#MOUNTD_NFS_V3="no"
MOUNTD_NFS_V2="no"
MOUNTD_NFS_V3="no"
#
#
# Path to remote quota server. See rquotad(8)
#RQUOTAD="/usr/sbin/rpc.rquotad"
RQUOTAD=no
# Port rquotad should listen on.
#RQUOTAD_PORT=875
# Optinal options passed to rquotad
#RPCRQUOTADOPTS=""
#
#
# Optional arguments passed to in-kernel lockd
#LOCKDARG=
# TCP port rpc.lockd should listen on.
#LOCKD_TCPPORT=32803
LOCKD_TCPPORT=32803
# UDP port rpc.lockd should listen on.
#LOCKD_UDPPORT=32769
LOCKD_UDPPORT=32769
#
#
# Optional arguments passed to rpc.nfsd. See rpc.nfsd(8)
# Turn off v2 and v3 protocol support
#RPCNFSDARGS="-N 2 -N 3"
RPCNFSDARGS="-N 2 -N 3 -U"
# Turn off v4 protocol support
#RPCNFSDARGS="-N 4"
# Number of nfs server processes to be started.
# The default is 8.
#RPCNFSDCOUNT=8
# Stop the nfsd module from being pre-loaded
#NFSD_MODULE="noload"
# Set V4 grace period in seconds
#NFSD_V4_GRACE=90
#
#
#
# Optional arguments passed to rpc.mountd. See rpc.mountd(8)
#RPCMOUNTDOPTS=""
# Port rpc.mountd should listen on.
#MOUNTD_PORT=892
#
#
# Optional arguments passed to rpc.statd. See rpc.statd(8)
#STATDARG=""
# Port rpc.statd should listen on.
#STATD_PORT=662
# Outgoing port statd should used. The default is port
# is random
#STATD_OUTGOING_PORT=2020
# Specify callout program
#STATD_HA_CALLOUT="/usr/local/bin/foo"
#
#
# Optional arguments passed to rpc.idmapd. See rpc.idmapd(8)
#RPCIDMAPDARGS=""
#
# Set to turn on Secure NFS mounts.
#SECURE_NFS="yes"
# Optional arguments passed to rpc.gssd. See rpc.gssd(8)
#RPCGSSDARGS=""
# Optional arguments passed to rpc.svcgssd. See rpc.svcgssd(8)
#RPCSVCGSSDARGS=""
#
# To enable RDMA support on the server by setting this to
# the port the server should listen on
#RDMA_PORT=20049

NFSで共有したいディレクトリを設定します。通常、共有先のホストのIP範囲を指定するところが、自ホストのIPになっている点、SSHトンネリングによる通常とはちがうportからの接続に対応するためにinsecureを指定している点に注意してください。理由は後述③のnetstat -naの出力でわかります。

[root@ip-10-128-3-242 ~]# vi /etc/exports
/       10.128.3.242/32(rw,sync,no_root_squash,insecure,fsid=0)

[root@ip-10-128-3-242 ~]# /usr/sbin/exportfs -ra
[root@ip-10-128-3-242 ~]# /usr/sbin/exportfs -v
/               10.128.3.242/32(ro,wdelay,root_squash,no_subtree_check,fsid=0)

サービスを起動します。

[root@ip-10-128-3-242 ~]# /sbin/service rpcbind start
rpcbind を起動中:                                          [  OK  ]
[root@ip-10-128-3-242 ~]# /sbin/service rpcidmapd start
RPC idmapd を起動中:                                       [  OK  ]
[root@ip-10-128-3-242 ~]# /sbin/service nfs start
NFS サービスを起動中:                                      [  OK  ]
NFS mountd を起動中:                                       [  OK  ]
RPC idmapd を停止中:                                       [  OK  ]
RPC idmapd を起動中:                                       [  OK  ]
NFS デーモンを起動中:            

①サーバ側のnetstat -naです。IPv6の表示は省略。今回は、SSHでトンネルを掘って接続しますので、22/TCPだけファイアウォールを空けておいてください。太字は、rpcbindを起動すると現れる、不用なポートです。どうにかして消せないものか。

[root@ip-10-128-3-242 ~]# netstat -na
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address     State
tcp        0      0 0.0.0.0:111                 0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:22                  0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:2049                0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:32803               0.0.0.0:*           LISTEN
tcp        0     52 10.128.3.242:22             1.72.4.106:58643    ESTABLISHED
udp        0      0 0.0.0.0:111                 0.0.0.0:*
udp        0      0 0.0.0.0:32769               0.0.0.0:*
udp 0 0 0.0.0.0:951 0.0.0.0:*
Active UNIX domain sockets (servers and established)
...

Webサーバ(NFSクライアント側)からマウント

クライアント側からマウントするにあたり、SSHで先にサーバまでトンネルを掘って(SSHトンネリング)、そこにNFSを通して接続します。

まず、トンネルを掘ります。

※このトンネルの掘り方には議論の余地があります。この用途に特化した、autosshていうのがありますので、そっちを使うべきでしょう。

[root@ip-10-146-70-17 ~]# ssh -f -N -i ~/.ssh/key.pem -L 2049:10.128.3.242:2049 root@10.128.3.242

②このときのサーバ側のnetstatは以下の通り。太字は、SSHトンネリングで掘ったトンネルです。

[root@ip-10-128-3-242 ~]# netstat -na
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address     State
tcp        0      0 0.0.0.0:111                 0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:22                  0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:2049                0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:32803               0.0.0.0:*           LISTEN
tcp 0 0 10.128.3.242:22 10.146.70.17:55764 ESTABLISHED
tcp        0     52 10.128.3.242:22             1.72.4.106:58643    ESTABLISHED
udp        0      0 0.0.0.0:111                 0.0.0.0:*
udp        0      0 0.0.0.0:32769               0.0.0.0:*
udp        0      0 0.0.0.0:951                 0.0.0.0:*
Active UNIX domain sockets (servers and established)
...

マウントします。普通共有元のサーバを指定するところが、localhostになっている点に注意してください。

[root@ip-10-146-70-17 ~]# mount -t nfs4 -o hard,intr localhost:/ /mnt
[root@ip-10-146-70-17 ~]# ls /mnt/
bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  sbin  selinux  srv  sys  tmp  usr  var
[root@ip-10-146-70-17 ~]#

共有できました。

③最終的なnetstatです。太字のところは、サーバ内でトンネルの出口からNFSへの接続が確立されているという様子です。

[root@ip-10-128-3-242 ~]# netstat -na
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 0.0.0.0:111                 0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:22                  0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:2049                0.0.0.0:*           LISTEN
tcp        0      0 0.0.0.0:32803               0.0.0.0:*           LISTEN
tcp 0 0 10.128.3.242:50115 10.128.3.242:2049 ESTABLISHED
tcp 0 0 10.128.3.242:2049 10.128.3.242:50115 ESTABLISHED
tcp 0 0 10.128.3.242:22 10.146.70.17:55764 ESTABLISHED
tcp        0     52 10.128.3.242:22             1.72.4.106:58643    ESTABLISHED
udp        0      0 0.0.0.0:111                 0.0.0.0:*
udp        0      0 0.0.0.0:32769               0.0.0.0:*
udp        0      0 0.0.0.0:951                 0.0.0.0:*
Active UNIX domain sockets (servers and established)
...
[root@ip-10-128-3-242 ~]#

でき上ったシステムに対する評価

現在稼働しているWebサーバのファイルシステムを、新しいサーバのNFSに置き換える用途であるとして、このシステムで実現するとなると、以下のような問題点が考えられます。

  1. SSHトンネリングということであるが、SSHは通信路の切断に弱い。定常的に利用するのは難しいのではないか。
  2. NFSファイルシステムを置き換える場合、キャッシュが効かず、毎回NFSにファイルをリクエストすることになるから、速度や、通信量の面で問題はないか。

1.については、当然品質の高いインターネット回線を確保することも必要ですが、さらにautosshによるSSHセッションの自動貼り直しツールを使うのも有効でしょう。

2.については、つまり一度読みこんだコンテンツをキャッシュするような仕組みの導入を考えればよいわけですが、昔からあるmod_cacheなどのApache内での解決を試みるのもありでしょうが、せっかくなのでNFSにキャッシュを組み込めるcachefilesdを使うことも検討して見られたらいかがでしょうか。

autossh、cachefilesd両ツールとも、CentOS 6ならyumから簡単にインストールできますよ。