MattermostをOpenShift Enterprise 3.1.1上でインスタントアプリケーション化する
MattermostはSlackのようなWebベースのチームチャットツールです。GolangとReactで書かれています。
以下の一行でセットアップができるようになっています。Mattermost 1.4.0, MySQL 5.6でMySQLがPersistentVolume使います。コードはGitHubにあります。
oc new-app -f https://raw.githubusercontent.com/nekop/openshift-sandbox/master/apps/mattermost/mattermost.yaml
アクセスすると以下のように初期画面がでます。
このアプリケーションの定義ファイル(マニフェスト、とも呼ばれます)は200行程度です。route定義は含めていないのですが、oc expose svc mattermost
すればrouteができて環境に応じたURLが割り当たるはずなので、マニフェストには含めなくてもいいかなぁ、と思っています。
Mattermostはjson設定ファイルにデータベースの接続情報を持つので、DockerのENTRYPOINTに指定する起動シェルスクリプトで、環境変数からデータベースの接続情報をこのファイルに反映させる、という処理をする必要があります。
Mattermostはデータベースの接続情報の他にも設定項目はいっぱいあるのですが、デプロイ時に動的に変わるものはとりあえずデータベースの接続情報だけのような感じだったので、あとの設定はイメージに焼いてしまっていいかなーと思って環境変数化していません。というか50個くらいある設定項目を全部環境変数にしてしまうと環境変数ヘルと呼ばれるような状態になりますし、json書き換えるのも収集つかなくなると思います。他の設定項目を書き換えたかったらおとなしくイメージを再ビルドすることにします。ビルドはOpenShiftに投げるだけですしね。
これからのDocker対応アプリケーションでどのように設定を受け取るか、というのは結構重要なポイントかもしれません。とりあえずアプリケーションは設定を環境変数を受けとれるようにする、という機能は入れておいて欲しいですね。yamlやらjsonやらxmlの設定ファイルに環境変数を反映させるようシェルスクリプトで書き換えるのはかなりきびしい印象があります。また、外部から設定情報をフェッチする、という方法も考えたんですがDockerイメージの自己完結性が失われるのでかなりダメな感じがします。外部に置いてある設定ファイルを編集したら動いていたDockerイメージが動かなくなった、というのはちょっと勘弁してもらいたいシナリオです。DockerイメージはDocker環境で完結する情報だけで動作すべきでしょう。
今回Mattermostのインスタントアプリケーションを作る手順は以下のような感じでした。
Dockerfile
を書いてgit push
- ベース作成のために
oc new-app
oc new-app <git clone url>
oc export
してベースにするyaml生成oc export dc,is,bc,svc -o yaml --as-template=mattermost > mattermost.yaml
- import時に省略できる設定も明示的にexportされてしまうので(ポータビリティ考えるとまぁそうだよね感)、そのへんは消す。dancer-exampleが結構最小に近いようなので参考にした。
oc get template dancer-example -n openshift -o yaml
- アプリケーション名を
APPLICATION_NAME
パラメータにして作成時にカスタマイズできるようにするmattermost
を${APPLICATION_NAME}
に置換して最終部パラメータにAPPLICATION_NAME
を定義
- MySQLを追加する。mysql-persistentのテンプレートからobjectsとparametersを抜き出してそのままmattermost.yamlにつなげる
oc get template mysql-persistent -n openshift -o yaml
- MySQLのパラメータをmattermostのDeploymentConfigにも渡すようにする
- mysqlのDeploymentConfigのenvをそのままコピー
- 設定ファイルにデータベース接続情報を反映させて起動する
mattermost-launch.sh
を作成してDockerfile
のENTRYPOINT
にする
いくつか参考になるテンプレート、シェルスクリプトやDockerfileを把握しておけば1時間程度でできるかな、という雰囲気です。
WildFly 10.0.0.Final リリースしました
Java EE 7アプリケーションサーバであるWildFly 10.0.0.Finalがリリースされました。WildFlyのサイトからダウンロードできます。
リリースノートはこちら。起動時間は僕の手元で1.6秒でした。
09:53:17,610 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 10.0.0.Final (WildFly Core 2.0.10.Final) started in 1606ms - Started 267 of 553 services (371 services are lazy, passive or on-demand)
ハイライトとしては以下のような感じです。
- Java EE 7
- Java 8以降
- Java 7では動作しません
- JMS実装がActiveMQ Artemisに
- UndertowでサーバサイドJavaScript
ActiveMQ ArtemisはHornetQがActiveMQに合流してできた新しいメッセージングミドルウェアです。このような合流はJavaミドルウェアだと以前にXML WebServicesでCeltixとXFireが合流してApache CXFができた、というのがありますね。
Java EE 7の商用サポート版であるJBoss EAP 7はこのWildFly 10をベースにエンタープライズ版になるためのエンジニアリングがされてリリースされる予定です。JBoss EAP 7のリリース予定日はまだ公式には未発表ですが、今までのリリースの傾向からするとたぶん今年の前半には出るんじゃないかなーという感じです(非公式見解です、内部リリース予定情報は見ないで書いています)。Red Hat Summitも6月にありますし。
OpenShiftのsource-to-image (s2i)をすごく簡単に説明するよ
この投稿はOpen PaaS Advent Calendar 2015の16日目の記事です。
OpenShiftにはソースコードからDockerイメージをビルドするs2iという仕組みがあります。ドキュメントを見ると煩雑な印象を受けるかもしれませんが、実はとっても簡単です。
単体のs2i
s2iはgithubなどのソースコードのURL、s2i builder imageを受け取って、Dockerイメージを作成するソフトウェアです。以下実行例ですがそのまんますぎて説明のしようがないくらいです。openshift/ruby-20-centos7というs2i builder imageを使ってtest-ruby-appというDockerイメージをビルドしています。
s2i build git://github.com/pmorie/simple-ruby openshift/ruby-20-centos7 test-ruby-app docker run --rm -i -p :8080 -t test-ruby-app
s2i builder image
s2i builder imageはs2iスクリプトが入っていて、ラベルが付いているだけのDockerイメージです。ぶっちゃけ以下のラベル付けるだけでs2i builder imageの要件は満たせます。
LABEL io.openshift.s2i.scripts-url=image:///usr/libexec/s2i
s2iはこのs2i builder imageのラベルからs2iスクリプトの場所を読み込み、実行してその結果のイメージを出力のDockerイメージとするだけです。s2iをマニュアルでやるとするとdocker run
してs2iスクリプトをキックしてdocker commit/tag
する、というイメージです。
OpenShiftでのsti-builderイメージ
OpenShiftではopenshift-sti-builder
とかorigin-sti-builder
などのイメージが提供されていますが、これらはs2i builder imageではありません。ややこしいですね、すみません。
これは実際には最初に説明した「単体のs2i」をOpenShift環境上で行うDockerイメージ、つまりOpenShift版s2iです。openshift-sti-buildコマンドというs2iを実行するコマンドが入っていて、OpenShift上ではs2iはこのイメージで実行しています。
stiだったりs2iだったり
同じです。最初stiだったんですけど途中でs2iにしようぜってことになったんですが全部修正されているわけではないので表記が混ざっています。熟練したOpenShift使いには同じに見えるはずです。
まとめ
OpenShift専用ホスティングサービス正式開始しました
OpenShift Dedicatedというお客様専用のOpenShiftをホスティング提供するサービスが正式開始しました。
OpenShift DedicatedはRed Hatがセットアップしてメンテナンスも提供するので、お客様は利用するだけ、というモデルになっています。AWS上全リージョンで提供されるので東京リージョンでも利用できます。
BASEパッケージではアプリケーションノードとして4ノード、24時間サポートつき、という内容です。アプリケーションノードはm4.xlargeで、4vCPU 16GB memoryです。master, etcd, router, docker registryは5ノードHAで構成しています。
興味がある方はお問い合わせフォームか、電話であれば0120-266-086へどうぞ。僕に直接連絡してくれてもたぶん大丈夫です。
OpenShift Origin v1.1 開発Vagrant環境を構築する
この投稿はOpen PaaS Advent Calendar 2015の14日目の記事です。
以前OpenShift Origin v3の最新版を試す - Vagrantで構築編とOpenShift Origin v3の最新版を試す - 利用編という2つの記事を書きましたが、7月時点のものでありバージョンはv1.0系でした。現時点ではv1.1系なので、内容をアップデートしておきます。
このエントリはOpenShiftをソースコードからビルドしてStandaloneモードで動作させる方法です。開発やデバッグなどの目的で動作させる方法ですので、通常の運用する形態のものを動作させたい場合はインストーラーでインストールするopenshift-ansibleとVagrantでOpenShift Origin v1.1のAll-in-one環境を構築するのほうを参照してください。
Fedora 23でのVagrant libvirtのセットアップまでのステップはVagrantで構築編から変更はありませんが、古いfedora_instイメージを持っている場合は一度削除して更新したほうが良いです。現時点でのイメージの最終更新日時は12/10になっています。
vagrant box remove fedora_inst
v1.1のコンパイルには前回記述した2GBのメモリでは足りなくなっています。4GBを割り当てましょう。vagrant ssh
すると、以前はホームディレクトリが/data/src/github.com/openshift/origin
になっていましたが、現在は/home/vagrant
になっています。今回は前回は省略したルーターのセットアップ手順も入れておきました。
git clone https://github.com/openshift/origin/ cd origin cat <<EOF >.vagrant-openshift.json { "cpus": "4", "memory": "4096" } EOF vagrant up vagrant ssh cd /data/src/github.com/openshift/origin/ make clean build # hack/build-go.sh took 258 seconds on my laptop sudo systemctl start openshift cat ./examples/image-streams/image-streams-centos7.json | oc create -n openshift -f - echo '{"kind":"ServiceAccount","apiVersion":"v1","metadata":{"name":"registry"}}' | oc create -f - echo '{"kind":"ServiceAccount","apiVersion":"v1","metadata":{"name":"router"}}' | oc create -f - (oc get scc privileged -o yaml -n default; echo "- system:serviceaccount:default:registry"; echo "- system:serviceaccount:default:router") | oc replace -f - sudo `which oadm` registry --config=/openshift.local.config/master/admin.kubeconfig --credentials=/openshift.local.config/master/openshift-registry.kubeconfig --service-account=registry sudo `which oadm` router --config=/openshift.local.config/master/admin.kubeconfig --credentials=/openshift.local.config/master/openshift-router.kubeconfig --service-account=router
これで一通り動作するOpenShiftができあがります。
OpenShiftでアプリケーションプロセスを殺してみる
この投稿はOpen PaaS Advent Calendar 2015の13日目の記事です。
OpenShift / Kubernetesではプロセスやコンテナのモニタリングが行われているので、煮たり焼いたり殴ったり殺したりしてもすぐ復旧するらしいのでやってみましょう。
材料はhello-sinatraさんです。
$ oc new-app https://github.com/nekop/hello-sinatra
とりあえずpsすると、アプリケーションであるrubyのプロセスが見えます。DockerのENTRYPOINTやで起動されるものはpid 1で起動します。これはコンテナプライマリプロセスと呼ばれます。
$ oc exec hello-sinatra-1-wznjc -- ps -eaf UID PID PPID C STIME TTY TIME CMD 1000030+ 1 0 0 05:51 ? 00:00:00 ruby /opt/app-root/src/bundle/ruby/bin/rackup -E production -P /tmp/rack.pid --host 0.0.0.0 --port 8080 1000030+ 75 0 0 06:17 ? 00:00:00 ps -eaf
まずはシンプルにkill
してみましょう。SIGTERMです。
$ oc exec hello-sinatra-1-wznjc -- kill 1 $ oc exec hello-sinatra-1-wznjc -- ps -eaf error: error executing remote command: Error executing command in container: container not found ("hello-sinatra") $ oc exec hello-sinatra-1-wznjc -- ps -eaf UID PID PPID C STIME TTY TIME CMD 1000030+ 1 0 38 06:18 ? 00:00:00 ruby /opt/app-root/src/bundle/ruby/bin/rackup -E production -P /tmp/rack.pid --host 0.0.0.0 --port 8080 1000030+ 25 0 0 06:18 ? 00:00:00 ps -eaf $ curl http://hello-sinatra-test.apps.192.168.100.100.xip.io/ hello
一瞬Pod内のコンテナが居なくなっていますが、すぐ再起動されているようです。Startup timeが変化しました。Podは変化していません。SIGKILLでもまぁ同じ感じになります。
サスペンドしてみましょう。Ctrl-zとかで送られるSIGTSTPです。
$ oc exec hello-sinatra-1-wznjc -- kill -TSTP 1 $ oc exec hello-sinatra-1-wznjc -- ps -eaf UID PID PPID C STIME TTY TIME CMD 1000030+ 1 0 38 06:18 ? 00:00:00 ruby /opt/app-root/src/bundle/ruby/bin/rackup -E production -P /tmp/rack.pid --host 0.0.0.0 --port 8080 1000030+ 25 0 0 06:18 ? 00:00:00 ps -eaf $ curl http://hello-sinatra-test.apps.192.168.100.100.xip.io/ hello
まったく効きませんね。
oc delete pod
でpodを潰すとPodのIDが新しくなりますが、killと特に違いはありません。
$ oc delete pod $(oc get pod | grep Running | head -n1 | awk '{print $1}') pod "hello-sinatra-1-d0b4c" deleted $ oc exec $(oc get pod | grep Running | head -n1 | awk '{print $1}') -- ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 1000030+ 1 19.5 1.2 117492 23764 ? Ssl 06:38 0:00 ruby /opt/app-root/src/bundle/ruby/bin/rackup -E production -P /tmp/rack.pid --host 0.0.0.0 --port 8080 1000030+ 21 0.0 0.0 19764 1168 ? Rs 06:38 0:00 ps aux
アプリケーションがハングしたような状態はどうなるでしょうか。
実は、ハングのチェックはデフォルトで有効になっていないため、特にそのままでは自動的に検知して再起動したりはしません。Deployment Configのspec.containersの下のコンテナ定義にlivenessProbeを加えることでモニタリングを有効化できます。
spec: containers: (省略) livenessProbe: httpGet: path: / port: 8080 scheme: HTTP initialDelaySeconds: 15 timeoutSeconds: 12
アプリケーションを変更して100秒スリープするというよく寝る子にして再度ビルドとデプロイを行います。
$ oc delete pod $(oc get pod | grep Running | head -n1 | awk '{print $1}') $ vi app.rb $ git commit -am 'sleep 100' && git push $ oc start-build hello-sinatra
少し放置プレイしておいてoc get pod
を見ると9分で6回再起動されているので、上の設定と合わせて考えるとlivenessProbeの実行は60秒くらいのインターバルがありそうです。このあたりは後でもう少しつっこんで調べようと思います。
$ oc get pod NAME READY STATUS RESTARTS AGE hello-sinatra-5-yugu3 1/1 Running 6 9m
OpenShiftのシステムログを見てみると、以下のようなログが出ていました。
[vagrant@ose3-master ~]$ sudo journalctl -n10000 | grep Live | grep -v refuse Dec 15 01:58:48 ose3-master.example.com origin-node[21405]: I1215 01:58:48.913911 21405 prober.go:105] Liveness probe for "hello-sinatra-5-yugu3_test:hello-sinatra" failed (failure): Get http://10.1.0.26:8080/: read tcp 10.1.0.26:8080: use of closed network connection Dec 15 02:00:18 ose3-master.example.com origin-node[21405]: I1215 02:00:18.913822 21405 prober.go:105] Liveness probe for "hello-sinatra-5-yugu3_test:hello-sinatra" failed (failure): Get http://10.1.0.26:8080/: read tcp 10.1.0.26:8080: use of closed network connection Dec 15 02:01:48 ose3-master.example.com origin-node[21405]: I1215 02:01:48.913582 21405 prober.go:105] Liveness probe for "hello-sinatra-5-yugu3_test:hello-sinatra" failed (failure): Get http://10.1.0.26:8080/: read tcp 10.1.0.26:8080: use of closed network connection Dec 15 02:03:18 ose3-master.example.com origin-node[21405]: I1215 02:03:18.914962 21405 prober.go:105] Liveness probe for "hello-sinatra-5-yugu3_test:hello-sinatra" failed (failure): Get http://10.1.0.26:8080/: read tcp 10.1.0.26:8080: use of closed network connection Dec 15 02:04:48 ose3-master.example.com origin-node[21405]: I1215 02:04:48.913876 21405 prober.go:105] Liveness probe for "hello-sinatra-5-yugu3_test:hello-sinatra" failed (failure): Get http://10.1.0.26:8080/: read tcp 10.1.0.26:8080: use of closed network connection
今回の実験はここまで。
OpenShiftでCrashLoopしているPodのログを見る
この投稿はOpen PaaS Advent Calendar 2015の10日目の記事です。
OpenShiftでおもむろにnginxをデプロイしてみます。
$ oc new-app nginx # official "nginx" docker image on docker hub
oc get all
してみますが、CrashLoopBackOffという状態になっていて稼働していないようです。RESTARTSが3になっていて増加していってるようです。
$ oc get all NAME DOCKER REPO TAGS UPDATED nginx library/nginx 1.7.10,latest,1 + 19 more... About a minute ago NAME TRIGGERS LATEST nginx ConfigChange, ImageChange 1 CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE nginx-1 nginx library/nginx@sha256:0a8bad8dfc80e38ccdd09c41d4efd2547fa9d6d58d8706431952a2ef312e2034 app=nginx,deployment=nginx-1,deploymentconfig=nginx 1 1m NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE nginx 172.30.126.189 <none> 80/TCP,443/TCP app=nginx,deploymentconfig=nginx 2m NAME READY STATUS RESTARTS AGE nginx-1-0khqs 0/1 CrashLoopBackOff 3 1m
back offというのは意図的に待っている状態で、この場合は再起動のインターバルを待っている状態です。docker pull待ちのDockerPullBackOffというのもあります。
oc logs
でログを見てみましょう。
$ oc logs nginx-1-0khqs Error from server: Internal error occurred: Pod "nginx-1-0khqs" in namespace "test": container "nginx" is in waiting state.
コンテナが現在稼働していないのでログが取れないと言われてしまいました。困りましたね。
このような場合、--previous
というオプションを指定することで、前回のログを見ることができます。
$ oc logs --previous nginx-1-0khqs nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied) 2015/12/15 05:08:11 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2 2015/12/15 05:08:11 [emerg] 1#1: open() "/var/log/nginx/error.log" failed (13: Permission denied)
Permission deniedですね。OpenShiftでPermission deniedが出ている場合は大抵USERが指定されているか、もしくはUSERを指定しておらずrootでの動作を前提としてしまっているイメージです。
OpenShiftではuser IDで権限を制御する部分があるので、USERによるユーザ名指定はデフォルトで禁止されており、動的にユーザIDが割り当たるようになっているため、上記のようなイメージはこのようなパーミッションエラーを引き起こします。詳しい説明はイメージガイドラインのSupport Arbitrary User IDsのところに記述されています。
ちなみにUSER、USER未指定rootの利用を許可する設定もできます。
oc logs --previous
はKubernetes由来のもので、kubectl logs --previous
というコマンドなのですが、どちらもぐぐってもほとんど情報が出てこないという謎の隠しコマンド状態です。なんででしょうね。レアポケモンの紹介でした。
追記: 初出時に「USERの指定がされているためエラーになった」旨で記載していましたが、実際にはnginxのイメージは「USERの指定がされていない、かつ実行時root前提のためエラーになった」というものだったので修正しました。