I have two docker containers frontend
and data-service
.
frontend
is using NextJS which is only relevant because NextJS has a method called getInitialProps()
which can be run on the server, or can be run in the visitor's browser (I have no control over this).
In getInitialProps()
I need to call an API to get the data for the page:
fetch('http://data-service:3001/user/123').then(...
When this is called on the server the API returns fine because my frontend container has access to the internal docker network and therefor can reference the data-service using the hostname http://data-service
.
When this is called on the client, however, it fails (obviously) because Docker is now exposed as http://localhost
and I can't reference http://data-service
anymore.
How can I configure Docker so that I can use 1 URL for both use cases. I would prefer not to have to figure out which environment I'm in in my NextJS code if possible.
If seeing my docker-compose is useful I have included it below:
version: '2.2'
services:
data-service:
build: ./data-service
command: npm run dev
volumes:
- ./data-service:/usr/src/app/
- /usr/src/app/node_modules
ports:
- "3001:3001"
environment:
SDKKEY: "whatever"
frontend:
build: ./frontend
command: npm run dev
volumes:
- ./frontend:/usr/src/app/
- /usr/src/app/node_modules
environment:
API_PORT: "3000"
API_HOST: "http://catalog-service"
ports:
- "3000:3000"
If you are running more than one container, you can let your containers communicate with each other by attaching them to the same network. Docker creates virtual networks which let your containers talk to each other. In a network, a container has an IP address, and optionally a hostname.
You need to connect them by placing both frontend and backend in same docker network (you don't need to put db in that network). Just create manually a standalone network and then reference it in docker-compose as external - same for backend and frontend.
The most elegant solution I've found is described in this post: Docker-compose make 2 microservices (frontend+backend) communicate to each other with http requests
Example implementation:
In next.config.js
:
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
URI: 'your-docker-uri:port'
},
publicRuntimeConfig: {
// Will be available on both server and client
URI: 'http://localhost:port'
}
}
In pages/index.js
:
import getConfig from 'next/config';
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
const API_URI = serverRuntimeConfig.apiUrl || publicRuntimeConfig.apiUrl;
const Index = ({ json }) => <div>Index</div>;
Index.getInitialProps = async () => {
...
const res = await fetch(`${API_URI}/endpoint`);
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With