--- name: 'build container images (reusable)' on: workflow_call: inputs: base-image: description: 'Base image' required: true type: string grpc-base-image: description: 'GRPC Base image, must be a compatible image with base-image' required: false default: '' type: string build-type: description: 'Build type' default: '' type: string cuda-major-version: description: 'CUDA major version' default: "12" type: string cuda-minor-version: description: 'CUDA minor version' default: "4" type: string platforms: description: 'Platforms' default: '' type: string tag-latest: description: 'Tag latest' default: '' type: string latest-image: description: 'Tag latest' default: '' type: string latest-image-aio: description: 'Tag latest' default: '' type: string tag-suffix: description: 'Tag suffix' default: '' type: string ffmpeg: description: 'FFMPEG' default: '' type: string image-type: description: 'Image type' default: '' type: string runs-on: description: 'Runs on' required: true default: '' type: string makeflags: description: 'Make Flags' required: false default: '--jobs=4 --output-sync=target' type: string aio: description: 'AIO Image Name' required: false default: '' type: string secrets: dockerUsername: required: true dockerPassword: required: true quayUsername: required: true quayPassword: required: true jobs: reusable_image-build: runs-on: ${{ inputs.runs-on }} steps: - name: Force Install GIT latest run: | sudo apt-get update \ && sudo apt-get install -y software-properties-common \ && sudo apt-get update \ && sudo add-apt-repository -y ppa:git-core/ppa \ && sudo apt-get update \ && sudo apt-get install -y git - name: Checkout uses: actions/checkout@v4 - name: Release space from worker if: inputs.runs-on == 'ubuntu-latest' run: | echo "Listing top largest packages" pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) head -n 30 <<< "${pkgs}" echo df -h echo sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true sudo apt-get remove --auto-remove android-sdk-platform-tools || true sudo apt-get purge --auto-remove android-sdk-platform-tools || true sudo rm -rf /usr/local/lib/android sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true sudo rm -rf /usr/share/dotnet sudo apt-get remove -y '^mono-.*' || true sudo apt-get remove -y '^ghc-.*' || true sudo apt-get remove -y '.*jdk.*|.*jre.*' || true sudo apt-get remove -y 'php.*' || true sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true sudo apt-get remove -y '^google-.*' || true sudo apt-get remove -y azure-cli || true sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true sudo apt-get remove -y '^gfortran-.*' || true sudo apt-get remove -y microsoft-edge-stable || true sudo apt-get remove -y firefox || true sudo apt-get remove -y powershell || true sudo apt-get remove -y r-base-core || true sudo apt-get autoremove -y sudo apt-get clean echo echo "Listing top largest packages" pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) head -n 30 <<< "${pkgs}" echo sudo rm -rfv build || true sudo rm -rf /usr/share/dotnet || true sudo rm -rf /opt/ghc || true sudo rm -rf "/usr/local/share/boost" || true sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true df -h - name: Docker meta id: meta if: github.event_name != 'pull_request' uses: docker/metadata-action@v5 with: images: | quay.io/go-skynet/local-ai localai/localai tags: | type=ref,event=branch type=semver,pattern={{raw}} type=sha flavor: | latest=${{ inputs.tag-latest }} suffix=${{ inputs.tag-suffix }} - name: Docker meta for PR id: meta_pull_request if: github.event_name == 'pull_request' uses: docker/metadata-action@v5 with: images: | ttl.sh/localai-ci-pr-${{ github.event.number }} tags: | type=ref,event=branch type=semver,pattern={{raw}} type=sha flavor: | latest=${{ inputs.tag-latest }} suffix=${{ inputs.tag-suffix }} - name: Docker meta AIO (quay.io) if: inputs.aio != '' id: meta_aio uses: docker/metadata-action@v5 with: images: | quay.io/go-skynet/local-ai tags: | type=ref,event=branch type=semver,pattern={{raw}} flavor: | latest=${{ inputs.tag-latest }} suffix=${{ inputs.aio }} - name: Docker meta AIO (dockerhub) if: inputs.aio != '' id: meta_aio_dockerhub uses: docker/metadata-action@v5 with: images: | localai/localai tags: | type=ref,event=branch type=semver,pattern={{raw}} flavor: | suffix=${{ inputs.aio }} - name: Set up QEMU uses: docker/setup-qemu-action@master with: platforms: all - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@master - name: Login to DockerHub if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: username: ${{ secrets.dockerUsername }} password: ${{ secrets.dockerPassword }} - name: Login to DockerHub if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: quay.io username: ${{ secrets.quayUsername }} password: ${{ secrets.quayPassword }} - name: Build and push uses: docker/build-push-action@v6 if: github.event_name != 'pull_request' with: builder: ${{ steps.buildx.outputs.name }} # The build-args MUST be an EXACT match between the image cache and other workflow steps that want to use that cache. # This means that even the MAKEFLAGS have to be an EXACT match. # If the build-args are not an EXACT match, it will result in a cache miss, which will require GRPC to be built from scratch. # This is why some build args like GRPC_VERSION and MAKEFLAGS are hardcoded build-args: | BUILD_TYPE=${{ inputs.build-type }} CUDA_MAJOR_VERSION=${{ inputs.cuda-major-version }} CUDA_MINOR_VERSION=${{ inputs.cuda-minor-version }} FFMPEG=${{ inputs.ffmpeg }} IMAGE_TYPE=${{ inputs.image-type }} BASE_IMAGE=${{ inputs.base-image }} GRPC_BASE_IMAGE=${{ inputs.grpc-base-image || inputs.base-image }} GRPC_MAKEFLAGS=--jobs=4 --output-sync=target GRPC_VERSION=v1.65.0 MAKEFLAGS=${{ inputs.makeflags }} context: . file: ./Dockerfile cache-from: type=gha platforms: ${{ inputs.platforms }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} ### Start testing image - name: Build and push uses: docker/build-push-action@v6 if: github.event_name == 'pull_request' with: builder: ${{ steps.buildx.outputs.name }} # The build-args MUST be an EXACT match between the image cache and other workflow steps that want to use that cache. # This means that even the MAKEFLAGS have to be an EXACT match. # If the build-args are not an EXACT match, it will result in a cache miss, which will require GRPC to be built from scratch. # This is why some build args like GRPC_VERSION and MAKEFLAGS are hardcoded build-args: | BUILD_TYPE=${{ inputs.build-type }} CUDA_MAJOR_VERSION=${{ inputs.cuda-major-version }} CUDA_MINOR_VERSION=${{ inputs.cuda-minor-version }} FFMPEG=${{ inputs.ffmpeg }} IMAGE_TYPE=${{ inputs.image-type }} BASE_IMAGE=${{ inputs.base-image }} GRPC_BASE_IMAGE=${{ inputs.grpc-base-image || inputs.base-image }} GRPC_MAKEFLAGS=--jobs=4 --output-sync=target GRPC_VERSION=v1.65.0 MAKEFLAGS=${{ inputs.makeflags }} context: . file: ./Dockerfile cache-from: type=gha platforms: ${{ inputs.platforms }} push: true tags: ${{ steps.meta_pull_request.outputs.tags }} labels: ${{ steps.meta_pull_request.outputs.labels }} - name: Testing image if: github.event_name == 'pull_request' run: | echo "Image is available at ttl.sh/localai-ci-pr-${{ github.event.number }}:${{ steps.meta_pull_request.outputs.version }}" >> $GITHUB_STEP_SUMMARY ## End testing image - name: Build and push AIO image if: inputs.aio != '' uses: docker/build-push-action@v6 with: builder: ${{ steps.buildx.outputs.name }} build-args: | BASE_IMAGE=quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} MAKEFLAGS=${{ inputs.makeflags }} context: . file: ./Dockerfile.aio platforms: ${{ inputs.platforms }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta_aio.outputs.tags }} labels: ${{ steps.meta_aio.outputs.labels }} - name: Build and push AIO image (dockerhub) if: inputs.aio != '' uses: docker/build-push-action@v6 with: builder: ${{ steps.buildx.outputs.name }} build-args: | BASE_IMAGE=localai/localai:${{ steps.meta.outputs.version }} MAKEFLAGS=${{ inputs.makeflags }} context: . file: ./Dockerfile.aio platforms: ${{ inputs.platforms }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta_aio_dockerhub.outputs.tags }} labels: ${{ steps.meta_aio_dockerhub.outputs.labels }} - name: Latest tag # run this on branches, when it is a tag and there is a latest-image defined if: github.event_name != 'pull_request' && inputs.latest-image != '' && github.ref_type == 'tag' run: | docker pull localai/localai:${{ steps.meta.outputs.version }} docker tag localai/localai:${{ steps.meta.outputs.version }} localai/localai:${{ inputs.latest-image }} docker push localai/localai:${{ inputs.latest-image }} docker pull quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} docker tag quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} quay.io/go-skynet/local-ai:${{ inputs.latest-image }} docker push quay.io/go-skynet/local-ai:${{ inputs.latest-image }} - name: Latest AIO tag # run this on branches, when it is a tag and there is a latest-image defined if: github.event_name != 'pull_request' && inputs.latest-image-aio != '' && github.ref_type == 'tag' run: | docker pull localai/localai:${{ steps.meta_aio_dockerhub.outputs.version }} docker tag localai/localai:${{ steps.meta_aio_dockerhub.outputs.version }} localai/localai:${{ inputs.latest-image-aio }} docker push localai/localai:${{ inputs.latest-image-aio }} docker pull quay.io/go-skynet/local-ai:${{ steps.meta_aio.outputs.version }} docker tag quay.io/go-skynet/local-ai:${{ steps.meta_aio.outputs.version }} quay.io/go-skynet/local-ai:${{ inputs.latest-image-aio }} docker push quay.io/go-skynet/local-ai:${{ inputs.latest-image-aio }} - name: job summary run: | echo "Built image: ${{ steps.meta.outputs.labels }}" >> $GITHUB_STEP_SUMMARY - name: job summary(AIO) if: inputs.aio != '' run: | echo "Built image: ${{ steps.meta_aio.outputs.labels }}" >> $GITHUB_STEP_SUMMARY