Docker-Provider/MARINER.md

7.1 KiB

Mariner Development

Mariner vs. Ubuntu

Mariner is an RPM-based distro whereas Ubuntu is Debian-based. Mariner uses tdnf as its package manager whereas Ubuntu uses apt. The largest difference between the two then is replacing all the apt commands with tdnf. This table provides all the equivalent commands between the two. Not all commands are available with tdnf, which is a trimmed-down C-based version of the dnf package manager. dnf can be installed by tdnf with tdnf install -y dnf if some extra commands are needed. Using dnf was useful for debugging to find which repo a package was coming or if it had a different name compared to the Ubuntu package.

More info about apt vs tdnf can be found here.

Adding an RPM Repository

New repositories are added with a *.repo file stored in the /etc/yum.repos.d/ directory.

Mariner by default has certain repo files in the container already. These include the repos for the mariner base and mariner extended packages.

azure-mdsd is in the Mariner-extras repository.

Distroless Containers

Distroless containers exclude packages provided by the distro such as a shell and package manager. They provide a slimmed down image with a smaller attack surface. We will still need a shell for our main.sh script and any debugging done by exec-ing into the container. But a distroless base image is still useful to not have the package managers and any unecessary packages which are needed solely for building and not at runtime. This is especially useful since tdnf does not have an autoremove command and using the distroless container trims down the size quite a bit.

Docker Multi-Stage Builds

Since the distroless container does not have a package manager, we will still need a way to install all the necessary packages. The standard way to do this for distroless containers is through multi-stage builds. The first build uses the regular base container and sets up everything as normal up until adding the entry command as running the main.sh script.

The second build uses the distroless image as the base image. Only the files we need at runtime are copied over from the first build. An example of this is here.

Note that this means that any new files added while developing will need to be copied over to the distroless build stage. Everything under /opt is currently copied over. See below for the steps to take when adding a new package.

If you are building locally, you will need to set DOCKER_BUILDKIT=1 because of this Docker bug. This has been set in our github actions builds.

Using the Shell in the Distroless Container

bash is still copied over into our container to be able to run our main.sh bash script. However, there are some interface issues with bash on the distroless container. Mariner has default support for using busybox as the shell for debugging. This however changes some of the commands when exec-ing into the container which I have noted below. Feel free to add more here if you find them.

Old Command New Command
ps -aux ps

Note: You can still call kubectl exec -it <pod name> -- bash, there will just be a weird warning from busybox in the beginning.

Adding or Upgrading a New Package

Base Image

You can start to add a package by including tdnf install -y <package name> in the builder Docker stage and trying to build to see if the package is available. tdnf will search all repos for the package and print out an error if it cannot be found.

Some naming conventions or package names are different for RPM packages. For example, *-dev and *-debug for Ubuntu packages vs. *-devel and *-debugsymbol for RPM pacakges. Similarly, cron has an equivalent RPM package called cronie and the name of the executable is crond. A package you are looking for may be provided by Mariner but under a different name. For example, libre2 is just re2 in the Mariner repository.

dnf has a command called whatprovides to help with this as explained here, but usually a quick internet search will also work.

Our Current Package Dependencies

  • All Mariner packages are supported for both AMD64 and ARM64.
  • telegraf, fluent-bit are built and published by the Mariner team in the Mariner base repository. ARM64 versions are available also.
  • azure-mdsd is published by their team to the Mariner extras repository. Release notes. The package for Mariner 2.0 is now available.
  • When updating any package, make sure to check the dependencies and add if any changes. (Avoid removing unless you are completely sure that non other packages have those dependencies as some dependencies in the list may also be used by some other package.)

Get dependencies for the distroless image

To get the .so file dependencies, run:

  • which <executable> to get the executable path

  • ldd <executable path> to get the list of dependencies

  • This will print out something similar to:

    linux-vdso.so.1 (0x00007ffc2eb6e000)
    libselinux.so.1 => /lib/libselinux.so.1 (0x00007f7677a6a000)
    libpam.so.0 => /lib/libpam.so.0 (0x00007f7677a58000)
    libc.so.6 => /lib/libc.so.6 (0x00007f7677856000)
    libpcre.so.1 => /lib/libpcre.so.1 (0x00007f76777df000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f7677b30000)
    libaudit.so.1 => /lib/libaudit.so.1 (0x00007f76777ae000)
    
  • Packages without => do not need to be copied as these will already be present in the distroless container If some files are missing after the =>, you can run these commands in a container that is using the base image instead of the distroless image to see which files need to be copied over

In the Dockerfile in the distroless stage:

  • Copy over the executable file path
  • Copy over the full path of all .so files that have =>
  • If not all necssary .so files are available, there will be an error saying that file is missing during runtime