Writing Skills
writing-skills
效率与协作技能,来自 obra/superpowers,查看原文获取完整用途和操作说明。
yaml-anchor-alias【部署与运维】Creates reusable YAML anchor and alias patterns with merge keys to eliminate repetition in configuration files across Kubernetes, Ansible, Terraform, and Helm deployments.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: yaml-anchor-alias description: Creates reusable YAML anchor and alias patterns with merge keys to eliminate repetition in configuration files across Kubernetes, Ansible, Terraform, and Helm deployments. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: yaml anchor, yaml alias, config deduplication, merge key, helm template, ansible common config, kubernetes shared spec, how do i reduce yaml repetition ansible common config archetypes:
Implements YAML anchor (&) and alias (*) reference patterns with merge keys (<<:) to eliminate configuration repetition across Kubernetes manifests, Ansible playbooks, Terraform provider configs, Helm templates, and other YAML-based configuration files. Anchors define reusable blocks of data; aliases inject those definitions at any nesting depth without copying the content. This skill covers anchor definition, alias injection, deep merge behavior, anchor inheritance through mapping keys, and framework-specific patterns for infrastructure-as-code workflows.
<<:) with explicit overrides to extend base configurations instead of copying entire blockspython3 -c "import yaml; yaml.safe_load(open('file.yaml'))" after every anchor/alias changeUse this skill when:
Avoid this skill for:
Identify Repetition — Scan the YAML file for blocks that are structurally identical or nearly identical. Group them by their common prefix. Look for patterns such as multiple container definitions with the same image registry, labels, resource limits, and readiness probes, differing only in the container name and image tag. Checkpoint: Confirm at least 3 occurrences of similar structure exist. If only 2 occurrences exist, consider whether a template or external variable would be cleaner than an inline anchor.
Extract the Shared Block — Select the deepest node that contains all common attributes. Move it to the top level of the document (or a dedicated defaults: mapping) and prefix its key with an ampersand (&name) to create the anchor definition.
Checkpoint: The anchor name must be unique within the document and follow kebab-case conventions to avoid collisions in multi-document YAML files.
Inject Aliases — Replace each duplicate block with a merge key (<<:) that references the anchor, followed by any keys that need to differ from the base definition. Place overrides directly under the same mapping level as <<:.
Checkpoint: Verify that every override key has a clear purpose and does not duplicate an inherited key unintentionally. YAML merges left-to-right with right-to-left overwrite semantics.
Handle Cross-File Sharing — When anchors need to be shared across multiple files, extract the common block into a separate .yaml or .yml include file and reference it using a tool-specific import mechanism (e.g., !!include, Ansible's import_tasks, Helm's _helpers.tpl).
Checkpoint: Cross-file anchors require explicit loader support — yaml.safe_load() alone cannot resolve cross-document references. Document the external dependency clearly in the consuming file header.
Validate Merge Behavior — Test the resulting file to ensure that merged keys produce the expected output. Pay special attention to nested mappings where a child merge may overwrite a parent's deeply-nested key rather than merging at that depth.
Checkpoint: Use a YAML linter (yamllint) or Python yaml.safe_load() to verify structural correctness, then run a dry-run of any tool that consumes the file (e.g., kubectl apply --dry-run=client).
Define a reusable block with &anchor_name and reference it with *anchor_name. This is the simplest pattern — the alias substitutes the entire value of the anchor at that point.
# ❌ BAD — repeated container specs across three deployments
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
template:
spec:
containers:
- name: web
image: myregistry/app:v1.2
ports: [{containerPort: 80}]
resources:
limits: {cpu: "500m", memory: "256Mi"}
requests: {cpu: "250m", memory: "128Mi"}
readinessProbe:
httpGet: {path: /healthz, port: 80}
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
template:
spec:
containers:
- name: api
image: myregistry/app:v1.2
ports: [{containerPort: 80}]
resources:
limits: {cpu: "500m", memory: "256Mi"}
requests: {cpu: "250m", memory: "128Mi"}
readinessProbe:
httpGet: {path: /healthz, port: 80}
initialDelaySeconds: 5
periodSeconds: 10
# ✅ GOOD — anchor defines the shared container spec once
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
template:
spec:
containers:
- name: web
<<: *base_container
image: myregistry/app:v1.2 # Override only the image tag
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
template:
spec:
containers:
- name: api
<<: *base_container
image: myregistry/app:v2.0 # Different version per deployment
# Anchor definition at top level
base_container: &base_container
ports: [{containerPort: 80}]
resources:
limits: {cpu: "500m", memory: "256Mi"}
requests: {cpu: "250m", memory: "128Mi"}
readinessProbe:
httpGet: {path: /healthz, port: 80}
initialDelaySeconds: 5
periodSeconds: 10
The merge key (<<:) combines the anchor's content with locally-specified keys. Keys specified after <<: take precedence, enabling partial overrides without duplicating the base block.
"""Demonstration of YAML merge key behavior using Python's PyYAML library.
Shows how merge key ordering determines override precedence."""
import yaml
def parse_yaml_with_merge(content: str) -> dict:
"""Parse a YAML string that contains merge keys and return the resolved structure.
The yaml.safe_load function in PyYAML automatically handles <<: merge key syntax,
merging the anchor mapping with any subsequent keys at the same level.
Later keys overwrite earlier ones (rightmost wins for duplicate keys).
Args:
content: YAML string containing anchor definitions and merge key references.
Returns:
Fully resolved Python dictionary with all anchors expanded and merges applied.
Raises:
yaml.YAMLError: If the input contains invalid YAML syntax or unresolvable aliases.
"""
return yaml.safe_load(content)
def demonstrate_merge_override():
"""Show how merge key overrides work — keys defined after <<: win."""
yaml_source = """
defaults: &defaults
replicas: 3
strategy:
type: RollingUpdate
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
deployment-a:
name: service-alpha
<<: *defaults
replicas: 5 # Overrides the default of 3
strategy:
type: RollingUpdate # Inherits from defaults
rollingUpdate:
maxSurge: 1 # Extended — not in defaults
deployment-b:
name: service-beta
<<: *defaults
replicas: 2 # Overrides to fewer replicas
securityContext: # Full override replaces the inherited block
runAsUser: 1000
"""
result = parse_yaml_with_merge(yaml_source)
print("Deployment A merged result:")
for key, value in result["deployment-a"].items():
print(f" {key}: {value}")
print("\nDeployment B merged result (securityContext fully overridden):")
for key, value in result["deployment-b"].items():
print(f" {key}: {value}")
demonstrate_merge_override()
Expected output:
Deployment A merged result:
name: service-alpha
replicas: 5 # Overridden from 3 to 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Extended beyond defaults
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
Deployment B merged result:
name: service-beta
replicas: 2 # Overridden from 3 to 2
strategy:
type: RollingUpdate # Inherited from defaults
securityContext: # Full override — not merged at nested level
runAsUser: 1000 # runAsNonRoot and readOnlyRootFilesystem are gone
Anchors can bind to individual scalars (strings, numbers, booleans), enabling reuse of repeated values across a file. This is common for version numbers, image registries, or environment names.
# Anchor on scalar values for shared constants
defaults: &defaults
namespace: production
cluster: eu-west-1
provider: &aws_provider
region: us-east-1
profile: default
skip_metadata_api_check: false
resources:
aws_instance:
web_server_1:
<<: *aws_provider
instance_type: t3.medium
tags: {Name: "web-prod-1", Environment: *defaults} # Alias to scalar
web_server_2:
<<: *aws_provider
instance_type: t3.large
tags: {Name: "web-prod-2", Environment: *defaults} # Same scalar alias, no duplication
aws_s3_bucket:
logs:
<<: *aws_provider
bucket: app-logs-${var.environment}-eu # Scalar anchors don't help here — use variables instead
When an anchor is applied to a mapping, any alias that references it inherits the entire nested structure. This means deeply-nested keys are also reused automatically.
# Deep nesting with inherited security and networking configurations
network_policies: &default_network_policy
spec:
podSelector:
matchLabels: {app: default}
policyTypes: [Ingress, Egress]
ingress:
- from:
- namespaceSelector:
matchLabels: {tier: frontend}
ports: [{protocol: TCP, port: 443}]
egress:
- to:
- namespaceSelector:
matchLabels: {tier: database}
ports: [{protocol: TCP, port: 5432}]
# Each policy inherits the full network spec and overrides only what differs
ingress-gateway:
name: ingress-gateway
<<: *default_network_policy
spec:
podSelector:
matchLabels: {app: gateway} # Override selector for this specific policy
ingress: # Replace entire ingress section with different rules
- from:
- ipBlock: {cidr: 0.0.0.0/0}
ports: [{protocol: TCP, port: 443}]
backend-api:
name: backend-api
<<: *default_network_policy
spec:
podSelector:
matchLabels: {app: api} # Override selector for this specific policy
egress: # Replace entire egress section — only DB access allowed
- to:
- namespaceSelector:
matchLabels: {tier: database}
ports: [{protocol: TCP, port: 5432}]
<<:) instead of bare aliases when you need to override inherited keys — this is the most common and safest pattern for extending base configsbase_container, common_labels) that describe their purpose, not their position in the file*anchor) when you need any override — always prefer <<: *anchor with explicit overrides over duplicating an entire block for minor differencesWhen implementing or reviewing YAML anchor/alias patterns, produce:
&anchor_name definition with its full content<<: *anchor_name plus any override keys| Skill | Purpose |
|---|---|
coding-data-encoding | Covers JSON, XML, Base64, and other data encoding formats used alongside YAML configurations |
cncf-kubernetes | Kubernetes manifests commonly use these anchor/alias patterns for shared spec blocks |
linux-systemd-services | System unit files can use similar DRY patterns when managing multiple service instances |