OpenShift ITMS ImageTagMirrorSet
Configure ImageTagMirrorSet in OpenShift 4.13+ for tag-based image mirroring. Mirror container images by tag instead of digest for disconnected clusters.
π‘ Quick Answer:
ImageTagMirrorSet(ITMS) mirrors images by tag instead of digest. Use it when your workloads reference images by tag (e.g.,nginx:1.25) and you need to redirect pulls to a mirror registry in disconnected or air-gapped OpenShift clusters. Available from OpenShift 4.13+.
The Problem
OpenShift has two mirror set types for disconnected environments:
- IDMS (ImageDigestMirrorSet) β mirrors images referenced by digest (
@sha256:...) - ITMS (ImageTagMirrorSet) β mirrors images referenced by tag (
:latest,:v1.2)
Many third-party applications, Helm charts, and operator catalogs reference images by tag, not digest. Without ITMS, these pulls fail in disconnected clusters because IDMS only intercepts digest-based references.
The Solution
Step 1: Create an ImageTagMirrorSet
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: enterprise-tag-mirrors
spec:
imageTagMirrors:
# Mirror Docker Hub images
- source: docker.io
mirrors:
- mirror.internal.example.com/docker-hub
mirrorSourcePolicy: AllowContactingSource
# Mirror Quay.io images
- source: quay.io
mirrors:
- mirror.internal.example.com/quay-io
mirrorSourcePolicy: AllowContactingSource
# Mirror GitHub Container Registry
- source: ghcr.io
mirrors:
- mirror.internal.example.com/ghcr-io
mirrorSourcePolicy: AllowContactingSource
# Mirror Red Hat registry
- source: registry.redhat.io
mirrors:
- mirror.internal.example.com/redhat-io
mirrorSourcePolicy: AllowContactingSource# Apply the ITMS
oc apply -f itms-enterprise.yaml
# Verify
oc get imagetagmirrorset
oc describe imagetagmirrorset enterprise-tag-mirrorsStep 2: Fully Disconnected (NeverContactSource)
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: airgapped-tag-mirrors
spec:
imageTagMirrors:
# Docker Hub β never contact source (fully air-gapped)
- source: docker.io
mirrors:
- mirror.internal.example.com/docker-hub
mirrorSourcePolicy: NeverContactSource
# NVIDIA NGC β GPU operator images
- source: nvcr.io
mirrors:
- mirror.internal.example.com/nvcr-io
mirrorSourcePolicy: NeverContactSource
# Quay.io β operators and tools
- source: quay.io
mirrors:
- mirror.internal.example.com/quay-io
mirrorSourcePolicy: NeverContactSource
# K8s registry
- source: registry.k8s.io
mirrors:
- mirror.internal.example.com/k8s-io
mirrorSourcePolicy: NeverContactSourceStep 3: Mirror Images with oc-mirror or skopeo
# Mirror specific images by tag using skopeo
skopeo copy \
docker://docker.io/nginx:1.25 \
docker://mirror.internal.example.com/docker-hub/nginx:1.25
skopeo copy \
docker://quay.io/prometheus/prometheus:v2.53.0 \
docker://mirror.internal.example.com/quay-io/prometheus/prometheus:v2.53.0
# Mirror NVIDIA GPU Operator images
skopeo copy \
docker://nvcr.io/nvidia/gpu-operator:v24.9.0 \
docker://mirror.internal.example.com/nvcr-io/nvidia/gpu-operator:v24.9.0
# Bulk mirror with oc-mirror (imageSetConfiguration)
cat << 'EOF' > imageset-config.yaml
apiVersion: mirror.openshift.io/v1alpha2
kind: ImageSetConfiguration
mirror:
additionalImages:
- name: docker.io/nginx:1.25
- name: docker.io/redis:7.4
- name: quay.io/prometheus/prometheus:v2.53.0
- name: nvcr.io/nvidia/tritonserver:24.12-py3
EOF
oc mirror --config imageset-config.yaml \
docker://mirror.internal.example.comStep 4: ITMS for Specific Namespaces / Projects
# Mirror NVIDIA AI images specifically
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: nvidia-ai-mirrors
spec:
imageTagMirrors:
- source: nvcr.io/nvidia
mirrors:
- mirror.internal.example.com/nvidia
mirrorSourcePolicy: NeverContactSource
- source: nvcr.io/nvidia/tritonserver
mirrors:
- mirror.internal.example.com/nvidia/tritonserver
mirrorSourcePolicy: NeverContactSource
---
# Mirror HuggingFace model images
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: ai-inference-mirrors
spec:
imageTagMirrors:
- source: docker.io/vllm/vllm-openai
mirrors:
- mirror.internal.example.com/vllm/vllm-openai
mirrorSourcePolicy: NeverContactSourceIDMS vs ITMS Comparison
| Feature | IDMS | ITMS |
|----------------------|------------------------------|-----------------------------|
| Full name | ImageDigestMirrorSet | ImageTagMirrorSet |
| References | Digest (@sha256:...) | Tag (:latest, :v1.2) |
| OpenShift version | 4.13+ | 4.13+ |
| Immutable references | Yes (digest never changes) | No (tag can be overwritten) |
| Use case | OCP platform, operators | Third-party apps, Helm |
| Legacy equivalent | ImageContentSourcePolicy | N/A (new in 4.13) |
| Scope | Cluster-wide | Cluster-wide |flowchart TD
A[Pod pulls nginx:1.25] --> B{ITMS configured?}
B -->|Yes| C[Check mirror first]
C --> D[mirror.internal.example.com/docker-hub/nginx:1.25]
D --> E{Image found in mirror?}
E -->|Yes| F[Pull from mirror]
E -->|No| G{mirrorSourcePolicy?}
G -->|AllowContactingSource| H[Fall back to docker.io]
G -->|NeverContactSource| I[Pull fails - image not mirrored]
B -->|No| J[Pull directly from docker.io]Step 5: Combined IDMS + ITMS Setup
# Check existing mirror sets
oc get imagedigestmirrorset
oc get imagetagmirrorset
# Check which images are using tags vs digests in your cluster
oc get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | \
sort -u | \
awk -F'@' '{if(NF>1) print "DIGEST:", $0; else print "TAG:", $0}'
# Verify mirror configuration is applied to nodes
oc debug node/<node-name> -- chroot /host \
cat /etc/containers/registries.conf.d/99-imagetagmirrorset.confStep 6: Validate ITMS is Working
# Check node configuration after ITMS apply
# MCO (Machine Config Operator) rolls out changes to all nodes
oc get mcp
# Wait for all MachineConfigPools to finish updating
# Test image pull from mirror
oc run test-mirror --image=nginx:1.25 --restart=Never -n default
oc describe pod test-mirror | grep -A5 "Events"
# Should show pull from mirror URL, not docker.io
# Check CRI-O registries config on a node
oc debug node/<node-name> -- chroot /host \
cat /etc/containers/registries.confCommon Issues
Node rolling restart after ITMS apply
# ITMS changes trigger MCO to update registries.conf on all nodes
# This causes a rolling restart of all nodes (one at a time)
# Plan ITMS changes during maintenance windows
# Check rollout status
oc get mcp -w
# Wait for UPDATED=True, UPDATING=False on all poolsTag not found in mirror
# Unlike digests, tags can be overwritten at source
# Your mirror might have an older version of :latest
# Solution: re-sync regularly
skopeo sync --src docker --dest docker \
docker.io/library/nginx \
mirror.internal.example.com/docker-hub/library/
# Or pin to specific tags instead of :latestITMS vs legacy ImageContentSourcePolicy
# ICSP (ImageContentSourcePolicy) is deprecated in 4.13+
# ICSP only supported digest-based mirroring
# Migrate ICSP to IDMS + ITMS:
oc adm migrate icsp /path/to/icsp.yaml \
--dest-dir /path/to/output/
# This generates IDMS files β add ITMS manually for tag-based mirrorsMultiple mirrors β fallback order
# Mirrors are tried in order β first match wins
imageTagMirrors:
- source: docker.io
mirrors:
- primary-mirror.example.com/docker-hub # tried first
- backup-mirror.example.com/docker-hub # tried second
mirrorSourcePolicy: AllowContactingSource # source tried lastBest Practices
- Use ITMS for third-party images that reference tags (Helm charts, vendor apps)
- Use IDMS for platform images (OpenShift release, operators) which use digests
NeverContactSourcefor fully air-gapped environmentsAllowContactingSourcefor partial disconnection (mirror as cache)- Schedule ITMS changes during maintenance β triggers node rolling restarts
- Sync mirrors regularly β tags are mutable, mirrors can become stale
- Pin to specific tags (
:1.25.3) instead of floating tags (:latest) - Combine with cluster-wide pull secret for mirror registry auth
Key Takeaways
- ITMS (
ImageTagMirrorSet) redirects tag-based image pulls to mirror registries - Available from OpenShift 4.13+ β replaces part of deprecated ICSP functionality
- IDMS for digests, ITMS for tags β use both in disconnected clusters
- Applying ITMS triggers MCO rolling restart of all nodes
mirrorSourcePolicy:AllowContactingSource(cache) vsNeverContactSource(air-gap)- Use skopeo or oc-mirror to populate the mirror registry with tagged images

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
