name: Daily Update Pipeline on: schedule: # Runs every day at 3:00 AM UTC - cron: '0 3 * * *' workflow_dispatch: # Allows manual triggering jobs: check-images: runs-on: ubuntu-latest outputs: base_image_digest: ${{ steps.mlflow-base.outputs.digest }} should_build: ${{ steps.decision.outputs.should_build }} steps: - name: Log in to Gitea Container Registry run: | mkdir -p ~/.docker echo '{"insecure-registries": ["10.0.0.2:3000"]}' > ~/.docker/config.json echo "${{ secrets.CI_RUNNER_TOKEN }}" | docker login 10.0.0.2:3000 --username "${{ gitea.actor }}" --password-stdin - name: Check MLflow-full base image digest id: mlflow-full run: | MANIFEST=$(docker manifest inspect "gitea.gt-proj.com/brian/mlflow-full:latest" 2>/dev/null || echo "{}") if [ "$MANIFEST" == "{}" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "MLflow-full manifest not found" exit 1 fi # Extract digest for linux/amd64 platform DIGEST=$(echo "$MANIFEST" | jq -r '.manifests[]? | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest // empty') if [ -z "$DIGEST" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "No suitable manifest found for linux/amd64" exit 1 fi # Get the manifest for the specific platform PLATFORM_MANIFEST=$(curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ -H "Authorization: Bearer ${{ secrets.CI_RUNNER_TOKEN }}" \ "https://gitea.gt-proj.com/v2/brian/mlflow-full/manifests/$DIGEST" 2>/dev/null || echo "{}") if [ "$PLATFORM_MANIFEST" == "{}" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "Failed to fetch platform-specific manifest" exit 1 fi # Extract config blob digest CONFIG_DIGEST=$(echo "$PLATFORM_MANIFEST" | jq -r '.config.digest // empty') if [ -z "$CONFIG_DIGEST" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "No config digest found in platform manifest" exit 1 fi # Fetch the configuration blob to get labels CONFIG_BLOB=$(curl -s "http://gitea.gt-proj.com/v2/brian/mlflow-full/blobs/$CONFIG_DIGEST" 2>/dev/null || echo "{}") if [ "$CONFIG_BLOB" == "{}" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "Failed to fetch config blob" exit 1 fi # Extract base image digest label from config BASE_IMAGE_DIGEST=$(echo "$CONFIG_BLOB" | jq -r '.config.Labels["base-image.digest"] // empty') if [ -z "$BASE_IMAGE_DIGEST" ]; then echo "digest_found=false" >> $GITHUB_OUTPUT echo "No base-image.digest label found in MLflow-full image" exit 1 fi echo "base_image_digest=$BASE_IMAGE_DIGEST" >> $GITHUB_OUTPUT echo "digest_found=true" >> $GITHUB_OUTPUT echo "Base image digest from MLflow-full image: $BASE_IMAGE_DIGEST" - name: Check MLflow base image digest id: mlflow-base if: steps.mlflow-full.outputs.digest_found == 'true' run: | MANIFEST=$(docker manifest inspect ghcr.io/mlflow/mlflow:latest 2>/dev/null || echo "{}") if [ "$MANIFEST" != "{}" ]; then DIGEST=$(echo "$MANIFEST" | jq -r '.manifests[]? | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest // empty') echo "digest=$DIGEST" >> $GITHUB_OUTPUT echo "digest_found=true" >> $GITHUB_OUTPUT echo "Digest found for MLflow base image: $DIGEST" else echo "digest_found=false" >> $GITHUB_OUTPUT echo "MLflow base image not found" fi - name: Build decision id: decision run: | if [ "${{ steps.mlflow-base.outputs.manifest_found }}" == "true" ] && \ [ "${{ steps.mlflow-full.outputs.manifest_found }}" == "true" ]; then echo "✅ Both MLflow base and MLflow-full images found" if [ "${{ steps.mlflow-base.outputs.digest }}" != "${{ steps.mlflow-full.outputs.base_image_digest }}" ]; then echo "Base image digest has changed" echo "should_build=true" >> $GITHUB_OUTPUT else echo "Base image digest is unchanged" echo "should_build=false" >> $GITHUB_OUTPUT fi elif [ "${{ steps.mlflow-base.outputs.manifest_found }}" != "true" ]; then echo "❌ MLflow base image not found" echo "should_build=false" >> $GITHUB_OUTPUT else echo "❌ MLflow-full image not found" echo "should_build=false" >> $GITHUB_OUTPUT fi build-and-publish: needs: check-images if: needs.check-images.outputs.should_build == 'true' runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: config-inline: | [registry."10.0.0.2:3000"] http = true insecure = true - name: Log in to Gitea Container Registry run: | # Configure Docker to allow insecure registry for this session mkdir -p ~/.docker echo '{ "auths": {}, "insecure-registries": ["10.0.0.2:3000"] }' > ~/.docker/config.json # Login using direct docker command echo "${{ secrets.CI_RUNNER_TOKEN }}" | docker login 10.0.0.2:3000 --username "${{ gitea.actor }}" --password-stdin - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: 10.0.0.2:3000/${{ gitea.repository_owner }}/${{ gitea.event.repository.name }} tags: | type=schedule,pattern={{date 'YYYYMMDD'}} type=raw,value=latest labels: | base-image.digest=${{ needs.check-images.outputs.base_image_digest }} - name: Build and push Docker image id: build-publish uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max build-args: | BASE_IMAGE_DIGEST=${{ needs.check-images.outputs.base_image_digest }} - name: Update deployment info run: | echo "Docker image built and pushed successfully at $(date)" echo "Image tags:" echo "${{ steps.meta.outputs.tags }}"