Production deployment throws fetch error

default discord avatar
dumbledore
6 months ago
17

I was setting up my CI/CD pipeline for deploying my payload app to app engine, where I dockerize the app, push it GCR and then deploy the image to app engine.


I have been successful in doing so. But the react app is making request to

http://localhost:3000/api/users/me

instead of

<PROVIDED HOSTNAME>/api/users/me

.


I've tried passing all the different environment variables

PAYLOAD_PUBLIC_PAYLOAD_URL

,

PAYLOAD_PUBLIC_PAYLOAD_API

and

PAYLOAD_URL

.



Production deployment throws fetch error



import { buildConfig } from "payload/config";
import path from "path";
import Categories from "./collections/Categories";
import Posts from "./collections/Posts";
import Tags from "./collections/Tags";
import Users from "./collections/Users";
import Media from "./collections/Media";
import { gcsAdapter } from "@payloadcms/plugin-cloud-storage/gcs";
import { cloudStorage } from "@payloadcms/plugin-cloud-storage";

let adapter = gcsAdapter({
  options: {
    // apiEndpoint: process.env.GCS_ENDPOINT,
    projectId: process.env.GCS_PROJECT_ID,
  },
  bucket: process.env.GCS_BUCKET,
});

if (!process.env.PAYLOAD_PUBLIC_PAYLOAD_URL) {
  // throw new Error("");
  console.error("Cannot get the env variables");
}

export default buildConfig({
  serverURL: process.env.PAYLOAD_PUBLIC_PAYLOAD_URL ?? "http://localhost:3000",
  admin: {
    user: Users.slug,
  },

  collections: [
    Categories,
    Posts,
    Tags,
    Users,
    Media,
  ],
  plugins: [
    cloudStorage({
      collections: {
        media: {
          adapter,
        },
      },
    }),
  ],
  typescript: {
    outputFile: path.resolve(__dirname, "payload-types.ts"),
  },
  graphQL: {
    schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"),
  },
});


FROM node:18.8-alpine as base

FROM base as builder

WORKDIR /home/node/app
COPY package*.json ./

COPY . .
RUN yarn install
RUN yarn build

FROM base as runtime

ARG PAYLOAD_PUBLIC_PAYLOAD_URL="http://localhost"

ENV NODE_ENV=production
ENV PAYLOAD_CONFIG_PATH=dist/payload.config.js
ENV GCS_BUCKET=my-test-bucket-2002
ENV GCS_PROJECT_ID=payloadcms-test
ENV PAYLOAD_PUBLIC_PAYLOAD_URL=${PAYLOAD_PUBLIC_PAYLOAD_URL}

WORKDIR /home/node/app
COPY package*.json  ./

COPY key.json ./key.json
ENV GOOGLE_APPLICATION_CREDENTIALS=./key.json

RUN yarn install --production
COPY --from=builder /home/node/app/dist ./dist
COPY --from=builder /home/node/app/build ./build

# EXPOSE 3000

CMD ["node", "dist/server.js"]
  • default discord avatar
    Alessio 🍣
    6 months ago

    @dumbledore can you hard-code that serverURL field instead of using an environment variable and see if that works - just to test?

    Discord_2023-03-12_at_15.57.002x.jpg
  • default discord avatar
    dumbledore
    6 months ago

    @Alessio 🍣 I did that as a temporary fix and it works. But I'm work on make it a reusable template with terraform for provisioning the infrastucture i.e creating storage bucket, provisioning mongodb database on atlas, enabling gcr, gae apis in gcp and a script that use github cli to add env secret to your git repo so that I can work on the schema and when I make a commit to the main branch the github actions deploy the new version of the app to app engine. In short, I want to automate all the tedious tasks before I start using it for something serious without going through the hassel setting things up.

  • default discord avatar
    Kyr
    6 months ago

    This is the same issue I had with DevOps deployment to Azure.



    The PAYLOAD_PUBLIC env cars have to be present when you run the “build” command to be compiled into the admin app



    If you’re using the dockerfile you’ll need to set the env var inside there before build is called.

  • default discord avatar
    dumbledore
    6 months ago

    I figured that too and I used docker args to inject the variable from github secrets when building the docker image. But that didn't cut it, so I had to hardcode the url in the build config as a temporary fix.

  • default discord avatar
    Kyr
    6 months ago

    I found I had to have a different dockerfile for each environment and set the bars in the dockerfile

  • default discord avatar
    dumbledore
    6 months ago

    I'm still trying make it work in a single environment i.e production. Once thats done then I'll move on working on provisioning different environment using IaaC and dedicate main and staging branch to deploy to those environment. But that's after I figure out this problem.

  • default discord avatar
    Kyr
    6 months ago

    After the issues I had I opened up a discussion on github

    https://github.com/payloadcms/payload/discussions/2288
  • default discord avatar
    dumbledore
    6 months ago

    Did you hardcode the url in your config or did passing the environment variable at build time work for you?

  • default discord avatar
    Kyr
    6 months ago

    I created a separate Dockerfile for each environment and hardcoded a

    ENV PAYLOAD_PUBLIC_SERVER_URL=http....

    in each just above the

    npm install

    line.



    In DevOps Pipelines I then have a dynamic variable that selects which Dockerfile to build and publish based on the branch that triggered it.

  • default discord avatar
    dumbledore
    6 months ago

    Though I'm exposing the endpoint in the repo currently, but that's not what I want it to be. I want to be able to pass the

    PAYLOAD_URL

    via some secrets manager like github for one.

  • default discord avatar
    Kyr
    6 months ago

    Basically we need the ability for the hosting environment variables to be passed to the admin (i.e. allow Admin to see/know about them at runtime rather than just at build time) ... not sure how feasible that is.

  • default discord avatar
    dumbledore
    6 months ago

    Thats the problem I'm trying to figure out

  • default discord avatar
    Kyr
    6 months ago

    I think the safest solution at the moment is to use

    .env.xxxxxx

    files for all

    PAYLOAD_PUBLIC_

    vars and create a separate build script in package.json for each environment.



    This way, you don't need to set the public vars in any hosting environment, you just have them all in the relevant file and that gets deployed alongside the app.



    You can set private env vars in the hosting environment and use them in the Express server side of things still. This just means that some vars (like API keys) might require you to create a custom Express route that can use the private var, proxying the secured API.

  • default discord avatar
    dumbledore
    6 months ago

    I guess this would have been lot easier than what I just did. I added an additional step that during the CD creates

    .env

    that holds all the env, currently its just the

    PAYLOAD_PUBLIC_

    and feeds this to docker during the build.

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.