kata-deploy: Allow overriding containerd config path and file name

Add two new Helm values under `containerd`:
- `configDir`: overrides the host directory where the containerd
  config lives, taking precedence over the k8sDistribution-based
  auto-detection.
- `configFileName`: overrides the containerd config file name,
  propagated to the kata-deploy binary via the new
  CONTAINERD_CONFIG_FILE_NAME environment variable.

These are useful for non-standard containerd setups that don't match
any of the built-in k8sDistribution presets (k8s, k3s, rke2, k0s,
microk8s).

The config file name override only affects the default runtime branch
in get_containerd_paths(). The k0s/microk8s/k3s/rke2 branches are
left untouched since those runtimes have mandatory file naming
conventions.

Also fixes a spurious leading space in the k3s containerdConfPath
branch.

Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com>
Made-with: Cursor
This commit is contained in:
Fabiano Fidêncio
2026-04-13 22:18:27 +02:00
parent 4c567a9c05
commit df1d02d3cf
4 changed files with 170 additions and 5 deletions

View File

@@ -243,7 +243,21 @@ impl Config {
};
let crio_drop_in_conf_file_debug = format!("{crio_drop_in_conf_dir}/100-debug");
let containerd_conf_file = "/etc/containerd/config.toml".to_string();
let containerd_config_file_name = env::var("CONTAINERD_CONFIG_FILE_NAME")
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.unwrap_or_else(|| "config.toml".to_string());
let containerd_conf_path = Path::new("/etc/containerd").join(&containerd_config_file_name);
if containerd_conf_path.parent() != Some(Path::new("/etc/containerd"))
|| containerd_conf_path.file_name() != Some(containerd_config_file_name.as_ref())
{
return Err(anyhow::anyhow!(
"CONTAINERD_CONFIG_FILE_NAME must be a simple file name without path separators, \
got: '{containerd_config_file_name}'"
));
}
let containerd_conf_file = containerd_conf_path.to_string_lossy().to_string();
let containerd_conf_file_backup = format!("{containerd_conf_file}.bak");
let containerd_drop_in_conf_file =
format!("{dest_dir}/containerd/config.d/kata-deploy.toml");
@@ -503,6 +517,7 @@ impl Config {
"* EXPERIMENTAL_FORCE_GUEST_PULL: {}",
self.experimental_force_guest_pull_for_arch.join(",")
);
info!("* CONTAINERD_CONF_FILE: {}", self.containerd_conf_file);
info!(
"* CUSTOM_RUNTIMES_ENABLED: {}",
self.custom_runtimes_enabled
@@ -558,7 +573,7 @@ impl Config {
.await
.ok();
let use_v3 = k3s_rke2_resolve_use_v3(
&self.containerd_conf_file,
k3s_rke2_rendered_config_path(),
container_runtime_version.as_deref(),
)?;
let config_file = k3s_rke2_containerd_template_path(use_v3).to_string();
@@ -801,6 +816,7 @@ mod tests {
"EXPERIMENTAL_FORCE_GUEST_PULL_AARCH64",
"EXPERIMENTAL_FORCE_GUEST_PULL_S390X",
"EXPERIMENTAL_FORCE_GUEST_PULL_PPC64LE",
"CONTAINERD_CONFIG_FILE_NAME",
];
for var in &vars {
std::env::remove_var(var);
@@ -1196,6 +1212,134 @@ mod tests {
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_default() {
setup_minimal_env();
let config = Config::from_env().unwrap();
assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml");
assert_eq!(
config.containerd_conf_file_backup,
"/etc/containerd/config.toml.bak"
);
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_custom() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "my-config.toml");
let config = Config::from_env().unwrap();
assert_eq!(
config.containerd_conf_file,
"/etc/containerd/my-config.toml"
);
assert_eq!(
config.containerd_conf_file_backup,
"/etc/containerd/my-config.toml.bak"
);
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_empty_uses_default() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "");
let config = Config::from_env().unwrap();
assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_whitespace_only_uses_default() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", " ");
let config = Config::from_env().unwrap();
assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_trimmed() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", " my-config.toml ");
let config = Config::from_env().unwrap();
assert_eq!(
config.containerd_conf_file,
"/etc/containerd/my-config.toml"
);
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_rejects_path_separator() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "../etc/shadow");
assert_config_error_contains("simple file name");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_rejects_slash() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "subdir/config.toml");
assert_config_error_contains("simple file name");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_rejects_dotdot() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "..");
assert_config_error_contains("simple file name");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_rejects_dot() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", ".");
assert_config_error_contains("simple file name");
cleanup_env_vars();
}
#[serial]
#[test]
fn test_containerd_config_file_name_allows_dots_in_name() {
setup_minimal_env();
std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "config.v2.toml");
let config = Config::from_env().unwrap();
assert_eq!(
config.containerd_conf_file,
"/etc/containerd/config.v2.toml"
);
cleanup_env_vars();
}
#[serial]
#[test]
fn test_arch_specific_all_variables() {

View File

@@ -44,13 +44,16 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Set the correct containerd conf path depending on the k8s distribution
Set the correct containerd conf path depending on the k8s distribution.
If containerd.configDir is set explicitly, use that instead.
*/}}
{{- define "containerdConfPath" -}}
{{- if eq .k8sDistribution "rke2" -}}
{{- if and .containerd .containerd.configDir -}}
{{- .containerd.configDir -}}
{{- else if eq .k8sDistribution "rke2" -}}
/var/lib/rancher/rke2/agent/etc/containerd/
{{- else if eq .k8sDistribution "k3s" -}}
/var/lib/rancher/k3s/agent/etc/containerd/
/var/lib/rancher/k3s/agent/etc/containerd/
{{- else if eq .k8sDistribution "k0s" -}}
/etc/k0s/
{{- else if eq .k8sDistribution "microk8s" -}}

View File

@@ -291,6 +291,10 @@ spec:
- name: EXPERIMENTAL_FORCE_GUEST_PULL_PPC64LE
value: {{ $forceGuestPullPpc64le | quote }}
{{- end }}
{{- if .Values.containerd.configFileName | trim }}
- name: CONTAINERD_CONFIG_FILE_NAME
value: {{ .Values.containerd.configFileName | trim | quote }}
{{- end }}
{{- with .Values.env.hostOS }}
- name: HOST_OS
value: {{ . | quote }}

View File

@@ -12,6 +12,20 @@ kubectlImage:
k8sDistribution: "k8s" # k8s, k3s, rke2, k0s, microk8s
# Containerd configuration overrides
# These override the auto-detected paths based on k8sDistribution.
# Use these when your containerd setup doesn't match any built-in distribution preset.
containerd:
# Override the host directory where containerd config lives.
# When empty, derived automatically from k8sDistribution.
# Example: "/etc/my-containerd/"
configDir: ""
# Override the containerd config file name.
# When empty, the kata-deploy binary uses its built-in default ("config.toml")
# or auto-detects based on the runtime (k0s, microk8s, k3s/rke2).
# Example: "my-config.toml"
configFileName: ""
# Node selector and tolerations to control which nodes the kata-deploy daemonset runs on
# Examples:
# nodeSelector: