Подключиться к mysql в контейнере докеров с хоста


109

(Вероятно, это глупый вопрос из-за моих ограниченных знаний в области администрирования Docker или mysql, но, поскольку я потратил на эту проблему целый вечер, осмелюсь задать его.)

В двух словах

Я хочу запустить mysql в контейнере докеров и подключиться к нему с моего хоста. На данный момент лучшее, что я достиг:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

Подробнее

Я использую следующее Dockerfile:

FROM ubuntu:14.04.3
RUN apt-get update && apt-get install -y mysql-server

# Ensure we won't bind to localhost only
RUN grep -v bind-address /etc/mysql/my.cnf > temp.txt \
  && mv temp.txt /etc/mysql/my.cnf

# It doesn't seem needed since I'll use -p, but it can't hurt
EXPOSE 3306

CMD /etc/init.d/mysql start && tail -F /var/log/mysql.log

В каталоге, где находится этот файл, я могу успешно создать образ и запустить его с помощью:

> docker build -t my-image .
> docker run -d -p 12345:3306 my-image

Когда я прикрепляю к изображению, кажется, что он работает нормально:

# from the host
> docker exec -it <my_image_name> bash

#inside of the container now
$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
[...]

Однако я не добился большого успеха от хозяина:

> mysql -P 12345 -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

Еще больше деталей

  • Я видел, что есть вопрос, похожий на мой . Однако это не то же самое (и на него все равно нет ответов)
    • Я видел, что есть изображения, посвященные mysql , но я не добился большего успеха с ними
    • Это grep -vможет показаться странным. По общему признанию, может быть более чистый способ сделать это. Но когда я прикрепляю свое изображение, я вижу, что оно действительно работает, как ожидалось (то есть: удалено bind-address). И я вижу в контейнере /var/log/mysql/error.log:

Имя хоста сервера (адрес привязки): '0.0.0.0'; порт: 3306 - «0.0.0.0» преобразуется в «0.0.0.0»; Серверный сокет создан на IP: '0.0.0.0'.


1
Наверное, не так уж и тупо. Я наткнулся на это уже в 10-й раз и, наконец, получил время попробовать это дома.
kiltek

Ответы:


171

Если ваш хост Docker MySQL работает правильно, вы можете подключиться к нему с локального компьютера, но вы должны указать хост, порт и протокол следующим образом:

mysql -h localhost -P 3306 --protocol=tcp -u root

Измените 3306 на номер порта, который вы перенаправили из контейнера Docker (в вашем случае это будет 12345).

Поскольку вы запускаете MySQL внутри контейнера Docker, сокет недоступен, и вам необходимо подключиться через TCP. Установка "--protocol" в команде mysql изменит это.


1
Вы можете уточнить, почему сокет mysql недоступен? Ваша команда работает, но мне интересно, есть ли способ подключить сокет mysql к хосту из контейнера.
Лукас

9
Я не специалист в области связи Unix, но насколько я понимаю, сокет - это соединение, представленное в виде файла. Поскольку файл сокета не используется совместно контейнером Docker и хост-машиной, клиент MySQL не может использовать его изнутри контейнера Docker. Чтобы подключиться к серверу MySQL внутри контейнера Docker с хост-машины, вы можете: 1. Настроить сервер MySQL на размещение сокета в указанном месте --socket=/var/run/mysqld/mysqld.sock2. Смонтировать этот файл вне контейнера Docker 3. Укажите путь к сокету в клиенте MySQL с помощью--socket=/host/mysql.sock
maniekq

@maniekq Отличный комментарий! Но вы проверили все свои три возможности? Все ли они действительно работают?
Андру

7
После долгой борьбы я нашел этот золотой ответ, --protocol=tcpнаконец, установил соединение. Спасибо @maniekq как за хороший ответ, так и за ваше объяснение о сокетах в вашем комментарии!
panepeter

1
Это не должно быть общепринятым ответом, поскольку он прямо заявляет, что не имеет представления о передаче файлов UNIX.
kiltek

50

Если вы используете "127.0.0.1" вместо localhost, mysql будет использовать метод tcp, и вы сможете подключить контейнер с помощью:

mysql -h 127.0.0.1 -P 3306 -u root

4
Я могу убедиться, что после того, как я изменил localhost на 127.0.0.1 и удалил флаг протокола, он работал так же,
Крейг Уэйн,

2
Думаю, это самый короткий и лучший ответ;)
rezam

1
Может быть, кратко, но это не ответ, учитывая, что TCP является более медленным методом взаимодействия с mysql. (больше ЦП и большая задержка)
Джон,

1
@John, ты прав, он медленнее, но он существует. Конечно, вы можете поделиться /var/run/mysqld/mysqld.sock между хостом и контейнером.
Василий Паскаль

2
Это то, что я бы рекомендовал для любой базы данных с более высокими требованиями. это так же просто, как "-v socketfile.sock", а затем mysql --socket /path/file.sock, не загрязняя стек tcp / ip.
Джон

27

Я рекомендую проверить docker-compose. Вот как это будет работать:

Создайте файл с именем docker-compose.yml, который выглядит так:

version: '2'

services:

  mysql:
    image: mariadb:10.1.19
    ports:
      - 8083:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: wp

Далее запускаем:

$ docker-compose up

Ноты:

Теперь вы можете получить доступ к консоли mysql следующим образом:

$ mysql -P 8083 --protocol = tcp -u корень -p

Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.5-10.1.19-MariaDB-1~jessie mariadb.org binary distribution

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Ноты:

  • Вы можете передать флаг -d для запуска контейнера mysql / mariadb в автономном / фоновом режиме.

  • Пароль - «wp», который определен в файле docker-compose.yml.

  • Тот же совет, что и maniekq, но полный пример с docker-compose.


3
--protocol=tcpисправил все для меня. Спасибо!
Charlie L

Спасибо за этот ответ, у меня была та же проблема, что и в теме, но после использования --protocol = tcp она исправлена. Я думал, что с докерной сетью что-то не так.
jiriki

16

Самый простой способ - поделиться сокетом mysql unix с хост-машиной. Затем подключите через розетку

Шаги:

  • Создайте общую папку для хост-машины, например: mkdir /host
  • Запустите контейнер докеров с опцией монтирования тома docker run -it -v /host:/shared <mysql image>.
  • Затем измените файл конфигурации mysql /etc/my.cnfи измените запись сокета в файле наsocket=/shared/mysql.sock
  • Перезапустите службу MySQL service mysql restartв докере
  • Наконец, подключитесь к серверу MySQL с хоста через сокет mysql -u root --socket=/host/mysql.sock. Если пароль использовать параметр -p

1
Обязательно ли это делать, если клиент MySQL находится в другом контейнере?
Стефан

Я этого не знаю. Я выбрал этот метод, потому что метод порта tcp-ip у меня не работал. Если вы используете два контейнера для сервера и клиента, вы можете использовать общий каталог для обоих контейнеров и использовать сокет Unix для подключения к MySQL.
Jobin

1
Ответ на мой вопрос - нет, когда я использую docker-compose со ссылкой на контейнеры.
Стефан

9

если вы запускаете докер под докер-машиной?

выполнить, чтобы получить ip:

docker-machine ip <machine>

возвращает ip для машины и попробуйте подключить mysql:

mysql -h<docker-machine-ip>

Решено в Docker-Toolbox :) Большое спасибо.
Vuong

5

Я делаю это путем запуска временного контейнера докеров на моем сервере, поэтому мне не нужно беспокоиться о том, что установлено на моем хосте. Сначала я определяю, что мне нужно (что вам следует изменить для своих целей):

export MYSQL_SERVER_CONTAINER=mysql-db
export MYSQL_ROOT_PASSWORD=pswd 
export DB_DOCKER_NETWORK=db-net
export MYSQL_PORT=6604

Я всегда создаю новую сеть докеров, которая понадобится любым другим контейнерам:

docker network create --driver bridge $DB_DOCKER_NETWORK

Запустите сервер базы данных mySQL:

docker run --detach --name=$MYSQL_SERVER_CONTAINER --net=$DB_DOCKER_NETWORK --env="MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD" -p ${MYSQL_PORT}:3306 mysql

Захватить IP-адрес нового контейнера сервера

export DBIP="$(docker inspect ${MYSQL_SERVER_CONTAINER} | grep -i 'ipaddress' | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])')"

Откройте интерфейс командной строки для сервера:

docker run -it -v ${HOST_DATA}:/data --net=$DB_DOCKER_NETWORK --link ${MYSQL_SERVER_CONTAINER}:mysql --rm mysql sh -c "exec mysql -h${DBIP} -uroot -p"

Этот последний контейнер удалится сам по себе, когда вы выйдете из интерфейса mySQL, в то время как сервер продолжит работу. Вы также можете совместно использовать том между сервером и хостом, чтобы упростить импорт данных или сценариев. Надеюсь это поможет!


5
mysql -u root -P 4406 -h localhost --protocol=tcp -p

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


2

Для конвертации , вы можете создать ~/.my.cnfфайл на хосте:

[Mysql]
user=root
password=yourpass
host=127.0.0.1
port=3306

Затем в следующий раз просто запустите mysqlклиент mysql, чтобы открыть соединение.


1

Мне удалось подключить свой sql server5.7, работающий на моем хосте, с помощью следующей команды: mysql -h 10.10.1.7 -P 3307 --protocol = tcp -u root -p, где указанный ip - это мой IP-адрес хоста, а 3307 - это порт переадресован в mysql docker. После ввода команды введите пароль для myql. это он. Теперь вы подключили контейнер mysql docker с вашего хост-компьютера.


0

выполните следующую команду, чтобы запустить контейнер

docker run --name db_name -e MYSQL_ROOT_PASSWORD=PASS--publish 8306:3306 db_name

запустите эту команду, чтобы получить mysql db на хост-машине

mysql -h 127.0.0.1 -P 8306 -uroot  -pPASS

в вашем случае это

mysql -h 127.0.0.1 -P 12345 -uroot  -pPASS

Это работает, только если вы используете 127.0.0.1 в качестве адреса. Если вы используете нелокальный адрес хоста, вам необходимо добавить --protocol=tcpфлаг, как описано в нескольких других комментариях / ответах. В моем случае это сбивало с толку, потому что у меня также был запущен локальный экземпляр mysql без докеров. По умолчанию, даже если порт указан, даже если порт неверен, команда mysql будет подключаться через файл сокета к локальному экземпляру.
Rich

@Rich, что ты сделал, чтобы решить эту проблему? Даже у меня аналогичная настройка: один MySql работает на хосте, а другой - в контейнере докеров.
NITHIN RAJ T

@NITHINRAJT есть 2 способа выполнить это ПОСЛЕ того, как вы убедитесь, что ваш экземпляр докера не прослушивает тот же порт (например, как в этом ответе, 8306). (1) Попробуйте этот ответ, тот, который мы комментируем (например, подключение к 127.0.0.1. (2) Попробуйте следующий ответ - mysql -u root -P <EXPOSED_DOCKER_PORT_HERE> -h <YOUR_HOST_IP_ADDRESS_HERE> --protocol=tcp -p. Флаг --protocol=tcpявляется ключом к выполнению этой работы.
Rich,


0

ХОРОШО. Я наконец решил эту проблему. Здесь следует мое решение, используемое в https://sqlflow.org/sqlflow .

Полное решение

Чтобы сделать демонстрацию автономной, я переместил весь необходимый код на https://github.com/wangkuiyi/mysql-server-in-docker .

Ключ к решению

Я не использую официальный образ на DockerHub.com https://hub.docker.com/r/mysql/mysql-server . Вместо этого я сделал свой собственный, установив MySQL на Ubuntu 18.04. Такой подход дает мне возможность запустить mysqld и привязать его к 0.0.0.0 (все IP-адреса) .

За подробностями обращайтесь к этим строкам в моем репозитории GitHub.

SQLFLOW_MYSQL_HOST=${SQLFLOW_MYSQL_HOST:-0.0.0.0}

echo "Start mysqld ..."
sed -i "s/.*bind-address.*/bind-address = ${SQLFLOW_MYSQL_HOST}/" \
    /etc/mysql/mysql.conf.d/mysqld.cnf
service mysql start

Чтобы проверить мое решение

  1. Git клонирует вышеупомянутый репо.
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
  2. Создайте образ Docker сервера MySQL
    docker build -t mysql:yi .
  3. Запустить сервер MySQL в контейнере
    docker run --rm -d -p 23306:3306 mysql:yi
  4. Если еще нет, установите клиент MySQL на хост. Я запускаю Ubuntu 18.04 на хосте (моей рабочей станции), поэтому использую apt-get.
    sudo apt-get install -y mysql-client
  5. Подключитесь от хоста к серверу MySQL, работающему в контейнере.
    mysql --host 127.0.0.1 --port 23306 --user root -proot

Подключиться из другого контейнера на том же хосте

Мы можем запустить клиент MySQL даже из другого контейнера (на том же хосте).

docker run --rm -it --net=host mysql/mysql-server mysql \
   -h 127.0.0.1 -P 13306 -u root -proot

Подключиться с другого хоста

На моем iMac я устанавливаю клиент MySQL с помощью Homebrew.

brew install mysql-client
export PATH="/usr/local/opt/mysql-client/bin:$PATH"

Затем я могу получить доступ к указанному выше хосту Ubuntu (192.168.1.22).

mysql -h 192.168.1.22 -P 13306 -u root -proot

Подключение из контейнера, запущенного на другом хосте

Я даже могу запустить клиент MySQL в контейнере на iMac, чтобы подключиться к серверу MySQL в контейнере на моей рабочей станции Ubuntu.

docker run --rm -it --net=host mysql/mysql-server mysql \
    -h 192.168.1.22 -P 13306 -u root -proot

Особый случай

В случае, если мы запускаем клиент и сервер MySQL в отдельных контейнерах, работающих на одном и том же хосте - это может произойти, когда мы настраиваем CI, нам не нужно создавать собственный образ Docker сервера MySQL. Вместо этого мы можем использовать --net=container:mysql_server_container_nameпри запуске клиентского контейнера.

Для запуска сервера

docker run --rm -d --name mysql mysql/mysql-server

Для запуска клиента

docker run --rm -it --net=container:mysql mysql/mysql-server mysql \
 -h 127.0.0.1 -P 3306 -u root -proot

-1
  • docker run -e MYSQL_ROOT_PASSWORD = pass --name sql-db -p 3306: 3306 mysql

  • docker exec -it sql-db bash

  • mysql -u корень -p


что закончитсяERROR 1524 (HY000): Plugin 'unix_socket' is not loaded
Enerccio

@Enerccio Не могли бы вы попробовать еще раз?
Аджай Сингх

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.