Skip to content

Commit

Permalink
Merge pull request #712 from kernelkit/container-ifname
Browse files Browse the repository at this point in the history
  • Loading branch information
troglobit authored Oct 14, 2024
2 parents 227b3a9 + de27d1c commit 31552bf
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 38 deletions.
9 changes: 9 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/>
Expand All @@ -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

Expand Down
72 changes: 45 additions & 27 deletions doc/container.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Containers in Infix
===================
<img align="right" src="img/docker.webp" alt="Docker whale" width=360>

* [Introduction](#introduction)
* [Caution](#caution)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions doc/img/cni-bridge-firewall.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions doc/img/cni-ntpd-bridged.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions doc/img/cni-ntpd-routed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/docker.webp
Binary file not shown.
2 changes: 1 addition & 1 deletion src/confd/src/ietf-system.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 13 additions & 2 deletions src/confd/src/infix-containers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion src/confd/yang/containers.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# REMEMBER TO UPDATE infix-interfaces ALSO IN confd.inc
MODULES=(
"[email protected] -e vlan-filtering -e containers"
"infix-containers@2024-03-27.yang"
"infix-containers@2024-10-14.yang"
)
32 changes: 25 additions & 7 deletions src/confd/yang/infix-containers.yang
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
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
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";
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;
}
}
Expand Down
File renamed without changes.

0 comments on commit 31552bf

Please sign in to comment.