Połącz się z mysql w kontenerze docker z hosta


109

(Prawdopodobnie jest to głupie pytanie ze względu na moją ograniczoną wiedzę z administracją Docker lub mysql, ale ponieważ spędziłem cały wieczór nad tym problemem, odważę się je zadać.)

W skrócie

Chcę uruchomić mysql w kontenerze docker i połączyć się z nim z mojego hosta. Jak dotąd najlepsze, co osiągnąłem, to:

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

Więcej szczegółów

Używam następujących 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

W katalogu, w którym znajduje się ten plik, mogę pomyślnie zbudować obraz i uruchomić go za pomocą:

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

Kiedy dołączam do obrazu, wydaje się, że działa dobrze:

# 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.
[...]

Jednak nie mam takiego sukcesu od gospodarza:

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

Jeszcze więcej szczegółów

  • Widziałem, że jest pytanie, które wygląda jak moje . Jednak to nie jest to samo (i tak nie ma żadnych odpowiedzi)
    • Widziałem, że są obrazy poświęcone mysql , ale nie odniosłem z nimi większego sukcesu
    • Mogę grep -vczuć się dziwnie. Trzeba przyznać, że można to zrobić czystszym sposobem. Ale kiedy dołączam mój obraz, widzę, że faktycznie działał zgodnie z oczekiwaniami (tj: usunął bind-address). I widzę w kontenerze /var/log/mysql/error.log:

Nazwa hosta serwera (adres-wiązania): „0.0.0.0”; port: 3306 - „0.0.0.0” jest zastępowane jako „0.0.0.0”; Gniazdo serwera utworzone na IP: „0.0.0.0”.


1
Prawdopodobnie nie taki głupi. Natknąłem się na to po raz dziesiąty i wreszcie miałem czas, aby wypróbować to w domu.
kiltek

Odpowiedzi:


171

Jeśli twój host Docker MySQL działa poprawnie, możesz połączyć się z nim z lokalnego komputera, ale powinieneś określić hosta, port i protokół w następujący sposób:

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

Zmień 3306 na numer portu, który przekazałeś z kontenera Docker (w twoim przypadku będzie to 12345).

Ponieważ używasz MySQL w kontenerze Docker, gniazdo nie jest dostępne i musisz połączyć się przez TCP. Ustawienie „--protocol” w poleceniu mysql to zmieni.


1
Czy możesz wyjaśnić, dlaczego gniazdo mysql nie jest dostępne? Twoje polecenie działa, ale zastanawiam się, czy istnieje sposób na zamontowanie gniazda mysql do hosta z kontenera.
Lucas

9
Nie jestem ekspertem w komunikacji uniksowej, ale z tego, co rozumiem, gniazdo jest połączeniem reprezentowanym jako plik. Ponieważ plik gniazda nie jest współużytkowany między kontenerem Docker a maszyną hosta, klient MySQL nie może używać go z wnętrza kontenera Docker. Aby połączyć się z serwerem MySQL wewnątrz kontenera Docker z komputera hosta, możesz: 1. Ustawić serwer MySQL tak, aby umieścić gniazdo w określonym miejscu --socket=/var/run/mysqld/mysqld.sock2. Zamontować ten plik poza kontenerem Docker 3. Określić ścieżkę do gniazda w kliencie MySQL za pomocą--socket=/host/mysql.sock
maniekq

@maniekq Świetny komentarz! Ale czy zweryfikowałeś wszystkie swoje trzy możliwości? Czy wszystkie naprawdę działają?
Andru,

7
Po długich zmaganiach znalazłem tę złotą odpowiedź, w --protocol=tcpkońcu udało mi się połączyć. Dzięki @maniekq zarówno za miłą odpowiedź, jak i wyjaśnienie dotyczące gniazd w komentarzu!
panepeter

1
Nie powinna to być akceptowana odpowiedź, ponieważ wyraźnie stwierdza, że ​​nie ma pojęcia o komunikacji plików w systemie UNIX.
kiltek

50

Jeśli użyjesz „127.0.0.1” zamiast localhost, mysql użyje metody tcp i powinieneś być w stanie połączyć kontener z:

mysql -h 127.0.0.1 -P 3306 -u root

4
Mogę sprawdzić, czy kiedy zmieniłem localhost na 127.0.0.1 i usunąłem flagę protokołu, zadziałało to samo
Craig Wayne

2
Myślę, że to krótka i najlepsza odpowiedź;)
rezam

1
Może być krótkie, ale to nie jest odpowiedź, biorąc pod uwagę, że TCP jest wolniejszą metodą komunikacji z mysql. (więcej procesora i większe opóźnienie)
John

1
@John, masz rację, jest wolniejszy, ale istnieje. Oczywiście możesz udostępniać /var/run/mysqld/mysqld.sock między hostem a kontenerem.
Vasili Pascal

2
To właśnie zalecałbym dla każdego DB o wyższym obciążeniu. jest to tak proste, jak „-v plik_gniazda.sock”, a następnie mysql --socket /path/file.sock bez zanieczyszczania stosu tcp / ip.
John

27

Polecam sprawdzić docker-compose. Oto jak to by działało:

Utwórz plik o nazwie docker-compose.yml, który wygląda następująco:

version: '2'

services:

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

Następnie uruchom:

$ docker-compose up

Uwagi:

Teraz możesz w ten sposób uzyskać dostęp do konsoli mysql:

$ mysql -P 8083 --protocol = tcp -u root -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>

Uwagi:

  • Możesz przekazać flagę -d, aby uruchomić kontener mysql / mariadb w trybie odłączonym / w tle.

  • Hasło to „wp”, które jest zdefiniowane w pliku docker-compose.yml.

  • Ta sama rada co maniekq, ale pełny przykład z docker-compose.


3
--protocol=tcpnaprawiłem wszystko dla mnie. Dziękuję Ci!
Charlie L

Dzięki za tę odpowiedź, miałem ten sam problem co w temacie, ale po użyciu --protocol = tcp naprawiono. Myślałem, że coś jest nie tak z siecią Docker.
jiriki

16

Prostą metodą jest udostępnienie gniazda mysql unix maszynie hosta. Następnie podłącz przez gniazdo

Kroki:

  • Utwórz folder współdzielony dla komputera hosta, np .: mkdir /host
  • Uruchom kontener Docker z opcją montowania woluminu docker run -it -v /host:/shared <mysql image>.
  • Następnie zmień plik konfiguracyjny mysql /etc/my.cnfi zmień wpis gniazda w pliku nasocket=/shared/mysql.sock
  • Uruchom ponownie usługę MySQL service mysql restartw dockerze
  • Na koniec połącz się z serwerem MySQL z hosta przez gniazdo mysql -u root --socket=/host/mysql.sock. W przypadku hasła użyj opcji -p

1
Czy musisz to zrobić, jeśli klient MySQL znajduje się w innym kontenerze?
Stephane

Nie wiem tego. Wybrałem tę metodę, ponieważ metoda portu TCP-IP nie działała dla mnie. Jeśli używasz dwóch kontenerów dla serwera i klienta, możesz udostępnić wspólny katalog dla obu kontenerów i użyć gniazda Unix do połączenia z MySQL.
Jobin

1
Odpowiedź na moje pytanie brzmi: nie, kiedy używam docker-compose z linkiem na kontenerach.
Stephane

9

jeśli uruchamiasz docker w docker-machine?

wykonaj, aby uzyskać adres IP:

docker-machine ip <machine>

zwraca adres IP maszyny i spróbuj połączyć się z mysql:

mysql -h<docker-machine-ip>

Rozwiązany w Docker-Toolbox :) Bardzo dziękuję.
Vuong

5

Robię to, uruchamiając tymczasowy kontener Dockera na moim serwerze, więc nie muszę się martwić, co jest zainstalowane na moim hoście. Najpierw określam, czego potrzebuję (co powinieneś zmodyfikować do swoich celów):

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

Zawsze tworzę nową sieć dockerową, której będą potrzebne inne kontenery:

docker network create --driver bridge $DB_DOCKER_NETWORK

Uruchom serwer bazy danych mySQL:

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

Przechwyć adres IP nowego kontenera serwera

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])')"

Otwórz interfejs wiersza poleceń do serwera:

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"

Ten ostatni kontener usunie się sam po wyjściu z interfejsu mySQL, podczas gdy serwer będzie nadal działał. Wolumen można również udostępniać między serwerem a hostem, aby ułatwić importowanie danych lub skryptów. Mam nadzieję że to pomoże!


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

Pamiętaj, aby zmienić użytkownika, port i hosta, aby pasowały do ​​twoich konfiguracji. Opcja -p jest wymagana, jeśli użytkownik bazy danych jest skonfigurowany przy użyciu hasła


2

Do konwersji , możesz utworzyć ~/.my.cnfplik na hoście:

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

Następnie następnym razem po prostu uruchom mysqlklienta mysql, aby otworzyć połączenie.


1

Udało mi się połączyć mój serwer sql5.7 działający na moim hoście za pomocą poniższego polecenia: mysql -h 10.10.1.7 -P 3307 --protocol = tcp -u root -p, gdzie podane IP to mój adres IP hosta, a 3307 to port forwaded w mysql docker. Po wpisaniu polecenia wpisz hasło do myql. to jest to. teraz jesteś połączony z kontenerem dokera mysql z twojego hosta


0

uruchom następujące polecenie, aby uruchomić kontener

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

uruchom to polecenie, aby uzyskać bazę danych mysql na komputerze-hoście

mysql -h 127.0.0.1 -P 8306 -uroot  -pPASS

w twoim przypadku tak jest

mysql -h 127.0.0.1 -P 12345 -uroot  -pPASS

Działa to tylko wtedy, gdy używasz adresu 127.0.0.1. Jeśli używasz nielokalnego adresu hosta, musisz dodać --protocol=tcpflagę, jak opisano w kilku innych komentarzach / odpowiedziach. W moim przypadku było to wyjątkowo zagmatwane, ponieważ miałem również uruchomioną lokalną, niedokeryzowaną instancję mysql. Domyślnie, nawet jeśli port jest określony, nawet jeśli port jest nieprawidłowy, polecenie „mysql” połączy się przez plik gniazda z lokalną instancją.
Rich

@Rich, więc co zrobiłeś, aby rozwiązać ten problem? Nawet mam podobną konfigurację, jedną MySql działającą na hoście, a drugą w kontenerze docker.
NITHIN RAJ T

@NITHINRAJT są 2 sposoby, aby to osiągnąć PO upewnieniu się, że instancja dockera nie nasłuchuje na tym samym porcie (np. Jak w tej odpowiedzi, 8306). (1) Wypróbuj tę odpowiedź, tę, którą komentujemy (np. Łączenie się z 127.0.0.1. (2) Wypróbuj następną odpowiedź -mysql -u root -P <EXPOSED_DOCKER_PORT_HERE> -h <YOUR_HOST_IP_ADDRESS_HERE> --protocol=tcp -p . Flaga --protocol=tcpjest kluczem do tego, aby to zadziałało.
Bogaty


0

DOBRZE. W końcu rozwiązałem ten problem. Oto moje rozwiązanie użyte w https://sqlflow.org/sqlflow .

Kompletne rozwiązanie

Aby demo było samodzielne, przeniosłem cały niezbędny kod na https://github.com/wangkuiyi/mysql-server-in-docker .

Klucz do rozwiązania

Nie używam oficjalnego obrazu na DockerHub.com https://hub.docker.com/r/mysql/mysql-server . Zamiast tego stworzyłem własne, instalując MySQL na Ubuntu 18.04. Takie podejście daje mi szansę na uruchomienie mysqld i powiązanie go z 0.0.0.0 (wszystkie adresy IP) .

Aby uzyskać szczegółowe informacje, zapoznaj się z tymi wierszami w moim repozytorium 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

Aby zweryfikować moje rozwiązanie

  1. Git sklonuje wspomniane repozytorium.
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
  2. Zbuduj obraz Docker serwera MySQL
    docker build -t mysql:yi .
  3. Uruchom serwer MySQL w kontenerze
    docker run --rm -d -p 23306:3306 mysql:yi
  4. Zainstaluj klienta MySQL na hoście, jeśli jeszcze nie jest. Używam Ubuntu 18.04 na hoście (mojej stacji roboczej), więc używam apt-get.
    sudo apt-get install -y mysql-client
  5. Połącz się z hosta z serwerem MySQL działającym w kontenerze.
    mysql --host 127.0.0.1 --port 23306 --user root -proot

Połącz się z innego kontenera na tym samym hoście

Klienta MySQL możemy uruchomić nawet z innego kontenera (na tym samym hoście).

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

Połącz z innego hosta

Na moim iMacu instaluję klienta MySQL za pomocą Homebrew.

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

Następnie mogę uzyskać dostęp do powyższego hosta Ubuntu (192.168.1.22).

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

Połącz się z kontenera działającego na innym hoście

Mogę nawet uruchomić klienta MySQL w kontenerze działającym na iMacu, aby połączyć się z serwerem MySQL w kontenerze na mojej stacji roboczej Ubuntu.

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

Specjalny przypadek

W przypadku, gdy uruchamiamy klienta i serwer MySQL w oddzielnych kontenerach działających na tym samym hoście - może się to zdarzyć, gdy konfigurujemy CI, nie musimy budować własnego obrazu Docker serwera MySQL. Zamiast tego możemy użyć--net=container:mysql_server_container_name gdy uruchamiamy kontener klienta.

Aby uruchomić serwer

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

Aby uruchomić klienta

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 root -p


to zakończy sięERROR 1524 (HY000): Plugin 'unix_socket' is not loaded
Enerccio

@Enerccio Czy możesz spróbować ponownie?
Ajay Singh

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.