Integrate with Node.js
This page details steps needed to successfully integrate Node.js applications with DX Cloud.
Ingress
To split requests between Node.js and Magnolia, point an MgnlIngress at the frontend Services. Add the manifest in the root of the frontend repository. Leave ingress.enabled off in values.yml.
Field names are in Map UI fields to manifest. acquireCertificate: true asks the platform to issue the certificate. See TLS certificates.
apiVersion: magnolia.info/v1alpha1
kind: MgnlIngress
metadata:
name: APP_NAME <1>
namespace: NAMESPACE <2>
labels:
app.kubernetes.io/managed-by: pipeline
spec:
acquireCertificate: true
rules:
- host: AUTHOR_URL <3>
paths:
- path: /
pathType: Prefix
backendName: APP_NAME-magnolia-helm-frontend-author-svc <4>
backendPortName: http
- host: PUBLIC_URL <5>
paths:
- path: /
pathType: Prefix
backendName: APP_NAME-magnolia-helm-frontend-public-svc <6>
backendPortName: http
tls:
- hosts:
- AUTHOR_URL <7>
- PUBLIC_URL
secretName: YOUR_SECRET_NAME <8>
App name, for example my-spa.
Namespace this Ingress belongs to.
URL for the author app.
Author Service name. It uses the app name from callout 1. backendPortName is the Service port name, http.
URL for the public app.
Public Service name. It uses the app name from callout 1.
The first domain in tls.hosts can be at most 63 characters.
Name of the TLS secret. Both the author domain and the public domain belong in hosts.
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:
- From inside the frontend repository, create a new Ingress configuration for each app.
- Create a Dockerfile for each app.
- Modify the
.gitlab-cipipeline to build the Docker image for each app. - Modify the
.gitlab-cipipeline to deploy the Docker image for each app. - Modify the
.gitlab-cipipeline 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"]