docker-composeのvolumeを途中から移動させたら上手く行かなかった

dockerでDBを使っているとデータを永続化させるためにローカルの特定のディレクトリなどをマウントさせる事が多い。運用しているdocker-composeを次のような感じで書いていた。

    image: mongo:3.6
    restart: unless-stopped
    volumes:
      - mongo_configdb:/data/configdb
      - mongo_db:/data/db
    restart: always

volumes:
  mongo_db:

まぁこれで全然問題なかったのだけど、volumesで特にパスを指定していなかった。

そのため /var/lib/docker/volumes以下に動かしているコンテナ名でディレクトリが作成されていて、そのディレクトリがmountされている感じで動いていた。

/var/lib/docker以下に保存していると、なにかdocker pruneとかしてしまうとファイルが消えてしまう可能性があるらしい。それは避けたいのでローカルディレクトリ上に保存しようとした。

ファイルの移動

どうも調べていると一度volumeとimageを消さないと移動はできないらしい。

mvで移動しても良かったが、最初にbackupがてらcpでディレクトリごとコピーした。 今思い返せばcpじゃなくてrsync使ってたほうが良かったのかもしれない。

$cp -r /var/lib/docker/volumes /home/anatofuz/backup

この時点で/var/lib/docker/volumesls -lしたら全てroot:rootになっていたので油断していた。

ホームディレクトリに移したのでanatofuz:dockerくらいにchownしていた。

docker-composeへの追記

docker-composeにカレントディレクトリ以下にデータを保存させたかったので次の様な感じで追記をした。

volumes:
  growi_data:
      driver_opts:
        type: none
        device: /home/anatofuz/growi/data/growi_growi_data
        o: bind
  mongo_configdb:
      driver_opts:
        type: none
        device: /home/anatofuz/growi/data/growi_mongo_configdb
        o: bind
  mongo_db:
      driver_opts:
        type: none
        device: /home/anatofuz/growi/data/growi_mongo_db
        o: bind
  es_data:
      driver_opts:
        type: none
        device: /home/anatofuz/growi/data/growi_es_data
        o: bind

docer-compose stopしてdocker-compose rmしたあとにdocer-compose buildしようとしたら所、 volumeを消せと言われたのでポチポチvolumeを消していった。

ビルド時のpermission

ビルドするとこんな感じになる

Successfully built e3a815260e49
Successfully tagged growi_elasticsearch:latest
Building app
Traceback (most recent call last):
  File "bin/docker-compose", line 6, in <module>
  File "compose/cli/main.py", line 72, in main
  File "compose/cli/main.py", line 128, in perform_command
  File "compose/cli/main.py", line 304, in build
  File "compose/project.py", line 397, in build
  File "compose/project.py", line 380, in build_service
  File "compose/service.py", line 1104, in build
  File "site-packages/docker/api/build.py", line 160, in build
  File "site-packages/docker/utils/build.py", line 30, in tar
  File "site-packages/docker/utils/build.py", line 49, in exclude_paths
  File "site-packages/docker/utils/build.py", line 214, in rec_walk
  File "site-packages/docker/utils/build.py", line 214, in rec_walk
  File "site-packages/docker/utils/build.py", line 214, in rec_walk
  File "site-packages/docker/utils/build.py", line 184, in rec_walk
PermissionError: [Errno 13] Permission denied: '/home/anatofuz/growi/data/growi_mariadb_data/mysql'
[395570] Failed to execute script docker-compose

そもそもappは次の様にdocker-compose.ymlを書いている。

  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 3000:3000
    links:
      - mongo:mongo
      - elasticsearch:elasticsearch
    depends_on:
      - mongo
      - elasticsearch
    environment:
      - MONGO_URI=mongodb://mongo:27017/growi
      - ELASTICSEARCH_URI=http://elasticsearch:9200/growi
      # - FILE_UPLOAD=mongodb   # activate this line if you use MongoDB GridFS rather than AWS
      - FILE_UPLOAD=local     # activate this line if you use local storage of server rather than AWS
      - MATHJAX=1             # activate this line if you want to use MathJax

    command: "dockerize
              -wait tcp://mongo:27017
              -wait tcp://elasticsearch:9200
              -timeout 60s
              npm run server:prod"
    restart: unless-stopped
    volumes:
      - growi_data:/data
    restart: always

mariadbのdataにアクセスする必要は無いと思うのだけれど、なぜかこのパーミッションで怒られている。dataディレクトリの中でコンテナごとにディレクトリを切っていたけれど、この運用が駄目だったのかもしれない。

root:rootなのが怪しいのかと思いchownで変更した。

sudo chown -R anatofuz:docker data/

こうするとbuildは通った。

起動するとDBの中身を読んでくれない問題

build通ったので喜びながらdocker-compose upしたがアプリケーションの初期設定画面が表示されてしまっていた。DBがデータを読んでなさそうな気配はあったが、docker-composeのlogを見る限りPermission関連で怒られている気配はない。

色々見た結果、もともと/var/lib/docker/volumesの中にあったgrowi_growi_dataの様なコンテナ名のディレクトリをプロジェクトのdataディレクトリにコピっていた。このコピー先の/home/anatofuz/growi/data/growi_growi_dataをdocker-composeでvolumeとして指定していたのだけど、これが駄目だった。

実際には/home/anatofuz/growi/data/growi_growi_dataの中に_dataディレクトリがあり、このディレクトリの中に実際のデータが存在している。つまりこの_dataまで指定しなければならない。

今回はdocker-composeを操作せずに、各コンテナ名ディレクトリの_datamv ..して解決した。正直この解決方法が正しいかは微妙である。

とはいえ

もう一度docer-compose buildすると、相変わらず

PermissionError: [Errno 13] Permission denied: '/home/anatofuz/growi/data/growi_mariadb_data/mysql'
[395570] Failed to execute script docker-compose

と怒られてしまう。

$ ls -l data/
total 56
drwxr-xr-x 3   anatofuz docker  4096 Jun  4 23:18 growi_es_data
drwxr-xr-x 3   anatofuz docker  4096 Jun  4 23:18 growi_growi_data
drwxr-xr-x 4   anatofuz docker  4096 Jun  4 23:18 growi_https-portal_data
drwxr-xr-x 5        999 docker  4096 Jun  4 23:23 growi_mariadb_data
drwxr-xr-x 2        999 docker  4096 Apr 30 02:20 growi_mongo_configdb
drwxr-xr-x 4        999 docker  4096 Jun  5 08:53 growi_mongo_db
-rw------- 1   anatofuz docker 65536 Jun  4 23:18 metadata.db

どうもdocker-compose runした瞬間にmariadbなどのDB系のユーザーが999で実行されてしまい、anatofuzで起動しているgrowi(app)からは参照できないらしい。

実際にps auxするとmariadbが999ユーザーで実行されていた。/var/lib/docker/volumesで実行していたときは999ではなくrootで動いていた気がするので、なぜこうなったかはよく解っていない。

所感

/var/lib/docker/volumesに結局データが保存されるのであれば、別にわざわざ違うディレクトリをマウントしようと頑張る必要はなかったのかもしれない。少なくともdocker-compose buildがスムーズに行かなくなってしまった。

dockerのvolumeを適当なディレクトリに保存して永続化させるよりは、mongodbやmysqlなどのコンテナにattachするなりしてバックアップを取っていくほうが無難であるかなという気がした。今の環境を元に戻すかは怪しいところ。戻せたら良いんだけど…

全体的にdockerよく解っていないことが露呈しているので、なぜこうなったか検討がつく方がいれば教えていただけると嬉しいです

追記 (2020/06/08)

'/home/anatofuz/growi/data/以下においていた999ユーザーで実行されてしまうDB系のファイル群を '/home/anatofuz/db/dataの様なトップディレクトリが異なるディレクトリ内に移動させてvolumeを作り直したところ、docker-compose build時のパーミッション問題は出なくなった。

おそらくappのビルド時にカレントディレクトリをマウントしていて、カレントディレクトリ以下のファイルのパーミッションは全て確認する挙動のような気がする。