feats: deploy with docker

This commit is contained in:
oiov
2025-05-25 10:57:26 +08:00
parent 5421285a29
commit 3145ef884d
8 changed files with 228 additions and 6 deletions
+64
View File
@@ -0,0 +1,64 @@
name: Build and Push Docker Image to GHCR
on:
push:
branches:
- main
tags:
- 'v*.*.*'
pull_request:
branches:
- main
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/wrdo
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
# 检出代码
- name: Checkout repository
uses: actions/checkout@v4
# 设置 Docker Buildx(支持多平台构建)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 登录到 GitHub 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 }}
# 提取 Docker 镜像元数据(标签、版本等)
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,format=short
type=ref,event=branch,prefix=
type=ref,event=tag
# 构建并推送 Docker 镜像
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }} # 仅在 push 时推送
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
ENVIRONMENT=${{ github.event.inputs.environment || 'production' }}
cache-from: type=gha
cache-to: type=gha,mode=max
+66
View File
@@ -0,0 +1,66 @@
FROM node:22-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
RUN npm install -g pnpm
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN pnpm config set registry https://registry.npmmirror.com
COPY prisma ./prisma
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN pnpm i --frozen-lockfile
FROM base AS builder
WORKDIR /app
RUN npm install -g pnpm
# ARG DATABASE_URL=""
# ARG AUTH_SECRET=""
# ARG NEXT_PUBLIC_APP_URL=http://localhost:3000
# ARG GOOGLE_CLIENT_ID=""
# ARG GOOGLE_CLIENT_SECRET=""
# ARG GITHUB_ID=""
# ARG GITHUB_SECRET=""
# ARG LinuxDo_CLIENT_ID=""
# ARG LinuxDo_CLIENT_SECRET=""
# ARG RESEND_API_KEY="res"
# ARG NEXT_PUBLIC_EMAIL_R2_DOMAIN=""
# ARG NEXT_PUBLIC_OPEN_SIGNUP="1"
# ARG NEXT_PUBLIC_GOOGLE_ID=""
# ARG SCREENSHOTONE_BASE_URL=""
# ARG GITHUB_TOKEN="g"
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm run build
FROM base AS runner
WORKDIR /app
RUN npm install -g pnpm
ENV NODE_ENV=production
ENV IS_DOCKER=true
# 复制必要文件
COPY --from=builder /app/public ./public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
+35 -2
View File
@@ -46,13 +46,15 @@ See docs about [email worker](https://wr.do/docs/developer/cloudflare-email-work
## Local development
copy `.env.example` to `.env` and fill in the necessary environment variables.
```bash
git clone https://github.com/oiov/wr.do
cd wr.do
pnpm install
```
copy `.env.example` to `.env` and fill in the necessary environment variables.
```bash
# run on localhost:3000
pnpm dev
```
@@ -68,6 +70,37 @@ pnpm db:push
Follow https://localhost:3000/setup
### Start on Docker
#### Dockerfile
```bash
git clone https://github.com/oiov/wr.do
cd wr.do
```
Fill in the environment variables in the `Dockerfile`, then build and run.
```bash
# Build image
docker build -t wrdo .
# Run
docker run -p 3000:3000 wrdo
```
#### Docker Compose
```bash
git clone https://github.com/oiov/wr.do
cd wr.do
```
Fill in the environment variables in the `env` file, then:
```bash
docker compose up -d
```
## Legitimacy review
- To avoid abuse, applications without website content will be rejected
+55
View File
@@ -0,0 +1,55 @@
services:
wrdo:
build:
context: .
dockerfile: Dockerfile
image: ghcr.io/oiov/wr.do/wrdo:${TAG:-latest}
container_name: wrdo
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- IS_DOCKER=true
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/wrdo
- AUTH_SECRET=${AUTH_SECRET:-your-auth-secret}
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-}
- GITHUB_ID=${GITHUB_ID:-}
- GITHUB_SECRET=${GITHUB_SECRET:-}
- LinuxDo_CLIENT_ID=${LinuxDo_CLIENT_ID:-}
- LinuxDo_CLIENT_SECRET=${LinuxDo_CLIENT_SECRET:-}
- RESEND_API_KEY=${RESEND_API_KEY:-}
- NEXT_PUBLIC_EMAIL_R2_DOMAIN=${NEXT_PUBLIC_EMAIL_R2_DOMAIN:-}
- NEXT_PUBLIC_OPEN_SIGNUP=${NEXT_PUBLIC_OPEN_SIGNUP:-1}
- NEXT_PUBLIC_GOOGLE_ID=${NEXT_PUBLIC_GOOGLE_ID:-}
- SCREENSHOTONE_BASE_URL=${SCREENSHOTONE_BASE_URL:-}
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
depends_on:
- postgres
networks:
- wrdo-network
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=wrdo
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- wrdo-network
restart: unless-stopped
volumes:
postgres-data:
name: wrdo-postgres-data
networks:
wrdo-network:
driver: bridge
+4 -4
View File
@@ -6,22 +6,22 @@ export const env = createEnv({
// This is optional because it's only used in development.
// See https://next-auth.js.org/deployment.
NEXTAUTH_URL: z.string().url().optional(),
AUTH_SECRET: z.string().min(1),
AUTH_SECRET: z.string().optional(),
GOOGLE_CLIENT_ID: z.string().optional(),
GOOGLE_CLIENT_SECRET: z.string().optional(),
GITHUB_ID: z.string().optional(),
GITHUB_SECRET: z.string().optional(),
LinuxDo_CLIENT_ID: z.string().optional(),
LinuxDo_CLIENT_SECRET: z.string().optional(),
DATABASE_URL: z.string().min(1),
DATABASE_URL: z.string().optional(),
RESEND_API_KEY: z.string().optional(),
SCREENSHOTONE_BASE_URL: z.string().optional(),
GITHUB_TOKEN: z.string().optional(),
},
client: {
NEXT_PUBLIC_APP_URL: z.string().min(1),
NEXT_PUBLIC_APP_URL: z.string().optional(),
NEXT_PUBLIC_OPEN_SIGNUP: z.string().min(1).default("1"),
NEXT_PUBLIC_EMAIL_R2_DOMAIN: z.string().min(1),
NEXT_PUBLIC_EMAIL_R2_DOMAIN: z.string().optional(),
},
runtimeEnv: {
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
+1
View File
@@ -6,6 +6,7 @@ import("./env.mjs");
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
output: "standalone",
images: {
remotePatterns: [
{
+3
View File
@@ -18,6 +18,9 @@
"email": "email dev --dir emails --port 3333",
"remove-content": "node ./setup.mjs"
},
"prisma": {
"schema": "./prisma/schema.prisma"
},
"dependencies": {
"@auth/prisma-adapter": "^2.4.1",
"@hookform/resolvers": "^3.9.0",
View File