Open Ask AI (⌘/Ctrl+I)

Integrate with Node.js

This page details steps needed to successfully integrate Node.js applications with DX Cloud.

Ingress

To allow the splitting of requests between Node.js and Magnolia we need to tell Ingress to point to a frontend instance. To do it we need to create a new file in the root of the frontend repository.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/proxy-body-size: 512m
  name: APP_NAME <1>
  namespace: NAMESPACE <2>
spec:
  rules:
    - host: AUTHOR_URL <3>
      http:
        paths:
          - backend:
              serviceName: APP_NAME-magnolia-helm-frontend-author-svc <4>
              servicePort: http
            path: /
            pathType: Prefix
    - host: PUBLIC_URL <5>
      http:
        paths:
          - backend:
              serviceName: APP_NAME-magnolia-helm-frontend-public-svc <6>
              servicePort: http
            path: /
            pathType: Prefix
  tls:
    - hosts: <7>
        - AUTHOR_URL <8>
        - PUBLIC_URL
      secretName: YOUR_SECRET_NAME <9>

App name e.g. my-spa.

Namespace for which the configuration will be used.

URL for the author app.

Author service name, notice the use of app name from point 1.

URL for the public app.

Public service name, notice the use of app name from point 1.

The first domain listed in tls.hosts can only be a maximum 63 characters long.

List of author and public domains.

Your secret name.

Dockerize the frontend application

Dockerize your SPA application.

Below you can see an example of Dockerizing React SPA and serving it with http-server application.

Frontend application repository

frontend-application-repository
...
└── spa <1>
└── http-server <2>
...

Folder with React SPA.

Folder with http-server application.

FROM node:16 as dependencies <1>
WORKDIR /app
COPY http-server/package.json ./
COPY http-server/package-lock.json ./
RUN npm install

FROM node:16 as builder <2>
ARG ENV_VARIABLE_1
ENV REACT_APP_ENV_VARIABLE_1=$ENV_VARIABLE_1
WORKDIR /app
COPY spa/package.json ./
COPY spa/package-lock.json ./
RUN npm install
COPY spa ./
RUN npm run build

FROM node:16 as runner <3>
WORKDIR /app
COPY --from=dependencies /app/package.json ./package.json <4>
COPY --from=dependencies /app/node_modules ./node_modules <5>
COPY --from=builder /app/build ./public <6>
EXPOSE 3000 <7>
CMD ["npm", "start"] <8>

Stage to install http-server dependencies.

Stage to build React SPA.

Prepare the final image.

Copy package.json from dependencies stage to be used by http-server.

Copy node_modules from dependencies stage to be used by http-server.

Copy build files of React SPA to public folder, from which http-server serves the files.

Expose the port on which Node.js application is listening.

Start the Node.js application.

The .gitlab-ci.yml file

We need to extend CI/CD configuration with jobs to prepare and deploy the Node.js application image.

stages:
  - prepare
  - deploy

# Prepare the frontend app
prepare:build-node-js-docker-image:
  stage: prepare
  image: 'docker:20'
  before_script:
    - apk add --no-cache git
    - git --version
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - export GIT_TAG=$(git describe --always) <1>
    - export DOCKER_BUILDKIT=1
    - export MAGNOLIA_DOCKER_AUTHOR=$CI_REGISTRY_IMAGE/author
    - export MAGNOLIA_DOCKER_PUBLIC=$CI_REGISTRY_IMAGE/public
  script:
    - docker build --pull -t "$MAGNOLIA_DOCKER_AUTHOR:$GIT_TAG" --build-arg ENV_VARIABLE_1=$ENV_VARIABLE_1 . <2>
    - docker push "$MAGNOLIA_DOCKER_AUTHOR:$GIT_TAG"
    - docker build --pull -t "$MAGNOLIA_DOCKER_PUBLIC:$GIT_TAG" --build-arg IS_PUBLIC=true --build-arg ENV_VARIABLE_1=$ENV_VARIABLE_1 .
    - docker push "$MAGNOLIA_DOCKER_PUBLIC:$GIT_TAG"
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
      variables:
        ENV_VARIABLE_1: foo
    - if: $CI_COMMIT_BRANCH == "master"
      variables:
        ENV_VARIABLE_1: bar

# Deploy the frontend app to the frontend pods
deploy:sync-node-js:
  stage: deploy
  image: registry.magnolia-platform.com/developers-artifact/spa-nodejs:1.0.2
  environment:
    name: $NAME
  before_script:
    - export KUBECTL_NAMESPACE=$NAME <3>
    - export MAGNOLIA_RELEASE=$NAME
    - export GIT_TAG=$(git describe --always)
    - export MAGNOLIA_DOCKER_AUTHOR=$CI_REGISTRY_IMAGE/author <4>
    - export MAGNOLIA_DOCKER_PUBLIC=$CI_REGISTRY_IMAGE/public
    - export MAGNOLIA_FRONTEND_PORT="3000"
    - export MAGNOLIA_FRONTEND_CPU="200m"
    - export MAGNOLIA_FRONTEND_MEMORY="2Gi"
    - export MAGNOLIA_FRONTEND_AUTHOR_REPLICAS="1" <5>
    - export MAGNOLIA_FRONTEND_PUBLIC_REPLICAS="2" <6>

  script:
    - export KUBECONFIG=$KUBE_CONFIG <7>
    - initialpath=$PWD
    - cd /k8s/base
    - envsubst < customization-template.yaml > customization.yaml ; kustomize build .
    - kubectl -n $NAME apply -k . <8>
    - cd $initialpath
    - kubectl apply -f ingress.yaml <9>
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
      variables:
        NAME: integration
    - if: $CI_COMMIT_BRANCH == "master"
      variables:
        NAME: prod

The GIT_TAG is used to set the tag for the created Docker image.

Build the image.

Export the environment variables used to customize the Kubernetes deployment.

You can specify different images for author and public.

Default number of frontend author replicas.

Default number of frontend public replicas.

The KUBE_CONFIG CI/CD variable should be defined as type File and hold KubeConfig of the cluster the deployment should go to. The same variable can be defined in different environment scopes.

Build the Kubernetes deployment files and apply them to the Kubernetes cluster.

Apply the Ingress configuration.

CDN

The CDN uses cache headers coming from Node.js app.

Deploying multiple frontend apps

When deploying multiple frontend apps within the same subscription:

  1. From inside the frontend repository, create a new Ingress configuration for each app.
  2. Create a Dockerfile for each app.
  3. Modify the .gitlab-ci pipeline to build the Docker image for each app.
  4. Modify the .gitlab-ci pipeline to deploy the Docker image for each app.
  5. Modify the .gitlab-ci pipeline to deploy the Ingress configuration for each app.

Useful V8 options

--max-old-space-size=SIZE (in megabytes)

Sets the max memory size of V8’s old memory section. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory.

On a machine with 2 GiB of memory, consider setting this to 1536 (1.5 GiB) to leave some memory for other uses and avoid swapping.

...
ENV NODE_OPTIONS=--max-old-space-size=1536
CMD ["npm", "start"]