feat(manifest): network_aliases — extra DNS aliases on a container's network
Add `container.network_aliases: Vec<String>` (serde default, DNS-label validated) so a stack member can answer to short hostnames its peers bake in, beyond its own container name. Rendered in both runtime paths: - podman_client: merged (deduped) into the custom-network aliases array. - quadlet from_manifest: appended after the container name; emitted only for Bridge networks (slirp/pasta reject aliases). Needed for the indeedhub migration: its frontend nginx proxies to `api:4000` / `minio:9000` / `relay:8080`, so those members declare `network_aliases: [api|minio|relay]` to keep the short names resolvable on the dedicated indeedhub-net (vs. colliding generic aliases on archy-net). Also fixes 4 pre-existing from_manifest test failures (unrelated to this change, surfaced now that the quadlet suite runs green): test manifests used the long-invalid `network_policy: archy-net` (allowlist is isolated/bridge/host → moved to network_policy: isolated + container.network) and bind sources outside /var/lib/archipelago. Tests: container crate 53 pass; archipelago quadlet+alias 47 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ccb5b7ca39
commit
b94b61f640
@@ -170,6 +170,17 @@ pub struct ContainerConfig {
|
||||
#[serde(default)]
|
||||
pub network: Option<String>,
|
||||
|
||||
/// Extra DNS aliases the container answers to on its `network`, in addition
|
||||
/// to its own container name (which is always added). Mirrors podman
|
||||
/// `--network-alias`. Used by multi-container stacks whose images reference
|
||||
/// peers by a short baked-in hostname — e.g. indeedhub's frontend nginx
|
||||
/// proxies to `api:4000` / `minio:9000` / `relay:8080`, so the api/minio/relay
|
||||
/// members declare `network_aliases: [api]` / `[minio]` / `[relay]` to keep
|
||||
/// those short names resolvable on the dedicated `indeedhub-net`. Ignored for
|
||||
/// slirp4netns/pasta (podman rejects aliases there).
|
||||
#[serde(default)]
|
||||
pub network_aliases: Vec<String>,
|
||||
|
||||
/// Extra positional arguments appended to the container command
|
||||
/// after the image. Mirrors `SPEC_CUSTOM_ARGS` in
|
||||
/// `scripts/container-specs.sh` (bitcoin-knots prune/dbcache flags,
|
||||
@@ -539,6 +550,25 @@ impl AppManifest {
|
||||
}
|
||||
}
|
||||
|
||||
// network_aliases: each must be a non-empty DNS label (lowercase
|
||||
// alphanumeric + hyphen, no leading/trailing hyphen) so it renders as a
|
||||
// valid podman --network-alias / aardvark-dns name.
|
||||
for (i, alias) in self.app.container.network_aliases.iter().enumerate() {
|
||||
let ok = !alias.is_empty()
|
||||
&& alias.len() <= 63
|
||||
&& alias
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
|
||||
&& !alias.starts_with('-')
|
||||
&& !alias.ends_with('-');
|
||||
if !ok {
|
||||
return Err(ManifestError::Invalid(format!(
|
||||
"container.network_aliases[{i}] '{alias}' must be a non-empty DNS label \
|
||||
(lowercase a-z, 0-9, '-'; no leading/trailing '-')"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// custom_args: no empty strings (would inject literal "" into
|
||||
// the podman command line and confuse downstream parsing).
|
||||
for (i, a) in self.app.container.custom_args.iter().enumerate() {
|
||||
@@ -1662,6 +1692,7 @@ app:
|
||||
pull_policy: "if-not-present".to_string(),
|
||||
build: None,
|
||||
network: None,
|
||||
network_aliases: vec![],
|
||||
custom_args: vec![],
|
||||
entrypoint: None,
|
||||
derived_env: vec![
|
||||
@@ -1716,6 +1747,7 @@ app:
|
||||
pull_policy: "if-not-present".to_string(),
|
||||
build: None,
|
||||
network: None,
|
||||
network_aliases: vec![],
|
||||
custom_args: vec![],
|
||||
entrypoint: None,
|
||||
derived_env: vec![],
|
||||
@@ -1758,6 +1790,7 @@ app:
|
||||
pull_policy: "if-not-present".to_string(),
|
||||
build: None,
|
||||
network: None,
|
||||
network_aliases: vec![],
|
||||
custom_args: vec![],
|
||||
entrypoint: None,
|
||||
derived_env: vec![],
|
||||
|
||||
@@ -385,11 +385,21 @@ impl PodmanClient {
|
||||
},
|
||||
});
|
||||
if let Some(network) = custom_network {
|
||||
// The container always answers to its own name; manifest
|
||||
// network_aliases add extra short hostnames peers may bake in
|
||||
// (e.g. indeedhub's api/minio/relay). Dedup so a manifest that
|
||||
// redundantly lists its own name doesn't double it.
|
||||
let mut aliases = vec![name.to_string()];
|
||||
for a in &manifest.app.container.network_aliases {
|
||||
if !aliases.iter().any(|x| x == a) {
|
||||
aliases.push(a.clone());
|
||||
}
|
||||
}
|
||||
body.as_object_mut()
|
||||
.expect("container create body is a JSON object")
|
||||
.insert(
|
||||
"networks".to_string(),
|
||||
serde_json::json!({ network: { "aliases": [name] } }),
|
||||
serde_json::json!({ network: { "aliases": aliases } }),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user