From 2caef17124494b5811b2a4576f046682a3f44413 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 27 Apr 2026 10:38:22 +0800 Subject: [PATCH] Add Docker support and GitHub Actions workflow --- .github/workflows/docker.yml | 61 +++++++++++++++++++++++++++++++++++ backend/Dockerfile | 25 ++++++++++++++ backend/cmd/server/sale.db | Bin 0 -> 233472 bytes docker-compose.yml | 27 ++++++++++++++++ frontend/Dockerfile | 19 +++++++++++ frontend/nginx.conf | 27 ++++++++++++++++ 6 files changed, 159 insertions(+) create mode 100644 .github/workflows/docker.yml create mode 100644 backend/Dockerfile create mode 100644 backend/cmd/server/sale.db create mode 100644 docker-compose.yml create mode 100644 frontend/Dockerfile create mode 100644 frontend/nginx.conf diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..867c788 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,61 @@ +name: Build and Push Docker Images + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + 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 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=sha,prefix= + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push backend image + uses: docker/build-push-action@v5 + with: + context: ./backend + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend:${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build and push frontend image + uses: docker/build-push-action@v5 + with: + context: ./frontend + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..22eebe2 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,25 @@ +FROM golang:1.21-alpine AS builder + +WORKDIR /app + +RUN apk add --no-cache git + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server ./cmd/server + +FROM alpine:latest + +WORKDIR /app + +RUN apk add --no-cache ca-certificates tzdata + +COPY --from=builder /app/server . +COPY --from=builder /app/uploads ./uploads + +EXPOSE 8080 + +CMD ["./server"] diff --git a/backend/cmd/server/sale.db b/backend/cmd/server/sale.db new file mode 100644 index 0000000000000000000000000000000000000000..1d935886066e0ff8ffa622c5d9447b4f0fbbad3c GIT binary patch literal 233472 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