將 Symfony 封裝到 Docker 中並配置 Nginx 及 PHP-FPM
前情提要
最近偶爾會使用 PaaS 的佈署平台例如 GCP App Engine 或是 Digital Ocean 的 App Platform,這兩個 PaaS 平台都有個共通的特點就是,有的時候想要做一些特殊的任務或是想要安裝自己的 PHP Extension 的時候,就必須要使用自己的 Docker Image 來作為載體,而這些平台提供的功能又不能用 Docker compose 把 Nginx 跟 PHP-FPM 分開裝,所以只能把這兩個東西裝在一起。
話說用 DigitalOcean App Platform 的時候,就覺得自己用自己的 Image 勢在必行,如果你跟我一樣使用 Doctrine 的話,那麼你”有機率”在部暑到 App Platform 之後得到這麼一個錯誤:
Operation ‘Doctrine\DBAL\Platforms\AbstractPlatform::getSequenceNextValSQL’ is not supported by platform.
然後你就只能在 Digital Ocean 中重開一個 App,然後用同一個步驟,多試幾次就解決了,完全不知道為什麼,所以這就使得佈署在 Digital Ocean 增加了一些不穩定性,所以想佈署在那裡,請一定要用自己的 Docker Image。
小牢騷
開工
其實這個工作並不難,我們只要在 Symfony 的 Project root directory 底下新增三個檔案,分別是 docker.sh、nginx以及Dockerfile。
建立 Docker 啟動腳本 (docker.sh)
這個腳本是在 Docker 啟動之後運行的 shell script:
#!/usr/bin/env sh
service php7.4-fpm restart
nginx -g 'daemon off;'
簡單來說就是在 Docker Instance 啟動之後,先啟動 PHP7.4 FPM 之後再啟動 nginx。之所以要將 nginx 的 daemon mode 關掉是因為,沒有一個應用程式在前台運行,docker 就會自動結束。
建立 Nginx Configuration File (nginx)
此外這個檔案可以依照需求自己改變。
server {
root /app/public;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
# optionally disable falling back to PHP script for the asset directories;
# nginx will return a 404 error when files are not found instead of passing the
# request to Symfony (improves performance but Symfony's 404 page is not displayed)
# location /bundles {
# try_files $uri =404;
# }
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
# optionally set the value of the environment variables used in the application
# fastcgi_param APP_ENV prod;
# fastcgi_param APP_SECRET <app-secret-id>;
# fastcgi_param DATABASE_URL "mysql://db_user:db_pass@host:3306/db_name";
# When you are using symlinks to link the document root to the
# current version of your application, you should pass the real
# application path instead of the path to the symlink to PHP
# FPM.
# Otherwise, PHP's OPcache may not properly detect changes to
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
# for more information).
# Caveat: When PHP-FPM is hosted on a different machine from nginx
# $realpath_root may not resolve as you expect! In this case try using
# $document_root instead.
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
# error_log /var/log/nginx/project_error.log;
# access_log /var/log/nginx/project_access.log;
}
建立 Dockerfile
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt install -y nginx php php-fpm composer
RUN apt install -y php-xml php-mysql php-zip
# 網站根目錄將會被放在 /app 中
COPY . /app
WORKDIR /app
RUN rm -R vendor
RUN APP_ENV=prod composer install
RUN chmod +x docker.sh
RUN rm /etc/nginx/sites-available/default
RUN cp nginx /etc/nginx/sites-available/default
# 這可以改成你想改的 Port
EXPOSE 80
# instance 啟動之後執行 /app/docker.sh
CMD ["/app/docker.sh"]
建立 DockerImage 及嘗試運行
sudo docker build -t floatflower/symfony .
# 如果你在 Dockerfile 中有更改 Port,那麼記得把 80 改成你指定的 Port。
sudo docker run -d -p 8003:80 floatflower/symfony
接下來我們用瀏覽器打開 http://localhost:8003,就能看到以下畫面,說明我們的 Docker 建立成功: