Apko: Build images for apk-based distributions declaratively

Related tags

DevOps Tools apko
Overview

apko

Build images for apk-based distributions declaratively!

Why

When maintaining images at scale, the Dockerfile concept built into Docker is inefficient. If we have a collection of build artifacts, repositories and a keyring, we can build images directly with APK, and upload them directly to container registries.

In fact, we can do more than that: using a service like kontain.me, we can serve fresh container images on demand, with the latest package updates, using nothing but declarative configuration.

How

This part is very much a work in progress, but basically you need a system with apk (soon: libapk), and this apko tool. You probably also want the other Chainguard stack components as well, e.g. crane.

To build an image, use the apko build command:

# apko build config.yaml tag output.tar

This will give you a Docker-style tarball which you can use with docker load:

# docker load < output.tar

You need root, or at least fakeroot + fakechroot to build images with apko, due to apk-tools' use of chroot(2).

Issues
  • multiarch support

    multiarch support

    With the proot support landed, we can do multiarch builds, since --no-scripts is now a requirement.

    From the apk side of things, this can be done by simply passing --arch [arch] when setting up the apkdb, e.g. in the InitApkDb step.

    I'm told that we can possibly recruit @imjasonh to work on this. Ideally we would probably build images for all of the archs at once, I suppose.

    opened by kaniini 20
  • Allow entrypoint to be blank.

    Allow entrypoint to be blank.

    Allowing entrypoint to be blank can be used to force default docker behaviour of running cmd in shell. Also updated examples.

    Closes #177.

    We could also create a PR to set CMD to /bin/sh -l which would be keep previous behaviour when no command is specified.

    opened by amouat 12
  • Multiarch support

    Multiarch support

    apko publish produces a multiarch image index. By default, this includes six common archs, which can be overridden with archs: in the image config YAML, or values in the --arch flag (in increasing order of preference).

    An attempt is made to accept both apk-style arch strings ("x86_86") and OCI-style arch strings ("amd64"), but more could probably be done. There's a TODO to support armv7 and armhf (arm/v7 and arm/v6 respectively, in OCI terms).

    apk keys are extracted from arch-specific locations (e.g., /usr/share/apk/keys/s390x/*) and placed in the standard location (/etc/apk/keys/*).

    apko build and apko build-minirootfs both only produce a single arch's tarball, for the current runtime arch. If the image config specifies archs in this case, a warning is logged to avoid confusion.

    opened by imjasonh 11
  • apko docker image entrypoint is maybe a little weird?

    apko docker image entrypoint is maybe a little weird?

    While working on GitHub actions integration for a demo, I noticed:

    localhost:~/actions/apko-build$ docker run ghcr.io/chainguard-dev/apko:v0.1 
    Error: unknown command "/bin/sh" for "apko"
    Run 'apko --help' for usage.
    2022/02/28 23:03:27 error during command execution: unknown command "/bin/sh" for "apko"
    

    @cpanato @mattmoor what do you think? are we missing something with ko?

    opened by kaniini 11
  • Discussion: Pinning Versions

    Discussion: Pinning Versions

    Right now apko installs the latest version of each package in the config file. This means that every time a build is done, the latest version of each package is used. Updates happen implicitly.

    This approach has a few tradeoffs:

    • Fast updates are great for picking up security fixes in a timely manner
    • Are simple to operate and do in apko

    But they:

    • can make post-hoc analysis (SBOMs) more difficult
    • introduce another attack vector: a compromised distro has RCE on your system

    This issue is to discuss whether the ability to pin versions is useful, and how it should be implemented!

    Hand-wavy Idea

    Somehow persist each independent package version ~forever. I think SLSA has a recommendation for storage lifecycle.

    Use a TUF-stye snapshot role to generate up to date indexes of "latest versions".

    Allow specific version pinning in an "apko.lock" style file, while still allowing users to specify just "latest". We shouldn't need any real constraint handling or SAT solving, the two choices are just a specific version or latest.

    Have a simple command to update a lock file, and throw that into Dependabot or similar to update very day.

    I have no idea what this would look like in apk2 or 3 though so I'm probably missing something.

    Other Considerations

    I'm not certain whether the alpine repositories persist old versions of packages. We'd need to keep them around somewhere to make this work.

    faq 
    opened by dlorenc 8
  • feat: make image generation deterministic by default

    feat: make image generation deterministic by default

    This PR makes image generation deterministic by default:

    • timestamps are zeroed out for reproducibility (see https://github.com/chainguard-dev/apko/issues/48)
    • apk is writing a tar archive to lib/apk/db/scripts.tar, to support reproducible builds the timestamps inside the archive needs to be deterministic/zeroed.

    Note: according to the spec of SOURCE_DATE_EPOCH (https://reproducible-builds.org/specs/source-date-epoch/):

    Build processes MUST use this variable for embedded timestamps in place of the "current" date and time.

    Since time.Now has been replaced with the zero value (January 1, year 1, 00:00:00.000000000 UTC) there's no need for SOURCE_DATE_EPOCH.

    Note: reproducible image generation has been tested with https://diffoscope.org/

    Closes https://github.com/chainguard-dev/apko/issues/48

    cc @imjasonh

    opened by kruskall 7
  • Add task to support running `apko` builds via Tekton.

    Add task to support running `apko` builds via Tekton.

    To build/install the task definition (w/ apko) you can run:

    KO_DOCKER_REPO=ghcr.io/mattmoor ko apply -Bf config/
    

    This task definition implements the interface defined in github.com/mattmoor/mink to support uploading local source and directing where to publish images (so it can be used with mink apply as well).

    You can invoke this task imperatively with the following mink command:

    $ mink run task apko --as=apko -- --path=./examples/nginx.yaml
    
    2022/02/19 19:21:58 building image 'gcr.io/mattmoor-chainguard/images' from config file './examples/nginx.yaml'
    2022/02/19 19:21:58 build context:
    2022/02/19 19:21:58   image configuration: {{[https://dl-cdn.alpinelinux.org/alpine/edge/main] [/etc/apk/keys/[email protected] /etc/apk/keys/[email protected] /etc/apk/keys/[email protected] /etc/apk/keys/[email protected] /etc/apk/keys/[email protected]] [alpine-baselayout nginx]} {service-bundle  map[nginx:/usr/sbin/nginx -c /etc/nginx/nginx.conf -g "daemon off;"]}}
    2022/02/19 19:21:58   working directory: /tmp/apko-2587090319
    2022/02/19 19:21:58   tarball path:
    2022/02/19 19:21:58 doing pre-flight checks
    2022/02/19 19:21:58 building image fileystem in /tmp/apko-2587090319
    2022/02/19 19:21:58 initializing apk database
    2022/02/19 19:21:58 running: /sbin/apk add --initdb --root /tmp/apko-2587090319
    2022/02/19 19:21:58 [apk] OK: 0 MiB in 0 packages
    2022/02/19 19:21:58 initializing apk keyring
    2022/02/19 19:21:58 installing key /etc/apk/keys/[email protected]
    2022/02/19 19:21:58 installing key /etc/apk/keys/[email protected]
    2022/02/19 19:21:58 installing key /etc/apk/keys/[email protected]
    2022/02/19 19:21:58 installing key /etc/apk/keys/[email protected]
    2022/02/19 19:21:58 installing key /etc/apk/keys/[email protected]
    2022/02/19 19:21:58 initializing apk repositories
    2022/02/19 19:21:58 initializing apk world
    2022/02/19 19:21:58 synchronizing with desired apk world
    2022/02/19 19:21:58 running: /sbin/apk fix --root /tmp/apko-2587090319 --no-cache --update-cache
    2022/02/19 19:21:58 [apk] fetch https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz
    (1/12) Installing musl (1.2.2-r7)
    (2/12) Installing busybox (1.35.0-r2)
    Executing busybox-1.35.0-r2.post-install
    (3/12) Installing alpine-baselayout (3.2.0-r19)
    Executing alpine-baselayout-3.2.0-r19.pre-install
    Executing alpine-baselayout-3.2.0-r19.post-install
    (4/12) Installing libcrypto1.1 (1.1.1m-r2)
    (5/12) Installing pcre (8.45-r2)
    (6/12) Installing libssl1.1 (1.1.1m-r2)
    (7/12) Installing zlib (1.2.11-r3)
    (8/12) Installing nginx (1.20.2-r0)
    Executing nginx-1.20.2-r0.pre-install
    Executing nginx-1.20.2-r0.post-install
    (9/12) Installing skalibs (2.11.1.0-r0)
    (10/12) Installing s6-ipcserver (2.11.0.1-r0)
    (11/12) Installing execline (2.8.2.0-r0)
    (12/12) Installing s6 (2.11.0.1-r0)
    Executing s6-2.11.0.1-r0.pre-install
    Executing busybox-1.35.0-r2.trigger
    OK: 8 MiB in 12 packages
    2022/02/19 19:21:58 generating supervision tree
    2022/02/19 19:21:58 simple service: nginx => /usr/sbin/nginx -c /etc/nginx/nginx.conf -g "daemon off;"
    2022/02/19 19:21:58   supervision dir: /tmp/apko-2587090319/sv/nginx
    2022/02/19 19:21:58 finished building filesystem in /tmp/apko-2587090319
    2022/02/19 19:21:59 built image layer tarball as /tmp/apko-1984638129.tar.gz
    2022/02/19 19:21:59 building OCI image 'gcr.io/mattmoor-chainguard/images' from layer '/tmp/apko-1984638129.tar.gz'
    2022/02/19 19:21:59 OCI layer digest: sha256:5b6a06005c97c31df81455008c3c92078a50c8b07bc394a98c2519f2945c47ff
    2022/02/19 19:21:59 OCI layer diffID: sha256:775a08d0e0b33a95dff11e6ffe1511605e9e6ef2646ab39353deeb3344b75577
    2022/02/19 19:21:59 output OCI image file to foo.tar.gz
    
    2022/02/19 19:22:02 pushed blob: sha256:3ed57839e782bc6b1c084f25433ef6d92647ec9906070d2ecc48ec31cfa84650
    2022/02/19 19:22:02 pushed blob: sha256:5b6a06005c97c31df81455008c3c92078a50c8b07bc394a98c2519f2945c47ff
    2022/02/19 19:22:03 gcr.io/mattmoor-chainguard/images: digest: sha256:a2fdd03e2be33056b469fe472917e1c2d19670de04da7963e566cd078771c02e size: 427
    
    gcr.io/mattmoor-chainguard/[email protected]:a2fdd03e2be33056b469fe472917e1c2d19670de04da7963e566cd078771c02e
    
    opened by mattmoor 7
  • Set up some actions for presubmit validation

    Set up some actions for presubmit validation

    We have loads of these in our mono repo, and many of these are based on workflows we've forked repeatedly over the years.

    I'm tempted to set up chainguard-dev/actions where we can stuff reusable workflows with workflow_call that we can recycle across our various repos over time.

    cc @n3wscott @k4leung4

    opened by mattmoor 7
  • Build multiarch images concurrently

    Build multiarch images concurrently

    This makes a no-op multiarch apko publish go from ~17s to ~5s, at the cost of more confusing interleaved logs (example)

    Other than that, things seem to have worked just fine. 🎉 The bug described in #56 seems to have been just improper isolation of build contexts, which is solved here with a DeepCopy.

    If we want to make the logs better we could either keep them interleaved with some log prefix, or better yet buffer them and make sure they all get logged together at once. I'm happy to go either way here, or punt to later if this seems okay as is.

    Fixes #76

    opened by imjasonh 6
  • WIP support for multi-layered images.

    WIP support for multi-layered images.

    Signed-off-by: Erik Sipsma [email protected]

    WIP fix to #66

    The code already technically works when using the build command for simple cases, try it out with apko build --multilayer test.yaml test output.tar using this test.yaml for instance:

    contents:
      repositories:
        - https://dl-cdn.alpinelinux.org/alpine/edge/main
      packages:
        - alpine-baselayout
        - curl
        - rsync
        - coreutils
    

    On running docker load <output.tar you'll see multiple layers loaded, 1 for each package in the DAG.

    However, still big caveats:

    1. Walking the package DAG has some hacks which probably don't always work, need guidance on how to deal with corner cases there
    2. Doesn't support supervision tree, custom keyfiles, sboms, etc.
    3. Just uses downloaded apks directly as layer tar.gzs, which does work but results in .PKGINFO and .SIGN.RSA* files sticking around in the exported image
    4. Doesn't support publish yet (this is probably easy though)
    5. Various other issues marked with TODO comments in the code

    @kaniini Opening as a draft so I can get guidance on some questions related to apk before cleaning up the rest. A few big ones:

    1. When there are multiple alternatives for a package, how do we disambiguate? i.e. I running apk info so:libudev.so.1 shows multiple implementations. Right now the code just picks the first package it finds, which feels likely to not always be correct? Obviously if the user specifically requests one version of the package, choose that one, but what about when the user doesn't request any one in particular? Is the default choice in the apk metadata somewhere?
    2. If the user provides multiple repositories, is it right to check each one for a requested package in order and use the package from the first repository its found in? Or is there some other logic that should be followed.
    3. Is there anything special about the apk keyring that would require special logic to use the keys to download the packages? Or is it just a matter of telling the Go http client to use them. I haven't actually looked into this yet, so apologies if it's a dumb question.

    There are some other TODOs in the apk DAG code too and I'm sure there's plenty of "unknown unknowns" I've overlooked too...

    Also, let me know if the package DAG parsing code would fit better upsteam in the the alpine/go package. Happy to put stuff there if you think it fits better.

    opened by sipsma 5
  • Is it OK to wrap apko?

    Is it OK to wrap apko?

    Is it considered a valid use case to integrate apko into a higher-level tool or toolchain? Or is it your preference that end-users always interact with apko directly (either in the terminal or by bespoke scripts).

    Early on, docker wrapped lxc. But we later discovered that the developers of lxc did not consider this a valid use case: it was important to them that lxc never be hidden from the end user. As a result interfaces broke often, unaddressed issues piled up, and generally everyone grew frustrated. Eventually we had to ditch lxc altogether and implement libcontainer, and later runc.

    What is your perspective on this? I think both answers are valid, it's just good to know in advance.

    Thanks!

    faq 
    opened by shykes 5
  • Fix image structure in apko SBOMs

    Fix image structure in apko SBOMs

    This PR implements proper image structure in the individual apko images. Both CycloneDX and SPDX have been updated to capture the structure of the images. The biggest change is when running apko publish:

    • When running apko publish and generating a Cyclonedx SBOM, the layer is now a subcomponent of a new image component.
    • When requesting an SPDX SBOM the image now has its own top level package and is related to the layer package.

    It is a big refactor as the SBOM generation is now done after publishing the images and the SBOM is now attached at the end of the publish function.

    Easiest to visualize it by looking at the sboms. This is before the change:

    image

    This is after the change:

    image

    There are other minor changes, each commit captures the changes as atomic as I could.

    Fixes https://github.com/chainguard-dev/apko/issues/225

    opened by puerco 0
  • Invalid SPDX liocense identifiers in APKINDEX lead to invalid SBOMs

    Invalid SPDX liocense identifiers in APKINDEX lead to invalid SBOMs

    It seems that some of the alpine packages have the license definition wrong in the APKINDEX database. Some are correct some not, for example musl-utils has an invalid identifier:

    C:Q16oHBreKeAw+6OgxrF8jsmLtrykk=
    P:musl-utils
    V:1.2.3-r0
    A:x86_64
    S:36786
    I:135168
    T:the musl c library (libc) implementation
    U:https://musl.libc.org/
    L:MIT BSD GPL2+
    o:musl
    m:Timo Teräs <[email protected]>
    t:1649396308
    c:ee13d43a53938d8a04ba787b9423f3270a3c14a7
    D:scanelf so:libc.musl-x86_64.so.1
    p:cmd:getconf=1.2.3-r0 cmd:getent=1.2.3-r0 cmd:iconv=1.2.3-r0 cmd:ldconfig=1.2.3-r0 cmd:ldd=1.2.3-r0
    

    To be a valid SPDX identifier the L field above should read something like L:MIT AND BSD AND GPL2+ . As we are lifting these verbatim into the apko SBOMs, the documents are not validating.

    We should add a check to the APK package to ensure we are getting valid identifiers before adding them to the SBOM.

    bug 
    opened by puerco 0
  • Improved apko development image

    Improved apko development image

    We need a decent apko container image for development and testing purposes. The apko-inception stuff worked well, but we need something that can just be pulled, is up-to-date and people can get going in a single command.

    This process is started at github.com/distroless/apko.

    enhancement 
    opened by amouat 0
  • Take care of s6 directory creation

    Take care of s6 directory creation

    If it's being installed, we should make sure s6 can run without changes to the yaml. At the moment I'm getting:

    $ docker run ghcr.io/distroless/[email protected]:21b4eaf7e0dc0650d3f8372a9f49fe7eb767331ebd033a914848e43ef17e54c4
    s6-svscan: fatal: unable to mkdir .s6-svscan: Permission denied
    
    opened by amouat 6
  • macOS support

    macOS support

    A frequent request is to support macOS for composing images. apk-tools itself has been ported to macOS as part of apk-tools v3, so it should be possible to get an apk on mac once #234 is resolved.

    However, we need to have an answer for the /bin/busybox --install -s step that gets done in the image. That is the other main blocker for getting image composition running on macOS.

    opened by kaniini 1
Releases(v0.4.0)
Owner
Chainguard
Making the software supply chain secure by default.
Chainguard
APKrash is an Android APK security analysis toolkit focused on comparing APKs to detect tampering and repackaging.

APKrash APKrash is an Android APK security analysis toolkit focused on comparing APKs to detect tampering and repackaging. Features Able to analyze pu

Henrique Goncalves 11 Jul 1, 2022
RancherOS v2 is an immutable Linux distribution built to run Rancher and it's corresponding Kubernetes distributions RKE2 and k3s

RancherOS v2 is an immutable Linux distribution built to run Rancher and it's corresponding Kubernetes distributions RKE2 and k3s. It is built using the cOS-toolkit and based on openSUSE

Rancher Sandbox 33 Jun 22, 2022
An image server which automatically optimize non webp and avif images to webp and avif images

go-imageserver go-imageserver is an image server which automatically optimize no

DeltaLaboratory 4 Apr 18, 2022
Boxygen is a container as code framework that allows you to build container images from code

Boxygen is a container as code framework that allows you to build container images from code, allowing integration of container image builds into other tooling such as servers or CLI tooling.

nitric 5 Dec 13, 2021
Woodpecker CI plugin to build multiarch Docker images with buildx

plugin-docker-buildx Woodpecker CI plugin to build multiarch Docker images with buildx Woodpecker CI plugin to build multiarch Docker images with buil

Woodpecker CI 2 Apr 25, 2022
crud is a cobra based CLI utility which helps in scaffolding a simple go based micro-service along with build scripts, api documentation, micro-service documentation and k8s deployment manifests

crud crud is a CLI utility which helps in scaffolding a simple go based micro-service along with build scripts, api documentation, micro-service docum

Piyush Jajoo 0 Nov 29, 2021
CLI based tools to find the secrets in docker Images

docker-secrets CLI based tools to find the secrets in docker Images This tool use detect-secrets to find the secrets in the docker Image file system P

joshua_jebaraj 2 Mar 22, 2022
Explore Docker registries and manipulate Docker images!

L/S tags Utility and API to manipulate (analyze, synchronize and aggregate) images across different Docker registries. Example invocation $ lstags alp

Ivan Ilves 288 Jun 15, 2022
Packer is a tool for creating identical machine images for multiple platforms from a single source configuration.

Packer Website: https://www.packer.io IRC: #packer-tool on Freenode Mailing list: Google Groups Packer is a tool for building identical machine images

HashiCorp 13.8k Jun 30, 2022
k8s-image-swapper Mirror images into your own registry and swap image references automatically.

k8s-image-swapper Mirror images into your own registry and swap image references automatically. k8s-image-swapper is a mutating webhook for Kubernetes

Enrico Stahn 306 Jun 30, 2022
Vilicus is an open source tool that orchestrates security scans of container images(docker/oci) and centralizes all results into a database for further analysis and metrics.

Vilicus Table of Contents Overview How does it work? Architecture Development Run deployment manually Usage Example of analysis Overview Vilicus is an

Ederson Brilhante 77 Jun 21, 2022
:recycle: Now you can easily rollback to previous deployed images whatever you want on k8s environment

EasyRollback EasyRollback is aim to easy rollback to previous images that deployed on k8s environment Installation You should have go installation fir

Trendyol Open Source 92 May 4, 2022
A Simple and Comprehensive Vulnerability Scanner for Container Images, Git Repositories and Filesystems. Suitable for CI

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI. Table of Contents Abstract Features Installation

Aqua Security 12.6k Jun 26, 2022
A Kubernetes Mutating Webhook to automatically re-point pod images to mirrors

kubernetes-mimic Kubernetes Mimic is a Mutating Webhook that will watch for pod creation and update events in a Kubernetes cluster and automatically a

null 5 Dec 1, 2021
Kubei is a flexible Kubernetes runtime scanner, scanning images of worker and Kubernetes nodes providing accurate vulnerabilities assessment, for more information checkout:

Kubei is a vulnerabilities scanning and CIS Docker benchmark tool that allows users to get an accurate and immediate risk assessment of their kubernet

Portshift 663 Jun 27, 2022
Sign Container Images with cosign and Verify signature by using Open Policy Agent (OPA)

Sign Container Images with cosign and Verify signature by using Open Policy Agent (OPA) In the beginning, I believe it is worth saying that this proje

Batuhan Apaydın 58 May 28, 2022
ghcr images - Fetched from docker-library

ghcri ghcri is the repo for Github Container Registry Images. Just like docker-library for Docker Registry. Usage Replace all docker library from dock

null 15 Dec 2, 2021
Image clone controller is a kubernetes controller to safe guard against the risk of container images disappearing

Image clone controller image clone controller is a kubernetes controller to safe guard against the risk of container images disappearing from public r

Jayadeep KM 0 Oct 10, 2021
Stream, Mutate and Sign Images with AWS Lambda and ECR

ocistow About How it works Try it yourself Prerequisites CLI (cmd/ocistow) Lambda (cmd/ocistow-lambda) Deploy Invoke Verify signatures with =cosign= I

Martin Baillie 17 May 12, 2022