aufs を使った一般ユーザ権限で起動するコンテナ
LXC ではコンテナのクローンを行う際に色々なストレージバックエンドの特徴を生かしたスナップショットクローンを行えます。この辺りは 連載の第 19 回〜 22 回 辺りで詳しく解説しています。
今まで、非特権LXCコンテナでストレージバックエンドの特徴を生かしたスナップショットクローンは、btrfs か overlayfs でしか行えませんでした。
先日、私の送ったパッチで aufs を使ったスナップショットクローンが一般ユーザ権限でもできるようになりました。
- aufs: Support unprivileged clone, mount · lxc/lxc@31a882e · GitHub
- Support unprivileged ephemeral container using aufs · lxc/lxc@dc80aa9 · GitHub
前者は liblxc 側の変更で lxc-clone や lxc-start 側で関係するパッチ、後者は lxc-start-ephemeral コマンドに関係するパッチです。
これで一般ユーザでも aufs を使った非特権クローンとコンテナが起動できるようなりました。簡単に紹介しておきます。
Plamo 5.3.1 に aufs パッチを当てた 4.1.1 カーネルを使っています。
$ lsb_release -d Description: Plamo Linux release 5.3.1 $ uname -r 4.1.1-plamo64-aufs
最近の aufs では allow_userns というモジュールオプションを Y にすると User Namespace 内の特権ユーザが aufs をマウントできるようになります。マニュアルにも記載があります。
私も手元では以下のように設定しています。
$ cat /etc/modprobe.d/aufs.conf options aufs allow_userns=1
こんな一般ユーザで操作しています。
$ id uid=1000(karma) gid=100(users) groups=100(users),26(audio),28(dialout),29(video),32(cdrom),36(kvm),38(pulse),39(pulse-access),44(mlocate),47(libvirt),60(docker),1000(sudo)
まず、普通に dir バックエンドを使ったコンテナを作成します。以下がその config の rootfs の設定。
$ grep lxc.rootfs ~/.local/share/lxc/ct01/config lxc.rootfs = /home/karma/.local/share/lxc/ct01/rootfs
このコンテナのクローンを作成します。
$ lxc-clone -o ct01 -n aufs01 -s -B aufs Created container aufs01 as snapshot of ct01 $ lxc-ls -f NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------- aufs01 STOPPED - - - NO ct01 STOPPED - - - NO
クローンは成功しています。
$ grep lxc.rootfs ~/.local/share/lxc/aufs01/config lxc.rootfs = aufs:/home/karma/.local/share/lxc/ct01/rootfs:/home/karma/.local/share/lxc/aufs01/delta0
こんな感じに aufs を使うコンテナのルートファイルシステムの定義がされています。
起動してみます。Plamo では cgmanager とか systemd-logind とかないので、起動前には自分で一般ユーザ権限の cgroup を作成して、現在のシェルの PID を登録してから起動しています。
$ lxc-start -n aufs01 -d $ lxc-ls -f NAME STATE IPV4 IPV6 GROUPS AUTOSTART ------------------------------------------------------ aufs01 RUNNING 10.0.100.179 - - NO ct01 STOPPED - - - NO
無事起動しましたね。
なぜ今 aufs ?
以上が動きと機能の紹介でした。でも、overlayfs がカーネルにマージされた今、なぜ aufs なのか? ってところですが...
色々なファイルシステムを扱う場合は特権が必要となります。例え User Namespace を使った Namespace 内の特権であっても、ファイルシステムをマウントできなかったりします。
User Namespace 内の特権ユーザがファイルシステムをマウントするには、カーネル内でファイルシステムのフラグに "FS_USERNS_MOUNT" というフラグが指定されている必要があります。(参考: overlayfs と LXC 非特権コンテナの snapshot によるクローン - TenForwardの日記)
このフラグ、4.1.1 カーネルで指定されているファイルシステムを調べてみると
$ find fs/ -type f | xargs grep FS_USERNS_MOUNT fs/devpts/inode.c: .fs_flags = FS_USERNS_MOUNT | FS_USERNS_DEV_MOUNT, fs/proc/root.c: .fs_flags = FS_USERNS_MOUNT, fs/ramfs/inode.c: .fs_flags = FS_USERNS_MOUNT, fs/sysfs/mount.c: .fs_flags = FS_USERNS_MOUNT, fs/namespace.c: if (!(type->fs_flags & FS_USERNS_MOUNT)) {
最後の (fs/namespace.c) は関係ないので devpts, proc, ramfs, sysfs だけです。この辺りはマウントできないとそもそも非特権のシステムコンテナが起動できなかったりするので指定されていて当然という気がしますね。つまり普通のファイルシステムはこれがそもそも指定されていないわけです。
overlayfs もこのフラグは指定されていません。なのに LXC で非特権 overlayfs がサポートされているのはなぜか? という話ですが、これは Ubuntu のカーネルにパッチが当たっているからです。パッチがあたっていないバニラカーネルだと当然これは失敗します。
$ lxc-clone -o ct01 -n overlay01 -s -B overlayfs clone failed
私の使っている 4.1.1 の overlayfs には特に何の変更も加えていないので、このように失敗します。
一方、aufs はカーネルにはマージされていないものの、最新の aufs が使える環境では素の aufs で User Namespace 内の特権ユーザが aufs をマウントできるわけです。この辺りからでしょうか。
まあ、パッチの量の大小の差はあるにせよ、overlayfs も aufs もバニラカーネルにパッチを当てないと非特権コンテナでは使えないわけで、なら aufs の非特権コンテナサポートを追加することで少しでも非特権コンテナのサポートする範囲が広がれば良いかなと思ってパッチを作りました。
あ、ちなみに Ubuntu のカーネルに当たっている aufs は古いバージョンなので、allow_userns は使えない模様です。Ubuntu は aufs 止めちゃうみたいですものね。
ま、LXC の overlayfs 周りとかは以前もパッチ送ったことがあってコードをよく知ってたので、非特権 aufs 対応はさほど難しくないって分かってたから作ったんですけどね。(^_^;)
シェルスクリプトで書かれた軽量コンテナ MINCS がすばらしい (1)
これはだいぶ前に書いたエントリです。MINCS作者による最新の解説があるのでそちらもご覧ください。 (2016-11-21追記)
コンテナは使いたいけど、たくさんコンテナを起動すると結局それぞれのコンテナに対するセキュリティアップデートなどのメンテナンスは必要だし、コンテナ内独自のプログラムやライブラリ以外はホストと共有したいよね、って話が出てきたりします。みんな考えることは同じで、bind mount を使えば良いよね、って話はでてきてました。
- こないだもブログで紹介した kazuho さんの jailing
- 私が LXC でも結構簡単にできるよ、っていう提案を兼ねて作った lxc-bind
- こないだのLinuxConでもDockerでたくさんのオプションを並べて、色々工夫して bind mount を使ってやってる発表もありました (Using Docker for existing installed OS and applications, running half inside half outside the container ながっ)。
この LinuxCon のセッション中に、ホストと色々共有しつつ (*) 簡単にコンテナ環境を作成できる、シェルスクリプトで書かれたコンテナ実装を知りました。これが @mhiramat さんの MINCS です。セッション中に早速軽く見て、これは素晴らしいってことで帰ってから少し調べたりしていました。
(*) ホストと共有しないこともできそうです。
どうやってコンテナを作っているか
MINCS がコンテナを作成する方法のキモは以下の 3 つかと思います。
- unshare コマンドと ip netns コマンドで Namespace を作成
- overlayfs の下層側 (lowerdir) にホストの / (ルート) を使い、コンテナディレクトリをマウント
- pivot_root でコンテナの / に移動
なのでキモの部分だけ抜き出すと
mount -t overlayfs ... pivot_root ... ip netns unshare -iumpf ...
の 3 行になってしまうシンプルさ(*)!! これだけでも素晴らしいのですが、これだけではコンテナ環境はできないので、それまでに色々細かい処理をやっています。その処理がシェルスクリプトなので簡単に追っていけるので、それも素晴らしいです。
(*) 実際は pivot_root を複数回行って chroot します。
軽くおためし
MINCS を使える環境は比較的新しい環境になります。それは、unshare コマンド (util-linux パッケージに入っています) でキチンと Namespace を作るには比較的新しい環境が必要なのと、カーネルが overlayfs をサポートしている必要があるためです (Ubuntu であれば 12.04 辺りからパッチ適用で overlayfs が使えます。ただし util-linux は古いです)。unshare は README.md にもあるように 2.24 以上が必要です。
(話はそれますが unshare コマンドについて少し:MINCS では使ってませんが、User Namespace をきちんと使おうとすると 2.26 が必要そうです。2.24 -> 2.25 間に便利なオプションが追加されてますが、2.26 にならないとちゃんと動きません --map-root-user。2.24 で追加されている --mount-proc も便利そう。)
私は Ubuntu 15.04 上で試しました。
インストールは git clone して、付属の install.sh を実行するだけです。/usr/local 以下に入ります。
一番簡単に使うには
$ sudo minc /bin/bash root@mincs01:/#
こんな感じになります。README.md に書かれていないオプションもあるので確認しましょう。
$ minc --help /usr/local/bin/minc - Run given command in a temporary namespace Usage: /usr/local/bin/minc [options] <command> [argument...] options: -h or --help Show this help -k or --keep Keep the temporary directory -t or --tempdir <DIR> Set DIR for temporary directory (imply -k) <UUID> Reuse UUID named container -r or --rootdir <DIR> Set DIR for original root directory <UUID> Use UUID named container image -X or --X11 Export local X11 unix socket -n or --net Use network namespace -c or --cpu <mask> Set CPU mask -p or --pty Assign new pty for the container --name <NAME> Set <NAME> as container's name (hostname) --user <USER>[:GROUP] specify user and group (ID or name) to use --simple Simple chroot model (do not pivot_root) --usedev Use devtmpfs for /dev (for loopback etc.) --debug Debug mode
ホスト名が付いていたほうが分かりやすいので --name を付けてみましょう。
$ sudo minc --name container /bin/bash root@container:/# hostname container
コンテナの中を少し見てみると、
root@container:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.5 22512 5240 ? S 19:58 0:00 /bin/bash root 48 0.0 0.2 18480 2636 ? R+ 19:59 0:00 ps aux
PID Namespace も分離されているようですし、
root@container:/# cat /proc/mounts overlayfs / overlay rw,relatime,lowerdir=/,upperdir=/tmp/minc1300-WwY7qz/storage,workdir=/tmp/minc1300-WwY7qz/work 0 0 tmpfs /dev tmpfs rw,relatime 0 0 devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0 udev /dev/console devtmpfs rw,relatime,size=496816k,nr_inodes=124204,mode=755 0 0 udev /dev/null devtmpfs rw,relatime,size=496816k,nr_inodes=124204,mode=755 0 0 udev /dev/zero devtmpfs rw,relatime,size=496816k,nr_inodes=124204,mode=755 0 0 mqueue /dev/mqueue mqueue rw,relatime 0 0 proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0 proc /proc/sysrq-trigger proc ro,nosuid,nodev,noexec,relatime 0 0 proc /proc/irq proc ro,nosuid,nodev,noexec,relatime 0 0 proc /proc/bus proc ro,nosuid,nodev,noexec,relatime 0 0 sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
/ は確かに overlayfs でマウントされているようですし、/proc 以下のヤバいファイルは Read-only でマウントされているようですね。
Network Namespace も分離するには -n か --net オプションを付けます。
$ sudo minc --net --name container /bin/bash root@container:/# ip a 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 4: vminc1369: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 6a:d9:17:92:bb:9a brd ff:ff:ff:ff:ff:ff
一応、veth ペアも作られて、コンテナに片方が割り当てられているようですね。アドレスは割りあたってませんし、ホスト側も
$ ip a :(snip) 3: veth1369: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 56:00:fe:13:93:28 brd ff:ff:ff:ff:ff:ff
という感じで作っただけという感じなので、その辺りはなんとかする必要はありそうです。
bind mount を使ったお気軽 LXC コンテナのススメ
お手軽に軽量な隔離環境を作るための kazuho さんの jailing とか、それにリソース管理の仕組みを加えた matsumotory さんの virtualing いいですね。
コンテナほどの隔離性は不要だし、一々イメージを落としてきて構築とかやるにはちょっと重たいなというシーンもあるわけで、そういう時に chroot、bind mount はお気軽で良いですし、それに cgroup でのリソース管理を加えてもそんなに重くはなりません。(docker だと他にも色々考えないとダメだし)
こういうのを思いついてサクッと作れてしまう才能がうらやましいわけですが、LXC を使えば才能がない私でも、何かをサクッと作る能力も努力もなく、もう少し隔離度を上げつつある程度の軽さを残した環境を LXC を使って作れますので、ここで紹介しましょう。
LXC 使っちゃったら、前述の軽さがなくなるから意味ないやんって話ですが、LXC ならコンテナ用のファイルシステムを作らずに bind mount を使ってコンテナを起動するのも簡単ですので、環境を作る手間のお手軽さと、bind mount を使ってホストのシステムを共用するというお手軽さは残して環境構築が可能です。
そもそもコンテナって、単に clone システムコールを使ってプロセス起動するだけなので、そんなに重くはならないでしょう、というお話です。もちろん LXC はそれ以外に色々やるので chroot に比べたら重いんですけどね。
bind mount を使った軽量(?)コンテナ
LXC にはコンテナ起動時にコンテナ用に何かをマウントするための設定があります。ここでホストのディレクトリやファイルを bind mount するだけで、ホストのシステムの一部をコンテナにエクスポートできます。
例えばホストの /usr をコンテナでそのまま使う場合、以下のように書けばそれでコンテナ起動時にマウントしてくれます。
lxc.mount.entry = /usr usr none ro,bind 0 0
つまり
- コンテナ用 rootfs 以下にディレクトリを作る (bind mount するにはマウントポイントないとダメですね)
- LXCの設定を書く
- lxc-startコマンドでコンテナ起動
これで jailing と同じような隔離環境が得られます。
LXC から cgroup を使うのも設定ファイルに制限値を設定すれば良いので、virtualing 相当の操作も可能ですね。
テンプレートを使って bind mount を使ったコンテナを作成する
言葉で書くと簡単ですが、ディレクトリを作ったり、設定ファイルを作ったりを手でやってると面倒で、jailing のお手軽さにかなうわけもありません。
そこで作ってみました。
LXC でコンテナを作る時は lxc-create コマンドにテンプレートを指定して作成します。その lxc-create に指定できるテンプレートファイルです。
$ sudo lxc-create -t bind -n (コンテナ名)
みたいにすれば、必要なディレクトリと設定ファイルを作成してくれます。
私の作った lxc-bind は決め打ちのところが多いです。そこはシェルスクリプトで書かれてるお気軽さですので、適当に変えてもらうということで。
もともと LXC には lxc-sshd というテンプレートが付属していて、これはまさしくコンテナのファイルシステムのほとんどをホストのディレクトリを bind mount して、sshd だけが起動するコンテナを作るテンプレートです。lxc-bind はこれを少し変えただけです。
jailing の例にあった /usr/local/apache/httpd を起動するコンテナを作るのも、
$ sudo lxc-create -t bind -n apache01 \ -- --bind=/usr/local/apache \ /usr/local/apache/bin/httpd \ -c /usr/local/apache/conf/httpd.conf $ sudo lxc-start -n apache01
ってな感じで簡単です (試してませんが :-p)。もちろん、作成したあとは起動させないとダメですので、jailing よりは実行するコマンドは増えます :-p
テンプレートに渡す引数なしで
lxc-create -t bind -n test01みたいに実行すると bash を実行するコンテナを勝手に作ります。他に dhclient を実行して勝手に eth0 にアドレスも割り当てます (lxc.network.ipv4 みたいな設定で静的に割り当てることも可能)。
実行例
$ sudo lxc-create -t bind -n test01 $ sudo cat /var/lib/lxc/test01/config lxc.network.type=veth lxc.network.link=lxcbr0 lxc.network.flags=up lxc.rootfs = /var/lib/lxc/test01/rootfs lxc.utsname = test01 lxc.pts = 1024 lxc.cap.drop = sys_module mac_admin mac_override sys_time lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed lxc.mount.entry = /etc/rc.d etc/rc.d none ro,bind 0 0 lxc.mount.entry = /etc/ssl/certs etc/ssl/certs none ro,bind 0 0 lxc.mount.entry = /dev dev none ro,bind 0 0 lxc.mount.entry = /run run none ro,bind 0 0 lxc.mount.entry = /bin bin none ro,bind 0 0 lxc.mount.entry = /sbin sbin none ro,bind 0 0 lxc.mount.entry = /usr usr none ro,bind 0 0 lxc.mount.entry = /lib lib none ro,bind 0 0 lxc.mount.entry = /lib64 lib64 none ro,bind 0 0 lxc.mount.entry = /var/lib/lxc/test01/init sbin/init none ro,bind 0 0
作成するとこんな感じに。
$ sudo lxc-start -n test01 $ sudo lxc-ls -f test01 NAME STATE IPV4 IPV6 GROUPS AUTOSTART ----------------------------------------------------- test01 RUNNING 10.0.100.41 - - NO $ pstree :(略) |-lxc-start---init.lxc-+-bash | `-dhclient :(略) $ sudo lxc-attach -n test01 -- ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 17272 596 ? S 11:28 0:00 /usr/sbin/init.lxc -- /bin/bash root 18 0.0 0.0 18984 6852 ? Ss 11:28 0:00 /usr/sbin/dhclient eth0 -cf /dhclient.conf -v root 19 100 0.0 20264 3144 ? R 11:28 12:00 /bin/bash root 21 0.0 0.0 16612 2624 ? R+ 11:40 0:00 ps aux
起動してますね。コンテナ内は bash と dhclient が動いています。
コンテナ内のマウントの様子を見てみると
$ sudo lxc-attach -n test01 -- cat /proc/mounts :(略) /dev/root /etc/rc.d ext4 ro,relatime,data=ordered 0 0 /dev/root /etc/ssl/certs ext4 ro,relatime,data=ordered 0 0 /dev /dev tmpfs ro,relatime,mode=755 0 0 /dev/root /run ext4 ro,relatime,data=ordered 0 0 /dev/root /bin ext4 ro,relatime,data=ordered 0 0 /dev/root /sbin ext4 ro,relatime,data=ordered 0 0 /dev/root /usr ext4 ro,relatime,data=ordered 0 0 /dev/root /lib ext4 ro,relatime,data=ordered 0 0 /dev/root /lib64 ext4 ro,relatime,data=ordered 0 0 /dev/mapper/LXCVG01-LXCLV01 /sbin/init btrfs ro,relatime,space_cache 0 0 :(略)
lxc.mount.entry で設定した辺りは上記でしょうかね。
ruby-lxc を使って同じようなことをやる
LXC には ruby-lxc というものがあって、これでスクリプトを書けば同じようなことが比較的簡単にできます。これをやるのが
です。シャレで作っただけなのでこれを使おうと思わないでください。^^;
こっちは --bind みたいなオプションも未実装なので使えないと思います。コンセプト作と思ってください。(ruby-lxc を使ってみたかっただけ)
$ sudo ruby lxcing /bin/bash
まとめ
延々とわけのわからないことを書きましたが、何が言いたいかというと、LXC お手軽だからもっとみんな使いましょう、ってことです。
おまけ
LXC 使っちゃうとまあ色々プロセス起動したり、ファイルシステム色々扱ったりするので、声を大にして「軽いぞ!!」とは言えない気もするのですが、libcontainer とか libct とか使ったら bind mount して気軽に隔離環境作るプログラムってすぐ作れないかな? 誰か作るといいですね。
4.0.2 kernel と非特権コンテナ
(2015-06-11 追記) 以下の問題は 4.0.5 カーネルで解決しています。
手元 (Plamo 5.3) では 4.0.2 カーネルで LXC の非特権コンテナを起動するとカーネルが固まります。その時のログは以下です (netconsole 経由で取ったので見にくい)。
4.0.2 でマージされたコミットのうち、以下を revert するとお亡くなりにはならなくなります (副作用は知りません)。
あまり関係する人はいないかもしれませんが、非特権コンテナを使う場合はとりあえず 4.0.1 までを使っておくのが良さそうです。
- mnt: Honor MNT_LOCKED when detaching mounts
- mnt: Fix the error check in __detach_mounts
- mnt: Update detach_mounts to leave mounts connected
とりあえず lxc-devel には「誰か同じような現象に遭遇した?」とメール投げてみましたが...
(2015-05-12 追記)
mainlineからstableへ適用すべきパッチが2つほど抜けていたようです。4.0.3 で直るのかな?
以下の 2 つのパッチを適用すると LXC 非特権コンテナが問題なく動作し、カーネルがハングアップする事もなくなります。
- mnt: Fail collect_mounts when applied to unmounted mounts
- fs_pin: Allow for the possibility that m_list or s_list go unused.
(2015-05-14 追記)
4.0.3 がリリースされていますが、上記のパッチは適用されていません。
(2015-05-18 追記)
4.0.4 がリリースされていますが、上記のパッチは適用されていません。
lxd を使ったライブマイグレーション (2)
このエントリの情報はおそらく古いです
前のエントリ はネットワークの設定なしで行いましたが、そこに veth でホストと通信可能なネットワークの設定を行って試しました。一度で書けよって内容ですが :-p
まず非特権コンテナで veth が使える設定を行います (多分必要)。LXC の設定です。/etc/lxc/lxc-usernet で "ubuntu" ユーザが 10 個 veth ペアを作成可能なようにしました (lxcbr0 を使用)。両方のホストで行っています。
$ cat /etc/lxc/lxc-usernet # USERNAME TYPE BRIDGE COUNT ubuntu veth lxcbr0 10
前のエントリ で作成した profile である "criu" にネットワーク設定を追加します。両方のホスト共変更します。
name: criu config: raw.lxc: | lxc.tty = 0 lxc.console = none lxc.cgroup.devices.deny = c 5:1 rwm security.privileged: "true" devices: eth0: nictype: bridged parent: lxcbr0 type: nic
これでコンテナを起動し、コンテナにアドレスを割り当てます。
$ lxc start ct01 $ lxc exec ct01 -- /sbin/dhclient eth0 $ lxc list +------+---------+-----------+------+ | NAME | STATE | IPV4 | IPV6 | +------+---------+-----------+------+ | ct01 | RUNNING | 10.0.3.77 | | +------+---------+-----------+------+
割り当たったのでマイグレーションします。
$ lxc move lxd01:ct01 lxd02:ct01 $ lxc list +------+-------+------+------+ | NAME | STATE | IPV4 | IPV6 | +------+-------+------+------+ +------+-------+------+------+ $ lxc list lxd02: +------+---------+-----------+------+ | NAME | STATE | IPV4 | IPV6 | +------+---------+-----------+------+ | ct01 | RUNNING | 10.0.3.77 | | +------+---------+-----------+------+
移動しましたね。
(追記)
lxd02 上で
$ lxc exec ct01 -- apt-get install micro-httpd $ lxc exec ct01 -- sh -c 'echo "LXD Test" | tee /var/www/index.html' $ curl http://10.0.3.77/ LXD Test
としておいて、lxd01 上で以下のように実行すると、ちゃんとマイグレーションされてますね。
$ lxc move lxd02:ct01 lxd01:ct01 $ curl http://10.0.3.77/ LXD Test
一度、まずマイグレーションした後である程度コンテナイメージが同期された状態で、特に何もファイルを更新しない状態でマイグレーションしてもそれなりにダウンタイムありますね。
(さらに追記) 1秒おきに date コマンドの結果を出力するスクリプトを回してマイグレーションするとこんなことも。結構時間かかりますね。それほどコンテナ上のファイルは (手では) 変更していません。
Wed Apr 15 10:06:12 UTC 2015 Wed Apr 15 10:06:13 UTC 2015 Wed Apr 15 10:07:31 UTC 2015 Wed Apr 15 10:07:32 UTC 2015
Wed Apr 15 10:09:53 UTC 2015 Wed Apr 15 10:09:54 UTC 2015 Wed Apr 15 10:10:14 UTC 2015 Wed Apr 15 10:10:15 UTC 2015