Slide 1

Slide 1 text

Container Images for the Cloud-Native Era Wolfi, apko, and melange: the OSS container image toolkit by Chainguard Chainguard.dev | @erikaheidi

Slide 2

Slide 2 text

Ecosystem Overview

Slide 3

Slide 3 text

Wolfi ● Tiny Linux Distribution ● "Undistro" because it doesn't have stuff that normally goes into a Linux distribution (kernel, man pages, a bunch of other packages that don't make sense for containers) ● Based on apk (the Alpine package manager) ● Primarily GLIB-C (but MUSL is on the roadmap) ● Packages defined as YAML and built with melange

Slide 4

Slide 4 text

melange ● Declarative apk builder tool ● Part of the building toolkit behind Wolfi / Chainguard Images ● Build pipelines are defined in YAML files ● Multi-architecture by default (via QUEMU) ● Platform-agnostic builds via Docker + apko image

Slide 5

Slide 5 text

apko ● Declarative OCI image builder tool based on apk ● Part of the building toolkit behind Wolfi / Chainguard Images ● Images are defined in YAML files ● Builds are fully reproducible ● Automatically generates SBOMs for every image ● Platform-agnostic builds via Docker + apko image

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

apko deep dive

Slide 8

Slide 8 text

Example apko.yaml file contents: repositories: - https://dl-cdn.alpinelinux.org/alpine/edge/main packages: - alpine-base cmd: /bin/sh -l environment: PATH: /usr/sbin:/sbin:/usr/bin:/bin

Slide 9

Slide 9 text

Building the image with apko via Docker $ docker run --rm -v ${PWD}:/work cgr.dev/chainguard/apko build alpine-base.yaml alpine-base:test alpine-test.tar Testing the image with Docker $ docker load < alpine-test.tar $ docker run -it alpine-base:test

Slide 10

Slide 10 text

Why apk ● Introduced by Alpine, it uses a different methodology to handle package management ● Package installation or removal is done as a side effect of modifying the system state ● This creates the ideal conditions for reproducible and declarative pipelines

Slide 11

Slide 11 text

Where do packages come from ● For Alpine-based images, use Alpine apks found at pkgs.alpinelinux.org/packages ● For Wolfi-based images, use Wolfi apks that are listed in the wolfi-os repository, hosted at packages.wolfi.dev/os ● Don't mix! ● You can also create your own apks with melange

Slide 12

Slide 12 text

Why distroless?

Slide 13

Slide 13 text

The distroless philosophy ● Minimalist container images with only what's absolutely necessary to build or execute your application ● Popular base images are full of software that only makes sense on bare-metal ● No need for package managers or interactive shells on production images ● Less dependencies = smaller attack surface, less CVEs

Slide 14

Slide 14 text

The distroless philosophy: less CVEs = win

Slide 15

Slide 15 text

Case Study: Dynacover Migrating a PHP image to apko / distroless

Slide 16

Slide 16 text

Dynacover Overview ● Dynamic header images for Twitter ● PHP application built with Minicli ● Main dependencies: PHP (cli), Curl and GD

Slide 17

Slide 17 text

Dynacover Overview ● GitHub Action that runs on schedule ● Using an image based on the official php:7.4-cli ○ Size: 589MB ○ CVEs (Trivy): 331

Slide 18

Slide 18 text

Migration step 1: collecting dependencies FROM php:7.4-cli ARG user=dynacover ARG uid=1000 RUN apt-get update && apt-get install -y git curl libonig-dev libxml2-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev zip unzip RUN apt-get clean && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \ docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd COPY --from=composer:latest /usr/bin/composer /usr/bin/composer RUN useradd -G sudo,root -u $uid -d /home/$user $user RUN mkdir -p /home/$user/.composer && \ chown -R $user:$user /home/$user USER $user RUN mkdir -p /home/$user/dynacover COPY . /home/$user/dynacover/ WORKDIR /home/$user/dynacover RUN composer install ● git ● curl ● zip ● unzip ● libonig-dev ● libfreetype6-dev ● libjpeg62-turbo-dev ● libpng-dev ● php-mbstring ● php-exif ● php-pcntl ● php-bcmath ● php-gd

Slide 19

Slide 19 text

Migration step 2: finding appropriate apks

Slide 20

Slide 20 text

Migration step 3: creating the apko.yaml file contents: repositories: - https://dl-cdn.alpinelinux.org/alpine/edge/main - https://dl-cdn.alpinelinux.org/alpine/edge/community … … packages: - alpine-baselayout-data - ca-certificates-bundle - curl - git - zip - unzip - libxml2-dev - freetype - freetype-dev - libjpeg-turbo - libjpeg-turbo-dev - libpng - php81 - php81-gd - php81-curl - php81-mbstring - php81-phar - php81-openssl - php81-pcntl

Slide 21

Slide 21 text

Migration step 3: creating the apko.yaml file entrypoint: command: /usr/bin/php81 environment: PATH: /usr/sbin:/sbin:/usr/bin:/bin … … accounts: groups: - groupname: minicli gid: 65532 users: - username: minicli uid: 65532 run-as: root - php81-pcntl

Slide 22

Slide 22 text

Migration step 4: building/pushing the image $ docker run --rm -v ${PWD}:/work cgr.dev/chainguard/apko build apko.yaml \ erikaheidi/minicli:php81 minicli-php81.tar $ docker load < minicli-php81.tar $ docker push erikaheidi/minicli:php81

Slide 23

Slide 23 text

Migration step 5: updating GH Action Dockerfile FROM erikaheidi/minicli:php81 COPY --from=composer:latest /usr/bin/composer /usr/bin/composer RUN git clone -b 1.0.1 --depth 1 https://github.com/erikaheidi/dynacover.git && \ cd dynacover && \ composer install --no-progress --no-dev --prefer-dist ENTRYPOINT [ "php81", "/dynacover/dynacover" ] CMD ["cover", "update"]

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Dynacover base image: before / after ● Based on php:7.4-cli ● Base image total size: 589MB ● Total CVEs: 331 ● Distroless based on Alpine ● Base image total size: 48MB ● Total CVEs: 0

Slide 26

Slide 26 text

Resources to Learn More ● minicli:php81 on GitHub ● Getting Started with apko tutorial on Chainguard Academy ● apko on GitHub ● Troubleshooting apko builds ● Chainguard Images documentation ● Wolfi documentation

Slide 27

Slide 27 text

Questions?

Slide 28

Slide 28 text

Thank You!