From 641ef039f3ae33b24b83ad8090f86bd1de6ace89 Mon Sep 17 00:00:00 2001 From: Marc Sune Date: Tue, 31 Dec 2024 13:38:17 +0100 Subject: [PATCH] ci: build and publish ARM64 images (experimental) This commit modifies the CI code (`ci.yaml`) to use the new docker build infrastructure (`Makefile`) in `docker/` to build linux/arm64 images in addition to linux/amd64. Several considerations: * The original step 3 is split in: - 3.1: where the basic (local) build for the host arch and the docker-compose smoke test is run. This is to mimic what a user would do locally. - 3.2: where the multi-platform images are built, smoke tested (host arch only and published. * Due to the limitations of `docker buildx` (see previous commit and `docker/README.md`), a temporary build docker registry is spawned as part of step 3.2. * docker image publishing is moved to step of 3.2 (`docker-build-test-publish`), which allows PRs to execute most of the sections of 3.1/3.2 and skip the publishing step only. ARM64 generation is slow. Building and - especially - pushing multi-platform images is much easier than _trying_ to do that across jobs. There isn't much to optimize on the ARM side of things (just a byproduct of cross-compiling). However, stage 3.2 could start in parallel with stage 1/2, but gate publishing to dockerhub until stage 1,2 and 3.1 have successfully completed (e.g. using artifacts to pass status). This is out of scope of this commit. Signed-off-by: Marc Sune --- .github/workflows/ci.yaml | 130 +++++++++++++++---------------- ci/smoke-test/docker-compose.yml | 16 ++-- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 433816b07..2ab00259b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -107,40 +107,21 @@ jobs: docker exec -i $CONTAINER_ID ./ci/script.sh docker stop $CONTAINER_ID - ### Step 3: official docker image generation - pmacct-docker: + ### Step 3.1: test that local single-platform builds work fine + docker-build-test-local: runs-on: ubuntu-22.04 steps: - name: Checkout pmacct - uses: actions/checkout@v4 + uses: actions/checkout@v1 #Don't use v2 messes everything with: path: pmacct - fetch-depth: 0 - fetch-tags: 1 - - name: Check DAEMONS env. variable... + - name: Build single-platform run: | - #Sanity, avoid regression #816 - N_DAEMONS="$(echo $DAEMONS | wc --words)" - if [[ "${N_DAEMONS}" != "7" ]]; then - echo "ERROR: invalid number of DAEMONS: ${N_DAEMONS}" - exit 1 - fi - - - name: Build containers - uses: ./pmacct/.github/actions/build_containers/ - with: - daemons: ${{env.DAEMONS}} - - - name: Docker save images - run: | - echo "Saving images as artifacts..." - mkdir -p /tmp/docker/ - docker save -o /tmp/docker/pmacct_docker_images.tar base:_build $(for DAEMON in ${DAEMONS};do echo "${DAEMON}:_build "; done) + cd docker && V=1 make - name: Docker (compose) smoke test run: | - cd pmacct echo "Running smoke test using docker compose..." TAG=_build docker compose -f ci/smoke-test/docker-compose.yml up -d sleep 10 @@ -151,51 +132,31 @@ jobs: echo "Stopping containers..." TAG=_build docker compose -f ci/smoke-test/docker-compose.yml down - - name: Export pmacct docker images as an artifact - uses: actions/upload-artifact@v4 - with: - name: pmacct_docker_images - retention-days: 1 - path: /tmp/docker - - ### Step 4: Upload images to dockerhub (bleeding-edge, latest and releases) - publish-dockerhub: - needs: [pmacct-docker, build-and-test] + ### Step 3.2: Build test and publish (bleeding-edge, latest and releases) + docker-multiplatform-build-test-publish: runs-on: ubuntu-22.04 - if: github.event_name != 'pull_request' && vars.SKIP_DOCKERHUB_PUBLISH != 'true' + needs: [build-and-test, docker-build-test-local] env: - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + PLATFORMS: linux/amd64,linux/arm64 steps: - - uses: actions/download-artifact@v4 - with: - name: pmacct_docker_images - path: /tmp/docker - - - name: Import pmacct docker images in the local registry - run: | - docker load -i /tmp/docker/pmacct_docker_images.tar - - name: Checkout pmacct uses: actions/checkout@v1 #Don't use v2 messes everything with: path: pmacct - - name: Build and upload containers + - name: Deduce PMACCT version and tags run: | echo "Fix mess with tags in actions/checkout..." git fetch -f && git fetch -f --tags echo "Deducing PMACCT_VERSION..." PMACCT_VERSION=$(git describe --abbrev=0 --match="v*") - echo "PMACCT_VERSION=$PMACCT_VERSION" - echo "Uploading to dockerhub ..."; - echo ${DOCKER_PASSWORD} | docker login -u ${DOCKER_USERNAME} --password-stdin; #Always push bleeding-edge when pushed to master GIT_IS_BLEEDING_EDGE=$( (git branch --all --contains HEAD | grep master ) || echo "") echo "GIT_IS_BLEEDING_EDGE=$GIT_IS_BLEEDING_EDGE" if [ "$GIT_IS_BLEEDING_EDGE" != "" ]; then echo "Tagging and uploading 'bleeding-edge'..." + TAGS="$TAGS bleeding-edge" else echo "NOT uploading 'bleeding-edge'... Not HEAD of master" fi @@ -205,12 +166,14 @@ jobs: if [ "$GIT_RELEASE_TAG" != "" ]; then echo "GIT_RELEASE_TAG=$GIT_RELEASE_TAG" echo "Tagging and uploading release '$GIT_RELEASE_TAG'..." + TAGS="$TAGS $GIT_RELEASE_TAG" #Latest tag GIT_LAST_TAG=$(git tag --sort=v:refname | tail -n 1); echo "GIT_LAST_TAG=$GIT_LAST_TAG" if [ "$GIT_RELEASE_TAG" == "$GIT_LAST_TAG" ]; then echo "Tagging and uploading 'latest'..." + TAGS="$TAGS latest" else echo "NOT uploading 'latest'..." fi @@ -218,19 +181,54 @@ jobs: echo "NOT uploading '$GIT_RELEASE_TAG' nor 'latest'. Not a release!" fi - #Let's do it! - EXT_DAEMONS="base ${DAEMONS}" - for DAEMON in ${EXT_DAEMONS}; do - if [ "$GIT_IS_BLEEDING_EDGE" != "" ]; then - docker tag ${DAEMON}:_build ${DOCKER_USERNAME}/${DAEMON}:bleeding-edge; - docker push ${DOCKER_USERNAME}/${DAEMON}:bleeding-edge; - fi - if [ "$GIT_RELEASE_TAG" != "" ]; then - docker tag ${DAEMON}:_build ${DOCKER_USERNAME}/${DAEMON}:${PMACCT_VERSION}; - docker push ${DOCKER_USERNAME}/${DAEMON}:${PMACCT_VERSION}; - if [ "$GIT_RELEASE_TAG" == "$GIT_LAST_TAG" ]; then - docker tag ${DAEMON}:_build ${DOCKER_USERNAME}/${DAEMON}:latest; - docker push ${DOCKER_USERNAME}/${DAEMON}:latest; - fi - fi - done + #Summarize deduced tags + echo "Deduced tags: $TAGS" + echo "TAGS=$TAGS" >> $GITHUB_ENV + + - name: Get Runner's IP Address + run: | + RUNNER_IP=$(hostname -I | awk '{print $1}') + echo "RUNNER_IP=$RUNNER_IP" >> $GITHUB_ENV + echo "Deduced RUNNER_IP: $RUNNER_IP" + + - name: Spawn docker registry + run: | + echo "Instruct dockerd to trust $RUNNER_IP:5000 as an insecure registry..." + sudo mkdir -p /etc/docker + echo "{ + \"insecure-registries\": [\"http://$RUNNER_IP:5000\"] + }" | sudo tee /etc/docker/daemon.json > /dev/null + sudo systemctl restart docker + echo "Starting temporary docker registry..." + docker run -d -p 5000:5000 --name registry registry:2 + + - name: Build for platforms + run: | + echo "Building platforms: ${{ env.PLATFORMS }}..." + echo "Got tags from previous step: $TAGS" + cd docker && BUILD_REGISTRY=$RUNNER_IP:5000 PLATFORMS="${{env.PLATFORMS}}" V=1 make + + - name: Docker (compose) smoke test + run: | + echo "Running smoke test using docker compose..." + export DOCKER_OPTS="--insecure-registry $RUNNER_IP:5000" + TAG=_build REPO=$RUNNER_IP:5000/ docker compose -f ci/smoke-test/docker-compose.yml up -d + sleep 10 + echo "Check that all containers are up and running, without restarts ..." + if [[ "$(docker inspect `docker ps -aq` | grep RestartCount | grep -v '\"RestartCount\": 0')" != "" ]]; then + echo "Some containers restarted!" && docker inspect `docker ps -aq` && /bin/false + fi + echo "Stopping containers..." + TAG=_build docker compose -f ci/smoke-test/docker-compose.yml down + + - name: Tag and push to dockerhub + if: ${{ github.event_name != 'pull_request' && vars.SKIP_DOCKERHUB_PUBLISH != 'true' && env.TAGS != '' }} + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + echo "Logging in..."; + echo ${DOCKER_PASSWORD} | docker login -u ${DOCKER_USERNAME} --password-stdin + echo "Publishing platforms(archs): ${{ env.PLATFORMS }}..." + echo "Got tags from previous step: $TAGS" + cd docker && BUILD_REGISTRY=$RUNNER_IP:5000 PUSH=${{secrets.DOCKER_USERNAME}} TAGS="${TAGS}" PLATFORMS="${{env.PLATFORMS}}" V=1 make diff --git a/ci/smoke-test/docker-compose.yml b/ci/smoke-test/docker-compose.yml index 55c1b621a..90bcc4db0 100644 --- a/ci/smoke-test/docker-compose.yml +++ b/ci/smoke-test/docker-compose.yml @@ -1,44 +1,42 @@ -version: "3" - services: nfacctd: - image: nfacctd:${TAG} + image: ${REPO:-}nfacctd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure pmacctd: - image: pmacctd:${TAG} + image: ${REPO:-}pmacctd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure pmbgpd: - image: pmbgpd:${TAG} + image: ${REPO:-}pmbgpd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure pmbmpd: - image: pmbmpd:${TAG} + image: ${REPO:-}pmbmpd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure pmtelemetryd: - image: pmtelemetryd:${TAG} + image: ${REPO:-}pmtelemetryd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure sfacctd: - image: sfacctd:${TAG} + image: ${REPO:-}sfacctd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure uacctd: - image: uacctd:${TAG} + image: ${REPO:-}uacctd:${TAG} volumes: - ./etc/pmacct:/etc/pmacct restart: on-failure