Cappend is a tool for appending to a container. No frills, just tars.
Cappend is substantially faster than other container building techniques by optimizing for the subset of workflows that only add files or adjust image metadata.
Templated Example
The following demonstrates a moderately complex use of Cappend, but a simple example is also provided.
.gitlab-ci.yml
build:
stage: build
image: alpine
variables:
CEDARCI_SERVICE_CAPPEND: "true"
CONTAINER_TAG_BASE: "${CI_REGISTRY_IMAGE}/${CI_COMMIT_BRANCH}"
CONTAINER_TAG_SHA: "${CONTAINER_TAG_BASE}:${CI_COMMIT_SHA}"
CONTAINER_TAG_LATEST: "${CONTAINER_TAG_BASE}:latest"
script: |
# Language specific images likely come with these (or should build a container).
apk add docker-cli jq
# `target/release/app` will be `/app` within the container owned by root:root.
tar --numeric-owner --owner=0 --group=0 \
-cf app.tar \
-C target/release \
app
# Fill template variable values.
jq -n \
--arg CONTAINER_TAG_LATEST "${CONTAINER_TAG_LATEST}" \
--arg CONTAINER_TAG_SHA "${CONTAINER_TAG_SHA}" \
--from-file cappend.json > cappend.final.json
diff -u cappend.json cappend.final.json || true
# Any docker compatible auth config generation will do.
docker login \
-u ${CI_REGISTRY_USER} \
-p ${CI_REGISTRY_PASSWORD} \
${CI_REGISTRY} 2> /dev/null
# Build and push.
/cedarci/cappend cappend.final.json
cappend.json
It can be preferable to generate the JSON from your language of choice instead of the jq template shown below.
Path Transform
Paths can be transformed by tar to re-create ADD app.tar /path.
Adjusting the above example the file would end up as /usr/local/bin/app.
tar --numeric-owner --owner=0 --group=0 \
--transform 's,^,usr/local/bin/,' \
-C target/release \
app
To retain relative symlinks utilize [^.] to avoid rewriting them since they begin with ../.
--transform 's,^\([^.]\),opt/\1,'
Reference
The following is the complete set of supported options.
The Go Language Documentation mentioned above.