เชื่อมต่อกับ mysql ใน Docker container จากโฮสต์


111

(อาจเป็นคำถามที่โง่เนื่องจากความรู้ที่ จำกัด ของฉันเกี่ยวกับ 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

คำตอบ:


174

หากโฮสต์ Docker MySQL ของคุณทำงานอย่างถูกต้องคุณสามารถเชื่อมต่อจากเครื่องภายในได้ แต่คุณควรระบุโฮสต์พอร์ตและโปรโตคอลดังนี้:

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

เปลี่ยน 3306 เป็นหมายเลขพอร์ตที่คุณส่งต่อจากคอนเทนเนอร์ Docker (ในกรณีของคุณจะเป็น 12345)

เนื่องจากคุณใช้ MySQL ภายในคอนเทนเนอร์ Docker จึงไม่สามารถใช้ซ็อกเก็ตได้และคุณต้องเชื่อมต่อผ่าน TCP การตั้งค่า "--protocol" ในคำสั่ง mysql จะเปลี่ยนสิ่งนั้น


1
คุณช่วยชี้แจงได้ไหมว่าทำไมซ็อกเก็ต mysql ไม่สามารถใช้งานได้? คำสั่งของคุณใช้งานได้ แต่ฉันสงสัยว่ามีวิธีเมาท์ซ็อกเก็ต mysql กับโฮสต์จากคอนเทนเนอร์หรือไม่
Lucas

9
ฉันไม่ใช่ผู้เชี่ยวชาญในการสื่อสาร Unix แต่จากสิ่งที่ฉันเข้าใจว่าซ็อกเก็ตคือการเชื่อมต่อที่แสดงเป็นไฟล์ เนื่องจากไฟล์ซ็อกเก็ตไม่ได้ใช้ร่วมกันระหว่างคอนเทนเนอร์ Docker และเครื่องโฮสต์ไคลเอ็นต์ MySQL จึงไม่สามารถใช้ไฟล์จากภายในคอนเทนเนอร์ Docker ได้ ในการเชื่อมต่อกับเซิร์ฟเวอร์ MySQL ภายในคอนเทนเนอร์ Docker จากเครื่องโฮสต์คุณสามารถ: 1. ตั้งค่าเซิร์ฟเวอร์ MySQL ให้ใส่ซ็อกเก็ตในตำแหน่งที่ระบุ--socket=/var/run/mysqld/mysqld.sock2. ติดตั้งไฟล์นี้นอกคอนเทนเนอร์ Docker 3. ระบุเส้นทางไปยังซ็อกเก็ตในไคลเอนต์ MySQL ด้วย--socket=/host/mysql.sock
maniekq

@maniekq คอมเม้นสุดยอด! แต่คุณตรวจสอบความเป็นไปได้ทั้งสามของคุณแล้วหรือยัง? พวกเขาทั้งหมดทำงานจริงหรือไม่?
Andru

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 และลบแฟล็กโปรโตคอลมันก็ใช้งานได้เหมือนเดิม
Craig Wayne

2
ฉันคิดว่านี่เป็นคำตอบที่สั้นและดีที่สุด;)
rezam

1
อาจสั้น แต่ไม่ใช่คำตอบเนื่องจาก TCP เป็นวิธีที่ช้ากว่าในการสื่อสารกับ mysql (CPU มากขึ้นและเวลาแฝงที่สูงขึ้น)
John

1
@ จอห์นคุณพูดถูกมันช้ากว่า แต่มันมีอยู่จริง แน่นอนว่าคุณสามารถแชร์ /var/run/mysqld/mysqld.sock ระหว่างโฮสต์และคอนเทนเนอร์ได้
Vasili Pascal

2
นั่นคือสิ่งที่ฉันขอแนะนำสำหรับฐานข้อมูลหน้าที่สูงกว่า มันง่ายเหมือน "-v socketfile.sock" ตามด้วย mysql --socket /path/file.sock โดยไม่ทำให้กอง tcp / ip เป็นมลพิษ
John

27

ฉันขอแนะนำให้ลองใช้นักเทียบเคียงเขียน นี่คือวิธีการทำงาน:

สร้างไฟล์ชื่อ 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 ขึ้น

หมายเหตุ:

ตอนนี้คุณสามารถเข้าถึงคอนโซล 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>

หมายเหตุ:

  • คุณสามารถส่งแฟล็ก -d เพื่อรันคอนเทนเนอร์ mysql / mariadb ในโหมดแยก / พื้นหลัง

  • รหัสผ่านคือ "wp" ซึ่งกำหนดไว้ในไฟล์ docker-compose.yml

  • คำแนะนำเช่นเดียวกับ maniekq แต่เป็นตัวอย่างเต็มรูปแบบด้วยนักเทียบท่าเขียน


3
--protocol=tcpแก้ไขทุกอย่างให้ฉัน ขอบคุณ!
Charlie L

ขอบคุณสำหรับคำตอบนี้ฉันมีปัญหาเดียวกันกับในหัวข้อนี้ แต่หลังจากใช้ --protocol = tcp มันได้รับการแก้ไขแล้ว ฉันคิดว่ามีบางอย่างผิดปกติกับ Docker Network
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ใน Docker
  • สุดท้ายเชื่อมต่อกับ MySQL servver mysql -u root --socket=/host/mysql.sockจากโฮสต์ผ่านซ็อกเก็ต หากรหัสผ่านใช้ตัวเลือก -p

1
คุณต้องทำเช่นนี้หรือไม่ถ้าไคลเอนต์ MySQL อยู่ในคอนเทนเนอร์อื่น?
Stephane

ฉันไม่รู้ว่า ฉันเลือกวิธีนี้เพราะวิธีการพอร์ต tcp-ip ไม่ได้ผลสำหรับฉัน หากคุณใช้สองคอนเทนเนอร์สำหรับเซิร์ฟเวอร์และไคลเอนต์คุณสามารถแชร์ไดเร็กทอรีทั่วไปกับทั้งสองคอนเทนเนอร์และใช้ซ็อกเก็ต Unix เพื่อเชื่อมต่อกับ MySQL
Jobin

1
คำตอบสำหรับคำถามของฉันคือไม่เมื่อฉันใช้นักเทียบท่าเขียนกับลิงก์บนคอนเทนเนอร์
Stephane

9

ถ้าคุณใช้นักเทียบท่าภายใต้ Docker-machine?

ดำเนินการเพื่อรับ 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 คือ พอร์ต forwaded ใน mysql docker หลังจากป้อนคำสั่งแล้วให้พิมพ์รหัสผ่านสำหรับ myql นั่นคือมันตอนนี้คุณเชื่อมต่อคอนเทนเนอร์นักเทียบท่า mysql จากโฮสต์ของคุณ


1

ตกลง. ในที่สุดฉันก็แก้ปัญหานี้ได้ นี่ต่อไปนี้วิธีการแก้ปัญหาของผมที่ใช้ใน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 (IPS ทั้งหมด)

สำหรับรายละเอียดโปรดดูบรรทัดเหล่านี้ใน repo 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 โคลน repo ดังกล่าวข้างต้น
    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

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' จะเชื่อมต่อผ่านไฟล์ซ็อกเก็ตไปยังอินสแตนซ์ภายในเครื่อง
รวย

@ รวยแล้วคุณทำอะไรเพื่อแก้ปัญหานั้น? แม้ว่าฉันจะมีการตั้งค่าที่คล้ายกัน แต่ 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คือกุญแจสำคัญในการทำงานนี้
รวย



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.