From 080f1b2dfec6b6a381a1f99713fc24484bd9e625 Mon Sep 17 00:00:00 2001 From: Jusong Yu Date: Mon, 3 Jun 2024 14:30:23 +0200 Subject: [PATCH 1/2] New docker build strategy --- .github/workflows/build_and_test.yaml | 44 ------- .github/workflows/ci.yml | 158 +++++++++++++++++++++++ .github/workflows/env.hcl | 2 + .github/workflows/extract-image-name.sh | 34 +++++ .github/workflows/push_to_dockerhub.yaml | 50 ------- .gitignore | 1 + Dockerfile | 50 +++++-- LICENSE | 21 --- README.md | 3 - build.json | 13 ++ docker-bake.hcl | 43 ++++++ 11 files changed, 290 insertions(+), 129 deletions(-) delete mode 100644 .github/workflows/build_and_test.yaml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/env.hcl create mode 100755 .github/workflows/extract-image-name.sh delete mode 100644 .github/workflows/push_to_dockerhub.yaml create mode 100644 .gitignore delete mode 100644 LICENSE create mode 100644 build.json create mode 100644 docker-bake.hcl diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml deleted file mode 100644 index 5d13f27..0000000 --- a/.github/workflows/build_and_test.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# Test the Docker image on every pull request. -# -# The steps are: -# 1. Build docker image using cached data. -# 2. Start the docker container with local folder mounted to it. - -name: build-and-test-image-from-pull-request - -on: - [pull_request] - -jobs: - - build-and-test: - - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - - - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Build image locally - uses: docker/build-push-action@v2 - with: - load: true - push: false - tags: psp-prerequisites:latest - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6e5dbfd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,158 @@ +--- +name: Build images and run tests and publish + +on: + pull_request: + push: + branches: + - main + - support/** + tags: + - "v*" + workflow_dispatch: + +env: + BUILDKIT_PROGRESS: plain + FORCE_COLOR: 1 + +# https://docs.github.com/en/actions/using-jobs/using-concurrency +concurrency: + # only cancel in-progress jobs or runs for the current workflow - matches against branch & tags + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + build: + + runs-on: ubuntu-latest + timeout-minutes: 30 + + outputs: + image: ${{ steps.bake_metadata.outputs.image }} + + steps: + - name: Checkout Repo ⚡️ + uses: actions/checkout@v4 + + - name: Set up QEMU + if: ${{ inputs.platforms != 'linux/amd64' }} + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry 🔑 + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + + - uses: crazy-max/ghaction-github-runtime@v3 + - name: Build and upload to ghcr.io 📤 + id: build-upload + uses: docker/bake-action@v4 + with: + push: true + # Using provenance to disable default attestation so it will build only desired images: + # https://github.com/orgs/community/discussions/45969 + provenance: false + set: | + *.platform=linux/amd64 + *.output=type=registry,name-canonical=true,push-by-digest=true + *.cache-from=type=gha + *.cache-to=type=gha,mode=max + + files: | + docker-bake.hcl + build.json + .github/workflows/env.hcl + + - name: Set output variables + id: bake_metadata + run: | + .github/workflows/extract-image-name.sh | tee -a "${GITHUB_OUTPUT}" + env: + BAKE_METADATA: ${{ steps.build-upload.outputs.metadata }} + + test: + runs-on: ubuntu-latest + timeout-minutes: 30 + needs: build + + steps: + + - name: Checkout Repo ⚡️ + uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry 🔑 + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Run container checking libraries exist in the container + run: | + docker run --rm ${{ needs.build.outputs.image }} /bin/bash -c "which pw.x" >> /tmp/cat-output.txt + docker run --rm ${{ needs.build.outputs.image }} /bin/bash -c "which ph.x" >> /tmp/cat-output.txt + if cat /tmp/cat-output.txt | grep -q "/usr/local/bin/pw.x"; then + echo "pw.x found" + else + echo "pw.x not found" + exit 1 + fi + + if cat /tmp/cat-output.txt | grep -q "/usr/local/bin/ph.x"; then + echo "ph.x found" + else + echo "ph.x not found" + exit 1 + fi + + publish: + runs-on: ubuntu-latest + timeout-minutes: 30 + needs: [build] + if: >- + github.repository == 'containers4hpc/quantum-espresso' + && (github.ref_type == 'tag' || github.ref_name == 'main') + + steps: + - uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry 🔑 + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Read build variables + id: build_vars + run: | + vars=$(cat build.json | jq -c '[.variable | to_entries[] | {"key": .key, "value": .value.default}] | from_entries') + echo "vars=$vars" | tee -a "${GITHUB_OUTPUT}" + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + env: ${{ fromJSON(steps.build_vars.outputs.vars) }} + with: + images: ghcr.io/${{ github.repository_owner }}/quantum-espresso + tags: | + type=edge,enable={{is_default_branch}} + type=raw,value={{tag}},enable=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} + type=raw,value=quantum-espresso-${{ env.QE_VERSION }},enable=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} + type=match,pattern=v(\d{4}\.\d{4}(-.+)?),group=1 + + - name: Push tags + uses: akhilerm/tag-push-action@v2.2.0 + with: + src: ${{ needs.build.outputs.image }} + dst: ${{ steps.meta.outputs.tags }} diff --git a/.github/workflows/env.hcl b/.github/workflows/env.hcl new file mode 100644 index 0000000..9a8782a --- /dev/null +++ b/.github/workflows/env.hcl @@ -0,0 +1,2 @@ +# env.hcl +REGISTRY = "ghcr.io" diff --git a/.github/workflows/extract-image-name.sh b/.github/workflows/extract-image-name.sh new file mode 100755 index 0000000..ebb56ee --- /dev/null +++ b/.github/workflows/extract-image-name.sh @@ -0,0 +1,34 @@ +# Extract image names together with their sha256 digests +# from the docker/bake-action metadata output. +# These together uniquely identify newly built images. + +# The input to this script is a JSON string passed via BAKE_METADATA env variable +# Here's example input (trimmed to relevant bits): +# BAKE_METADATA: { +# "base": { +# "containerimage.descriptor": { +# "mediaType": "application/vnd.docker.distribution.manifest.v2+json", +# "digest": "sha256:8e57a52b924b67567314b8ed3c968859cad99ea13521e60bbef40457e16f391d", +# "size": 6170, +# }, +# "containerimage.digest": "sha256:8e57a52b924b67567314b8ed3c968859cad99ea13521e60bbef40457e16f391d", +# "image.name": "ghcr.io/pspgen/quantum-espresso" +# } +# } +# +# Example output (real output is on one line): +# +# image="ghcr.io/pspgen/quantum-espresso@sha256:79a0f984b9e03b733304fda809ad3e8eec8416992ff334052d75da00cadb8f12" +# } +# +# This json output is later turned to environment variables using fromJson() GHA builtin +# (e.g. BUILD_MACHINE_IMAGE=ghcr.io/pspgen/quantum-espresso@sha256:8e57a52b...) +# and these are in turn read in the docker-compose..yml files for tests. + +if [[ -z ${BAKE_METADATA-} ]];then + echo "ERROR: Environment variable BAKE_METADATA is not set!" + exit 1 +fi + +image=$(echo "${BAKE_METADATA}" | jq -c '. as $base | to_entries[] | [(.value."image.name"|split(",")[0]),(.value."containerimage.digest")]|join("@")' | tr -d '"') +echo "image=$image" diff --git a/.github/workflows/push_to_dockerhub.yaml b/.github/workflows/push_to_dockerhub.yaml deleted file mode 100644 index 25e88d7..0000000 --- a/.github/workflows/push_to_dockerhub.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# Build the new Docker image on every commit to main branch and on every new tag. -# No caching is involved for the image build. The new image is then pushed to the Docker Hub. - -name: build-and-push-to-dockerhub - -on: - push: - branches: - - main - tags: - - 'v*' - -jobs: - - build-and-push: - - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - - - uses: actions/checkout@v2 - - - name: Docker meta - id: meta - uses: docker/metadata-action@v3 - with: - images: ${{ github.repository }} - tags: | - type=ref,event=branch - type=semver,pattern={{version}} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Build and push - id: docker_build - uses: docker/build-push-action@v2 - with: - push: true - tags: ${{ steps.meta.outputs.tags }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..88f9974 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_build/* diff --git a/Dockerfile b/Dockerfile index 0065afb..26e9e5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,39 @@ -FROM containers4hpc/base-mpich314:0.1.0 - -# Install QE 7.0 (pw.x only for now) -# FOR PRODUCTION: PUT ALL IN THE SAME LINE TO AVOID HAVING LAYERS WITH A LOT OF FILES! -RUN wget -q https://gitlab.com/QEF/q-e/-/archive/qe-7.0/q-e-qe-7.0.tar.gz \ - && tar xzf q-e-qe-7.0.tar.gz -RUN cd q-e-qe-7.0 \ - && ./configure \ - && make -j4 pw \ - && make install \ - && cd .. && rm -fr q-e-qe-* \ No newline at end of file +FROM build-base-image + +WORKDIR /qe-build + +# Compile Lapack +# TODO: this should be moved to build-machine base image +ARG LAPACK_VERSION="3.10.1" + +RUN wget -c -O lapack.tar.gz https://github.com/Reference-LAPACK/lapack/archive/refs/tags/v${LAPACK_VERSION}.tar.gz && \ + mkdir -p lapack && \ + tar xf lapack.tar.gz -C lapack --strip-components=1 && \ + cd lapack && \ + cp INSTALL/make.inc.gfortran make.inc && \ + make lapacklib blaslib && \ + mkdir -p /usr/local/lapack/lib && \ + cp *.a /usr/local/lapack/lib + +# Compile QE +ARG QE_VERSION + +RUN wget -c -O qe.tar.gz https://gitlab.com/QEF/q-e/-/archive/qe-${QE_VERSION}/q-e-qe-${QE_VERSION}.tar.gz && \ + mkdir -p qe && \ + tar xf qe.tar.gz -C qe --strip-components=1 && \ + cd qe && \ + LAPACK_LIBS=/usr/local/lapack/lib/liblapack.a BLAS_LIBS=/usr/local/lapack/lib/librefblas.a ./configure -enable-static && \ + make -j8 pw ph && \ + make install + + +# Move binaries to a small image to reduce the size +FROM runtime-base-image + +#RUN apt-get update && apt-get install -y \ +# libquadmath0 \ +# && rm -rf /var/lib/apt/lists/* \ +# && apt-get clean all + +COPY --from=0 /usr/local/bin/* /usr/local/bin/ + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d6a12c4..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 container4hpc - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 051d7ef..bcf4db9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,3 @@ The Quantum ESPRESSO v7.0 (only pw.x supported at the moment) is compiled with MPICH 3.1.4 which support ABI interface. Based on [`container4hpc/base-mpich314:0.1.0`](https://hub.docker.com/repository/docker/container4hpc/base-mpich314) -# version - -[0.1.0](https://hub.docker.com/repository/docker/containers4hpc/qe-mpich314) \ No newline at end of file diff --git a/build.json b/build.json new file mode 100644 index 0000000..d60eae5 --- /dev/null +++ b/build.json @@ -0,0 +1,13 @@ +{ + "variable": { + "BUILD_BASE_IMAGE": { + "default": "docker.io/containers4hpc/base-mpich314:0.1.0" + }, + "RUNTIME_BASE_IMAGE": { + "default": "phusion/baseimage:focal-1.2.0" + }, + "QE_VERSION": { + "default": "7.0" + } + } +} diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..9fd6606 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,43 @@ +group "default" { + targets = ["mpich"] +} + +variable "ORGANIZATION" { + default = "containers4hpc" +} + +variable "BULID_BASE_IMAGE" { +} + +variable "RUNTIME_BASE_IMAGE" { +} + +variable "QE_VERSION" { +} + +variable "REGISTRY" { + default = "ghcr.io" +} + +function "tags" { + params = [image] + result = [ + "${REGISTRY}/${ORGANIZATION}/${image}", + ] +} + +target "mpich-meta" { + tags = tags("quantum-espresso") +} + +target "mpich" { + inherits = ["mpich-meta"] + context = "." + contexts = { + build-base-image = "docker-image://${BUILD_BASE_IMAGE}" + runtime-base-image = "docker-image://${RUNTIME_BASE_IMAGE}" + } + args = { + "QE_VERSION" = "${QE_VERSION}" + } +} From 4252171697e2c50b5c3fddc10dc24d18e396a776 Mon Sep 17 00:00:00 2001 From: Jusong Yu Date: Mon, 3 Jun 2024 16:22:52 +0200 Subject: [PATCH 2/2] Use simple qe version tag for the published image It was `quantum-espresso-7.0` which is verbose, changed to `qe-7.0`. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e5dbfd..864d9d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,7 @@ jobs: tags: | type=edge,enable={{is_default_branch}} type=raw,value={{tag}},enable=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} - type=raw,value=quantum-espresso-${{ env.QE_VERSION }},enable=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} + type=raw,value=qe-${{ env.QE_VERSION }},enable=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} type=match,pattern=v(\d{4}\.\d{4}(-.+)?),group=1 - name: Push tags