2015/02/23 平見知久
Dockerバージョンアップで動かなくなる
弊社では開発環境の一部にdockerを使っています。
さすがにインフラ系が絡む部分があるので準本番(ステージング)は仮想マシン直上に置きますが、開発や検証の場合、dockerによるスナップショットは開発・検証効率の向上にかなり効きます。
とはいえdockerもノートラブルというわけではないので焦ることもなくはないです。たまたま出くわしましたのでメモ兼ねてご紹介します。
OSはCentOS6、dockerはEPELの1.0を使っていて、「そろそろアップデートしとかないとな〜」といった軽いノリで、yum update docker-ioとか掛けてしまいました。
$ yum info docker-io Name : docker-io Arch : x86_64 Version : 1.0.0 Release : 6.el6 (略) Available Packages Name : docker-io Arch : x86_64 Version : 1.4.1 (略)
で、検証用のdockerコンテナを上げようとして、「あれ?docker動かないや…」
$ docker ps -a FATA[0000] Cannot connect to the Docker daemon. Is 'docker -d' running on this host?
1.0ではサービスはなかったはずなので、サービス上げればいいかな〜
$ service start docker Starting docker: [ OK ]
よしよし。これで動くかな?
$ docker ps -a FATA[0000] Cannot connect to the Docker daemon. Is 'docker -d' running on this host?
… あらぁ?
所詮開発環境ですので、実データ等が入ってるコンテナはないので最悪失われてもなんとかはなるのですが、されど開発環境。色々試行錯誤した内容がイメージとして残ってますので全部なくなったといった事態は避けたいところです..
落ち着いてまずログを見ます。
$ less /var/log/docker ... time="2015-02-17T13:02:05+09:00" level="info" msg="WARNING: You are running linux kernel version 2.6.32-504.8.1.el6.x86_64, which might be unstable running docker. Please upgrade your kernel to 3.8.0." time="2015-02-17T13:02:05+09:00" level="info" msg="Listening for HTTP on unix (/var/run/docker.sock)" /usr/bin/docker: relocation error: /usr/bin/docker: symbol dm_task_get_info_with_deferred_remove, version Base not defined in file libdevmapper.so.1.02 with link time reference
カーネル3.8.0以降を使えと言われてしまっています。CentOS6の標準カーネルは2.6で3.8はありません。docker1.4はカーネル3.8以降に依存するのか。さてどうしたものか…
案1: dockerのバージョンを戻す
案2: 言われてる通りカーネルのバージョンを上げる
案1の場合、dockerのバージョンダウンになりますので、ひょっとするとレポジトリの内容に影響が出る可能性が0ではないです。dockerホストは最悪ボロボロになってもまあ建て直せばOKですが、レポジトリが失われるのは避けたいところ。ということで、ホスト側でスナップショットで保険をかけて案2でいくことにします。
CentOS標準では3.8は提供されていませんが、困ったときのEPELということで、EPELから3.xのカーネルを取ってくることにします。
rpm -Uvh http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm sudo yum install --enablerepo=elrepo-kernel kernel-ml
起動時にカーネルを切り替えて、ホストを上げ直します。
# uname -ar Linux docker 3.19.0-1.el6.elrepo.x86_64 #1 SMP Mon Feb 9 11:00:58 EST 2015 x86_64 x86_64 x86_64 GNU/Linux
これでうまくいくといいな〜と思いつつ、dockerサービスを上げて、dockerコマンド叩いてみます。
$ docker ps -a FATA[0000] Cannot connect to the Docker daemon. Is 'docker -d' running on this host?
あらぁ。ダメっすか。再度ログを確認。 カーネルバージョン上げろというメッセージは消えましたが、dm_task_get_info_with_deferred_removeほにゃらというメッセージが出ていました。
time="2015-02-17T13:46:11+09:00" level="info" msg="+job serveapi(unix:///var/run/docker.sock)" /usr/bin/docker: relocation error: /usr/bin/docker: symbol dm_task_get_info_with_deferred_remove, version Base not defined in file libdevmapper.so.1.02 with link time reference
libdevmapper.so .. デバイスマッパーまわりということで、周辺モジュール絡みだな、と当たりをつけ、device-mapperをアップグレードしてみます。
# yum update device-mapper
docker はホストとコンテナでカーネルを共有する技術の関係上、カーネルとその周辺モジュール/コマンドまわりのバージョンについては比較的シビアなところがあります。dockerが出る前にdockerが使っているLXCという技術を直で触っていた時期があるのですが、こいつもカーネルと周辺モジュールのバージョンがかなりシビアで、組み合わせで動いたり動かなかったりということが結構ありました。
ハードウェアをエミュレーションする仮想化技術と異なり、仕組み上、カーネルのプロセス空間を分けたり分割したグループ毎にファイルシステムを分けたりしてますので仕方のない部分ではあります。その辺の動作原理をある程度把握していればトラブルシュート出来ますが、理解せずに動いたからいいやでいくと、今回みたいにバージョンアップではまったりということが往々にしてある技術であることは気をつけたいところです。
… ハマっといて言うのも格好悪いですが。
念のためリブートして、再度挑戦。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
なんとか動作するところまでこぎつけました。ホスト側のgrubをカーネル3.8で起動するように設定してとりあえずは復旧。やれやれです。
前述のとおりdockerではホストとコンテナでカーネルが共有されています。ホスト側のカーネルのバージョンを上げた場合、コンテナ側のカーネルも入れ替わることになります。
今回の場合コンテナ側で見た時にはこれまではカーネル2.6で動いていたのに対し、今後はコンテナもカーネル3.19で動く形になります。
厳密にはこの差異がアプリの動作に影響するかどうかについてはコンテナ毎に判断する必要がありますので動いて即OKとは一概には言えません。ただし、このホストで動かしているアプリについてはカーネルに依存するものが基本的にないことがわかっているため今回はこれでOK。この辺は動かしているアプリの特性・中身をきちんと把握しておかないと余計なリスクをしょいこむことになりますので注意したいところではあります。
さらに言えば弊社の場合、dockerの開発環境から即本番とすることはなく、一度仮想マシン直上のステージング環境で動作確認を取るようにしているのでこの辺の部分の影響はそこで弾くという考え方です。保険はかけつつ、開発効率はトップギアに持っていかないと時間いくらあっても足りませんからね。
まあ何はともあれ、作ったイメージ類救えてとりあえず一安心。といっても開発環境(それも仮想環境のホスト)とはいえCentOS6にカーネル3.xはちょっとアレですので、おとなしくCentOS7ベースにお引っ越しすることにしたいところ。さて、イメージのお引越しどうするかなぁ…
ということで続く..かもしれませんw