admin管理员组

文章数量:1122826

I have a docker setup with a nextjs application in a container and another container with a postgres database, using prisma as ORM. The containers start fine and I can access my nextjs application on localhost:3000, but no content from the layout.tsx or root page.tsx is showing? I've put some logs in those files as well but see no output.

I believe this is some problem with connecting to the database because i can reproduce this in my development setup with just setting the incorrect postgres .env variables. In development I've used Neon as remote database, but I want to move on to production I want a local postgres database in a container, which is where the problem starts. Switching back to the Neon connection variables the site load normally as expected.

I can access the database with the pgadmin service and can connect to the database service and I see all tables there, however they are empty because the site wont load in the body content.

I can ping the containers between each other with a success, so they have to communicate somehow. Using docker dekstop interface and using the terminal in the nextjs-app logobrewer:

/app $ ping postgres_db
PING postgres_db (172.31.0.2): 56 data bytes
64 bytes from 172.31.0.2: seq=0 ttl=42 time=0.038 ms
64 bytes from 172.31.0.2: seq=1 ttl=42 time=0.053 ms

.env

DATABASE_URL=postgres://postgres:password@postgres_db:5432/logobrewer?schema=public
PGHOST=postgres_db
PGDATABASE=logobrewer
PGUSER=postgres
PGPASSWORD=password

Docker-compose.yml (Edited after Ravis comment)

version: '3.8'

services:
  postgres_db:
    image: postgres:15
    container_name: postgres_db
    restart: always
    environment:
      POSTGRES_DB: $PGDATABASE
      POSTGRES_USER: $PGUSER
      POSTGRES_PASSWORD: $PGPASSWORD
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
    - app_network

  app:
    container_name: logobrewer
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
      - "5555:5555"
    environment:
      NODE_ENV: production
      DATABASE_URL: postgres://postgres:password@postgres_db:5432/logobrewer?schema=public
    volumes:
      - F:\React\LogoAi\logo-ai\logs:/logs
    command: >
      sh -c "
      until pg_isready -h postgres_db -p 5432 -U postgres; do
        echo 'Waiting for Postgres...';
        sleep 2;
      done;
      npx prisma migrate deploy && node server.js"
    depends_on: 
      postgres_db: 
        condition: service_healthy
    networks:
    - app_network

  pgadmin:
    image: dpage/pgadmin4
    container_name: pgadmin4_container
    restart: always
    ports:
      - "8888:80"
    environment:
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: 1234
    volumes:
      - pgadmin_data:/var/lib/pgadmin
    depends_on:
      - postgres_db
    networks:
      - app_network
       
volumes:
 postgres_data:
 pgadmin_data:

networks:
  app_network:
    driver: bridge

schema.prisma:

// This is your Prisma schema file,
// learn more about it in the docs: 

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: 

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "debian-openssl-1.1.x", "debian-openssl-3.0.x", "linux-musl", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-1.1.x"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Product {
  id              String  @id @default(cuid())
  name            String
  description     String?
  stripeProductId String
  type            String
  orders          Order[] // Establishes a one-to-many relationship with Order
}

Dockerfile:

FROM node:18.18-alpine AS deps

WORKDIR /app

RUN apk add --no-cache \
    libc6-compat \
    cairo-dev \
    pango-dev \
    cairo-tools \
    giflib-dev \
    pixman-dev \
    libjpeg-turbo-dev \
    build-base \
    python3 \
    make \
    g++ \
    bash \
    pkgconfig \
    wget \
    && ln -sf /usr/bin/python3 /usr/bin/python

COPY package.json package-lock.json* ./ 
RUN \
    if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
    elif [ -f package-lock.json ]; then npm ci; \
    elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
    else echo "Lockfile not found." && exit 1; \
    fi

# Force canvas installation if it has issues
RUN npm install canvas --build-from-source --legacy-peer-deps

# Rebuild the source code only when needed
FROM deps AS builder

WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npx prisma generate
RUN npm run build

# Production image, copy all the files and run Next.js
FROM builder AS runner
WORKDIR /app

# Install Cairo runtime libraries (needed for canvas)
RUN apk add --no-cache \
    cairo \
    pango \
    fontconfig \
    libc6-compat  # Sometimes required for compatibility in Alpine

# Set environment variables
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV HOME=/home/nextjs

# Create and configure non-root user
RUN addgroup -S nodejs && adduser -S -G nodejs -u 1001 -D -h /home/nextjs nextjs \
    && mkdir -p /home/nextjs \
    && chown -R nextjs:nodejs /home/nextjs

# Create and set permissions for the /logs directory
RUN mkdir -p /logs && chown nextjs:nodejs /logs

# Copy necessary files from builder stage
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./app/.next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ 
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma

# Set ownership for the app directory
RUN chown -R nextjs:nodejs /app

#Use this to specify which folders instead of above which takes all the files
#RUN chown -R nextjs:nodejs /app/.next /app/public /app/prisma

# Use non-root user
USER nextjs

# Expose port and start the server
EXPOSE 3000

CMD ["node", "server.js"]

So, in the development (starting application locally npm run dev) using the Neon connection variables, which worked fine. But now switching to a local database running alongside in a container in the same docker network the problem starts.

I believe I've tried multiple solutions like rewriting the docker-compose, dockerfile, docker networking configurations.

EDIT: After some more thinking, could the issue be that during building the docker image my dockerfile I get a warning like this:

Invalid `prisma.generation.findFirst()` invocation:


Can't reach database server at `postgres_db:5432`

Please make sure your database server is running at `postgres_db:5432`. PrismaClientInitializationError: 
Invalid `prisma.generation.findFirst()` invocation:


Can't reach database server at `postgres_db:5432`

Please make sure your database server is running at `postgres_db:5432`.
    at qn.handleRequestError (F:\React\LogoAi\logo-ai\node_modules\@prisma\client\runtime\library.js:121:7615)


Can this cause a problem later on when spinning up the image to the container?

Also, I tried to use Postman to reach a api endpoint in my code which makes a database lookup like this:

export async function GET() {
    try {
        const getUserSession = await prisma.session.findFirst();

        if (getUserSession) {
            return NextResponse.json(getUserSession);
        }
}

And I actually get data back form the database. So the application needs to have connection i believe? This is so strange.

For some reason the application still don't load the layout.tsx children, but the navbar and the footer is loaded. This is the layout page where I have some debugging going on but they never show any output:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import SessionProvider from "./components/SessionProvider";
import CookieConsentBanner from "./components/CookieConsentBanner";
import Register from "./components/Register";
import { Toaster } from "react-hot-toast";
import Footer from "./components/Footer";
import logger from "@/utils/logger";
import Nav from "./components/Nav";
import { log } from "console";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "LogoBrewer",
  description: "Generated by create next app",
};

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {

  try {

    console.log("RootLayout");
    logger.info("RootLayout");

    return (
      <html lang="en" className="bg-base-100 min-h-screen ">
        <SessionProvider>
          <body className={`${inter.className} min-h-screen flex flex-col`}>
            {/* only appears if user hasnt registered */}
            <Register />

            <Nav />
            <div className="flex justify-center">
              <Toaster
                position="bottom-center"
                toastOptions={{
                  duration: 5000,
                  style: {
                    padding: "1em",
                  },
                }}
              />
              {children}
              <CookieConsentBanner />
            </div>
            <Footer />
          </body>
        </SessionProvider>
      </html>
    );
  } catch (error) {
    logger.error(error);
  }
}

I have a docker setup with a nextjs application in a container and another container with a postgres database, using prisma as ORM. The containers start fine and I can access my nextjs application on localhost:3000, but no content from the layout.tsx or root page.tsx is showing? I've put some logs in those files as well but see no output.

I believe this is some problem with connecting to the database because i can reproduce this in my development setup with just setting the incorrect postgres .env variables. In development I've used Neon as remote database, but I want to move on to production I want a local postgres database in a container, which is where the problem starts. Switching back to the Neon connection variables the site load normally as expected.

I can access the database with the pgadmin service and can connect to the database service and I see all tables there, however they are empty because the site wont load in the body content.

I can ping the containers between each other with a success, so they have to communicate somehow. Using docker dekstop interface and using the terminal in the nextjs-app logobrewer:

/app $ ping postgres_db
PING postgres_db (172.31.0.2): 56 data bytes
64 bytes from 172.31.0.2: seq=0 ttl=42 time=0.038 ms
64 bytes from 172.31.0.2: seq=1 ttl=42 time=0.053 ms

.env

DATABASE_URL=postgres://postgres:password@postgres_db:5432/logobrewer?schema=public
PGHOST=postgres_db
PGDATABASE=logobrewer
PGUSER=postgres
PGPASSWORD=password

Docker-compose.yml (Edited after Ravis comment)

version: '3.8'

services:
  postgres_db:
    image: postgres:15
    container_name: postgres_db
    restart: always
    environment:
      POSTGRES_DB: $PGDATABASE
      POSTGRES_USER: $PGUSER
      POSTGRES_PASSWORD: $PGPASSWORD
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
    - app_network

  app:
    container_name: logobrewer
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
      - "5555:5555"
    environment:
      NODE_ENV: production
      DATABASE_URL: postgres://postgres:password@postgres_db:5432/logobrewer?schema=public
    volumes:
      - F:\React\LogoAi\logo-ai\logs:/logs
    command: >
      sh -c "
      until pg_isready -h postgres_db -p 5432 -U postgres; do
        echo 'Waiting for Postgres...';
        sleep 2;
      done;
      npx prisma migrate deploy && node server.js"
    depends_on: 
      postgres_db: 
        condition: service_healthy
    networks:
    - app_network

  pgadmin:
    image: dpage/pgadmin4
    container_name: pgadmin4_container
    restart: always
    ports:
      - "8888:80"
    environment:
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: 1234
    volumes:
      - pgadmin_data:/var/lib/pgadmin
    depends_on:
      - postgres_db
    networks:
      - app_network
       
volumes:
 postgres_data:
 pgadmin_data:

networks:
  app_network:
    driver: bridge

schema.prisma:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "debian-openssl-1.1.x", "debian-openssl-3.0.x", "linux-musl", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-1.1.x"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Product {
  id              String  @id @default(cuid())
  name            String
  description     String?
  stripeProductId String
  type            String
  orders          Order[] // Establishes a one-to-many relationship with Order
}

Dockerfile:

FROM node:18.18-alpine AS deps

WORKDIR /app

RUN apk add --no-cache \
    libc6-compat \
    cairo-dev \
    pango-dev \
    cairo-tools \
    giflib-dev \
    pixman-dev \
    libjpeg-turbo-dev \
    build-base \
    python3 \
    make \
    g++ \
    bash \
    pkgconfig \
    wget \
    && ln -sf /usr/bin/python3 /usr/bin/python

COPY package.json package-lock.json* ./ 
RUN \
    if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
    elif [ -f package-lock.json ]; then npm ci; \
    elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
    else echo "Lockfile not found." && exit 1; \
    fi

# Force canvas installation if it has issues
RUN npm install canvas --build-from-source --legacy-peer-deps

# Rebuild the source code only when needed
FROM deps AS builder

WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npx prisma generate
RUN npm run build

# Production image, copy all the files and run Next.js
FROM builder AS runner
WORKDIR /app

# Install Cairo runtime libraries (needed for canvas)
RUN apk add --no-cache \
    cairo \
    pango \
    fontconfig \
    libc6-compat  # Sometimes required for compatibility in Alpine

# Set environment variables
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV HOME=/home/nextjs

# Create and configure non-root user
RUN addgroup -S nodejs && adduser -S -G nodejs -u 1001 -D -h /home/nextjs nextjs \
    && mkdir -p /home/nextjs \
    && chown -R nextjs:nodejs /home/nextjs

# Create and set permissions for the /logs directory
RUN mkdir -p /logs && chown nextjs:nodejs /logs

# Copy necessary files from builder stage
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./app/.next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ 
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma

# Set ownership for the app directory
RUN chown -R nextjs:nodejs /app

#Use this to specify which folders instead of above which takes all the files
#RUN chown -R nextjs:nodejs /app/.next /app/public /app/prisma

# Use non-root user
USER nextjs

# Expose port and start the server
EXPOSE 3000

CMD ["node", "server.js"]

So, in the development (starting application locally npm run dev) using the Neon connection variables, which worked fine. But now switching to a local database running alongside in a container in the same docker network the problem starts.

I believe I've tried multiple solutions like rewriting the docker-compose, dockerfile, docker networking configurations.

EDIT: After some more thinking, could the issue be that during building the docker image my dockerfile I get a warning like this:

Invalid `prisma.generation.findFirst()` invocation:


Can't reach database server at `postgres_db:5432`

Please make sure your database server is running at `postgres_db:5432`. PrismaClientInitializationError: 
Invalid `prisma.generation.findFirst()` invocation:


Can't reach database server at `postgres_db:5432`

Please make sure your database server is running at `postgres_db:5432`.
    at qn.handleRequestError (F:\React\LogoAi\logo-ai\node_modules\@prisma\client\runtime\library.js:121:7615)


Can this cause a problem later on when spinning up the image to the container?

Also, I tried to use Postman to reach a api endpoint in my code which makes a database lookup like this:

export async function GET() {
    try {
        const getUserSession = await prisma.session.findFirst();

        if (getUserSession) {
            return NextResponse.json(getUserSession);
        }
}

And I actually get data back form the database. So the application needs to have connection i believe? This is so strange.

For some reason the application still don't load the layout.tsx children, but the navbar and the footer is loaded. This is the layout page where I have some debugging going on but they never show any output:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import SessionProvider from "./components/SessionProvider";
import CookieConsentBanner from "./components/CookieConsentBanner";
import Register from "./components/Register";
import { Toaster } from "react-hot-toast";
import Footer from "./components/Footer";
import logger from "@/utils/logger";
import Nav from "./components/Nav";
import { log } from "console";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "LogoBrewer",
  description: "Generated by create next app",
};

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {

  try {

    console.log("RootLayout");
    logger.info("RootLayout");

    return (
      <html lang="en" className="bg-base-100 min-h-screen ">
        <SessionProvider>
          <body className={`${inter.className} min-h-screen flex flex-col`}>
            {/* only appears if user hasnt registered */}
            <Register />

            <Nav />
            <div className="flex justify-center">
              <Toaster
                position="bottom-center"
                toastOptions={{
                  duration: 5000,
                  style: {
                    padding: "1em",
                  },
                }}
              />
              {children}
              <CookieConsentBanner />
            </div>
            <Footer />
          </body>
        </SessionProvider>
      </html>
    );
  } catch (error) {
    logger.error(error);
  }
}

Share Improve this question edited yesterday jnilssonn asked yesterday jnilssonnjnilssonn 11 bronze badge
Add a comment  | 

1 Answer 1

Reset to default 0

Prisma relies on the DATABASE_URL to connect, and if the database isn't ready yet, migrations and subsequent queries fail.

  1. Add Wait-for-DB Logic: Ensure the database is ready before the Next.js app starts. Update the command in docker-compose.yml:
    command: >
      sh -c "
      until pg_isready -h postgres_db -p 5432 -U postgres; do
        echo 'Waiting for Postgres...';
        sleep 2;
      done;
      npx prisma migrate deploy && node server.js"
    
    

Adjust depends_on: While depends_on ensures startup order, it doesn't wait for readiness. Use a proper health check, which you already have for postgres_db.

Rebuild Containers: Ensure all changes are applied:

docker-compose down -v
docker-compose up --build

本文标签: postgresqlNextjsPrismapostgresDocker wont show layouttsx children pagesStack Overflow