Не могу подружить Elasticsearch и Laravel

Есть вот такой метод

public function esSearch() {
    $client = ClientBuilder::create()->setHosts(['172.20.0.1:9200'])->build();
    
    $params = [
        'index' => 'my_index',
        'id' => 'test_id',
        'body' => ['testField' => 'abc']
    ];

    $result = $client->index($params);
    dd($result);
}

В итоге получаю ошибку 504 Gateway Time-out

Все это дело крутится вертится в докере, у контейнера где Laravel задан статический ip, поэтому метод написал таким образом setHosts(['172.20.0.1:9200']), если заменить ip на localhost, то получаю No alive nodes found in your cluster

version: '3'
services:
#PHP Service
app:
    build:
        context: .
        dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
        SERVICE_NAME: app
        SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
        - ./:/var/www
        - ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
        postgres:
            ipv4_address: 172.20.128.2
#Nginx Service
webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
        - "80:80"
        - "443:443"
    volumes:
        - ./:/var/www
        - ./docker/nginx/conf.d/:/etc/nginx/conf.d/
    networks:
        - postgres
#Redis
redis:
    image: 'redis:alpine'
    ports:
        - "6379:6379"
#PostgreSQL        
postgres:
    container_name: postgres_container
    image: postgres
    hostname: postgres
    environment:
        POSTGRES_DB: postgres
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: secret
        PGDATA: /data/postgres
    volumes:
        - postgres:/data/postgres
    ports:
        - "5432:5432"
    networks:
        - postgres
    restart: unless-stopped

pgadmin:
    container_name: pgadmin_container
    image: dpage/pgadmin4
    environment:
        PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:[email protected]}
        PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin}
    volumes:
        - pgadmin:/root/.pgadmin
    ports:
        - "${PGADMIN_PORT:-5050}:80"
    networks:
        - postgres
    restart: unless-stopped  
    depends_on: 
        - postgres     
#RabbitMQ
rabbit:
    image: "rabbitmq:3-management"
    hostname: "rabbit"
    environment:
        RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
        RABBITMQ_DEFAULT_USER: "rabbitmq"
        RABBITMQ_DEFAULT_PASS: "rabbitmq"
        RABBITMQ_DEFAULT_VHOST: "/"
    ports:
        - "15672:15672"
        - "5672:5672"
    labels:
        NAME: "rabbitmq"    
    networks:
        - postgres     
#ElasticSearch
es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.0.1
    container_name: es01
    environment:
        - cluster.initial_master_nodes=es01
    ulimits:
        memlock:
            soft: -1
            hard: -1
    ports:
        - "9200:9200"
        - "9300:9300"
    networks:
        - postgres

kibana:
    image: docker.elastic.co/kibana/kibana:6.2.4
    container_name: kibana
    ports:
        - "5601:5601"
    depends_on:
        - es01
    networks:
        - postgres                    
#Docker Networks
networks:
    postgres:
        ipam:
            config:
                - subnet: 172.20.0.0/16

volumes:
    postgres:
        pgadmin: 

Ответы (1 шт):

Автор решения: Total Pusher

Небольшое пояснение

docker-compose - это "обертка" над докером, сделана для удобства. В частности, команда создает подсети.

Поднимите ваши контейнеры docker-compose up и выполните docker network list - увидите все подсети докера. В этом списке будут как подсети, созданные из файла docker-compose.yml, так и другие, созданные в других проектах.

Теперь запустите ip route и вы увидите роуты типа br-... - их насоздавал докер.

Затем выполните docker-compose ps - увидите список контейнеров, и порты которые они прослушивают. Если видите 9000/tcp - значит порт виден только внутри подсети докера, и не виден с хост-машины. А если 0.0.0.0:8087->80/tcp - значит порт виден с хост-машины как 8087, и перенаправляется на 80 порт контейнера.

Среди них будет postgres - эта сеть прописана в файле. К ней подключены все ваши контейнеры. Поэтому к эластику можно обратиться как es01:9200 и es01:9300 - то есть прямо по названию контейнера и порта. Но так можно сделать только внутри контейнеров этой подсети, потому что докер имеет свой DNS-резолвер, каждый контейнер имеет свой IP адрес, и поэтому через localhost невозможно обратиться к другому контейнеру. А с хост машины можно подключиться через localhost:9200.

Я постарался расписать как это работает, потому что без понимания механики работы докер выглядит как какое-то волшебство.

Решение

Итак, вам нужно вместо IP адреса использовать название контейнера:

->setHosts(['es01:9200'])

а докер сам разрешит es01в IP адрес.

Можете даже войти в какой-нибудь контейнер и попинговать соседа.

docker-compose exec app bash, и в нем ping es01. Если в контейнере app есть bash, ping и сосед доступен, вы увидите пинги и реальный IP адрес - используйте такой прием для траблшутинга.

→ Ссылка