BÀi viết này sẽ dùng docker compose version 3 để làm việc với các service tạo nên môi trường phát triển php

Cài đặt môi trường phát triển php với docker

2022-03-20 1509 lượt xem
Trương Thanh Hùng

Một máy chủ web thường bao gồm nhiều chương trình khác nhau - chẳng hạn như NGINX, PHP và MySQL. Theo thuật ngữ của Docker, mỗi chương trình bạn muốn cài đặt là một service. Và trong bài viết này chúng ta sẽ thiết lập php chạy nginx làm máy chủ chạy php-fpm 

Bắt đầu thôi!

Cài máy chủ nginx

Đầu tiên, hãy thêm một máy chủ web Nginx với việc tạo 1 file thực thi docker compose: docker-compose.yml

touch docker-compose.yml

Nội dung file docker-compose.yml: 

 
version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"

Khúc này bạn tạm hiểu là nó build image nginx:latest về rồi tạo 1 service với việc bind port trong docker là 80 ra port ngoài là 80. nếu bạn nghịch 8080:80 thì ý nghĩa là bind port trong docker là 80 ra port thực tế máy bạn là 8080 😄 

Chạy service

Để chạy service thì bạn gọi lệnh : docker-compose up

khi đó bạn gõ vào trình duyệt dòng : http://127.0.0.1 thì sẽ hiện thị như sau: 

Bây giờ server đã được cài đặt và chạy qua Docker, chúng tôi có thể hiển thị các file của mình trên máy chủ.

Bind code và cài đặt nginx

Docker có thể cho phép bạn chia sẽ 1 file hoặc 1 folder lên container. Vậy nên bạn sẽ tạo ra 1 file config nginx là app.conf trong folder nginx và folder code của bạn là app

Ta có việc binding volumn như sau:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx:/etc/nginx/conf.d/
            - ./app:/app

Bây giờ bất kỳ thay đổi nào thuộc folder /app/nginx đều được bind liên tục vào trong container đang chạy!

Bạn vào document của https://hub.docker.com/_/nginx có nói về việc nginx này config ở thư mục nào: outputs to /etc/nginx/conf.d/default.conf like this ... 

=> Mọi file config đều được nạp từ folder /etc/nginx/conf.d

Điều đó giải thích cho việc chúng ta vừa code ở trên là bind từ ./nginx vào /etc/nginx/conf.d/

Ok hiểu là thế, vậy giờ chúng ta sẽ tạo file nginx/app.conf config như sau: 

server {
    listen 80 default_server;
    root /app/public;
} 

Khi bạn viết như vậy là bạn đang thông báo cho nginx chạy trong cái container đó là: hey nginx, cứ có truy cập nào mày cũng cho nó lấy code trong folder /app/public nha!

Mà cái code trong folder app/public thì chả có 😄 nhưng chúng ta cũng từng khai báo với nginx là binding cái folder code app ở ngoài với cái app trong container rồi nên là giờ chúng ta chỉ viẹc tạo file app/public/index.html với nội dung như sau:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test thử nha</title>
</head>
<body>
    đây là trang tao mới thử tạo code html chưa có liên quan gì php
</body>
</html>

Ta được kết quả như sau: 

Cài đặt PHP-FPM

1 file docker compose có thể chạy nhiều cái service cùng 1 lúc nên nhiệm vụ chúng ta là thêm service php vào trong file docker compose tiếp như sau: 

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx:/etc/nginx/conf.d/
            - ./app:/app
    php:
        image: php:fpm
        volumes:
            - ./app:/app

Cái đoạn: image: php:fpm là sử dụng image php:fpm. Đối với NGINX, bạn sẽ cần sử dụng gói fpm. Hiện tại mình ghi vậy là không chỉ định phiên bản và chỉ sử dụng php: fpm, nó sẽ sử dụng phiên bản mới nhất - tại thời điểm viết bài, là 8.0.

Nếu bạn muốn chỉ định cụ thể thì dùng: php:7.4-fpm, php:7.3-fpm, php:8.0-fpm Tuỳ ý và có thể xem chi tiết ở đây: https://hub.docker.com/_/php

Như bạn đã biết hay không biết thì bạn cũng phải biết: nginx muốn chạy php phải config cho nó chạy file đuôi php 😄 nãy chưa config đâu giừo sửa lại file nginx/app.conf 1 tí: 

server {
    listen 80;
    index index.php index.html;
    
    root /app/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
} 

Cuối cùng muốn thực thi file php thì phải có file php mà thực thi chứ 😄 vậy trong folder app/public tạo file index.php với nội dung như sau: 

<?php
// file /app/public/index.php
phpinfo();

Okey! giừo restart lại docker compose là thôi! 

docker-compose up

Chờ xíu nó download xong thì gõ :  http://127.0.0.1 thì sẽ hiện thị ví dụ php:7.3-fpm như sau: 

Đặt vấn đề

Bạn nhớ khi cài xampp bạn muốn dùng mysql rồi mấy cái extention như PDO hay là image magic đều được start lên NHƯNG với tình huống này chúng ta kiểm tra thì không thấy nó được start + muốn start cũng chả biết chỗ quái nào mà start!!!

Vậy thì căng 😄 idea là mình sẽ tạo 1 image custom việc này cùng cấp với docker compose rồi trong docker compose mình tái sử dụng! 

1. Bước 1 sửa docker compose

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx:/etc/nginx/conf.d/
            - ./app:/app
    php:
        build:
            context: .
            dockerfile: PHP_CUSTOM.Dockerfile
        volumes:
            - ./app:/app

Tạo file PHP_CUSTOM.Dockerfile ngang cấp docker-compose.yml với nội dung:

FROM php:7.3-fpm
RUN docker-php-ext-install pdo pdo_mysql

Ok như vậy là bạn đã có pdo cho mysql chạy rồi. Tương tự nếu bạn muốn cài thêm extention khác thì cứ nghịch trong PHP_CUSTOM.Dockerfile là ok rồi. Ví dụ bạn muốn cài thêm cho php là chạy cái xdebug thì gọi như sau: 

FROM php:7.3-fpm

RUN docker-php-ext-install pdo pdo_mysql

RUN pecl install xdebug && docker-php-ext-enable xdebug

Chạy lại docker-compose up và kiểm tra output của phpinfo () sẽ cho thấy rằng cả pdo_mysql và xdebug đều được cài đặt:

Như vậy là cài đặt thành công php rồi! nếu bạn muốn xem : Cài thêm xdebug cho docker - nginx - vscode - php-fpm - macos

Lưu ý to đùng: Đôi khi bạn build docker compose bạn sẽ dính cache và nó không nhận code mới của bạn! bạn dùng lệnh build này trước: 

docker-compose build --no-cache
# sau đó mới gọi 
docker-compose up

CàiMariaDB thay cho mysql

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx:/etc/nginx/conf.d/
            - ./app:/app
    php:
        build:
            context: .
            dockerfile: PHP_CUSTOM.Dockerfile
        volumes:
            - ./app:/app
    mysql:
        image: mariadb:latest
        environment:
            MYSQL_ROOT_PASSWORD: 'secret'
            MYSQL_USER: 'admin'
            MYSQL_PASSWORD: 'secret'
            MYSQL_DATABASE: 'testing'
        volumes:
            - mysqldata:/var/lib/mysql
        ports:
            - 3306:3306
volumes:
    mysqldata: {}

Image đang sử dụng là mariadb:lastest. Cũng như NGINX và PHP, nếu muốn, bạn có thể chỉ định một phiên bản cụ thể của MariaDB tại đây.

Bạn có mấy biến để khi dùng php bạn config connection đến: 

MYSQL_ROOT_PASSWORD: mật khẩu gốc của cơ sở dữ liệu.

MYSQL_USER và MYSQL_PASSWORD: tên và mật khẩu cho người dùng MySQL được tạo với các quyền hạn chế.

MYSQL_DATABASE: tên của database

cổng 3306 để chúng ta có thể kết nối với nó với một máy khách như MySQL Workbench để quản lý cơ sở dữ liệu.

Khởi động lại máy chủ của bạn: 

docker-compose up

Vào file php edit đoạn code này thử xem chạy được chưa: 

<?php
$pdo = new PDO(
    'mysql:dbname=testing;host=mysql', 'admin', 'secret', 
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

$query = $pdo->query('SHOW VARIABLES like "version"');

$row = $query->fetch();

echo 'MySQL version:' . $row['Value'];

kết quả: 

 

Bonus cuối:

# nếu bạn muốn thực thi command trong 1 container nào đó thì gõ:
docker exec -it ID_CONTAINER /bin/sh
docker exec -it ID_CONTAINER /bin/bash
# ví dụ
docker exec -it 092d7adebed9 /bin/bash
# ID_CONTAINER lấy đâu ra : 
docker ps

Để vào mysql xem connect của php xem thế nào:

 docker ps

Kết quả 

 ###########
CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS          PORTS                              NAMES
092d7adebed9   nginx:latest         "/docker-entrypoint.…"   31 minutes ago   Up 29 minutes   0.0.0.0:80->80/tcp                 learningdocker-webserver-1
a20fda699208   learningdocker_php   "docker-php-entrypoi…"   31 minutes ago   Up 29 minutes   9000/tcp                           learningdocker-php-1
52ff7e05beb0   mysql:5.7.22         "docker-entrypoint.s…"   31 minutes ago   Up 29 minutes   0.0.0.0:3306->3306/tcp             db1

 Chạy vào terminal mysql

mysql -u root -p

Nhập password là secret vào:

Gõ lệnh kiểm tra connect:

show processlist;

 

những tag