A Concourse task for building OCI
images. Currently uses
buildkit for building.
A stretch goal of this is to support running without privileged: true, though
it currently still requires it.
The task implementation is available as an image on Docker Hub at
vito/oci-build-task. (This
image is built from Dockerfile using the oci-build task
itself.)
This task implementation started as a spike to explore patterns around reusable tasks to hopefully lead to a proper RFC. Until that RFC is written and implemented, configuration is still done by way of providing your own task config as follows:
First, your task needs to point to the oci-build-task image:
image_resource:
type: registry-image
source:
repository: vito/oci-build-taskNext, any of the following optional parameters may be specified:
-
$CONTEXT(default.): the path to the directory to provide as the context for the build. -
$DOCKERFILE(default$CONTEXT/Dockerfile): the path to theDockerfileto build. -
$BUILD_ARG_*: params prefixed withBUILD_ARG_will be provided as build args. For exampleBUILD_ARG_foo=bar, will set thefoobuild arg asbar. -
$BUILD_ARGS_FILE(default empty): path to a file containing build args in the formfoo=bar, one per line. Empty lines are skipped.Example file contents:
[email protected] HOW_MANY_THINGS=1 DO_THING=false -
$TARGET(default empty): a target build stage to build. -
$TARGET_FILE(default empty): path to a file containing the name of the target build stage to build. -
$UNPACK_ROOTFS(defaultfalse): unpack the image as Concourse's image format (rootfs/,metadata.json) for use with theimagetask step option.
Note: this is the main pain point with reusable tasks - env vars are kind of an awkward way to configure a task. Once the RFC lands these will turn into a JSON structure similar to configuring
paramson a resource, and task params will becomeenvinstead.
There are no required inputs - your task should just list each artifact it
needs as an input. Typically this is in close correlation with $CONTEXT:
params:
CONTEXT: my-image
inputs:
- name: my-imageShould your build be dependent on multiple inputs, you may want to leave
$CONTEXT as its default (.) and set an explicit path to the $DOCKERFILE:
params:
DOCKERFILE: my-repo/Dockerfile
inputs:
- name: my-repo
- name: some-dependencyIt might also make sense to place one input under another, like so:
params:
CONTEXT: my-repo
inputs:
- name: my-repo
- name: some-dependency
path: my-repo/some-dependencyOr, to fully rely on the default behavior and use path to wire up the context
accordingly, you could set your primary context as path: . and set up any
additional inputs underneath:
inputs:
- name: my-repo
path: .
- name: some-dependencyA single output named image may be configured:
outputs:
- name: imageThe output will contain the following files:
-
image.tar: the OCI image tarball. This tarball can be uploaded to a registry using the Registry Image resource. -
digest: the digest of the OCI config. This file can be used to tag the image after it has been loaded withdocker load, like so:docker load -i image/image.tar docker tag $(cat image/digest) my-name
If $UNPACK_ROOTFS is configured, the following additional entries will be
created:
-
rootfs/*: the unpacked contents of the image's filesystem. -
metadata.json: a JSON file containing the image's env and user configuration.
This is a Concourse-specific format to support using the newly built image for
a subsequent task by pointing the task step's image
option to the output,
like so:
plan:
- task: build-image
output_mapping: {image: my-built-image}
- task: use-image
image: my-built-image(The output_mapping here is just for clarity; alternatively you could just
set image: image.)
Note: at some point Concourse will likely standardize on OCI instead.
Caching can be enabled by caching the cache path on the task:
caches:
- path: cacheYour task should run the build executable:
run:
path: buildThe docker-image resource was previously used for building and pushing a
Docker image to a registry in one fell swoop.
The oci-build task, in contrast, only supports building images - it does not
support pushing or even tagging the image. It can be used to build an image and
use it for a subsequent task image without pushing it to a registry, by
configuring $UNPACK_ROOTFS.
In order to push the newly built image, you can use a resource like the
registry-image
resource like so:
resources:
- get: my-image-src
type: git
source:
uri: https://github.com/...
- name: my-image
type: registry-image
source:
repository: my-user/my-repo
jobs:
- name: build-and-push
plan:
# fetch repository source (containing Dockerfile)
- get: my-image-src
# build using `oci-build` task
#
# note: this task config could be pushed into `my-image-src` and loaded using
# `file:` instead
- task: build
privileged: true
config:
platform: linux
image_resource:
type: registry-image
source:
repository: vito/oci-build-task
inputs:
- name: my-image-src
path: .
outputs:
- name: image
run:
path: build
# push using `registry-image` resource
- put: my-image
params: {image: image/image.tar}The builder task was a stepping
stone that led to the oci-build task. It is now deprecated. The transition
should be relatively smooth, with the following differences:
- The
oci-buildtask does not support configuring$REPOSITORYor$TAG.- for running the image with
docker, adigestfile is provided which can be tagged withdocker tag - for pushing the image, the repository and tag are configured in the
registry-imageresource
- for running the image with
- The
oci-buildtask has a more efficient caching implementation. By usingbuildkitdirectly we can make use of itslocalcache exporter/importer, which doesn't require a separate translation step for saving into the task cache. - This task is written in Go instead of Bash, and has tests!
This repo contains an example.yml, which builds the image for the task
itself:
fly -t dev execute -c example.yml -o image=. -p
docker load -i image.tar