[docker] 多容器项目 - PHP+MySQL+Nginx+utility containers
这个项目总共会配置 6 个容器,主要还是学习一下 docker 的使用和配置,目标是:
本机不安装 PHP、Nginx
安装部分全都交给 docker 容器实现
可以运行一个 Laravel 网页项目
修改本机代码可以即时更新网页
大概流程是这样的:
主机只负责保存必要的源码,PHP 容器会读取本机变动的源码,随后进行必要的更新
这个项目也是把之前所有学的知识点全都整合一下,本项目没有任何的 PHP 实现
service 实现
按照模块分
nginx
YAML 部分配置如下:
server: image: "nginx:stable-alpine3.17" ports: - "8000:80" volumes: - ./src:/var/www/html:delegated - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
image 选择用 alpine 是因为体积小一些
port 是暴露的端口
volumes 是配置文件的 bind mounts
host machine 不会安装 nginx,所以配置文件只能选择用 bind mounts 进行同步
src 还没有创建,到 php 那里会创建目录
nginx.conf 配置如下:
server { listen 80; index index.php index.html; server_name localhost; root /var/www/html/public; location / { try_files $uri $uri/ /index.php?$query_string; } 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; } }
nginx 的配置不会细说,这里唯一提到的就是这行配置:fastcgi_pass php:9000;。这里的 php 是 docker 容器的名称,对应的是 docker-compose 中的 php 这个 service,而 9000 是 php 镜像默认暴露的端口
此时目录结构如下:
❯ tree . . ├── docker-compose.yaml └── nginx └── nginx.conf 2 directories, 2 files
php
dockerfile 如下:
FROM php:8.1-fpm-alpine WORKDIR /var/www/html RUN docker-php-ext-install pdo pdo_mysql
这里是一个最简配置,其中:
php:8.1-fpm-alpine 是需要的 docker 镜像
Nginx 用 PHP Fast Process Manager (PHP-FPM) 去运行脚本,所以 一定 要用 fpm 相关的镜像
/var/www/html 这个目录和 Laravel 的配置相关
RUN 指令会下载安装所需要的依赖
service 部分实现如下:
php: build: context: "./dockerfiles" dockerfile: "php.dockerfile" volumes: - ./src:/var/www/html:delegated # ports: # - "3000:9000"
这里没什么特别复杂的,bind mounts 是为了同步本机的源码与 php 文件中的源码,delegated 可以理解成 batch update,是一个小优化
这里的 port mapping 被注释掉了,原因是因为 php 需要和 nginx 进行沟通,但是沟通的配置已经通过 nginx 实现,所以这里并不需要暴露端口。之后在 docker 的安全部分也会提及一下这个内容
mysql
⚠️:Laravel 现在默认使用的是 SQLite,不过这里还是会使用 mysql
service 的配置如下:
mysql: image: mysql:8.3.0 env_file: - "./env/mysql.env"
这里版本随意,用 latest 也行,我主要想看下下载下来的 image 有多大……我下载下来的 latest 有 632MB,但是 tags 上显示的都是不到 200MB……沉思……
环境变量的配置如下:
MYSQL_DATABASE=homestead MYSQL_USER=homestead MYSQL_PASSWORD=secret MYSQL_ROOT_PASSWORD=secret
homestead 曾经 是 laravel 的默认数据库名称,配置方面的就不多赘述了
这时候项目结构如下
❯ tree . ├── docker-compose.yaml ├── dockerfiles │ └── php.dockerfile ├── env │ └── mysql.env ├── nginx │ └── nginx.conf └── src 5 directories, 4 files
到这一步,主要的容器都实现完毕了,下面的都是 util container,用来辅助实现功能的
composer
composer 是用来安装 laravel 的,主要是用来配置 laravel 项目,属于运行了一次之后就可以关闭的那种
docker compose 配置如下:
composer: build: context: ./dockerfiles dockerfile: composer.dockerfile volumes: - ./src:/var/www/html:delegated
这里的内容都过了一遍了,就不多赘述。dockerfile 内容如下:
FROM composer:latest WORKDIR /var/www/html ENTRYPOINT [ "composer" ]
这里主要就是需要一个 ENTRYPOINT 的实现,去在 WORKDIR 下执行命令
⚠️:我看到教程上说需要添加 "--ignore-platform-reqs",事实上我加了这个 flag 反而会有 version 冲突的问题……是 PHP7 和 PHP8 之间关于 readonly 这个 namespace 的冲突
此时项目结构如下:
❯ tree . ├── docker-compose.yaml ├── dockerfiles │ ├── composer.dockerfile │ └── php.dockerfile ├── env │ └── mysql.env ├── nginx │ └── nginx.conf └── src 5 directories, 5 files
创建 laravel 项目
这里是从 Creating a Laravel Project 这里贴的指令,需要运行的指令如下:
composer create-project laravel/laravel example-app
ENTRYPOINT 已经指定了 composer,所以在终端上只需要运行 create-project laravel/laravel example-app 即可
这里会先运行一下 composer,去创建一个基础的 laravel 项目结构。因为已经实现了 bind mounts,所以后面的容器可以通过当前的项目结构去在容器中,通过 php 和 nginx 去启动服务器
❯ docker compose run --rm composer create-project laravel/laravel . WARN[0000] /Users/user/study/docker/section08/docker-compose.yaml: `version` is obsolete [+] Creating 1/1 ✔ Network section08_default Created 0.1s [+] Building 8.0s (6/6) FINISHED docker:desktop-linux # 省略一些 download 和 build 过程 85 packages you are using are looking for funding. Use the `composer fund` command to find out more! > @php artisan vendor:publish --tag=laravel-assets --ansi --force INFO No publishable resources for tag [laravel-assets]. No security vulnerability advisories found. > @php artisan key:generate --ansi INFO Application key set successfully. > @php -r "file_exists('database/database.sqlite') || touch('database/database.sqlite');" > @php artisan migrate --graceful --ansi INFO Preparing database. Creating migration table ............................................................................................................. 9.41ms DONE INFO Running migrations. 0001_01_01_000000_create_users_table ................................................................................................ 34.41ms DONE 0001_01_01_000001_create_cache_table ................................................................................................. 8.67ms DONE 0001_01_01_000002_create_jobs_table ................................................................................................. 30.52ms DONE
这里没什么报错,一路非常成功的下载了所有的 deps,随后看一下目前的结构目录:
└── vite.config.js 1290 directories, 8111 files # src 下面的文件太多了,我这里只展现 2 层 ❯ tree . -L 2 . ├── docker-compose.yaml ├── dockerfiles │ ├── composer.dockerfile │ └── php.dockerfile ├── env │ └── mysql.env ├── nginx │ └── nginx.conf └── src ├── README.md ├── app ├── artisan ├── bootstrap ├── composer.json ├── composer.lock ├── config ├── database ├── package.json ├── phpunit.xml ├── public ├── resources ├── routes ├── storage ├── tests ├── vendor └── vite.config.js 15 directories, 12 files
可以看到,laravel 的项目成功的安装好了,并且同步到了 src 下面:
想到以前还真的学过 php 和 laravel 的青葱岁月啊……
修改 laravel 配置
这里主要修改的是 src/.env,之前提到了现在 laravel 已经使用 sqlite 了,所以需要修改一下 mysql 的配置:
# 大概是 22-27 行这里 DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret
运行 laravel 项目
这里使用 docker compose up,使用方式有两种:
# 1. 这里会运行指定的3个容器 ❯ docker compose up server php mysql # 2. 或者配置 depends_on,之前没有配置,不过在我的 docker compose 里已经补上了 ❯ docker compose up server # 省略掉一些 download 和 build [+] Running 0/3 ⠹ Container section08-php-1 Created 0.2s ⠹ Container section08-mysql-1 Created 0.2s ⠋ Container section08-server-1 Created 0.1s Attaching to server-1 server-1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration server-1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ server-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh server-1 | 10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?) server-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh server-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh server-1 | /docker-entrypoint.sh: Configuration complete; ready for start up server-1 | 2024/04/25 03:45:52 [notice] 1#1: using the "epoll" event method server-1 | 2024/04/25 03:45:52 [notice] 1#1: nginx/1.24.0 server-1 | 2024/04/25 03:45:52 [notice] 1#1: built by gcc 12.2.1 20220924 (Alpine 12.2.1_git20220924-r4) server-1 | 2024/04/25 03:45:52 [notice] 1#1: OS: Linux 6.6.22-linuxkit server-1 | 2024/04/25 03:45:52 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker processes server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 21 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 22 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 23 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 24 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 25 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 26 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 27 server-1 | 2024/04/25 03:45:52 [notice] 1#1: start worker process 28
看起来服务器已经成功启动了:
⚠️:这里的报错是因为 mysql 没有成功配置好的关系,现在 laravel 默认使用的是 sqlite,所以配置都是按照 sqlite 进行的,等到下一步配置完 artisan 就好了
artisan & npm
compose 配置如下:
artisan: build: context: "./dockerfiles" dockerfile: "php.dockerfile" volumes: - ./src:/var/www/html:delegated entrypoint: ["php", "/var/www/html/artisan", "migrate"] npm: image: node:20-alpine working_dir: /var/www/html entrypoint: ["npm"] volumes: - ./src:/var/www/html:delegated
这两个没有新创建一个 dockerfile——也不是不可以,不过这里展现一下不用新建 dockerfile 也可以实现 entrypoint 之类的功能。
同样,这两个也是 util container
artisan 运行结果如下:
❯ docker compose run --rm artisan WARN[0000] /Users/user/study/docker/section08/docker-compose.yaml: `version` is obsolete INFO Preparing database. Creating migration table ...................................... 25.68ms DONE INFO Running migrations. 0001_01_01_000000_create_users_table .......................... 79.47ms DONE 0001_01_01_000001_create_cache_table .......................... 27.05ms DONE 0001_01_01_000002_create_jobs_table ........................... 82.80ms DONE
这代表数据库已经 migrate 成功了:
npm 运行结果如下:
❯ docker compose run --rm npm WARN[0000] /Users/user/study/docker/section08/docker-compose.yaml: `version` is obsolete npm Usage: npm install install all the dependencies in your project npm install add the dependency to your project npm test run this project's tests npm run run the script named npm -h quick help on npm -l display usage info for all commands npm help search for help on npm help npm more involved overview All commands: access, adduser, audit, bugs, cache, ci, completion, config, dedupe, deprecate, diff, dist-tag, docs, doctor, edit, exec, explain, explore, find-dupes, fund, get, help, help-search, hook, init, install, install-ci-test, install-test, link, ll, login, logout, ls, org, outdated, owner, pack, ping, pkg, prefix, profile, prune, publish, query, rebuild, repo, restart, root, run-script, sbom, search, set, shrinkwrap, star, stars, start, stop, team, test, token, uninstall, unpublish, unstar, update, version, view, whoami Specify configs in the ini-formatted file: /root/.npmrc or on the command line via: npm --key=value More configuration info: npm help config Configuration fields: npm help 7 config npm@10.5.0 /usr/local/lib/node_modules/npm
至此,就完成了不需要在本机上安装这些功能,但是依旧可以启动一个 laravel 项目的 docker 案例了
还没有评论,来说两句吧...