gorules / zen

Open-source Business Rules Engine for your Rust, NodeJS, Python or Go applications.
https://gorules.io
MIT License
835 stars 80 forks source link

Ability to change the PORT mapping for the web application #227

Open lockhinator opened 3 months ago

lockhinator commented 3 months ago

We are in the process of deploying a self-hosted instance of GoRules on Heroku. As you may know, Heroku dynamically assigns a port to applications internally within their infrastructure. Therefore, we need the capability to configure the web application's port, ideally through an environment variable.

Could you please confirm if this functionality is currently supported? If not, is there a possibility it could be supported in the near future?

stefan-gorules commented 3 months ago

Hi, this is something we can take a look in. Would you be able to provide more details around your set-up in Heroku?

From what I've seen from quick google search, deployment of Docker images in Heroku works by:

Appreciate it!

lockhinator commented 3 months ago

Hi, this is something we can take a look in. Would you be able to provide more details around your set-up in Heroku?

From what I've seen from quick google search, deployment of Docker images in Heroku works by:

  • Pulling the image from docker.io registry
  • Pushing the image to Heroku registry
  • Deploying the container

Appreciate it!

We are currently using the image and running it via a heroku.yml file as well as doing some env setting in a startup bash script. Here are both files for context:

# heroku.yml
setup:
  addons:
    - plan: heroku-postgresql
      as: DATABASE

build:
  docker:
    gorules: Dockerfile

run:
  web:
    image: gorules
#!/bin/bash

# Extract the components from DATABASE_URL
if [ -n "$DATABASE_URL" ]; then
    # Remove the protocol (e.g., "postgres://")
    url=${DATABASE_URL#*//}

    # Extract the user and password
    userpass=${url%%@*}
    export DB_USER=${userpass%%:*}
    export DB_PASSWORD=${userpass#*:}

    # Extract the host and port
    hostport=${url#*@}
    hostport=${hostport%%/*}
    export DB_HOST=${hostport%%:*}
    export DB_PORT=${hostport#*:}

    # Extract the database name
    export DB_NAME=${url##*/}
fi

# Start the application
docker run gorules

We are using the PostgreSQL addon for PostgreSQL which mounts the DATABASE_URL into the dyno via Heroku's backend. Because of this we leverage the start.sh script but do not have the ability to change the port for the frontend in this case as it is assigned by Heroku.

placidic commented 3 hours ago

I would like to add that this would also be beneficial when running the container under a Red Hat Openshift based kubernetes deployment.

When i attempt to deploy, the dockerfile exposes the port as 0.0.0.0:80 EXPOSE map[80/tcp:{}]

which in openshift, can fail with errors like the following, due to do SCC Context Permissions and non-root limitations. "err":{"type":"Error","message":"listen EACCES: permission denied 0.0.0.0:80","stack":"Error: listen EACCES: permission denied 0.0.0.0:80\n at Server.setupListenHandle [as _listen2] (node:net:1885:21)\n at listenInCluster (node:net:1964:12)\n at node:net:2170:7\n at process.processTicksAndRejections (node:internal/process/task_queues:90:21)","code":"EACCES","errno":-13,"syscall":"listen","address":"0.0.0.0","port":80},"msg":"application startup error"}

If the HTTP IP/Port were exposed as Environment Variables, this could easily be overcome.

I did notice that there are 'nonroot' tags available, however they fail to start when used, stating the main.js file is missing.

stefan-gorules commented 3 hours ago

Hi, there's a nonroot tag for Docker image that you can utilise in such scenarios: https://hub.docker.com/r/gorules/brms/tags. It exposes 8080 port instead.

stefan-gorules commented 3 hours ago

Also just checked with the latest image, main.js does exists, are here any file access issues which you might be when using openshift?

placidic commented 2 hours ago

Thank you for the quick feedback!!

I just tried forcing a fresh new image to be pulled from the 'nonroot' tag. when i try to start the app, i seem to get this error on container start:

node:internal/modules/cjs/loader:1249 Error: Cannot find module '/home/nonroot/main.js' at Function._resolveFilename (node:internal/modules/cjs/loader:1249:15) at Function.<anonymous> (node:internal/modules/cjs/loader:1075:27) at TracingChannel.traceSync (node:diagnostics_channel:315:14) at wrapModuleLoad (node:internal/modules/cjs/loader:218:24) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5) at node:internal/main/run_main_module:36:49

stefan-gorules commented 2 hours ago

Are you running it locally or on openshift? Locally for me it works simply by running:

docker run gorules/brms:nonroot

The latest digest is: 542ebccd528b631761c59ed5a4d4de4385c5e1669a259f4e6785a290b64d9d8a.

placidic commented 1 hour ago

Within Openshift, not locally

Its so strange - Confirmed I have the same latest digest, I've been trying to find a way and pause the container so i can enter and view the files, but openshift likes to restart automatically and fail when an error is encountered. I even tried running the container with the commands: sleep, /bin/bash, /bin/ash, to try and cause a delay to inspect the container, but none of those utilities exist within the image.

When i view my image digest, i see its listed the same as you'd stated above. state: terminated: exitCode: 1 reason: Error startedAt: '2024-11-22T16:45:34Z' finishedAt: '2024-11-22T16:45:37Z' containerID: 'cri-o://5a965c162aa12faaf2998f61e71f31b4ca45c02bc5680325e26cdc69af73c7e1' imageID: 'docker.io/gorules/brms@sha256:542ebccd528b631761c59ed5a4d4de4385c5e1669a259f4e6785a290b64d9d8a' image: 'docker.io/gorules/brms:nonroot'

but still the following error as if that path to the working directory for the nonroot image doesn't exist on container start: node:internal/modules/cjs/loader:1249 Error: Cannot find module '/home/nonroot/main.js' at Function._resolveFilename (node:internal/modules/cjs/loader:1249:15) at Function.<anonymous> (node:internal/modules/cjs/loader:1075:27) at TracingChannel.traceSync (node:diagnostics_channel:315:14) at wrapModuleLoad (node:internal/modules/cjs/loader:218:24) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5) at node:internal/main/run_main_module:36:49

The regular, (not the non-root) image works properly for me in Openshift and starts initializing the application until the networking step, so I dont think its any issue with caching or permissions as far as deploying root vs nonroot.