Background
I’m relatively new to Docker and have finally sat down to learn more about it for a month or so. I am currently attempting to create a local development environment for my team, so ideally an environment that is easily scalable and is able to run multiple applications at the same time.
So far, my experiments have gone quite well, until I hit this particular roadblock, occurring when cross-application (and therefore cross-container) calls need to occur.
Codebase
I will provide the relevant code underneath this post, but for easier browsing, I have also set up a public repository replicating my issue: Tom Peters / Docker Workshop · GitLab
The Docker environment consists of a single NginX container and two PHP containers (“App” and “API”) containing Symfony-based applications, managed via a single Docker-Compose file, and all sharing the same network.
Intended Functionality
“App” should perform a HTTP-based request (using Symfony’s HttpClient
) to “API”, retrieve a message, and display it on a simple page.
Issue At Hand
Currently, routing to the individual applications functions as intended and show the expected results.
However, when the “App” container attempts to request data from the “API” container, I run into one of several issues:
-
http://API/api/data
results in a refused connection on port 80. -
http://API:9000/api/data
results in a connection reset by peer. -
http:/host.docker.internal/api/data
resolves, but simply retrieves the first matching route, so this setup would not allow for applications using the same routes.
Troubleshooting So Far
As the above shows, I have already attempted several different solutions besides the ones that have not been persisted to the example repository.
Beyond that, I have browsed several issues here on the forums, but none have seemed to offer the solutions I am seeking (sources: 1, 2, 3, 4, 5).
Relevant Code
Docker Configuration
version: '3'
services:
server:
container_name: NginX
image: nginx:1.14.0
tty: true
ports:
- '80:80'
networks:
- local-network
volumes:
- .\nginx:/etc/nginx/conf.d
- .\api:/var/www/api
- .\app:/var/www/app
api:
container_name: API
image: php:8.1.3-fpm
tty: true
networks:
- local-network
volumes:
- .\api:/var/www/api
app:
container_name: App
image: php:8.1.3-fpm
tty: true
networks:
- local-network
volumes:
- .\app:/var/www/app
networks:
local-network:
driver: bridge
NginX Configuration
API
server {
server_name api.local;
index index.php;
root /var/www/api/public;
access_log /var/log/nginx/api-access.log;
error_log /var/log/nginx/api-error.log;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass API:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
App
server {
server_name app.local;
index index.php;
root /var/www/app/public;
access_log /var/log/nginx/app-access.log;
error_log /var/log/nginx/app-error.log;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass App:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
PHP Setup
API Route
class DataController extends AbstractController
{
/**
* @Route("/api/data")
*/
public function index(): Response
{
$today = new DateTime();
return $this->json('The date and time are currently ' . $today->format('Y-m-d H:i:s'));
}
}
App Route
class ExternalDataController extends AbstractController
{
private HttpClientInterface $client;
public function __construct(HttpClientInterface $client)
{
$this->client = $client;
}
/**
* @Route("/")
*/
public function index(): Response
{
/* Failed to connect to api port 80: Connection refused for "http://api/api/data". */
// $response = $this->client->request('GET', 'http://API/api/data');
/* Recv failure: Connection reset by peer for "http://api:9000/api/data". */
// $response = $this->client->request('GET', 'http://API:9000/api/data');
/* Resolves properly, but directs to the first /api/data found, which is not as intended. */
$response = $this->client->request('GET', 'http://host.docker.internal/api/data');
$message = $response->getContent();
return $this->render('external_data/index.html.twig', [
'message' => $message,
]);
}
/**
* @Route("/api/data")
*/
public function duplicateRoute(): Response
{
return $this->json('These are not the data you\'re looking for.');
}