Skip to content

Commit 2c63371

Browse files
committed
OKD-294: Migrate runtime from runc to crun on an upgrade for OKD
Centos stream 10 dopped the runc package. For now OKD users are following the workaround to edit the MC to point to crun before the upgrade, but this should help with the migration rather than having to intervene manually. This PR: - checks for presence of the configmap - if MCO is built for OKD, edit the MC so the runtime is crun. - deletes the configmap
1 parent a43523e commit 2c63371

File tree

2 files changed

+114
-8
lines changed

2 files changed

+114
-8
lines changed

pkg/controller/container-runtime-config/container_runtime_config_controller.go

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ const (
6060
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s, 10.2s, 20.4s, 41s, 82s
6161
maxRetries = 15
6262

63-
builtInLabelKey = "machineconfiguration.openshift.io/mco-built-in"
63+
builtInLabelKey = "machineconfiguration.openshift.io/mco-built-in"
64+
forceSyncOnUpgrade = "force-sync-on-upgrade"
6465
)
6566

6667
var (
@@ -79,6 +80,7 @@ type Controller struct {
7980
templatesDir string
8081

8182
client mcfgclientset.Interface
83+
kubeClient clientset.Interface
8284
configClient configclientset.Interface
8385
eventRecorder record.EventRecorder
8486

@@ -148,6 +150,7 @@ func New(
148150
ctrl := &Controller{
149151
templatesDir: templatesDir,
150152
client: mcfgClient,
153+
kubeClient: kubeClient,
151154
configClient: configClient,
152155
eventRecorder: ctrlcommon.NamespacedEventRecorder(eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: "machineconfigcontroller-containerruntimeconfigcontroller"})),
153156
queue: workqueue.NewTypedRateLimitingQueueWithConfig(
@@ -213,6 +216,7 @@ func New(
213216

214217
ctrl.clusterVersionLister = clusterVersionInformer.Lister()
215218
ctrl.clusterVersionListerSynced = clusterVersionInformer.Informer().HasSynced
219+
ctrl.queue.Add(forceSyncOnUpgrade)
216220

217221
ctrl.fgHandler = fgHandler
218222

@@ -596,6 +600,84 @@ func (ctrl *Controller) addAnnotation(cfg *mcfgv1.ContainerRuntimeConfig, annota
596600
return annotationUpdateErr
597601
}
598602

603+
// migrateRuncToCrun performs the upgrade migration from runc to crun as the default container runtime.
604+
// This function checks for the existence of the crio-default-container-runtime ConfigMap. If it exists,
605+
// it updates the MachineConfigs for master and worker pools to use crun instead of runc, then deletes
606+
// the ConfigMap to prevent re-running the migration.
607+
func (ctrl *Controller) migrateRuncToCrun() error {
608+
// Check if the migration ConfigMap exists
609+
_, err := ctrl.kubeClient.CoreV1().ConfigMaps(ctrlcommon.MCONamespace).Get(context.TODO(), "crio-default-container-runtime", metav1.GetOptions{})
610+
if errors.IsNotFound(err) {
611+
// ConfigMap doesn't exist, no migration needed
612+
return nil
613+
}
614+
if err != nil {
615+
return fmt.Errorf("error checking for crio-default-container-runtime configmap: %w", err)
616+
}
617+
618+
klog.Info("Found crio-default-container-runtime ConfigMap, starting migration from runc to crun")
619+
620+
// Get all MachineConfigPools
621+
pools, err := ctrl.mcpLister.List(labels.Everything())
622+
if err != nil {
623+
return fmt.Errorf("error listing MachineConfigPools: %w", err)
624+
}
625+
626+
// Only process master and worker pools for the migration
627+
for _, pool := range pools {
628+
if pool.Name != "master" && pool.Name != "worker" {
629+
continue
630+
}
631+
632+
// Get the MachineConfig name for this pool
633+
mcName := fmt.Sprintf("00-override-%s-generated-crio-default-container-runtime", pool.Name)
634+
635+
// Get the existing MachineConfig
636+
mc, err := ctrl.client.MachineconfigurationV1().MachineConfigs().Get(context.TODO(), mcName, metav1.GetOptions{})
637+
if errors.IsNotFound(err) {
638+
klog.Infof("MachineConfig %s not found, skipping migration for pool %s", mcName, pool.Name)
639+
continue
640+
}
641+
if err != nil {
642+
return fmt.Errorf("error getting MachineConfig %s: %w", mcName, err)
643+
}
644+
645+
// Create the new crun configuration file
646+
configFileList := createDefaultContainerRuntimeFile()
647+
648+
// Create the new Ignition config
649+
ctrRuntimeConfigIgn := createNewIgnition(configFileList)
650+
rawCtrRuntimeConfigIgn, err := json.Marshal(ctrRuntimeConfigIgn)
651+
if err != nil {
652+
return fmt.Errorf("error marshalling container runtime config Ignition: %w", err)
653+
}
654+
655+
// Update the MachineConfig with the new crun configuration
656+
mc.Spec.Config.Raw = rawCtrRuntimeConfigIgn
657+
mc.SetAnnotations(map[string]string{
658+
ctrlcommon.GeneratedByControllerVersionAnnotationKey: version.Hash,
659+
})
660+
661+
// Update the MachineConfig
662+
if err := retry.RetryOnConflict(updateBackoff, func() error {
663+
_, err = ctrl.client.MachineconfigurationV1().MachineConfigs().Update(context.TODO(), mc, metav1.UpdateOptions{})
664+
return err
665+
}); err != nil {
666+
return fmt.Errorf("error updating MachineConfig %s: %w", mcName, err)
667+
}
668+
669+
klog.Infof("Successfully migrated MachineConfig %s to use crun", mcName)
670+
}
671+
672+
// Delete the ConfigMap after successful migration
673+
if err := ctrl.kubeClient.CoreV1().ConfigMaps(ctrlcommon.MCONamespace).Delete(context.TODO(), "crio-default-container-runtime", metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {
674+
return fmt.Errorf("error deleting crio-default-container-runtime configmap: %w", err)
675+
}
676+
677+
klog.Info("Successfully completed migration from runc to crun and deleted migration ConfigMap")
678+
return nil
679+
}
680+
599681
// syncContainerRuntimeConfig will sync the ContainerRuntimeconfig with the given key.
600682
// This function is not meant to be invoked concurrently with the same key.
601683
// nolint: gocyclo
@@ -606,6 +688,17 @@ func (ctrl *Controller) syncContainerRuntimeConfig(key string) error {
606688
klog.V(4).Infof("Finished syncing ContainerRuntimeconfig %q (%v)", key, time.Since(startTime))
607689
}()
608690

691+
// OKD only: Run the migration function at the start of sync
692+
if version.IsSCOS() {
693+
if err := ctrl.migrateRuncToCrun(); err != nil {
694+
return fmt.Errorf("Error during runc to crun migration: %w", err)
695+
}
696+
}
697+
698+
if key == forceSyncOnUpgrade {
699+
return nil
700+
}
701+
609702
_, name, err := cache.SplitMetaNamespaceKey(key)
610703
if err != nil {
611704
return err
@@ -709,7 +802,7 @@ func (ctrl *Controller) syncContainerRuntimeConfig(key string) error {
709802
}
710803
_, ok := cfg.GetAnnotations()[ctrlcommon.MCNameSuffixAnnotationKey]
711804
arr := strings.Split(managedKey, "-")
712-
// the first managed key value 99-poolname-generated-containerruntime does not have a suffix
805+
// the first managed key value 00-override-poolname-generated-containerruntime does not have a suffix
713806
// set "" as suffix annotation to the containerruntime config object
714807
if _, err := strconv.Atoi(arr[len(arr)-1]); err != nil && !ok {
715808
if err := ctrl.addAnnotation(cfg, ctrlcommon.MCNameSuffixAnnotationKey, ""); err != nil {

pkg/controller/container-runtime-config/helpers.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ const (
4949
policyConfigPath = "/etc/containers/policy.json"
5050
// CRIODropInFilePathLogLevel is the path at which changes to the crio config for log-level
5151
// will be dropped in this is exported so that we can use it in the e2e-tests
52-
CRIODropInFilePathLogLevel = "/etc/crio/crio.conf.d/01-ctrcfg-logLevel"
53-
crioDropInFilePathPidsLimit = "/etc/crio/crio.conf.d/01-ctrcfg-pidsLimit"
54-
crioDropInFilePathLogSizeMax = "/etc/crio/crio.conf.d/01-ctrcfg-logSizeMax"
55-
CRIODropInFilePathDefaultRuntime = "/etc/crio/crio.conf.d/01-ctrcfg-defaultRuntime"
56-
imagepolicyType = "sigstoreSigned"
57-
sigstoreRegistriesConfigFilePath = "/etc/containers/registries.d/sigstore-registries.yaml"
52+
CRIODropInFilePathLogLevel = "/etc/crio/crio.conf.d/01-ctrcfg-logLevel"
53+
crioDropInFilePathPidsLimit = "/etc/crio/crio.conf.d/01-ctrcfg-pidsLimit"
54+
crioDropInFilePathLogSizeMax = "/etc/crio/crio.conf.d/01-ctrcfg-logSizeMax"
55+
CRIODropInFilePathDefaultRuntime = "/etc/crio/crio.conf.d/01-ctrcfg-defaultRuntime"
56+
CRIODropInFilePathDefaultContainerRuntimeCrun = "/etc/crio/crio.conf.d/01-mc-defaultContainerRuntimeCrun"
57+
imagepolicyType = "sigstoreSigned"
58+
sigstoreRegistriesConfigFilePath = "/etc/containers/registries.d/sigstore-registries.yaml"
5859
)
5960

6061
var (
@@ -1211,3 +1212,15 @@ func imagePolicyConfigFileList(namespaceJSONs map[string][]byte) []generatedConf
12111212
}
12121213
return namespacedPolicyConfigFileList
12131214
}
1215+
1216+
// createDefaultContainerRuntimeFile creates a TOML config file for crun as the default container runtime
1217+
func createDefaultContainerRuntimeFile() []generatedConfigFile {
1218+
generatedConfigFileList := make([]generatedConfigFile, 0)
1219+
tomlConf := tomlConfigCRIODefaultRuntime{}
1220+
tomlConf.Crio.Runtime.DefaultRuntime = string(mcfgv1.ContainerRuntimeDefaultRuntimeCrun)
1221+
generatedConfigFileList, err := addTOMLgeneratedConfigFile(generatedConfigFileList, CRIODropInFilePathDefaultContainerRuntimeCrun, tomlConf)
1222+
if err != nil {
1223+
klog.V(2).Infof("error setting default-container-runtime to crio.conf.d: %v", err)
1224+
}
1225+
return generatedConfigFileList
1226+
}

0 commit comments

Comments
 (0)