Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/apko_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ environment:
```

Running `apko build` on this file will produce a tar file containing an Alpine base container image.
The image can be used by container runtimes (for example, running `docker load image.tar` will add
The image can be used by container runtimes (for example, running `docker load < image.tar` will add
the image to Docker). The command `apko publish` can also be used to directly push the image to an
image registry.

Expand Down
40 changes: 18 additions & 22 deletions docs/build-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The entire build is configured from a declarative file `apko.yaml`, which does n
commands. Instead, all content is generated from installing `apk` packages.

The build process is driven by the implementation of the `apko build` command, specifically
[`BuildCmd()`](../internal/cli/build.go#L104).
[`BuildCmd()`](../internal/cli/build.go#L142).

The entire build process involves laying out the desired files in a temporary working directory, and then
packaging that working directory as an OCI filesystem layer `.tar.gz`. With that layer file in hand,
Expand All @@ -14,44 +14,40 @@ it can be packaged into an OCI image, and an SBoM can be created.
The process is as follows:

1. Create a temporary working directory.
1. Create a [`build.Context`](../pkg/build/build.go#L37-45). This `Context` contains:
* The path to the config file, default to `apko.yaml`
* The parsed config file into an internal structure [`ImageConfiguration`](../pkg/build/types/types.go#L55-83)
* The [`buildImplementation`](../pkg/build/build_implementation.go#L43-59), which is the engine responsible for executing the actual build
* The [`Executor`](../pkg/exec/exec.go#L26-31), which handles external command execution by the `buildImplementation`
2. Create a [`build.Context`](../pkg/build/build.go#L52-61). This `Context` contains:
* The parsed config file into an internal structure [`ImageConfiguration`](../pkg/build/types/types.go#L150-199)
* The [`s6.Context`](../pkg/s6/s6.go#L23-26), which contains configuration for optionally installing the s6 supervisor to manage the process in the container
* Build-time options
1. Refresh the `build.Context`, which sets initialization and runtime parameters, such as isolation, working directory, the executor and the s6 context.
1. Build the layer in the working directory, the heart of the build, calling [`build.Context.BuildLayer()`](../pkg/build/build.go#L80-109). This results in the entire laid out filesystem packaged up into a `.tar.gz` file. More detail on this follows later in this document.
1. Generate an SBoM.
1. Generate an OCI image tar file from the single layer `.tar.gz` file in [`oci.BuildImageTarballFromLayer()`](../pkg/build/oci/oci.go#L285).
3. Refresh the `build.Context`, which sets initialization and runtime parameters, such as isolation, working directory, the executor and the s6 context.
4. Build the layer in the working directory, the heart of the build, calling [`build.Context.BuildLayer()`](../pkg/build/build.go#L117-135). This results in the entire laid out filesystem packaged up into a `.tar.gz` file. More detail on this follows later in this document.
5. Generate an SBoM.
6. Generate an OCI image tar file from the single layer `.tar.gz` file in [`oci.BuildImageTarballFromLayer()`](../pkg/build/oci/image.go#L190).

## Layer Build

As described above, after everything is setup, the actual build occurs inside the working directory.
The build is in [`build.Context.BuildLayer()`](../pkg/build/build.go#L80-109), which consists of:
The build is in [`build.Context.BuildLayer()`](../pkg/build/build.go#L117-135), which consists of:

1. `Context.BuildImage()`: building the image
1. `Context.GenerateSBOM()` optionally generate the SBoM

The actual building of the image via `BuildImage()` just wraps [`buildImage()`](../pkg/build/build_implementation.go#L195-247).
The actual building of the image via `BuildImage()` just wraps [`buildImage()`](../pkg/build/build_implementation.go#L154-246).

It involves several steps:

1. Validate the image configuration. This includes setting defaults.
1. Initialize the apk. This involves setting up the various apk directories inside the working directory.
1. Add additional tags for apk packages.
1. `MutateAccounts()`: Create users and groups.
1. Set file and directory permissions.
1. Set the symlinks for busybox, as busybox is a single binary which determines what action to take based on the invoked path.
1. Update ldconfig.
1. Create the `/etc/os-release` file.
1. If s6 is used for supervision, install it and create its configuration files.
2. Initialize the apk. This involves setting up the various apk directories inside the working directory.
3. Add additional tags for apk packages.
4. `MutateAccounts()`: Create users and groups.
5. Set file and directory permissions.
6. Set the symlinks for busybox, as busybox is a single binary which determines what action to take based on the invoked path.
7. Update ldconfig.
8. Create the `/etc/os-release` file.
9. If s6 is used for supervision, install it and create its configuration files.

Note that all of the steps involve some file manipulation.

* In the case of simply laying out files or changing permissions, this is straightforward and performed in the working directory.
* In the case of apk commands, it uses the [pkg/apk/impl](../pkg/apk/impl/) implementation to lay out files directly.
* In the case of apk commands, it uses the [pkg/apk/apk/implementation](../pkg/apk/apk/implementation.go) implementation to lay out files directly.
* In the case of `chown`/`chmod`, if it cannot do so directly - either because the underlying filesystem does not support it or because it is not running as root - it ignores the errors and keeps track of the intended ownership and permissions, adding them to the final layer tar stream.
* In the case of `ldconfig`, it replicates the equivalent functionality by parsing the library ELF headers and creating the symlinks.
* In the case of `busybox`, it creates symlinks to the busybox binary, based on a fixed list.
Expand Down
2 changes: 1 addition & 1 deletion pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import (
)

// Context contains all of the information necessary to build an
// OCI image. Includes the configurationfor the build,
// OCI image. Includes the configuration for the build,
// the path to the config file, the executor for root jails and
// architecture emulation, the s6 supervisor to add to the image,
// build options, and the `buildImplementation`, which handles the actual build.
Expand Down