背景
オフィス内で一時的に作ったSkypeメッセージをSlackへ投げつけるプログラムが、(人為的な)停電の度に落ちるのでそろそろコンテナ化してオフィス外に出そうかと思う。
現状
Xvfbに対してSkypeが立ち上がりDBus経由でSkype2Pyのスクリプトがメッセージを抜き取ってSlack APIへ転送する仕組み。
準備
久々のboot2dockerなのでupgradeからスタート
$ boot2docker upgrade
Backing up existing docker binary...
Downloading new docker client binary...
Success: downloaded https://get.docker.com/builds/Darwin/x86_64/docker-latest
to /usr/local/bin/docker
The old version is backed up to ~/.boot2docker.
Backing up existing boot2docker binary...
Downloading new boot2docker client binary...
Success: downloaded https://github.com/boot2docker/boot2docker-cli/releases/download/v1.5.0/boot2docker-v1.5.0-darwin-amd64
to /usr/local/bin/boot2docker
The old version is backed up to ~/.boot2docker.
Latest release for boot2docker/boot2docker is v1.5.0
Downloading boot2docker ISO image...
Success: downloaded https://github.com/boot2docker/boot2docker/releases/download/v1.5.0/boot2docker.iso
to /Users/hac/.boot2docker/boot2docker.iso
1.5になった。
Slack側にSkypeからのメッセージを受け付けるチャンネルの作成と、APIのトークン発行を行っておく。
Dockerfileを書く
$ mkdir skype2slack
$ cd skype2slack
$ nano Dockerfile
極度のeeかnanoファンである
FROM debian:stable
# debconfにnon-interactiveモードであることを教える
ENV DEBIAN_FRONTEND noninteractive
# i386アーキテクチャのものも追加する
RUN dpkg --add-architecture i386
# 必要なパッケージをまずは導入
RUN apt-get update
RUN apt-get -y install x11vnc xvfb fonts-takao openbox wget
# Skypeをダウンロード
RUN wget http://download.skype.com/linux/skype-debian_4.3.0.37-1_i386.deb
# 依存性を無視してSkypeをとりあえずインストール
RUN dpkg -i skype-debian_4.3.0.37-1_i386.deb || true
# 不足している依存パッケージのインストール
RUN apt-get -fy install
# Skype4Pyとpyslackを準備
RUN apt-get -y install python python-pip git
RUN pip install Skype4Py
RUN pip install requests
RUN pip install pyslack
# skype2slackスクリプトを配置
ADD skype2slack.py /
RUN mv /skype2slack.py /root
# x11vncにパスワードを設定
RUN mkdir /root/.vnc
RUN x11vnc -storepasswd [パスワード] /root/.vnc/passwd
# タイムゾーンとロケールを設定
RUN localedef -v -c -i ja_JP -f UTF-8 ja_JP.UTF-8 || :
RUN echo "Asia/Tokyo" > /etc/timezone
RUN dpkg-reconfigure -f noninteractive tzdata
# 起動スクリプトを押し込める
ADD startup.sh /
RUN mv startup.sh /root
ENTRYPOINT ["/bin/bash"]
CMD ["/root/startup.sh"]
EXPOSE 5900
起動スクリプトはこちら
# /bin/bash
rm -f /tmp/.X1-lock
rm -fr /tmp/.X11*
rm -fr /tmp/*
rm -fr /root/.Xauthority
# なぜか自分のMacでは数秒待たないと消えない
sync; sync; sync;
sleep 3s
# 他の環境では問題なかった
Xvfb :1 -extension GLX -screen 0 1024x768x24 &
x11vnc -display :1 -bg -usepw -forever
DISPLAY=:1 /usr/bin/openbox-session &
DISPLAY=:1 XAUTHORITY=/root/.Xauthority python /root/skype2slack.py &
DISPLAY=:1 skype
Skypeは結構ウインドウをバカスカ開いてユーザーに確認をさせる場面があり枠がついてないとそのウインドウを消すことも移動することも出来なくなる。なのでウインドウマネージャとしてopenboxを入れてみることにした。
あとロケールについてはUTF-8のマップねえよ!と怒られるがみなさんなぜか入れているようなので真似しただけ。。。
もし利用する方いらっしゃれば x11vncのパスワードをお好きに決めて下さいな。
skype2slack.pyを配置
そして、Dockerfileと同じディレクトリにskype2slack.pyを配置する
# coding: utf-8
import os
import time
import requests
import Skype4Py
import slack.chat
def handler(msg, event):
slack.api_token = os.environ["SLACK_TOKEN"]
channel = os.environ["SLACK_CHANNEL"]
print "Event %s: %s" % (event, msg)
if (event == u"RECEIVED") or (event == u"SENT"):
slack.chat.post_message(channel, msg.Body, username=msg.FromDisplayName)
def main():
time.sleep(10)
skype = Skype4Py.Skype(Transport='x11')
skype.OnMessageStatus = handler
skype.Attach()
while True:
time.sleep(1)
requests.packages.urllib3.disable_warnings()
if __name__ == "__main__":
main()
まずはsleepで10秒待ちが入る。これはSkypeより先にこのスクリプトを起動させているから。
そののち"RECEIVED"と"SENT"イベントの場合にSlackにメッセージを投げつける。
Slack API用のトークン(SLACK_TOKEN)とチャンネル(SLACK_CHANNEL)はコンテナ起動時の環境変数として受け渡しを期待している。
requests.packages.urllib3.disable_warnings()
を呼んでいる箇所だが、pyslackモジュールが内部でrequestsを使っていて、通信中常時Warningを吐きまくるのを抑制している
イメージをビルドする
$ docker build -t skype2slack:latest .
長い・・・長すぎるよ
タバコが3本とコーヒーもいける
まずは1回目の起動
$ docker run -p 5900:5900 -e SLACK_TOKEN="xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXXX" -e SLACK_CHANNEL="#skype-proxy" skype2slack:latest bash /root/startup.sh
トークンとチャンネルを環境変数で渡して起動する
$ boot2docker ip
192.168.59.103
早速、Macから vnc:://192.168.59.103 で接続すると先のDockerfileで指定したパスワードを求められるので入力すると?
うまく起動しているようだ。
Skypeアカウントにサインインするにあたり、自動ログインをチェックするのを忘れずに。
この状態まで進めることが出来たら、まずコンテナを止めてイメージをコミットしておく。
Skypeの認証情報の保存が目的だ。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
930ce7c5f3d7 skype2slack:latest "bash /root/startup. 4 minutes ago Up 4 minutes 0.0.0.0:5900->5900/tcp pensive_galileo
$ docker stop 930ce7c5f3d7
930ce7c5f3d7
$ docker commit 930ce7c5f3d7 skype2slack-run:latest
033784851a53c77f49d4ecffdebf7a087cd54c7f6c152f0f37d1c7661e0df493
これで skype2slack-run:latest という名前でコミット出来た。
2回目の起動
先ほどコミットした skype2slack-run:latest を起動する。
$ docker run -p 5900:5900 -e SLACK_TOKEN="xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXXX" -e SLACK_CHANNEL="#skype-proxy" skype2slack-run:latest /bin/bash /root/startup.sh
この2回目の起動では Skypeに対してskype2slack.pyが接続を要求してくるはずだ。
「この選択を記憶する」にチェックを入れて「はい」を選択する。
以下の画面からSkype4PyがSkypeと繋がったことを確認できる。
さぁ、またここまでの状況をコミットしておこう。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ceb3f3b96ab skype2slack-run:latest "/bin/bash /root/ About a minute ago Up About a minute 0.0.0.0:5900->5900/tcp trusting_mcclintock
$ docker stop 5ceb3f3b96ab
5ceb3f3b96ab
$ docker commit 5ceb3f3b96ab skype2slack-run:latest
101643e8d66983e2dd2c22481a10aca822fed9d74a105b9bf2b520f856e66809
本番稼働
$ docker run --rm -p 5900:5900 -e SLACK_TOKEN="xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXXX" -e SLACK_CHANNEL="#skype-proxy" skype2slack-run:latest /bin/bash /root/startup.sh
長かった。
メッセージをSkypeアカウントに送りつけると自動的にSlackのチャンネルに転送されるようになった。
Slack側のアイコン等もSkype的にすると混乱しなくて宜しいかも。
ちなみに動いている最中のstatsはこんな感じ。
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O
93664c636361 11.19% 121.4 MiB/1.961 GiB 6.05% 359.3 KiB/718.5 KiB
思ったよりヘビーだなぁ。
最後に
今回、DockerでSkypeをやってみたけどもGUIでしか設定出来ない部分はどうしようも無さそうで運用対応としてしまったのは心残りだ。
あと理由は分からないが、起動スクリプトの先頭にあるrmコマンドがうまく動かない場合があるのか、起動したりしなかったりする。
ロックファイルが消えないとXが立ち上がらずエラーになってしまうのだがこれはboot2dockerだけの問題なのだろうか?
(多い時は20回くらい失敗して起動)
と思って社長のMacbook Air(Docker 1.3)でやってる分にはこの問題は出ないので自分の環境だけだと思われる。
そして、このskype2slackスクリプトでは全てのメッセージを拾いきれて無いらしい(社内談)
ログ的にどんなイベントが拾えてないのか分かってないのでこれもまた判明次第記事更新しようと思う。
hubot側にも流してみればメッセージの違いがわかったりするかもしれない。