蚊帳の中の日記

ゆるく生きてます

Dockerコンテナの/var/lib/docker/overlay配下の容量が大きくなって起動できない事象に遭遇したので周辺知識を調べた。

業務でとあるサーバー上のDockerコンテナが立ち上がらなくなってしまう事象に出会った。 原因を先にいうと、Dockerコンテナ内のvar/lib/docker/overlay配下の容量が肥大化してコンテナのデータ容量が100%になってしまっていた。 色々やって結局先輩エンジニア方が解決してくれたんだけど「そもそもoverlayって何?」って感じで調べたら、この間勉強したLPICの内容も少し絡んでいて面白かったのでまとめてみた。

原因

先程も書いたが、今回の事象の原因は、var/lib/docker/overlayの容量が大きくなってしまって、データ領域が足りなくなりコンテナが立ち上がらなくなってしまっていた。*1

overlayって何?

で、「overlayってなんぞ?」となったのだけど、やっぱり公式を見るのが一番ということで調べてみたら、DockerのドキュメントにoverlayFS driverというのがあった。

docs.docker.com

overlayFSのTL;DR

Dockerイメージはread onlyなlayerを束ねたものなんだけど、それらlayer(一つ一つがファイルシステム)のデータ情報などはoverlayFSという技術を使って管理されている。*2 overlayFSの実態は/var/lib/docker/overlayもしくは/var/lib/docker/overlay2配下に集約されていて、一度システムを読み込んでしまえば、キャッシュによるシステム起動も早くなるし、iノードの節約にも繋がって容量がエコになるらしい。

概要を自分用にまとめたのが以下。

  • DockerのoverlayFileSystem(以降、overlayFSと略す)はDockerコンテナ上のデータ領域やイメージの情報を管理するファイルシステムのこと。
  • OverlayFSという技術自体はDocker特有の物というよりもシステム関連の技術っぽくて、こちらの記事が簡単なまとめをしてくださっていてわかりやすかった。既存で存在しているaufsというものの類似技術で、複数のシステムのファイルとかディレクトリなどを階層構造上に持ち、それぞれを透過的に重ねてマージして一つのシステムとして管理できるシステムのことを言うみたい。
  • overlayFSはxfsをサポートしている。LPICにも出てくるのだけど、xfsはシステム操作をjournalに保存する仕組みになっているファイルシステム。つまり、システム操作ログなどはjournalctlコマンドで見れる。
    • まあ、正直ふーんという感じだけど、Dockerの公式ドキュメントのイメージ画像がわかりやすかった。
    • aufsよりも早くて実装がシンプルらしい。aufsをよく知らないからふーんという感じだけど、まあすごいみたい。
  • ちなみに現状はoverlayoverlay2の2つのバージョンがあり、自分のコンテナのがどっちを使っているかはdocker infoで見れる。

    f:id:kayamelo151515:20191031225325p:plain
    https://docs.docker.com/storage/storagedriver/overlayfs-driver から拝借

  • 「階層構造上に持つ」とは具体的には、一つのLinuxホストにupper dir, lower dirという2つのディレクトリ構造を持っていて、その2つを統合した(mergedディレクトリという構成になっている。このmergedされたのが一つのシステムとしてマウントされてるらしい。ちなみに、このディレクトリをlayerと呼んでいる。

  • で、この階層構造の実態は/var/lib/docker/overlayで、ここにlayerが保存されている。つまり今回はこのlayerが肥大化したのが原因と言い換えられる。
    • lower dir: 読み込み専用
    • upper dir: 書き込み可能
    • merged: 上2つを統合したレイヤ。効率的なマウントポイント。
  • この機能によって何が嬉しいのか?と言うと、Dockerドキュメントにはよると、docker buildやdocker commitなどのレイヤー関連のDockerコマンドのパフォーマンスが向上し、ファイルシステムで消費するiノードが少なくなる。
    • ちなみにiノードLPICでも習った。*3
    • パフォーマンス向上に関しては、一度mergedされたファイルを読み出してしまえば、システムがキャッシュを使ってくれるので、次からの起動が早くなるということらしい。
    • iノードについては、merged layerにあるシステムのiノードに、残りのlower dir, upper dirにあるシステムがハードリンクがされている。ハードリンクされているということはiノードが同じなので、layerが増えてもmerged layerにあるノードだけで済んでiノードの節約ができるという原理みたい。*4
    • ちなみに、df -iでiノードの利用状況を確認することができる。

dockerで触ってたときに、モヤモヤしてた所が少しわかった

ここまでまとめて見て、いままでdockerを触っていたときにモヤモヤしていた所が少しだけ分かってきた気がした。

確かにdocker pullとかしたとき、

$ docker pull centos
latest: Pulling from centos
f1b103484249: Pull complete
23456d61e65: Pull complete
12322fbe74aa5: Already exists
centos:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:as334436c65123532ecb7bb790b1db0279668d3763c3b81f31bc6c4e60eooa112
Status: Downloaded newer image for centos:latest

みたいに複数のハッシュ値みたいなのがログに出ていたけど、これがそれぞれlayerっぽい。なるほどな〜。 ちなみに、このlayerたちはdocker imageの履歴としてdocker historyで確認できる。

で、結局今回の問題はどうやって対処したか?

docs.docker.com

ドキュメントに不要なオブジェクトの排除方法みたいなのが載っていた。

forums.docker.com

他にも同じような事象になる質問があって、これらにある情報と同じ感じで先輩エンジニアが docker container prune overlayで対処してくれて、事なきを得た。

対処後の疑問

この後に「layerがどんどん増えていったら、また将来的にoverlayが肥大化しちゃうから、うまい具合にoverlayを自動で消してくれないかな」とか思ったけど、ドキュメントをよく見ると、

Docker takes a conservative approach to cleaning up unused objects (often referred to as “garbage collection”), such as images, containers, volumes, and networks: these objects are generally not removed unless you explicitly ask Docker to do so.

「dockerは諸々のオブジェクトを掃除してくれるアプローチを持っているけど、それは明示的にコマンドを叩くなどして要求しないと駄目よ」的なことが書いてあった。なるほど。容量がでかくなったら、docker hogehoge pruneするなどしてくれる自動化するのが今後の再発防止策なのかもしれないな〜とか思ったりした。

あとはこちらのスライドも参考にさせてもらったのだけど、overlaysのディレクトリを別システムに移してそちらで管理するとかもできるらしい。なるほどな〜。色々アプローチはありそう。

ちなみに、調べた感じoverlayFSは制限がないので、運用上の注意が必要とのこと。なるほど。容量制限もできないのか。


難しいdockerについてちょっとだけ詳しくなれた日だった。

*1:この記事とよく似た状況と原因だった。

*2:overlayFS以外にもストレージ管理の技術はあるようで、これはそのうちの一つ。cf: Use the OverlayFS storage driver | Docker Documentation

*3:iノートとはファイル属性を格納するもので、ディスク上にファイル情報(アクセス権や所有権)が記録される。すべてのファイルにはこのiノードがあり、これが枯渇すると新しいファイルを作成するなどができなくなります。例えディスクに空き容量があってもiノードが残っていなければ駄目。小さなファイルをたくさん作ると、iノードが枯渇することがある。

*4:https://www.slideshare.net/HommasSlide/docker-52965982