Есть веб-сервисы внутри докер-контейнеров, назовем их api1 и api2.
Внутри api1 определены следующие маршруты:
Route::get('/test', function () {
return view('welcome');
});
$router->group(['prefix' => '/v1/user'], function ($router) {
$router->post('/auth', 'Api\SignInController@auth');
$router->post('/request-password-reset', 'Api\SignInController@request_password_reset');
$router->post('/set-password', 'Api\SignInController@set_password');
$router->post('/set-password/by-token', 'Api\SignInController@set_password_by_token');
});
$router->group(['prefix' => '/v1/session'], function ($router) {
$router->post('/check-session', 'Api\SessionController@checkSession');
$router->post('/expire', 'Api\SessionController@expire');
});
Из системы http-запросы он принимает исправно. А вот когда возникла необходимость из одного сервиса обращаться в другой (использую guzzle) возникли проблемa:
curl запрос не находит адрес контейнера, который доступен извне, при этом, если запрос идет на имя контейнера - он доходит, но возвращает какой-то бред.
Итак, мой docker-compose.yml:
version: "3.0"
services:
app-api-signin:
container_name: app-api-signin
build: docker/common/php
working_dir: /app
volumes:
- ./api_signin:/app
expose:
- 9000
links:
- mysql
- memcached
nginx-api-signin:
container_name: nginx-api-signin
image: nginx:latest
ports:
- "127.0.0.2:8081:80"
volumes:
- ./api_signin:/app
- ./docker/common/api-signin/nginx/vhost.conf:/etc/nginx/conf.d/vhost.conf
links:
- app-api-signin
app-api-cabinet:
container_name: app-api-cabinet
build: docker/common/php
working_dir: /app
volumes:
- ./api_cabinet:/app
expose:
- 9000
links:
- mysql
- memcached
- nginx-api-signin
nginx-api-cabinet:
container_name: nginx-api-cabinet
image: nginx:latest
ports:
- "127.0.0.2:8083:80"
volumes:
- ./api_cabinet:/app
- ./docker/common/api-cabinet/nginx/vhost.conf:/etc/nginx/conf.d/vhost.conf
links:
- app-api-cabinet
mysql:
container_name: mysql
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- ./db-data:/var/lib/mysql:rw
memcached:
container_name: memcached
image: memcached:latest
ports:
- "11211:11211"
Что я пробовал делать:
1) Слать запросы на адрес nginx:
$client = new Client([
'base_uri' => 'http://127.0.0.2:8081'
]);
$g_request = new \GuzzleHttp\Psr7\Request('POST', '/api/v1/session/check-session');
$response = $client->send($g_request);
dd($response->getBody());
Ответ:
ConnectException
cURL error 7: Failed to connect to 127.0.0.2 port 8081: Connection refused
2) Слать запрос, используя вместо ip-адреса имя docker-container:
$client = new Client([
'base_uri' => 'http://nginx-api-signin'
]);
$g_request = new \GuzzleHttp\Psr7\Request('POST', '/api/v1/session/check-session');
$response = $client->send($g_request);
dd($response->getBody());
Ответ:
ClientException
Client error: `POST http://nginx-api-signin/api/v1/session/check-session` resulted in a `404 Not Found` response:
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr> (truncated...)
3) Слать запрос просто на докер-контейнер меняя метод запроса на get:
$client = new Client([
'base_uri' => 'http://nginx-api-signin/'
]);
$g_request = new \GuzzleHttp\Psr7\Request('GET', '/');
$response = $client->send($g_request);
dd($response->getBody());
Ответ (не является ошибкой):
Stream {#176
-stream: stream resource @12
wrapper_type: "PHP"
stream_type: "TEMP"
mode: "w+b"
unread_bytes: 0
seekable: true
uri: "php://temp"
options: []
}
-size: null
-seekable: true
-readable: true
-writable: true
-uri: "php://temp"
-customMetadata: []
}
Из этого всего видно, что доступ к docker-containerу получаю в последнем случае, но как мне обратиться к своему api, используя имя docker-container'a?
По умолчанию Docker использует bridge-сетку для каждого контейнера, выдающую ему адрес из внутреннего диапазона (например, 172.17.0.2) и позволяющую обращаться к ресурсам внешней сети. В случае с Docker Сompose такая сеть создается для каждой композиции контейнеров:
etki@kepler:/tmp > docker-compose up -d
Creating network "tmp_default" with the default driver
Creating tmp_nginx_1
etki@kepler:/tmp > docker network inspect tmp_default
[
{
"Name": "tmp_default",
...
"Driver": "bridge",
...
}
]
Это значит следующее:
Кроме того, в docker встроен DNS, которым пользуется Docker Compose. Внутри созданной сетки имена контейнеров будут резолвиться в их адреса:
etki@kepler:/tmp > docker exec tmp_nginx_1 getent hosts nginx
192.168.0.2 nginx
Таким образом, для обращения к контейнерам спеки nginx-api-signin
действительно правильней всего указывать nginx-api-signin
в качестве хоста, потому что такой запрос уйдет на внутренний ДНС и зарезолвится в реальные айпишники контейнеров. Nginx, в свою очередь, должен использовать app-api-signin
и app-api-cabinet
в качестве адресов FCGI-обработчиков.
Насколько видно, до nginx получается достучаться, однако он отдает 404 и 405. Это означает просто то, что nginx неправильно сконфигурирован и не воспринимает приходящие запросы как приходящие на нужный сервер; скорее всего, у него внутри нет хоста nginx-api-signin, а default_server занимается обычной раздачей статики. Должно быть достаточно создать этот хост, чтобы запросы к нему начали отрабатывать корректно.
В случае каких-либо проблем можно включить дебаг-лог nginx, указав формат debug
для error_log и изменив команду контейнера на [nginx-debug, -g, 'daemon off;']
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
С клиента на сервер приходит json формы, в одном из полей которой храниться картинка в виде base64Как эту картинку средствами php5 сохранить на сервер...
Здравствуйте,у меня есть json файл который передается с формы на серверКак мне вывести все checked элементы в таблицу на PHP для отправки на эмейл