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
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 và /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!
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:
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:
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
Nhập password là secret vào:
Gõ lệnh kiểm tra connect: