ReactJS browser app cannot see things in the Docker Compose network - reactjs

I have a ReactJS project with its own Dockerfile, exposing port 3000:3000.
I also have a PHP project with its own Dockerfile, exposing port 80:80. The PHP app also has containers for MySQL, Redis and Nginx
For the PHP app, I have a docker-compose file that creates a network (my-net) for PHP, Nginx, MySQL and Redis to communicate on. However, I now want the ReactJS (which is in a separate project) to be able to communicate with the PHP app.
I added a docker-compose file to the React project, and added it to the network from the PHP project my-net and declared it as external so that it doesn't try to create it.
This seems to work: From the ReactJS container, I can ping app (the name of my backend service) and it works properly. However, from the ReactJS code, if I use something like axios to try and hit the backend API, it can't resolve app or http://app or any variation. It can however access the underlying IP address if I substitute that into in axios.
So there seems to be some issue with the hostname resolution, and presumably this is on the axios / JavaScript end. is there something I'm missing or a reason this isn't working?

When the JavaScript runs in a browser (outside of Docker) you can not use app because that is only available inside the Docker network (via the embedded DNS server).
To access your PHP server from outside use localhost and the exposed port (80) instead.

Related

Docker container is using my host DNS instead of the docker internal DNS

I have a docker-compose file that builds two basic application.
A front-end with angular and a backend with adonis.
version: "3.9"
services:
backend_login:
build:
context: ./apis/apis/login_api
ports:
- "3333:3333"
sendit_frontend:
build:
context: ./frontend/frontend/external
ports:
- "4500:4200"
depends_on:
- api_backend_login
When i run the docker-compose up the two applications go up and they work in their respective ports.
The problems comes when i call the api from the front-end app using the name of the service (in this case backend_login).
I attached my terminal to both containers and did a telnet test between them, they seems to work as the y resolve the name and connect to the respective ports
Finally, i discovered that the front-end app, when is called from firefox, tries to resolve the name using the host dns and not the internal docker dns.
Now i don't know where is the problem, if it is in the code or in the way that i build the container.
Edit: I realize that the app is running in the browser of my host machine (i'm a newbie with containers) and obviously it uses my host DNS.
Is there a way to workaround this?
docker compose sets up a docker network for all services inside the compose file that allows it to instrument the DNS rules you're talking about, but only from service to service. As you noted, your Angular application is technically "run" from the browser (e.g. Firefox) which means it's not inside the network.
There's not a practical way to run SPAs or static sites like Angular from inside the container environment, but the simple way around your problem would be to point the frontend to http://localhost:3333. You've mapped the port to the host so it should be available from the host network directly.
Note: this will be a problem for prod when you get there too. SPAs and static sites can be tricky when it comes to dynamic backend addresses. Most SPA frameworks recommend that you re-build the app every time you deploy to a new environment so that the backend address can be built into the artifact, but that tends to be at-odds with container-centric development which tend to maintain the philosophy of "build once, deploy anywhere".

Cannot deploy a react app to azure app services

I’m trying to deploy a basic react app to Azure app services, but I cannot get it to work.
The app itself is the initial app created following npx create react app my-app command. I want to get this one working first before trying to deploy my actual react app.
The Azure App Service is a Linux setup, using node 16.
I’ve added “pm2 serve /home/site/wwwroot --no-daemon” as the startup command. I’ve also added PORT 3000 and WEBSITE_PORT 3000 in app settings.
Lastly I’ve added a web.config file to the react app itself.
Nothing I do seems to work though as it is not loading at all. I just get ‘application error’ if I try to open the app.
The only two errors i can see in the logs are:
“…didn't respond to HTTP pings on port: 3000” and “… did not start within expected time limit”
My deployment is set as continuous via git hub, though as this is building without an issue I think the problem must be something in the Azure App Service settings but I’m lost as to what.
Does anyone have any ideas to fix this?
It could be that there is no access to port 3000 in the app service.
It depends on how you have set it up what needs to be fixed. It could be the network settings on the app service. If your app service is on a VNET then it could be the settings on the VNET that need to be updated.

React local workspace setup to connect to REST API server

Let's say I have a React app and want to connect locally to my local Tomcat server (for ultimately consuming REST endpoints from my React app). I have 2 questions;
Is there a standard local workspace setup recommended by React to point to our localhost running backend services?
Is there an easy/configurable setup, where I have both options e.g. switch from connecting to actual backend service TO say using mock
endpoint responses on my local i.e. by a simple config change ?
Note: I am trying to avoid hardcoding any absolute URLs on my client-side i.e. In my client side code, I would just have the endpoint defined as "mycontext/my/endpoint" and say if my React app is running on say http://localhost, then it should automatically construct the full endpoint as http://localhost/mycontext/my/endpoint
You can define environment variables, which could include the address of the API server you'd like to use. Then you would simply change that variable any time you wish to hit a different API server (be it localhost or remote).
If you are using Create React App to bootstrap your setup, you can also use the proxy setting in your package.json.

How to access a database from a hybrid app without crossing domains?

I am developing an app with PhoneGap (Cordova) + Framework7 and I need to connect to a database. The issue is that it's an hybrid app, which means the www files are local and the app creates an internal server, and so if you try to use AJAX to run a php file it crosses domains, since it'll try to reach for my webserver while it's running it's own server. What can I do?
(I know Cordova has a utility named WebSQL that connects to SQLite, but my database is MySQL, and I think it can only connect to a local db)
(You can't move php to be local because Cordova can't run php files, also it's probably not very secure)
My suggestion is to use Ajax to access your server. (to run the PHP file) You can allow your server URL in environment variables of frontend.
Check for Content-Security-Policy and connect-src in frontend and add your server URL there. Then you will be able to send Ajax to your server.
Hope this helps.

Debugging GAE microservices locally but without using localhost

I would like to debug my Google App Engine (GAE) app locally but without using localhost. Since my application is made up of microservices, the urls in a production environment would be along the lines of:
https://my-service.myapp.appspot.com/
But code in one service can call another service and that means that the urls are hardcoded. I could of course use a mechanism in code to determine whether the app is running locally or on GAE and use urls that are different although I don't see how a local url would handle the since the only way to run an app locally is to use localhost. Hence:
http://localhost:8080/some-service
Notice that "some-service" maps to a servlet, whereas "my-service" is a name assigned to a service when the app is uploaded. These are really two different things.
The only possible solution I was able to find was to use a reverse proxy which would map one url to a different one. Still, it isn't clear whether the GAE development SDK even supports this.
Personally I chose to detect the local development vs GAE environment and build my inter-services URLs accordingly. I feel it was a well-worthy effort, I've been (re)using it a lot. No reverse proxy or any other additional ops necessary, it just works.
Granted, I'm using Python, so I'm not 100% sure a complete similar Java solution exists. But maybe it can point you in the right direction.
To build the per-service URLs I used modules.get_hostname() (the implementation is presented in Resolve Discovery path on App Engine Module). I believe the Java equivalent would be getInstanceHostname() from com.google.appengine.api.modules.
This method, when executed on the local server, automatically provides the particular port the server listens to for each service.
BTW, all my services for an app are executed by a single development server process, which listens on multiple ports (this is, I guess, how it can provide the modules.get_hostname() info). See Running multiple services using dev_appserver.py on different ports. This is part I'm unsure about: if/how the java local dev server can simultaneously run multiple services. Apparently this used to be supported some time ago (when services were still called modules):
Serving multiple GAE modules from one development server?
GAE modules on development server
This can be accomplished with the following steps:
Create an entry in the hosts file
Run the App Engine Dev server from a Terminal using certain options
Use IntelliJ with Remote debugging to attach the App Engine Dev server.
To edit the hosts file on a Mac, edit the file /etc/hosts and supply the domain that corresponds to your service:. Example:
127.0.0.1 my-service.myapp.com
After you save this, you need to restart your computer for the changes to take place.
Run the App Engine Dev server manually:
dev_appserver.sh --address=0.0.0.0 --jvm_flag=-Xdebug
--jvm_flag=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
[path_to_exploded_war_directory]
In IntelliJ, create a debug configuration. Use the Remote template to create this configuration. Set the host to the url you set in the hosts file and set the port to 8000.
You can set a breakpoint and run the app in IntelliJ. IntelliJ will attach to the running instance of App Engine Dev server.
Because you are using a port during debugging and no port is actually used when the app is uploaded to the GAE during production, you need to add code that identifies when the app is running locally and when it's running on GAE. This can be done as follows:
private String mServiceUrl = "my-service.my-app.appspot.com";
...
if (SystemProperty.environment.value() != SystemProperty.Environment.Value.Production) {
mServiceUrl += ":8000";
}
See https://cloud.google.com/appengine/docs/standard/java/tools/using-local-server
An improved solution is to avoid including the port altogether and not having to use code to determine whether your app is running locally or on the production server. One way to do this is to use Charles (an application for monitoring and interacting with requests) and use a feature called Remote Mapping which lets you map one url to another. When enabled, you could map something like:
https://my-service.my-app.appspot.com/
to
https://localhost:8080
You would then enable the option to include the original host, so that this gets delivered to the local dev server. As far as your code is concerned it only sees:
https://my-service.my-app.appspot.com/
although the ip address will be 127.0.0.1:8080 when remote mapping is enabled. To use https on local host however does require that you enable ssl certificates for Charles.
For a complete overview on how to setup and debug microservices for a GAE Java app in IntelliJ, see:
https://github.com/JohannBlake/gae-microservices

Resources