[{"data":1,"prerenderedAt":549},["ShallowReactive",2],{"blog-ja-docker-compose-k3s-local-path-provisioner-permission-denied":3,"blog-related-ja-docker-compose-k3s-local-path-provisioner-permission-denied":489,"blog-ja-docker-compose-k3s-local-path-provisioner-permission-denied-alt":479},{"id":4,"title":5,"author":6,"body":7,"date":474,"description":475,"extension":476,"image":22,"locale":477,"meta":478,"navigation":479,"path":480,"seo":481,"stem":482,"tags":483,"__hash__":488},"blog\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied.md","Docker Composeではそのまま動いていたボリュームが、K3sに持ち込んだ瞬間Permission deniedになった","Kubo Team",{"type":8,"value":9,"toc":466},"minimark",[10,15,23,35,46,49,53,59,80,107,124,128,134,157,230,250,254,260,263,322,331,335,341,348,369,391,394,397,400,431,443,462],[11,12,14],"h2",{"id":13},"_1-docker-composeでは誰も気にしていなかったボリュームの持ち主","1. Docker Composeでは誰も気にしていなかった「ボリュームの持ち主」",[16,17,18],"p",{},[19,20],"img",{"alt":21,"src":22},"title","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied\u002Ftitle.webp",[16,24,25,26,30,31,34],{},"Docker Composeでローカル開発をしているとき、ボリュームの「所有者が誰か」を意識したことがある人は少ないはずだ。",[27,28,29],"code",{},"docker-compose.yml","に",[27,32,33],{},"volumes: .\u002Fdata:\u002Fapp\u002Fdata","と書けば、ホストのディレクトリがそのままコンテナに見える。権限で困ることはほとんどない。",[16,36,37,38,45],{},"これは当然の結果で、Docker公式ドキュメントも「bind mountはデフォルトでホスト上のファイルへの書き込みアクセス権を持つ」と説明している（",[39,40,44],"a",{"href":41,"rel":42},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fstorage\u002Fbind-mounts\u002F",[43],"nofollow","Docker公式ドキュメント: Bind mounts","）。つまりホスト側のディレクトリ権限がそのままコンテナ内に反映されるだけで、Docker自身が別途権限レイヤーを挟むわけではない。開発用に広めの権限でディレクトリを作っておけば、たいていのアプリケーションは何も考えずに動く。",[16,47,48],{},"この「何も考えずに動く」という前提こそが、Docker ComposeからK3sへ移行するときに最初につまずく原因になる。K3s（あるいはKubernetesクラスタ全般）は、ボリュームの扱いに関してComposeとは根本的に異なる設計思想を持っているからだ。構築を手作業で詰めていくほど、こうした前提の差異に一つずつ気づいて直す作業が増えていく。",[11,50,52],{"id":51},"_2-k3sに持ち込んだ瞬間何が起きるか-local-path-provisionerの仕様","2. K3sに持ち込んだ瞬間、何が起きるか — local-path-provisionerの仕様",[16,54,55],{},[19,56],{"alt":57,"src":58},"section01","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied\u002Fsection01.webp",[16,60,61,62,65,66,71,72,75,76,79],{},"K3sには標準でRancherの",[27,63,64],{},"local-path-provisioner","が組み込まれており、PVC（PersistentVolumeClaim）を作成するだけでノードのローカルディスク上にボリューム用ディレクトリを自動生成してくれる（",[39,67,70],{"href":68,"rel":69},"https:\u002F\u002Fdocs.k3s.io\u002Fadd-ons\u002Fstorage",[43],"K3s公式ドキュメント: Volumes and Storage","）。デフォルトでは",[27,73,74],{},"storageClassName: local-path","が使われ、ボリュームの実体は",[27,77,78],{},"\u002Fvar\u002Flib\u002Francher\u002Fk3s\u002Fstorage","配下に作られる。",[16,81,82,83,87,88,90,91,94,95,100,101,106],{},"問題は、このプロビジョニング処理が",[84,85,86],"strong",{},"ディレクトリの所有者（chown）までは面倒を見ない","ことだ。",[27,89,64],{},"公式リポジトリのセットアップスクリプトを見ると、実行される処理は",[27,92,93],{},"mkdir -m 0777 -p \"$VOL_DIR\"","のみで、パーミッションは777（誰でも読み書き可能）に設定されるが、所有ユーザー・グループの変更（chown）は行われない（",[39,96,99],{"href":97,"rel":98},"https:\u002F\u002Fgithub.com\u002Francher\u002Flocal-path-provisioner",[43],"rancher\u002Flocal-path-provisioner","、",[39,102,105],{"href":103,"rel":104},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fblob\u002F7f659759dd006ba2e5156198dde9ca8bf8a6d4e1\u002Fmanifests\u002Flocal-storage.yaml",[43],"k3s-io\u002Fk3s local-storage.yaml","）。",[16,108,109,110,113,114,117,118,123],{},"777権限なら誰でも書き込めるはずだと思うかもしれない。ところが、多くの公式コンテナイメージは",[27,111,112],{},"runAsNonRoot","や特定のUID\u002FGIDを前提に作られており、Pod側の",[27,115,116],{},"securityContext","でrunAsUserを明示していたり、イメージ自体が非rootユーザーで起動する設計になっていたりすると、ノード側のSELinux設定やumaskの組み合わせによって書き込みに失敗するケースが報告されている（",[39,119,122],{"href":120,"rel":121},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fissues\u002F10130",[43],"k3s-io\u002Fk3s Issue #10130","）。Docker Composeのbind mountでは起きなかった「誰が書き込むか」という問題が、K3sでは一気に表面化する。",[11,125,127],{"id":126},"_3-相対パスも罠になる-hostpathは絶対パス必須","3. 相対パスも罠になる — hostPathは絶対パス必須",[16,129,130],{},[19,131],{"alt":132,"src":133},"section02","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied\u002Fsection02.webp",[16,135,136,137,140,141,143,144,147,148,151,152,106],{},"Docker Composeのbind mountに慣れていると、もう一つ見落としがちな前提がある。Composeの",[27,138,139],{},"volumes:","は",[27,142,29],{},"からの相対パスを許容するが、Kubernetesの",[27,145,146],{},"hostPath","ボリュームは",[84,149,150],{},"絶対パスでなければ動かない","（",[39,153,156],{"href":154,"rel":155},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fvolumes\u002F#hostpath",[43],"Kubernetes公式ドキュメント: Volumes",[158,159,164],"pre",{"className":160,"code":161,"language":162,"meta":163,"style":163},"language-yaml shiki shiki-themes tokyo-night","volumes:\n  - name: data-volume\n    hostPath:\n      path: \u002Fmnt\u002Fdata  # 絶対パス必須。相対パスは不可\n      type: Directory\n","yaml","",[27,165,166,179,196,204,219],{"__ignoreMap":163},[167,168,171,175],"span",{"class":169,"line":170},"line",1,[167,172,174],{"class":173},"s0U2E","volumes",[167,176,178],{"class":177},"sAklC",":\n",[167,180,182,186,189,192],{"class":169,"line":181},2,[167,183,185],{"class":184},"sgJMe","  -",[167,187,188],{"class":173}," name",[167,190,191],{"class":177},":",[167,193,195],{"class":194},"sPY7s"," data-volume\n",[167,197,199,202],{"class":169,"line":198},3,[167,200,201],{"class":173},"    hostPath",[167,203,178],{"class":177},[167,205,207,210,212,215],{"class":169,"line":206},4,[167,208,209],{"class":173},"      path",[167,211,191],{"class":177},[167,213,214],{"class":194}," \u002Fmnt\u002Fdata",[167,216,218],{"class":217},"sbD-w","  # 絶対パス必須。相対パスは不可\n",[167,220,222,225,227],{"class":169,"line":221},5,[167,223,224],{"class":173},"      type",[167,226,191],{"class":177},[167,228,229],{"class":194}," Directory\n",[16,231,232,233,236,237,239,240,243,244,246,247,249],{},"Compose時代の感覧のまま",[27,234,235],{},".\u002Fdata","のような相対パス表記をマニフェストに持ち込むと、Kubernetesはそのディレクトリをホスト上のどこにも見つけられずPodがCreateContainerConfigError等で止まる。さらに",[27,238,146],{},"はノードのファイルシステムに直接アクセスできる強い権限を持つため、Kubernetes公式ドキュメントも本番環境では必要最小限のディレクトリに限定し、可能であれば",[27,241,242],{},"readOnly: true","を付けることを推奨している。実際の移行では、",[27,245,64],{},"が自動生成するPVC経由のボリュームに寄せて、",[27,248,146],{},"を直接書く場面はできるだけ減らすのが安全だ。",[11,251,253],{"id":252},"_4-回避策-fsgroupと-initcontainerstorageclassのカスタムパターン","4. 回避策 — fsGroupと initContainer、StorageClassのカスタムパターン",[16,255,256],{},[19,257],{"alt":258,"src":259},"section03","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied\u002Fsection03.webp",[16,261,262],{},"この権限問題には、複雑なスクリプトを書かなくても対処できる公式の仕組みがいくつか用意されている。",[264,265,266,292,316],"ul",{},[267,268,269,275,276,279,280,106,285,288,289,291],"li",{},[84,270,271,274],{},[27,272,273],{},"securityContext.fsGroup","を設定する",": PodのsecurityContextに",[27,277,278],{},"fsGroup","を指定すると、Kubernetesはコンテナ起動前にボリュームのグループ所有権を自動的にそのGIDへ変更してくれる（",[39,281,284],{"href":282,"rel":283},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Ftasks\u002Fconfigure-pod-container\u002Fsecurity-context\u002F",[43],"Kubernetes公式ドキュメント: Security Context",[27,286,287],{},"runAsUser","と",[27,290,278],{},"を合わせて設定しておけば、非rootコンテナでもボリュームへの書き込みが可能になる。初期構成で最初に試すべき最も手軽な方法だ。",[267,293,294,308,309,311,312,315],{},[84,295,296,297,300,301,300,304,307],{},"StorageClassの",[27,298,299],{},"userPattern","\u002F",[27,302,303],{},"groupPattern",[27,305,306],{},"permPattern","をカスタマイズする",": ",[27,310,64],{},"はStorageClassの設定パラメータでディレクトリ作成時の所有者・パーミッションパターンを変更できる仕組みを持っている（",[39,313,99],{"href":97,"rel":314},[43],"）。チーム全体で統一したUID\u002FGIDを使う場合はこちらが向いている。",[267,317,318,321],{},[84,319,320],{},"initContainerでchownする",": fsGroupが効かない特殊なケース（一部のCSIドライバやレガシーイメージ）では、root権限のinitContainerで対象ディレクトリを明示的にchownしてから本体コンテナを起動する方法が依然として有効だ。",[16,323,324,325,330],{},"どの方法を選ぶにせよ、「Docker Composeでは意識しなかったボリュームの所有者」を、K3sでは明示的に設計し直す必要があるという点は変わらない。この手の「fsGroupにするかStorageClassのパターンを変えるか」という判断は、経験がないと地味に時間を取られるポイントでもある。",[39,326,329],{"href":327,"rel":328},"https:\u002F\u002Fkubo.hexabase.io\u002F",[43],"Kubo","のAI-Driven Deploymentであれば、アプリの構成要件を伝えるだけでこうしたボリューム権限の初期設計を提案してもらえるため、ゼロから手探りで検証する時間を減らせる。",[11,332,334],{"id":333},"_5-depends_onも消える-起動順を前提にしたcomposeはそのままでは動かない","5. depends_onも消える — 起動順を前提にしたComposeはそのままでは動かない",[16,336,337],{},[19,338],{"alt":339,"src":340},"section04","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied\u002Fsection04.webp",[16,342,343,344,347],{},"ボリューム権限と並んで、移行時にもう一つ見落とされがちなのが起動順序だ。Docker Composeの",[27,345,346],{},"depends_on","はコンテナの起動順序を保証する便利な機能だが、Kubernetesには同等の概念が存在せず、Podは基本的に並列に起動する。",[16,349,350,351,354,355,357,358,100,363,368],{},"Compose定義を機械的にKubernetesマニフェストへ変換するツール",[27,352,353],{},"kompose","を使った場合でも、",[27,356,346],{},"キーは単純に無視される（",[39,359,362],{"href":360,"rel":361},"https:\u002F\u002Fgithub.com\u002Fjvitor83\u002Fkompose-network\u002Fblob\u002F16c4818f90e7\u002Fdocs\u002Fconversion.md",[43],"kompose公式: conversion doc",[39,364,367],{"href":365,"rel":366},"https:\u002F\u002Foneuptime.com\u002Fblog\u002Fpost\u002F2026-02-08-how-to-convert-docker-compose-files-to-kubernetes-manifests-with-kompose\u002Fview",[43],"OneUptime: Komposeによる変換ガイド","）。DBコンテナより先にアプリコンテナが起動し、接続エラーでクラッシュループするという事態が、ボリューム権限の問題を解決した直後に次の壁として立ちはだかることが多い。",[16,370,371,372,375,376,379,380,385,386,106],{},"対策としては、",[27,373,374],{},"initContainers","でDB等の依存先に接続できるまで待機するロジック（",[27,377,378],{},"until nslookup db-service; do sleep 2; done","のようなチェック）を入れるか、アプリケーション側に接続リトライを実装するのが定石だ（",[39,381,384],{"href":382,"rel":383},"https:\u002F\u002Fbesthub.dev\u002Farticles\u002F10-common-pitfalls-when-migrating-docker-compose-to-kubernetes-a9f6b6310605",[43],"10 Common Pitfalls When Migrating Docker Compose to Kubernetes","）。サービス名による名前解決自体はDocker ComposeのDNSとKubernetesのCoreDNSで概念的に近いため、ここは比較的移行しやすい部分だと言える（",[39,387,390],{"href":388,"rel":389},"https:\u002F\u002Fkindatechnical.com\u002Fnetworking\u002Fservice-discovery-dns-containers.html",[43],"Service Discovery and DNS in Containers",[16,392,393],{},"こうした「ローカルでは暗黙の前提として機能していたものが、K3sでは明示的な設計を要求される」という構造は、ボリューム権限と起動順序の両方に共通している。",[11,395,396],{"id":396},"まとめ",[16,398,399],{},"Docker ComposeからK3sへの移行でつまずくポイントを整理すると、次の3点に集約される。",[401,402,403,414,423],"ol",{},[267,404,405,308,408,410,411,413],{},[84,406,407],{},"ボリューム権限",[27,409,64],{},"はディレクトリを777で作成するだけでchownしない。",[27,412,278],{},"やStorageClassのカスタムパターンで明示的に所有者を設計する必要がある。",[267,415,416,419,420,422],{},[84,417,418],{},"パス形式",": Composeの相対パスはK3sの",[27,421,146],{},"では通用しない。絶対パス指定が必須。",[267,424,425,308,428,430],{},[84,426,427],{},"起動順序",[27,429,346],{},"に相当する機能はKubernetesになく、initContainerやアプリ側リトライで代替する必要がある。",[16,432,433,434,437,438,442],{},"いずれも「ローカルで動いていたから本番でも動くはず」という前提を崩される落とし穴だ。こうした初期構築のハマりどころは、構成をゼロから手作業で詰めていく限り何度でも再発する。",[39,435,329],{"href":327,"rel":436},[43],"のAI-Driven Deploymentなら、ボリュームの権限設計やStorageClassの選定を自然言語の指示で進められ、YAMLを1行ずつ書きながら権限エラーの原因を切り分けるような作業を減らせる。構成の全体像は",[39,439,441],{"href":327,"rel":440},[43],"Kubo Captain UI","で可視化されるため、ブラックボックスのまま進めてしまう不安もない。",[16,444,445,446,451,452,455,456,461],{},"Docker Composeからの移行で手戻りを減らしたい、あるいは今まさにPermission deniedで止まっているという場合は、",[39,447,450],{"href":448,"rel":449},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[43],"お問い合わせ","から構成相談も可能だ。K3sベースの",[39,453,329],{"href":327,"rel":454},[43],"は、EKS\u002FAKSのパワーをVercelのような手軽さで使える環境を目指しており、今回挙げたような移行時の初期ハマりどころを前提にした設計になっている。社内データを外に出せない事情があるなら、同じK3sベースで自社環境に閉じて構築できる",[39,457,460],{"href":458,"rel":459},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fkubo\u002Fon-premise",[43],"Kubo On-Premise","という選択肢もある。",[463,464,465],"style",{},"html pre.shiki code .s0U2E, html code.shiki .s0U2E{--shiki-default:#F7768E}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sgJMe, html code.shiki .sgJMe{--shiki-default:#9ABDF5}html pre.shiki code .sPY7s, html code.shiki .sPY7s{--shiki-default:#9ECE6A}html pre.shiki code .sbD-w, html code.shiki .sbD-w{--shiki-default:#51597D;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":163,"searchDepth":181,"depth":181,"links":467},[468,469,470,471,472,473],{"id":13,"depth":181,"text":14},{"id":51,"depth":181,"text":52},{"id":126,"depth":181,"text":127},{"id":252,"depth":181,"text":253},{"id":333,"depth":181,"text":334},{"id":396,"depth":181,"text":396},"2026-11-05","Docker ComposeからK3sへ移行したら、ローカルでは問題なかったボリュームがPermission deniedになった。local-path-provisionerの仕様が原因。移行時の回避策を実例で解説。","md","ja",{},true,"\u002Fblog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied",{"title":5,"description":475},"blog\u002Fja\u002Fdocker-compose-k3s-local-path-provisioner-permission-denied",[484,485,486,64,487],"k3s","kubernetes","docker-compose","persistent-storage","bxgoRNvOXNyrKGc_aSARkBvJHchf_OYqyFpIHjtrspg",[490,499,509,519,529,539],{"path":491,"title":492,"description":493,"date":494,"tags":495},"\u002Fblog\u002Fja\u002Fk3s-longhorn-storage-network-multus-replica-rebuild-stall","K3sノードを再起動したら、Longhornのレプリカ再構築が0%のまま静かに止まっていた。Storage Networkの起動順序という盲点","K3sノードを再起動したらLonghornのレプリカ再構築が0%で止まっていた。実際のバグ報告からStorage Network(Multus)の起動順序、レプリカ数設計、ノードdrain時の詰みポイントを解説する","2026-09-23",[484,485,496,497,498,487],"longhorn","storage-network","multus",{"path":500,"title":501,"description":502,"date":503,"tags":504},"\u002Fblog\u002Fja\u002Fk3s-local-path-provisioner-capacity-node-affinity-pvc-pending","K3sのPVCがPendingのまま戻ってこない。ローカルストレージの『容量無視』とノードアフィニティが起こす静かな詰み","K3sのPVCがPending状態から戻らない原因は、local-path-provisionerが容量制限を無視する設計にある。ハイパーバイザーのthin provisioning、Volume Node Affinity Conflict、バックアップの誤解まで、K3sのローカルストレージ設計の落とし穴を解説する。","2026-09-12",[484,485,505,64,506,507,508],"storage","persistent-volume","node-affinity","zfs",{"path":510,"title":511,"description":512,"date":513,"tags":514},"\u002Fblog\u002Fja\u002Fk3s-ai-agent-audit-log-traceability-gap","AIエージェントがKubernetes APIを叩いた後、何をしたのか追えなかった。Audit Logの設定に空いていた穴","AIエージェントをKubernetes上で動かし始めたら、トラブル発生時にAudit Logだけでは「誰が・何の目的で」操作したのか追えないことに気づいた。Audit Policyの盲点とトレーサビリティ確保の実践を解説する。","2026-11-09",[484,485,515,516,517,518],"ai-agent","audit-log","rbac","observability",{"path":520,"title":521,"description":522,"date":523,"tags":524},"\u002Fblog\u002Fja\u002Fk3s-kubelet-eviction-inode-exhaustion-diskpressure","K3sでPodが次々Evictedされた。ディスクは余っているのにinodeだけ枯渇していた","K3sでPodが次々Evictedされ、df -hは正常なのに復旧しない。原因はディスク容量ではなくinode枯渇だった。kubeletのeviction閾値とdf -iでの診断、再発防止策を解説する。","2026-11-08",[484,485,525,526,527,528],"kubelet","eviction","diskpressure","troubleshooting",{"path":530,"title":531,"description":532,"date":533,"tags":534},"\u002Fblog\u002Fja\u002Fk3s-cilium-kube-proxy-replacement-nodeport-unreachable","K3sでCiliumのkube-proxy置き換えをしたら、NodePortだけ繋がらなくなった","K3sにCiliumのkube-proxy replacementを公式手順通りに導入したら、NodePort経由の通信だけが届かなくなった。原因はFlannelやServiceLB(Klipper)との競合、k8sServiceHost未設定などK3s特有の設定差分にあった。本番投入前のチェックリストを解説。","2026-11-07",[484,485,535,536,537,538],"cilium","ebpf","kube-proxy","networking",{"path":540,"title":541,"description":542,"date":543,"tags":544},"\u002Fblog\u002Fja\u002Fk3s-memory-qos-cgroup-v2-memory-high-throttling","requestsもlimitsも正しいのに、K3sのPodが突然重くなった。犯人はOOMKillではなくcgroup v2のmemory.high早期スロットリングだった","K3sでrequests\u002Flimitsを正しく設定したPodが、OOMKilledイベントもなく突然重くなった謎を追った記録。原因はcgroup v2のmemory.highによる早期スロットリング。切り分け方法と対策を解説する。","2026-11-06",[484,485,545,546,547,548],"cgroup-v2","memory-qos","memory-high","resource-management",1794305474232]