# Copyright 2024 RustFS Team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Build and Push Docker Images on: push: branches: - main tags: - "v*" pull_request: branches: - main workflow_dispatch: inputs: push_to_registry: description: "Push images to registry" required: false default: "true" type: boolean env: REGISTRY_IMAGE_DOCKERHUB: rustfs/rustfs REGISTRY_IMAGE_GHCR: ghcr.io/${{ github.repository }} jobs: # Skip duplicate job runs skip-check: permissions: actions: write contents: read runs-on: ubuntu-latest outputs: should_skip: ${{ steps.skip_check.outputs.should_skip }} steps: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: concurrent_skipping: "same_content_newer" cancel_others: true paths_ignore: '["*.md", "docs/**"]' # Build RustFS binary for different platforms build-binary: needs: skip-check if: needs.skip-check.outputs.should_skip != 'true' strategy: matrix: include: - target: x86_64-unknown-linux-musl os: ubuntu-latest arch: amd64 use_cross: false - target: aarch64-unknown-linux-gnu os: ubuntu-latest arch: arm64 use_cross: true runs-on: ${{ matrix.os }} timeout-minutes: 120 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: target: ${{ matrix.target }} components: rustfmt, clippy - name: Install cross-compilation dependencies (native build) if: matrix.use_cross == false run: | sudo apt-get update sudo apt-get install -y musl-tools - name: Install cross tool (cross compilation) if: matrix.use_cross == true uses: taiki-e/install-action@v2 with: tool: cross - name: Install protoc uses: arduino/setup-protoc@v3 with: version: "31.1" repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Install flatc uses: Nugine/setup-flatc@v1 with: version: "25.2.10" - name: Cache cargo dependencies uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-${{ matrix.target }}- ${{ runner.os }}-cargo- - name: Generate protobuf code run: cargo run --bin gproto - name: Build RustFS binary (native) if: matrix.use_cross == false run: | cargo build --release --target ${{ matrix.target }} --bin rustfs - name: Build RustFS binary (cross) if: matrix.use_cross == true run: | cross build --release --target ${{ matrix.target }} --bin rustfs - name: Upload binary artifact uses: actions/upload-artifact@v4 with: name: rustfs-${{ matrix.arch }} path: target/${{ matrix.target }}/release/rustfs retention-days: 1 # Build and push multi-arch Docker images build-images: needs: [skip-check, build-binary] if: needs.skip-check.outputs.should_skip != 'true' runs-on: ubuntu-latest timeout-minutes: 60 strategy: matrix: image-type: [production, ubuntu, rockylinux, devenv] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Download binary artifacts uses: actions/download-artifact@v4 with: path: ./artifacts - name: Setup binary files run: | mkdir -p target/x86_64-unknown-linux-musl/release mkdir -p target/aarch64-unknown-linux-gnu/release cp artifacts/rustfs-amd64/rustfs target/x86_64-unknown-linux-musl/release/ cp artifacts/rustfs-arm64/rustfs target/aarch64-unknown-linux-gnu/release/ chmod +x target/*/release/rustfs - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Login to Docker Hub if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set Dockerfile and context id: dockerfile run: | case "${{ matrix.image-type }}" in production) echo "dockerfile=Dockerfile" >> $GITHUB_OUTPUT echo "context=." >> $GITHUB_OUTPUT echo "suffix=" >> $GITHUB_OUTPUT ;; ubuntu) echo "dockerfile=.docker/Dockerfile.ubuntu22.04" >> $GITHUB_OUTPUT echo "context=." >> $GITHUB_OUTPUT echo "suffix=-ubuntu22.04" >> $GITHUB_OUTPUT ;; rockylinux) echo "dockerfile=.docker/Dockerfile.rockylinux9.3" >> $GITHUB_OUTPUT echo "context=." >> $GITHUB_OUTPUT echo "suffix=-rockylinux9.3" >> $GITHUB_OUTPUT ;; devenv) echo "dockerfile=.docker/Dockerfile.devenv" >> $GITHUB_OUTPUT echo "context=." >> $GITHUB_OUTPUT echo "suffix=-devenv" >> $GITHUB_OUTPUT ;; esac - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY_IMAGE_DOCKERHUB }} ${{ env.REGISTRY_IMAGE_GHCR }} tags: | type=ref,event=branch,suffix=${{ steps.dockerfile.outputs.suffix }} type=ref,event=pr,suffix=${{ steps.dockerfile.outputs.suffix }} type=semver,pattern={{version}},suffix=${{ steps.dockerfile.outputs.suffix }} type=semver,pattern={{major}}.{{minor}},suffix=${{ steps.dockerfile.outputs.suffix }} type=semver,pattern={{major}},suffix=${{ steps.dockerfile.outputs.suffix }} type=raw,value=latest,suffix=${{ steps.dockerfile.outputs.suffix }},enable={{is_default_branch}} flavor: | latest=false - name: Build and push multi-arch Docker image uses: docker/build-push-action@v5 with: context: ${{ steps.dockerfile.outputs.context }} file: ${{ steps.dockerfile.outputs.dockerfile }} platforms: linux/amd64,linux/arm64 push: ${{ (github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))) || github.event.inputs.push_to_registry == 'true' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=${{ matrix.image-type }} cache-to: type=gha,mode=max,scope=${{ matrix.image-type }} build-args: | BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}