Google Cloud Compute Engine の micro インスタンスが無料で使えるようになりました。みなさん使っていますか?僕は http://manga.dog/ で使っています。が、しかし、新しい機能を追加しようと思ったのですが、どうも全文検索エンジンの Elasticsearch を使わないといけないようです。そして Elasticsearch はメモリを食いまくるので現在の micro インスタンスに同居させるのはとても難しい。Amazon Elasticsearch Service を使って機能を実装してはみたのだけど、そもそも無料の micro インスタンスを使っていたので有料サービスを使うのは負けた気がする!そこで自宅に転がっていた Raspberry Pi3 に Elasticsearch を入れシステムに組み込み勝利をつかみ取ることにしました。
必要な機能
- ラズパイで Elasticsearch を動かす
- アプリケーションサーバから自宅のラズパイにアクセスする
このような機能が必要なのですが、まぁいわゆる自宅サーバを公開すればよいわけですね。一般的には自宅のルーターに外部からきたアクセスを特定の機器にルーティングする設定をおこなう方法だと思います。でもこの方法だと自宅のIPが変わるとアクセスできなくなってしまいます。それを回避するためにダイナミックDNSを使います。でもこの方法はかっこ悪いなと前々から思っていました。
そこで VPN を使った方法で構築したいと思います。全体の構成はこのようになります。
VPNサーバを無料なGoogle Cloud Compute Engineに立てます。ラズパイは自宅からVPNサーバに接続します。するとサーバとクライアントは 10.8.0.1 と 10.8.0.6 の仮想ネットワーク上のIPアドレスで接続されます。繋がってしまえば簡単ですね。サーバに飛んできたHTTPリクエスを nginx をプロキシサーバにしてラズパイに投げてしまえばよいのです。
手順としては以下の4段階になります。
- VPNサーバの設定
- Raspberry Pi3 を VPN サーバに接続する
- Raspberry Pi3 で Elasticsearch を動かす
- VPNサーバに nginx でプロキシサーバを立てる
それでは設定していきます。
VPNサーバの設定
環境: Google Cloud Compute Engine
OS: Ubuntu 16.04 LTS
開放ポート: 80-TCP, 1194-UDP
サーバを用意したら80と1194のポートを開放してください。1194はUDPになります。
まずは更新します。
$ sudo apt-get update
$ sudo apt-get upgrade
openvpn と git をインストールします。easy-rsa という鍵を作成するツールのリポジトリも取得します。
$ sudo apt install openvpn git
$ git clone https://github.com/OpenVPN/easy-rsa.git
鍵がいくつも必要になるので作っていきます。作成した鍵は /etc/openvpn/keys
にコピーします。
ca.crt
を作ります。phrase と Common Name は適当なものを入力してください。
$ cd easy-rsa/easyrsa3
$ ./easyrsa init-pki
$ ./easyrsa build-ca
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: google
$ sudo mkdir /etc/openvpn/keys
$ sudo cp pki/ca.crt /etc/openvpn/keys
server.crt
と server.key
を作成します。途中で ca.key
の phrase を求められるので入力します。
$ ./easyrsa build-server-full server nopass
Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:
$ sudo cp pki/issued/server.crt /etc/openvpn/keys
$ sudo cp pki/private/server.key /etc/openvpn/keys
dh.pem
を作成します。こちらも ca.key
の phrase を入力します。このキーの作成は少し時間がかかります。
$ ./easyrsa gen-dh
$ sudo cp pki/dh.pem /etc/openvpn/keys
crl.pem
を作成します。途中で ca.key
の phrase を入力します。
$ ./easyrsa gen-crl
Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:
$ sudo cp pki/crl.pem /etc/openvpn/keys
$ sudo chmod o+r /etc/openvpn/keys/crl.pem
クライアントの鍵を作成します。[client-name] に適当な名前を入れてください。僕の場合はクライアントがラズパイなので ras としました。また、クライアント鍵の phrase が求められるので適当なものを入力し、その後に ca.key
の phrase も入力します。
$ ./easyrsa build-client-full [client-name]
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:
ca.crt
とクライアントの鍵はラズパイにアップロードする必要があるのでローカル環境にダウンロードしておきます。
$ cp pki/ca.crt ~
$ cp pki/issued/[client-name].crt ~
$ cp pki/private/[client-name].key ~
$ scp XXX.XXX.XXX.XXX:~/ca.crt ~/vpn/
$ scp XXX.XXX.XXX.XXX:~/ras.crt ~/vpn/
$ scp XXX.XXX.XXX.XXX:~/ras.key ~/vpn/
/etc/openvpn/server.conf
を作成します。各パラメーターの詳しい説明は以下の記事を参考にしてください。
OpenVPNのインストールとセットアップからインターネット接続までのガイドブック
port 1194
proto udp
dev tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key
dh /etc/openvpn/keys/dh.pem
crl-verify /etc/openvpn/keys/crl.pem
ifconfig-pool-persist /etc/openvpn/ipp.txt
server 10.8.0.0 255.255.255.0
push "route 10.8.0.0 255.255.255.0"
client-to-client
keepalive 10 120
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn-status.log
log /var/log/openvpn.log
log-append /var/log/openvpn.log
verb 3
openvpn
コマンドで動作するか確認します。
$ sudo openvpn --config /etc/openvpn/server.conf
ログはこのようになります。
Jul 3 01:13:09 vpn2 ntpd[1613]: Listen normally on 6 tun0 10.8.0.1:123
Jul 3 01:13:09 vpn2 ntpd[1613]: Listen normally on 7 tun0 [fe80::b142:7fdf:3c3c:7f79%3]:123
Jul 3 01:13:09 vpn2 ntpd[1613]: new interface(s) found: waking up resolver
ifconfig
でIPが割り振られているか確認します。 10.8.0.1
となっていますね。
$ ifconfig
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.1 P-t-P:10.8.0.2 Mask:255.255.255.255
inet6 addr: fe80::b142:7fdf:3c3c:7f79/64 Scope:Link
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:144 (144.0 B)
openvpn
での実行を止めて、サービスで起動させます。
$ sudo systemctl start openvpn@server
自動起動になっていないので有効にします。
sudo systemctl enable openvpn@server
VPNサーバの設定は以上です。
Raspberry Pi3 を VPN サーバに接続する
OS は Ubuntu MATE 16.04.2 LTS を使用します。Mac を使ったインストール方法も書いておきます。
ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz をダウンロードします。次に SDカードをアダプタなどを使い Mac の USB に刺します。
$ diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *500.3 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_CoreStorage Macintosh HD 499.4 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3
/dev/disk1 (internal, virtual):
#: TYPE NAME SIZE IDENTIFIER
0: Apple_HFS Macintosh HD +499.0 GB disk1
Logical Volume on disk0s2
DF19241A-6A88-40A6-AC98-2B2929C13B2A
Unencrypted
/dev/disk2 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *31.4 GB disk2
1: Windows_FAT_32 PI_BOOT 66.1 MB disk2s1
2: Linux 31.4 GB disk2s2
SDカードは /dev/disk2
と認識されているようです。
df
で Mounted on
を確認し、unmount します。
$ df
Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on
/dev/disk1 974700800 735691904 238496896 76% 3494843 4291472436 0% /
devfs 389 389 0 100% 674 0 100% /dev
map -hosts 0 0 0 100% 0 0 100% /net
map auto_home 0 0 0 100% 0 0 100% /home
/dev/disk2s1 128912 42672 86240 34% 512 0 100% /Volumes/PI_BOOT
$ sudo diskutil unmount "/Volumes/PI_BOOT"
イメージをSDカードにコピーします。このとき /dev/rdisk2
と disk の前に r を入れます。またbs=1m
も追加します。これをしないと何時間もかかってしまうので注意が必要です。
$ xzcat ~/Downloads/ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz | sudo dd of=/dev/rdisk2 bs=1m
contrl+t
で進捗を確認できます。
終わったらSDカードをラズパイに刺せば Ubuntu MATE が起動します。
更新します。
$ sudo apt-get update
$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
You might want to run 'apt-get -f install' to correct these.
The following packages have unmet dependencies:
libc6-dev : Depends: libc6 (= 2.23-0ubuntu9) but 2.23-0ubuntu5 is installed
E: Unmet dependencies. Try using -f.
-f を使わないと更新ができないようです。
$ sudo apt-get -f upgrade
openvpn
をインストールします。
$ sudo apt-get install openvpn
VPNサーバで作成した鍵をラズパイにアップロードし、 /etc/openvpn/keys
に配置します。
$ scp ~/vpn/ca.crt XXX.XXX.XXX.XXX:~
$ scp ~/vpn/ras.crt XXX.XXX.XXX.XXX:~
$ scp ~/vpn/ras.key XXX.XXX.XXX.XXX:~
$ sudo mkdir /etc/openvpn/keys
$ sudo mv ca.crt /etc/openvpn/keys
$ sudo mv ras.crt /etc/openvpn/keys
$ sudo mv ras.key /etc/openvpn/keys
/etc/openvpn/keys/pass
にクライアント鍵の phrase を入れておきます。
$ sudo vi /etc/openvpn/keys/pass
/etc/openvpn/client.conf
にクライアントの設定を記載します。XXX.XXX.XXX.XXX
はVPNサーバのIPアドレスを入れてください。
client
dev tun
proto udp
remote XXX.XXX.XXX.XXX 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/ras.crt
key /etc/openvpn/keys/ras.key
askpass /etc/openvpn/keys/pass
comp-lzo
verb 3
openvpn
コマンドで接続できるか試します。
$ sudo openvpn --config /etc/openvpn/client.conf
別ウィンドウで ifconfig
を実行してみます。 10.8.0.6
とIPが割り振られたようです。
$ ifconfig
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.6 P-t-P:10.8.0.5 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:252 (252.0 B) TX bytes:252 (252.0 B)
VPNサーバに ping
が届くか確認します。
$ ping 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=68.8 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=58.9 ms
逆にVPNサーバからラズパイに ping
を打ってみます。
$ ping 10.8.0.6
PING 10.8.0.6 (10.8.0.6) 56(84) bytes of data.
64 bytes from 10.8.0.6: icmp_seq=1 ttl=64 time=63.5 ms
64 bytes from 10.8.0.6: icmp_seq=2 ttl=64 time=59.5 ms
問題がなさそうなので、openvpn
の実行を終了し、サービスの起動と自動起動の設定を行います。
$ sudo service openvpn start
$ sudo systemctl enable openvpn
ラズパイで Elasticsearch を動かす
オフィシャルのインストール方法はこちらに書いてあります。
Install Elasticsearch with Debian Package
インストールします。
$ wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
$ echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
$ sudo apt-get update
$ sudo apt-get install elasticsearch
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.3.deb
$ sudo dpkg -i elasticsearch-5.4.3.deb
Elasticsearch は初期設定だとメモリを2GB使いますが、Raspberry Pi3 は1GBしか積んでいないので、jvm の設定を変更して512MBにします。
#-Xms2g
#-Xmx2g
-Xms512m
-Xmx512m
外部のPCからアクセスできるように設定を追記します。
network.host: 0.0.0.0
http.port: 9200
transport.host: localhost
transport.tcp.port: 9300
実行します。
$ sudo service elasticsearch start
起動には時間がかかります。ログを確認します。
$ tail -f /var/log/elasticsearch/elasticsearch.log
[2017-07-03T21:17:00,200][INFO ][o.e.n.Node ] [d0hREp4] starting ...
[2017-07-03T21:17:04,266][INFO ][o.e.t.TransportService ] [d0hREp4] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}
[2017-07-03T21:17:04,471][WARN ][o.e.b.BootstrapChecks ] [d0hREp4] system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
[2017-07-03T21:17:08,265][INFO ][o.e.c.s.ClusterService ] [d0hREp4] new_master {d0hREp4}{d0hREp4RSZq1h-A-VUWbvw}{FSLOhsEiQfGR9w81wvmmgg}{localhost}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)
[2017-07-03T21:17:08,639][INFO ][o.e.h.n.Netty4HttpServerTransport] [d0hREp4] publish_address {10.0.1.30:9200}, bound_addresses {[::]:9200}
[2017-07-03T21:17:08,680][INFO ][o.e.n.Node ] [d0hREp4] started
[2017-07-03T21:17:08,713][INFO ][o.e.g.GatewayService ] [d0hREp4] recovered [0] indices into cluster_state
多くのログが吐かれますが、このようになれば起動しています。
自動起動の設定もしておきます。
$ sudo systemctl enable elasticsearch
動いているかローカルで確認してみます。
$ wget http://localhost:9200
$ cat index.html
{
"name" : "d0hREp4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "QIfUBpUkTvm8NdxRmlQERg",
"version" : {
"number" : "5.4.3",
"build_hash" : "eed30a8",
"build_date" : "2017-06-22T00:34:03.743Z",
"build_snapshot" : false,
"lucene_version" : "6.5.1"
},
"tagline" : "You Know, for Search"
}
大丈夫なようなので、VPNサーバからも確認してみます。
$ wget http://10.8.0.6:9200
$ cat index.html
{
"name" : "d0hREp4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "QIfUBpUkTvm8NdxRmlQERg",
"version" : {
"number" : "5.4.3",
"build_hash" : "eed30a8",
"build_date" : "2017-06-22T00:34:03.743Z",
"build_snapshot" : false,
"lucene_version" : "6.5.1"
},
"tagline" : "You Know, for Search"
}
VPNサーバに nginx でプロキシサーバを立てる
さて、最後にプロキシサーバを立てます。これで外部からVPNサーバのパブリックなIPアドレスにアクセスすると、ラズパイにクエリが転送されるようになります。
nginx をインストールします。
$ sudo apt-get install nginx
プロキシサーバの設定を書きます。XXX.XXX.XXX.XXX はVPNサーバのIPアドレスを入れてください。
server {
server_name XXX.XXX.XXX.XXX;
proxy_set_header Host $http_host;
location / {
proxy_pass http://10.8.0.6:9200;
}
}
nginx を再起動します。
$ sudo service nginx restart
Elasticsearch on ラズパイの完成です。
性能
Elasticksearch へのデータのバルクインサートは、AWS の t2.small.elasticsearch
で2分くらいかかっていたものがラズパイだと120分かかりました。インデックス作成がものすごく遅いのかな?search は2〜3倍遅いくらいなので実用はできています。
おわりに
ラズパイをサーバにするのは面白いですね。電気代も月50円もかからないようですし、スペースも取らないのでいろいろ設置したくなります。こんなのとか楽しそう。
あと、Raspberry Pi3 での設定方法を書きましたが、実際の運用は Asus Tinker board(CPU1.5倍速, メモリ2GB, ラズパイと同じ形なのでケースが使いまわせる) で行っています。ただこのボードはアメリカだと7,000円で買えるのですが、日本だと16,000円と割に合わないので Raspberry Pi3 の設定を書きました。
Asus Tinker Board 発売
Raspberry Pi3と同サイズで性能2倍のASUS製「Tinker Board」が国内発売
日本での公式な販売が決まったようです。
ラズパイと同様の手順で設定が可能ですが、OSがDebianなのでコマンドが少し変わります。
-
ifconfig
→/sbin/ifconfig
-
sudo service [サービス名] start
→sudo systemctl start [サービス名]
メモリが2GB搭載されているので Elasticsearch の使用メモリを1GBにします。
#-Xms2g
#-Xmx2g
-Xms1g
-Xmx1g