Implementing secure and efficient migration practices is essential for production environments. This chapter covers comprehensive best practices for plan management, provider security, query optimization, and secure operations derived from real-world deployment experience and security requirements.
Overview: Operational Excellence Framework
Best Practices Philosophy
Effective kubectl-mtv operations balance several key principles:
- Security by Default: Implement least-privilege access, secure authentication, and encrypted communications
- Operational Efficiency: Optimize workflows, automate repetitive tasks, and minimize manual interventions
- Risk Management: Test thoroughly, implement rollback procedures, and maintain audit trails
- Performance Optimization: Leverage warm migrations, optimize resource placement, and monitor performance
- Maintainability: Document configurations, standardize procedures, and implement consistent naming
Security Layers
Migration security encompasses multiple layers:
- Authentication: Provider credentials, service accounts, and user authentication
- Authorization: RBAC policies, namespace isolation, and resource access control
- Network Security: TLS encryption, certificate validation, and network policies
- Data Protection: Encryption at rest, secure key management, and data integrity
- Audit and Compliance: Logging, monitoring, and regulatory compliance
Plan Management Strategies
Testing and Validation
Migration Testing Hierarchy
Implement systematic testing approaches:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| # 1. Single VM Test Plan
kubectl mtv create plan test-single \
--source test-provider \
--target test-cluster \
--vms "small-test-vm" \
--target-namespace test-migrations \
--migration-type cold
# 2. Small Batch Test Plan
kubectl mtv create plan test-batch \
--source test-provider \
--target test-cluster \
--vms "test-vm-01,test-vm-02,test-vm-03" \
--target-namespace test-migrations \
--migration-type warm
# 3. Production Pilot Plan
kubectl mtv create plan pilot-production \
--source prod-provider \
--target prod-cluster \
--vms "non-critical-app-01" \
--target-namespace production-pilot \
--migration-type warm \
--convertor-node-selector "migration=true"
# 4. Full Production Plan (after validation)
kubectl mtv create plan production-migration \
--source prod-provider \
--target prod-cluster \
--vms @validated-production-vms.yaml \
--target-namespace production \
--migration-type warm \
--network-mapping prod-network-map \
--storage-mapping prod-storage-map \
--pre-hook production-backup-hook \
--post-hook production-validation-hook
|
Test Plan Validation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Validate plan configuration before execution
kubectl mtv describe plan test-plan --with-vms
# Check resource availability
kubectl describe nodes | grep -A5 "Allocatable"
# Verify mapping configurations
kubectl mtv describe mapping network test-network-map
kubectl mtv describe mapping storage test-storage-map
# Test provider connectivity
kubectl mtv get inventory vm test-provider -v=2
# Validate target namespace and permissions
kubectl auth can-i create vm -n test-migrations
|
Warm Migration Strategy
Optimal Warm Migration Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # Production warm migration with strategic scheduling
kubectl mtv create plan production-warm \
--source vsphere-prod \
--target openshift-prod \
--migration-type warm \
--vms @production-vms.yaml \
--target-namespace production \
--convertor-node-selector "migration-worker=true,performance=high" \
--convertor-affinity "REQUIRE nodes(storage=nvme) on node" \
--target-affinity "PREFER nodes(production=true) on zone" \
--network-mapping production-network \
--storage-mapping production-storage
# Start with cutover scheduled for maintenance window
kubectl mtv start plan production-warm \
--cutover "$(date -d 'next Sunday 2:00 AM' --iso-8601=seconds)"
# Monitor warm migration progress
kubectl mtv get plan production-warm -w
# Adjust cutover if needed
kubectl mtv cutover plan production-warm \
--cutover "$(date -d '+30 minutes' --iso-8601=seconds)"
|
Warm Migration Benefits
- Reduced Downtime: Pre-copy phase minimizes service interruption
- Validation Window: Time to verify data transfer before cutover
- Rollback Capability: Source VM remains available until cutover completion
- Performance Optimization: Multiple attempts to optimize transfer speed
Archiving and Lifecycle Management
Strategic Plan Archival
1
2
3
4
5
6
7
8
9
10
11
12
13
| # Archive completed migrations for audit trail
kubectl mtv archive plan completed-q1-migration
kubectl mtv archive plan successful-pilot-test
# Bulk archive old completed plans
for plan in $(kubectl mtv get plans -o json | jq -r '.items[] | select(.status.phase == "Succeeded" and (.metadata.creationTimestamp | fromdateiso8601) < (now - 90*24*3600)) | .metadata.name'); do
echo "Archiving old plan: $plan"
kubectl mtv archive plan "$plan"
done
# Maintain active plans, archive obsolete ones
kubectl mtv get plans | grep -E "(Failed|Cancelled)" | awk '{print $1}' | \
xargs -I {} kubectl mtv archive plan {}
|
Plan Template Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # Create reusable plan templates
kubectl mtv create plan template-web-tier \
--source vsphere-template \
--migration-type warm \
--target-namespace web-applications \
--convertor-node-selector "workload=web" \
--target-affinity "PREFER pods(tier=web) on zone" \
--network-mapping web-network-map \
--storage-mapping web-storage-map \
--vms placeholder-vm
# Archive template for reuse
kubectl mtv archive plan template-web-tier
# Clone template for actual use
kubectl mtv unarchive plan template-web-tier
kubectl mtv patch plan template-web-tier \
--description "Q2 2024 web tier migration" \
--vms "web-01,web-02,web-03"
|
Provider Security
Credentials Management
Secure Provider Creation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Use strong authentication credentials
kubectl mtv create provider secure-vsphere \
--type vsphere \
--url https://vcenter.secure.com/sdk \
--username "migration_service@secure.local" \
--password "$(openssl rand -base64 32)" \
--cacert @/secure/certificates/vcenter-ca.crt \
--vddk-init-image registry.secure.com/vddk:8.0.2
# Verify certificate validation is enabled
kubectl mtv describe provider secure-vsphere | grep -i "skip.*tls\|insecure"
# Rotate credentials regularly
kubectl mtv patch provider secure-vsphere \
--password "$(openssl rand -base64 32)"
|
Secret Management Best Practices
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # Use dedicated service accounts for providers
kubectl create serviceaccount migration-service -n migrations
# Create secrets with appropriate labels and annotations
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: vsphere-credentials
namespace: migrations
labels:
app: migration
provider-type: vsphere
security-level: restricted
annotations:
kubernetes.io/description: "VMware vSphere migration credentials"
migration.security/rotation-schedule: "monthly"
migration.security/access-review: "quarterly"
type: Opaque
stringData:
username: "migration_service@vsphere.local"
password: "secure-generated-password"
EOF
# Reference secure secret in provider
kubectl mtv create provider secure-vsphere \
--type vsphere \
--url https://vcenter.company.com/sdk \
--existing-secret vsphere-credentials \
--cacert @/etc/ssl/certs/company-ca.pem
|
TLS Verification
Certificate Validation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # Always validate certificates in production
kubectl mtv create provider production-vsphere \
--type vsphere \
--url https://vcenter.prod.company.com/sdk \
--username "migration@company.com" \
--password "secure-password" \
--cacert @/etc/ssl/company/vcenter-ca.crt
# Note: No --insecure-skip-tls flag
# For development only, use insecure connections with clear labeling
kubectl mtv create provider dev-vsphere \
--type vsphere \
--url https://vcenter-dev.company.com/sdk \
--username "dev-migration@company.com" \
--password "dev-password" \
--provider-insecure-skip-tls
# Add clear labels for security auditing
kubectl label provider dev-vsphere \
security-level=development \
certificate-validation=disabled \
environment=non-production
|
Certificate Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Extract and verify certificates
openssl s_client -connect vcenter.company.com:443 -showcerts < /dev/null 2>/dev/null | \
openssl x509 -outform PEM > vcenter-cert.pem
# Verify certificate chain
openssl verify -CAfile company-ca.pem vcenter-cert.pem
# Use certificate bundle for provider
kubectl mtv create provider verified-vsphere \
--type vsphere \
--url https://vcenter.company.com/sdk \
--username "migration@company.com" \
--password "secure-password" \
--cacert @vcenter-cert.pem
|
RBAC Configuration
Least-Privilege Provider Access
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| # Minimal RBAC for migration operators
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: migration-operator
rules:
# MTV/Forklift resources
- apiGroups: ["forklift.konveyor.io"]
resources: ["providers", "plans", "mappings", "hosts"]
verbs: ["get", "list", "create", "update", "patch", "delete", "watch"]
# Secret access for credentials
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "update", "patch"]
resourceNames: ["vsphere-*", "ovirt-*", "openstack-*"]
# Inventory access
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
# Route discovery (OpenShift)
- apiGroups: ["route.openshift.io"]
resources: ["routes"]
verbs: ["get", "list"]
---
# Bind to service account
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: migration-operator-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: migration-operator
subjects:
- kind: ServiceAccount
name: migration-operator
namespace: migrations
|
Namespace-Scoped RBAC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # Namespace-specific migration permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production-migrations
name: migration-user
rules:
- apiGroups: ["forklift.konveyor.io"]
resources: ["plans"]
verbs: ["get", "list", "create", "update", "patch", "watch"]
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["get", "list", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: production-migration-users
namespace: production-migrations
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: migration-user
subjects:
- kind: User
name: alice@company.com
apiGroup: rbac.authorization.k8s.io
- kind: User
name: bob@company.com
apiGroup: rbac.authorization.k8s.io
|
Query Optimization Tips
Efficient Inventory Queries
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Use specific filters instead of broad queries
# Good: Specific criteria
kubectl mtv get inventory vm vsphere-prod \
--query "where powerState = 'poweredOn' and memory.size > 8192 and name like 'prod-%'"
# Avoid: Broad unfiltered queries
# kubectl mtv get inventory vm vsphere-prod # Returns everything
# Good: Targeted network queries
kubectl mtv get inventory network vsphere-prod \
--query "where name ~= '.*production.*' and type != 'dvPortGroup'"
# Good: Storage queries with size filters
kubectl mtv get inventory storage vsphere-prod \
--query "where capacity > 1073741824 and type = 'VMFS'" # > 1GB
|
Index-Friendly Query Patterns
1
2
3
4
5
6
7
8
9
10
11
| # Use exact matches when possible (more efficient)
kubectl mtv get inventory vm vsphere-prod \
--query "where name = 'specific-vm-name'"
# Use LIKE with anchored patterns
kubectl mtv get inventory vm vsphere-prod \
--query "where name like 'prod-web-%'" # Anchored prefix
# Combine filters efficiently
kubectl mtv get inventory vm vsphere-prod \
--query "where powerState = 'poweredOn' and guestOS like 'linux%' and memory.size between 4096 and 16384"
|
Query Result Management
Efficient Result Processing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # Export large queries to files for processing
kubectl mtv get inventory vm large-provider \
--query "where tags.category = 'production'" \
-o planvms > production-vms.yaml
# Use pagination for massive datasets
kubectl mtv get inventory vm huge-provider \
--query "where name ~= '^[a-m].*'" # First half alphabetically
kubectl mtv get inventory vm huge-provider \
--query "where name ~= '^[n-z].*'" # Second half
# Process results in manageable chunks
for prefix in {a..z}; do
kubectl mtv get inventory vm large-provider \
--query "where name like '${prefix}%'" \
-o planvms > "vms-${prefix}.yaml"
done
|
Secure Service Account Setup for Admin Access
Administrative Service Account
Complete Admin Service Account Setup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| # Create dedicated namespace for migration administration
kubectl create namespace migration-admin
# Create administrative service account
kubectl create serviceaccount migration-admin -n migration-admin
# Create comprehensive admin cluster role
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: migration-admin
rules:
# Full MTV/Forklift access
- apiGroups: ["forklift.konveyor.io"]
resources: ["*"]
verbs: ["*"]
# Core Kubernetes resources for migration
- apiGroups: [""]
resources: ["secrets", "configmaps", "namespaces", "services", "pods", "persistentvolumes", "persistentvolumeclaims"]
verbs: ["get", "list", "create", "update", "patch", "delete", "watch"]
# Storage management
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses", "volumeattachments"]
verbs: ["get", "list"]
# Network management
- apiGroups: ["k8s.cni.cncf.io"]
resources: ["network-attachment-definitions"]
verbs: ["get", "list", "create", "update", "patch", "delete"]
# OpenShift routes (if applicable)
- apiGroups: ["route.openshift.io"]
resources: ["routes"]
verbs: ["get", "list"]
# Node information
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
# Events for troubleshooting
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
EOF
# Bind admin role to service account
kubectl create clusterrolebinding migration-admin-binding \
--clusterrole=migration-admin \
--serviceaccount=migration-admin:migration-admin
|
Token Management for Automation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # Create long-lived token secret (Kubernetes 1.24+)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: migration-admin-token
namespace: migration-admin
annotations:
kubernetes.io/service-account.name: migration-admin
type: kubernetes.io/service-account-token
EOF
# Extract token for use in automation
ADMIN_TOKEN=$(kubectl get secret migration-admin-token -n migration-admin -o jsonpath='{.data.token}' | base64 -d)
# Create kubeconfig for service account
kubectl config set-cluster migration-cluster \
--server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}') \
--certificate-authority-data=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
kubectl config set-credentials migration-admin \
--token="$ADMIN_TOKEN"
kubectl config set-context migration-admin-context \
--cluster=migration-cluster \
--user=migration-admin
# Test service account access
kubectl --context=migration-admin-context auth whoami
kubectl --context=migration-admin-context get providers --all-namespaces
|
Security Audit and Monitoring
Access Monitoring
1
2
3
4
5
6
7
8
9
10
11
| # Monitor service account usage
kubectl get events --all-namespaces | grep migration-admin
# Audit RBAC permissions
kubectl auth can-i --list --as=system:serviceaccount:migration-admin:migration-admin
# Check recent authentication events
kubectl get events --all-namespaces | grep -i "authentication\|authorization"
# Review service account tokens
kubectl get secrets --all-namespaces | grep service-account-token | grep migration
|
Security Compliance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # Regular permission reviews
echo "=== Migration Admin Permissions Review ==="
kubectl describe clusterrolebinding migration-admin-binding
kubectl describe clusterrole migration-admin
# Token rotation schedule
kubectl delete secret migration-admin-token -n migration-admin
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: migration-admin-token
namespace: migration-admin
annotations:
kubernetes.io/service-account.name: migration-admin
rotation-date: "$(date --iso-8601)"
type: kubernetes.io/service-account-token
EOF
# Access pattern analysis
kubectl get events --all-namespaces --sort-by='.metadata.creationTimestamp' | \
grep migration-admin | tail -50
|
Operational Security Framework
Network Security
Network Policies for Migration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # Restrict migration namespace network access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: migration-network-policy
namespace: migrations
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: migration-admin
egress:
- to:
- namespaceSelector:
matchLabels:
name: openshift-mtv
- to: []
ports:
- protocol: TCP
port: 443 # HTTPS for provider APIs
- protocol: TCP
port: 6443 # Kubernetes API
|
Secure Communication
1
2
3
4
5
6
7
8
| # Ensure all provider communications use TLS
kubectl mtv get providers -o yaml | grep -B5 -A5 "insecureSkipTLS: true" || echo "All providers use TLS"
# Verify certificate validation
for provider in $(kubectl mtv get providers -o jsonpath='{.items[*].metadata.name}'); do
echo "Provider: $provider"
kubectl mtv describe provider "$provider" | grep -i "certificate\|tls\|insecure"
done
|
Data Protection
Encryption and Key Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Use encrypted secrets for provider credentials
kubectl create secret generic secure-provider-creds \
--from-literal=username=encrypted_user \
--from-literal=password="$(gpg --symmetric --armor --cipher-algo AES256 <<< 'actual-password')" \
-n migrations
# Label secrets for encryption compliance
kubectl label secret secure-provider-creds \
encryption=required \
compliance=sox \
data-classification=confidential
# Verify secret encryption at rest
kubectl get secrets -o yaml | grep -A5 -B5 "encryption"
|
Audit Trail Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # Enable audit logging for migration operations
cat <<EOF | sudo tee /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Detailed
resources:
- group: "forklift.konveyor.io"
resources: ["*"]
- level: Request
verbs: ["create", "update", "patch", "delete"]
resources:
- group: ""
resources: ["secrets"]
namespaces: ["migrations", "migration-admin"]
EOF
# Monitor audit logs for migration activities
sudo journalctl -u kubelet | grep -i "forklift\|migration" | tail -20
|
Resource Limits and Quotas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| # Resource quota for migration namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: migration-quota
namespace: migrations
spec:
hard:
requests.cpu: "20"
requests.memory: 64Gi
limits.cpu: "40"
limits.memory: 128Gi
persistentvolumeclaims: "50"
secrets: "20"
---
# Limit range for migration pods
apiVersion: v1
kind: LimitRange
metadata:
name: migration-limits
namespace: migrations
spec:
limits:
- type: Pod
max:
cpu: "8"
memory: 16Gi
default:
cpu: "2"
memory: 4Gi
defaultRequest:
cpu: "1"
memory: 2Gi
|
Secure Convertor Pod Configuration
1
2
3
4
5
6
7
8
9
| # Create convertor pods with security context
kubectl mtv create plan secure-migration \
--source vsphere-secure \
--convertor-node-selector "security=restricted,taint=dedicated" \
--convertor-labels "security-context=restricted,compliance=required" \
--vms @secure-vms.yaml
# Verify convertor security configuration
kubectl describe pod convertor-pod | grep -A10 "Security Context"
|
Compliance and Governance
Migration Documentation
Required Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # Document all migration plans
cat <<EOF > migration-documentation.md
# Migration Plan Documentation
## Plan: production-q4-migration
- **Purpose**: Quarterly production workload migration
- **Source**: VMware vSphere 7.0 (vcenter.company.com)
- **Target**: OpenShift 4.12 (prod-cluster.company.com)
- **Migration Window**: 2024-01-15 02:00-06:00 UTC
- **Rollback Plan**: Documented in rollback-procedures.md
- **Approvals**: IT Manager (John Smith), Security (Jane Doe)
- **Risk Assessment**: Medium (tested in staging)
## VMs Included:
$(kubectl mtv get plan production-q4-migration -o jsonpath='{.spec.vms[*].name}' | tr ' ' '\n' | sort)
## Security Considerations:
- TLS verification enabled for all providers
- RBAC follows least-privilege principle
- Audit logging enabled
- Network policies restrict access
EOF
|
Change Management Integration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # Migration change request workflow
#!/bin/bash
# migration-change-request.sh
PLAN_NAME="$1"
CHANGE_TICKET="$2"
if [ -z "$PLAN_NAME" ] || [ -z "$CHANGE_TICKET" ]; then
echo "Usage: $0 <plan-name> <change-ticket-id>"
exit 1
fi
# Label plan with change management metadata
kubectl label plan "$PLAN_NAME" \
change-ticket="$CHANGE_TICKET" \
approval-status=approved \
risk-level=medium \
change-window="$(date --iso-8601=date)"
# Add change management annotation
kubectl annotate plan "$PLAN_NAME" \
change-management/approver="migration-board@company.com" \
change-management/window="Maintenance window 02:00-06:00 UTC" \
change-management/rollback="Available until cutover completion"
echo "Plan $PLAN_NAME tagged with change request $CHANGE_TICKET"
|
Next Steps
After implementing comprehensive best practices and security:
- AI Integration: Explore advanced automation in Chapter 19: Model Context Protocol (MCP) Server Integration
- Tool Integration: Learn KubeVirt ecosystem integration in Chapter 20: Integration with KubeVirt Tools
Previous: Chapter 17: Debugging and Troubleshooting
Next: Chapter 19: Model Context Protocol (MCP) Server Integration