Merge pull request #712 from kernelkit/container-ifname

This commit is contained in:
Joachim Wiberg
2024-10-14 21:01:38 +02:00
committed by GitHub
11 changed files with 106 additions and 38 deletions
+9
View File
@@ -13,6 +13,13 @@ addresses for interfaces! For details, see below issue #680.
- Update CONTRIBUTING.md for scaling core team and helping external
contributors understand the development process, issue #672
- OSPF: Add limitation to only allow one interface per area
- Add support for "dummy" interfaces, mostly useful for testing
- Add support for container hostname format specifiers, just like it
already works for the host's hostname setting
- Updated container documentation, improved images, detail how to set
interface name inside the container, and some syntax fixes
- Greatly reduced size of bundled curiOS httpd OCI container image,
reduced from 1.8 MiB to 281 KiB
- The default builds now include the curiOS nftables container image,
which can be used for advanced firewall setups. For an introduction
see <https://kernelkit.org/posts/firewall-container/>
@@ -37,6 +44,8 @@ addresses for interfaces! For details, see below issue #680.
this includes all operational data in ietf-routing:/routing/ribs.
- Fix #697: password is not always set for new users, bug introduced
in v24.06.0 when replacing Augeas with native user handling
- Fix #708: allow all container networks to set interface name inside
container, not just auto-generated veth-pair ends for `docker0` bridge
- Fix BFD in OSPF, previously you could not enable BFD on a single
interface without it was enabled on all interfaces
+45 -27
View File
@@ -1,5 +1,6 @@
Containers in Infix
===================
<img align="right" src="img/docker.webp" alt="Docker whale" width=360>
* [Introduction](#introduction)
* [Caution](#caution)
@@ -78,16 +79,17 @@ In the CLI, containers can be run in one of two ways:
1. `container run IMAGE [COMMAND]`, and
2. enter `configure` context, then `edit container NAME`
The first is useful mostly for testing, or running single commands in an
image. It is a wrapper for `podman run -it --rm ...`, while the latter
is a wrapper and adaptation of `podman create ...`.
The former is useful mostly for testing, or running single commands in
an image. It is a wrapper for `podman run -it --rm ...`, while the
latter is a wrapper and adaptation of `podman create ...`.
The second create a container with a semi-persistent writable layer that
survives container restarts and host system restarts. However, if you
change the container configuration or upgrade the image (see below), the
container will be recreated and the writable layer is lost. This is why
it is recommended to set up a named volume for directories, or use file
[Content Mounts][], in your container you want truly persistent content.
[Content Mounts](#content-mounts), in your container if you want truly
persistent content.
In fact, in many cases the best way is to create a `read-only` container
and use file mounts and volumes only for the critical parts. Podman
@@ -299,14 +301,19 @@ Currently two types of of container networks are supported:
> For more information on VETH pairs, see the [Networking Guide][0].
### Container Bridge
A container bridge is what most container setups use and users want.
![IP Masquerading Container Bridge](img/cni-bridge-firewall.svg)
The difference from a regular bridge is that the container runtime fully
manages them -- connecting containers automatically with VETH pairs and
setting up firewall rules between the host and other containers, as well
as managing port forwarding. This transparent background management is
what makes container use seem to be so simple.
manages them -- connecting containers with automatically created VETH
pairs (look at the bridge port names) and setting up firewall rules
between the host and other containers, as well as managing port
forwarding. This transparent background management is what makes
container use seem to be so simple.
All interface configuration is done in configure context.
@@ -394,20 +401,21 @@ namespace of a container[^3]. This of course works with plain Ethernet
interfaces as well, but here we will use one end of a VETH pair as an
example.
The network `option` setting is available also for this case, but only
the `interface_name=foo0` option works. Which is still very useful. To
change the MAC address, you need to use the `custom-phys-adderss` in the
general network settings.
[^3]: Something which the container bridge network type does behind the
scenes with one end of an automatically created VETH pair.
#### Routed Setup
In this routed setup we reserve 192.168.0.0/24 for the network between
the host and the `ntpd` container.
_____________
| |
veth0 .1 | .2 eth0 |
\ 192.168.0.0/24 | / |
'--------------------' [ntpd] |
|_____________|
![Basic VETH pair connecting ntpd container.](img/cni-ntpd-routed.svg)
Configuration is a straight-forward VETH pair setup where we name the
container-end of pair `ntpd`. This is just a convenience for us when
@@ -429,9 +437,12 @@ Adding the interface to the container is the same as before, but since
everything for host interfaces is set up in the interfaces context, we
can take a bit of a shortcut.
admin@example:/config/container/ntpd/> set network ntpd
admin@example:/config/container/ntpd/> set network interface ntpd
admin@example:/config/container/ntpd/> leave
> Use the `set network inteface ntpd option interface_name=foo0` to set
> the name of the interface inside the container to `foo0`.
The point of the routed case is that port forwarding from the container
in this case is limited to a single interface, not *all interfaces* as
is the default in the masquerading container bridge setup.
@@ -443,21 +454,15 @@ A perhaps more common case is to bridge the other end of the VETH pair
with other physical ports. In this section we show how to add a new
pair to give our container two interfaces:
_______________
| | .1 br0
veth0 .1 | .2 eth0 | / \
\ 192.168.0.0/24 | / eth1 .2 | veth1b e1
'------------------' \ | 192.168.1.0/24 /
| [ntpd] '------------------'
|_______________|
![Bridged setup with ntpd container.](img/cni-ntpd-bridged.svg)
We start by adding the second VETH pair:
admin@example:/config/> edit interface veth1a
admin@example:/config/interface/veth1a/> set veth peer veth1b
admin@example:/config/interface/veth1a/> set veth peer veth1
admin@example:/config/interface/veth1a/> set ipv4 address 192.168.1.2 prefix-length 24
> The LAN bridge (br0) in this example has IP address 192.168.1.1.
> The LAN bridge (br1) in this example has IP address 192.168.1.1.
When a container has multiple host interfaces it can often be useful to
have a default route installed. This can be added from the host with a
@@ -473,15 +478,16 @@ have a default route installed. This can be added from the host with a
}
}
veth {
peer veth1b;
peer veth1;
}
admin@example:/config/interface/veth1a/> end
admin@example:/config/> set interface veth1b bridge-port bridge br0
admin@example:/config/> set interface veth1 bridge-port bridge br1
Please note, container network routes require the base interface also
have a static IP address set. Setting only the route, but no address,
means the route is skipped.
### Host Networking
The third use-case is host networking, this is where a container share
@@ -491,7 +497,7 @@ the host operating system.
The host networking setup cannot be combined with any other network.
For an example, see below.
For an example, [see below](#application-container-nftables).
Mounts and Volumes
@@ -599,6 +605,17 @@ container ID (hash) is used, but this can be easily changed:
admin@example:/> container shell system
root@sys101:/#
In fact, the container `hostname` setting supports the same format
specifiers as the host's `hostname` setting:
- `%i`: OS ID, from `/etc/os-release`, from Menuconfig branding
- `%h`: Default hostname, from `/etc/os-release`, from branding
- `%m`: NIC specific part of base MAC, e.g., to `c0-ff-ee`
- `%%`: Literal %
The most useful combination is probably `"container-name-%m"`, which in
this example give the container hostname `container-name-c0-ff-ee`.
[^1]: this does not apply to the admin-exec command `container run`.
This command is intended to be used for testing and evaluating
container images. Such containers are given a private network
@@ -626,6 +643,7 @@ Notice how we `set network host`, so the container can see and act on
all the host's interfaces, and that we also have to run the container
in *privileged* mode.
### Application Container: ntpd
The default NTP server/client in Infix is Chrony, a fully working and
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 317 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 340 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

+1 -1
View File
@@ -1625,7 +1625,7 @@ static char *get_mac(struct confd *confd, char *mac, size_t len)
*
* XXX: PLEASE REFACTOR THIS INTO A PYTHON HELPER FOR FUTURE EXTENSIONS, OR BUGS!
*/
static int hostnamefmt(struct confd *confd, char **fmt)
int hostnamefmt(struct confd *confd, char **fmt)
{
size_t hostlen, fmt_len;
char *hostname;
+13 -2
View File
@@ -21,6 +21,9 @@
#define ACTIVE_QUEUE "/var/lib/containers/active"
#define LOGGER "logger -t container -p local1.notice"
int hostnamefmt(struct confd *confd, char **fmt);
static int add(const char *name, struct lyd_node *cif)
{
const char *image = lydx_get_cattr(cif, "image");
@@ -46,8 +49,16 @@ static int add(const char *name, struct lyd_node *cif)
LYX_LIST_FOR_EACH(lyd_child(cif), node, "search")
fprintf(fp, " --dns-search %s", lyd_get_value(node));
if ((string = lydx_get_cattr(cif, "hostname")))
fprintf(fp, " --hostname %s", string);
if ((string = lydx_get_cattr(cif, "hostname"))) {
char *fmt = (char *)string;
if (hostnamefmt(&confd, &fmt)) {
ERRNO("%s: failed setting custom hostname", name);
} else {
fprintf(fp, " --hostname %s", fmt);
free(fmt);
}
}
if (lydx_is_enabled(cif, "read-only"))
fprintf(fp, " --read-only");
+1 -1
View File
@@ -2,5 +2,5 @@
# REMEMBER TO UPDATE infix-interfaces ALSO IN confd.inc
MODULES=(
"infix-interfaces@2024-09-23.yang -e vlan-filtering -e containers"
"infix-containers@2024-03-27.yang"
"infix-containers@2024-10-14.yang"
)
+25 -7
View File
@@ -22,6 +22,17 @@ module infix-containers {
prefix infix-if;
}
import infix-system {
prefix infix-sys;
}
revision 2024-10-14 {
description "Two major changes:
- Allow changing name of host interfaces inside container
- Support hostname format specifiers, like ietf-system";
reference "internal";
}
revision 2024-03-27 {
description "Add support for capabilities.";
reference "internal";
@@ -160,8 +171,11 @@ module infix-containers {
}
leaf hostname {
description "Sets the container host name that is available inside the container.";
type inet:domain-name;
description "Sets the container host name, available inside the container.
Format specifiers are for, default hostname, ID, and the
last three octets in base MAC, e.g., c0-ff-ee";
type infix-sys:hostname;
}
leaf privileged {
@@ -201,12 +215,16 @@ module infix-containers {
}
leaf-list option {
when "deref(../name)/../infix-if:container-network/infix-if:type = 'infix-if:bridge'";
description "Options for masquerading container bridges.
description "Options for interface inside container, e.g., interface_name=foo0
Example: ip=1.2.3.4 -- request a specific IP (IPv4 or IPv6)
mac=00:01:02:c0:ff:ee -- set fixed MAC address in container
interface_name=foo0 -- set interface name inside container";
Options: ip=1.2.3.4 -- Set static IPv4 address*
ip6=2001:0:130f::9c0:876a:130b -- Set static IPv6 address*
mac=00:01:02:c0:ff:ee -- Set fixed MAC address
interface_name=foo0 -- Set interface name
NOTE: Some (*) options only work with masquerading container bridges,
which automatically create VETH pairs with one end in the host
bridge and the other in the container.";
type string;
}
}