<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>v1alpha1 Archives - Linuxcent</title>
	<atom:link href="https://linuxcent.com/tag/v1alpha1/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxcent.com/tag/v1alpha1/</link>
	<description>Infrastructure security, from the kernel up.</description>
	<lastBuildDate>Sat, 09 May 2026 18:40:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxcent.com/wp-content/uploads/2026/04/favicon-512x512-1-150x150.png</url>
	<title>v1alpha1 Archives - Linuxcent</title>
	<link>https://linuxcent.com/tag/v1alpha1/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">211632295</site>	<item>
		<title>Kubernetes CRD Versioning: From v1alpha1 to v1 Without Breaking Clients</title>
		<link>https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/</link>
					<comments>https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Sat, 25 Apr 2026 18:16:44 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[API Evolution]]></category>
		<category><![CDATA[Conversion Webhook]]></category>
		<category><![CDATA[CRD Versioning]]></category>
		<category><![CDATA[Operator]]></category>
		<category><![CDATA[Storage Version]]></category>
		<category><![CDATA[v1alpha1]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>Evolve Kubernetes CRDs safely through v1alpha1, v1beta1, and v1 — storage versions, conversion webhooks, and the hub-and-spoke model explained for production clusters.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/">Kubernetes CRD Versioning: From v1alpha1 to v1 Without Breaking Clients</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><em>Kubernetes CRDs &amp; Operators: Extending the API, Episode 8</em><br />
<em><a href="/what-is-kubernetes-crd/">What Is a CRD?</a> · <a href="/kubernetes-custom-resources-examples/">CRDs You Already Use</a> · <a href="/kubernetes-crd-schema-explained/">CRD Anatomy</a> · <a href="/write-kubernetes-crd-yaml-walkthrough/">Write Your First CRD</a> · <a href="/kubernetes-crd-cel-validation/">CEL Validation</a> · <a href="/kubernetes-controller-reconcile-loop/">Controller Loop</a> · <a href="/build-kubernetes-operator-controller-runtime/">Build an Operator</a> · </em><em><a href="/kubernetes-crd-versioning-conversion-webhook/">CRD Versioning</a></em><em> · <a href="/kubernetes-admission-webhooks-explained/">Admission Webhooks</a> · <a href="/kubernetes-crd-production-finalizers-conditions-rbac/">CRDs in Production</a></em></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>Kubernetes CRD versioning lets you evolve your API from <code class="" data-line="">v1alpha1</code> to <code class="" data-line="">v1</code> without deleting existing custom resources or breaking clients still using the old version<br />
  <em>(storage version = the version etcd actually stores objects in; served versions = the versions the API server responds to; you can serve v1alpha1 and v1 simultaneously while migrating)</em></li>
<li>The <strong>hub-and-spoke model</strong> is the recommended conversion architecture: one &#8220;hub&#8221; version (usually <code class="" data-line="">v1</code>) that every other version converts to/from</li>
<li>Without a conversion webhook, the API server only allows one served version at a time — you must use a webhook to serve multiple versions with schema differences</li>
<li><code class="" data-line="">kubectl storage-version-migrator</code> (or manual re-apply) migrates existing objects from the old storage version to the new one after you update <code class="" data-line="">storage: true</code></li>
<li>Changing field names between versions without a conversion webhook corrupts data silently — always test conversion round-trips before promoting a version</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">  CRD VERSION LIFECYCLE

  Stage 1: Alpha                 Stage 2: Beta              Stage 3: Stable
  ──────────────────             ──────────────             ──────────────
  v1alpha1                       v1alpha1 (deprecated)      v1alpha1 (removed)
    served: true                   served: true               served: false
    storage: true                  storage: false             storage: false
                                 v1beta1                    v1beta1 (deprecated)
                                   served: true               served: true
                                   storage: false             storage: false
                                 v1                         v1
                                   served: true               served: true
                                   storage: true              storage: true

  Clients using v1alpha1:         The API server converts     Eventually remove
  still work via conversion       on the fly                  old served versions
  webhook
</code></pre>
<p>Kubernetes CRD versioning is what allows you to ship <code class="" data-line="">BackupPolicy v1alpha1</code> today, learn from real usage, evolve the schema to <code class="" data-line="">v1</code> with renamed fields and new constraints, and keep existing clusters running without a migration window.</p>
<hr />
<h2 id="why-versioning-is-necessary">Why Versioning Is Necessary</h2>
<p>When <code class="" data-line="">BackupPolicy v1alpha1</code> shipped, the spec used <code class="" data-line="">retentionDays</code>. After six months of production use, the team learns:</p>
<ul>
<li><code class="" data-line="">retentionDays</code> should be renamed to <code class="" data-line="">retention.days</code> (nested under a <code class="" data-line="">retention</code> object for future extensibility)</li>
<li>A new required field <code class="" data-line="">backupFormat</code> needs to be added with a default of <code class="" data-line="">tar.gz</code></li>
<li>The <code class="" data-line="">targets</code> field should be renamed to <code class="" data-line="">includedNamespaces</code></li>
</ul>
<p>These are breaking changes. Clients (GitOps repos, Helm charts, other operators) still have YAML referencing <code class="" data-line="">v1alpha1</code> with the old field names. You cannot simply rename the fields.</p>
<p>The solution: add <code class="" data-line="">v1</code> with the new schema, run both versions simultaneously via a conversion webhook, migrate objects to the new storage version, then deprecate <code class="" data-line="">v1alpha1</code>.</p>
<hr />
<h2 id="simple-case-non-breaking-addition-no-webhook-needed">Simple Case: Non-Breaking Addition (No Webhook Needed)</h2>
<p>If you only add new optional fields to the schema — no renames, no removals — you can add a new version without a conversion webhook, as long as only one version is served at a time.</p>
<pre><code class="" data-line="">versions:
  - name: v1alpha1
    served: false      # stop serving old version
    storage: false
    schema: ...
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        properties:
          spec:
            properties:
              schedule:
                type: string
              retentionDays:
                type: integer
              backupFormat:          # new optional field
                type: string
                default: &quot;tar.gz&quot;
</code></pre>
<p>Existing objects stored as <code class="" data-line="">v1alpha1</code> are served as <code class="" data-line="">v1</code> with the new field defaulted. This works for purely additive changes because the stored bytes are compatible with the new schema.</p>
<p><strong>When this is not enough:</strong> field renames, type changes, field removal, or structural reorganization all require a conversion webhook.</p>
<hr />
<h2 id="the-hub-and-spoke-model">The Hub-and-Spoke Model</h2>
<p>For breaking schema changes, the API server needs a conversion webhook. The recommended architecture is hub-and-spoke:</p>
<pre><code class="" data-line="">  HUB-AND-SPOKE CONVERSION

       v1alpha1
          │
          ▼ convert to hub
         v1  (hub)
          ▲
          │ convert to hub
       v1beta1

  Every version converts TO the hub and FROM the hub.
  The hub is always the storage version.
  Two-version conversion: v1alpha1 → v1 → v1beta1
  Never directly: v1alpha1 → v1beta1
</code></pre>
<p>This means you only write N conversion functions (one per version) rather than N² (one per version pair). As you add versions, the conversion complexity grows linearly.</p>
<hr />
<h2 id="writing-a-conversion-webhook">Writing a Conversion Webhook</h2>
<p>The conversion webhook is an HTTPS endpoint that the API server calls when it needs to convert an object between versions.</p>
<h3 id="1-define-the-conversion-hub">1. Define the conversion hub</h3>
<p>In the kubebuilder project, mark <code class="" data-line="">v1</code> as the hub:</p>
<p>In <code class="" data-line="">api/v1/backuppolicy_conversion.go</code>:</p>
<pre><code class="" data-line="">package v1

// Hub marks this type as the conversion hub.
func (*BackupPolicy) Hub() {}
</code></pre>
<h3 id="2-implement-conversion-in-v1alpha1">2. Implement conversion in v1alpha1</h3>
<p>In <code class="" data-line="">api/v1alpha1/backuppolicy_conversion.go</code>:</p>
<pre><code class="" data-line="">package v1alpha1

import (
    &quot;fmt&quot;
    v1 &quot;github.com/example/backup-operator/api/v1&quot;
    &quot;sigs.k8s.io/controller-runtime/pkg/conversion&quot;
)

// ConvertTo converts v1alpha1 BackupPolicy to v1 (the hub).
func (src *BackupPolicy) ConvertTo(dstRaw conversion.Hub) error {
    dst := dstRaw.(*v1.BackupPolicy)

    // Metadata
    dst.ObjectMeta = src.ObjectMeta

    // Field mapping: v1alpha1 → v1
    dst.Spec.Schedule      = src.Spec.Schedule
    dst.Spec.BackupFormat  = &quot;tar.gz&quot;           // new field: default for old objects
    dst.Spec.StorageClass  = src.Spec.StorageClass
    dst.Spec.Suspended     = src.Spec.Suspended

    // Renamed field: retentionDays → retention.days
    dst.Spec.Retention = v1.RetentionSpec{
        Days: src.Spec.RetentionDays,
    }

    // Renamed field: targets → includedNamespaces
    for _, t := range src.Spec.Targets {
        dst.Spec.IncludedNamespaces = append(dst.Spec.IncludedNamespaces,
            v1.NamespaceTarget{
                Namespace:      t.Namespace,
                IncludeSecrets: t.IncludeSecrets,
            })
    }

    dst.Status = v1.BackupPolicyStatus(src.Status)
    return nil
}

// ConvertFrom converts v1 (hub) BackupPolicy back to v1alpha1.
func (dst *BackupPolicy) ConvertFrom(srcRaw conversion.Hub) error {
    src := srcRaw.(*v1.BackupPolicy)

    dst.ObjectMeta = src.ObjectMeta

    dst.Spec.Schedule      = src.Spec.Schedule
    dst.Spec.StorageClass  = src.Spec.StorageClass
    dst.Spec.Suspended     = src.Spec.Suspended
    dst.Spec.RetentionDays = src.Spec.Retention.Days

    for _, n := range src.Spec.IncludedNamespaces {
        dst.Spec.Targets = append(dst.Spec.Targets, BackupTarget{
            Namespace:      n.Namespace,
            IncludeSecrets: n.IncludeSecrets,
        })
    }

    // backupFormat cannot be round-tripped to v1alpha1 (no such field)
    // Store it in an annotation to preserve the value if the object is
    // re-converted back to v1.
    if src.Spec.BackupFormat != &quot;&quot; &amp;&amp; src.Spec.BackupFormat != &quot;tar.gz&quot; {
        if dst.Annotations == nil {
            dst.Annotations = make(map[string]string)
        }
        dst.Annotations[&quot;storage.example.com/backup-format&quot;] = src.Spec.BackupFormat
    }

    dst.Status = BackupPolicyStatus(src.Status)
    return nil
}
</code></pre>
<h3 id="3-register-the-webhook">3. Register the webhook</h3>
<pre><code class="" data-line="">kubebuilder create webhook \
  --group storage \
  --version v1alpha1 \
  --kind BackupPolicy \
  --conversion
</code></pre>
<p>This generates the webhook server setup. Deploy with a TLS certificate (cert-manager can manage this automatically via the kubebuilder <code class="" data-line="">//+kubebuilder:webhook:...</code> marker).</p>
<hr />
<h2 id="updating-the-crd-to-reference-the-webhook">Updating the CRD to Reference the Webhook</h2>
<pre><code class="" data-line="">spec:
  conversion:
    strategy: Webhook
    webhook:
      clientConfig:
        service:
          name: backup-operator-webhook-service
          namespace: backup-operator-system
          path: /convert
      conversionReviewVersions: [&quot;v1&quot;, &quot;v1beta1&quot;]
  versions:
    - name: v1alpha1
      served: true
      storage: false
      schema: ...
    - name: v1
      served: true
      storage: true
      schema: ...
</code></pre>
<p>Once applied, <code class="" data-line="">kubectl get backuppolicies.v1alpha1.storage.example.com/nightly</code> and <code class="" data-line="">kubectl get backuppolicies.v1.storage.example.com/nightly</code> both work — the API server converts transparently.</p>
<hr />
<h2 id="migrating-existing-objects-to-the-new-storage-version">Migrating Existing Objects to the New Storage Version</h2>
<p>After changing <code class="" data-line="">storage: true</code> from <code class="" data-line="">v1alpha1</code> to <code class="" data-line="">v1</code>, existing objects in etcd are still stored as <code class="" data-line="">v1alpha1</code> bytes. They are served correctly (via conversion) but are not yet migrated.</p>
<p>Migrate them:</p>
<pre><code class="" data-line=""># Option 1: Manual re-apply (works for small object counts)
kubectl get backuppolicies -A -o name | while read name; do
  kubectl apply -f &lt;(kubectl get $name -o yaml)
done

# Option 2: Storage Version Migrator (automated, for large clusters)
# Install: https://github.com/kubernetes-sigs/kube-storage-version-migrator
kubectl apply -f storageVersionMigration.yaml
</code></pre>
<p>After migration, all objects in etcd are stored as <code class="" data-line="">v1</code>. You can then set <code class="" data-line="">v1alpha1 served: false</code> to stop serving the old version.</p>
<hr />
<h2 id="storage-version-migration-checklist">Storage Version Migration Checklist</h2>
<pre><code class="" data-line="">  SAFE VERSION PROMOTION CHECKLIST

  □ New version (v1) has served: true, storage: true
  □ Old version (v1alpha1) has served: true, storage: false
  □ Conversion webhook deployed and healthy
  □ Round-trip conversion tested (v1alpha1 → v1 → v1alpha1 preserves all data)
  □ kubectl get backuppolicies works at both versions
  □ Existing objects migrated (re-applied or migration job run)
  □ Old version set to served: false (stop serving)
  □ Old version removed from CRD after N release cycles
</code></pre>
<hr />
<h2 id="common-mistakes"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Common Mistakes</h2>
<p><strong>Changing the storage version without a conversion webhook.</strong> If you flip <code class="" data-line="">storage: true</code> from <code class="" data-line="">v1alpha1</code> to <code class="" data-line="">v1</code> while still serving <code class="" data-line="">v1alpha1</code>, the API server tries to read stored <code class="" data-line="">v1alpha1</code> bytes as <code class="" data-line="">v1</code> and fails. Always deploy the conversion webhook before changing the storage version.</p>
<p><strong>Lossy conversion.</strong> If <code class="" data-line="">ConvertFrom</code> (v1 → v1alpha1) drops a field that exists in v1, objects are silently corrupted when a v1alpha1 client reads and re-saves them. Round-trip test every conversion: <code class="" data-line="">original → hub → original</code> must produce identical objects (or use annotations to preserve fields that cannot round-trip).</p>
<p><strong>Forgetting to migrate existing objects.</strong> After changing the storage version, existing objects are still stored in the old format. They convert on read, but etcd still holds old bytes. Until migrated, your etcd backup/restore story is broken — restoring from backup would restore old-format bytes that need conversion.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<pre><code class="" data-line=""># Check which version is currently the storage version
kubectl get crd backuppolicies.storage.example.com \
  -o jsonpath=&#039;{.status.storedVersions}&#039;
# output: [&quot;v1alpha1&quot;]  or  [&quot;v1alpha1&quot;,&quot;v1&quot;]  or  [&quot;v1&quot;]

# Verify conversion webhook is reachable
kubectl get crd backuppolicies.storage.example.com \
  -o jsonpath=&#039;{.spec.conversion.webhook.clientConfig}&#039;

# Read an object at a specific version
kubectl get backuppolicies.v1alpha1.storage.example.com/nightly -n demo -o yaml
kubectl get backuppolicies.v1.storage.example.com/nightly -n demo -o yaml

# Check CRD conditions (NamesAccepted, Established)
kubectl describe crd backuppolicies.storage.example.com | grep -A5 Conditions
</code></pre>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>CRD versioning lets you evolve the schema without a migration window — old and new versions coexist via a conversion webhook</li>
<li>The hub-and-spoke model minimizes conversion code: N functions, not N² — the hub version is always the storage version</li>
<li>Never change the storage version without a deployed conversion webhook for breaking schema changes</li>
<li>Conversion must be lossless — fields that cannot round-trip should be preserved in annotations</li>
<li>Migrate existing objects to the new storage version after promoting it, then deprecate the old served version</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="/kubernetes-admission-webhooks-explained/">EP09: Admission Webhooks</a> completes the Kubernetes extension picture — validating and mutating webhooks that intercept API requests before they reach etcd, when to use them alongside CRDs, and how they differ from CEL validation.</p>
<p>Get EP09 in your inbox when it publishes → <a href="https://linuxcent.com">subscribe at linuxcent.com</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&amp;linkname=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-crd-versioning-conversion-webhook%2F&#038;title=Kubernetes%20CRD%20Versioning%3A%20From%20v1alpha1%20to%20v1%20Without%20Breaking%20Clients" data-a2a-url="https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/" data-a2a-title="Kubernetes CRD Versioning: From v1alpha1 to v1 Without Breaking Clients"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/">Kubernetes CRD Versioning: From v1alpha1 to v1 Without Breaking Clients</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-crd-versioning-conversion-webhook/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1696</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: linuxcent.com @ 2026-09-01 02:13:19 by W3 Total Cache
-->