MySQL + Docker เขียน + Nodejs/Python— คำแนะนำทีละขั้นตอน
MySQL เป็นหนึ่งใน ฐานข้อมูลเชิงสัมพันธ์ที่ได้รับความ นิยมสูงสุดตลอดกาล การใช้ MySQL กับ Docker และ docker-compose ทำให้ง่ายและรวดเร็วในการทดสอบการเปลี่ยนแปลงในแอปพลิเคชันใดๆ โดยใช้ MySQL เป็นฐานข้อมูล ในบทช่วยสอนนี้ เราจะให้รายละเอียดวิธีใช้ MySQL กับ Docker และ docker-compose ทีละขั้นตอน ทำให้เข้าใจได้ง่าย
รหัส TLDR ที่นี่ มากลิ้งกัน!
เหตุใดจึงต้องใช้ MySQL กับ Docker เพื่อการพัฒนาในพื้นที่
มีเหตุผลที่ดีหลายประการในการใช้ฐานข้อมูลใด ๆ รวมถึง MySQL พร้อม Docker สำหรับการพัฒนาในพื้นที่ เหตุผลบางประการมีดังนี้:
- การใช้ MySQL เวอร์ชันใดก็ได้ เช่น 5.6, 5.7 หรือ 8 ตามโครงการหรือเหตุผลอื่นๆ นั้นง่ายมาก
- โดยปกติแล้วกับนักเทียบท่า ถ้ามันทำงานบนเครื่องของคุณ มันจะทำงานบนเครื่องของวิศวกรซอฟต์แวร์รายอื่น ในสภาพแวดล้อมที่กำลังจัดเตรียม และในการผลิตด้วยเช่นกัน เนื่องจากมีความเข้ากันได้บางอย่าง
- สมาชิกในทีมใหม่สามารถทำงานได้อย่างมีประสิทธิภาพภายในไม่กี่ชั่วโมง ไม่ใช่วันๆ เนื่องจากนักเทียบท่าและเครื่องมืออื่นๆ ได้รับการตั้งค่าอย่างมีประสิทธิภาพ
ข้อกำหนดเบื้องต้น
ก่อนที่เราจะจัดการกับโค้ดและคำสั่ง CLI บางคำสั่ง ด้านล่างนี้เป็นสิ่งที่ควรทำก่อน:
- ความรู้พื้นฐานของ Docker และคำสั่งที่เกี่ยวข้อง เช่น docker build, run, execute ฯลฯ จะเป็นประโยชน์สำหรับคำแนะนำนี้
- ข้อมูลใด ๆ ก่อนหน้านี้เกี่ยวกับ Docker-compose จะมีประโยชน์มาก
- ความเข้าใจทั่วไปเกี่ยวกับวิธีการทำงานของฐานข้อมูลเชิงสัมพันธ์ โดยเฉพาะ MySQL จะพิจารณาเป็นพิเศษ
รัน MySQL ด้วย Docker
สำหรับคู่มือเริ่มต้นนี้ เราจะใช้อิมเมจ MySQL Docker อย่างเป็นทางการจากDockerHub อิมเมจ MySQL Docker อย่างเป็นทางการไม่มีเวอร์ชัน Alpine Linux แต่เวอร์ชัน Debian ยังมีขนาด 147 MB ซึ่งไม่ใหญ่เกินไปสำหรับอิมเมจนักเทียบท่า
หากต้องการเรียกใช้คอนเทนเนอร์ MySQL 8.0 โดยใช้อิมเมจอย่างเป็นทางการ ให้เรียกใช้คำสั่งต่อไปนี้:
mkdir /tmp/mysql-data
docker run --name basic-mysql --rm -v /tmp/mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=ANSKk08aPEDbFjDO -e MYSQL_DATABASE=testing -p 3306:3306 -it mysql:8.0
--name
เพื่อตั้งชื่อคอนเทนเนอร์basic-mysql
--rm
เพื่อนำคอนเทนเนอร์ออกเมื่อหยุดทำงาน-v /tmp/mysql-data:/var/lib/mysql
ถูกเพิ่มเพื่อเก็บข้อมูลเมื่อคอนเทนเนอร์รีสตาร์ท มันจะหายไปเมื่อเครื่องโฮสต์รีสตาร์ทตามที่เป็นอยู่/tmp
-e MYSQL_ROOT_PASSWORD=ANSKk08aPEDbFjDO -e MYSQL_DATABASE=testing
สำหรับตั้งรหัสผ่านของผู้ใช้ root และเริ่มต้นฐานข้อมูลชื่อtesting
-p 3306:3306
แมปพอร์ตโฮสต์ 3306 กับพอร์ตคอนเทนเนอร์ 3306 พอร์ต 3306 เป็นพอร์ตเริ่มต้นของ MySQL-it mysql:8.0
- -มันจะแสดงบันทึกทั้งหมดและเรากำลังใช้อิมเมจ MySQL เวอร์ชัน 8.0 อย่างเป็นทางการซึ่งจะเรียกใช้รสชาติของ Debian
2022-10-27 06:11:09+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
2022-10-27 06:11:10+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2022-10-27 06:11:10+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
2022-10-27 06:11:11+00:00 [Note] [Entrypoint]: Initializing database files
2022-10-27T06:11:11.957280Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
2022-10-27T06:11:11.957392Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.31) initializing of server in progress as process 80
2022-10-27T06:11:11.987130Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2022-10-27T06:11:12.013548Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2022-10-27T06:11:16.919522Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2022-10-27T06:11:20.772591Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2022-10-27 06:11:27+00:00 [Note] [Entrypoint]: Database files initialized
2022-10-27 06:11:27+00:00 [Note] [Entrypoint]: Starting temporary server
mysqld will log errors to /var/lib/mysql/729f35877b11.err
mysqld is running as pid 133
2022-10-27 06:11:40+00:00 [Note] [Entrypoint]: Temporary server started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
2022-10-27 06:11:44+00:00 [Note] [Entrypoint]: Creating database testing
2022-10-27 06:11:44+00:00 [Note] [Entrypoint]: Stopping temporary server
2022-10-27 06:11:48+00:00 [Note] [Entrypoint]: Temporary server stopped
2022-10-27 06:11:48+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
2022-10-27T06:11:48.661152Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
2022-10-27T06:11:48.670274Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.31) starting as process 1
2022-10-27T06:11:48.683339Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2022-10-27T06:11:48.700826Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2022-10-27T06:11:51.317151Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2022-10-27T06:11:52.336910Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2022-10-27T06:11:52.336965Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2022-10-27T06:11:52.352191Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2022-10-27T06:11:52.548249Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2022-10-27T06:11:52.548394Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
docker exec -it basic-mysql /bin/bash
#once inside the container
mysql -u root -p
#put/paste the password, ANSKk08aPEDbFjDO, and once inside MySQL CLI run
show databases;
เราสามารถหยุดภาชนะได้ด้วยdocker stop basic-mysql
แม้ว่านั่นจะไม่ยากเกินไป แต่ฉันก็ไม่คิดว่ามันง่ายอีกทั้งพารามิเตอร์ของคำสั่งก็จำได้ไม่ยาก อีกแง่มุมหนึ่งคือเราเรียกใช้ MySQL แบบแยกจากกัน ไม่มีการเชื่อมโยงระหว่างแอปพลิเคชัน Quotes API Node.js และคอนเทนเนอร์ MySQL นี่คือสิ่งที่ลักษณะการประกาศของการเขียนนักเทียบท่ามีประโยชน์มากดังที่เราจะเห็นในหัวข้อถัดไป
รัน MySQL ด้วย docker-compose
เพิ่มสคริปต์การฉีดเริ่มต้น
mkdir basic-mysql && touch ./basic-mysql/init.sql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
USE testing;
DROP TABLE IF EXISTS `order`;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS coffee;
/*NEVER store passwords in clear text as it's done here!!!*/
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
password TEXT NOT NULL,
role ENUM('admin', 'consumer')
);
INSERT INTO
users (name, email, password, role)
VALUES
('test', '[email protected]', 'test', 'consumer'),
('admin', '[email protected]', 'admin', 'admin');
CREATE TABLE coffee (
id SERIAL PRIMARY KEY,
blend_name char(64),
origin char(64),
variety char(64),
notes char(64),
intensifier char(64),
price float
);
INSERT INTO
coffee (
blend_name,
origin,
variety,
notes,
intensifier,
price
)
VALUES
(
'Good-morning Symphony',
'Dipilto, Nicaragua',
'Kona',
'crisp, coating, concord grape, fresh wood, maple syrup',
'astringent',
23.7
),
(
'KrebStar Mug',
'Central Valley, Costa Rica',
'Yellow Bourbon',
'mild, tea-like, pineapple, barley, musty',
'delicate',
40.0
);
CREATE TABLE `order` (
id SERIAL PRIMARY KEY,
coffeeId BIGINT UNSIGNED NOT NULL,
userId BIGINT UNSIGNED NOT NULL,
quantity INT NOT NULL,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_coffeeId FOREIGN KEY (coffeeId) REFERENCES coffee(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_userId FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
-- insert data into order table
INSERT INTO
`order` (coffeeId, userId, quantity)
VALUES
(1, 1, 2),
(2, 2, 1);
version: '3.8'
services:
basic-mysql:
container_name: basic-mysql
image: mysql:8.0
cap_add:
- SYS_NICE
restart: always
environment:
- MYSQL_DATABASE=testing
- MYSQL_ROOT_PASSWORD=ANSKk08aPEDbFjDO
ports:
- '3306:3306'
- '33060:33060'
command: --init-file /docker-entrypoint-initdb.d/init.sql
volumes:
- basic-mysql:/var/lib/mysql
- ./basic-mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
basic-mysql:
driver: local
- ใช้ไฟล์ docker-compose เวอร์ชัน 3.8ซึ่งเป็นหนึ่งในไฟล์ล่าสุด
- ดังนั้นเราจึงกำหนด
db
ให้เป็นบริการ แต่ละบริการจะเทียบเท่ากับคำสั่งเรียกใช้นักเทียบท่าใหม่ - ต่อจากนั้น เราชี้ให้นักเทียบท่าเขียนเพื่อใช้อิมเมจ MySQL 8.0 อย่างเป็นทางการสำหรับบริการฐานข้อมูลนี้
- ชุด
cap_add
ที่จะSYS_NICE
ระงับข้อความแสดงข้อผิดพลาดที่ไม่มีประโยชน์ - ขั้นต่อไป เราจะขอให้นักเทียบท่าที่เขียนใหม่รีสตาร์ทคอนเทนเนอร์นี้เสมอหากล้มเหลว
- หลังจากนั้น เราเพิ่มตัวแปรสภาพแวดล้อม 2 ตัวสำหรับฐานข้อมูล MySQL และรหัสผ่านของผู้ใช้รูท ตามความต้องการ เราสามารถเพิ่มผู้ใช้รายอื่นเพื่อให้สิทธิ์กับ env vars อื่นน้อยลง
- จากนั้น เราแมปพอร์ตโฮสต์
3306
กับพอร์ตคอนเทนเนอร์3306
เนื่องจากเซิร์ฟเวอร์ MySQL กำลังทำงานบนพอร์ต3306
คอนเทนเนอร์ พอร์ตโฮสต์อาจเปลี่ยนแปลงได้ขึ้นอยู่กับความต้องการ - จากนั้น เรารันสคริปต์การ seed เพื่อใส่ข้อมูลเริ่มต้นลงในฐานข้อมูล mysql ของเรา
testing
- จากนั้นเราเพิ่ม 2 วอลุ่ม วอลุ่มแรกคือวอลุ่ม DB ที่แมปกับวอลุ่มด้าน
basic-mysql
ล่าง ซึ่งโดยทั่วไปจะบอกนักเทียบท่าและนักเทียบท่าที่เขียนเพื่อจัดการโวลุ่มให้เรา ต่อไป เราเพิ่มinit.sql
สคริปต์ที่จะเริ่มต้น ฐานข้อมูล ของเราtesting
ด้วยไฟล์ SQL ที่กำหนด
docker-compose up
[+] Running 1/1
⠿ Container basic-mysql Created 0.2s
Attaching to basic-mysql
basic-mysql | 2022-10-27 09:38:51+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
basic-mysql | 2022-10-27 09:38:51+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
basic-mysql | 2022-10-27 09:38:51+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.31-1.el8 started.
basic-mysql | '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
basic-mysql | 2022-10-27T09:38:52.620935Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
basic-mysql | 2022-10-27T09:38:52.628931Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.31) starting as process 1
basic-mysql | 2022-10-27T09:38:52.649308Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
basic-mysql | 2022-10-27T09:38:53.380032Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
basic-mysql | 2022-10-27T09:38:53.698374Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
basic-mysql | 2022-10-27T09:38:53.698422Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
basic-mysql | 2022-10-27T09:38:53.705214Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
basic-mysql | 2022-10-27T09:38:53.904655Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
basic-mysql | 2022-10-27T09:38:53.904741Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
การเชื่อมต่อกับฐานข้อมูลผ่าน UI เช่นMySQL Workbench และตรวจสอบว่าตารางของเราได้รับการ seed อย่างถูกต้อง
ทดสอบการเชื่อมต่อผ่านสคริปต์ python
ตรวจสอบให้แน่ใจว่ามีการติดตั้งการพึ่งพา วิ่งpip install pymysql
หรือpip3 install pymysql
# main.py
import pymysql.cursors
# Connect to the database
connection = pymysql.connect(
host='localhost',
user='root',
password='ANSKk08aPEDbFjDO',
database='testing',
cursorclass=pymysql.cursors.DictCursor
)
with connection:
with connection.cursor() as cursor:
# Read a single record
sql = "SELECT * FROM `users`"
cursor.execute(sql)
result = cursor.fetchall()
print(result)
การทดสอบการเชื่อมต่อผ่านโหนดสคริปต์
ตรวจสอบให้แน่ใจว่ามีการติดตั้งการพึ่งพา วิ่งnpm i mysql
// main.js
const mysql = require('mysql');
const con = mysql.createConnection({
host: "localhost",
user: "root",
password: "ANSKk08aPEDbFjDO",
database: "testing"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
con.query("SELECT * FROM `users`", function (err, result, fields){
if (err) throw err;
console.log(result);
});
});
เรียกร้องให้ดำเนินการ
หากคุณเห็นว่าคู่มือนี้มีประโยชน์ โปรดปรบมือและติดตามฉันได้ตามสบาย เข้าร่วมสื่อผ่านลิงก์นี้เพื่อเข้าถึงบทความพรีเมียมทั้งหมดจากฉันและนักเขียนที่ยอดเยี่ยมคนอื่นๆ ที่นี่บนสื่อ
เพิ่มระดับการเข้ารหัส
ขอบคุณที่เป็นส่วนหนึ่งของชุมชนของเรา! ก่อนที่คุณจะไป:
- ปรบมือให้กับเรื่องราวและติดตามผู้เขียน
- ดูเนื้อหาเพิ่มเติมในสิ่งพิมพ์ Level Up Coding
- ติดตามเรา: Twitter | LinkedIn | จดหมายข่าว