2016年12月25日日曜日

ConoHa Advent Calendar 25日目:ConoHa APIで、このはシンクライアントを試作する

 
どうも、島田です。今回は ConoHa アドベントカレンダーの最終日ということで適当に書きます。
思いっきりトリを取ってしまった訳ですが、多忙な時期をずらしたいねーということで適当にこの辺に入れた次第です。結局思惑外れてめっちゃ忙しいのですが。orz

今年のConoHa

今年はざっと振り返ると、機能追加というよりはサービス拡充が充実した一年だったかなと思います。

そんな中でも技術的にはまた次の展開が見えてきたような気がしますね。ブロックチェーンなんかも気になります(まだちゃんと調べていませんが)。ただ、ベースで使っている OpenStack のバージョンも結構上がっていますし、そろそろ次を期待....はできるのかな?というのはちょっと思っています。
ConoHaでたまに聞く欠点であるSSD容量の少なさと、VMプランの少なさを何らかの形でカバーできればいいのですが...。

ちなみに、今年の座敷わらしこと美雲このは先生とのやりとりはこんな感じでした。相変わらずのやりたい放題ですんません。



そんなこんなで相変わらずお世話になっています。ということで今年もちょっと ConoHa で遊んでみました的レポートをお届けします。


 本題:APIを使ってConoHaのVMをシンクライアント的に使ってみる(試作)

さて本題ですが、VPSの邪道な使い方としてLinux GUI環境を使うというのがあります。基本的にはあまりお勧めできないような使い方にも見えなくはないのですが、最近のConoHaはSSDやし回線もそこそこ強いので、それっぽいこともできなくはないでしょう。

その手段として、あらかじめGUI環境とVNC / RDPサーバをインストールして、起動しっぱなしにしておくといった使い方はよく見かけます。

 しかし、ConoHa API でVMの生成とか起動削除ができるのならば、VM立てっぱなしの必要の必要ないんじゃないか?とふと思いました。必要になったときにスクリプトを走らせれば、シンクライアント用のVMがスポーンしてすぐ使える(ついでに使った時間分だけ課金される)ってなれば面白いと思いませんか? (思う人はほぼ居ないと思いますが...)

ということでちょっと試作してみたいと思います。

 VMイメージの作成 : Xubuntu デスクトップ環境とxrdp

今回は時間がないので、あらかじめ GUI 環境と xrdp を仕込んで固めたイメージを作ることにします。普通にConoHa上で Ubuntu 16.04 (64bit) テンプレートを選択してVMを作成し、まずは一般ユーザを作成してパスワードをつけます。
# useradd -m -G adm,sudo shimada
# passwd shimada
次に以下のコマンドで、Xubuntu 同等のデスクトップ環境を一気にインストールしてしまいます。少し時間がかかります。
# apt-get update
# apt-get dist-upgrade
# apt-get install lightdm xubuntu-desktop gksu leafpad synaptic
# apt-get clean
これで再起動します。
# reboot
ここまで行って ConoHa コントロールパネル上のコンソールを見ると、Xubuntuのログイン画面が出ているのが判ると思います。

ConoHa上のコンソールに現れた Xubuntu ログイン画面
ログイン後の画面
そのままFirefoxを実行すればブラウジングできる。但し描画やマウス移動は遅い。

この時点でもログインして、Webブラウザとかで遊べてしまいます。しかし、これは Web ブラウザ上で、かつ NoVNC 上なので、シンクライアントするには速度も使い勝手も微妙だと思います。


次に、このVMに xrdp (RDPサーバ)をインストールします。この部分は、日本 xrdp ユーザ会さんの情報とかを基に、X11RDP-O-Matic インストーラを使用して導入します。

X11RDP-o-Matic を使って xrdp を導入します。
(Ubuntu 16.04なので、上記サイトの方法から若干アレンジしています。またbuildを行う
のでしばらく時間がかかります。)
$ git clone -b master https://github.com/scarygliders/X11RDP-o-Matic.git
$ cd X11RDP-o-Matic
$ sudo ./X11rdp-o-matic.sh --justdoit --branch v0.8 --cleanup
上記のコマンドが全自動でインストール後、若干の修正が必要です。
まず、systemd まわりが RedHat 系ぽい指定方法になっているので直す必要があります。

修正するファイルは以下のふたつの
/lib/systemd/system/xrdp-sesman.service
/lib/systemd/system/xrdp.service

以下の行を修正しましょう。
EnvironmentFile=/etc/sysconfig/xrdp



EnvironmentFile=/etc/default/xrdp
あとは変更を反映します。
$ sudo systemctl daemon-reload
RSAキーを生成しましょう。
$ cd /etc/xrdp/
$ sudo xrdp-keygen xrdp
xrdpを有効にして起動します。これでRDPで繋がるようになるはずです。一度繋いでみてログインまで確認するとよいかと思います。

$ sudo systemctl enable xrdp
$ sudo systemctl enable xrdp-sesman
$ sudo systemctl restart xrdp
$ sudo systemctl restart xrdp-sesman

ここまで環境構築を終えたら、VMを終了し、ConoHaのコントロールパネル「イメージの保存」を選択します。しばらくするとイメージリストに項目が現れるので、それを確認したら現在のVMを削除してしまいましょう。これで準備完了です。

ConoHa APIで全自動VM作成 + RDP接続をする(試作)

あとは ConoHa API との通信には Example でおなじみ curl コマンドと、json パーサである jq を使用し、下手なシェル芸を駆使して、VMの作成 -> 起動 -> IPアドレスを拾って FreeRDP (RDPクライアント) に接続させるといったことを全自動で行います。

...といっても、この辺のscriptはここに貼り付けると長いので、Gistに貼っておきました。これをダウンロードし、冒頭にある ConoHa APIのユーザ名、パスワード、テナントID、保存したイメージ名、起動するVMのプラン(フレーバー) 等を適当に設定して実行するといけると思います....が、突貫で作ったためエラーチェックをすっとばしている等、色々危ないスクリプトですので実行は凄く推奨できません。座敷わらしに侵入されても責任は負えません、参考程度にどうぞ。

こちらで実行してみると、約10分ほどで FreeRDPが起動し、さっきと同じように直ぐ Xubuntu デスクトップ環境が楽しめるようになります。RDPプロトコルですので、NoVNC と異なり、反応はそこそこ速いのが実感いただけるものと思います。

急ごしらえで書いたスクリプトを実行したところの画面。右のshellに、非表示にし忘れた curl コマンドのプログレス表示の一端が見える。

ログイン後 Firefox を実行したときの画面。よく見ると、グラテーションのようなものがかかったような減色後が見られることから、RDPの方で回線帯域に応じた最適化をかけていることが判る。

なお、VMの削除までは実装していないため、起動して遊んだらConoHa コントロールパネルからVMを削除しましょう


考察

 以上はあくまで駆け足での試作であり、実際に実用に使うには色々とハードルがあると思います。特にRDPポート(Port 3389)がそのまま開いているのは怖いので、本当はポートを閉じておい
て、SSH ポートフォワーディングなりVPNなりと併用した方がベターでしょう。

また、シンクライアントは回線帯域を使いまくるということも気をつけるべきでしょう。RDPサーバかクライアントの設定で色数を落としたり、解像度を下げたり圧縮率を上げるなどの対策を一通り取ることをおすすめします。

後はVMのイメージが少々大きいというのも解決すべき問題だと思います。今回試作したイメージは15GBありました。これを毎回展開ってなると正直しんどいので、X11RDP-o-Matic時の中間ファイルを削除するなどして、もっともっと削る必要があるでしょう。 後shutdown時にパスワードが聞かれる等、細かいチューニングも必要です。


と、課題だらけで座敷わらしに怒られそうではあるのですが、適当に書いたスクリプトで全自動で無から仮想シンクライアント環境が出来上がって、実際動くのは楽しいですね。手前味噌ですが僕自身は opencocon というシンクライアントLinuxディストリビューションを作ってるので、これを真面目に書けば、各種 VPN 同様にメニュー項目に入って必要事項を入力するか、設定ファイルに追記するだけで ConoHa上に VM ができて、シンクライアント環境がすぐできる、といったこともできるかもしれません。
 
後根本的な問題として、VPSでシンクライアントってどうなんって話はやはり否めません。しかしそれ専用のサービスは相変わらず高価であることが多いですので、諸々課題が解決さえできれば、選択肢のひとつとしてはありだと思ってはいます。





BTW:NGワードの意味

おっと、最後にもうひとつ。少し前にOSS関係者な方と、ConoHa ACのNGワードについて、もうその意味を知ってる人はもう多くないやろなーと話していたので、その意味について少しメモしておきます。

今でこそ、ConoHaとそのキャラクター的座敷わらしである美雲このは氏は純粋に清楚かわいいマーケティングをしているわけですが、初期からConoHaを使ってる人ならご存知の通り、昔のTwitterでのマーケティングはNGワードがよく似合う時期がありました。そんな頃のツイートを一部紹介しますとこんな感じです。



今はもう笑い話ですが、当時はこんなんじゃ技術的に優れて安価であっても、こんな宣伝じゃConoHa駄目なんとちゃうの、と批判する向きもありました。

ちなみに、そこらじゅうからツッコミを食らっていたのを逆手に取り、TechOYAJIなるイベントも開催していたことがあります。今から思えば、インフラ技術をご存知の方にConoHaを知ってもらうための手段としてのNGワードだったのかなとも思います。多分仕掛ける側でも色々ゴタゴタはあったかと思いますが...。

 そんな過去のモヤモヤがあるため、これからも清楚かわいい、かつ皆に遊んでもらえるサービスであり続けてもらうために、 このはがキャラ崩壊かな?という時には今でもNGワードを発動する用意があるわけです。ご理解いただければ幸いです。

さいごに

僕自身何年か仕事で OpenStack を触ってきたのですが、昔のバージョンはだいぶ不具合が多かったものの、ここ数年で(感覚としてはJuno辺りから..?)だいぶ安定してきたように思います。しかし、初期のConoHaはそれ以前のバージョンがベースだと考えると、多分最初の立ち上げは大変だっただろうなぁとなんとなく思いました。身を持ってOpenStackの大変さを感じた者として、ConoHaを支える技術屋の方に敬意を表します。

多分OpenStackってまだ発展途上で、今はまだまだできることの表面しか触ってないように思いますし、それに伴いConoHaも伸ばせるところはあるんじゃないかと思います。最初にも書きましたが、来年もおもろい展開を期待しています。



これで、ConoHa アドベントは閉幕...でしょうかね(〆たのは初めて)。皆様良いお年を。

2016年9月5日月曜日

OpenStack : お手軽にポートフォワーディングして、IPアドレスを有効活用する

訳あってこの頃OpenStackをちょくちょく触ることがあります。始めたばかりのときはIcehouseでしたので、結構不安定であり苦労しましたが、最近のLibertyとかMitakaは基本的な機能に目立った不具合もなく、なんとか使えるような感触になってきました。

それでも、実運用で現場に当ててみると、そのままではうまくいかない部分が少々あるため、Tips的に記事を出していければええのかなと思います。(ツッコミが怖いですが...)

とりあえず、ポートフォワーディングしたい

OpenStackのNeutronは通常、Floating IP等を用いて、インスタンスと外部ネットワークをグローバルIP等を用いてダイレクトに通信する仕組みを持っています。 実際の運用においてFloating IPをふんだんに使える環境であればこの仕組みは便利に機能するのですが、実際にはこうにはいかないケースが多いものと思います。中には、利用可能なグローバルIPはひとつだけ、という家庭のネット環境に近い実環境もあるかもしれません。

そんな場合、Neutron で router を作成してそこから通信する形になるのですが、そのままではインスタンスにWebサーバを立てたとしても、外部からそれにアクセスすることができません。 この点においては、現状のOpenStackでは外部->内部へのポートフォワーディングAPI等の仕組みがありません(後述)。

幸い、RDO等でインストールした普通(?)のNeutronでは、router でNAT的な処理を行う部分は、 Linux kernel の機能である iptables で行われていますので、そこにDNATルールを追加すればこの欠点を補うことができます。つまり、手動でポートフォワーディングをしてあげれば良い感じです。

この部分は通常の iptables では指定できず、namespace で区切られた部分のみとなりますので、例えばルールを追加するときは、例えば以下のようにコマンドを入れる必要があります。

※ 以下の例は、Neutronにrouterがひとつだけある場合を想定しています。2つ以上ある場合は、$(/sbin/ip netns|/usr/bin/grep qrouter) の部分を該当の qrouter 名に置き換えてください。

From : 外部ネットワーク (192.168.1.100:5001) -> 内部のインスタンス (192.168.50.11:22) とした

# ip netns exec $(/sbin/ip netns|/usr/bin/grep qrouter) iptables  -t nat -A PREROUTING -p tcp -m tcp --dport 5001 -d 192.168.1.100/32 -j DNAT --to 192.168.50.11:22

これだけで外部からの通信がポートフォワーディングされますが、この設定は reboot 等で消えてしまうため、保存する仕組みを作る必要があります。
手動では以下のコマンドで保存することができます。

# ip netns exec $(/sbin/ip netns|/usr/bin/grep qrouter) iptables-save > /etc/iptables-namespace

同じように復元するには以下のコマンドで行います。

# /sbin/ip netns exec $(/sbin/ip netns|/usr/bin/grep qrouter) /sbin/iptables-restore < /etc/iptables-namespace

ポートフォワーディングを起動時に自動適用したい

次に、このスクリプトをサーバ自体の起動時に自動的に反映されるようにします。なぜこれが必要なのかといいますと、何らかの原因で再起動が必要になった際に、設定を失ったり、手動での反映を失念するのを防ぎたいからです。

しかし、ただ systemd に仕掛ければよい訳ではありません。qrouter-* ネームスペースが生成されるのは起動シーケンスが見た目終了してしばらく後と大変遅く、仕掛けづらい状況です。いろいろ試行錯誤しましたが、Neutronの起動が完了したタイミングでもうまくいきません。 このため、今のところ systemd ファイルを以下のように書いてみます(抜粋です)。

( /usr/lib/systemd/system/openstack-namespace-iptables.service )


[Unit]

Description=Setup iptables on Linux namespace

DefaultDependencies=false

After=neutron-server.service



[Service]

Type=oneshot

ExecStart=/usr/local/bin/openstack-namespace-iptables restore

ExecStop=/usr/local/bin/openstack-namespace-iptables backup

TimeoutSec=60

RemainAfterExit=yes



[Install]

RequiredBy=multi-user.target



( /usr/local/bin/openstack-namespace-iptables )

#!/bin/sh



logfile="/var/log/iptables-namespace.log"

iptables_file="/etc/iptables-namespace"

iptables_backup_file="$iptables_file"



# Wait for standup namespaces (because always delay about 1 min).

while :

do

  namespace="$(/sbin/ip netns|/usr/bin/grep qrouter)"

  if [ "$namespace" ];

  then

    break;

  fi

  sleep 2

done

… (以下省略)

 本当は、このスクリプトはもっと改良の余地があると思います。qrouter-* namespace が見えるようになってから、という点を [Unit] の After= 以下に書ければいいのですが、その辺どうやるべきか思いつかず、こんな表現になってしまっています。 それでも、手元の環境ではある程度の確率(100%ではないのですが…)で自動的に namespace 内の iptables に反映できるようになるかと思います。

これらのScriptはダウンロードできるようにしましたので、参考にしていただければと思います。
CentOS 7 で実際に動かしています。

根本策?

根本的には、FWaaS側にポートフォワーディングの機能があり、APIで操作できればこのような手動設定を行う必要がなく、またHA構成であったり、バックエンドが iptables ではなく MidoNet 等の場合でもスムーズな対応を期待できるのですが、残念ながら blueprint に複数の要望が 上がってる程度で、まだ搭載までは至っていないようです。

...とここまで書いたところで再度調べてみたのですが、作業を行っていると思われるlaunchpadでは、最近少しづつではありますが実装作業が行われている(らしい)状況ですので、この Tips が将来不要になる日は来るかもしれません。