EVE Base Distribution design

EVE Base Distribution design

Proposal

Proposed Design: Simplify the EVE alpine package chain and build process by eliminating all except the most recent stage of eve-alpine. In doing so, we accept frequent small updates in order to avoid infrequent very complex and expensive updates, that almost never get done.

Proposed Policy: Update the distro base and all OS packages to latest versions at least twice each year, in line with LTS releases.

Architectural Note: While this currently applies to Alpine, which is the base distro used for EVE packages, the same principles apply to any base distro and its packaging system. Should EVE switch to any other base distro and packaging system, the structures and concerns would be the same.

Current Design

All EVE package images are built on a Linux distribution base, in the case of EVE, alpine. EVE has a container image that serves as a cache of all packages, as well as some useful utilities. This cache is the image lfedge/eve-alpine and the source is in the main EVE repository under pkg/alpine.

This cache’s primary purpose is to ensure builds are reproducible. Since reinstalling a distro software package from upstream can download a different version, or possibly even updated bits for the same version, a cache ensures that EVE component images always rebuild identically, by pulling distro packages from the cache, rather than upstream.

For illustration, the most recent version of lfedge/eve-alpine container image, as of this writing, is 56e65818c517e51f04c44bfa2c525a283167411e. All downstream packages will pull from there, for example, pkg/installer/Dockerfile uses FROM lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04 AS build and all other packages are built similarly.

lfedge/eve-alpine, however, does not base itself on upstream alpine as FROM alpine:3.22 or similar. Instead, it bases itself on a previous version of the cache:

# DON'T FORGET TO UPDATE THE HASH WHEN SOMETHING CHANGES! # please see https://github.com/lf-edge/eve/blob/master/docs/BUILD.md#how-to-update-eve-alpine-package FROM lfedge/eve-alpine:e799def68af51dba83ec5a41f34bd0109704574f AS cache

The purpose of this is to ensure that adding or updating a single distro software package, e.g. tcpdump, does not pull in updates of other packages, eg. bind-utils or hwinfo-libs.

Finally, there is a third stage. The very base of the chain is lfedge/eve-alpine-base, with the source in the main EVE repository under pkg/alpine-base.

The build chain looks like this:

alpine:3.16 -> alpine-base -> alpine (cache) v1 -> alpine v2 -> alpine v3 -> .... -> alpine vN -> (pillar, wwan, installer, etc.)

This is described in detail in docs/BUILD.md.

Benefits of Current Design

This is supposed to have the following benefits:

  • Use of cache ensures reproducible EVE package images.

  • Cache chaining, wherein eve-alpine depends on previous version of eve-alpine and so on, enables quick addition of new distro packages to eve-alpine cache without updating other distro packages.

  • Use of alpine-base provides a common base of the chain, as well as support for riscv64, which did not exist in earlier version of upstream alpine containers.

Costs of Current Design

The current design has the following costs:

  • The design is so complex as to make it difficult to follow, even for experienced engineers, let alone new contributors.

  • The complexity makes it so hard to update the base version, especially concern about downstream impact on other EVE images, that the alpine version almost never gets updated; EVE has been based on alpine:3.16 for years because it was too difficult to update. We miss CVE updates, versions, and other commitments.

  • Older packages never get removed.

Proposed Design

We propose removing the entire chained build and alpine-base build.

Instead, eve-alpine will be based directly on FROM alpine:3.23 or the latest upstream version. There will be no need to remember to update the FROM in eve-alpine with each update, nor will there be a need to understand how to bump to a newer version of alpine as a base distro.

The build chain looks like this:

alpine:3.23 -> alpine (cache) latest -> (pillar, wwan, installer, etc.)

Benefits of Proposed Design

This has the following benefits:

  • Use of cache ensures reproducible EVE package images (UNCHANGED).

  • Simple design makes it easy for existing and new contributors to understand quickly.

  • No need for alpine-base, as riscv64 support has been available since alpine:3.20.

Costs of Current Design

The proposed design has the following costs:

  • Any updates to the cache - additions or removals - may update other distro packages, which can affect downstream EVE package images.

In our opinion, this is “a feature, not a bug”. Small regular updates encourage keeping downstream EVE images up to date as part of regular practice. This keeps it from building up to a nearly impossible burden once the requirement is unavoidable.

In addition, it does not automatically update downstream. When the cache is updated, it gets a new version. For example, as of this writing, the latest version is lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04, while the previous is lfedge/eve-alpine:e799def68af51dba83ec5a41f34bd0109704574f . Downstream packages, such as pillar, are unaffected until they change:

FROM lfedge/eve-alpine:e799def68af51dba83ec5a41f34bd0109704574f

to:

FROM lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04

Further, these changes are likely to be small and incremental, since there will be complete updates every 6 months.

Proposed Policy

In addition to the design, we propose a “twice-a-year distro update” policy.

The EVE project releases LTS versions twice each year. On master branch, immediately after creating LTS branch, the following steps are taken:

  1. In eve-alpine, the upstream dependency is updated to the latest version, e.g. FROM alpine:3.21 is updated to FROM alpine:3.22, if such is available.

  2. In eve-alpine, all of the distro packages are updated to their latest versions. In the case of languages, such as Rust, Python or Go, where support for multiple versions may be necessary, and differing minor versions can be significant, then the latest patch version of each.

  3. In each downstream EVE package image, all of the build bases are updated to the latest FROM lfedge/eve-alpine. The majority of these should work without any difficulty, and CI, especially eden tests, should catch any issues. Some will not work due to changed interfaces or split distro packages, and will require minor rework.

We believe these are necessary in order to keep up to date, avoid CVE issues, comply with software policies, and keep the costs of updating manageable.

We do it immediately after creating the LTS branch with the following considerations:

  1. If we updated immediately before, it could expose some unexpected compatibility issues in LTS, which are much more painful to fix, given the “LTS” nature. Thus, we update in master branch immediately after cutting LTS branch.

  2. We update immediately after, so that the process becomes connected to the LTS process, and strengthens its regularity.

  3. Updating after LTS means that LTS will have the older versions. This is acceptable, or even desirable, as long as they are not too far behind. This requires ensuring that the update process happens regularly.