feat: 使用github workflow

This commit is contained in:
sylarchen1389 2025-11-15 09:01:45 +08:00
parent 88396a16e6
commit 4f6de98909
20 changed files with 3340 additions and 722 deletions

View file

@ -1,7 +1,12 @@
{
"permissions": {
"allow": [
"Bash(tree:*)"
"Bash(tree:*)",
"Bash(pip show:*)",
"Bash(git rev-parse:*)",
"Bash(chmod:*)",
"Bash(test:*)",
"Bash(lsof:*)"
],
"deny": [],
"ask": []

View file

@ -1,11 +1,10 @@
name: Create and publish Docker images with specific build args
name: Build and Push Docker Image (Production)
on:
workflow_dispatch:
push:
branches:
- main
- dev
tags:
- v*
@ -13,429 +12,14 @@ env:
REGISTRY: ghcr.io
jobs:
build-main-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-${{ matrix.platform }}-
latest=false
- name: Build Docker image (latest)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-main-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-cuda-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (cuda tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-cuda-${{ matrix.platform }}-
latest=false
- name: Build Docker image (cuda)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_CUDA=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-cuda-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-cuda126-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (cuda126 tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-cuda126-${{ matrix.platform }}-
latest=false
- name: Build Docker image (cuda126)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_CUDA=true
USE_CUDA_VER=cu126
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-cuda126-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-ollama-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (ollama tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=ollama
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-ollama,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-ollama-${{ matrix.platform }}-
latest=false
- name: Build Docker image (ollama)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_OLLAMA=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-ollama-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-slim-image:
runs-on: ${{ matrix.runner }}
name: Build Slim Image (amd64)
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
@ -443,28 +27,20 @@ jobs:
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to the Container registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker images (slim tag)
- name: Extract metadata for Docker images
id: meta
uses: docker/metadata-action@v5
with:
@ -489,312 +65,37 @@ jobs:
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-slim-${{ matrix.platform }}-
prefix=cache-slim-linux-amd64-
latest=false
- name: Build Docker image (slim)
- name: Build and push Docker image (slim)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_SLIM=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-slim-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge-main-images:
runs-on: ubuntu-latest
needs: [build-main-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-main-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-cuda-images:
runs-on: ubuntu-latest
needs: [build-cuda-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
- name: Output image tags
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-cuda-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-cuda126-images:
runs-on: ubuntu-latest
needs: [build-cuda126-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-cuda126-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-ollama-images:
runs-on: ubuntu-latest
needs: [build-ollama-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-ollama-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default ollama tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=ollama
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-ollama,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-slim-images:
runs-on: ubuntu-latest
needs: [build-slim-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-slim-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default slim tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=slim
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-slim,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
echo "## 🐳 Docker 镜像构建成功" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**镜像标签:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**拉取命令:**" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.FULL_IMAGE_NAME }}:slim" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

800
.github/workflows_bak/docker-build.yaml vendored Normal file
View file

@ -0,0 +1,800 @@
name: Create and publish Docker images with specific build args
on:
workflow_dispatch:
push:
branches:
- main
- dev
tags:
- v*
env:
REGISTRY: ghcr.io
jobs:
build-main-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-${{ matrix.platform }}-
latest=false
- name: Build Docker image (latest)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-main-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-cuda-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (cuda tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-cuda-${{ matrix.platform }}-
latest=false
- name: Build Docker image (cuda)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_CUDA=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-cuda-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-cuda126-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (cuda126 tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-cuda126-${{ matrix.platform }}-
latest=false
- name: Build Docker image (cuda126)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_CUDA=true
USE_CUDA_VER=cu126
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-cuda126-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-ollama-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (ollama tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=ollama
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-ollama,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-ollama-${{ matrix.platform }}-
latest=false
- name: Build Docker image (ollama)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_OLLAMA=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-ollama-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-slim-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- 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 for Docker images (slim tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=slim
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-slim,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-slim-${{ matrix.platform }}-
latest=false
- name: Build Docker image (slim)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_SLIM=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-slim-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge-main-images:
runs-on: ubuntu-latest
needs: [build-main-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-main-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-cuda-images:
runs-on: ubuntu-latest
needs: [build-cuda-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-cuda-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-cuda126-images:
runs-on: ubuntu-latest
needs: [build-cuda126-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-cuda126-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-ollama-images:
runs-on: ubuntu-latest
needs: [build-ollama-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-ollama-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default ollama tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=ollama
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-ollama,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-slim-images:
runs-on: ubuntu-latest
needs: [build-slim-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v5
with:
pattern: digests-slim-*
path: /tmp/digests
merge-multiple: true
- 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 for Docker images (default slim tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=slim
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-slim,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}

1
.gitignore vendored
View file

@ -40,6 +40,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
data
# PyInstaller
# Usually these files are written by a python script from a template

View file

@ -27,7 +27,7 @@ FROM --platform=$BUILDPLATFORM node:22-alpine3.20 AS build
ARG BUILD_HASH
# Set Node.js options (heap limit Allocation failed - JavaScript heap out of memory)
# ENV NODE_OPTIONS="--max-old-space-size=4096"
ENV NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /app

1088
docs/DOCKER-DEPLOYMENT.md Normal file

File diff suppressed because it is too large Load diff

676
docs/LOCAL-PUSH-GUIDE.md Normal file
View file

@ -0,0 +1,676 @@
# 本地镜像构建与推送指南
本指南介绍如何在本地构建 Docker 镜像并手动推送到 GitHub Container Registry (GHCR)。
## 当前仓库信息
- **仓库**: `ai-friend-coming/open-webui-next`
- **镜像仓库**: `ghcr.io/ai-friend-coming/open-webui-next`
- **当前分支**: `main`
- **当前 commit**: `88396a16e`
---
## 前置准备
### 1. 登录 GitHub Container Registry
#### 创建 Personal Access Token (PAT)
1. 访问 https://github.com/settings/tokens
2. 点击 "Generate new token" → "Generate new token (classic)"
3. 设置权限:
- `write:packages` - 推送容器镜像
- `read:packages` - 拉取容器镜像
- `delete:packages` - (可选) 删除镜像
4. 生成并保存 Token
#### 登录 GHCR
```bash
# 方式 1: 使用 PAT 登录 (推荐)
export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin
# 方式 2: 交互式登录
docker login ghcr.io -u ai-friend-coming
# Password: [输入 PAT]
```
成功登录后会显示:
```
Login Succeeded
```
### 2. 验证 Docker 环境
```bash
# 检查 Docker 版本
docker --version
# 推荐: Docker version 24.0.0 或更高
# 检查 Buildx 插件
docker buildx version
# 推荐: v0.11.0 或更高
# 创建 Buildx builder (如果不存在)
docker buildx create --name multiarch-builder --use
docker buildx inspect --bootstrap
```
---
## 构建与推送流程
### 方式一: 模拟 GitHub Actions 流程 (推荐)
完全模拟 `.github/workflows/docker-build.yaml` 的构建流程:
```bash
#!/bin/bash
# build-and-push.sh
set -e # 遇到错误立即退出
# ============ 配置变量 ============
REGISTRY="ghcr.io"
IMAGE_NAME="ai-friend-coming/open-webui-next"
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE_NAME}"
# 获取 Git 信息
BUILD_HASH=$(git rev-parse HEAD)
SHORT_HASH=$(git rev-parse --short HEAD)
BRANCH=$(git branch --show-current)
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
echo "========================================="
echo "构建信息:"
echo " 仓库: ${IMAGE_NAME}"
echo " 分支: ${BRANCH}"
echo " Commit: ${SHORT_HASH}"
echo " 时间: ${TIMESTAMP}"
echo "========================================="
# ============ 镜像标签生成 ============
TAGS=(
"${FULL_IMAGE_NAME}:slim" # 主标签
"${FULL_IMAGE_NAME}:${BRANCH}-slim" # 分支标签
"${FULL_IMAGE_NAME}:git-${SHORT_HASH}-slim" # Git commit 标签
"${FULL_IMAGE_NAME}:${TIMESTAMP}-slim" # 时间戳标签
)
# 如果在 main 分支,添加 latest-slim 标签
if [ "$BRANCH" = "main" ]; then
TAGS+=("${FULL_IMAGE_NAME}:latest-slim")
fi
# 构建标签参数
TAG_ARGS=""
for tag in "${TAGS[@]}"; do
TAG_ARGS="${TAG_ARGS} -t ${tag}"
done
echo ""
echo "将构建以下标签:"
for tag in "${TAGS[@]}"; do
echo " - ${tag}"
done
echo ""
# ============ 构建镜像 ============
echo "开始构建镜像..."
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${BUILD_HASH}" \
--build-arg USE_SLIM=true \
${TAG_ARGS} \
--load \
.
echo ""
echo "✅ 镜像构建成功!"
echo ""
# ============ 推送镜像 ============
read -p "是否推送镜像到 GHCR? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "开始推送镜像..."
for tag in "${TAGS[@]}"; do
echo "推送: ${tag}"
docker push "${tag}"
done
echo ""
echo "✅ 所有镜像推送成功!"
echo ""
echo "拉取命令:"
echo " docker pull ${FULL_IMAGE_NAME}:slim"
echo ""
echo "查看镜像:"
echo " https://github.com/${IMAGE_NAME}/pkgs/container/open-webui-next"
else
echo "跳过推送"
fi
# ============ 清理 ============
echo ""
read -p "是否清理本地构建缓存? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "清理构建缓存..."
docker builder prune -f
echo "✅ 缓存清理完成"
fi
```
**使用方法**:
```bash
# 添加执行权限
chmod +x build-and-push.sh
# 执行构建
./build-and-push.sh
```
### 方式二: 手动分步执行
#### 1. 构建镜像
```bash
# 获取当前 commit SHA
BUILD_HASH=$(git rev-parse HEAD)
SHORT_HASH=$(git rev-parse --short HEAD)
# 构建镜像
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${BUILD_HASH}" \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
-t ghcr.io/ai-friend-coming/open-webui-next:main-slim \
-t ghcr.io/ai-friend-coming/open-webui-next:git-${SHORT_HASH}-slim \
--load \
.
```
**构建参数说明**:
- `--platform linux/amd64`: 构建 x86_64 架构镜像
- `--build-arg BUILD_HASH`: 传入 Git commit SHA
- `--build-arg USE_SLIM=true`: 构建精简版 (不预装模型)
- `-t`: 指定镜像标签 (可以多个)
- `--load`: 加载到本地 Docker (用于单平台构建)
#### 2. 验证镜像
```bash
# 查看镜像大小
docker images | grep open-webui-next
# 查看镜像详细信息
docker inspect ghcr.io/ai-friend-coming/open-webui-next:slim
# 测试运行
docker run --rm -p 8080:8080 ghcr.io/ai-friend-coming/open-webui-next:slim
```
#### 3. 推送镜像
```bash
# 推送所有标签
docker push ghcr.io/ai-friend-coming/open-webui-next:slim
docker push ghcr.io/ai-friend-coming/open-webui-next:main-slim
docker push ghcr.io/ai-friend-coming/open-webui-next:git-${SHORT_HASH}-slim
```
或批量推送:
```bash
# 批量推送
docker images | grep "ghcr.io/ai-friend-coming/open-webui-next" | awk '{print $1":"$2}' | xargs -I {} docker push {}
```
#### 4. 验证推送
```bash
# 从 GHCR 拉取验证
docker pull ghcr.io/ai-friend-coming/open-webui-next:slim
# 访问 GitHub Packages 页面
# https://github.com/ai-friend-coming/open-webui-next/pkgs/container/open-webui-next
```
---
## 构建不同镜像变体
### Slim 版本 (默认, 推荐)
```bash
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
--load \
.
```
**特点**:
- 镜像较小 (~7.8GB)
- 首次运行时自动下载 AI 模型
- 适合生产环境
### 标准版本 (预装模型)
```bash
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=false \
-t ghcr.io/ai-friend-coming/open-webui-next:latest \
--load \
.
```
**特点**:
- 镜像较大 (~10GB)
- 预装 AI 模型,启动更快
- 适合离线环境
### CUDA 版本 (GPU 加速)
```bash
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_CUDA=true \
--build-arg USE_CUDA_VER=cu128 \
-t ghcr.io/ai-friend-coming/open-webui-next:cuda \
--load \
.
```
**特点**:
- 支持 NVIDIA GPU 加速
- 需要宿主机安装 NVIDIA Docker runtime
- 镜像更大 (~15GB)
---
## 高级功能
### 1. 多架构构建 (amd64 + arm64)
```bash
# 创建 multiarch builder
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
# 构建并推送多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
--push \
.
```
**注意**:
- 多架构构建会自动推送 (不支持 `--load`)
- ARM64 构建可能需要 1-2 小时
### 2. 使用缓存加速构建
```bash
# 第一次构建: 导出缓存
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
--cache-to type=registry,ref=ghcr.io/ai-friend-coming/open-webui-next:cache-slim-amd64 \
--load \
.
# 后续构建: 使用缓存
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
--cache-from type=registry,ref=ghcr.io/ai-friend-coming/open-webui-next:cache-slim-amd64 \
--load \
.
```
**效果**: 构建时间从 5 分钟降低到 1-2 分钟
### 3. 本地缓存 (更快)
```bash
# 使用本地缓存
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH=$(git rev-parse HEAD) \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
--cache-to type=local,dest=/tmp/docker-cache \
--cache-from type=local,src=/tmp/docker-cache \
--load \
.
```
---
## 故障排查
### 1. 构建内存不足
**错误**:
```
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
```
**解决方案**:
- ✅ 确认 Dockerfile 第 30 行已取消注释: `ENV NODE_OPTIONS="--max-old-space-size=4096"`
- ✅ 增加 Docker 内存限制: Docker Desktop → Settings → Resources → Memory (建议 8GB+)
### 2. 推送权限被拒绝
**错误**:
```
denied: permission_denied: write_package
```
**解决方案**:
```bash
# 检查登录状态
docker info | grep Username
# 重新登录
docker logout ghcr.io
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin
# 确认 PAT 有 write:packages 权限
```
### 3. 镜像推送超时
**错误**:
```
error: timeout exceeded
```
**解决方案**:
```bash
# 增加 Docker 推送超时
export DOCKER_CLIENT_TIMEOUT=300
export COMPOSE_HTTP_TIMEOUT=300
# 或分别推送每个标签
docker push ghcr.io/ai-friend-coming/open-webui-next:slim
```
### 4. Buildx 不可用
**错误**:
```
ERROR: buildx: command not found
```
**解决方案**:
```bash
# 更新 Docker Desktop 到最新版本
# 或手动安装 Buildx 插件
mkdir -p ~/.docker/cli-plugins
curl -Lo ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/v0.11.2/buildx-v0.11.2.linux-amd64
chmod +x ~/.docker/cli-plugins/docker-buildx
```
---
## 清理与维护
### 清理本地镜像
```bash
# 删除 dangling 镜像
docker image prune -f
# 删除所有未使用的镜像
docker image prune -a -f
# 删除特定镜像
docker rmi ghcr.io/ai-friend-coming/open-webui-next:slim
```
### 清理构建缓存
```bash
# 清理 Buildx 缓存
docker buildx prune -f
# 清理所有 Docker 缓存 (谨慎使用)
docker system prune -a --volumes -f
```
### 查看镜像层信息
```bash
# 使用 dive 工具分析镜像
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest \
ghcr.io/ai-friend-coming/open-webui-next:slim
```
---
## 自动化脚本示例
### 完整的 CI/CD 本地模拟脚本
保存为 `scripts/local-build.sh`:
```bash
#!/bin/bash
# scripts/local-build.sh
# 完整的本地构建、测试、推送流程
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
echo_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
echo_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 配置
REGISTRY="ghcr.io"
IMAGE_NAME="ai-friend-coming/open-webui-next"
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE_NAME}"
VARIANT="slim"
# Git 信息
BUILD_HASH=$(git rev-parse HEAD)
SHORT_HASH=$(git rev-parse --short HEAD)
BRANCH=$(git branch --show-current)
# 检查工作目录
if [ ! -f "Dockerfile" ]; then
echo_error "请在项目根目录运行此脚本"
exit 1
fi
# 检查未提交的更改
if [ -n "$(git status --porcelain)" ]; then
echo_warn "存在未提交的更改:"
git status --short
read -p "继续构建? (y/n): " -n 1 -r
echo
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
fi
echo_info "========================================="
echo_info "构建配置:"
echo_info " 仓库: ${IMAGE_NAME}"
echo_info " 分支: ${BRANCH}"
echo_info " Commit: ${SHORT_HASH}"
echo_info " 变体: ${VARIANT}"
echo_info "========================================="
# 1. 构建镜像
echo_info "步骤 1/5: 构建镜像..."
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${BUILD_HASH}" \
--build-arg USE_SLIM=true \
-t ${FULL_IMAGE_NAME}:${VARIANT} \
-t ${FULL_IMAGE_NAME}:git-${SHORT_HASH}-${VARIANT} \
--load \
.
# 2. 验证镜像大小
echo_info "步骤 2/5: 验证镜像..."
IMAGE_SIZE=$(docker images ${FULL_IMAGE_NAME}:${VARIANT} --format "{{.Size}}")
echo_info " 镜像大小: ${IMAGE_SIZE}"
# 3. 测试镜像
echo_info "步骤 3/5: 测试镜像..."
CONTAINER_ID=$(docker run -d -p 8081:8080 ${FULL_IMAGE_NAME}:${VARIANT})
echo_info " 测试容器 ID: ${CONTAINER_ID}"
# 等待健康检查
echo_info " 等待服务启动 (最多 60 秒)..."
for i in {1..60}; do
if curl -sf http://localhost:8081/health > /dev/null 2>&1; then
echo_info " ✅ 健康检查通过"
break
fi
sleep 1
[ $i -eq 60 ] && echo_error "健康检查超时" && docker logs ${CONTAINER_ID} && exit 1
done
# 清理测试容器
docker stop ${CONTAINER_ID} > /dev/null
docker rm ${CONTAINER_ID} > /dev/null
echo_info " 测试容器已清理"
# 4. 推送镜像
echo_info "步骤 4/5: 推送镜像到 GHCR..."
read -p "确认推送? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# 检查登录状态
if ! docker info | grep -q "Username: ai-friend-coming"; then
echo_error "未登录 GHCR,请先登录:"
echo " echo \$CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin"
exit 1
fi
docker push ${FULL_IMAGE_NAME}:${VARIANT}
docker push ${FULL_IMAGE_NAME}:git-${SHORT_HASH}-${VARIANT}
echo_info " ✅ 推送成功"
else
echo_warn "跳过推送"
fi
# 5. 清理
echo_info "步骤 5/5: 清理..."
docker builder prune -f > /dev/null
echo_info " 构建缓存已清理"
echo_info "========================================="
echo_info "✅ 构建流程完成!"
echo_info ""
echo_info "拉取命令:"
echo_info " docker pull ${FULL_IMAGE_NAME}:${VARIANT}"
echo_info ""
echo_info "查看镜像:"
echo_info " https://github.com/${IMAGE_NAME}/pkgs/container/open-webui-next"
echo_info "========================================="
```
**使用方法**:
```bash
chmod +x scripts/local-build.sh
./scripts/local-build.sh
```
---
## 最佳实践
### 1. 构建前检查清单
- [ ] 代码已提交到 Git
- [ ] Docker 有足够内存 (8GB+)
- [ ] 已登录 GHCR
- [ ] 磁盘空间充足 (20GB+)
### 2. 标签命名规范
```bash
# 生产环境
ghcr.io/ai-friend-coming/open-webui-next:v1.2.3-slim
# 测试环境
ghcr.io/ai-friend-coming/open-webui-next:dev-slim
# 特性分支
ghcr.io/ai-friend-coming/open-webui-next:feature-auth-slim
```
### 3. 安全建议
- 不要在脚本中硬编码 PAT
- 使用环境变量: `export CR_PAT=xxx`
- 定期轮换 PAT (90 天)
- 使用 `.gitignore` 排除敏感文件
### 4. 性能优化
- 使用 `--cache-from` 复用缓存
- 本地缓存构建结果到 `/tmp`
- 使用 SSD 存储 Docker 数据
- 增大 Docker 内存限制
---
## 常用命令速查
```bash
# 构建
docker buildx build -t IMAGE:TAG --load .
# 推送
docker push IMAGE:TAG
# 拉取
docker pull IMAGE:TAG
# 登录
echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
# 清理
docker system prune -a -f
# 查看镜像
docker images | grep open-webui-next
# 测试镜像
docker run --rm -p 8080:8080 IMAGE:TAG
```
---
**最后更新**: 2024-11-14

322
scripts/README.md Normal file
View file

@ -0,0 +1,322 @@
# 构建脚本使用指南
本目录包含用于本地构建和推送 Docker 镜像的自动化脚本。
## 脚本列表
### 1. `build-and-push.sh` - 完整构建和推送流程 (推荐)
**功能**: 完整的构建、测试、推送流程,包含健康检查
**使用方法**:
```bash
# 1. 登录 GHCR (如需推送)
export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin
# 2. 运行脚本
./scripts/build-and-push.sh
```
**流程**:
1. 检查 Git 状态和未提交更改
2. 构建 Docker 镜像 (slim 版本)
3. 验证镜像大小和 ID
4. 运行健康检查测试 (可选)
5. 推送镜像到 GHCR (需确认)
6. 清理构建缓存 (可选)
**适用场景**: 正式发布前的完整测试和推送
---
### 2. `quick-build.sh` - 快速本地构建
**功能**: 快速构建镜像用于本地测试,不推送
**使用方法**:
```bash
./scripts/quick-build.sh
```
**特点**:
- 无交互式确认
- 仅构建,不推送
- 构建速度快 (如有缓存)
**适用场景**: 本地开发和快速测试
---
### 3. `simulate-workflow.sh` - 模拟 GitHub Actions
**功能**: 完整模拟 `.github/workflows/docker-build.yaml` 的执行流程
**使用方法**:
```bash
# 设置 CR_PAT (可选)
export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN
# 运行模拟
./scripts/simulate-workflow.sh
```
**特点**:
- 模拟 GitHub Actions 环境变量
- 创建独立的 Buildx builder
- 使用 registry 缓存
- 输出格式与 GitHub Actions 一致
**适用场景**:
- 测试 workflow 配置
- 在推送代码前验证构建流程
- 排查 CI/CD 问题
---
## 使用示例
### 场景 1: 本地快速测试
```bash
# 1. 快速构建
./scripts/quick-build.sh
# 2. 运行测试
docker run -d -p 8080:8080 ghcr.io/ai-friend-coming/open-webui-next:slim
# 3. 验证
curl http://localhost:8080/health
```
### 场景 2: 发布新版本
```bash
# 1. 确保代码已提交
git add .
git commit -m "feat: add new feature"
git push
# 2. 登录 GHCR
export CR_PAT=ghp_xxxxxxxxxxxx
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin
# 3. 构建和推送
./scripts/build-and-push.sh
# 按提示操作: 运行健康检查 → 确认推送 → 清理缓存
# 4. 验证推送成功
docker pull ghcr.io/ai-friend-coming/open-webui-next:slim
```
### 场景 3: 测试 GitHub Actions workflow
```bash
# 1. 模拟 workflow 执行
export CR_PAT=ghp_xxxxxxxxxxxx
./scripts/simulate-workflow.sh
# 2. 查看构建结果
docker images | grep open-webui-next
# 3. 如果成功,推送代码触发真实 workflow
git push origin main
```
---
## 环境要求
### 必需软件
- **Docker**: 24.0.0+
- **Docker Buildx**: v0.11.0+
- **Git**: 任意版本
- **Bash**: 4.0+
### 系统要求
- **内存**: 建议 8GB+
- **磁盘空间**: 至少 20GB 可用空间
- **网络**: 需要访问 ghcr.io
### Docker 配置
确保 Docker 有足够的资源:
```bash
# Docker Desktop 配置 (推荐):
# - Memory: 8GB
# - Swap: 2GB
# - Disk image size: 64GB
```
---
## 常见问题
### 1. 构建失败 - 内存不足
**错误信息**:
```
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
```
**解决方案**:
- 确认 `Dockerfile` 第 30 行已启用: `ENV NODE_OPTIONS="--max-old-space-size=4096"`
- 增加 Docker Desktop 内存限制到 8GB+
### 2. 推送失败 - 未登录
**错误信息**:
```
unauthorized: authentication required
```
**解决方案**:
```bash
# 设置 PAT
export CR_PAT=ghp_your_token_here
# 登录 GHCR
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin
```
### 3. 脚本无执行权限
**错误信息**:
```
Permission denied
```
**解决方案**:
```bash
chmod +x scripts/*.sh
```
### 4. Buildx 不可用
**错误信息**:
```
ERROR: buildx: command not found
```
**解决方案**:
```bash
# 安装 Buildx 插件
docker buildx install
# 或更新 Docker Desktop 到最新版本
```
---
## 标签规则
所有脚本都会生成以下标签:
| 标签格式 | 示例 | 说明 |
|---------|------|------|
| `slim` | `ghcr.io/ai-friend-coming/open-webui-next:slim` | 主标签 (main 分支) |
| `latest-slim` | `ghcr.io/ai-friend-coming/open-webui-next:latest-slim` | 最新版本 (仅 main 分支) |
| `{branch}-slim` | `ghcr.io/ai-friend-coming/open-webui-next:main-slim` | 分支标签 |
| `git-{sha}-slim` | `ghcr.io/ai-friend-coming/open-webui-next:git-88396a1-slim` | Git commit 标签 |
---
## 安全最佳实践
### PAT (Personal Access Token) 管理
1. **权限设置**: 仅授予 `read:packages``write:packages`
2. **存储位置**: 使用环境变量,不要硬编码到脚本
3. **轮换周期**: 建议每 90 天轮换一次
4. **作用域**: 为不同用途创建不同的 PAT
### 环境变量设置
```bash
# 临时设置 (当前会话)
export CR_PAT=ghp_xxxxxxxxxxxx
# 永久设置 (添加到 ~/.bashrc 或 ~/.zshrc)
echo 'export CR_PAT=ghp_xxxxxxxxxxxx' >> ~/.bashrc
source ~/.bashrc
```
**注意**: 不要提交 PAT 到 Git 仓库
---
## 性能优化
### 使用构建缓存
```bash
# 第一次构建会较慢 (5-10 分钟)
./scripts/build-and-push.sh
# 后续构建会使用缓存 (1-2 分钟)
# 前提: 没有清理缓存
```
### 并行构建 (高级)
如果需要同时构建多个变体:
```bash
# 构建 slim 和 cuda 版本
docker buildx build --build-arg USE_SLIM=true -t IMAGE:slim . &
docker buildx build --build-arg USE_CUDA=true -t IMAGE:cuda . &
wait
```
---
## 清理命令
### 清理所有本地镜像
```bash
# 删除所有 open-webui-next 镜像
docker images | grep open-webui-next | awk '{print $3}' | xargs docker rmi -f
# 清理悬空镜像
docker image prune -f
# 清理所有未使用的镜像
docker image prune -a -f
```
### 清理构建缓存
```bash
# 清理 Buildx 缓存
docker buildx prune -f
# 清理所有 Docker 数据 (谨慎使用)
docker system prune -a --volumes -f
```
---
## 相关文档
- [本地推送完整指南](../docs/LOCAL-PUSH-GUIDE.md)
- [Docker 部署指南](../docs/DOCKER-DEPLOYMENT.md)
- [GitHub Actions Workflow](../.github/workflows/docker-build.yaml)
---
## 获取帮助
如果遇到问题:
1. 查看脚本输出的错误信息
2. 参考本文档的"常见问题"部分
3. 查看详细文档: `docs/LOCAL-PUSH-GUIDE.md`
4. 提交 Issue: https://github.com/ai-friend-coming/open-webui-next/issues
---
**最后更新**: 2024-11-14

215
scripts/build-and-push.sh Executable file
View file

@ -0,0 +1,215 @@
#!/bin/bash
# build-and-push.sh - 本地构建并推送镜像到 GHCR
# 使用方法: ./scripts/build-and-push.sh
set -e # 遇到错误立即退出
# ============ 颜色输出 ============
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
echo_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
echo_error() { echo -e "${RED}[ERROR]${NC} $1"; }
echo_step() { echo -e "${BLUE}[STEP]${NC} $1"; }
# ============ 配置变量 ============
REGISTRY="ghcr.io"
IMAGE_NAME="ai-friend-coming/open-webui-next"
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE_NAME}"
# 获取 Git 信息
BUILD_HASH=$(git rev-parse HEAD)
SHORT_HASH=$(git rev-parse --short HEAD)
BRANCH=$(git branch --show-current)
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
# 检查工作目录
if [ ! -f "Dockerfile" ]; then
echo_error "请在项目根目录运行此脚本"
exit 1
fi
echo_info "========================================="
echo_info "构建信息:"
echo_info " 仓库: ${IMAGE_NAME}"
echo_info " 分支: ${BRANCH}"
echo_info " Commit: ${SHORT_HASH} (${BUILD_HASH:0:40}...)"
echo_info " 时间: ${TIMESTAMP}"
echo_info "========================================="
echo ""
# 检查未提交的更改
if [ -n "$(git status --porcelain)" ]; then
echo_warn "存在未提交的更改:"
git status --short
echo ""
read -p "继续构建? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo_info "已取消"
exit 0
fi
fi
# ============ 镜像标签生成 ============
TAGS=(
"${FULL_IMAGE_NAME}:slim" # 主标签
"${FULL_IMAGE_NAME}:${BRANCH}-slim" # 分支标签
"${FULL_IMAGE_NAME}:git-${SHORT_HASH}-slim" # Git commit 标签
)
# 如果在 main 分支,添加 latest-slim 标签
if [ "$BRANCH" = "main" ]; then
TAGS+=("${FULL_IMAGE_NAME}:latest-slim")
fi
# 构建标签参数
TAG_ARGS=""
for tag in "${TAGS[@]}"; do
TAG_ARGS="${TAG_ARGS} -t ${tag}"
done
echo_info "将构建以下标签:"
for tag in "${TAGS[@]}"; do
echo " - ${tag}"
done
echo ""
# ============ 构建镜像 ============
echo_step "步骤 1/4: 构建 Docker 镜像"
echo_info "开始构建镜像 (这可能需要 5-10 分钟)..."
echo ""
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${BUILD_HASH}" \
--build-arg USE_SLIM=true \
${TAG_ARGS} \
--load \
.
echo ""
echo_info "✅ 镜像构建成功!"
echo ""
# ============ 验证镜像 ============
echo_step "步骤 2/4: 验证镜像"
IMAGE_SIZE=$(docker images ${FULL_IMAGE_NAME}:slim --format "{{.Size}}")
IMAGE_ID=$(docker images ${FULL_IMAGE_NAME}:slim --format "{{.ID}}")
echo_info "镜像信息:"
echo " - ID: ${IMAGE_ID}"
echo " - 大小: ${IMAGE_SIZE}"
echo ""
# ============ 测试镜像 ============
echo_step "步骤 3/4: 测试镜像"
read -p "是否运行健康检查测试? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo_info "启动测试容器 (端口 8081)..."
CONTAINER_ID=$(docker run -d -p 8081:8080 ${FULL_IMAGE_NAME}:slim)
echo_info "容器 ID: ${CONTAINER_ID}"
echo ""
echo_info "等待服务启动 (最多 120 秒)..."
HEALTH_CHECK_PASSED=false
for i in {1..120}; do
if curl -sf http://localhost:8081/health > /dev/null 2>&1; then
echo_info "✅ 健康检查通过 (耗时 ${i} 秒)"
HEALTH_CHECK_PASSED=true
break
fi
# 每 10 秒显示一次进度
if [ $((i % 10)) -eq 0 ]; then
echo_info " 等待中... (${i}/120 秒)"
fi
sleep 1
done
if [ "$HEALTH_CHECK_PASSED" = false ]; then
echo_error "健康检查超时!"
echo_error "容器日志:"
docker logs ${CONTAINER_ID} | tail -50
docker stop ${CONTAINER_ID} > /dev/null
docker rm ${CONTAINER_ID} > /dev/null
exit 1
fi
# 清理测试容器
echo_info "清理测试容器..."
docker stop ${CONTAINER_ID} > /dev/null
docker rm ${CONTAINER_ID} > /dev/null
echo ""
else
echo_warn "跳过健康检查"
echo ""
fi
# ============ 推送镜像 ============
echo_step "步骤 4/4: 推送镜像到 GHCR"
echo_info "将推送 ${#TAGS[@]} 个标签到 ${REGISTRY}"
echo ""
read -p "确认推送? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# 检查登录状态
if ! docker info 2>/dev/null | grep -q "Username"; then
echo_error "未登录 GHCR!"
echo_error "请先执行:"
echo " export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN"
echo " echo \$CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin"
exit 1
fi
echo_info "开始推送镜像..."
echo ""
for tag in "${TAGS[@]}"; do
echo_info "推送: ${tag}"
docker push "${tag}"
done
echo ""
echo_info "✅ 所有镜像推送成功!"
echo ""
echo_info "拉取命令:"
echo " docker pull ${FULL_IMAGE_NAME}:slim"
echo ""
echo_info "查看镜像:"
echo " https://github.com/${IMAGE_NAME}/pkgs/container/open-webui-next"
echo ""
else
echo_warn "跳过推送"
echo ""
fi
# ============ 清理 ============
echo_info "清理选项:"
read -p "是否清理本地构建缓存? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo_info "清理构建缓存..."
docker builder prune -f
echo_info "✅ 缓存清理完成"
else
echo_warn "保留构建缓存 (下次构建会更快)"
fi
echo ""
echo_info "========================================="
echo_info "✅ 构建流程完成!"
echo_info "========================================="

29
scripts/quick-build.sh Executable file
View file

@ -0,0 +1,29 @@
#!/bin/bash
# quick-build.sh - 快速本地构建 (不推送)
# 使用方法: ./scripts/quick-build.sh
set -e
# 获取 Git 信息
BUILD_HASH=$(git rev-parse HEAD)
SHORT_HASH=$(git rev-parse --short HEAD)
echo "🏗️ 开始快速构建..."
echo "📋 Commit: ${SHORT_HASH}"
echo ""
# 构建镜像
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${BUILD_HASH}" \
--build-arg USE_SLIM=true \
-t ghcr.io/ai-friend-coming/open-webui-next:slim \
-t ghcr.io/ai-friend-coming/open-webui-next:dev \
--load \
.
echo ""
echo "✅ 构建完成!"
echo ""
echo "🚀 运行命令:"
echo " docker run -d -p 8080:8080 ghcr.io/ai-friend-coming/open-webui-next:slim"

181
scripts/simulate-workflow.sh Executable file
View file

@ -0,0 +1,181 @@
#!/bin/bash
# simulate-workflow.sh - 模拟 GitHub Actions workflow 完整流程
# 使用方法: ./scripts/simulate-workflow.sh
set -e
# 颜色
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo_job() { echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; echo -e "${BLUE}[JOB]${NC} $1"; }
echo_step() { echo -e "${GREEN}[STEP]${NC} $1"; }
echo_info() { echo -e " $1"; }
# ============ 模拟 GitHub Actions 环境变量 ============
export GITHUB_REPOSITORY="ai-friend-coming/open-webui-next"
export GITHUB_SHA=$(git rev-parse HEAD)
export GITHUB_REF=$(git symbolic-ref HEAD)
export GITHUB_REF_NAME=$(git branch --show-current)
export IMAGE_NAME="${GITHUB_REPOSITORY,,}" # 转小写
export FULL_IMAGE_NAME="ghcr.io/${IMAGE_NAME}"
echo_job "Build Slim Image (amd64)"
echo ""
# ============ Step 1: Set repository and image name ============
echo_step "Set repository and image name to lowercase"
echo_info "IMAGE_NAME=${IMAGE_NAME}"
echo_info "FULL_IMAGE_NAME=${FULL_IMAGE_NAME}"
echo ""
# ============ Step 2: Checkout repository ============
echo_step "Checkout repository"
echo_info "Repository: ${GITHUB_REPOSITORY}"
echo_info "Branch: ${GITHUB_REF_NAME}"
echo_info "Commit: ${GITHUB_SHA:0:7}"
echo ""
# ============ Step 3: Set up Docker Buildx ============
echo_step "Set up Docker Buildx"
if ! docker buildx inspect github-actions > /dev/null 2>&1; then
docker buildx create --name github-actions --use
echo_info "Created new builder: github-actions"
else
docker buildx use github-actions
echo_info "Using existing builder: github-actions"
fi
docker buildx inspect --bootstrap
echo ""
# ============ Step 4: Log in to GitHub Container Registry ============
echo_step "Log in to GitHub Container Registry"
echo_info "Registry: ghcr.io"
echo_info "Username: $(whoami)"
if [ -z "$CR_PAT" ]; then
echo -e "${YELLOW}[WARN]${NC} CR_PAT 环境变量未设置,跳过登录"
echo_info "如需推送,请设置: export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN"
SKIP_PUSH=true
else
echo $CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin > /dev/null 2>&1
echo_info "✅ Login Succeeded"
SKIP_PUSH=false
fi
echo ""
# ============ Step 5: Extract metadata for Docker images ============
echo_step "Extract metadata for Docker images"
# 生成标签
if [ "$GITHUB_REF_NAME" = "main" ]; then
TAGS=(
"${FULL_IMAGE_NAME}:slim"
"${FULL_IMAGE_NAME}:latest-slim"
"${FULL_IMAGE_NAME}:${GITHUB_REF_NAME}-slim"
"${FULL_IMAGE_NAME}:git-${GITHUB_SHA:0:7}-slim"
)
else
TAGS=(
"${FULL_IMAGE_NAME}:${GITHUB_REF_NAME}-slim"
"${FULL_IMAGE_NAME}:git-${GITHUB_SHA:0:7}-slim"
)
fi
echo_info "Tags:"
for tag in "${TAGS[@]}"; do
echo_info " - ${tag}"
done
echo ""
# 构建标签参数
TAG_ARGS=""
for tag in "${TAGS[@]}"; do
TAG_ARGS="${TAG_ARGS} --tag ${tag}"
done
# ============ Step 6: Extract metadata for Docker cache ============
echo_step "Extract metadata for Docker cache"
CACHE_TAG="${FULL_IMAGE_NAME}:cache-slim-linux-amd64-${GITHUB_REF_NAME}"
echo_info "Cache: ${CACHE_TAG}"
echo ""
# ============ Step 7: Build and push Docker image ============
echo_step "Build and push Docker image (slim)"
echo_info "Platform: linux/amd64"
echo_info "Build args: BUILD_HASH=${GITHUB_SHA}, USE_SLIM=true"
echo ""
if [ "$SKIP_PUSH" = true ]; then
# 仅构建,不推送
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${GITHUB_SHA}" \
--build-arg USE_SLIM=true \
${TAG_ARGS} \
--cache-from type=registry,ref=${CACHE_TAG} \
--load \
.
echo ""
echo -e "${YELLOW}[WARN]${NC} 跳过推送 (CR_PAT 未设置)"
else
# 构建并推送
read -p "确认推送到 GHCR? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${GITHUB_SHA}" \
--build-arg USE_SLIM=true \
${TAG_ARGS} \
--cache-from type=registry,ref=${CACHE_TAG} \
--cache-to type=registry,ref=${CACHE_TAG},mode=max \
--push \
.
echo ""
echo_info "✅ Image pushed successfully"
else
docker buildx build \
--platform linux/amd64 \
--build-arg BUILD_HASH="${GITHUB_SHA}" \
--build-arg USE_SLIM=true \
${TAG_ARGS} \
--cache-from type=registry,ref=${CACHE_TAG} \
--load \
.
echo ""
echo -e "${YELLOW}[WARN]${NC} 用户取消推送"
fi
fi
echo ""
# ============ Step 8: Inspect image ============
echo_step "Inspect image"
if [ "$SKIP_PUSH" = false ] && [[ $REPLY =~ ^[Yy]$ ]]; then
docker buildx imagetools inspect ${FULL_IMAGE_NAME}:slim
else
docker images | grep open-webui-next | head -5
fi
echo ""
# ============ Step 9: Output image tags ============
echo_step "Output image tags"
echo ""
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}🐳 Docker 镜像构建成功${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo "📦 镜像标签:"
for tag in "${TAGS[@]}"; do
echo " ${tag}"
done
echo ""
echo "🚀 拉取命令:"
echo " docker pull ${FULL_IMAGE_NAME}:slim"
echo ""
echo "🌐 查看镜像:"
echo " https://github.com/${GITHUB_REPOSITORY}/pkgs/container/open-webui-next"
echo ""
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"