תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

התקנת PHP, mySQL ושרת אפאצי באמצעות דוקר Docker

מחבר:
בתאריך:

Docker הוא פלטפורמה המאפשרת לארוז אפליקציה ולהריץ אותה בתוך סביבה מבודדת המכונה קונטיינר. כאשר ניתן להריץ כמה קונטיינרים על אותו מחשב במקביל.

היתרונות של קונטיינר שאתה יכול ליצור את הסביבה לפיתוח האפליקציה שלך ממש בקלות, ואחר כך ניתן להתקין את הסביבה על כל המחשבים שלך ושל המתכנתים האחרים שעובדים על הפרויקט. לדוגמה, אם אתה כותב את האפליקציה שלך על PHP גרסה 7.4 עם גרסה 8.0.21 של mySQL על שרת Apache. אתה יכול לבקש יפה מכל המפתחים בפרויקט להתקין בדיוק את הסביבה שלך או להתקין Virtual Machine שמאט את המחשב כיוון שכל סביבה מריצה מערכת הפעלה משלה. דרך מודרנית יותר היא להשתמש ב- Docker שבו סביבות הפיתוח השונות חולקות את אותה מערכת הפעלה. מה שמאפשר לכל הסביבות לרוץ הרבה יותר מהר.

התקנת PHP, mySQL ושרת אפאצי באמצעות דוקר Docker

במדריך זה:

  1. נכיר את המושגים החשובים ביותר בעולם ה- Docker
  2. נתקין Docker משורת הפקודות על לינוקס
  3. נתקין סביבת LAMP הכוללת PHP, מסד נתונים mySQL וממשק ניהול מסד הנתונים phpMyAdmin על שרת Apache.
  4. נתקשר עם הקונטיינרים באמצעות הטרמינל.

 

3 המושגים החשובים ביותר בעולם ה-Dokcer

לפני התקנת סביבת העבודה על המחשב האישי כדאי שנכיר את 3 המושגים הבאים: 

  1. Dockerfile - הסכימה שאומרת ל-Docker אילו מרכיבים צריכים להיות בתמונה, Image.
  2. Image - תמונה של כל מרכיבי האפליקציה בזמן נתון. ניתן לארוז את התמונה כדי להשתמש בה בעתיד או לחלוק עם מפתחים אחרים המעורבים בפרויקט. ניתן גם להוריד תמונות מוכנות דוגמת תמונות של מערכת הפעלה Ubuntu 20.04 או גרסה מסוימת של PHP או את הגרסה האחרונה של mySQL. התמונה יכול לכלול הכול: קוד, סביבת פיתוח, ספריות והגדרות.
  3. 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.

search php in hub.docker.com

בתוך לשונית ה-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 נלמד איך לייבא מסד נתונים.

  1. נצא מתוך הקונטיינר של Docker:

    root@0f4e15ea153a:/#exit;
  2. נייבא את הקובץ של מסד הנתונים מתיקיית המקור (source_directory) לתוך הקונטיינר:

    $ docker cp <source_directory>/dump.sql lamp_database_1:/dump.sql
  3. נתחבר לטרמינל של הקונטיינר:

    $ docker exec -it lamp_database_1 /bin/bash
  4. בתוך הטרמינל של הקונטיינר נוודא שהקובץ אכן קיים בתיקיית השורש של הקונטיינר:

    root@0f4e15ea153a:/# ls -al
  5. בתוך הקונטיינר, נעשה לוגאין ל-CLI של mySQL באמצעות
    mysql -u root -p:

    root@0f4e15ea153a:/# mysql -u root -p
    • והזנת הסיסמה שהגדרנו בקובץ הקונפיגורציה.
  6. ניצור מסד נתונים חדש, אם יש צורך:

    mysql> CREATE DATABASE my_db;
  7. עדיין בתוך ה-CLI של ה-mySQL, נוודא שמסד הנתונים אכן התווסף:

    mysql> SHOW DATABASES;
  8. עדיין בתוך ה-CLI של ה-mySQL, נעבור להשתמש במסד הנתונים:

    mysql> USE my_db;
  9. נייבא את מסד הנתונים:

    mysql> SOURCE ./dump.sql;
  10. נוודא שאכן מסד הנתונים עלה:

    mysql> SHOW tables;
  11. נצא מממשק ה-CLI של mySQL חזרה אל הקונטיינר:

    mysql> EXIT;
  12. נמחק את קובץ ה-SQL מתיקיית השורש של הקונטיינר, אם רצוננו בכך:

    root@0f4e15ea153a:/# rm dump.sql
  13. נצא מן הקונטיינר, אם צריך:

    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

לכל מדריכי ה-PHP

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.

למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.

שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.

המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?

השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.

הוסף תגובה חדשה

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

איך אומרים בעברית אינטרנט?

 

תמונת המגיב

איתי בתאריך: 08.11.2021

מדריך מצוין. עזר לי מאוד.

תמונת המגיב

משה בתאריך: 25.03.2022

איזה מדריך מדהים, וואו!