[{"data":1,"prerenderedAt":1594},["ShallowReactive",2],{"blog-ja-helm-charts-best-practices":3,"blog-ja-helm-charts-best-practices-alt":124},{"id":4,"title":5,"author":6,"body":7,"date":1579,"description":1580,"extension":1581,"image":54,"locale":1582,"meta":1583,"navigation":124,"path":1584,"seo":1585,"stem":1586,"tags":1587,"__hash__":1593},"blog\u002Fblog\u002Fja\u002Fhelm-charts-best-practices.md","Helm チャート開発のベストプラクティス 2025","Kubo Team",{"type":8,"value":9,"toc":1550},"minimark",[10,27,31,40,44,55,59,71,154,159,163,166,170,177,351,355,368,374,443,449,473,476,479,488,539,547,551,566,570,619,623,865,869,904,908,916,1080,1095,1099,1108,1112,1188,1192,1215,1219,1267,1273,1276,1279,1348,1351,1354,1426,1429,1450,1453,1509,1523,1527,1530,1546],[11,12,13,20,21,26],"p",{},[14,15,19],"a",{"href":16,"rel":17},"https:\u002F\u002Fhelm.sh\u002F",[18],"nofollow","Helm"," は Kubernetes のパッケージマネージャーとして、アプリケーションのデプロイを再現可能かつ管理しやすくする標準ツールです。しかし、チャートの品質はプロジェクトの運用コストに直結します。テンプレートの過度な抽象化、テスト不足、セキュリティの見落としは、本番環境で深刻な問題を引き起こします。",[14,22,25],{"href":23,"rel":24},"https:\u002F\u002Fkubo.hexabase.io\u002F",[18],"Kubo"," では Helm チャートを活用した宣言的デプロイを標準パターンとして採用しており、本記事のベストプラクティスは Kubo 環境にそのまま適用できます。",[28,29,30],"h2",{"id":30},"チャート構造とディレクトリ設計",[11,32,33,34,39],{},"Helm チャートの品質は、構造設計の段階で決まります。",[14,35,38],{"href":36,"rel":37},"https:\u002F\u002Fhelm.sh\u002Fdocs\u002Fchart_best_practices\u002F",[18],"Helm 公式ドキュメント","と実践から導かれたベストプラクティスを紹介します。",[41,42,43],"h3",{"id":43},"標準的なチャート構造",[45,46,51],"pre",{"className":47,"code":49,"language":50},[48],"language-text","my-app\u002F\n├── Chart.yaml              # チャートのメタデータ\n├── Chart.lock              # 依存関係のロックファイル\n├── values.yaml             # デフォルト設定値\n├── values-dev.yaml         # 開発環境のオーバーライド\n├── values-staging.yaml     # ステージング環境のオーバーライド\n├── values-production.yaml  # 本番環境のオーバーライド\n├── templates\u002F\n│   ├── _helpers.tpl        # 共通テンプレートヘルパー\n│   ├── deployment.yaml\n│   ├── service.yaml\n│   ├── ingress.yaml\n│   ├── hpa.yaml\n│   ├── serviceaccount.yaml\n│   ├── configmap.yaml\n│   └── tests\u002F\n│       └── test-connection.yaml\n├── charts\u002F                 # サブチャート（依存関係）\n└── .helmignore\n","text",[52,53,49],"code",{"__ignoreMap":54},"",[41,56,58],{"id":57},"環境別-values-ファイルの分離","環境別 values ファイルの分離",[11,60,61,66,67,70],{},[14,62,65],{"href":63,"rel":64},"https:\u002F\u002Fcarlosneto.dev\u002Fblog\u002F2025\u002F2025-02-25-helm-best-practices\u002F",[18],"Carlos Neto のブログ","が指摘するように、単一の ",[52,68,69],{},"values.yaml"," で全環境を管理しようとすると、ファイルが肥大化して管理不能になります。環境ごとに values ファイルを分離し、デプロイ時に明示的に指定します。",[45,72,76],{"className":73,"code":74,"language":75,"meta":54,"style":54},"language-bash shiki shiki-themes tokyo-night","# 開発環境\nhelm upgrade --install my-app .\u002Fmy-app -f values.yaml -f values-dev.yaml\n\n# 本番環境\nhelm upgrade --install my-app .\u002Fmy-app -f values.yaml -f values-production.yaml\n","bash",[52,77,78,87,119,126,132],{"__ignoreMap":54},[79,80,83],"span",{"class":81,"line":82},"line",1,[79,84,86],{"class":85},"sbD-w","# 開発環境\n",[79,88,90,94,98,102,105,108,111,114,116],{"class":81,"line":89},2,[79,91,93],{"class":92},"sE3pS","helm",[79,95,97],{"class":96},"sPY7s"," upgrade",[79,99,101],{"class":100},"sT800"," --install",[79,103,104],{"class":96}," my-app",[79,106,107],{"class":96}," .\u002Fmy-app",[79,109,110],{"class":100}," -f",[79,112,113],{"class":96}," values.yaml",[79,115,110],{"class":100},[79,117,118],{"class":96}," values-dev.yaml\n",[79,120,122],{"class":81,"line":121},3,[79,123,125],{"emptyLinePlaceholder":124},true,"\n",[79,127,129],{"class":81,"line":128},4,[79,130,131],{"class":85},"# 本番環境\n",[79,133,135,137,139,141,143,145,147,149,151],{"class":81,"line":134},5,[79,136,93],{"class":92},[79,138,97],{"class":96},[79,140,101],{"class":100},[79,142,104],{"class":96},[79,144,107],{"class":96},[79,146,110],{"class":100},[79,148,113],{"class":96},[79,150,110],{"class":100},[79,152,153],{"class":96}," values-production.yaml\n",[11,155,156,158],{},[52,157,69],{}," にはデフォルト値を定義し、環境固有ファイルではオーバーライドが必要な値のみを記述します。これにより各ファイルが小さく保たれ、差分が明確になります。",[28,160,162],{"id":161},"テンプレート設計の原則-dry-と-yagni","テンプレート設計の原則: DRY と YAGNI",[11,164,165],{},"Helm テンプレートの品質を左右する 2 つの重要な原則があります。",[41,167,169],{"id":168},"drydont-repeat-yourself","DRY（Don't Repeat Yourself）",[11,171,172,173,176],{},"マニフェストの重複はエラーの温床です。共通パターンは ",[52,174,175],{},"_helpers.tpl"," に抽出し、テンプレート関数として再利用します。",[45,178,182],{"className":179,"code":180,"language":181,"meta":54,"style":54},"language-yaml shiki shiki-themes tokyo-night","{{\u002F* _helpers.tpl *\u002F}}\n{{- define \"my-app.labels\" -}}\napp.kubernetes.io\u002Fname: {{ include \"my-app.name\" . }}\napp.kubernetes.io\u002Finstance: {{ .Release.Name }}\napp.kubernetes.io\u002Fversion: {{ .Chart.AppVersion | quote }}\napp.kubernetes.io\u002Fmanaged-by: {{ .Release.Service }}\nhelm.sh\u002Fchart: {{ include \"my-app.chart\" . }}\n{{- end }}\n\n{{- define \"my-app.selectorLabels\" -}}\napp.kubernetes.io\u002Fname: {{ include \"my-app.name\" . }}\napp.kubernetes.io\u002Finstance: {{ .Release.Name }}\n{{- end }}\n","yaml",[52,183,184,196,209,227,241,255,270,285,297,302,314,327,340],{"__ignoreMap":54},[79,185,186,190,193],{"class":81,"line":82},[79,187,189],{"class":188},"sAklC","{{",[79,191,192],{"class":96},"\u002F* _helpers.tpl *\u002F",[79,194,195],{"class":188},"}}\n",[79,197,198,200,204,207],{"class":81,"line":89},[79,199,189],{"class":188},[79,201,203],{"class":202},"sGX4V","- ",[79,205,206],{"class":96},"define \"my-app.labels\" -",[79,208,195],{"class":188},[79,210,211,215,218,221,224],{"class":81,"line":121},[79,212,214],{"class":213},"s0U2E","app.kubernetes.io\u002Fname",[79,216,217],{"class":188},":",[79,219,220],{"class":188}," {{",[79,222,223],{"class":96}," include \"my-app.name\" .",[79,225,226],{"class":188}," }}\n",[79,228,229,232,234,236,239],{"class":81,"line":128},[79,230,231],{"class":213},"app.kubernetes.io\u002Finstance",[79,233,217],{"class":188},[79,235,220],{"class":188},[79,237,238],{"class":96}," .Release.Name",[79,240,226],{"class":188},[79,242,243,246,248,250,253],{"class":81,"line":134},[79,244,245],{"class":213},"app.kubernetes.io\u002Fversion",[79,247,217],{"class":188},[79,249,220],{"class":188},[79,251,252],{"class":96}," .Chart.AppVersion | quote",[79,254,226],{"class":188},[79,256,258,261,263,265,268],{"class":81,"line":257},6,[79,259,260],{"class":213},"app.kubernetes.io\u002Fmanaged-by",[79,262,217],{"class":188},[79,264,220],{"class":188},[79,266,267],{"class":96}," .Release.Service",[79,269,226],{"class":188},[79,271,273,276,278,280,283],{"class":81,"line":272},7,[79,274,275],{"class":213},"helm.sh\u002Fchart",[79,277,217],{"class":188},[79,279,220],{"class":188},[79,281,282],{"class":96}," include \"my-app.chart\" .",[79,284,226],{"class":188},[79,286,288,290,292,295],{"class":81,"line":287},8,[79,289,189],{"class":188},[79,291,203],{"class":202},[79,293,294],{"class":96},"end",[79,296,226],{"class":188},[79,298,300],{"class":81,"line":299},9,[79,301,125],{"emptyLinePlaceholder":124},[79,303,305,307,309,312],{"class":81,"line":304},10,[79,306,189],{"class":188},[79,308,203],{"class":202},[79,310,311],{"class":96},"define \"my-app.selectorLabels\" -",[79,313,195],{"class":188},[79,315,317,319,321,323,325],{"class":81,"line":316},11,[79,318,214],{"class":213},[79,320,217],{"class":188},[79,322,220],{"class":188},[79,324,223],{"class":96},[79,326,226],{"class":188},[79,328,330,332,334,336,338],{"class":81,"line":329},12,[79,331,231],{"class":213},[79,333,217],{"class":188},[79,335,220],{"class":188},[79,337,238],{"class":96},[79,339,226],{"class":188},[79,341,343,345,347,349],{"class":81,"line":342},13,[79,344,189],{"class":188},[79,346,203],{"class":202},[79,348,294],{"class":96},[79,350,226],{"class":188},[41,352,354],{"id":353},"yagniyou-arent-gonna-need-it","YAGNI（You Aren't Gonna Need It）",[11,356,357,358,362,363,367],{},"テンプレートの",[359,360,361],"strong",{},"過度な抽象化は最大のアンチパターン","です。",[14,364,366],{"href":63,"rel":365},[18],"実践的な Helm 開発ガイド","は「すべての条件分岐、関数、パラメータは認知的オーバーヘッドを増やす」と警告しています。",[11,369,370,373],{},[359,371,372],{},"悪い例",": 不要な抽象化",[45,375,377],{"className":179,"code":376,"language":181,"meta":54,"style":54},"{{- if .Values.deployment.enabled }}\n{{- if .Values.deployment.strategy.enabled }}\nstrategy:\n  type: {{ .Values.deployment.strategy.type | default \"RollingUpdate\" }}\n{{- end }}\n{{- end }}\n",[52,378,379,390,401,409,423,433],{"__ignoreMap":54},[79,380,381,383,385,388],{"class":81,"line":82},[79,382,189],{"class":188},[79,384,203],{"class":202},[79,386,387],{"class":96},"if .Values.deployment.enabled",[79,389,226],{"class":188},[79,391,392,394,396,399],{"class":81,"line":89},[79,393,189],{"class":188},[79,395,203],{"class":202},[79,397,398],{"class":96},"if .Values.deployment.strategy.enabled",[79,400,226],{"class":188},[79,402,403,406],{"class":81,"line":121},[79,404,405],{"class":213},"strategy",[79,407,408],{"class":188},":\n",[79,410,411,414,416,418,421],{"class":81,"line":128},[79,412,413],{"class":213},"  type",[79,415,217],{"class":188},[79,417,220],{"class":188},[79,419,420],{"class":96}," .Values.deployment.strategy.type | default \"RollingUpdate\"",[79,422,226],{"class":188},[79,424,425,427,429,431],{"class":81,"line":134},[79,426,189],{"class":188},[79,428,203],{"class":202},[79,430,294],{"class":96},[79,432,226],{"class":188},[79,434,435,437,439,441],{"class":81,"line":257},[79,436,189],{"class":188},[79,438,203],{"class":202},[79,440,294],{"class":96},[79,442,226],{"class":188},[11,444,445,448],{},[359,446,447],{},"良い例",": シンプルで必要十分",[45,450,452],{"className":179,"code":451,"language":181,"meta":54,"style":54},"strategy:\n  type: {{ .Values.strategy | default \"RollingUpdate\" }}\n",[52,453,454,460],{"__ignoreMap":54},[79,455,456,458],{"class":81,"line":82},[79,457,405],{"class":213},[79,459,408],{"class":188},[79,461,462,464,466,468,471],{"class":81,"line":89},[79,463,413],{"class":213},[79,465,217],{"class":188},[79,467,220],{"class":188},[79,469,470],{"class":96}," .Values.strategy | default \"RollingUpdate\"",[79,472,226],{"class":188},[11,474,475],{},"現在の要件を満たすシンプルなテンプレートを書き、将来の仮想的な要件のために複雑化させないことが重要です。",[41,477,478],{"id":478},"ライブラリチャートの活用",[11,480,481,482,487],{},"組織内で複数のチャートがある場合、",[14,483,486],{"href":484,"rel":485},"https:\u002F\u002Fgithub.com\u002Fbitnami\u002Fcharts\u002Ftree\u002Fmain\u002Fbitnami\u002Fcommon",[18],"Bitnami Common Chart"," のようなライブラリチャートに共通テンプレートを集約します。ライブラリチャートはリソースを直接デプロイせず、テンプレートヘルパーのみを提供します。",[45,489,491],{"className":179,"code":490,"language":181,"meta":54,"style":54},"# Chart.yaml\ndependencies:\n  - name: common\n    version: 2.x.x\n    repository: https:\u002F\u002Fcharts.bitnami.com\u002Fbitnami\n",[52,492,493,498,505,519,529],{"__ignoreMap":54},[79,494,495],{"class":81,"line":82},[79,496,497],{"class":85},"# Chart.yaml\n",[79,499,500,503],{"class":81,"line":89},[79,501,502],{"class":213},"dependencies",[79,504,408],{"class":188},[79,506,507,511,514,516],{"class":81,"line":121},[79,508,510],{"class":509},"sgJMe","  -",[79,512,513],{"class":213}," name",[79,515,217],{"class":188},[79,517,518],{"class":96}," common\n",[79,520,521,524,526],{"class":81,"line":128},[79,522,523],{"class":213},"    version",[79,525,217],{"class":188},[79,527,528],{"class":96}," 2.x.x\n",[79,530,531,534,536],{"class":81,"line":134},[79,532,533],{"class":213},"    repository",[79,535,217],{"class":188},[79,537,538],{"class":96}," https:\u002F\u002Fcharts.bitnami.com\u002Fbitnami\n",[11,540,541,546],{},[14,542,545],{"href":543,"rel":544},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fcaptain-ai\u002F",[18],"Captain.AI"," は、テンプレートの品質分析や最適化提案も AI で支援します。",[28,548,550],{"id":549},"テスト戦略-品質を担保する多層アプローチ","テスト戦略: 品質を担保する多層アプローチ",[11,552,553,554,559,560,565],{},"Helm チャートのテストは、ci-cd パイプラインの信頼性に直結します。",[14,555,558],{"href":556,"rel":557},"https:\u002F\u002Fgithub.com\u002Fhelm\u002Fchart-testing",[18],"Chart Testing（ct）ツール","と ",[14,561,564],{"href":562,"rel":563},"https:\u002F\u002Fgithub.com\u002Fhelm-unittest\u002Fhelm-unittest",[18],"helm-unittest"," を組み合わせた多層テストを実装しましょう。",[41,567,569],{"id":568},"レイヤー-1-lint-と静的検証","レイヤー 1: Lint と静的検証",[45,571,573],{"className":73,"code":572,"language":75,"meta":54,"style":54},"# Helm 組み込みの lint\nhelm lint .\u002Fmy-app --values values-production.yaml\n\n# Chart Testing による厳密な lint\nct lint --chart-dirs charts\u002F --all\n",[52,574,575,580,594,598,603],{"__ignoreMap":54},[79,576,577],{"class":81,"line":82},[79,578,579],{"class":85},"# Helm 組み込みの lint\n",[79,581,582,584,587,589,592],{"class":81,"line":89},[79,583,93],{"class":92},[79,585,586],{"class":96}," lint",[79,588,107],{"class":96},[79,590,591],{"class":100}," --values",[79,593,153],{"class":96},[79,595,596],{"class":81,"line":121},[79,597,125],{"emptyLinePlaceholder":124},[79,599,600],{"class":81,"line":128},[79,601,602],{"class":85},"# Chart Testing による厳密な lint\n",[79,604,605,608,610,613,616],{"class":81,"line":134},[79,606,607],{"class":92},"ct",[79,609,586],{"class":96},[79,611,612],{"class":100}," --chart-dirs",[79,614,615],{"class":96}," charts\u002F",[79,617,618],{"class":100}," --all\n",[41,620,622],{"id":621},"レイヤー-2-ユニットテストhelm-unittest","レイヤー 2: ユニットテスト（helm-unittest）",[45,624,626],{"className":179,"code":625,"language":181,"meta":54,"style":54},"# tests\u002Fdeployment_test.yaml\nsuite: Deployment Tests\ntemplates:\n  - deployment.yaml\ntests:\n  - it: should set correct replicas\n    set:\n      replicaCount: 5\n    asserts:\n      - equal:\n          path: spec.replicas\n          value: 5\n\n  - it: should have resource limits\n    asserts:\n      - isNotEmpty:\n          path: spec.template.spec.containers[0].resources.limits\n\n  - it: should use correct image\n    set:\n      image.repository: my-registry\u002Fmy-app\n      image.tag: \"v1.0.0\"\n    asserts:\n      - equal:\n          path: spec.template.spec.containers[0].image\n          value: \"my-registry\u002Fmy-app:v1.0.0\"\n",[52,627,628,633,643,650,657,664,676,683,694,701,711,721,730,734,746,753,763,773,778,790,797,808,825,832,841,851],{"__ignoreMap":54},[79,629,630],{"class":81,"line":82},[79,631,632],{"class":85},"# tests\u002Fdeployment_test.yaml\n",[79,634,635,638,640],{"class":81,"line":89},[79,636,637],{"class":213},"suite",[79,639,217],{"class":188},[79,641,642],{"class":96}," Deployment Tests\n",[79,644,645,648],{"class":81,"line":121},[79,646,647],{"class":213},"templates",[79,649,408],{"class":188},[79,651,652,654],{"class":81,"line":128},[79,653,510],{"class":509},[79,655,656],{"class":96}," deployment.yaml\n",[79,658,659,662],{"class":81,"line":134},[79,660,661],{"class":213},"tests",[79,663,408],{"class":188},[79,665,666,668,671,673],{"class":81,"line":257},[79,667,510],{"class":509},[79,669,670],{"class":213}," it",[79,672,217],{"class":188},[79,674,675],{"class":96}," should set correct replicas\n",[79,677,678,681],{"class":81,"line":272},[79,679,680],{"class":213},"    set",[79,682,408],{"class":188},[79,684,685,688,690],{"class":81,"line":287},[79,686,687],{"class":213},"      replicaCount",[79,689,217],{"class":188},[79,691,693],{"class":692},"sOJ5S"," 5\n",[79,695,696,699],{"class":81,"line":299},[79,697,698],{"class":213},"    asserts",[79,700,408],{"class":188},[79,702,703,706,709],{"class":81,"line":304},[79,704,705],{"class":509},"      -",[79,707,708],{"class":213}," equal",[79,710,408],{"class":188},[79,712,713,716,718],{"class":81,"line":316},[79,714,715],{"class":213},"          path",[79,717,217],{"class":188},[79,719,720],{"class":96}," spec.replicas\n",[79,722,723,726,728],{"class":81,"line":329},[79,724,725],{"class":213},"          value",[79,727,217],{"class":188},[79,729,693],{"class":692},[79,731,732],{"class":81,"line":342},[79,733,125],{"emptyLinePlaceholder":124},[79,735,737,739,741,743],{"class":81,"line":736},14,[79,738,510],{"class":509},[79,740,670],{"class":213},[79,742,217],{"class":188},[79,744,745],{"class":96}," should have resource limits\n",[79,747,749,751],{"class":81,"line":748},15,[79,750,698],{"class":213},[79,752,408],{"class":188},[79,754,756,758,761],{"class":81,"line":755},16,[79,757,705],{"class":509},[79,759,760],{"class":213}," isNotEmpty",[79,762,408],{"class":188},[79,764,766,768,770],{"class":81,"line":765},17,[79,767,715],{"class":213},[79,769,217],{"class":188},[79,771,772],{"class":96}," spec.template.spec.containers[0].resources.limits\n",[79,774,776],{"class":81,"line":775},18,[79,777,125],{"emptyLinePlaceholder":124},[79,779,781,783,785,787],{"class":81,"line":780},19,[79,782,510],{"class":509},[79,784,670],{"class":213},[79,786,217],{"class":188},[79,788,789],{"class":96}," should use correct image\n",[79,791,793,795],{"class":81,"line":792},20,[79,794,680],{"class":213},[79,796,408],{"class":188},[79,798,800,803,805],{"class":81,"line":799},21,[79,801,802],{"class":213},"      image.repository",[79,804,217],{"class":188},[79,806,807],{"class":96}," my-registry\u002Fmy-app\n",[79,809,811,814,816,819,822],{"class":81,"line":810},22,[79,812,813],{"class":213},"      image.tag",[79,815,217],{"class":188},[79,817,818],{"class":188}," \"",[79,820,821],{"class":96},"v1.0.0",[79,823,824],{"class":188},"\"\n",[79,826,828,830],{"class":81,"line":827},23,[79,829,698],{"class":213},[79,831,408],{"class":188},[79,833,835,837,839],{"class":81,"line":834},24,[79,836,705],{"class":509},[79,838,708],{"class":213},[79,840,408],{"class":188},[79,842,844,846,848],{"class":81,"line":843},25,[79,845,715],{"class":213},[79,847,217],{"class":188},[79,849,850],{"class":96}," spec.template.spec.containers[0].image\n",[79,852,854,856,858,860,863],{"class":81,"line":853},26,[79,855,725],{"class":213},[79,857,217],{"class":188},[79,859,818],{"class":188},[79,861,862],{"class":96},"my-registry\u002Fmy-app:v1.0.0",[79,864,824],{"class":188},[41,866,868],{"id":867},"レイヤー-3-テンプレートレンダリング検証","レイヤー 3: テンプレートレンダリング検証",[45,870,872],{"className":73,"code":871,"language":75,"meta":54,"style":54},"# テンプレートを YAML にレンダリングして検証\nhelm template my-app .\u002Fmy-app -f values-production.yaml | kubeval --strict\n",[52,873,874,879],{"__ignoreMap":54},[79,875,876],{"class":81,"line":82},[79,877,878],{"class":85},"# テンプレートを YAML にレンダリングして検証\n",[79,880,881,883,886,888,890,892,895,898,901],{"class":81,"line":89},[79,882,93],{"class":92},[79,884,885],{"class":96}," template",[79,887,104],{"class":96},[79,889,107],{"class":96},[79,891,110],{"class":100},[79,893,894],{"class":96}," values-production.yaml",[79,896,897],{"class":188}," |",[79,899,900],{"class":92}," kubeval",[79,902,903],{"class":100}," --strict\n",[41,905,907],{"id":906},"レイヤー-4-統合テストhelm-test","レイヤー 4: 統合テスト（helm test）",[11,909,910,915],{},[14,911,914],{"href":912,"rel":913},"https:\u002F\u002Fhelm.sh\u002Fdocs\u002Ftopics\u002Fchart_tests\u002F",[18],"Helm の chart test 機能","を使い、デプロイ後の実環境テストを実行します。",[45,917,919],{"className":179,"code":918,"language":181,"meta":54,"style":54},"# templates\u002Ftests\u002Ftest-connection.yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: \"{{ include \"my-app.fullname\" . }}-test\"\n  annotations:\n    \"helm.sh\u002Fhook\": test\nspec:\n  containers:\n    - name: curl-test\n      image: curlimages\u002Fcurl:latest\n      command: ['curl', '--fail', 'http:\u002F\u002F{{ include \"my-app.fullname\" . }}:{{ .Values.service.port }}']\n  restartPolicy: Never\n",[52,920,921,926,936,946,953,971,978,993,1000,1007,1019,1029,1070],{"__ignoreMap":54},[79,922,923],{"class":81,"line":82},[79,924,925],{"class":85},"# templates\u002Ftests\u002Ftest-connection.yaml\n",[79,927,928,931,933],{"class":81,"line":89},[79,929,930],{"class":213},"apiVersion",[79,932,217],{"class":188},[79,934,935],{"class":96}," v1\n",[79,937,938,941,943],{"class":81,"line":121},[79,939,940],{"class":213},"kind",[79,942,217],{"class":188},[79,944,945],{"class":96}," Pod\n",[79,947,948,951],{"class":81,"line":128},[79,949,950],{"class":213},"metadata",[79,952,408],{"class":188},[79,954,955,958,960,962,965,968],{"class":81,"line":134},[79,956,957],{"class":213},"  name",[79,959,217],{"class":188},[79,961,818],{"class":188},[79,963,964],{"class":96},"{{ include ",[79,966,967],{"class":188},"\"",[79,969,970],{"class":96},"my-app.fullname\" . }}-test\"\n",[79,972,973,976],{"class":81,"line":257},[79,974,975],{"class":213},"  annotations",[79,977,408],{"class":188},[79,979,980,983,986,988,990],{"class":81,"line":272},[79,981,982],{"class":188},"    \"",[79,984,985],{"class":96},"helm.sh\u002Fhook",[79,987,967],{"class":188},[79,989,217],{"class":188},[79,991,992],{"class":96}," test\n",[79,994,995,998],{"class":81,"line":287},[79,996,997],{"class":213},"spec",[79,999,408],{"class":188},[79,1001,1002,1005],{"class":81,"line":299},[79,1003,1004],{"class":213},"  containers",[79,1006,408],{"class":188},[79,1008,1009,1012,1014,1016],{"class":81,"line":304},[79,1010,1011],{"class":509},"    -",[79,1013,513],{"class":213},[79,1015,217],{"class":188},[79,1017,1018],{"class":96}," curl-test\n",[79,1020,1021,1024,1026],{"class":81,"line":316},[79,1022,1023],{"class":213},"      image",[79,1025,217],{"class":188},[79,1027,1028],{"class":96}," curlimages\u002Fcurl:latest\n",[79,1030,1031,1034,1036,1039,1042,1045,1047,1050,1053,1056,1058,1060,1062,1065,1067],{"class":81,"line":329},[79,1032,1033],{"class":213},"      command",[79,1035,217],{"class":188},[79,1037,1038],{"class":188}," [",[79,1040,1041],{"class":188},"'",[79,1043,1044],{"class":96},"curl",[79,1046,1041],{"class":188},[79,1048,1049],{"class":188},",",[79,1051,1052],{"class":188}," '",[79,1054,1055],{"class":96},"--fail",[79,1057,1041],{"class":188},[79,1059,1049],{"class":188},[79,1061,1052],{"class":188},[79,1063,1064],{"class":96},"http:\u002F\u002F{{ include \"my-app.fullname\" . }}:{{ .Values.service.port }}",[79,1066,1041],{"class":188},[79,1068,1069],{"class":188},"]\n",[79,1071,1072,1075,1077],{"class":81,"line":342},[79,1073,1074],{"class":213},"  restartPolicy",[79,1076,217],{"class":188},[79,1078,1079],{"class":96}," Never\n",[45,1081,1083],{"className":73,"code":1082,"language":75,"meta":54,"style":54},"helm test my-release\n",[52,1084,1085],{"__ignoreMap":54},[79,1086,1087,1089,1092],{"class":81,"line":82},[79,1088,93],{"class":92},[79,1090,1091],{"class":96}," test",[79,1093,1094],{"class":96}," my-release\n",[28,1096,1098],{"id":1097},"oci-レジストリとチャート配布","OCI レジストリとチャート配布",[11,1100,1101,1102,1107],{},"Helm 3.8 以降、",[14,1103,1106],{"href":1104,"rel":1105},"https:\u002F\u002Fhelm.sh\u002Fdocs\u002Ftopics\u002Fregistries\u002F",[18],"OCI（Open Container Initiative）レジストリ","がチャート配布の推奨メカニズムとなっています。コンテナイメージと同じレジストリでチャートを管理でき、運用の一元化が可能です。",[41,1109,1111],{"id":1110},"oci-レジストリへのプッシュ","OCI レジストリへのプッシュ",[45,1113,1115],{"className":73,"code":1114,"language":75,"meta":54,"style":54},"# パッケージング\nhelm package .\u002Fmy-app\n\n# レジストリにログイン\nhelm registry login ghcr.io -u $GITHUB_USER -p $GITHUB_TOKEN\n\n# プッシュ\nhelm push my-app-1.0.0.tgz oci:\u002F\u002Fghcr.io\u002Fyour-org\u002Fcharts\n",[52,1116,1117,1122,1132,1136,1141,1166,1170,1175],{"__ignoreMap":54},[79,1118,1119],{"class":81,"line":82},[79,1120,1121],{"class":85},"# パッケージング\n",[79,1123,1124,1126,1129],{"class":81,"line":89},[79,1125,93],{"class":92},[79,1127,1128],{"class":96}," package",[79,1130,1131],{"class":96}," .\u002Fmy-app\n",[79,1133,1134],{"class":81,"line":121},[79,1135,125],{"emptyLinePlaceholder":124},[79,1137,1138],{"class":81,"line":128},[79,1139,1140],{"class":85},"# レジストリにログイン\n",[79,1142,1143,1145,1148,1151,1154,1157,1160,1163],{"class":81,"line":134},[79,1144,93],{"class":92},[79,1146,1147],{"class":96}," registry",[79,1149,1150],{"class":96}," login",[79,1152,1153],{"class":96}," ghcr.io",[79,1155,1156],{"class":100}," -u",[79,1158,1159],{"class":92}," $GITHUB_USER",[79,1161,1162],{"class":100}," -p",[79,1164,1165],{"class":92}," $GITHUB_TOKEN\n",[79,1167,1168],{"class":81,"line":257},[79,1169,125],{"emptyLinePlaceholder":124},[79,1171,1172],{"class":81,"line":272},[79,1173,1174],{"class":85},"# プッシュ\n",[79,1176,1177,1179,1182,1185],{"class":81,"line":287},[79,1178,93],{"class":92},[79,1180,1181],{"class":96}," push",[79,1183,1184],{"class":96}," my-app-1.0.0.tgz",[79,1186,1187],{"class":96}," oci:\u002F\u002Fghcr.io\u002Fyour-org\u002Fcharts\n",[41,1189,1191],{"id":1190},"oci-レジストリからのインストール","OCI レジストリからのインストール",[45,1193,1195],{"className":73,"code":1194,"language":75,"meta":54,"style":54},"helm install my-app oci:\u002F\u002Fghcr.io\u002Fyour-org\u002Fcharts\u002Fmy-app --version 1.0.0\n",[52,1196,1197],{"__ignoreMap":54},[79,1198,1199,1201,1204,1206,1209,1212],{"class":81,"line":82},[79,1200,93],{"class":92},[79,1202,1203],{"class":96}," install",[79,1205,104],{"class":96},[79,1207,1208],{"class":96}," oci:\u002F\u002Fghcr.io\u002Fyour-org\u002Fcharts\u002Fmy-app",[79,1210,1211],{"class":100}," --version",[79,1213,1214],{"class":692}," 1.0.0\n",[41,1216,1218],{"id":1217},"ci-cd-パイプラインでの自動公開","ci-cd パイプラインでの自動公開",[45,1220,1222],{"className":179,"code":1221,"language":181,"meta":54,"style":54},"# GitHub Actions 例\n- name: Publish Helm Chart\n  run: |\n    helm package .\u002Fcharts\u002Fmy-app --version ${{ github.ref_name }}\n    helm push my-app-${{ github.ref_name }}.tgz \\\n      oci:\u002F\u002Fghcr.io\u002F${{ github.repository_owner }}\u002Fcharts\n",[52,1223,1224,1229,1241,1252,1257,1262],{"__ignoreMap":54},[79,1225,1226],{"class":81,"line":82},[79,1227,1228],{"class":85},"# GitHub Actions 例\n",[79,1230,1231,1234,1236,1238],{"class":81,"line":89},[79,1232,1233],{"class":509},"-",[79,1235,513],{"class":213},[79,1237,217],{"class":188},[79,1239,1240],{"class":96}," Publish Helm Chart\n",[79,1242,1243,1246,1248],{"class":81,"line":121},[79,1244,1245],{"class":213},"  run",[79,1247,217],{"class":188},[79,1249,1251],{"class":1250},"sd1Qi"," |\n",[79,1253,1254],{"class":81,"line":128},[79,1255,1256],{"class":96},"    helm package .\u002Fcharts\u002Fmy-app --version ${{ github.ref_name }}\n",[79,1258,1259],{"class":81,"line":134},[79,1260,1261],{"class":96},"    helm push my-app-${{ github.ref_name }}.tgz \\\n",[79,1263,1264],{"class":81,"line":257},[79,1265,1266],{"class":96},"      oci:\u002F\u002Fghcr.io\u002F${{ github.repository_owner }}\u002Fcharts\n",[11,1268,1269,1272],{},[14,1270,25],{"href":23,"rel":1271},[18]," では OCI 準拠のレジストリが統合されており、チャートの公開と管理がシームレスに行えます。",[28,1274,1275],{"id":1275},"セキュリティとリソース管理",[41,1277,1278],{"id":1278},"リソース制限の適切な設定",[45,1280,1282],{"className":179,"code":1281,"language":181,"meta":54,"style":54},"# values.yaml\nresources:\n  requests:\n    cpu: 100m\n    memory: 128Mi\n  limits:\n    cpu: 500m\n    memory: 512Mi\n",[52,1283,1284,1289,1296,1303,1313,1323,1330,1339],{"__ignoreMap":54},[79,1285,1286],{"class":81,"line":82},[79,1287,1288],{"class":85},"# values.yaml\n",[79,1290,1291,1294],{"class":81,"line":89},[79,1292,1293],{"class":213},"resources",[79,1295,408],{"class":188},[79,1297,1298,1301],{"class":81,"line":121},[79,1299,1300],{"class":213},"  requests",[79,1302,408],{"class":188},[79,1304,1305,1308,1310],{"class":81,"line":128},[79,1306,1307],{"class":213},"    cpu",[79,1309,217],{"class":188},[79,1311,1312],{"class":96}," 100m\n",[79,1314,1315,1318,1320],{"class":81,"line":134},[79,1316,1317],{"class":213},"    memory",[79,1319,217],{"class":188},[79,1321,1322],{"class":96}," 128Mi\n",[79,1324,1325,1328],{"class":81,"line":257},[79,1326,1327],{"class":213},"  limits",[79,1329,408],{"class":188},[79,1331,1332,1334,1336],{"class":81,"line":272},[79,1333,1307],{"class":213},[79,1335,217],{"class":188},[79,1337,1338],{"class":96}," 500m\n",[79,1340,1341,1343,1345],{"class":81,"line":287},[79,1342,1317],{"class":213},[79,1344,217],{"class":188},[79,1346,1347],{"class":96}," 512Mi\n",[11,1349,1350],{},"環境ごとにリソース値を調整します。開発環境では最小限に、本番ではトラフィックに応じた適切な値を設定します。",[41,1352,1353],{"id":1353},"セキュリティコンテキスト",[45,1355,1357],{"className":179,"code":1356,"language":181,"meta":54,"style":54},"securityContext:\n  runAsNonRoot: true\n  runAsUser: 1000\n  readOnlyRootFilesystem: true\n  allowPrivilegeEscalation: false\n  capabilities:\n    drop:\n      - ALL\n",[52,1358,1359,1366,1376,1386,1395,1405,1412,1419],{"__ignoreMap":54},[79,1360,1361,1364],{"class":81,"line":82},[79,1362,1363],{"class":213},"securityContext",[79,1365,408],{"class":188},[79,1367,1368,1371,1373],{"class":81,"line":89},[79,1369,1370],{"class":213},"  runAsNonRoot",[79,1372,217],{"class":188},[79,1374,1375],{"class":692}," true\n",[79,1377,1378,1381,1383],{"class":81,"line":121},[79,1379,1380],{"class":213},"  runAsUser",[79,1382,217],{"class":188},[79,1384,1385],{"class":692}," 1000\n",[79,1387,1388,1391,1393],{"class":81,"line":128},[79,1389,1390],{"class":213},"  readOnlyRootFilesystem",[79,1392,217],{"class":188},[79,1394,1375],{"class":692},[79,1396,1397,1400,1402],{"class":81,"line":134},[79,1398,1399],{"class":213},"  allowPrivilegeEscalation",[79,1401,217],{"class":188},[79,1403,1404],{"class":692}," false\n",[79,1406,1407,1410],{"class":81,"line":257},[79,1408,1409],{"class":213},"  capabilities",[79,1411,408],{"class":188},[79,1413,1414,1417],{"class":81,"line":272},[79,1415,1416],{"class":213},"    drop",[79,1418,408],{"class":188},[79,1420,1421,1423],{"class":81,"line":287},[79,1422,705],{"class":509},[79,1424,1425],{"class":96}," ALL\n",[41,1427,1428],{"id":1428},"シークレットの外部化",[11,1430,1431,1432,1437,1438,1443,1444,1449],{},"テンプレート内で ",[14,1433,1436],{"href":1434,"rel":1435},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fconfiguration\u002Fsecret\u002F",[18],"Kubernetes Secrets"," を参照しつつ、シークレットデータ自体は ",[14,1439,1442],{"href":1440,"rel":1441},"https:\u002F\u002Fexternal-secrets.io\u002F",[18],"External Secrets Operator"," や ",[14,1445,1448],{"href":1446,"rel":1447},"https:\u002F\u002Fgithub.com\u002Fbitnami-labs\u002Fsealed-secrets",[18],"Sealed Secrets"," で管理します。",[41,1451,1452],{"id":1452},"脆弱性スキャン",[45,1454,1456],{"className":73,"code":1455,"language":75,"meta":54,"style":54},"# Trivy によるチャートと参照イメージのスキャン\ntrivy config .\u002Fmy-app\u002F\ntrivy image my-registry\u002Fmy-app:v1.0.0\n\n# Kubescape による設定スキャン\nkubescape scan framework nsa .\u002Fmy-app\u002F\n",[52,1457,1458,1463,1474,1484,1488,1493],{"__ignoreMap":54},[79,1459,1460],{"class":81,"line":82},[79,1461,1462],{"class":85},"# Trivy によるチャートと参照イメージのスキャン\n",[79,1464,1465,1468,1471],{"class":81,"line":89},[79,1466,1467],{"class":92},"trivy",[79,1469,1470],{"class":96}," config",[79,1472,1473],{"class":96}," .\u002Fmy-app\u002F\n",[79,1475,1476,1478,1481],{"class":81,"line":121},[79,1477,1467],{"class":92},[79,1479,1480],{"class":96}," image",[79,1482,1483],{"class":96}," my-registry\u002Fmy-app:v1.0.0\n",[79,1485,1486],{"class":81,"line":128},[79,1487,125],{"emptyLinePlaceholder":124},[79,1489,1490],{"class":81,"line":134},[79,1491,1492],{"class":85},"# Kubescape による設定スキャン\n",[79,1494,1495,1498,1501,1504,1507],{"class":81,"line":257},[79,1496,1497],{"class":92},"kubescape",[79,1499,1500],{"class":96}," scan",[79,1502,1503],{"class":96}," framework",[79,1505,1506],{"class":96}," nsa",[79,1508,1473],{"class":96},[11,1510,1511,1516,1517,1522],{},[14,1512,1515],{"href":1513,"rel":1514},"https:\u002F\u002Ftrivy.dev\u002F",[18],"Trivy"," と ",[14,1518,1521],{"href":1519,"rel":1520},"https:\u002F\u002Fkubescape.io\u002F",[18],"Kubescape"," を CI パイプラインに統合し、デプロイ前にセキュリティ問題を検出します。",[28,1524,1526],{"id":1525},"まとめ-kubo-で-helm-チャートを最大限に活用する","まとめ: Kubo で Helm チャートを最大限に活用する",[11,1528,1529],{},"Helm チャートの品質は、Kubernetes 運用の成功を左右します。DRY と YAGNI のバランス、多層テスト戦略、OCI レジストリによる配布、セキュリティベストプラクティスを組み合わせることで、保守しやすく安全なチャートを開発できます。",[11,1531,1532,1535,1536,1539,1540,1545],{},[14,1533,25],{"href":23,"rel":1534},[18]," は Helm チャートによる宣言的デプロイを標準パターンとしてサポートしており、ArgoCD や FluxCD との連携も組み込まれています。",[14,1537,545],{"href":543,"rel":1538},[18]," がチャートの品質分析やテンプレート最適化を AI で支援し、開発者の生産性を最大化します。Helm チャート開発の改善に取り組みたい方は、ぜひ",[14,1541,1544],{"href":1542,"rel":1543},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[18],"お問い合わせ","ください。",[1547,1548,1549],"style",{},"html pre.shiki code .sbD-w, html code.shiki .sbD-w{--shiki-default:#51597D;--shiki-default-font-style:italic}html pre.shiki code .sE3pS, html code.shiki .sE3pS{--shiki-default:#C0CAF5}html pre.shiki code .sPY7s, html code.shiki .sPY7s{--shiki-default:#9ECE6A}html pre.shiki code .sT800, html code.shiki .sT800{--shiki-default:#E0AF68}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);}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sGX4V, html code.shiki .sGX4V{--shiki-default:#A9B1D6}html pre.shiki code .s0U2E, html code.shiki .s0U2E{--shiki-default:#F7768E}html pre.shiki code .sgJMe, html code.shiki .sgJMe{--shiki-default:#9ABDF5}html pre.shiki code .sOJ5S, html code.shiki .sOJ5S{--shiki-default:#FF9E64}html pre.shiki code .sd1Qi, html code.shiki .sd1Qi{--shiki-default:#BB9AF7}",{"title":54,"searchDepth":89,"depth":89,"links":1551},[1552,1556,1561,1567,1572,1578],{"id":30,"depth":89,"text":30,"children":1553},[1554,1555],{"id":43,"depth":121,"text":43},{"id":57,"depth":121,"text":58},{"id":161,"depth":89,"text":162,"children":1557},[1558,1559,1560],{"id":168,"depth":121,"text":169},{"id":353,"depth":121,"text":354},{"id":478,"depth":121,"text":478},{"id":549,"depth":89,"text":550,"children":1562},[1563,1564,1565,1566],{"id":568,"depth":121,"text":569},{"id":621,"depth":121,"text":622},{"id":867,"depth":121,"text":868},{"id":906,"depth":121,"text":907},{"id":1097,"depth":89,"text":1098,"children":1568},[1569,1570,1571],{"id":1110,"depth":121,"text":1111},{"id":1190,"depth":121,"text":1191},{"id":1217,"depth":121,"text":1218},{"id":1275,"depth":89,"text":1275,"children":1573},[1574,1575,1576,1577],{"id":1278,"depth":121,"text":1278},{"id":1353,"depth":121,"text":1353},{"id":1428,"depth":121,"text":1428},{"id":1452,"depth":121,"text":1452},{"id":1525,"depth":89,"text":1526},"2026-05-27","Helm チャート開発のベストプラクティスを 2025 年の最新動向とともに解説。テンプレート設計、テスト戦略、OCI レジストリ、セキュリティまで網羅。","md","ja",{},"\u002Fblog\u002Fja\u002Fhelm-charts-best-practices",{"title":5,"description":1580},"blog\u002Fja\u002Fhelm-charts-best-practices",[19,1588,1589,1590,1591,1592],"Kubernetes","パッケージ管理","チャート開発","ベストプラクティス","GitOps","6UDOpJ9knDAz1azJoPKgOVjGScwh6nHYAOEMkwI78cs",1779964617053]