התקנת PHP, mySQL ושרת אפאצי באמצעות דוקר Docker
Docker הוא פלטפורמה המאפשרת לארוז אפליקציה ולהריץ אותה בתוך סביבה מבודדת המכונה קונטיינר. כאשר ניתן להריץ כמה קונטיינרים על אותו מחשב במקביל.
היתרונות של קונטיינר שאתה יכול ליצור את הסביבה לפיתוח האפליקציה שלך ממש בקלות, ואחר כך ניתן להתקין את הסביבה על כל המחשבים שלך ושל המתכנתים האחרים שעובדים על הפרויקט. לדוגמה, אם אתה כותב את האפליקציה שלך על PHP גרסה 7.4 עם גרסה 8.0.21 של mySQL על שרת Apache. אתה יכול לבקש יפה מכל המפתחים בפרויקט להתקין בדיוק את הסביבה שלך או להתקין Virtual Machine שמאט את המחשב כיוון שכל סביבה מריצה מערכת הפעלה משלה. דרך מודרנית יותר היא להשתמש ב- Docker שבו סביבות הפיתוח השונות חולקות את אותה מערכת הפעלה. מה שמאפשר לכל הסביבות לרוץ הרבה יותר מהר.
במדריך זה:
- נכיר את המושגים החשובים ביותר בעולם ה- Docker
- נתקין Docker משורת הפקודות על לינוקס
- נתקין סביבת LAMP הכוללת PHP, מסד נתונים mySQL וממשק ניהול מסד הנתונים phpMyAdmin על שרת Apache.
- נתקשר עם הקונטיינרים באמצעות הטרמינל.
3 המושגים החשובים ביותר בעולם ה-Dokcer
לפני התקנת סביבת העבודה על המחשב האישי כדאי שנכיר את 3 המושגים הבאים:
- Dockerfile - הסכימה שאומרת ל-Docker אילו מרכיבים צריכים להיות בתמונה, Image.
- Image - תמונה של כל מרכיבי האפליקציה בזמן נתון. ניתן לארוז את התמונה כדי להשתמש בה בעתיד או לחלוק עם מפתחים אחרים המעורבים בפרויקט. ניתן גם להוריד תמונות מוכנות דוגמת תמונות של מערכת הפעלה Ubuntu 20.04 או גרסה מסוימת של PHP או את הגרסה האחרונה של mySQL. התמונה יכול לכלול הכול: קוד, סביבת פיתוח, ספריות והגדרות.
- Container - כשמריצים את התמונה היא הופכת לקונטיינר. בתוך הקונטיינר מריצים ומפתחים את האפליקציות.
מושג חשוב נוסף הוא Service שזו תמונה בתוך הקשר של אפליקציה.
התקנת Docker על המחשב האישי
נתקין דרך הטרמינל את 2 החבילות:
$ sudo apt install docker docker-compose
- docker-compose הוא ממשק ניהול אפליקציות המשלבות מספר קונטיינרים. בנוסף, הוא מאפשר להגדיר את רשימת ה-services של האפליקציה בתוך קובץ YAML במקום בשורת הפקודות.
כדי לתת למשתמש שלנו הרשאה להשתמש ב-Docker, נוסיף קבוצה ששמה "docker". לתוכה נצרף את המשתמש שלנו:
$ sudo groupadd docker
התוצאה:
groupadd: group 'docker' already exists
נוסיף את עצמנו לקבוצה:
$ sudo usermod -aG docker $USER
נשנה את הקבוצה הנוכחית שלנו ל-"docker":
$ newgrp docker
נריץ את הפקודה שמראה לנו את התמונות המותקנות:
$ docker image ls
התוצאה:
REPOSITORY TAG IMAGE ID CREATED SIZE
נבחן את ההתקנה באמצעות הפקודה:
$ docker run hello-world
התוצאה היא ש-Docker מזהה שהתמונה hello-world לא קיימת אצלנו, מוריד ומתקין אותה ואז גם מריץ:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
נציג את רשימת הקונטיינרים:
$ docker container ls -a
התוצאה:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f2069d0cee3b hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago sad_brahmagupta
- שם הקונטיינר sad_brahmagupta (זה במקרה שלי. אצלך על המחשב יהיה שם שונה)
נציג את רשימת התמונות אחרי ההתקנה:
$ docker image ls
התוצאה:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 8 months ago 13.3kB
- שם התמונה "hello-world"
אחרי שלמדנו איך להתקין תמונה וראינו שהכל עובד, אפשר למחוק אותה כי לא נזדקק לה בהמשך.
כדי למחוק תמונה קודם כל צריך למחוק את הקונטיינר שמשתמש בה. הפקודה docker container rm תמחק את הקונטיינר:
$ docker container rm sad_brahmagupta
האם המחיקה הצליחה? אילו קונטיינרים נותרו?
$ docker container ls -a
התוצאה:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- אין קונטיינרים.
עכשיו - אחרי מחיקת הקונטיינר - אפשר למחוק את התמונה:
$ docker rmi hello-world
התוצאה:
Untagged: hello-world:latest
Untagged: hello-world@sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
האם המחיקה הצליחה? אילו תמונות יש לנו?
$ docker images ls -a
התוצאה:
REPOSITORY TAG IMAGE ID CREATED SIZE
התקנת LAMP
האפליקצייה תשב בתוך חבילת תוכנה LAMP. ראשי תיבות של Linux, Apache, MySQL, PHP.
ניצור את תיקיית האפליקציה. לתיקייה שלי אני קורא lamp:
$ mkdir lamp/
נכנס לתוך התיקייה:
$ cd lamp/
לתיקייה נוסיף את שני הקבצים: php.Dockerfile וקובץ הקונפיגורציה docker-compose.yaml
כך נראה מבנה התיקייה lamp:
lamp ├── docker-compose.yaml └── php.Dockerfile
- בתוך הקובץ docker-compose.yaml נגדיר את רשימת ה-services.
- בתוך php.Dockerfile נבנה על בסיס התמונה הרשמית של PHP את התמונה הרצויה לנו הכוללת את ההרחבות: PDO ו-mysqli שיאפשרו לנו לעבוד עם מסד הנתונים.
בשביל ה-dockefile צריך למצוא את התמונה הרשמית של PHP.
את התמונה אתרתי על ידי גלישה ל-https://hub.docker.com שם חיפשתי תמונה של php.
בתוך לשונית ה-description מצאתי את הקישור: official-images repo's library/php שלחיצה עליו העבירה אותי לדף של github - https://github.com/docker-library/official-images/blob/master/library/php שמכיל את כל התגיות.
בדף ה-github חיפשתי את המונח apache מה שהעלה כמה אפשרויות אז בחרתי את הגרסה היציבה האחרונה של PHP עם התגית 7.4.10-apache-buster
כתבתי את הפקודות הבאות בתוך הקובץ php.Dockerfile על בסיס מה שמצאתי:
docker/lamp/php.Dockerfile
FROM php:7.4.10-apache-buster
RUN docker-php-ext-install mysqli pdo pdo_mysql
- הפקודה FROM ממפה את שם התמונה PHP על התגית שאיתרתי בצעד הקודם כדי להורות ל-Docker מאיזו תמונה ספציפית למשוך את הנתונים.
- הפקודה RUN מורה על התקנת התמונה PHP עם ההרחבות: mysqli pdo
בתוך קובץ הקונפיגורציה docker-compose.yml נגדיר את רשימת ה-services:
version: '3.3'
services:
webserver:
build:
dockerfile: php.Dockerfile
context: .
restart: always
volumes:
- ./html/:/var/www/html/
ports:
- '8080:80'
database:
image: 'mysql:8.0.21'
restart: always
volumes:
- ./mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: my_db
ports:
- '3308:3306'
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
restart: always
environment:
PMA_HOST: database
PMA_USER: root
PMA_PASSWORD: 1234
ports:
- '5000:80'
- version מגדיר את גרסת ה-Docker.
- ישנם 3 services ששמם: webserver, database, phpmyadmin
- את התמונה של PHP אני מושך מ-php.Dockerfile בעוד את התמונות של mySQL ו-phpMyAdmin אני מוריד ישירות וללא שינוי מהמאגר של Docker. לדוגמה:
image: mysql:8.0.21
- את התמונות אתרתי ב-https://hub.docker.com
- כדי להפנות לתיקייה של php.Dockerfile נשתמש ב-build:
build: dockerfile: php.Dockerfile context: .
- בשדה dockerfile נציין את שם הקובץ
- שדה context מציין את התיקייה בה הקובץ נמצא (נקודה מציינת את התיקייה הנוכחית).
- restart:always - מאתחל את הקונטיינר בכל עדכון של קונפיגורציה או של אחת התלויות
- השדה volumes ממפה את התיקיות. לדוגמה:
"./html/:/var/www/html/"
- ממפה את התיקייה שתיכף ניצור, docker/lamp/html/, על תיקיית השורש של אפאצ'י - /var/www/html/ ומאפשר לנו לעבוד בתוך התיקיות שלנו.
- השדה ports ממפה את הפורטים כדי שנוכל להשתמש בפורט 8080 ל-PHP, ב-5000 בשביל phpMyAdmin, וב-3308 בשביל mySQL. המיפוי חשוב כדי למנוע התנגשויות עם שירותים קיימים. אצלי לדוגמה, פורט 3306 נמצא בשימוש של mySQL (ללא קשר ל-Docker) והמיפוי מאפשר לי לעבוד עם השירות מתוך הקונטיינר ללא קונפליקטים.
- השדה environment מגדיר משתני סביבה דוגמת שם משתמש וסיסמה.
- בתוך תיקיית docker/lamp נוסיף 2 תיקיות:
- תיקיית mysql מאפשרת לשמור את המידע של מסד הנתונים אפילו אם מוחקים את הקונטיינר.
- תיקיית html מכילה את קבצי האפליקציה. בפרט, קובץ index.php שבו נבחן התחברות ל-mysql:
docker/lamp/html/index.php
";
$host = "database";
$user = "root";
$pass = "1234";
$db = "my_db";
try {
$dbh = new PDO("mysql:host=$host;dbname=$db", $user, $pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
echo "mySQL is up and running ";
} catch (PDOException $e) {
echo "Error!: " . $e->getMessage();
}
נסכם את מבנה הקבצים והתיקיות:
lamp ├── docker-compose.yaml ├── html │ └── index.php ├── mysql └── php.Dockerfile
נאתחל את הקונטיינר:
$ docker-compose up
נגלוש לאפליקציה מהדפדפן //localhost:8080/
ואם הכל כשורה זה מה שיודפס למסך:
PHP is up and running mySQL is up and running
ממשק phpmyadmin נמצא בכתובת //localhost:5000/
איך לעבוד עם קונטיינר של Docker משורת הפקודות?
1. כדי לראות את רשימת כל הקונטיינרים נשתמש בפקודה:
$ docker container ls
התוצאה:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0f4e15ea153a mysql:8.0.21 "docker-entrypoint.s…" 10 minutes ago Up 25 minutes 33060/tcp, 0.0.0.0:3308->3306/tcp lamp_database_1
3ceb3651d0ea lamp_webserver "docker-php-entrypoi…" 10 minutes ago Up 25 minutes 0.0.0.0:8080->80/tcp lamp_webserver_1
f8f084644505 phpmyadmin/phpmyadmin:latest "/docker-entrypoint.…" 10 minutes ago Up 10 minutes 0.0.0.0:5000->80/tcp lamp_phpmyadmin_1
- הקונטיינר שמעניין אותנו שמו lamp_database_1 (אצלך יכול להיות שם שונה).
2. נריץ את הפקודה הבאה בשביל לפתוח טרמינל bash בתוך הקונטיינר:
$ docker exec -it lamp_database_1 /bin/bash
ועכשיו נתחבר ל-mysql עם שם משתמש וסיסמה כפי שהגדרנו בקובץ ה- yaml:
root@0f4e15ea153a:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 33
Server version: 8.0.21 MySQL Community Server - GPL
Copyright (c) 2000, 2020, 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>
3. עכשיו אפשר להריץ פקודות של mysql, לדוגמה:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| my_db |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
4. נצא ממשק CLI מסד הנתונים חזרה אל הקונטיינר:
mysql> exit;
איך לייבא מסד נתונים?
כדי לתרגל את העבודה עם קונטיינר של Docker נלמד איך לייבא מסד נתונים.
-
נצא מתוך הקונטיינר של Docker:
root@0f4e15ea153a:/#exit;
-
נייבא את הקובץ של מסד הנתונים מתיקיית המקור (source_directory) לתוך הקונטיינר:
$ docker cp <source_directory>/dump.sql lamp_database_1:/dump.sql
-
נתחבר לטרמינל של הקונטיינר:
$ docker exec -it lamp_database_1 /bin/bash
-
בתוך הטרמינל של הקונטיינר נוודא שהקובץ אכן קיים בתיקיית השורש של הקונטיינר:
root@0f4e15ea153a:/# ls -al
-
בתוך הקונטיינר, נעשה לוגאין ל-CLI של mySQL באמצעות
mysql -u root -p:root@0f4e15ea153a:/# mysql -u root -p
- והזנת הסיסמה שהגדרנו בקובץ הקונפיגורציה.
-
ניצור מסד נתונים חדש, אם יש צורך:
mysql> CREATE DATABASE my_db;
-
עדיין בתוך ה-CLI של ה-mySQL, נוודא שמסד הנתונים אכן התווסף:
mysql> SHOW DATABASES;
-
עדיין בתוך ה-CLI של ה-mySQL, נעבור להשתמש במסד הנתונים:
mysql> USE my_db;
-
נייבא את מסד הנתונים:
mysql> SOURCE ./dump.sql;
-
נוודא שאכן מסד הנתונים עלה:
mysql> SHOW tables;
-
נצא מממשק ה-CLI של mySQL חזרה אל הקונטיינר:
mysql> EXIT;
-
נמחק את קובץ ה-SQL מתיקיית השורש של הקונטיינר, אם רצוננו בכך:
root@0f4e15ea153a:/# rm dump.sql
-
נצא מן הקונטיינר, אם צריך:
root@0f4e15ea153a:/# exit;
איך להסיר את הקונטיינרים?
לפעמים התקנה של Docker עושה בעיות, אז ניתן לעצור כל אחד מהקונטיינרים כדי לבדוק עם אפשרות אח"כ להחזיר לפעולה. כך עוצרים קונטיינר מסויים:
א. מבררים את שם הקונטיינרים ופרטים נוספים, דוגמת לאיזה פורט הם מאזינים:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0f4e15ea153a mysql:8.0.21 "docker-entrypoint.s…" 10 minutes ago Up 25 minutes 33060/tcp, 0.0.0.0:3308->3306/tcp lamp_database_1
3ceb3651d0ea lamp_webserver "docker-php-entrypoi…" 10 minutes ago Up 25 minutes 0.0.0.0:8080->80/tcp lamp_webserver_1
f8f084644505 phpmyadmin/phpmyadmin:latest "/docker-entrypoint.…" 10 minutes ago Up 10 minutes 0.0.0.0:5000->80/tcp lamp_phpmyadmin_1
ב. עוצרים את הקונטיינר לפי ה-CONTAINER ID המופיע בעמודה הראשונה. לדוגמה, כדי לעצור את הקונטיינר אשר שמו lamp_database_1:
$ docker stop 0f4e15ea153a
לפעמים צריך להסיר לחלוטין את הקונטיינרים. הפקודה הבאה מסירה את הקונטיינרים. כולל התיקיות volumes והתמונות images:
$ docker-compose down
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.