docs: deduplicate Technical Details sections in values-and-merging.md (#2575)

Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
yxxhero 2026-05-03 20:59:03 +08:00 committed by GitHub
parent e703b15075
commit 7cc5fe0358
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 38 additions and 127 deletions

View File

@ -412,133 +412,6 @@ Here's the complete data flow when running `helmfile sync`:
- Defaults & Values: `ArrayMergeStrategySparse` (auto-detect nil values)
- CLIOverrides: `ArrayMergeStrategyMerge` (always element-by-element)
## Technical Details
### Secret Handling Intern
Helmfile processes secrets in a special way:
**Non-HCL secrets (.yaml, .yaml.gotmpl):**
1. Decrypted using helm-secrets plugin
2. Parsed into values immediately (during load phase)
3. Stored separately from regular values
4. **Mrged last** (highest priority) after all environment values are loaded
**HCL secrets (.hcl):**
1. Decrypted using helm-secrets plugin
2. Decrypted file paths added to values file list
3. Processed in step 2 (HCL loading phase)
4. Can reference values from other HCL files (using `hv.` accessor)
This separation allows:
- Secrets to override regular values without being re-decrypted multiple times
- HCL secrets to participate in HCL's cross-file referencing system
### Multiple Helmfiles and State files
When using multi-part helmfiles (multiple YAML documents separated by `---`):
```yaml
# Part 1: base.yaml
helmDefaults:
wait: true
timeout: 300
---
# Part 2: environments.yaml
environments:
default:
production:
```
Each part is processed in order:
and the results are merged with later parts taking precedence.
## Technical Details
### Environment Structure Internals
The `Environment` struct has three key fields that affect merging:
```go
type Environment struct {
Name string
KubeContext string
Values map[string]any // Environment values + secrets
Defaults map[string]any // Root-level values: block
CLIOverrides map[string]any // CLI --state-values-set
}
```
### Final Merge Process (GetMergedValues)
When you access `.Values` in templates, Helmfile calls `GetMergedValues()` which merges in this order:
```go
func (e *Environment) GetMergedValues() (map[string]any, error) {
vals := map[string]any{}
vals = maputil.MergeMaps(vals, e.Defaults) // 1. Defaults (root-level values:)
vals = maputil.MergeMaps(vals, e.Values) // 2. Values (environment values + secrets)
vals = maputil.MergeMaps(vals, e.CLIOverrides, // 3. CLIOverrides (highest priority)
maputil.MergeOptions{ArrayStrategy: maputil.ArrayMergeStrategyMerge})
return vals, nil
}
```
**Important:** CLIOverrides uses `ArrayMergeStrategyMerge` (element-by-element merging), while Defaults and Values use the default strategy (sparse auto-detection).
### Merging Library: mergo
Helmfile uses the [mergo](https://github.com/imdario/mergo) library for deep merging with these key features:
1. **Deep merge for maps**: Nested maps are merged recursively
2. **WithOverride option**: Later values override earlier values
3. **Type-safe**: Preserves value types during merge
Example from code:
```go
// In loadEnvValues()
if err := mergo.Merge(&valuesVals, &secretVals, mergo.WithOverride); err != nil {
return nil, err
}
```
### Array Merge Strategies Implementation
The `maputil.MergeMaps` function supports three array merge strategies:
```go
type ArrayMergeStrategy int
const (
ArrayMergeStrategySparse ArrayMergeStrategy = iota // Auto-detect based on nil values
ArrayMergeStrategyReplace ArrayMergeStrategy = iota // Always replace arrays
ArrayMergeStrategyMerge ArrayMergeStrategy = iota // Always merge element-by-element
)
```
**Sparse Strategy (Default for most cases):**
```go
func mergeSlices(base, override []any, strategy ArrayMergeStrategy) []any {
if strategy == ArrayMergeStrategySparse {
isSparse := false
for _, v := range override {
if v == nil {
isSparse = true
break
}
}
if !isSparse {
return override // Replace entirely
}
// Otherwise merge element-by-element
}
}
```
This means:
- `[1, 2, 3]` merged with `[4, 5]` → result: `[4, 5]` (replaced, no nils)
- `[null, 2]` merged with `[1, 2, 3]` → result: `[1, 2, 3]` (merged, has nil)
## Common Patterns
### Pattern 1: Global Defaults with Environment Overrides
@ -633,6 +506,44 @@ environments:
## Technical Implementation Details
### Secret Handling
Helmfile processes secrets in a special way:
**Non-HCL secrets (.yaml, .yaml.gotmpl):**
1. Decrypted using helm-secrets plugin
2. Parsed into values immediately (during load phase)
3. Stored separately from regular values
4. **Merged last** (highest priority) after all environment values are loaded
**HCL secrets (.hcl):**
1. Decrypted using helm-secrets plugin
2. Decrypted file paths added to values file list
3. Processed in step 2 (HCL loading phase)
4. Can reference values from other HCL files (using `hv.` accessor)
This separation allows:
- Secrets to override regular values without being re-decrypted multiple times
- HCL secrets to participate in HCL's cross-file referencing system
### Multiple Helmfiles and State files
When using multi-part helmfiles (multiple YAML documents separated by `---`):
```yaml
# Part 1: base.yaml
helmDefaults:
wait: true
timeout: 300
---
# Part 2: environments.yaml
environments:
default:
production:
```
Each part is processed in order and the results are merged with later parts taking precedence.
### Environment Structure
The `Environment` struct is the core data structure that holds all values: