From 08e8edcb82e0b5585877f00a31cc413c04b1a9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nio=20Cardoso?= Date: Thu, 23 May 2024 21:36:17 -0300 Subject: [PATCH] .github: try parallel --- .github/workflows/deploy.yml | 242 ++++++++++++++++++++++------------- Dockerfile | 4 +- 2 files changed, 152 insertions(+), 94 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 46c79da..bf1317f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,136 +1,194 @@ name: Test, Build and Deploy Images env: + PROJECT: blueos + DOCKER: base DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + IMAGE_LIMIT_SIZE_MB: 600 on: - workflow_dispatch: - pull_request: - push: - schedule: + workflow_dispatch: + pull_request: + push: + schedule: # Run every 6 days to keep our caches alive - cron: '0 0 */6 * *' jobs: - deploy-docker-images: - runs-on: ubuntu-latest + build: + runs-on: ubuntu-22.04 + strategy: matrix: - docker: [base] - project: [companion] - new_project: [blueos] - platforms: ["linux/arm/v7,linux/arm/v8,linux/amd64"] + platform: + # - linux/arm/v7 + # - linux/arm64 + - linux/amd64 + steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Prepare id: prepare run: | - # Deploy image with the name of the branch, if the build is a git tag, replace tag with the tag name. - # If git tag matches semver, append latest tag to the push. - DOCKER_IMAGE=${DOCKER_USERNAME:-bluerobotics}/${{ matrix.project }}-${{ matrix.docker }} - VERSION=${GITHUB_REF##*/} + echo "buildx_args=VUE_APP_GIT_DESCRIBE=$(git describe --long --always --dirty --all)" >> $GITHUB_OUTPUT - if [[ $GITHUB_REF == refs/tags/* ]]; then - VERSION=${GITHUB_REF#refs/tags/} - fi + echo "DOCKER_IMAGE=${DOCKER_USERNAME:-bluerobotics}/${PROJECT}-${DOCKER}" >> $GITHUB_ENV - TAGS="--tag ${DOCKER_IMAGE}:${VERSION}" - if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - TAGS="$TAGS --tag ${DOCKER_IMAGE}:latest" - fi + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_IMAGE }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} - # Add temporary tag for the new project name - TAGS="$TAGS --tag ${DOCKER_USERNAME:-bluerobotics}/${{ matrix.new_project }}-${{ matrix.docker }}:${VERSION}" - echo ::set-output name=docker_image::${DOCKER_IMAGE} - echo ::set-output name=version::${VERSION} - echo ::set-output name=buildx_args:: \ - --build-arg VUE_APP_GIT_DESCRIBE=$(git describe --long --always --dirty --all) \ - --cache-from "type=local,src=/tmp/.buildx-cache" \ - --cache-to "type=local,dest=/tmp/.buildx-cache" \ - ${TAGS} \ - --file Dockerfile . - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 with: version: latest - - name: Cache Docker layers - uses: actions/cache@v2 + - name: Cache APT + uses: actions/cache@v4 id: cache with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ matrix.docker }}-${{ hashFiles('Dockerfile') }} - restore-keys: | - ${{ runner.os }}-buildx-${{ matrix.docker }}-${{ hashFiles('Dockerfile') }} - ${{ runner.os }}-buildx-${{ matrix.docker }} + path: | + var-cache-apt + var-lib-apt + key: ${{ matrix.platform }}-cache-apt-${{ hashFiles('Dockerfile') }} + restore-keys: ${{ matrix.platform }}-cache-apt- + + - name: Inject cache into Docker + uses: reproducible-containers/buildkit-cache-dance@v3 + with: + cache-map: | + { + "var-cache-apt": "/var/cache/apt", + "var-lib-apt": "/var/lib/apt" + } + skip-extraction: ${{ steps.cache.outputs.cache-hit }} + + - name: Login to DockerHub + if: success() && github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - - name: Docker Buildx (build) - run: | - # Pull latest version of image to help with build speed - IFS=',' read -ra platforms <<< "${{ matrix.platforms }}" - for platform in "${platforms[@]}"; do - docker pull --platform ${platform} ${DOCKER_USERNAME:-bluerobotics}/${{ matrix.project }}-${{ matrix.docker }}:master || true - done - docker buildx build \ - --output "type=image,push=false" \ - --platform ${{ matrix.platforms }} \ - ${{ steps.prepare.outputs.buildx_args }} + - name: Build and push by digest + id: build + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + push: ${{ github.event_name != 'pull_request' }} + # outputs: type=image,name=${{ env.DOCKER_IMAGE }},push-by-digest=true,name-canonical=true + outputs: type=image,name=${{ env.DOCKER_IMAGE }},push-by-digest=true + #outputs: type=image,name=${{ env.DOCKER_IMAGE }} + build-args: ${{ steps.prepare.outputs.buildx_args }} + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max - name: Check size run: | - # Check if the image size is lower than our limit docker image list - IMAGE_ID=$(docker images -q ${DOCKER_USERNAME:-bluerobotics}/${{ matrix.project }} | head -n 1) - LIMIT_SIZE_MB=600 - IMAGE_SIZE_MB=$(( $(docker inspect $IMAGE_ID --format {{.Size}})/(2**20) )) - echo "Core size is: $IMAGE_SIZE_MB MB" - ((IMAGE_SIZE_MB < LIMIT_SIZE_MB)) + IMAGE_SIZE_MB=$(du -sm ${{ steps.build.outputs.digest }} | cut -f1) + echo "Core size is: ${IMAGE_SIZE_MB} MB" + echo "Core size limit: ${IMAGE_LIMIT_SIZE_MB} MB" + if (( IMAGE_SIZE_MB >= IMAGE_LIMIT_SIZE_MB )); then + echo "Image size is larger than the limit" + exit 1 + fi + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # - name: Create image artifact + # # We are serializing each export here because "Currently, multi-platform images cannot be + # # exported with the docker export type." (https://docs.docker.com/engine/reference/commandline/buildx_build/#output) + # run: | + # DOCKER_IMAGE=${DOCKER_USERNAME:-bluerobotics}/${PROJECT}-${DOCKER}} + # GIT_HASH_SHORT=$(git rev-parse --short "$GITHUB_SHA") + # IFS=',' read -ra platforms <<< "${{ matrix.platform }}" + # for platform in "${platforms[@]}"; do + # docker buildx build \ + # --platform $platform \ + # ${{ steps.prepare.outputs.buildx_args }} \ + # --tag ${DOCKER_IMAGE}:${GIT_HASH_SHORT} \ + # --output "type=docker,dest=BlueOS-base-${GIT_HASH_SHORT}.tar" + # done + + # - name: Upload artifact + # uses: actions/upload-artifact@v4 + # with: + # name: BlueOS-base-docker-image.zip + # path: '*.tar' + + merge: + runs-on: ubuntu-22.04 + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - if: success() && github.event_name != 'pull_request' - uses: crazy-max/ghaction-docker-login@v1 + - name: Prepare + id: prepare + run: | + echo "DOCKER_IMAGE=${DOCKER_USERNAME:-bluerobotics}/${PROJECT}-${DOCKER}" >> $GITHUB_ENV + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_IMAGE }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Docker Buildx (push) - if: success() && github.event_name != 'pull_request' + + - name: Create manifest list and push + working-directory: /tmp/digests run: | - docker buildx build \ - --output "type=image,push=true" \ - --platform ${{ matrix.platforms }} \ - ${{ steps.prepare.outputs.buildx_args }} - + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKER_IMAGE }}@sha256:%s ' *) + - name: Inspect image - if: always() && github.event_name != 'pull_request' run: | - docker buildx imagetools \ - inspect ${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.version }} + docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} - - name: Create image artifact - # We are serializing each export here because "Currently, multi-platform images cannot be - # exported with the docker export type." (https://docs.docker.com/engine/reference/commandline/buildx_build/#output) - run: | - DOCKER_IMAGE=${DOCKER_USERNAME:-bluerobotics}/${{ matrix.project }}-${{ matrix.docker }} - GIT_HASH_SHORT=$(git rev-parse --short "$GITHUB_SHA") - IFS=',' read -ra platforms <<< "${{ matrix.platforms }}" - for platform in "${platforms[@]}"; do - docker buildx build \ - --platform $platform \ - ${{ steps.prepare.outputs.buildx_args }} \ - --tag ${DOCKER_IMAGE}:${GIT_HASH_SHORT} \ - --output "type=docker,dest=BlueOS-base-${GIT_HASH_SHORT}.tar" - done - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: BlueOS-base-docker-image.zip - path: '*.tar' \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e5ceff5..15e607a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ FROM python:3.11.7-slim-bullseye AS build_gstreamer RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ rm -f /etc/apt/apt.conf.d/docker-clean && \ - echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache && \ + echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache # Install and setup apt-fast RUN apt-get update \ @@ -256,7 +256,7 @@ RUN echo "deb http://deb.debian.org/debian bullseye-backports main contrib non-f RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ rm -f /etc/apt/apt.conf.d/docker-clean && \ - echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache && \ + echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache # Install and setup apt-fast RUN apt-get update \