Run multiple git branches with PM2 - node.js

I have an express application with three branches: master, staging, and development. I want to run all three branches simultaneously, each on a different port, i.e. master on 3000, staging on 3001, development on 3002.
I'm hoping to achieve this with PM2, but haven't been able to get this to work yet. I was trying with an ecosystem.config.yml like the one below, which successfully runs the application on ports 3000-3002 and injects the corresponding environment variables, but runs the code of the active branch on all three ports.
Is it possible configure PM2 to run different git branches on different ports? Maybe with the PM2 deploy command and associated configuration somehow?
module.exports = {
apps: [
{
name: "api",
script: "app.js",
watch: ".",
env: {
NODE_ENV: "production",
PORT: "3000",
},
},
{
name: "api-staging",
script: "app.js",
watch: ".",
env: {
NODE_ENV: "staging",
PORT: "3001",
},
},
{
name: "api-dev",
script: "app.js",
watch: ".",
env: {
NODE_ENV: "development",
PORT: "3002",
},
},
],
};

Answering my own question here. The only way I've found to easily do this is to make a local copy of each branch of my repo in its own directory using git clone --branch <branchname> --single-branch <remote-repo-url>, e.g. git clone --branch development --single-branch git#github.com:myuser/my-api.git api-dev to clone the development branch of my repo into a local directory /api-dev.
Then in each local directory, which contains a single branch of my repo, I create an ecosystem.config.js file with configuration appropriate for that branch, e.g.
module.exports = {
apps: [
{
name: "api-dev",
script: "app.js",
watch: ".",
env: {
NODE_ENV: "development",
PORT: "3002",
},
},
],
};
Then I can run pm2 start ecosystem.config.js in each of my local repositories and run each branch on its own port.
Does anyone know a simpler way to do this?

Related

How to fix "Error: Cannot find module '/home/site/wwwroot/index.js" with an app deployed to Azure?

I'm attempting for the first time to deploy a node.js app to Azure as an Azure App Service, but I'm facing this stubborn error when trying to run the app that I haven't figured out how to troubleshoot. Maybe someone here has some hints on where I'm making the mistake.
To give some background:
I'm working on a project that has a subset of directories, each of the directories being an app (server, client, ...)
The main directory is the git directory
The nodejs app I am working on is built with typescript, and leveraging Apollo Server (which itself leverages express)
I'm deploying to Azure via GitHub
With that in mind, my project folder structure looks like:
| main_folder
| .github
| workflows
workflow.yml
| server
| src
| dist
.env
index.ts
package-lock.json
package.json
tsconfig.json
| other_apps
.gitignore
README.md
In index.ts I have the code relevant to running the app. The rest of the relevant files look like this:
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"lib": [
"ES2022", "DOM"
],
"strict": true,
"rootDir": ".",
"outDir": "./dist",
"sourceMap": true,
"esModuleInterop": true
}
}
package.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "ts-node-dev --transpile-only --no-notify --exit-child index.ts",
"build": "npx tsc",
"start": "node ."
},
// ...
}
workflow.yml
on:
push:
branches: ["master"]
workflow_dispatch:
env:
AZURE_WEBAPP_NAME: my-app-name
AZURE_WEBAPP_PACKAGE_PATH: "." # set this to the path to your web app project, defaults to the repository root
NODE_VERSION: "16.x" # set this to the node version to use
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./server
steps:
- uses: actions/checkout#v3
- name: Set up Node.js
uses: actions/setup-node#v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
cache-dependency-path: ./server/package-lock.json
- name: npm install, build, and test
run: |
npm install
npm run build --if-present
npm run test --if-present
- name: Zip artifact for deployment
run: zip -r release.zip ./* .env
- name: Upload artifact for deployment job
uses: actions/upload-artifact#v3
with:
name: node-app
path: ./server/release.zip
deploy:
permissions:
contents: none
runs-on: ubuntu-latest
needs: build
environment:
name: "Development"
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact#v3
with:
name: node-app
- name: unzip artifact for deployment
run: unzip release.zip
- name: "Deploy to Azure WebApp"
id: my_app_id
uses: azure/webapps-deploy#v2
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
This app works perfectly fine in local (running npm run dev). When I push to master in GitHub, both the build & deployment jobs work correctly. However, when I go to Azure Portal and check on the app, I see these two things:
When I open the url for the app, the page shows:
When I check the diagnostics of the app in Azure, it tells me:
The error being Error: Cannot find module '/home/site/wwwroot/index.js'. While setting up the configurations for automatic build & deployment in GitHub I faced several issues with my project structure, as my git repository doesn't actually contain any app (package.json), but they are instead in nested folders. However, I don't think this error stems from that set up, but from somewhere else.
Can somebody hint me on what I'm doing wrong here? I'll repeat that this is my first attempt at publishing a nodejs app to Azure, and even though I think I followed the docs correctly, there are chances I messed up in an obvious step. I would appreciate having anybody pointing it out if that's the case!
I'll be happy to add any more information to the description that might be relevant to the issue.
I have tried to reproduce this by creating a sample node.js webapp and pushed the code to github.
Created an Azure App service with github actions CI/CD pipelines and deployed successfully.
Make sure you have the below Project Structure:
Created a secret in GitHub by using the publish profile of azure app service from portal as shown in below image:
After configuring the above steps, Push the code from local repo to git repo then it will trigger the github pipelines and code will be deployed to azure app service as shown in below screenshot:
You can go to the azure portal and check the deployement as successful as shown below:
Output screen after clicking on the Azure app service url:

Node/Express server deploy with Heroku and PM2

Attempting to add clustering ability via PM2 and deploy via my Node/Express application.
I've set up the following command:
pm2 start build/server/app.js -i max
The above works fine locally. I'm testing the functionality on a staging environment on Heroku via Performance 1X.
The above shows the log for the command but attempting 1 instance rather than max. It shows typical info after successfully running pm2 start however you can see app immediately crashes afterward.
Any advice or guidance is appreciated.
I ended up using the following documentation: https://pm2.keymetrics.io/docs/integrations/heroku/
Using a ecosystem.config.js with the following:
module.exports = {
apps : [
{
name: `app-name`,
script: 'build/server/app.js',
instances: "max",
exec_mode: "cluster",
env: {
NODE_ENV: "localhost"
},
env_development: {
NODE_ENV: process.env.NODE_ENV
},
env_staging: {
NODE_ENV: process.env.NODE_ENV
},
env_production: {
NODE_ENV: process.env.NODE_ENV
}
}
],
};
Then the following package.json script handles the deployment per the environment I am looking to deploy e.g. production:
"deploy:cluster:prod": "pm2-runtime start ecosystem.config.js --env production --deep-monitoring",
I got the same error but I fixed it by adding
{
"preinstall":"npm I -g pm2",
"start":"pm2-runtime start build/server/app.js -i 1"
}
To my package.json file
This is advised for production environment
But running
pm2 start build/server/app.js -i max
Is for development purpose

Pass variable to Dockerfile CMD, Nodejs

I'm getting used to with Docker. Here is my current code in DockerFile:
FROM node:12-alpine AS builder
ARG NODE_ENV
ENV NODE_ENV ${NODE_ENV}
RUN npm run build
CMD ["sh","-c","./start-docker.sh ${NODE_ENV}"]
And I'm using pm2 to manage cluster in Nodejs, here is my start-docker.sh:
NODE_PATH=. pm2-runtime ./ecosystem.config.js --env $NODE_ENV
In my ecosystem.config.js, I define an env:
env_dev: {
NODE_ENV: 'development'
}
Everything is oke, but on my server, the NODE_ENV=''. I think there is something wrong when I pass in my CMD but can not find out what's wrong
Okay in my mind there is another way to do this, please try this way. this will not be actual code, it will just be an idea.
ecosystem.config.js
module.exports = {
apps : [{
name: "app",
script: "./app.js",
env: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
}
}]
}
And your dockerfile
dockerfile
FROM node:12-alpine
RUN npm run build
CMD ["pm2","start","ecosystem.config.js"]
As described in PM2 CLI documentation you just need to run command to start the application using the command pm2 start ecosystem.config.js this is automatically accessing the ENV variable described in ecosystem.config.js
https://pm2.keymetrics.io/docs/usage/application-declaration/#cli
Please try this, you might have new problems, but hope problems with some error logs, so that we can debug more. But I am sure that this could work and resolve your problem

pm2 script execution path is incorrect, doesn't match the one in ecosystem.config.js

My ecosystem.config.js looks like this:
module.exports = {
apps: [{
name: 'production',
script: '/home/username/sites/Website/source/server.js',
env: { NODE_ENV: 'PRODUCTION' },
args: '--run-server'
}, {
name: 'staging',
script: '/home/username/sites/WebsiteStaging/source/server.js',
env: { NODE_ENV: 'STAGING' },
args: '--run-server'
}],
deploy: {
production: {
user: 'username',
host: ['XXX.XXX.XX.XXX'],
ref: 'origin/production',
repo: 'git#github.com:ghuser/Website.git',
path: '/home/username/sites/Website',
'post-deploy': 'npm install && pm2 reload ecosystem.config.js --only production',
env: { NODE_ENV: 'PRODUCTION' }
},
staging: {
user: 'username',
host: ['XXX.XXX.XX.XXX'],
ref: 'origin/staging',
repo: 'git#github.com:ghuser/Website.git',
path: '/home/username/sites/WebsiteStaging',
'post-deploy': 'npm install && pm2 reload ecosystem.config.js --only staging',
env: { NODE_ENV: 'STAGING' }
}
}
};
When I deploy the application, I expect to see two processes - one called 'production' and one called 'staging'. These run code from the same repo, but from different branches.
I do see two processes, however, when I run pm2 desc production I can see that the script path is /home/username/sites/WebsiteStaging/source/server.js. This path should be /home/username/sites/Website/source/server.js as per the config file.
I've tried setting the script to ./server.js and using the cwd parameter but the result has been the same.
The deploy commands I am using are pm2 deploy production and pm2 deploy staging and I have verified that both the Website and the WebsiteStaging folders are present on my server.
Is there something I'm missing here? Why would it be defaulting to the staging folder like this?
What worked for me was to delete the pm2 application and start it.
pm2 delete production
pm2 start production
When I ran pm2 desc production, I saw that the script path was incorrect, and nothing I did seemed to correct that path, short of the above.
I had the same issue.
Seems it happend due to old dump.pm2 that was not updated after changes to ecosystem.config.js were made.
Updating the startup script solved the issue
pm2 save
pm2 unstartup
pm2 startup

Microsoft Azure hosting | Nodejs | file doesn't get compiled by webpack

I'm trying to build a webapp using nodejs. It compiles and runs fine on my local machine but when I try to host it on Azure, webpack seems to cause problem.
//webpack.config.js
var config = {
entry: './main.js',
output: {
path:'/',
filename: 'index.js',
},
devServer: {
// inline: true,
// port: 8080
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
}
module.exports = config;
This is the file hierarchy:
This is the sources tab in Chrome Dev tool for local machine. I notice here the index.js get compiled as specified in the config file.
Then I just place the source on the server using git. This is the response I get from the server:
This is the sources tab for the hosting server.
I suspect that it could be because there is difference in interpreting the directories on my local machine and the host?! I'm using MacOS.
Basically, you would need to compile your WebPack application first before deploying to Azure production server. However, you can also leverage Custom Deployment Script to install Node.js modules and run custom scripts to build your WebPack application on Azure Web Apps during the Azure Deployment task. For detailed steps, please check out this post on StackOverflow.

Resources