ربط تطبيق Node.js بـ MySQL باستخدام Docker
السلام عليكم ورحمة الله وبركاته
يمكنك متابعة السلسلة بالترتيب أو الانتقال مباشرة إلى أي مقال:
المقدمة
في المقالات السابقة تعرفنا على الـ Volumes والـ Bind Mounts وكيفية حفظ البيانات بشكل دائم خارج الـ Container
وتعلمنا كيف أن حذف الـ Container لا يعني بالضرورة فقدان البيانات إذا كنا نستخدم Volume
الآن حان الوقت لنطبق ما تعلمناه في مثال عملي حقيقي
في هذه المقالة سنقوم بتشغيل قاعدة بيانات MySQL داخل Container
ثم سنبني تطبيق Node.js بسيط يتصل بقاعدة البيانات هذه ويقوم بتخزين واسترجاع البيانات منها
وسنستخدم Volume لحفظ بيانات قاعدة البيانات بشكل دائم حتى لو حذفنا الـ Container
الجميل في هذا المثال أنك لن تحتاج لتثبيت MySQL على جهازك الشخصي
الـ Docker سيتكفل بتشغيلها داخل Container وأنت تتعامل معها كأنها مثبتة على جهازك
وهذه من أجمل فوائد الـ Docker في بيئة التطوير
تحميل وتجهيز الـ MySQL Image
الـ MySQL لديها Image رسمي على Docker Hub يمكننا استخدامه مباشرة بدون ما نحتاج لكتابة Dockerfile خاص بها
سنستخدم الإصدار 9.6.0 من MySQL، أي أن الـ Image الذي سنستخدمه هو mysql:9.6.0
لكن قبل إنشاء الـ Container، هناك بعض الأشياء التي نحتاج لمعرفتها عن الـ Image الرسمي لـ MySQL
الـ Image الرسمي للـ MySQL يتطلب بعض الـ Environment Variables عند إنشاء الـ Container
وأهم هذه المتغيرات هو MYSQL_ROOT_PASSWORD الذي يحدد كلمة المرور لمستخدم root في MySQL
بدون هذا المتغير، الـ Container لن يعمل وسيعطينا خطأ
وهناك متغيرات أخرى اختيارية لكنها مفيدة جدًا:
MYSQL_DATABASEلإنشاء قاعدة بيانات تلقائيًا عند إنشاء الـContainerلأول مرةMYSQL_USERلإنشاء مستخدم جديد غيرrootMYSQL_PASSWORDلتحديد كلمة المرور لهذا المستخدم الجديد
نحن في هذا المثال سنستخدم MYSQL_ROOT_PASSWORD و MYSQL_DATABASE فقط لتبسيط الأمور
لتمرير هذه المتغيرات إلى الـ Container عند إنشائه، نستخدم خيار -e في أمر docker container run
الخيار -e يسمح لنا بتعريف Environment Variable داخل الـ Container
مثلًا -e MYSQL_ROOT_PASSWORD=tabarani-very-secret سيقوم بتعريف متغير env اسمه MYSQL_ROOT_PASSWORD بقيمة tabarani-very-secret داخل الـ Container
الآن عرفنا كل ما نحتاجه، لننشيء الـ Container من الـ MySQL
الآن نحتاج فقط لإنشاء Volume لربط البيانات التي سنخزنها في قاعدة البيانات MySQL به، حتى لا نفقدها عند حذف الـ Container
> docker volume create mysql-tabarani-db
mysql-tabarani-db
يستحسن أن يكون اسم الـ Volume واضحًا ويعبر عن المشروع أو الخدمة التي يستخدمها، لذلك اخترت mysql-tabarani-db كاسم لهذا الـ Volume
لنتخيل أن اسم المشروع هو Tabarani و هذا الـ Volume مخصص لقاعدة بيانات MySQL الخاصة بهذا المشروع
الآن لنحمل الـ Image الخاص بـ MySQL من الـ Docker Hub
> docker image pull mysql:9.6.0
9.6.0: Pulling from library/mysql
c07617e6f14b: Pulling fs layer
fe44c8bf49c1: Pull complete
4f37333d1be6: Pull complete
e5a384f12fc1: Pull complete
85e7dc27e1dd: Pull complete
7a3034072b44: Pull complete
74e9390a4418: Pull complete
c3c2157be11c: Pull complete
a5b1ba019080: Pull complete
93b95dea6553: Pull complete
Digest: sha256:db32c8ec843c042a728efb0ac7aa814d6f010eaac8923e20ae0a849d09c5baf8
Status: Downloaded newer image for mysql:9.6.0
docker.io/library/mysql:9.6.0
لنرى الـ Image الموجودة في جهازنا:
> docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
nodejs-docker-app v3.0 380feaf700d6 7 hours ago 248MB
mysql 9.6.0 db32c8ec843c 45 hours ago 1.25GB
لدينا nodejs-docker-app الذي أنشأناه في المقالات السابقة، والآن لدينا أيضًا mysql:9.6.0 الذي قمنا بتحميله للتو
الآن لنقم بعمل inspect لهذا الـ mysql:9.6.0 لنتعرف على المزيد من التفاصيل حوله:
> docker image inspect db32c8ec843c
[
{
...
"Config": {
...
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
...
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.19",
"MYSQL_MAJOR=innovation",
"MYSQL_VERSION=9.6.0-1.el9",
"MYSQL_SHELL_VERSION=9.6.0-1.el9"
],
...
"Volumes": {
"/var/lib/mysql": {}
},
...
},
...
}
]
لقد قمت بإخفاء الكثير من التفاصيل في نتيجة inspect لأنني أريدك فقط تركز على الأجزاء المهمة بالنسبة لنا في هذا المثال
أولًا، الـ Image يستخدم port رقم 3306 وهو الـ port الافتراضي لقاعدة بيانات MySQL
ثانيًا، الـ Image يحتوي على متغيرات env مكتوبة في الـ Dockerfile الخاص به
لكن هناك متغيرات أخرى مهمة مثل MYSQL_ROOT_PASSWORD و MYSQL_DATABASE غير مدونة في الـ Dockerfile لأن هذه المتغيرات يجب أن يحددها المستخدم عند إنشاء الـ Container بالتالي ليس لها قيم افتراضية في الـ Dockerfile
وهذه المعلومات ستحصل خلال قراءة الصفحة الرسمية لهذا الـ Image على Docker Hub
ثالثًا، الـ Image يحتوي على VOLUME يحدد أن مجلد /var/lib/mysql داخل الـ Container مخصص لتخزين بيانات MySQL
بالتالي نفهم أننا نحتاج لربط هذا المجلد بـ Volume خارجي لكي نحافظ على البيانات بشكل دائم ولا نعتمد على الـ Anonymous Volume
إنشاء الـ Container وربطه بالـ Volume
الآن سنقوم بإنشاء الـ Container من الـ Image الخاصة بـ MySQL وربطه بالـ Volume الذي أنشأناه سابقًا
الأمر سيكون طويل قليلًا لأننا سنمرر عدة خيارات عند إنشاء الـ Container، لكن لا تقلق سأشرح كل جزء منه بعد الأمر
> docker container run -d --rm --name mysql-container -p 3306:3306 -e MYSQL_ROOT_PASSWORD=tabarani-very-secret -e MYSQL_DATABASE=tabarani-app -v mysql-tabarani-db:/var/lib/mysql mysql:9.6.0
1a60ca4ea14c77ce61a8d3d40065083de1a9d30a0896f9708e13d407669140b8
حسنًا، سأشرح الأمر بالتفصيل الآن، أظن أنك إن ركزت فيه وقرأته بعناية ستفهم كل جزء منه بسهولة، لأن كل شيء شرحناه من قبل
على أي حال، إليك شرح كل خيار في الأمر:
-dلتشغيل الـContainerفي الخلفية--rmلحذف الـContainerتلقائيًا عند إيقافه--name mysql-containerلتسمية الـContainerباسم واضح-p 3306:3306لربط الـportرقم3306على جهازنا بالـportرقم3306داخل الـContainer، وهذا هو الـportالافتراضي لـMySQLالذي تم تحديده في الـImageكما رأينا في نتيجةinspect-e MYSQL_ROOT_PASSWORD=tabarani-very-secretلتحديد كلمة مرور مستخدم الـrootالخاص بـMySQL-e MYSQL_DATABASE=tabarani-appلإنشاء قاعدة بيانات بإسمtabarani-appتلقائيًا عند إنشاء الـContainerلأول مرة-v mysql-tabarani-db:/var/lib/mysqlلربط الـVolumeالذي أنشأناهmysql-tabarani-dbبمجلد/var/lib/mysqlداخل الـContainerحيث يتم تخزين بياناتMySQLmysql:9.6.0هو اسم الـImageالذي نريد إنشاء الـContainerمنه
لنتأكد أن الـ Container يعمل:
> docker container list
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a60ca4ea14c mysql:9.6.0 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-container
حسنًا، كما ترى أن الـ Container يعمل
وأن الـ port رقم 3306 مربوط ما بين جهازنا والـ Container
بالتالي أي تطبيق يعمل على جهازنا يمكنه الاتصال بـ MySQL عن طريق localhost:3306 كأن MySQL مثبتة على جهازنا مباشرة
التحقق من أن MySQL يعمل
لكي نقطع الشك باليقين ونتأكد فعلًا أن MySQL يعمل داخل الـ Container وأن قاعدة البيانات tabarani-app تم إنشاؤها بنجاح
سنقوم بالدخول إلى CLI الخاص بـ MySQL داخل الـ Container وننفذ بعض أوامر SQL لنتأكد أن كل شيء يعمل بشكل صحيح
سندخل إلى CLI الخاص بـ MySQL عن طريق تنفيذ أمر mysql داخل الـ Container:
> docker container exec -it mysql-container mysql -u root -p tabarani-very-secret
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 9.6.0 MySQL Community Server - GPL
...
mysql>
هنا باستخدام أمر docker container exec دخلنا إلى الـ Container الذي يعمل فيه MySQL
ثم قمنا بتنفيذ أمر mysql -u root -ptabarani-very-secret داخل الـ Container
وهذا الأمر يفتح لنا واجهة الأوامر الخاصة بـ MySQL حيث يمكننا تنفيذ أوامر SQL
ملحوظة: لاحظ أنه لا توجد مسافة بين-pوكلمة المرورtabarani-very-secret، هذه هي الطريقة لتمرير كلمة المرور في أمرmysql
لنرى قواعد البيانات الموجودة:
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| tabarani-app |
+--------------------+
5 rows in set (0.013 sec)
لاحظ أن قاعدة البيانات tabarani-app تم إنشاؤها تلقائيًا كما حددنا في -e MYSQL_DATABASE=tabarani-app
أما باقي قواعد البيانات الظاهرة فهي تأتي مع MySQL بشكل افتراضي
حسنًا، كل شيء يعمل بشكل صحيح
لنخرج من الـ CLI الخاص بـ MySQL عن طريق تنفيذ الأمر exit:
mysql> exit
Bye
إنشاء تطبيق Node.js
الآن بعد أن تأكدنا أن MySQL يعمل داخل الـ Container
سنقوم بإنشاء تطبيق Node.js بسيط يتصل بقاعدة البيانات ويقوم بإضافة واسترجاع بيانات المنتجات من جدول يدعى products
لنقم بإنشاء مجلد جديد لمشروعنا:
> mkdir nodejs-mysql-app
> cd nodejs-mysql-app
ملف الـ package.json سيكون كالتالي:
{
"name": "nodejs-mysql-app",
"version": "1.0.0",
"description": "Node.js app connected to MySQL in Docker",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^5.2.1",
"mysql2": "^3.16.3"
}
}
لدينا express لإنشاء الـ API ومكتبة mysql2 للتعامل مع قاعدة البيانات MySQL في Node.js
الآن ملف الـ app.js:
const express = require("express");
const mysql = require("mysql2/promise");
const app = express();
const port = process.env.PORT || 3000;
const dbConfig = {
host: process.env.DB_HOST || "localhost",
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
};
let connection;
async function connectDB() {
connection = await mysql.createConnection(dbConfig);
await connection.execute(`
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10, 2) NOT NULL
)
`);
console.log("Connected to MySQL and products table is ready");
}
app.use(express.json());
app.get("/products", async (req, res) => {
const [rows] = await connection.execute("SELECT * FROM products");
res.json(rows);
});
app.post("/products", async (req, res) => {
const { name, price } = req.body;
const [result] = await connection.execute(
"INSERT INTO products (name, price) VALUES (?, ?)",
[name, price],
);
res.status(201).json({ id: result.insertId, name, price });
});
connectDB().then(() => {
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
});
لا تقلق إذا كان الكود يبدو معقدًا في البداية، سأشرح كل جزء منه بشكل سريع
كل ما في الأمر أنه لدينا متغير يدعى dbConfig وهو مجرد object يحتوي على إعدادات الاتصال بقاعدة البيانات MySQL
وهذه الإعدادات تشمل host و port و user و password و database
لاحظ أن host هو localhost و port هو 3306
ولو لاحظت فأنني ربطنا الـ port رقم 3306 الموجود داخل الـ Container بالـ port رقم 3306 على جهازنا
بالتالي أي شيء يتصل بـ localhost:3306 على جهازنا سيتصل فعليًا بقاعدة البيانات MySQL داخل الـ Container
وباقي الإعدادات مثل user و password و database لم نحدد لها قيم افتراضية كنوع من الحماية، لذلك يجب أن نمررها من خلال Environment Variables في ملف الـ .env
ثم لدينا دالة connectDB تقوم بالاتصال بقاعدة البيانات وإنشاء جدول products إذا لم يكن موجودًا
ثم لدينا endpoint للـ GET /products يقوم بجلب جميع المنتجات من جدول products
و endpoint للـ POST /products يقوم بإضافة منتج جديد
وأخيرًا نقوم بالاتصال بقاعدة البيانات أولًا ثم ننشيء الـ Server
ملحوظة: لو كنت شخص جديد علىNode.jsوExpress، فهذا لا يهم فنحن لا نحتاج لفهم كل تفاصيل الكود
فقط ركز على فكرة أننا لديناMySQLيعمل داخلDocker ContainerولديناServerنريده أن يتصل بهذا الـMySQL
سواء الـServerمكتوب بـNode.jsأوPHPأو أي لغة أخرى لا يهم، المهم هو فكرة الاتصال بقاعدة البيانات داخل الـContainer
وأخيرًا ملف الـ .env لتحديد Environment Variables الخاصة بقاعدة البيانات:
# APP Port
PORT=3000
# Database configuration
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=tabarani-very-secret
DB_NAME=tabarani-app
ملحوظة: في هذا المثال لن نقوم بعملimageأوcontainerلتطبيق الـNode.jsهذه المرة، بل سنشغل الـServerمباشرة على جهازنا بشكل اعتيادي ونربطه بقاعدة البيانات التي تعمل داخل الـContainer
وهذا لتبسيط المثال لا أكثر ولكي لا نضطر إلى الدخول في مشاكل متعلقة بربطContainerبـContainerآخر، لأن هذا موضوع سنغطيه في مقالات لاحقة نتكلم فيها عنDocker NetworksوDocker Compose
الآن أصبح لدينا كل الملفات اللازمة لتشغيل الـ Server
تشغيل Server الـ Node.js وربطه بقاعدة البيانات MySQL داخل الـ Container
أولًا لا ننسى أن نقوم بتثبيت المكاتب الخاصة بالتطبيق:
> npm install
ثم لنشغل الـ Server:
> npm start
> nodejs-mysql-app@1.0.0 start
> node app.js
Connected to MySQL and products table is ready
Server is running on port 3000
كما تلاحظ الـ Server اتصل بقاعدة البيانات MySQL التي بداخل الـ Container بنجاح
وتم إنشاء جدول products أيضًا
لاحظ أن الـ Server احتل الـ Terminal الخاصة بنا في الـ Foreground لذا سنقوم بفتح نافذة Terminal جديدة لاختبار الـ API الخاص بنا واستكمال باقي الخطوات
ونترك الـ Server يعمل في النافذة الأولى كما هو
الآن لنقم باختبار الـ Server لنتأكد بشكل قاطع أن كل شيء يعمل بشكل صحيح
لنضف بعض المنتجات عن طريق POST /products:
> curl -X POST http://localhost:3000/products -H "Content-Type: application/json" -d '{"name": "Laptop", "price": 1200.00}'
{"id":1,"name":"Laptop","price":1200}
> curl -X POST http://localhost:3000/products -H "Content-Type: application/json" -d '{"name": "Phone", "price": 800.00}'
{"id":2,"name":"Phone","price":800}
> curl -X POST http://localhost:3000/products -H "Content-Type: application/json" -d '{"name": "Tablet", "price": 500.00}'
{"id":3,"name":"Tablet","price":500}
أضفنا ثلاثة منتجات بنجاح ولم نحصل على أي Exception لذا الأمور تسير بشكل جيد
لاحظ أن كل منتج حصل على id تلقائي بفضل AUTO_INCREMENT في جدول products
الآن لنجلب جميع المنتجات عن طريق GET /products:
> curl http://localhost:3000/products
[{"id":1,"name":"Laptop","price":1200},{"id":2,"name":"Phone","price":800},{"id":3,"name":"Tablet","price":500}]
كل المنتجات موجودة وتم تخزينها في قاعدة بيانات MySQL داخل الـ Container
التحقق من البيانات من داخل الـ MySQL مباشرة
لنتأكد أن البيانات موجودة فعلًا في MySQL داخل الـ Container
سندخل إلى CLI الخاص بـ MySQL داخل الـ Container مرة أخرى وننفذ أوامر SQL لعرض البيانات
> docker container exec -it mysql-container mysql -u root -ptabarani-very-secret
...
mysql>
لنختار قاعدة البيانات tabarani-app:
mysql> USE tabarani-app;
Database changed
الآن لنرى المنتجات الموجودة في جدول products:
mysql> SELECT * FROM products;
+----+-------+-------+
| id | name | price |
+----+-------+-------+
| 1 | Laptop | 1200 |
| 2 | Phone | 800 |
| 3 | Tablet | 500 |
+----+-------+-------+
3 rows in set (0.0001 sec)
البيانات موجودة في قاعدة البيانات وتم تخزينها بنجاح
هذه البيانات مخزنة في الـ Container في مجلد /var/lib/mysql
ولكن بما أننا ربطنا هذا المجلد بالـ Volume الذي يدعى mysql-tabarani-db
فالبيانات في الحقيقة مخزنة في الـ Volume وليس في الـ Container نفسه
والموجودة في الـ Container هي نسخة من البيانات الموجودة في الـ Volume
بالتالي حتى لو حذفنا الـ Container، البيانات ستظل موجودة في الـ Volume ويمكننا ربطها بأي Container آخر في المستقبل
لنخرج من الـ CLI الخاص بـ MySQL:
mysql> exit
Bye
التأكد من وجود البيانات حتى بعد حذف الـ Container الخاص بـ MySQL
الآن جاء الجزء المهم
لنرى هل الـ Volume سيحمي بياناتنا هذه المرة أم لا
نحن نعرف أن الإجابة نعم لأننا تعلمنا في مقالة حفظ البيانات في Docker باستخدام Volumes أن البيانات المخزنة في Volume لا تتأثر بحذف الـ Container
لكن لنختبر هذا عمليًا مرة أخرى في هذا المثال
أولًا لنوقف تطبيق Node.js بالضغط على Ctrl + C في النافذة التي يعمل فيها الـ Server
ثم لنوقف الـ Container الخاص بـ MySQL وبما أننا استخدمنا --rm فسيتم حذفه تلقائيًا:
> docker container stop mysql-container
mysql-container
هكذا تم حذف الـ Container الخاص بـ MySQL، لنتأكد أن الـ Volume ما زال موجودًا أم لا:
> docker volume list
DRIVER VOLUME NAME
local mysql-tabarani-db
الـ Volume الذي يحتوي على بيانات MySQL ما زال موجودًا
الآن لنعيد إنشاء Container جديد ونربطه بنفس الـ Volume:
> docker container run -d --rm --name mysql-container -p 3306:3306 -e MYSQL_ROOT_PASSWORD=tabarani-very-secret -e MYSQL_DATABASE=tabarani-app -v mysql-tabarani-db:/var/lib/mysql mysql:9.6.0
8cc1487ac9c305753fe818aed05380ab8e72414bdb9c0092681e214c124e5b80
لاحظ أن الأمر هو نفسه تمامًا أي نفس الـ Volume و نفس الـ port ونفس كل الإعدادات
الآن لنشغل الـ Server الخاص بالـ Node.js مرة أخرى:
> npm start
> nodejs-mysql-app@1.0.0 start
> node app.js
Connected to MySQL and products table is ready
Server is running on port 3000
الـ Server اتصل بقاعدة البيانات بنجاح
الآن اللحظة الحاسمة، هل البيانات ما زالت موجودة ؟
سنقوم بفتح نافذة Terminal جديدة وننفذ أمر curl لجلب المنتجات مرة أخرى:
> curl http://localhost:3000/products
[{"id":1,"name":"Laptop","price":1200},{"id":2,"name":"Phone","price":800},{"id":3,"name":"Tablet","price":500}]
البيانات ما زالت موجودة
رغم أننا حذفنا الـ Container بالكامل وأنشأنا واحد جديد
لكن البيانات لم تضيع لأنها محفوظة في الـ Volume وليس في الـ Container نفسه
لو أننا لم نستخدم الـ Volume وكتبنا الأمر بدون -v mysql-tabarani-db:/var/lib/mysql
لكانت كل البيانات اختفت عند حذف الـ Container
ولكانت الـ Anonymous Volume الذي تم إنشاؤه تلقائيًا قد تم حذفه مع حذف الـ Container بسبب استخدامنا لخيار --rm
وكنا سنفقد كل البيانات التي أضفناها في قاعدة البيانات MySQL داخل الـ Container
لنضف منتج جديد لنتأكد أن كل شيء يعمل بشكل طبيعي:
> curl -X POST http://localhost:3000/products -H "Content-Type: application/json" -d '{"name": "Headphones", "price": 150}'
{"id":4,"name":"Headphones","price":150}
> curl http://localhost:3000/products
[{"id":1,"name":"Laptop","price":1200},{"id":2,"name":"Phone","price":800},{"id":3,"name":"Tablet","price":500},{"id":4,"name":"Headphones","price":150}]
لاحظ أن الـ id للمنتج الجديد هو 4 وليس 1
لأن MySQL تتذكر آخر id تم استخدامه بفضل AUTO_INCREMENT
وهذا دليل آخر على أن البيانات القديمة ما زالت سليمة ولم يتم إعادة إنشاء الجدول من الصفر
حسنًا لنقم بإيقاف الـ Server مرة أخرى عن طريق Ctrl + C في النافذة التي يعمل فيها الـ Server
ونقم بحذف الـ Container الخاص بـ MySQL
> docker container stop mysql-container
mysql-container
ماذا لو لم نستخدم Volume ؟
ماذا لو نسينا استخدام Volume مع MySQL ؟
لقد عرفنا أن الـ Image الرسمية الخاصة بالـ MySQL يحتوي على أمر VOLUME في الـ Dockerfile الخاص به
وهذا يعني أن الـ Docker سينشئ Anonymous Volume تلقائيًا حتى لو لم نحدد -v عند إنشاء الـ Container
لكن كما تعلمنا في مقالة حفظ البيانات في Docker باستخدام Volumes، أن الـ Anonymous Volume ليس خيارًا جيدًا
لأن اسمه يكون hash عشوائي ولا يمكننا إعادة استخدامه بسهولة بين الـ Containers
وإذا استخدمنا --rm عند إنشاء الـ Container، فسيتم حذف الـ Anonymous Volume تلقائيًا مع حذف الـ Container
لذلك دائمًا استخدم Named Volume عند التعامل مع قواعد البيانات
هكذا تضمن أن بياناتك محفوظة بشكل آمن ويمكنك إعادة استخدامها مع أي Container في المستقبل
الخلاصة
في هذه المقالة قمنا بمثال عملي حقيقي يجمع بين ما تعلمناه في المقالات السابقة
شغلنا MySQL داخل Container بدون ما نحتاج لتثبيتها على جهازنا
واستخدمنا Volume لحفظ بيانات قاعدة البيانات بشكل دائم
ثم أنشأنا تطبيق Node.js بسيط يتصل بقاعدة البيانات ويتعامل معها
وتعلمنا أيضًا أهمية استخدام Named Volume مع قواعد البيانات لحماية البيانات من الضياع
لاحظ أننا في هذه المقالة لم نستخدم Dockerfile لتشغيل تطبيق الـ Node.js داخل Container، بل شغلناه مباشرة على جهازنا وربطناه بقاعدة البيانات داخل الـ Container
فعلت هذا لتبسيط المثال والتركيز على فكرة الاتصال بقاعدة البيانات داخل الـ Container
لأننا لو حولنا Server الخاص بالـ Node.js إلى Container آخر، كنا سنحتاج لربط Container بـ Container آخر وهذا موضوع سنغطيه في مقالات لاحقة عن Docker Networks و Docker Compose