[CI] rootless container images

Refs: https://codeberg.org/forgejo/forgejo/issues/25
This commit is contained in:
Loïc Dachary 2022-12-17 21:45:28 +01:00
parent abc3637d0d
commit f1f495381c
No known key found for this signature in database
GPG key ID: 992D23B392F9E4F2
5 changed files with 246 additions and 27 deletions

View file

@ -11,6 +11,13 @@ variables:
- &dind_image 'docker:20.10-dind' - &dind_image 'docker:20.10-dind'
- &buildx_image 'woodpeckerci/plugin-docker-buildx:2.0.0' - &buildx_image 'woodpeckerci/plugin-docker-buildx:2.0.0'
- &integration_image 'codeberg.org/forgejo-integration/forgejo' - &integration_image 'codeberg.org/forgejo-integration/forgejo'
- &dockerfile_root 'Dockerfile'
# - &dockerfile_root 'releases/Dockerfile'
- &dockerfile_rootless 'Dockerfile.rootless'
# - &dockerfile_rootless 'releases/Dockerfile-rootless'
- &verify 'true'
# - &verify 'false'
- &archs 'amd64 arm64'
pipeline: pipeline:
fetch-tags: fetch-tags:
@ -20,17 +27,37 @@ pipeline:
- git config --add safe.directory '*' - git config --add safe.directory '*'
- git fetch --tags --force - git fetch --tags --force
publish-integration: publish-root:
image: *buildx_image image: *buildx_image
group: integration
pull: true pull: true
settings: settings:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
dockerfile: *dockerfile_root
registry: registry:
from_secret: domain from_secret: domain
tag: ${CI_COMMIT_TAG##v} tag: ${CI_COMMIT_TAG##v}
repo: *integration_image repo: *integration_image
build_args: build_args:
- GOPROXY=https://proxy.golang.org,direct - GOPROXY=https://proxy.golang.org
password:
from_secret: releaseteamtoken
username:
from_secret: releaseteamuser
publish-rootless:
image: *buildx_image
group: integration
pull: true
settings:
platforms: linux/amd64,linux/arm64
dockerfile: *dockerfile_rootless
registry:
from_secret: domain
tag: ${CI_COMMIT_TAG##v}-rootless
repo: *integration_image
build_args:
- GOPROXY=https://proxy.golang.org
password: password:
from_secret: releaseteamtoken from_secret: releaseteamtoken
username: username:
@ -40,32 +67,10 @@ pipeline:
image: *dind_image image: *dind_image
environment: environment:
INTEGRATION_IMAGE: *integration_image INTEGRATION_IMAGE: *integration_image
VERIFY: *verify
ARCHS: *archs
commands: commands:
- apk --update --no-cache add coredns - ./releases/container-images-pull-verify-push.sh
- ( echo ".:53 {" ; echo " forward . /etc/resolv.conf"; echo "}" ) > /etc/coredns/Corefile
- coredns -conf /etc/coredns/Corefile &
- /usr/local/bin/dockerd --data-root /var/lib/docker --host=unix:///var/run/docker.sock --dns 172.17.0.3 &
- for i in $$(seq 60) ; do DOCKER_HOST=unix:///var/run/docker.sock docker version && break ; sleep 1 ; done
- tag=${CI_COMMIT_TAG##v}
- docker login -p "$RELEASETEAMTOKEN" -u "$RELEASETEAMUSER" $DOMAIN
- tagged_image=$${INTEGRATION_IMAGE}':'$$tag
- manifests=""
- for arch in arm64 amd64 ; do
- arch_image=${CI_REPO_LINK##https://}':'$$tag-$$arch
- docker pull --platform linux/$$arch $$tagged_image
- docker run --platform linux/$$arch --rm $$tagged_image gitea --version | grep 'built with'
- docker tag $$tagged_image $$arch_image
- docker push $$arch_image
- manifests="$$manifests $$arch_image"
- docker image prune --all --force
- done
- published=${CI_REPO_LINK##https://}':'$$tag
- docker manifest create $$published $$manifests
- docker manifest push $$published
- short_tag=$${tag%.*-*}
- short_published=${CI_REPO_LINK##https://}':'$$short_tag
- docker manifest create $$short_published $$manifests
- docker manifest push $$short_published
secrets: secrets:
- releaseteamtoken - releaseteamtoken
- releaseteamuser - releaseteamuser

View file

@ -0,0 +1,24 @@
platform: linux/amd64
branches:
includes: [ wip-ci-* ]
when:
event: push
variables:
- &dind_image 'docker:20.10-dind'
pipeline:
container-images-pull-verify-push:
image: *dind_image
commands:
# arm64 would require qemu-user-static which is not available on alpline
# the test coverage does not change much and running the tests test locally
# is possible if there is a doubt
- ARCHS=amd64 ./releases/container-images-pull-verify-push.sh test
- ./releases/container-images-pull-verify-push.sh test_teardown
secrets:
- releaseteamuser
- releaseteamtoken
- domain

3
releases/Dockerfile Normal file
View file

@ -0,0 +1,3 @@
FROM alpine:3.17
RUN echo root > state

View file

@ -0,0 +1,3 @@
FROM alpine:3.17
RUN echo rootless > state

View file

@ -0,0 +1,184 @@
#!/bin/sh
#
# Tests are run when on a wip-ci-* branch, see .woodpecker/releases-helper.yml
# It should be changed to run it every time this file is changed when 1.18 is used because 1.17 does not have
# webhooks with the information for that filtering.
#
set -ex
: ${DOCKER_HOST:=unix:///var/run/docker.sock}
: ${ARCHS:=amd64 arm64}
: ${INTEGRATION_USER:=forgejo-integration}
: ${INTEGRATION_IMAGE:=codeberg.org/$INTEGRATION_USER/forgejo}
: ${CI_REPO_OWNER:=dachary}
: ${CI_COMMIT_TAG:=v17.1.42-2}
: ${TAG:=${CI_COMMIT_TAG##v}}
: ${SHORT_TAG=${TAG%.*-*}}
: ${CI_REPO_LINK:=https://codeberg.org/dachary/forgejo}
: ${DOMAIN:=codeberg.org}
: ${VERIFY:=true}
VERIFY_COMMAND='gitea --version'
VERIFY_STRING='built with'
publish() {
for suffix in '' '-rootless' ; do
images=""
for arch in $ARCHS ; do
#
# Get the image from the integration user
#
image=$(image_name $INTEGRATION_USER $suffix)
docker pull --platform linux/$arch $image
#
# Verify it is usable
#
if $VERIFY ; then
docker run --platform linux/$arch --rm $image $VERIFY_COMMAND | grep "$VERIFY_STRING"
fi
#
# Push the image with a tag reflecting the architecture to the repo owner
#
arch_image=$(arch_image_name $CI_REPO_OWNER $arch $suffix)
docker tag $image $arch_image
docker push $arch_image
images="$images $arch_image"
done
#
# Push a manifest with all the architectures to the repo owner
#
manifest=$(image_name $CI_REPO_OWNER $suffix)
docker manifest rm $manifest || true
docker manifest create $manifest $images
image_put $CI_REPO_OWNER $(image_tag $suffix) $manifest
image_put $CI_REPO_OWNER $(short_image_tag $suffix) $manifest
#
# Sanity check to ensure the manifest that are published can actualy
# be used.
#
for arch in $ARCHS ; do
docker pull --platform linux/$arch $(image_name $CI_REPO_OWNER $suffix)
docker pull --platform linux/$arch $(short_image_name $CI_REPO_OWNER $suffix)
done
done
}
boot() {
if docker version ; then
return
fi
apk --update --no-cache add coredns jq curl
( echo ".:53 {" ; echo " forward . /etc/resolv.conf"; echo "}" ) > /etc/coredns/Corefile
coredns -conf /etc/coredns/Corefile &
/usr/local/bin/dockerd --data-root /var/lib/docker --host=$DOCKER_HOST --dns 172.17.0.3 &
for i in $(seq 60) ; do
docker version && break
sleep 1
done
docker version || exit 1
}
authenticate() {
echo "$RELEASETEAMTOKEN" | docker login --password-stdin --username "$RELEASETEAMUSER" $DOMAIN
token=$(curl -u$RELEASETEAMUSER:$RELEASETEAMTOKEN -sS https://$DOMAIN/v2/token | jq --raw-output .token)
}
image_delete() {
curl -sS -H "Authorization: token $token" -X DELETE https://$DOMAIN/v2/$1/forgejo/manifests/$2
}
image_put() {
docker manifest inspect $3 > /tmp/manifest.json
curl -sS -H "Authorization: token $token" -X PUT --data-binary @/tmp/manifest.json https://$DOMAIN/v2/$1/forgejo/manifests/$2
}
main() {
boot
authenticate
publish
}
image_name() {
echo $DOMAIN/$1/forgejo:$(image_tag $2)
}
image_tag() {
echo $TAG$1
}
short_image_name() {
echo $DOMAIN/$1/forgejo:$(short_image_tag $2)
}
short_image_tag() {
echo $SHORT_TAG$1
}
arch_image_name() {
echo $DOMAIN/$1/forgejo:$(arch_image_tag $2 $3)
}
arch_image_tag() {
echo $TAG-$1$2
}
#
# Create the same set of images that buildx would
#
test_setup() {
dir=$(dirname $0)
for suffix in '' '-rootless' ; do
(
cd $dir
manifests=""
for arch in $ARCHS ; do
image=$(arch_image_name $INTEGRATION_USER $arch $suffix)
docker build -f Dockerfile$suffix --platform linux/$arch -t $image .
docker push $image
images="$images $image"
done
manifest=$(image_name $INTEGRATION_USER $suffix)
docker manifest rm $manifest || true
docker manifest create $manifest $images
image_put $INTEGRATION_USER $(image_tag $suffix) $manifest
)
done
}
test_teardown() {
authenticate
for suffix in '' '-rootless' ; do
image_delete $INTEGRATION_USER $(image_tag $suffix)
image_delete $CI_REPO_OWNER $(image_tag $suffix)
image_delete $CI_REPO_OWNER $(short_image_tag $suffix)
for arch in $ARCHS ; do
image_delete $INTEGRATION_USER $(arch_image_tag $arch $suffix)
image_delete $CI_REPO_OWNER $(arch_image_tag $arch $suffix)
done
done
}
#
# Running the test locally instead of withing Woodpecker
#
# 1. Setup: obtain a token at https://codeberg.org/user/settings/applications
# 2. Run: RELEASETEAMUSER=<username> RELEASETEAMTOKEn=<apptoken> container-images-pull-verify-push.sh test
# 3. Verify: (optional) manual verification at https://codeberg.org/<username>/-/packages/container/forgejo/versions
# 4. Cleanup: RELEASETEAMUSER=<username> RELEASETEAMTOKEn=<apptoken> container-images-pull-verify-push.sh test_teardown
#
test() {
boot
test_teardown
test_setup
VERIFY_STRING=something
VERIFY_COMMAND="echo $VERIFY_STRING"
echo "================================ TEST BEGIN"
main
echo "================================ TEST END"
}
${@:-main}