Advanced Usage
Advanced techniques for power users and complex deployment scenarios. This page assumes familiarity with Writing Manifests, Kustomize Integration, and the CLI Reference.
Runtime Value Overrides with --set
The --set flag lets you override manifest values without editing files. Think of it like command-line arguments for your infrastructure.
Basic Syntax
openmcf pulumi up \
-f deployment.yaml \
--set key=value
Nested Fields
Use dot notation to access nested fields:
# Override nested spec fields
openmcf pulumi up \
-f api.yaml \
--set spec.container.replicas=5 \
--set spec.container.image.tag=v2.0.0 \
--set spec.container.resources.limits.cpu=2000m
Multiple Overrides
Repeat the --set flag multiple times:
openmcf pulumi up \
-f deployment.yaml \
--set spec.replicas=10 \
--set spec.container.image.tag=v1.5.0 \
--set metadata.labels.version=v1.5.0 \
--set metadata.labels.environment=staging
When to Use --set
✅ Good use cases:
- Quick testing: "What if I used 10 replicas instead of 3?"
- CI/CD parameterization: Dynamic image tags from build pipeline
- Emergency overrides: Temporary configuration changes
- A/B testing: Compare different configurations
❌ Bad use cases:
- Permanent configuration: Changes that should be committed
- Complex changes: Better to edit manifest directly
- Team deployments: Others won't see the override in Git
Examples
Testing different replica counts:
# Test with 1 replica (cheapest)
openmcf pulumi preview \
-f api.yaml \
--set spec.replicas=1
# Test with 5 replicas (more realistic)
openmcf pulumi preview \
-f api.yaml \
--set spec.replicas=5
# Deploy with 3 (commit to manifest for permanence)
vim api.yaml # Set replicas: 3
openmcf pulumi up -f api.yaml
Dynamic image tags in CI/CD:
# In GitHub Actions
IMAGE_TAG="${GITHUB_SHA:0:7}" # Short commit hash
openmcf pulumi up \
-f deployment.yaml \
--set spec.container.image.tag=$IMAGE_TAG \
--yes
Emergency scaling:
# Production is slow, scale up immediately
openmcf pulumi up \
-f prod-api.yaml \
--set spec.replicas=10 \
--yes
# Later: Update manifest and revert to normal
vim prod-api.yaml # Set permanent replica count
openmcf pulumi up -f prod-api.yaml
Limitations
Cannot override:
- Lists/arrays directly (override the whole field instead)
- Maps with specific keys (override entire map)
- Complex nested structures (edit manifest instead)
Can override:
- Strings
- Numbers (int, float)
- Booleans
- Nested scalar fields
- Message fields (creates if needed)
Loading Manifests from URLs
Deploy infrastructure directly from URLs without downloading files manually.
Basic Usage
# Deploy from GitHub raw URL
openmcf pulumi up \
-f https://raw.githubusercontent.com/myorg/manifests/main/prod/database.yaml
# Deploy from any HTTPS URL
openmcf pulumi up \
-f https://config-server.example.com/api/manifests/vpc.yaml
How It Works
1. CLI detects manifestPath is a URL (has scheme + host)
↓
2. Downloads file using http.Get
↓
3. Saves to temp file with generated name (ULID)
↓
4. Processes temp file as normal manifest
↓
5. Deploys
↓
6. Cleans up temp file
Temp file location: ~/.openmcf/manifests/downloaded/<ulid>.yaml
Use Cases
Centralized manifest repository:
# Team maintains manifests in central repo
# Developers deploy from URLs
MANIFEST_REPO="https://raw.githubusercontent.com/myorg/infra-manifests/main"
openmcf pulumi up \
-f $MANIFEST_REPO/prod/database.yaml
openmcf pulumi up \
-f $MANIFEST_REPO/prod/cache.yaml
Generated manifests from API:
# CI/CD generates manifests via API
MANIFEST_URL=$(curl -s https://config-api.example.com/generate?env=prod&service=api)
openmcf pulumi up -f $MANIFEST_URL
Version-pinned deployments:
# Deploy from specific Git tag/commit
openmcf pulumi up \
-f https://raw.githubusercontent.com/myorg/manifests/v1.0.0/database.yaml
# Rollback to previous version
openmcf pulumi up \
-f https://raw.githubusercontent.com/myorg/manifests/v0.9.0/database.yaml
URL Requirements
- Must be HTTPS (HTTP not allowed for security)
- Must return raw YAML (not HTML page)
- Must be publicly accessible (no authentication)
GitHub raw URLs:
# ✅ Correct - raw.githubusercontent.com
https://raw.githubusercontent.com/myorg/manifests/main/database.yaml
# ❌ Wrong - github.com (returns HTML)
https://github.com/myorg/manifests/blob/main/database.yaml
Validation and Load-Manifest
Use openmcf validate to catch errors before deployment, and openmcf load-manifest to inspect the effective manifest with defaults and overrides applied. For detailed usage of these commands, see Configuration.
# Validate manifest
openmcf validate -f resource.yaml
# Inspect effective manifest with defaults
openmcf load-manifest -f resource.yaml
# Inspect with overrides applied
openmcf load-manifest -f resource.yaml --set spec.container.replicas=5
# Inspect kustomize output
openmcf load-manifest --kustomize-dir services/api/kustomize --overlay prod
Module Directory Override
Customize or test IaC modules locally before deploying. For the conceptual overview of how module resolution works (direct, binary, staging), see Module System.
When to Use --module-dir
- Local development: Testing changes to Pulumi/OpenTofu modules
- Custom modules: Using forked/modified deployment modules
- Module testing: Validating module changes before committing
Default Behavior
Without --module-dir, OpenMCF uses current working directory:
cd /path/to/module
openmcf pulumi up -f resource.yaml
# Uses current directory as module directory
Override Behavior
With --module-dir, you can deploy from anywhere:
# From any location
openmcf pulumi up \
-f ~/manifests/database.yaml \
--module-dir ~/projects/custom-modules/postgres-k8s
Local Module Development Workflow
# 1. Clone or fork a module
git clone https://github.com/plantonhq/openmcf
cd apis/org/openmcf/provider/kubernetes/postgresqk8s/v1/iac/pulumi
# 2. Make changes to module code
vim main.go
# 3. Test with your manifest
openmcf pulumi preview \
-f ~/test-manifests/postgres.yaml \
--module-dir .
# 4. Iterate
vim main.go
openmcf pulumi preview -f ~/test-manifests/postgres.yaml --module-dir .
# 5. Deploy when ready
openmcf pulumi up \
-f ~/test-manifests/postgres.yaml \
--module-dir .
Custom Module Example
Fork and customize:
# 1. Fork the default module
cp -r apis/org/openmcf/provider/aws/awss3bucket/v1/iac/pulumi \
~/custom-modules/my-s3-module
# 2. Customize
cd ~/custom-modules/my-s3-module
vim main.go # Add custom logic
# 3. Test
openmcf pulumi up \
-f s3-bucket.yaml \
--module-dir ~/custom-modules/my-s3-module
# 4. If it works, consider contributing back or maintaining internally
Combining Techniques
Kustomize + --set
# Base from kustomize, runtime override for image tag
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay prod \
--set spec.container.image.tag=$GIT_SHA
Order of application:
- Kustomize builds base + overlay
- --set overrides applied to result
- Final manifest validated
- Deployed
URL Manifest + --set
# Load from URL, override specific values
openmcf pulumi up \
-f https://manifests.example.com/database.yaml \
--set spec.region=us-west-2 \
--set spec.instanceSize=large
Kustomize + Custom Module
# Custom overlay + custom module
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay prod \
--module-dir ~/custom-modules/api-module
Pro Tips
1. Use Shell Variables for Readability
# ✅ Good: Clear and reusable
MANIFEST="ops/resources/database.yaml"
OVERLAY="prod"
IMAGE_TAG="v1.2.3"
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay $OVERLAY \
--set spec.container.image.tag=$IMAGE_TAG
# ❌ Bad: Hard to read, error-prone
openmcf pulumi up --kustomize-dir services/api/kustomize --overlay prod --set spec.container.image.tag=v1.2.3
2. Create Deployment Scripts
#!/bin/bash
# deploy-api.sh
set -e
ENVIRONMENT=${1:-dev}
IMAGE_TAG=${2:-latest}
echo "Deploying API to $ENVIRONMENT with tag $IMAGE_TAG"
openmcf pulumi preview \
--kustomize-dir services/api/kustomize \
--overlay $ENVIRONMENT \
--set spec.container.image.tag=$IMAGE_TAG
read -p "Apply? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay $ENVIRONMENT \
--set spec.container.image.tag=$IMAGE_TAG
fi
Usage:
./deploy-api.sh staging v1.2.0
3. Validate in Pre-Commit Hooks
.git/hooks/pre-commit:
#!/bin/bash
# Validate all manifests before committing
for manifest in $(git diff --cached --name-only --diff-filter=ACM | grep '\.yaml$'); do
if openmcf validate -f $manifest; then
echo "✓ $manifest valid"
else
echo "✗ $manifest invalid"
exit 1
fi
done
4. Use Make for Complex Workflows
Makefile:
.PHONY: validate deploy-dev deploy-staging deploy-prod
validate:
@for f in ops/manifests/*.yaml; do \
openmcf validate -f $$f; \
done
deploy-dev:
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay dev \
--yes
deploy-staging:
openmcf pulumi preview \
--kustomize-dir services/api/kustomize \
--overlay staging
@read -p "Deploy to staging? (y/N) " REPLY; \
if [ "$$REPLY" = "y" ]; then \
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay staging; \
fi
deploy-prod:
@echo "⚠️ Production deployment - review carefully"
openmcf pulumi preview \
--kustomize-dir services/api/kustomize \
--overlay prod
@echo "Deploy to PRODUCTION?"
@read -p "Type 'yes' to confirm: " REPLY; \
if [ "$$REPLY" = "yes" ]; then \
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay prod; \
fi
Usage:
make validate
make deploy-dev
make deploy-prod
Advanced Patterns
Pattern 1: Environment Matrix Testing
Test configuration across all environments:
#!/bin/bash
# test-all-environments.sh
for env in dev staging prod; do
echo "Testing $env environment..."
if openmcf validate \
--kustomize-dir services/api/kustomize \
--overlay $env; then
echo "✓ $env configuration valid"
else
echo "✗ $env configuration invalid"
exit 1
fi
done
Pattern 2: Progressive Rollout
Deploy gradually across environments with validation:
#!/bin/bash
# progressive-rollout.sh
IMAGE_TAG=$1
# Deploy to dev
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay dev \
--set spec.container.image.tag=$IMAGE_TAG \
--yes
# Wait and test
sleep 60
curl -f https://api-dev.example.com/health || exit 1
# Deploy to staging
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay staging \
--set spec.container.image.tag=$IMAGE_TAG \
--yes
# Wait and test
sleep 60
curl -f https://api-staging.example.com/health || exit 1
# Deploy to prod (with manual confirmation)
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay prod \
--set spec.container.image.tag=$IMAGE_TAG
Debugging Techniques
Inspecting Final Manifest
See exactly what gets deployed:
# Load manifest with all transformations applied
openmcf load-manifest \
--kustomize-dir services/api/kustomize \
--overlay prod \
--set spec.container.image.tag=v1.2.0 \
> final-manifest.yaml
# Review
cat final-manifest.yaml
Validating Before Deploy
# Validate with overrides
openmcf validate \
--kustomize-dir services/api/kustomize \
--overlay prod
# If validation passes, deploy
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay prod
Testing Module Changes
# Test modified module without deploying
cd ~/projects/custom-module
# 1. Validate manifest
openmcf validate -f ~/test-manifests/test.yaml
# 2. Preview changes
openmcf pulumi preview \
-f ~/test-manifests/test.yaml \
--module-dir .
# 3. If preview looks good, deploy to test environment
openmcf pulumi up \
-f ~/test-manifests/test.yaml \
--module-dir . \
--stack test-org/test-project/test-stack
Power User Workflows
Multi-Manifest Deployment
Deploy multiple related resources:
#!/bin/bash
# deploy-stack.sh
OVERLAY=${1:-dev}
MANIFESTS=(
"vpc.yaml"
"database.yaml"
"cache.yaml"
"application.yaml"
)
for manifest in "${MANIFESTS[@]}"; do
echo "Deploying $manifest to $OVERLAY..."
openmcf pulumi up \
--kustomize-dir ops/resources/kustomize \
--overlay $OVERLAY \
--yes
# Wait between deployments
sleep 10
done
Conditional Deployment
Deploy only if validation passes:
if openmcf validate -f database.yaml; then
echo "✓ Validation passed, deploying..."
openmcf pulumi up -f database.yaml --yes
else
echo "✗ Validation failed, aborting"
exit 1
fi
Parameterized Deployments
#!/bin/bash
# deploy-with-params.sh
ENVIRONMENT=$1
REPLICAS=$2
CPU=$3
MEMORY=$4
openmcf pulumi up \
--kustomize-dir services/api/kustomize \
--overlay $ENVIRONMENT \
--set spec.replicas=$REPLICAS \
--set spec.container.resources.limits.cpu=$CPU \
--set spec.container.resources.limits.memory=$MEMORY
Usage:
./deploy-with-params.sh prod 5 2000m 4Gi
Common Mistakes to Avoid
❌ Using --set for Permanent Changes
# BAD: Override in CI/CD but not in manifest
openmcf pulumi up \
-f api.yaml \
--set spec.replicas=10 \
--yes
# 3 months later: "Why is prod running 10 replicas?"
# Nobody knows because it's not in the manifest!
# GOOD: Update manifest first
vim api.yaml # Set replicas: 10
git commit -m "scale: increase API replicas to 10"
openmcf pulumi up -f api.yaml --yes
❌ Loading Non-Raw GitHub URLs
# BAD: Returns HTML page, not YAML
openmcf pulumi up \
-f https://github.com/myorg/repo/blob/main/manifest.yaml
# GOOD: Use raw.githubusercontent.com
openmcf pulumi up \
-f https://raw.githubusercontent.com/myorg/repo/main/manifest.yaml
❌ Complex --set Overrides
# BAD: Trying to override complex structures
openmcf pulumi up \
-f api.yaml \
--set spec.container.resources='{"limits":{"cpu":"2000m"}}' # Won't work
# GOOD: Override individual fields
openmcf pulumi up \
-f api.yaml \
--set spec.container.resources.limits.cpu=2000m
What's Next
- Writing Manifests — Manifest structure and best practices
- Kustomize Integration — Multi-environment overlay workflows
- CI/CD Integration — Automation patterns for pipelines
- Module System — How module resolution works
- CLI Reference — Complete command and flag reference
Next article