From 6cfd9774ae1cc5882016e918d2214d2298a43730 Mon Sep 17 00:00:00 2001 From: Alex TYRODE Date: Thu, 24 Apr 2025 22:31:01 +0000 Subject: [PATCH 1/2] refactor: enhance Dockerfile build flow - Re-arranged steps order to install requirements before copying backend for better caching. - Introduced a healthcheck command to monitor the application status. - Set environment variables and documented the exposed port for better container management. --- Dockerfile | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b254246..5979be9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,45 @@ +# Frontend build stage FROM node:20-slim as frontend-builder WORKDIR /app/frontend + +# Copy package files first to leverage layer caching COPY src/frontend/package.json src/frontend/yarn.lock ./ RUN yarn install --frozen-lockfile + +# Copy all frontend files COPY src/frontend/ ./ + +# Build the frontend RUN yarn build +# Backend stage FROM python:3.11-slim WORKDIR /app -COPY src/backend /app + +# Copy requirements first to leverage layer caching +COPY src/backend/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt + +# Install curl for healthcheck +RUN apt-get update && apt-get install -y --no-install-recommends curl && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Copy backend files +COPY src/backend . + +# Copy built frontend from the frontend-builder stage COPY --from=frontend-builder /app/frontend/dist /app/frontend/dist -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +# Add healthcheck +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:8000/ || exit 1 + +# Set environment variables +ENV PYTHONUNBUFFERED=1 + +# Document the port number the container will expose +EXPOSE 8000 + +# Run the application +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file From 1bae5b81eef22ed8371e8a2d7362e41d33f6ec39 Mon Sep 17 00:00:00 2001 From: Alex TYRODE Date: Thu, 24 Apr 2025 22:31:17 +0000 Subject: [PATCH 2/2] feat: implement multi-architecture Docker build workflow - Added separate jobs for building and pushing AMD64 and ARM64 Docker images. - Configured conditional execution for ARM64 builds to only run on the main branch. - Enhanced the Docker build process with digest export and artifact upload for both architectures. - Created a job to generate a multi-architecture manifest after successful builds. - Updated tags and labels for better image management. --- .github/workflows/docker-build.yml | 165 ++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 134e019..a549d57 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -12,20 +12,22 @@ env: IMAGE_NAME: ${{ github.repository }} jobs: - build-and-push: + # Job for AMD64 architecture - runs on all events + build-amd64: runs-on: ubuntu-latest permissions: contents: read packages: write - steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + id: buildx - name: Log in to the Container registry + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} @@ -44,14 +46,167 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=sha,format=long - - name: Build and push Docker image + - name: Build and push AMD64 Docker image + id: build uses: docker/build-push-action@v5 with: context: . push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} + tags: ${{ steps.meta.outputs.tags }}-amd64 + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 + cache-from: type=gha + cache-to: type=gha,mode=max + builder: ${{ steps.buildx.outputs.name }} + outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + + - name: Export AMD64 digest + if: github.event_name != 'pull_request' + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + echo "AMD64_DIGEST=${digest}" >> $GITHUB_ENV + + - name: Upload AMD64 digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: amd64-digest + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # Job for ARM64 architecture - only runs on main branch + build-arm64: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # Only run this job for pushes to main, not for PRs + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + id: buildx + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,format=long + + - name: Build and push ARM64 Docker image + id: build + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }}-arm64 labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64,linux/arm64 + platforms: linux/arm64 cache-from: type=gha cache-to: type=gha,mode=max builder: ${{ steps.buildx.outputs.name }} + outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true + + - name: Export ARM64 digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + echo "ARM64_DIGEST=${digest}" >> $GITHUB_ENV + + - name: Upload ARM64 digest + uses: actions/upload-artifact@v4 + with: + name: arm64-digest + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # Job to create multi-architecture manifest + create-manifest: + runs-on: ubuntu-latest + needs: [build-amd64, build-arm64] + # This job only runs if at least build-amd64 completed successfully + # build-arm64 might be skipped for PRs, so we don't require it + if: github.event_name != 'pull_request' && always() && needs.build-amd64.result == 'success' + permissions: + contents: read + packages: write + steps: + - name: Download AMD64 digest + uses: actions/download-artifact@v4 + with: + name: amd64-digest + path: /tmp/digests/amd64 + + - name: Download ARM64 digest + # Only try to download ARM64 digest if the job ran + if: needs.build-arm64.result == 'success' + uses: actions/download-artifact@v4 + with: + name: arm64-digest + path: /tmp/digests/arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,format=long + + - name: Create manifest list and push + run: | + # Get the first tag from meta outputs + FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | cut -d, -f1) + + # If ARM64 build was skipped, only use AMD64 digest + if [ "${{ needs.build-arm64.result }}" != "success" ]; then + AMD64_DIGEST=$(cat /tmp/digests/amd64/*) + docker buildx imagetools create \ + --tag ${FIRST_TAG} \ + ${AMD64_DIGEST} + else + # Otherwise use both digests + AMD64_DIGEST=$(cat /tmp/digests/amd64/*) + ARM64_DIGEST=$(cat /tmp/digests/arm64/*) + docker buildx imagetools create \ + --tag ${FIRST_TAG} \ + ${AMD64_DIGEST} ${ARM64_DIGEST} + fi + + - name: Inspect image + run: | + FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | cut -d, -f1) + docker buildx imagetools inspect ${FIRST_TAG} \ No newline at end of file