QTアプリケーションから生成したJsonファイルの保持について

Torizon OS上で動作するQtアプリケーション(GUIアプリケーション)を開発しております。
GUIアプリケーションは実行ファイルと同階層に配置されたdataフォルダ内に、
GUIの設定値を保存したJsonファイルを保持しており、GUIから設定値を操作し書き込みを行っております。

Dockerコンテナの再起動によって、書き込んだはずの設定がクリアされてしまうため、
コンテナ外のフォルダとマウントする必要があると考え、ボリューム機能の利用を検討しております。

ボリューム機能は、docker-compose.ymlへの設定が必要と考え
以下の記載のサイトを参考に設定を行いましたが、データが保持されませんでした。
https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/#use-a-volume-with-docker-compose

version: "3.9"
services:
  Guiqtdemo-debug:
    build:
      context: .
      dockerfile: Dockerfile.debug
    image: ${LOCAL_REGISTRY}:5002/Guiqtdemo-debug:${TAG}
    ports:
      # SSH debug
      - 2231:2231
      # gdbserver
      - 2232:2232
      # qml debug
      - 2233:2233
    devices:
      - "/dev/ttyRPMSG31:/dev/ttyRPMSG31" 
      - "/dev/snd"
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
        read_only: false
      - type: bind
        bind:
          propagation: shared
        source: /media
        target: /media
      - data-volume:/home/torizon/GUIApp/data

    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"
    depends_on: [
      weston
    ]

  Guiqtdemo:
    build:
      context: .
      dockerfile: Dockerfile
    image: ${DOCKER_LOGIN}/Guiqtdemo:${TAG}
    devices:
      - "/dev/ttyRPMSG31:/dev/ttyRPMSG31" 
      - "/dev/snd"
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        bind:
          propagation: shared
        source: /media
        target: /media 
      - data-volume:/home/torizon/GUIApp/data
    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"
    depends_on: [
      weston
    ]

  weston:
#    image: torizon/weston${GPU}:3
    image: ${LOCAL_REGISTRY}:5002/torizon/weston${GPU}:3
    environment:
      - ACCEPT_FSL_EULA=1
    # Required to get udev events from host udevd via netlink
    network_mode: host
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        source: /run/udev
        target: /run/udev
      - type: bind
        source: /etc/xdg/weston/
        target: /etc/xdg/weston/]
      - data-volume:/home/torizon/GUIApp/data
    cap_add:
      - CAP_SYS_TTY_CONFIG
    # Add device access rights through cgroup...
    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty1
      - "c 4:1 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"
  backup:
    image: backup-service
    volumes:
      - data-volume:/home/torizon/GUIApp/data
volumes:
  data-volume:

お手数をおかけして申し訳ありませんが、
GUIアプリから変更を加えたファイルをコンテナ再起動後も保持するための具体的な設定方法をご教示いただけますでしょうか。

1 Like

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


こんにちは、ご質問ありがとうございます。

コンテナ再起動後も設定ファイル(Json)を保持するには、Dockerのボリュームを正しく設定する必要があります。Torizonでは公式ガイドのとおり、ボリュームの宣言サービスごとのマウント指定が重要です。

1. docker-compose.ymlによるボリュームの宣言

volumes:
  data-volume:
    driver: local

このように明示的にdriver: localを指定します。

2. サービスごとのボリュームマウント指定

サービス内のvolumes指定は下記のように記載します:

services:
  Guiqtdemo-debug:
    # ...(省略)
    volumes:
      # その他のバインドマウント省略
      - type: volume
        source: data-volume
        target: /home/torizon/GUIApp/data

  Guiqtdemo:
    # ...(省略)
    volumes:
      - type: volume
        source: data-volume
        target: /home/torizon/GUIApp/data

ポイント

  • type: volumeでボリュームとしてマウントすることを明記します。
  • sourceはcomposeファイル下部のvolumesで宣言したdata-volumeです。
  • targetアプリケーション内でデータフォルダとして実際に使用しているパスと一致させてください。
  • 他サービス(例:westonやbackup)でこのボリュームをマウントする必要がなければ、不要です。

3. ディレクトリ権限を確認

初回起動時、/home/torizon/GUIApp/dataディレクトリがアプリ内で作成される場合は、コンテナユーザー(例:torizonユーザー)がこのディレクトリのオーナーになることを確認してください。

4. 例:修正されたdocker-compose.yml抜粋

version: "3.9"
services:
  Guiqtdemo-debug:
    # ...(省略)
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
        read_only: false
      - type: bind
        bind:
          propagation: shared
        source: /media
        target: /media
      - type: volume
        source: data-volume
        target: /home/torizon/GUIApp/data
    # ...(省略)

  Guiqtdemo:
    # ...(省略)
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        bind:
          propagation: shared
        source: /media
        target: /media
      - type: volume
        source: data-volume
        target: /home/torizon/GUIApp/data

volumes:
  data-volume:
    driver: local

5. 既存ボリュームに初期データをコピーしたい場合

初回起動時、/home/torizon/GUIApp/data内に何もファイルがなければ、data-volumeは空になります。
初期データ登録が必要な場合は、公式ドキュメントの例のように、entrypointスクリプト等で初期コピー処理を追加することを検討してください。


参考ドキュメント:

何かご不明な点がありましたら、どうぞご質問ください。

Best regards, Toradex AI Assistant.

ご提示いただいた内容で /home/torizon/GUIApp/dataをボリュームとして設定したところ配置されたJsonファイルに書き込み権限が無く編集できませんでした。

GUIアプリケーション起動時に、
”/home/torizon/GUIApp/data”に配置されたJsonファイルに対して
file.open(QIODevice::ReadWrite);を行うのですが
Permission deniedとなり、書き込み権限がFalseとなっておりました。
GUIアプリケーションから新規にテキストやJsonファイルを
”/home/torizon/GUIApp/data”上に作成しようとすると、同様に権限が無く実行不可でした。

しかし、ボリュームで設定した以外のパス
例えば”/home/torizon/GUIApp”や”/home/torizon/GUIApp/data3”などには
GUIアプリケーションから新規ファイル作成を行うことができました(書き込み権限がtrueであることも確認済み)。

ボリュームで指定したフォルダのみ書き込み不可のような動きに見えるのですが
その他、確認すべき内容、必要な設定などございますでしょうか。

GUIアプリケーションからは”/home/torizon/GUIApp/data”上のJsonファイルを読み書きし
そのフォルダ内のJsonファイルの設定がコンテナ再起動後も維持されることを想定しております。

@h-ysk

ご返信が遅くなり申し訳ございません。
フォローアップの内容を確認いたしました。

TorizonCore OS では、ルートファイルシステムがデフォルトで読み取り専用(read-only)となっており、そのためアプリケーションからデータの永続化を行う場合には、
書き込みが許可された特定のフォルダを使用することが推奨されています。

その中でも一般的にカスタマイズ情報や設定ファイルの永続化には /etc フォルダがよく利用されております。
このフォルダは TorizonCore において 永続化用の overlayfs に含まれており、書き込みが可能です。

今回のように GUI アプリケーションから JSON 設定ファイルを保存/更新したい場合は、
以下のような形で /etc 配下に専用のサブフォルダを作成し、そこにファイルを配置する方法をおすすめいたします:

例)

/etc/GUIApp/settings.json

公式ドキュメントでも /etc を使ったカスタマイズ方法が紹介されておりますので、
あわせてご参照いただけますと幸いです:

Torizon OS Customization
/etc 配下への設定ファイル配置方法の参考になります)

恐れ入りますがご確認いただければと思います。
アルバロ。

ご回答いただきありがとうございます。
以下のように理解しましたが間違いありませんでしょうか
・docker-compose.ymlでの設定において
”/home/torizon/GUIApp/data”指定の箇所を”/etc/GUIApp/”に変更し永続化パスをetcに設定
・GUIアプリにおいて、書き込み先パスも”/etc/GUIApp/settings.json”に変更
また、/etcを使用するうえで、その他、Dockerファイル、docker-compose.ymlなど設定が必要な項目はありますでしょうか。

併せて確認させていただきたいのですが
一般的に/etcに関しては権限周りの設定を行わないとフォルダの作成やファイルへの書き込み不可となると思われます。
以下の想定処理に必要な権限周りの設定方法を伺いたいです。
(例えばDockerファイル、docker-compose.ymlの設定など)

-想定処理-
・今回、初回起動で”/etc/GUIApp/settings.json”のフォルダが存在しない場合
フォルダを作成するか、または、あらかじめ用意しておいたフォルダを(Jsonファイルごと)コピーする、いずれかの処理を想定しております。
・GUIアプリからの”/etc/GUIApp/settings.json”に対する読み込み\書き込みを想定
・”/etc/GUIApp/settings.json”の永続化を想定

@h-ysk

ご理解いただいております内容はその通りで問題ございません。
加えて /etc フォルダ利用時の具体的な設定例と、初回起動時のフォルダ作成+ファイル配置方法について、以下のような形をおすすめいたします。

※ 下記のサンプルコードは AI により自動生成された参考例となっております。
実際のご使用環境やアプリケーション仕様により、適宜調整が必要になる場合がございます。
基本的な実装のベースとしてご参考いただき、プロジェクトに合わせてご活用いただけますと幸いです。

:white_check_mark: entrypoint.sh にて:

  • /etc/GUIApp が無ければ作成
  • settings.json が無ければデフォルトを /etc/GUIApp/settings.json にコピー
  • その後 GUI アプリを起動
#!/bin/sh

# /etc/GUIApp が無ければ作成
if [ ! -d /etc/GUIApp ]; then
  echo "Creating /etc/GUIApp..."
  sudo mkdir -p /etc/GUIApp
  sudo chown torizon:torizon /etc/GUIApp
fi

# settings.json が無ければデフォルトをコピー
if [ ! -f /etc/GUIApp/settings.json ]; then
  echo "Copying default settings.json..."
  cp /tmp/default-settings.json /etc/GUIApp/settings.json
fi

# GUI アプリを実行
exec /usr/local/bin/your_app_binary

:white_check_mark: Dockerfile / docker-compose.yml にて:

  • /etc/GUIApp をボリュームとしてマウント → 永続化
  • entrypoint.sh を ENTRYPOINT として設定
version: "3.9"
services:
  guiqtdemo:
    build: .
    volumes:
      # /etc/GUIApp を永続化
      - /etc/GUIApp:/etc/GUIApp
    environment:
      - QT_QPA_PLATFORM=wayland
    # 他に必要な設定があれば追加

FROM torizon/qt5-wayland (例: 使用しているベースイメージに合わせて変更)

# 必要なパッケージがあればインストール
# RUN apt-get update && apt-get install -y <packages>

# アプリをコピー
COPY GUIApp/your_app_binary /usr/local/bin/your_app_binary

# デフォルト設定ファイルをコピー (コンテナ内の一時場所へ)
COPY default-settings/settings.json /tmp/default-settings.json

# エントリポイントスクリプトをコピー
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

# ユーザー切り替え (例: torizonユーザーを使う場合)
USER torizon

# エントリポイントを設定
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]


上記のような形にしていただくことで:

  • /etc/GUIApp 配下は TorizonCore OS 側で永続化対象となるため、コンテナ再起動後も保持されます。
  • アプリ側では /etc/GUIApp/settings.json を読み書き可能になります。
  • 初回起動時は entrypoint.sh 内で自動的に初期設定を配置できます。

注意点:

  • /etc 配下のパーミッションに注意 → 初回作成時に chown torizon:torizon などで権限設定しておくと良いです。
  • docker-compose.yml にて /etc/GUIApp を明示的にボリューム指定していただくことで、アプリの更新時にも設定は保持されます。