From 2786e5a1df4dbbe930d12ab1ad5ad9e1ab145438 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Fri, 6 Oct 2023 18:52:26 +0200 Subject: [PATCH] Update GitHub Actions Workflow - Updated workflow to use qemu and buildx bake In the future i would like to extract the alpine based binaries and add them as artifacts to the release. --- .github/workflows/build.yml | 19 ++-- .github/workflows/release.yml | 209 ++++++++++++---------------------- docker/Dockerfile.alpine | 4 +- docker/Dockerfile.debian | 28 +++-- docker/Dockerfile.j2 | 32 ++++-- docker/test.sh | 21 ++++ 6 files changed, 145 insertions(+), 168 deletions(-) create mode 100755 docker/test.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 382194657a..446b0fcef8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,7 +34,6 @@ jobs: # This is done globally to prevent rebuilds when the RUSTFLAGS env variable changes. env: RUSTFLAGS: "-D warnings" - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse strategy: fail-fast: false matrix: @@ -205,12 +204,12 @@ jobs: cargo build --release --features sqlite,mysql,postgresql # End Build the binary - - # Upload artifact to Github Actions - - name: "Upload artifact" - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - if: ${{ matrix.channel == 'rust-toolchain' }} - with: - name: vaultwarden - path: target/release/vaultwarden - # End Upload artifact to Github Actions + # TODO: We should not upload these. We should extract Alpine build binaries from the containers and upload them + # # Upload artifact to Github Actions + # - name: "Upload artifact" + # uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + # if: ${{ matrix.channel == 'rust-toolchain' }} + # with: + # name: vaultwarden + # path: target/release/vaultwarden + # # End Upload artifact to Github Actions diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4829be6f15..b54a20495d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,6 @@ on: - ".github/workflows/release.yml" - "src/**" - "migrations/**" - - "hooks/**" - "docker/**" - "Cargo.*" - "build.rs" @@ -15,6 +14,7 @@ on: branches: # Only on paths above - main + - release-build-revision tags: # Always, regardless of paths above - '*' @@ -25,7 +25,8 @@ jobs: # We will skip this check if we are creating a tag, because that has the same hash as a previous run already. skip_check: runs-on: ubuntu-22.04 - if: ${{ github.repository == 'dani-garcia/vaultwarden' }} + # if: ${{ github.repository == 'dani-garcia/vaultwarden' }} + if: ${{ github.repository == 'BlackDex/vaultwarden' }} outputs: should_skip: ${{ steps.skip_check.outputs.should_skip }} steps: @@ -35,23 +36,21 @@ jobs: with: cancel_others: 'true' # Only run this when not creating a tag - if: ${{ startsWith(github.ref, 'refs/heads/') }} + if: ${{ github.ref_type == 'branch' }} docker-build: runs-on: ubuntu-22.04 timeout-minutes: 120 needs: skip_check - # Start a local docker registry to be used to generate multi-arch images. - services: - registry: - image: registry:2 - ports: - - 5000:5000 + # if: ${{ needs.skip_check.outputs.should_skip != 'true' && github.repository == 'dani-garcia/vaultwarden' }} + if: ${{ needs.skip_check.outputs.should_skip != 'true' && github.repository == 'BlackDex/vaultwarden' }} + # TODO: Start a local docker registry to be used to extract the final Alpine static build images + # services: + # registry: + # image: registry:2 + # ports: + # - 5000:5000 env: - # Use BuildKit (https://docs.docker.com/build/buildkit/) for better - # build performance and the ability to copy extended file attributes - # (e.g., for executable capabilities) across build phases. - DOCKER_BUILDKIT: 1 SOURCE_COMMIT: ${{ github.sha }} SOURCE_REPOSITORY_URL: "https://github.com/${{ github.repository }}" # The *_REPO variables need to be configured as repository variables @@ -65,7 +64,6 @@ jobs: # QUAY_REPO needs to be 'quay.io//' # Check for Quay.io credentials in secrets HAVE_QUAY_LOGIN: ${{ vars.QUAY_REPO != '' && secrets.QUAY_USERNAME != '' && secrets.QUAY_TOKEN != '' }} - if: ${{ needs.skip_check.outputs.should_skip != 'true' && github.repository == 'dani-garcia/vaultwarden' }} strategy: matrix: base_image: ["debian","alpine"] @@ -77,18 +75,43 @@ jobs: with: fetch-depth: 0 - # Determine Docker Tag - - name: Init Variables - id: vars + - name: Initialze QEMU binfmt support + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + with: + platforms: "arm64,arm" + + # Start Docker Buildx + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + # https://github.com/moby/buildkit/issues/3969 + # Also set max parallelism to 2, the default of 4 breaks GitHub Actions + with: + config-inline: | + [worker.oci] + max-parallelism = 2 + driver-opts: | + network=host + + # Determine Base Tags and Source Version + - name: Determine Base Tags and Source Version shell: bash run: | - # Check which main tag we are going to build determined by github.ref - if [[ "${{ github.ref }}" == refs/tags/* ]]; then - echo "DOCKER_TAG=${GITHUB_REF#refs/*/}" | tee -a "${GITHUB_OUTPUT}" - elif [[ "${{ github.ref }}" == refs/heads/* ]]; then - echo "DOCKER_TAG=testing" | tee -a "${GITHUB_OUTPUT}" + # Check which main tag we are going to build determined by github.ref_type + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "BASE_TAGS=latest,${GITHUB_REF#refs/*/}" | tee -a "${GITHUB_ENV}" + elif [[ "${{ github.ref_type }}" == "branch" ]]; then + echo "BASE_TAGS=testing" | tee -a "${GITHUB_ENV}" + fi + + # Get the Source Version for this release + GIT_EXACT_TAG="$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || true)" + if [[ -n "${GIT_EXACT_TAG}" ]]; then + echo "SOURCE_VERSION=${GIT_EXACT_TAG}" | tee -a "${GITHUB_ENV}" + else + GIT_LAST_TAG="$(git describe --tags --abbrev=0)" + echo "SOURCE_VERSION=${GIT_LAST_TAG}-${SOURCE_COMMIT:0:8}" | tee -a "${GITHUB_ENV}" fi - # End Determine Docker Tag + # End Determine Base Tags # Login to Docker Hub - name: Login to Docker Hub @@ -98,6 +121,12 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} if: ${{ env.HAVE_DOCKERHUB_LOGIN == 'true' }} + - name: Add registry for DockerHub + if: ${{ env.HAVE_DOCKERHUB_LOGIN == 'true' }} + shell: bash + run: | + echo "CONTAINER_REGISTRIES=${{ vars.DOCKERHUB_REPO }}" | tee -a "${GITHUB_ENV}" + # Login to GitHub Container Registry - name: Login to GitHub Container Registry uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 @@ -107,6 +136,12 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} if: ${{ env.HAVE_GHCR_LOGIN == 'true' }} + - name: Add registry for ghcr.io + if: ${{ env.HAVE_GHCR_LOGIN == 'true' }} + shell: bash + run: | + echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${{ vars.GHCR_REPO }}" | tee -a "${GITHUB_ENV}" + # Login to Quay.io - name: Login to Quay.io uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 @@ -116,120 +151,22 @@ jobs: password: ${{ secrets.QUAY_TOKEN }} if: ${{ env.HAVE_QUAY_LOGIN == 'true' }} - # Debian - - # Docker Hub - - name: Build Debian based images (docker.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.DOCKERHUB_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/build - if: ${{ matrix.base_image == 'debian' && env.HAVE_DOCKERHUB_LOGIN == 'true' }} - - - name: Push Debian based images (docker.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.DOCKERHUB_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'debian' && env.HAVE_DOCKERHUB_LOGIN == 'true' }} - - # GitHub Container Registry - - name: Build Debian based images (ghcr.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.GHCR_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/build - if: ${{ matrix.base_image == 'debian' && env.HAVE_GHCR_LOGIN == 'true' }} - - - name: Push Debian based images (ghcr.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.GHCR_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'debian' && env.HAVE_GHCR_LOGIN == 'true' }} - - # Quay.io - - name: Build Debian based images (quay.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.QUAY_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/build - if: ${{ matrix.base_image == 'debian' && env.HAVE_QUAY_LOGIN == 'true' }} - - - name: Push Debian based images (quay.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.QUAY_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'debian' && env.HAVE_QUAY_LOGIN == 'true' }} - - # Alpine - - # Docker Hub - - name: Build Alpine based images (docker.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.DOCKERHUB_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" - run: | - ./hooks/build - if: ${{ matrix.base_image == 'alpine' && env.HAVE_DOCKERHUB_LOGIN == 'true' }} - - - name: Push Alpine based images (docker.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.DOCKERHUB_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'alpine' && env.HAVE_DOCKERHUB_LOGIN == 'true' }} - - # GitHub Container Registry - - name: Build Alpine based images (ghcr.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.GHCR_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" - run: | - ./hooks/build - if: ${{ matrix.base_image == 'alpine' && env.HAVE_GHCR_LOGIN == 'true' }} - - - name: Push Alpine based images (ghcr.io) - shell: bash - env: - DOCKER_REPO: "${{ vars.GHCR_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'alpine' && env.HAVE_GHCR_LOGIN == 'true' }} - - # Quay.io - - name: Build Alpine based images (quay.io) + - name: Add registry for Quay.io + if: ${{ env.HAVE_QUAY_LOGIN == 'true' }} shell: bash - env: - DOCKER_REPO: "${{ vars.QUAY_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" run: | - ./hooks/build - if: ${{ matrix.base_image == 'alpine' && env.HAVE_QUAY_LOGIN == 'true' }} + echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${{ vars.QUAY_REPO }}" | tee -a "${GITHUB_ENV}" - - name: Push Alpine based images (quay.io) - shell: bash + - name: Bake ${{ matrix.base_image }} containers + uses: docker/bake-action@511fde2517761e303af548ec9e0ea74a8a100112 # v4.0.0 env: - DOCKER_REPO: "${{ vars.QUAY_REPO }}" - DOCKER_TAG: "${{steps.vars.outputs.DOCKER_TAG}}-alpine" - run: | - ./hooks/push - if: ${{ matrix.base_image == 'alpine' && env.HAVE_QUAY_LOGIN == 'true' }} + BASE_TAGS: "${{ env.BASE_TAGS }}" + SOURCE_COMMIT: "${{ env.SOURCE_COMMIT }}" + SOURCE_VERSION: "${{ env.SOURCE_VERSION }}" + SOURCE_REPOSITORY_URL: "${{ env.SOURCE_REPOSITORY_URL }}" + CONTAINER_REGISTRIES: "${{ env.CONTAINER_REGISTRIES }}" + with: + pull: true + push: true + files: docker/docker-bake.hcl + targets: "${{ matrix.base_image }}-multi" diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 77742c35b0..6bfe90ad35 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -73,7 +73,9 @@ COPY ./build.rs ./build.rs # Shared variables across Debian and Alpine RUN echo "export CARGO_TARGET=${RUST_MUSL_CROSS_TARGET}" >> /env-cargo && \ # To be able to build the armv6 image with mimalloc we need to tell the linker to also look for libatomic - if [[ "${TARGETARCH}${TARGETVARIANT}" == "armv6" ]] ; then echo "export RUSTFLAGS='-Clink-arg=-latomic'" >> /env-cargo ; fi + if [[ "${TARGETARCH}${TARGETVARIANT}" == "armv6" ]] ; then echo "export RUSTFLAGS='-Clink-arg=-latomic'" >> /env-cargo ; fi && \ + # Output the current contents of the file + cat /env-cargo # Enable MiMalloc to improve performance on Alpine builds ARG DB=sqlite,mysql,postgresql,enable_mimalloc diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index edeec27358..8607e63a3b 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -51,22 +51,28 @@ ENV DEBIAN_FRONTEND=noninteractive \ # Install clang to get `xx-cargo` working # Install pkg-config to allow amd64 builds to find all libraries +# Install the libc cross packages based upon the debian-arch RUN apt-get update && \ apt-get install -y \ --no-install-recommends \ - clang pkg-config + clang pkg-config \ + "libc6-$(xx-info debian-arch)-cross" \ + "libc6-dev-$(xx-info debian-arch)-cross" \ + "linux-libc-dev-$(xx-info debian-arch)-cross" && \ + # Run xx-cargo early, since it sometimes seems to break when run at a later stage + echo "export CARGO_TARGET=$(xx-cargo --print-target-triple)" >> /env-cargo RUN xx-apt-get install -y \ --no-install-recommends \ gcc \ - libc6-dev \ - linux-libc-dev \ - libmariadb-dev \ - libmariadb-dev-compat \ libmariadb3 \ libpq-dev \ libpq5 \ - libssl-dev + libssl-dev && \ + # Force install arch dependend mariadb dev packages + # Installing them the normal way breaks several other packages (again) + apt-get download "libmariadb-dev-compat:$(xx-info debian-arch)" "libmariadb-dev:$(xx-info debian-arch)" && \ + dpkg --force-all -i ./libmariadb-dev*.deb # Create CARGO_HOME folder and don't download rust docs RUN mkdir -pv "${CARGO_HOME}" \ @@ -82,17 +88,19 @@ COPY ./rust-toolchain.toml ./rust-toolchain.toml COPY ./build.rs ./build.rs # Environment variables for cargo across Debian and Alpine -RUN echo "export CARGO_TARGET=$(xx-cargo --print-target-triple)" >> /env-cargo && \ +RUN source /env-cargo && \ if xx-info is-cross ; then \ # We can't use xx-cargo since that uses clang, which doesn't work for our libraries. # Because of this we generate the needed environment variables here which we can load in the needed steps. - echo "export CC_$(xx-cargo --print-target-triple | tr '[:upper:]' '[:lower:]' | tr - _)=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ - echo "export CARGO_TARGET_$(xx-cargo --print-target-triple | tr '[:lower:]' '[:upper:]' | tr - _)_LINKER=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ + echo "export CC_$(echo "${CARGO_TARGET}" | tr '[:upper:]' '[:lower:]' | tr - _)=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ + echo "export CARGO_TARGET_$(echo "${CARGO_TARGET}" | tr '[:lower:]' '[:upper:]' | tr - _)_LINKER=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ echo "export PKG_CONFIG=/usr/bin/$(xx-info)-pkg-config" >> /env-cargo && \ echo "export CROSS_COMPILE=1" >> /env-cargo && \ echo "export OPENSSL_INCLUDE_DIR=/usr/include/$(xx-info)" >> /env-cargo && \ echo "export OPENSSL_LIB_DIR=/usr/lib/$(xx-info)" >> /env-cargo ; \ - fi + fi && \ + # Output the current contents of the file + cat /env-cargo # Configure the DB ARG as late as possible to not invalidate the cached layers above ARG DB=sqlite,mysql,postgresql diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 index 1a182116c2..5748850ee1 100644 --- a/docker/Dockerfile.j2 +++ b/docker/Dockerfile.j2 @@ -69,22 +69,28 @@ ENV DEBIAN_FRONTEND=noninteractive \ # Install clang to get `xx-cargo` working # Install pkg-config to allow amd64 builds to find all libraries +# Install the libc cross packages based upon the debian-arch RUN apt-get update && \ apt-get install -y \ --no-install-recommends \ - clang pkg-config + clang pkg-config \ + "libc6-$(xx-info debian-arch)-cross" \ + "libc6-dev-$(xx-info debian-arch)-cross" \ + "linux-libc-dev-$(xx-info debian-arch)-cross" && \ + # Run xx-cargo early, since it sometimes seems to break when run at a later stage + echo "export CARGO_TARGET=$(xx-cargo --print-target-triple)" >> /env-cargo RUN xx-apt-get install -y \ --no-install-recommends \ gcc \ - libc6-dev \ - linux-libc-dev \ - libmariadb-dev \ - libmariadb-dev-compat \ libmariadb3 \ libpq-dev \ libpq5 \ - libssl-dev + libssl-dev && \ + # Force install arch dependend mariadb dev packages + # Installing them the normal way breaks several other packages (again) + apt-get download "libmariadb-dev-compat:$(xx-info debian-arch)" "libmariadb-dev:$(xx-info debian-arch)" && \ + dpkg --force-all -i ./libmariadb-dev*.deb {% endif %} # Create CARGO_HOME folder and don't download rust docs @@ -102,17 +108,19 @@ COPY ./build.rs ./build.rs {% if base == "debian" %} # Environment variables for cargo across Debian and Alpine -RUN echo "export CARGO_TARGET=$(xx-cargo --print-target-triple)" >> /env-cargo && \ +RUN source /env-cargo && \ if xx-info is-cross ; then \ # We can't use xx-cargo since that uses clang, which doesn't work for our libraries. # Because of this we generate the needed environment variables here which we can load in the needed steps. - echo "export CC_$(xx-cargo --print-target-triple | tr '[:upper:]' '[:lower:]' | tr - _)=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ - echo "export CARGO_TARGET_$(xx-cargo --print-target-triple | tr '[:lower:]' '[:upper:]' | tr - _)_LINKER=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ + echo "export CC_$(echo ${CARGO_TARGET} | tr '[:upper:]' '[:lower:]' | tr - _)=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ + echo "export CARGO_TARGET_$(echo ${CARGO_TARGET} | tr '[:lower:]' '[:upper:]' | tr - _)_LINKER=/usr/bin/$(xx-info)-gcc" >> /env-cargo && \ echo "export PKG_CONFIG=/usr/bin/$(xx-info)-pkg-config" >> /env-cargo && \ echo "export CROSS_COMPILE=1" >> /env-cargo && \ echo "export OPENSSL_INCLUDE_DIR=/usr/include/$(xx-info)" >> /env-cargo && \ echo "export OPENSSL_LIB_DIR=/usr/lib/$(xx-info)" >> /env-cargo ; \ - fi + fi && \ + # Output the current contents of the file + cat /env-cargo # Configure the DB ARG as late as possible to not invalidate the cached layers above ARG DB=sqlite,mysql,postgresql @@ -120,7 +128,9 @@ ARG DB=sqlite,mysql,postgresql # Shared variables across Debian and Alpine RUN echo "export CARGO_TARGET=${RUST_MUSL_CROSS_TARGET}" >> /env-cargo && \ # To be able to build the armv6 image with mimalloc we need to tell the linker to also look for libatomic - if [[ "${TARGETARCH}${TARGETVARIANT}" == "armv6" ]] ; then echo "export RUSTFLAGS='-Clink-arg=-latomic'" >> /env-cargo ; fi + if [[ "${TARGETARCH}${TARGETVARIANT}" == "armv6" ]] ; then echo "export RUSTFLAGS='-Clink-arg=-latomic'" >> /env-cargo ; fi && \ + # Output the current contents of the file + cat /env-cargo # Enable MiMalloc to improve performance on Alpine builds ARG DB=sqlite,mysql,postgresql,enable_mimalloc diff --git a/docker/test.sh b/docker/test.sh new file mode 100755 index 0000000000..fe53d2298f --- /dev/null +++ b/docker/test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +GITHUB_ENV="/dev/stderr" +SOURCE_COMMIT="$(git rev-parse HEAD)" + +# Check which main tag we are going to build determined by github.ref_type +if [[ "branch" == "tag" ]]; then +echo "BASE_TAGS=latest,${GITHUB_REF#refs/*/}" | tee -a "${GITHUB_ENV}" +elif [[ "branch" == "branch" ]]; then +echo "BASE_TAGS=testing" | tee -a "${GITHUB_ENV}" +fi + +GIT_EXACT_TAG="$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || true)" +if [[ -n "${GIT_EXACT_TAG}" ]]; then + echo "SOURCE_VERSION=${GIT_EXACT_TAG}" | tee -a "${GITHUB_ENV}" +else + GIT_LAST_TAG="$(git describe --tags --abbrev=0)" + echo "SOURCE_VERSION=${GIT_LAST_TAG}-${SOURCE_COMMIT:0:8}" | tee -a "${GITHUB_ENV}" +fi