Kubernetes package repository move to pkgs.k8s.io

Nodes still pointed at the frozen apt.kubernetes.io and yum.kubernetes.io repositories cannot install newer Kubernetes packages. This page explains how to move them to the per-minor-version pkgs.k8s.io repositories safely before a Kubernetes upgrade.

On this page

Why a Kubernetes upgrade starts with the package repository move

The repository move must happen on each node before the upgrade can install new packages. A self-managed node that still resolves kubeadm, kubelet and kubectl from the frozen apt.kubernetes.io or yum.kubernetes.io repositories can only see package versions from the legacy line, so the next minor version cannot be installed no matter how the upgrade is scripted. The move points each node at the per-minor-version pkgs.k8s.io repository for the release you are targeting, after which the package manager can list the packages for that line. Before you schedule any change window, check the repository source file on every node and confirm which versions the package manager reports as available.

The supported path is one minor version at a time, with kube-apiserver upgraded first. kube-controller-manager, kube-scheduler and kubelets follow, and kubelets may be up to three minor versions older than kube-apiserver under the version skew policy. The Kubernetes project maintains the three most recent minor releases. As of September 2026 these were 1.37, 1.36 and 1.35, so a cluster on an older line has to move forward through each intermediate minor version rather than jumping to the newest release. Your plan should record the current version of every control plane and worker component, the target for each step, and the order in which the nodes will change.

Kubernetes ships roughly three minor releases a year on a cycle of about 14 weeks. A cluster that misses the repository move does not fall behind once. It falls behind again with every release, and each skipped minor version adds another upgrade step to the plan. Treat the repository move as its own tracked task with an owner, a verification step and an approval, rather than a line inside the upgrade runbook. Ask your platform team which node groups still use the legacy repositories, whether any nodes were installed from distribution packages, and how packages are mirrored if your clusters run without internet access.

The repository move changes only where packages come from. It does not upgrade any component, and it can leave a cluster in a mixed state if some nodes are updated and others are not. Confirm that package holds or version pins do not block the target packages, and record the installed kubelet and kubectl versions before and after each node changes. Keep the previous package versions available so that a node can be returned to its known state if the new repository source causes an install failure. Confirm the exact steps for your operating system and package manager against the Kubernetes installation documentation for the target release before you run them in production.

What changes in the package sources and the Kubernetes packages

This table compares what changes in the package sources, the packages themselves and the upgrade cadence when a cluster moves from the legacy apt.kubernetes.io and yum.kubernetes.io repositories to pkgs.k8s.io. Read each row as a question to answer for every node before an upgrade starts. The main takeaway is that the repository must be checked at every upgrade, since a new minor release arrives about every 14 weeks.

ChangeImpactAction needed
Legacy repositoriesThe apt.kubernetes.io and yum.kubernetes.io sources no longer receive new Kubernetes packages.Move every node to its pkgs.k8s.io source before the upgrade starts, so the target packages are available.
Per-minor repositoriesEach Kubernetes minor version has its own pkgs.k8s.io repository, so a node only sees packages for the minor version it is pinned to.Point each node at the repository for the minor version it runs now, and switch it only when you upgrade that node.
Repository definition and signing keyEvery node keeps its own source file and signing key, so each one must be updated individually.Update the definition and key on all control plane and worker nodes, then confirm the expected versions are listed.
kubeadm, kubelet and kubectlAll three packages come from the repository for the target minor version and should match that version.Install the target minor versions from the new source at each step, in the order the upgrade procedure sets out.
Version skewThe kube-apiserver must move one minor version at a time, and kubelets may be up to three minor versions older than it.Keep each step inside the official version skew policy and recheck it before every upgrade.
Release cycleA new minor release arrives about every 14 weeks, so the repository choice comes up again with each upgrade.Include the repository switch as a standard step in every upgrade plan, not only in the first move.
Dates and repository addressesFreeze dates and exact repository addresses are set by the project and can change over time.Confirm both against the official package installation instructions for your Linux distribution before changing any node.

How the per-minor-version repositories change what a node can install

A node's package repository points at one minor line, so moving a node to the next minor version starts with changing the repository entry, before any package upgrade runs. The legacy apt.kubernetes.io and yum.kubernetes.io repositories are frozen, which means a node still pointed there cannot receive packages for newer minor releases, whatever its package manager reports. Each per-minor-version repository on pkgs.k8s.io carries packages for a single minor line, so the repository entry itself defines what a node can install. Confirm the exact repository path format, package names and signing key location for your operating system against the current Kubernetes installation documentation before editing any node.

The version skew policy sets the order in which that change can happen. The kube-apiserver is upgraded first, one minor version at a time, before kube-controller-manager, kube-scheduler and kubelets. Kubelets may be up to three minor versions older than kube-apiserver, which gives node groups a window to finish, but it does not permit skipping steps in the sequence. Control plane and node packages must follow the same order, so the repository change for a node belongs in that node's stage of the plan, after the control plane has reached the target minor. Write the sequence as a checklist per node group so each repository change is tied to a verified control plane version.

Pinning matters because the repository is per minor line. When kubelet, kubeadm and kubectl packages are held to their current minor during routine patching, a standard security update cannot pull in a newer minor by accident. Patch windows are where cross-minor upgrades most often happen unintentionally, because a generic upgrade command treats every available newer version as eligible. Confirm how your package manager holds packages on your operating system, and run a listing before patching to check that only patch releases within the current minor line would be installed. Record which hold is set on each node so the upgrade plan starts from a known state.

Plan for the change to be recorded and reversible. A node stage should include the repository entry change, the package versions it will install, and the previous entry needed to roll back. Confirm that each node can reach the new repository, or an internal mirror if the cluster runs without internet access, and ask who maintains that mirror and how often it is synchronized. Kubeadm can pull control plane images from a private registry, but package mirrors need their own owner and process. Keep an inventory that states the minor version and repository each node uses, since mixed entries are the first thing to check when a node will not upgrade.

Preparation before touching any node repository

These four preparations cover what you must be able to recover, what you need to know about each node, where you can rehearse the change, and which images the nodes need. Finish them before any node moves to a pkgs.k8s.io repository, because they decide whether a failed package step becomes a rollback or a rebuild.

Verified etcd snapshot

Take a snapshot of the etcd data with etcdctl snapshot save before any package changes, and record the endpoint, the certificates used and a checksum of the file. Restore that file with etcdutl into a separate environment and confirm the cluster starts and lists the objects you expect. Until a backup restores cleanly, it is only a file. Snapshots contain every Kubernetes Secret, which is stored unencrypted in etcd by default, so keep them in encrypted, access-controlled storage with logged access and a retention rule your security team has approved.

Node version and repository inventory

List every node with its current kubelet and kubeadm versions, the repository file it uses and the signing key that file references. Clusters built from the older apt.kubernetes.io and yum.kubernetes.io repositories often show mixed versions and stale entries, so check each node individually rather than trusting the cluster template. Record hostnames, whether each node is a control plane or worker node, and whether control plane nodes run stacked etcd or external etcd. Use this inventory to set node order and to confirm that no node still points at a repository you have not reviewed.

Staging cluster at production topology

Build a staging cluster that matches production, with the same stacked or external etcd layout and at least three control plane nodes behind a TCP load balancer on port 6443, as the kubeadm high availability guide describes. A single-node test cannot show how a package change behaves when one control plane node is unavailable during the update. Match the network plugin, storage classes, admission settings and node pools as well. Run the repository change there first and note which steps need a pause or a manual check.

Control plane image check

Run kubeadm config images list to see the control plane images for the version you are moving to, then run kubeadm config images pull on a node that can reach a registry. Where nodes have no internet access, copy those images to a private registry and point kubeadm at it with the --image-repository option described in the kubeadm init documentation. Confirm that the mirror holds every listed image before the first node is touched, because a missing image stops the step partway through and leaves that node in an unclear state.

Kubernetes upgrade steps for moving each node to pkgs.k8s.io

This sequence moves each node off the frozen legacy Kubernetes package repositories and onto the per-minor-version pkgs.k8s.io repository. Done in order, it leaves every control plane node on a package source that can install the next minor version, with a verified etcd backup and a rollback point at each stage.

  1. Confirm the etcd backup and cluster health

    Before any package changes, take an etcd snapshot with etcdctl snapshot save, copy it off the control plane nodes and confirm the file is present and readable. Check that every etcd member is healthy and that all control plane nodes report Ready with their kube-system pods running. Rollback point: the verified snapshot. Stop if any etcd member is unhealthy, the snapshot cannot be inspected, or a node is already NotReady, and resolve that first. Ask your etcd operator or platform team to confirm the restore procedure before you proceed.

  2. Record current versions on every node

    Run kubectl get nodes -o wide to read the kubelet version and container runtime on each node, then check the installed kubeadm, kubelet and kubectl package versions on each host with your package manager. Compare these against the version skew policy: kube-apiserver is upgraded one minor version at a time, and kubelets may be up to three minor versions older than kube-apiserver. Save this inventory as your baseline. Stop if nodes report unexpected or mixed minor versions that you cannot explain, because the upgrade assumes a known starting state.

  3. Swap the legacy repository on one node

    On the first control plane node, back up the existing apt.kubernetes.io or yum.kubernetes.io source file and its signing key, then remove them. Add the pkgs.k8s.io entry for the node's current minor version and import its signing key, then refresh the package index. Illustrative example: a node on 1.36 receives the 1.36 entry now, and the 1.37 entry is added only when the kubeadm upgrade begins in the sibling topic, Kubernetes 1.36 to 1.37 upgrade with kubeadm. Rollback point: restore the backed-up source file and key. Stop if the index refresh fails signature verification.

  4. Update packages and check versions

    On the same node, install the latest patch release of the current minor version for kubeadm, kubelet and kubectl, then hold those packages so they do not change during routine updates. Confirm the output of kubeadm version, kubelet --version and kubectl version --client, and check that kubelet restarted and is active. Verify node readiness with kubectl get nodes, confirm the control plane static pods for kube-apiserver, kube-controller-manager, kube-scheduler and etcd are running, and confirm the API server version reported by kubectl version. Stop if the kubelet fails to start or any control plane pod enters a restart loop.

  5. Repeat on remaining control plane nodes

    Apply the same repository swap and package update to each remaining control plane node, one node at a time. After each node, confirm it reports Ready, its control plane pods are healthy, and etcd still has a healthy quorum with the expected member count. Wait for the node to settle before starting the next one. Rollback point: the previous node's verified state and the etcd snapshot from the first step. Stop if quorum is lost or a node cannot rejoin, and do not start on another node until the cause is known. Keep a written record of which nodes have completed each step.

  6. Move worker nodes after the control plane

    Update worker nodes only after every control plane node runs the same repository and package state. For each worker, cordon and drain the node, update the packages using the same repository and hold steps, restart the kubelet, then uncordon the node. Verify that the node reports Ready, that its pods are rescheduled and running without restart loops, and that the kubelet version falls within the allowed skew. Stop if a drain is blocked by a PodDisruptionBudget or a workload that cannot be moved, and resolve that with the application owner before continuing.

Rollback points and tests after each node

Rollback is realistic at the package layer and limited at the cluster layer, so decide where your safe points are before the first node changes. Restoring a repository entry is simple: point the node back to the previous source file and confirm that the older kubelet and kubectl packages are still installable from your mirror. Once kubeadm has run on the control plane, however, reverting binaries does not revert the cluster state already written to etcd. For that you need an etcd snapshot taken with etcdctl snapshot save before the first change, and a restore procedure using etcdutl that your team has rehearsed in a non-production cluster. Confirm the exact rollback commands for your kubeadm version in the official upgrade documentation before the maintenance window, not during it.

After each node, run the same short set of checks and record the results before moving on. First, confirm the node reports Ready in the output of kubectl get nodes. Second, confirm that the VERSION column shows the kubelet version you expect, which proves the node has reported its new version to the API server and is not still running the old binary. Third, check workload health: pods drained from the node should be running on other nodes, no pods should be in crash loops, and disruption budgets should have held. Fourth, run the smoke test agreed with application owners, such as a request through the ingress to a service that touches a dependency. A check that is not written down in advance tends to be skipped under time pressure.

The version skew policy sets how far a node may lag behind the control plane during the rollout. The kube-apiserver must be upgraded one minor version at a time and before the controller manager, scheduler and kubelets, and a kubelet may be up to three minor versions older than the kube-apiserver. That gives a node some room, but it is a hard boundary, not a holding area. A node that stays on an old package because its repository move failed can drift toward the edge of the allowed window, and a fleet split across several versions makes every later step harder to reason about. Plan the number of nodes you can leave behind, and treat any node that cannot reach the target version within your change window as a finding, not a reason to extend the window indefinitely.

A failed node should stop the rollout before the next node is touched. The problem may come from the node, but it may also come from something shared, such as the new repository configuration, a package dependency, a container runtime change or a control plane fault that only appears once a kubelet reconnects. Draining the next node would move more workload onto fewer healthy nodes while the cause is still unknown. Define stop criteria in advance: the node is not Ready, reports the wrong version, shows failing workloads, or fails the smoke test. When a stop criteria is met, hold the rollout, decide whether to roll that node back or fix it forward, and resume only after the cause is recorded.

What makes the repository move and upgrade take longer

This table lists the conditions that most often lengthen a move to the pkgs.k8s.io repositories and the minor version upgrades that follow it. Read each row as a question about your own fleet, then ask for a written estimate built on those answers. The main takeaway is that cluster count, etcd setup and air-gapped constraints often matter more than the package change itself.

DriverEffect on effortWhat to confirm
Number of nodes and control plane topologyMore nodes mean more drain, package and verification cycles. Highly available control planes add ordering checks at each step.Node count per pool, control plane node count and whether a TCP load balancer fronts kube-apiserver on port 6443.
Stacked or external etcd and backup maturityExternal etcd adds a separate upgrade and restore path. Unverified snapshots raise the cost of any failed step.Topology, member count, date of the last snapshot restore test and who holds the etcdctl and etcdutl procedures.
Air-gapped networks needing a private registryPackages and images must be mirrored inside the network first, adding a sync and approval stage before any node changes.Whether repository content and control plane images can be mirrored, and the private registry path kubeadm will use.
Operating systems and distributions in the fleetEach OS family needs its own repository configuration, package pinning and tested install steps.Exact OS versions, package manager on each node and any nodes sourcing packages from a distribution-specific channel.
Custom admission controllers, Pod Security Standards and operatorsWebhooks and operators tied to a Kubernetes version can block upgrade steps or need their own release first.Webhook failure policies, Pod Security admission levels per namespace and each operator's supported Kubernetes versions.
Helm charts and manifests using deprecated APIsRemoved API versions must be found and rewritten before the target minor version, adding a review pass for each chart.Chart versions, whether rendered manifests are kept in Git, and results of a deprecated API scan against the target release.
Change windows and approval stepsNarrow windows and multi-party sign-off limit how many nodes move per session and how long rollback stays open.Window length and frequency, required approvers, and whether a rollback decision must be made inside the window.
Clusters on different minor versionsEach cluster needs its own sequence. Skew rules limit how far kubelets can lag the API server, so mixed fleets need a planned order.Current minor version of every cluster, the target version for each, and a review against the version skew policy.

Debian-based and RHEL-based nodes need different repository edits

On Debian and Ubuntu nodes, the repository change lives in an apt source entry and the signing key that apt uses to verify packages. The source entry names the repository address, the release suite, the component and the keyring that apt trusts for that repository. The move to the per-minor-version repository replaces the old entry for the frozen repository with a new entry whose suite matches the minor version you are installing. The key is replaced in the same step: you fetch the signing key published for the new repository, store it in a keyring file, and point the new entry at that keyring with the signed-by option. Do not disable signature checks to get past a key error. A key error usually means the entry or keyring is wrong, and turning off verification removes the protection the repository exists to provide.

What to do on each node:

  • Remove the frozen entry so apt does not query a repository that no longer receives new packages.
  • Confirm the new suite and keyring against the official install instructions for your target minor version.
  • Refresh the package index and read the output for signature or key warnings before installing anything.
  • Hold kubelet, kubeadm and kubectl with apt-mark hold after installation, so routine updates do not move them to a newer minor version.
  • Unhold during upgrades only, in the order your upgrade runbook specifies, then hold again.

After the install, run apt-mark showhold to confirm the holds, apt-cache policy on the three packages to confirm the candidate version comes from the new repository, and kubeadm version and kubelet --version to confirm the installed binaries. Check the kubelet service status as well. Confirm exact source file locations and keyring paths in your distribution's documentation and the official Kubernetes install guide, because they can change between releases.

Questions teams ask before a Kubernetes upgrade

How much does moving Kubernetes nodes to pkgs.k8s.io and upgrading cost?

Cost depends on the number of clusters and nodes, how many minor versions separate your current release from the target, and how much preparation your workloads need. Changing the package repository is a small step, so most of the effort goes to inventory, change planning, staging rehearsals, the upgrade itself and validation. One-time work covers planning, runbooks and the upgrade. Recurring costs appear only if you add ongoing support or upgrade retainers, which DeployOpen offers. DeployOpen does not publish prices and most engagements are fixed-scope. Ask any partner for a written scope that lists each cluster, node count, target version, environment, who performs each step, what is tested, what is excluded, and which follow-up items are priced separately.

How long does a package repository move and kubeadm upgrade take?

Duration follows from the work involved rather than a fixed figure. The main drivers are the number of minor versions you cross, because each step needs its own node sequence, the number of clusters and their size, whether control planes use stacked etcd or an external etcd cluster, how many workloads have tight disruption limits, and how many change windows your organization can approve. Staging rehearsals add time but reduce surprises in production. Ask for a timeline in the written scope that separates planning, staging, each production window and post-upgrade validation, so you can see which dates depend on your approvals and which depend on the partner.

What does our team need to provide before an upgrade starts?

The work needs administrative access to the clusters, including a kubeconfig with sufficient rights and console or SSH access to every control plane and worker node. You also need approved change windows, a backup target with enough storage for etcd snapshots, and a tested restore path. Each workload needs a named owner who can confirm readiness and sign off on testing, and someone must own the decision to proceed or roll back. If your nodes cannot reach the public package repositories, you must also provide a package mirror. A staging or test cluster that matches production closely is strongly useful, and your scope should state who provides each item.

Can our internal platform team run this upgrade alone?

Yes, a capable internal team can run the upgrade alone if it has hands-on experience with the required skills. Those include kubeadm upgrade plan and apply, draining and uncordoning nodes, restarting kubelets, pinning and installing packages with apt or yum, taking and restoring etcd snapshots with etcdctl and etcdutl, and reading the version skew policy. The team also needs to check API deprecations and add-on compatibility such as CNI, ingress and storage drivers. Teams with limited etcd or control plane experience often use a partner for the first cluster, then take over the runbook. Confirm your team's skills against the scope before deciding.

What changes if our Kubernetes cluster has no internet access?

An air-gapped cluster needs the packages and container images mirrored into your own infrastructure before the upgrade starts. Packages for the target minor version must come from a mirror you control, because the older apt and yum repositories are frozen and do not carry new releases. Kubeadm can list and pull the required control plane images on a connected staging host, which are then pushed to a private registry and referenced with the image repository option during kubeadm init or upgrade. Add-on images, such as the CNI plugin, ingress controller and CSI drivers, must be mirrored too. Confirm the exact mirroring tooling and approval process with your security team.

Is changing the package repository the only step in an upgrade?

No, the repository change only makes new packages installable. The upgrade also requires a current etcd backup, checks for deprecated APIs in manifests, Helm charts and operators, and confirmation that add-ons support the target version. The control plane must move one minor version at a time, and kubelets may run up to three minor versions behind the API server, so the node sequence matters. Each node is drained, upgraded and checked before the next starts. Supported releases change over time, so confirm the target version against the current release page before planning. Validation of workloads and rollback steps should be written down before the first production window.

How DeployOpen scopes and delivers a Kubernetes upgrade

DeployOpen starts with an inventory of which nodes still point at the frozen apt.kubernetes.io and yum.kubernetes.io repositories and which Kubernetes minor version each one runs. We then plan the move to the per-minor-version pkgs.k8s.io repositories so the packages needed for the next upgrade are available, within the kubelet skew rules in the version skew policy. Every step is written into a scope that you approve before work starts.

How we scope

  • Inventory of each node's OS family, package source and running kubelet and kubectl versions.
  • Written list of hosts to move, with the target minor version for each node pool and its upgrade window.
  • Fixed scope agreed in writing before work starts, with ongoing support available as a retainer afterward.

How we build

  • Repository definition for each target minor version, signed key handling and mirror setup for air-gapped nodes.
  • Node-by-node change plan covering cordon, drain, package swap and kubelet restart in the agreed order.
  • Test run on a non-production cluster that mirrors the production node inventory and package sources.

How we hand over

  • Runbook with repository URLs, pinned package versions, rollback steps and per-node verification commands.
  • Record of each node's before and after package source, kubelet version and drain outcome.
  • Notes on the next upgrade step, including the version skew checks that apply to your control plane.

How we support

  • Retainer option for patch releases, repository maintenance and upgrades to later minor versions.
  • Review of Kubernetes release and end-of-life dates against your planned upgrade schedule.
  • Operator handover so your own team can run future repository changes and minor version upgrades.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.