最近组里的一个项目使用了 Laravel 8 来开发。Laravel 8 自带的 sail 提供了开发时的镜像打包脚本,但它是直接运行 php 命令行进程,不能用于生产环境。
为了方便开发和部署,我做了一个 Nginx + PHP 8 (fpm)的 docker 镜像:
它 基于官方的 php:8-fpm-alpine, node:15-alpine3.13, nginx:alpine 和 richarvey/nginx-php-fpm 等镜像和构建脚本,实际的镜像大小比 sail 的要小很多: 400M vs 700M,在docker hub上压缩后不到200M。
怎么用呢?
开发环境
假如是在开发环境开发一个 Laravel 8 或 9 的项目,可以直接把 docker-compose.yml
里的镜像打包部分去掉,改成用我的这个镜像,这个镜像也直接支持 sail 的命令行操作。例子:
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
image: tangramor/nginx-php8-fpm
environment:
TZ: 'Asia/Shanghai'
WEBROOT: '/var/www/html/public'
PHP_REDIS_SESSION_HOST: 'redis'
CREATE_LARAVEL_STORAGE: '1'
ports:
- '${APP_PORT:-80}:80'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
- meilisearch
- selenium
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
volumes:
- 'sail-meilisearch:/data.ms'
networks:
- sail
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
selenium:
image: 'selenium/standalone-chrome'
volumes:
- '/dev/shm:/dev/shm'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
sail-meilisearch:
driver: local
生产环境
要部署一个 Nginx + PHP8 的生产环境虽然不麻烦,但容器能够更快捷的帮你完成任务,还能实现环境隔离。写一个 Dockerfile:
FROM tangramor/nginx-php8-fpm
# 拷贝源码
COPY . /var/www/html
# 如果在源码根目录下存在 conf 目录,那么 start.sh 脚本会
# 拷贝 conf/nginx.conf 到 /etc/nginx/nginx.conf
# 拷贝 conf/nginx-site.conf 到 /etc/nginx/conf.d/default.conf
# 拷贝 conf/nginx-site-ssl.conf 到 /etc/nginx/conf.d/default-ssl.conf
# 拷贝 ssl 证书文件
COPY conf/ssl /etc/nginx/ssl
# start.sh 会设置时区为 $TZ 值
ENV TZ Asia/Shanghai
# start.sh 会替换缺省的 web 根目录为 $WEBROOT 值
ENV WEBROOT /var/www/html/public
# start.sh 会使用 redis 作为会话存储方式并连接 $PHP_REDIS_SESSION_HOST 服务器或容器名
ENV PHP_REDIS_SESSION_HOST redis
# 如果 $CREATE_LARAVEL_STORAGE = 1,start.sh 会创建 laravel storage 目录结构
ENV CREATE_LARAVEL_STORAGE "1"
# 下载 node/php 依赖包,
# 有些 nodejs 模块需要 gcc/g++
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache --virtual .build-deps gcc g++ libc-dev make \
# set preferred npm mirror
&& cd /usr/local \
&& npm config set registry https://registry.npm.taobao.org \
&& cd /var/www/html \
# install node modules
&& npm install \
# install php composer packages
&& composer install \
# clean
&& apk del .build-deps \
# build js/css
&& npm run dev \
# set .env
&& cp .env.test .env \
# change /var/www/html user/group
&& chown -Rf nginx.nginx /var/www/html
用它来打包你的 Laravel 8 或 9 应用为一个容器镜像,就可以部署了。