Как запустить несколько Docker-контейнеров с MySQL на одном порту и на одном хосте?

Хочу на VPS с одним IP-адресом запускать докер контейнеры с сайтами и базами данных.
С помощью Nginx-proxy сделал доступ по 80 порту для nginx-контейнеров с сайтами.
Попробовал сделать то же самое с MySQL на 3306 порту - не получилось.
Привожу пример своих docker-compose файлов с Nginx-proxy и с MySQL контейнером.

Nginx-proxy:
services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:alpine
    restart: always
    ports:
      - 3306:3306
    networks:
      - nginx-proxy
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./settings.conf:/etc/nginx/conf.d/settings.conf:ro
networks:
  nginx-proxy:


MySQL:
services:
  mysql:
    image: mysql:8.2
    restart: always
    environment:
      MYSQL_DATABASE: example.com
      MYSQL_ROOT_PASSWORD: password
      VIRTUAL_HOST: example.com
      VIRTUAL_PORT: 3306

    volumes:
      - ./databases/mysql:/var/lib/mysql
      - ./docker/mysql:/etc/mysql/conf.d
    expose:
      - 3306

networks:
  nginx-proxy:
    name: proxy_nginx-proxy
    external: true


В подключении к БД указываю следующие данные:

user: root
password: password
host: example.com
port: 3306


При подключении получаю ошибку:

"2013 - Lost connection to server at 'handshake: reading initial communication packet', system error: 35"

В логах MySQL и в логах Nginx-proxy нет ничего, что указывало бы на эту ошибку.

Как быть с базами данных?
Вижу 2 варианта:
1. Отказаться от идеи реверс-прокси для баз данных и прокидывать на каждый контейнер с БД свой порт. Мне не нравится это решение, так как контейнеров будет много и может возникнуть путаница с портами. Гораздо удобнее было бы подключаться по имени хоста и одному порту.

2. Попробовать вместо nginx-proxy использовать Traefik. Ни разу с ним не работал и не знаю насколько он хорош.

Вопрос:

1. Что я делаю не так в текущей конфигурации и как исправить эту ошибку?
2. Насколько сильно Traefik и Nginx-proxy влияют на скорость ответа сервера при обращении к сайтам?
  • Вопрос задан
  • 5160 просмотров
Решения вопроса 2
martin74ua
@martin74ua
Linux administrator
В http протоколе есть заголовок, позволяющий определить, к какому сайту делается запрос.
в mysql протоколе нет такого признака.
так что вешайте мускул серверы на разные порты.
Ответ написан
@PendalF89 Автор вопроса
Решил оставить реверс-прокси только для Nginx. Для БД решил сделать реестр портов/сайтов в таблице Excel (чтобы не запутаться) и подключаться по IP и уникальному порту. Traefik вроде бы может с MySQL работать, но нормальной инструкции я не нашёл, да и избыточен он для этой задачи.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
dimonchik2013
@dimonchik2013
non progredi est regredi
services:
    db_logistics:
        image: mysql:5.7
        volumes:
            - mysql_bkp_logistics:/var/lib/mysql
    db_products:
        image: mysql:5.7
        volumes:
            - mysql_bkp_products:/var/lib/mysql

volumes:
    mysql_bkp_logistics:
    mysql_bkp_products:
Ответ написан
@WebMonet
Как решить вашу проблему?

Дано - хост 1.2.3.4
К нему привязаны домены foo.com, bar.com, baz.org. За каждым доменом закреплен сайт, который состоит из PHP, Nginx, MySQL (далее по вкусу). Назовем каждый сайт приложением. С помощью docker-compose можно запустить примерно вот такой конфиг

version: "3.6"
networks:
    app_network:
        name: foo_net

services:

    nginx: 
        ports:
            -   target: 80
                published: ${APP_PORT}
                protocol: tcp
                mode: host
        volumes:
            - ./:/var/www/html
        networks:
            - app_network      

    php:
        build:
         ...
        volumes:
            - ./:/var/www/html
        networks:
            - app_network

    db_server: 
        ports:
            -   target: 3306
                published: '${APP_DB_PORT}'
        volumes:
            - ../mysql:/var/lib/mysql
        networks:
            - app_network

    node:
        depends_on:
            - php
        volumes:
            - ./:/var/www/html:rw
        command: npm install && npm run dev
        networks:
            - app_network


Прикол в том, что все контейнеры одного приложения видят друг-друга в пределах одной виртуальной сети (app_network) даже без EXPOSE. EXPOSE связывает целевой порт контейнера с портом хоста (1.2.3.4) Без него nginx прекрасно видит PHP-FPM по порту 9000 (только имя контейнера должно быть правильным. В данном примере это будет php:9000)
....
location ~* \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass<b> php:9000;</b>
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
...


, PHP видит mysql по дефолтному порту 3306. Возникает вопрос, зачем же мы прокинули на хост какой-то ${APP_DB_PORT} от db_server. ответ прост - по этому порту можно подключиться напрямую к БД из своей любимой IDE, phpMyAdmin и.д. Соответственно, внешний порт БД для foo.com может быть 33061, для bar.com 33062 а для baz.org - 33063.
Такая же история и с NGINX, который выступает у нас фронтендом приложений. Мы слушаем на хосте ${APP_PORT} и прокидываем из него все в 80 порт соответствующего контейнера. Получается, что по порту 1080 нам ответит foo.com, 1180 - bar.com, а 1280 - baz.org. В итоге, у нас уже на одном хосте крутятся 3 приложения / сайта, которые не мешают друг-другу (и даже не подозревают о существовании друг-друга)
Остается самая малость - выпустить их в интернет. Тут все совсем просто: поднимаете nginx/haproxy/etc и говорите им, что для хостнейма foo.com используй апстрим 127.0.0.1:1080, для bar.com 127.0.0.1:1180 и угадайте сами, что для baz.org. Внимательно отнеситесь к слешам на конце апстрима. Документация вам расскажет, когда они нужны, а когда нет.
Откуда взялись переменные типа ${APP_PORT} ? Их можно задавать в .env файликах, которые будут лежать рядом с docker-compose.yml.

APP_PORT=1180
APP_DB_PORT=33062


В итоге, всех встречает шлюз, в соответствии с именем хоста раскидывает по апстримам, а внутри приложения контейнеры уже сами видят друг-друга.
Схема 100% рабочая, но не без изъянов. Для продакшена повнимательнее изучите нюансы. За подробностями приходите в личку и на мой курс про докер для PHP-разработчиков.
Ответ написан
@rusik2293
Без прокси подключается?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы