From e27e7635e15b28c1a6ce795b9c8b0698dfe9a084 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 28 Sep 2024 16:57:59 +0200 Subject: [PATCH] Build multi arch images --- .github/workflows/main.yml | 163 ++++++++++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 37 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7960d3b..1021dcd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,9 +7,25 @@ on: schedule: - cron: '0 0 * * 0' jobs: + supported-arch-matrix: + name: Supported processor architectures + runs-on: ubuntu-latest + needs: + - lint-dockerfile + outputs: + arch: ${{ steps.supported-arch-matrix.outputs.arch }} + steps: + - uses: actions/checkout@v4 + - id: supported-arch-matrix + name: Generate Arch + run: | + echo "arch=[\"linux/amd64\",\"linux/arm64\"]" >> $GITHUB_OUTPUT registry-matrix: name: Extract registries from registry secret mapping +# if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/master' runs-on: ubuntu-latest + needs: + - tests outputs: registry: ${{ steps.registry-matrix.outputs.registry }} steps: @@ -17,7 +33,7 @@ jobs: - id: registry-matrix name: Extract registries from registry secret mapping run: | - echo "::set-output name=registry::$(printenv DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING | jq -c 'keys')" + echo "registry=$(printenv DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING | jq -c 'keys')" >> $GITHUB_OUTPUT generate-image-strategy: name: Generate Image Strategy runs-on: ubuntu-latest @@ -30,10 +46,12 @@ jobs: run: | ls images | jq -csR '. + "random" | split("\n")' > images.list cat images.list - echo "::set-output name=images::$(cat images.list)" + echo "images=$(cat images.list)" >> $GITHUB_OUTPUT generate-rule-strategy: name: Generate Rules Strategy runs-on: ubuntu-latest + needs: + - scan-vulnerability outputs: rules: ${{ steps.generate-rule-strategy.outputs.rules }} steps: @@ -43,7 +61,7 @@ jobs: run: | ls tests/rules | jq -csR '. | rtrimstr("\n") | split("\n")' > rules.list cat rules.list - echo "::set-output name=rules::$(cat rules.list)" + echo "rules=$(cat rules.list)" >> $GITHUB_OUTPUT lint-dockerfile: name: Lint ${{ matrix.image }}'s Dockerfile needs: @@ -63,77 +81,117 @@ jobs: entrypoint: hadolint args: ./images/${{ matrix.image }}/Dockerfile build-docker-image: - name: Build ${{ matrix.image }} Docker + name: Build ${{ matrix.image }} Docker (${{ matrix.platform }}) strategy: fail-fast: false matrix: + platform: ${{ fromJson(needs.supported-arch-matrix.outputs.arch) }} image: ${{ fromJson(needs.generate-image-strategy.outputs.images) }} needs: + - supported-arch-matrix - generate-image-strategy - lint-dockerfile runs-on: ubuntu-latest steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - uses: actions/checkout@v4 - run: cp -R $(echo -e "./images/$(ls ./images/ | shuf -n 1)") ./images/random if: matrix.image == 'random' - - run: docker image build --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` --build-arg VCS_REF=`git rev-parse --short HEAD` -t "${DOCKER_IMAGE}:${{ matrix.image }}" --no-cache --build-arg VERSION=$TAG_VERSION ./images/${{ matrix.image }}/ - run: mkdir ./docker-image - - run: docker save "${DOCKER_IMAGE}:${{ matrix.image }}" -o ./docker-image/docker_image.tar - - uses: actions/upload-artifact@master + - run: docker image build --platform=${{ matrix.platform }} --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` --build-arg VCS_REF=`git rev-parse --short HEAD` -t "${DOCKER_IMAGE}:${{ matrix.image }}-${{ env.PLATFORM_PAIR }}" --no-cache --build-arg VERSION=$TAG_VERSION ./images/${{ matrix.image }}/ + - run: docker save "${DOCKER_IMAGE}:${{ matrix.image }}-${{ env.PLATFORM_PAIR }}" -o ./docker-image/docker_image-${{ env.PLATFORM_PAIR }}.tar +# - name: Build +# uses: docker/build-push-action@v6 +# with: +# context: ./images/${{ matrix.image }}/ +# tags: ${{ env.DOCKER_IMAGE }}:${{ matrix.image }} +# platforms: ${{ matrix.platform }} +# labels: ${{ steps.meta.outputs.labels }} +# outputs: type=tar,dest=./docker-image/docker_image-${{ env.PLATFORM_PAIR }}.tar +# cache-from: type=gha +# cache-to: type=gha,mode=max + - uses: actions/upload-artifact@v4 with: - name: docker-image-${{ matrix.image }} + name: docker-image-${{ matrix.image }}-${{ env.PLATFORM_PAIR }} path: ./docker-image scan-vulnerability: - name: Scan ${{ matrix.image }} for vulnerabilities + name: Scan ${{ matrix.image }} for vulnerabilities (${{ matrix.platform }}) strategy: fail-fast: false matrix: + platform: ${{ fromJson(needs.supported-arch-matrix.outputs.arch) }} image: ${{ fromJson(needs.generate-image-strategy.outputs.images) }} needs: + - supported-arch-matrix - generate-image-strategy - build-docker-image runs-on: ubuntu-latest steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - uses: actions/checkout@v4 - - uses: actions/download-artifact@master + - uses: actions/download-artifact@v4 with: - name: docker-image-${{ matrix.image }} - path: ./docker-image - - run: docker load --input ./docker-image/docker_image.tar - - run: rm -Rf ./docker-image/ - - run: echo -e "${DOCKER_IMAGE}:${{ matrix.image }}" | xargs -I % sh -c 'docker run -v /tmp/trivy:/var/lib/trivy -v /var/run/docker.sock:/var/run/docker.sock -t aquasec/trivy:latest --cache-dir /var/lib/trivy image --exit-code 1 --no-progress --format table %' + name: docker-image-${{ matrix.image }}-${{ env.PLATFORM_PAIR }} + path: /tmp/docker-image + - run: docker load --input /tmp/docker-image/docker_image-${{ env.PLATFORM_PAIR }}.tar + - run: rm -Rf /tmp/docker-image/ + - run: echo -e "${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-${{ env.PLATFORM_PAIR }}" | xargs -I % sh -c 'docker run -v /tmp/trivy:/var/lib/trivy -v /var/run/docker.sock:/var/run/docker.sock -t aquasec/trivy:latest --cache-dir /var/lib/trivy image --exit-code 1 --no-progress --format table %' tests: - name: Test ${{ matrix.image }} against ${{ matrix.rule }} + name: Test ${{ matrix.image }} against ${{ matrix.rule }} (${{ matrix.platform }}) needs: + - supported-arch-matrix - generate-image-strategy - generate-rule-strategy - scan-vulnerability strategy: fail-fast: false matrix: + platform: ${{ fromJson(needs.supported-arch-matrix.outputs.arch) }} image: ${{ fromJson(needs.generate-image-strategy.outputs.images) }} rule: ${{ fromJson(needs.generate-rule-strategy.outputs.rules) }} runs-on: ubuntu-latest steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - uses: actions/checkout@v4 - - uses: actions/download-artifact@master + - uses: actions/download-artifact@v4 with: - name: docker-image-${{ matrix.image }} - path: ./docker-image - - run: docker load --input ./docker-image/docker_image.tar - - name: Start image ${{ matrix.image }} - run: docker run -d --rm -v ${GITHUB_WORKSPACE}/${REDIRECT_CONFIG_FILE}:/etc/redirect/config.yaml ${DOCKER_IMAGE}:${{ matrix.image }} + name: docker-image-${{ matrix.image }}-${{ env.PLATFORM_PAIR }} + path: /tmp/docker-image + - run: docker load --input /tmp/docker-image/docker_image-${{ env.PLATFORM_PAIR }}.tar + - run: docker image ls -a + - name: Start image ${{ matrix.image }} (${{ matrix.platform }}) + run: docker run -d --platform=${{ matrix.platform }} --rm -v ${GITHUB_WORKSPACE}/${REDIRECT_CONFIG_FILE}:/etc/redirect/config.yaml ${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-${{ env.PLATFORM_PAIR }} env: IMAGE: ${{ steps.build.outputs.tag }} REDIRECT_CONFIG_FILE: tests/rules/${{ matrix.rule }}/config.yaml - name: Get running image ID id: ps - run: printf "::set-output name=id::%s" $(docker ps --format "{{.ID}}") + run: printf "id=%s" $(docker ps --format "{{.ID}}") >> $GITHUB_OUTPUT env: IMAGE: ${{ steps.build.outputs.tag }} - name: Get running image IP id: inspect - run: printf "::set-output name=ip::%s" $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${IMAGE_ID}) + run: printf "ip=%s" $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${IMAGE_ID}) >> $GITHUB_OUTPUT env: IMAGE_ID: ${{ steps.ps.outputs.id }} - name: Sleep 13 seconds before attempting to connect @@ -147,14 +205,14 @@ jobs: env: IMAGE_IP: ${{ steps.inspect.outputs.ip }} - name: Run unit tests ${{ matrix.rule }} against ${{ matrix.image }} - run: docker run -i loadimpact/k6 run -u 1000 -d 30s -e IMAGE_IP=${IMAGE_IP} -< ${SCRIPT_FILEIMAGE} + run: docker run -i loadimpact/k6 run -u 100 -d 30s -e IMAGE_IP=${IMAGE_IP} -< ${SCRIPT_FILEIMAGE} env: IMAGE: ${{ matrix.image }} IMAGE_IP: ${{ steps.inspect.outputs.ip }} IMAGE_ID: ${{ steps.ps.outputs.id }} SCRIPT_FILEIMAGE: ./tests/rules/${{ matrix.rule }}/unit.js - name: Run metrics tests ${{ matrix.rule }} against ${{ matrix.image }} - run: docker run -i loadimpact/k6 run -u 10 -d 10s -e IMAGE_IP=${IMAGE_IP} -< ${SCRIPT_FILEIMAGE} + run: docker run -i loadimpact/k6 run -u 1 -d 10s -e IMAGE_IP=${IMAGE_IP} -< ${SCRIPT_FILEIMAGE} env: IMAGE: ${{ matrix.image }} IMAGE_IP: ${{ steps.inspect.outputs.ip }} @@ -165,7 +223,7 @@ jobs: env: IMAGE_ID: ${{ steps.ps.outputs.id }} push-image: - if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/master' +# if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/master' name: Push ${{ matrix.image }} to ${{ matrix.registry }} strategy: fail-fast: false @@ -173,17 +231,47 @@ jobs: registry: ${{ fromJson(needs.registry-matrix.outputs.registry) }} image: ${{ fromJson(needs.generate-image-strategy.outputs.images) }} needs: + - supported-arch-matrix - generate-image-strategy - tests - registry-matrix runs-on: ubuntu-latest + services: + registry: + image: registry:2 + ports: + - 5000:5000 steps: - - uses: actions/download-artifact@master + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 with: - name: docker-image-${{ matrix.image }} - path: ./docker-image - - run: docker load --input ./docker-image/docker_image.tar - - run: rm -Rf ./docker-image/ + driver-opts: network=host + - uses: actions/download-artifact@v4 + with: + pattern: docker-image-${{ matrix.image }}-* + path: /tmp/docker-image + merge-multiple: true + - run: ls -lasth /tmp/docker-image/ + - run: | + for f in /tmp/docker-image/docker_image-*.tar; do + docker load --input $f + done + - run: rm -Rf /tmp/docker-image/ + - run: docker images + - run: | + archs=${{ join(fromJson(needs.supported-arch-matrix.outputs.arch), ',') }} + for arch in ${archs//,/ } + do + docker tag "${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-${arch//\//-}" "localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-${arch//\//-}" + docker push "localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-${arch//\//-}" + done +# docker tag ${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-amd64 localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-amd64 +# docker tag ${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-arm64 localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-arm64 +# docker push localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-amd64 +# docker push localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-linux-arm64 + - run: docker images - name: Login to ${{ matrix.registry }} run: | echo "${{ env.DOCKER_PASSWORD }}" | \ @@ -195,8 +283,9 @@ jobs: DOCKER_PASSWORD: ${{ secrets[fromJson(env.DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING)[matrix.registry]] }} - name: Docker info run: docker info - - run: docker tag ${DOCKER_IMAGE}:${{ matrix.image }} ${{ matrix.registry }}/${DOCKER_IMAGE}:${{ matrix.image }} - - name: Echo full tag - run: echo -e "${{ matrix.registry }}/${DOCKER_IMAGE}:${{ matrix.image }}" - - name: Push image to Docker Hub - run: docker push "${{ matrix.registry }}/${DOCKER_IMAGE}:${{ matrix.image }}" + - name: Create merge Dockerfile + run: echo "FROM localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }}-\${TARGETOS}-\${TARGETARCH}" >> docker-file-${{ matrix.registry }}-wyrihaximusnet-redirect-${{ matrix.image }} + - run: cat docker-file-${{ matrix.registry }}-wyrihaximusnet-redirect-${{ matrix.image }} + - name: Merged different arch imags into one + run: docker buildx build -f docker-file-${{ matrix.registry }}-wyrihaximusnet-redirect-${{ matrix.image }} --platform=${{ join(fromJson(needs.supported-arch-matrix.outputs.arch), ',') }} -t localhost:5000/${{ env.DOCKER_IMAGE }}:${{ matrix.image }} . --push +# run: docker buildx build -f docker-file-${{ matrix.registry }}-wyrihaximusnet-redirect-${{ matrix.image }} --platform=${{ join(fromJson(needs.supported-arch-matrix.outputs.arch), ',') }} -t ${{ matrix.registry }}/${{ env.DOCKER_IMAGE }}:${{ matrix.image }} . --push