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前提のためエラーになった」というものだったので修正しました。
openshift-ansibleとVagrantでOpenShift Origin v1.1のAll-in-one環境を構築する
この投稿はOpen PaaS Advent Calendar 2015の9日目の記事です。
openshift-ansibleとVagrantでOpenShift Origin v1.1を構築するでは3台構成のOpenShiftを構築しましたが、ちょっと試すだけなら3台も要らないよね?ってことで1台の構成を作ってみましょう。1台であればメモリももうちょっと割り当てられますし。
手順は前回とほぼ同じなのですが、vagrant up
の前にこの環境変数をexportしておきます。
export OPENSHIFT_NUM_NODES=0
0という指定は若干奇妙ですが、masterノードのみセットアップします。masterは実際にはnodeサービスも同居して動作しているので、All-in-one構成として利用可能です。masterのnodeサービスはschedulable=falseになっているので、trueに変更したまま運用します。
vagrant up --provider=libvirt --no-provision vagrant provision vagrant ssh master sudo oadm manage-node ose3-master.example.com --schedulable=true sudo oadm registry --selector=kubernetes.io/hostname=ose3-master.example.com --credentials=/etc/origin/master/openshift-registry.kubeconfig --service-account=registry sudo oadm router --selector=kubernetes.io/hostname=ose3-master.example.com --credentials=/etc/origin/master/openshift-router.kubeconfig --service-account=router sudo vi /etc/origin/master/master-config.yaml # Change the subdomain value as follows: # subdomain: "apps.192.168.100.100.xip.io" sudo systemctl restart origin-master
これで1台構成のOpenShiftができあがりますので、そのまま遊べます。
openshift-ansibleとVagrantでOpenShift Origin v1.1を構築する
この投稿はOpen PaaS Advent Calendar 2015の8日目の記事です。
OpenShiftにはopenshift-ansibleというインストーラーのプロジェクトがあり、Vagrantと組み合わせて簡単にOpenShiftの実行環境が構築できるようになっています。VagrantでのセットアップについてはREADME_vagrant.mdに記述されています。
デフォルトの設定では以下の3台構成のOpenShiftができあがります。
192.168.100.100 ose3-master.example.com 192.168.100.200 ose3-node1.example.com 192.168.100.201 ose3-node2.example.com
これを自分の4 CPU cores, 12GBメモリのラップトップで構築してみましょう。Fedora 23でのVagrant libvirtのセットアップまでのステップはVagrantで構築編を参照してください。
openshift-ansibleではansibleとvagrantのvagrant-hostmanagerプラグインが必要ですので、それらもインストールします。
sudo dnf install ansible -y vagrant plugin install vagrant-hostmanager
CPUやメモリの設定はVagrantfileにハードコードされていますが、多少控え目に定義してあって実際に利用するとつらい感じになりやすいので、cloneした後に若干増やしておきます。
- libvirt.cpus = 2 - libvirt.memory = 1024 + libvirt.cpus = 4 + libvirt.memory = 2048
vagrant up
のときに--no-provision
を忘れずにつけましょう。忘れると1ノード時点でprovisionがはじまってしまうのでやり直すはめになります。
vagrant provision
を実行するとAnsibleによるインストールがはじまるので、結構時間がかかります。
git clone https://github.com/openshift/openshift-ansible/ cd openshift-ansible vi Vagrantfile # modify cpus and memory if needed vagrant up --provider=libvirt --no-provision vagrant provision
マルチノード構成なので、masterノードで作業します。
vagrant ssh master
oc get node
を実行すると3台構成となっているのがわかります。
oc get node NAME LABELS STATUS AGE ose3-master.example.com kubernetes.io/hostname=ose3-master.example.com Ready,SchedulingDisabled 26m ose3-node1.example.com kubernetes.io/hostname=ose3-node1.example.com Ready 26m ose3-node2.example.com kubernetes.io/hostname=ose3-node2.example.com Ready 26m
docker registryとrouterを作成しましょう。3台くらいの構成ではmasterにregistryとrouterを稼働させるのが一般的です。デフォルトでschedulable=falseとなっているので、このときだけtrueに変更します。
sudo oadm manage-node ose3-master.example.com --schedulable=true sudo oadm registry --selector=kubernetes.io/hostname=ose3-master.example.com --credentials=/etc/origin/master/openshift-registry.kubeconfig --service-account=registry sudo oadm router --selector=kubernetes.io/hostname=ose3-master.example.com --credentials=/etc/origin/master/openshift-router.kubeconfig --service-account=router sleep 120 # docker pullがどのくらいの時間で終わるのかは環境依存なので、目視確認したりsleep調整したりしてください sudo oadm manage-node ose3-master.example.com --schedulable=false
master-config.xmlのsubdomainにxip.ioを記述しておくとアプリケーションもそのままアクセスできるようになるので設定しておきましょう。
sudo vi /etc/origin/master/master-config.yaml # Change the subdomain value as follows: # subdomain: "apps.192.168.100.100.xip.io" sudo systemctl restart origin-master
これでmaster上での作業は終わりです。あとはVagrantホストからリモートで利用できます。
vagrant-hostmanagerプラグインによって、vagrantホストの/etc/hosts
エントリも追加されるので、ブラウザでWebコンソールにアクセス可能になっています。オレオレTLSなので警告が出ます。
https://ose3-master.example.com:8443/console/
認証はAllowAllが設定されているので、適当なユーザ名と空ではないパスワードで認証が通るようになっています。
ブラウザアクセスだけではなく、ocコマンドももちろん利用できます。masterからocコマンドを取ってきて実行すれば良いです。
vagrant ssh master -- cat /usr/bin/oc > oc chmod +x ./oc ./oc version ./oc login ose3-master.example.com
さて、プロジェクトを作成してアプリケーションを放り込んでみましょう。
./oc login ose3-master.example.com --username=nekop ./oc new-project test ./oc new-app https://github.com/nekop/hello-sinatra ./oc expose service hello-sinatra
oc get all
で状態を確認すると以下のように見えます。
./oc get all NAME TYPE FROM LATEST hello-sinatra Source Git 1 NAME TYPE FROM STATUS STARTED DURATION hello-sinatra-1 Source Git Running 2 minutes ago 2m48s NAME DOCKER REPO TAGS UPDATED hello-sinatra 172.30.90.98:5000/test/hello-sinatra NAME TRIGGERS LATEST hello-sinatra ConfigChange, ImageChange 0 NAME HOST/PORT PATH SERVICE LABELS INSECURE POLICY TLS TERMINATION hello-sinatra hello-sinatra-test.apps.192.168.100.100.xip.io hello-sinatra app=hello-sinatra NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE hello-sinatra 172.30.44.105 <none> 8080/TCP app=hello-sinatra,deploymentconfig=hello-sinatra 2m NAME READY STATUS RESTARTS AGE hello-sinatra-1-build 1/1 Running 0 2m
ビルドが終われば、http://hello-sinatra-test.apps.192.168.100.100.xip.io
にアクセスすることでアプリケーションが稼働していることを確認できます。
年末調整メモ
年末調整ってなんであんなに書きにくいフォーマットなんだろうね?IT化自動化してほしい。
自分は都民共済(生命保険と介護保険の2つに分かれる)と学資保険が子供2人分なので、生命保険のエントリが4つ、介護保険のエントリが2つ。支払の主体としては自分と奥さんのお財布の区別はないので、自分と奥さんの年末調整、どちらにでも書いていいはず。学資保険の額が大きいので、学資保険を自分と奥さんに振り分けて書く。あとはどっちに書いても控除額は増えないので、自分にまとめて書く。
住宅ローンがある場合は10年分の住宅借入金等特別控除申告書が手元にあるはずなので、残高証明書を元に記入する。
年末調整に向けて届く書類は、保険の支払証明が2通(2社分)、残高証明書、年末調整書類。あとは保管してある住宅借入金等特別控除申告書で、必要書類が揃う。こういうの毎年何いるんだっけ?ってなる。
全部書いたら一応全部写真を取って返送する。
OpenShiftにGogsをセットアップする
インターナルでWebhookが使えるGit hostでhttpしゃべるものが欲しかったのだけど、社内のGitがhttpsなのでフロントエンドでプロキシするか別のGit hostを、ということで気になっていたGogs試してみた。この人ボストンで学生やってるっぽいんだけどめちゃめちゃコード書いててすごい。
private docker registryの時と同じくRunAsAny設定が必要。
oc new-project gogs oc new-app gogs/gogs oc expose dc gogs --port=3000 --name=gogs-http oc expose se gogs-http
http://gogs-http.gogs.tkimura.shift
にアクセスするとセットアップ画面が出るので、httpのURLがデフォルトでlocalhost
になっているのをこのサーバに修正しておしまい。そのあとログイン画面に遷移するけど、最初に作ったユーザがadminになるので普通に登録してログインすればいい。tkimura.shift
は自分のDNSに設定しているオレオレOpenShiftドメイン名。
あとはぽちぽちリポジトリ作ってgit clone http://gogs-http.gogs.tkimura.shift/nekop/first.git
して動いたのでOK。
Gogsは3000と22の二つのポートがexposeされているので、3000のほうを別のServiceにしてRouteを作る。oc expose se gogs
とやってしまうとHTTPとSSHにロードバランスされて面白いことになる。
Dockerの不要なコンテナとイメージを削除する
変なgrepしてたりコマンド置換$(...)
使ってdocker rmから引数ないぞ警告でちゃうような微妙なサンプルが多かったので、自分のバージョンをメモ。
/etc/cron.daily/docker-cleanup
に置いて日次実行にしてます。たまにマニュアルで叩いてたりもします。
#/bin/bash docker ps -q -f status=exited | xargs --no-run-if-empty docker rm docker images -q -f dangling=true | xargs --no-run-if-empty docker rmi