【记录】基于多个Docker的NGINX、PHP、MYSQL的Web环境搭建

    技术2023-12-06  81

    公司派下来一个任务,把ERP进销存环境放到docker上去跑,对docker、php及web环境搭建毫不熟悉的我只好一步一步来,网上相关教程想必很多了,这里还是记录一下新手小白长达四天经历各种愚蠢的失败终于完成的搭建过程……

    ERP进销存获取链接:https://www.52pojie.cn/thread-1151307-1-1.html

    差不多的web项目应该都能依据此步骤完成,这里以此ERP进销存系统为实现例子。

     

    1.镜像拉取


    由于我的设备是arm64处理器,mysql这里选择Docker Hub上的mysql/mysql-server(直接搜索),tag选择latest;php就用php,根据下面的此ERP进销存项目的要求,tag选择5.6-fpm;nginx就使用nginx,我在这选择了1.17.6的tag,nginx的tag选择影响应该不大。

    欢迎使用模板饭ERP进销存V8标准版系统

    请按照以下方法安装程序

    安装环境PHP5.6

    1、首先把更目录的erp.sql导入到数据库

    2、打开application\config\database.php文件,找到数据库配置字段

    如下:

    $db['default']['hostname'] = 'localhost';  //一般默认即可

    $db['default']['username'] = 'root';   //数据库用户名

    $db['default']['password'] = 'root';  //数据库密码

    $db['default']['database'] = 'erpv8';  //数据库名称

     

    访问您的网址  账号为 admin  密码为 mobanfan.com

     PS:docker中的tag类似与git中的版本,具体镜像和tag选择要根据项目的要求和项目所跑设备的处理器类型来,比如DockerHub中的mysql镜像仓库就没有适用arm64的,因此选择mysql/mysql-server。而且刚开始我直接拉取php:latest,结果当然不能用,人家网上教程都让拉取php-fpm,至于为什么不能用看了半天相关资料仍然没懂透,原谅我对于php在此之前实在是一无所知,公司疯狂催我,鄙人只能见好就过……先把过程记录下来吧。

    据上,依次使用下面的命令拉取镜像:

    docker pull mysql/mysql-server:latest docker pull php:5.6-fpm docker pull nginx:1.17.6

    经过三次漫长的等待后,我们可以查看系统中已拉取的镜像:

    root@localhost:/home/ubuntu# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql/mysql-server latest cefadf73f449 2 months ago 435MB nginx 1.17.6 bfbe0b456268 6 months ago 120MB php 5.6-fpm 3c6e97923edb 17 months ago 305MB

     

    2.部署Mysql容器


    镜像成功拉取后,我们要挨着run各镜像生成容器,先从最独立的mysql开始。

    docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server:latest

    参数解释:

    --name : 为运行的容器取一个别名(只需注意系统中各docker容器的name不可重复),此后对容器的重启停止删除等操作可以直接适用此别名。

    -p:端口映射,格式为主机port:容器port,这里我们直接把mysql默认开放的3306端口映射到主机的3306上。

    -e:传递环境变量,这里后面的MYSQL_ROOT_PASSWORD=123456意为将mysql数据库root用户的密码设置为123456。

    -d:后台运行容器

    mysql/mysql-server:latest:你所要运行的目标镜像名:tag

     命令执行后,我们查看mysql是否成功执行:

    root@localhost:/home/ubuntu# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c33536c36bcb mysql/mysql-server "/entrypoint.sh mysq…" 2 days ago Up 4 hours (healthy) 0.0.0.0:3306->3306/tcp, 33060/tcp mysql

     可以看到mysql的docker容器已经成功起来了,但是还没完,我们把对mysql容器所需操作一口气做完,免得后面弄完nginx和php后又回头整。

    导入sql数据

    根据安装提示,我们可以先把项目提供的sql文件导入到已经起来的mysql容器中,先把sql文件拷入容器中(这里之前运行容器时如果加了文件挂载选项,可以直接拷贝到相关目录下,但我没有为mysql容器挂载目录,使用docker cp也是一样的):

    root@localhost:/home/ubuntu# docker cp ERPModel/erp.sql mysql:/home

    以上命令为:把ERP项目目录下的erp.sql文件拷贝到名为mysql的容器内部的/home目录下。

    然后以mysql方式,输入之前设定的密码123456进入容器内部数据库:

    root@localhost:/home/ubuntu# docker exec -it mysql mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 5132 Server version: 8.0.20 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>

     当然,先进入容器bash命令行,再进入数据库命令行也是可以的:

    root@localhost:/home/ubuntu# docker exec -it mysql bash bash-4.2# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 5136 Server version: 8.0.20 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>

     创建一个数据库,再把之前拷贝入容器的sql文件导入:

    mysql> create erp_database; mysql> use erp_database; mysql> source /home/erp.sql;

    查看项目设计的各种表是否导入成功:

    mysql> show tables; +------------------------+ | Tables_in_erp_database | +------------------------+ | ci_account | | ci_account_info | | ci_address | | ci_admin | | ci_assistingprop | | ci_assistsku | | ci_category | | ci_contact | | ci_goods | | ci_goods_img | | ci_invoice | | ci_invoice_img | | ci_invoice_info | | ci_invoice_type | | ci_log | | ci_menu | | ci_options | | ci_order | | ci_order_info | | ci_staff | | ci_storage | | ci_unit | | ci_unittype | | ci_verifica_info | | ci_warehouse | +------------------------+ 25 rows in set (0.01 sec) mysql>

    设置用户host

    由于我们的三个docker是分开独立的,如果要让php docker里的程序能连接上另一个docker里的mysql,相当于远程登陆,因此要修改下所使用user的host值,让php能顺利登陆。

    查看现有用户的host:

    mysql> select host,user from user; +-----------+------------------+ | host | user | +-----------+------------------+ | localhost | root | | localhost | healthchecker | | localhost | mysql.infoschema | | localhost | mysql.session | | localhost | mysql.sys | +-----------+------------------+ 5 rows in set (0.00 sec)

    我不打算创建新用户了,直接使用root登陆,就修改root的host(也可以创建新用户设置host值,之后的登陆就用此信息):

    mysql> update user set host='%' where user='root';

    此步骤参考:https://www.cnblogs.com/bulh/articles/12362124.html

    my.cnf配置

    为防止因字符集设置问题出现字符解析错误,修改/etc目录下的my.cnf文件,以下是我的my.cnf内容,标黄部分是在原基础上添加的(不能在容器中直接修改的,可以在外部写好文件后拷贝进去):

    # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html

    [client] default-character-set=utf8

    [mysql] default-character-set=utf8

    [mysqld] # # Remove leading # and set to the amount of RAM for the most important data # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%. # innodb_buffer_pool_size = 128M # # Remove leading # to turn on a very important data integrity option: logging # changes to the binary log between backups. # log_bin # # Remove leading # to set options mainly useful for reporting servers. # The server defaults are faster for transactions and fast SELECTs. # Adjust sizes as needed, experiment to find the optimal values. # join_buffer_size = 128M # sort_buffer_size = 2M # read_rnd_buffer_size = 2M

    # Remove leading # to revert to previous value for default_authentication_plugin, # this will increase compatibility with older clients. For background, see: # https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin # default-authentication-plugin=mysql_native_password skip-host-cache skip-name-resolve datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock secure-file-priv=/var/lib/mysql-files user=mysql

    pid-file=/var/run/mysqld/mysqld.pid

    collation-server = utf8_unicode_ci                              # MySQL服务端校对规则character-set-server = utf8                                         # MySQL服务端校对规则default_authentication_plugin = mysql_native_password         # 使用mysql_native_password插件认证

     修改密码加密方式

    由于这里使用的mysql是8.0以上的版本,需要修改一下密码加密方式:

    mysql> alter user 'root'@'%' identified with mysql_native_password by '123456'; mysql> flush privileges;

    此步骤参考:https://www.cnblogs.com/shenhuawen/p/13020388.html

    修改sql_mode

    这里提一下,在我初次搭建完成后,数据显示有问题,报服务器响应错误,网站提示错误信息:

    A Database Error Occurred Error Number: 1055 Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'erp_database.ci_invoice_info.billDate' which is not functionally dependent on columns in GROUP BY clause; 

    查询发现,由于mysql版本问题,导致数据库操作中Gourp by语句出了问题,需要修改一下sql_mode,进入mysql容器的mysql命令行,执行下面命令:

    mysql> use erp_database; mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

    查看执行结果:

    mysql> select @@sql_mode; +----------------------------------------------------------------------------------------------------+ | @@sql_mode | +----------------------------------------------------------------------------------------------------+ | STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION | +----------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)

    此步骤详细内容参考:https://blog.csdn.net/weixin_43064185/article/details/99646535

     

    到此,我们mysql相关设置大概就完成了,部署php和nginx前,先创建两个目录,方便之后挂载docker文件目录:

    mkdir /home/ubuntu/nginx/conf.d /home/ubuntu/nginx/www

     

    3.部署php容器


    同样,根据拉取的基础镜像生成容器,把php容器中的/www目录挂载到刚刚创建的目录上:

    docker run --name phphhh -v /home/ubuntu/nginx/www:/www --link mysql:mysql -d php:5.6-fpm

    -v:docker目录挂载选项,将本机的实际目录挂载到容器中的目录。

    --link:连接两个容器,这里的参数设置意为把mysql与php的docker 容器连接以方便通信

    现在可以很方面地直接把ERP项目拷贝到此目录下:

    cp ERPModel/* /home/ubuntu/nginx/www -rf

    安装mysql扩展

    虽然上面连接了php与mysql容器,但仅仅满足了容器间的通信要求,我这里拉的镜像版本里不自带mysql扩展,所以需要我们进入容器自己安装:

    root@localhost:/home/ubuntu# docker exec -it php bash root@fbed8943def9:/usr/local/bin# docker-php-ext-install mysql root@fbed8943def9:/usr/local/bin# docker-php-ext-install mysqli

    安装好后,找到容器中/usr/local/etc/php目录下的php.ini文件(从基础镜像跑起来的容器可能没有此文件,但是同目录下有php.ini-production文件也是一样的,不能在容器中直接修改的可以把这个拷贝出来,修改后再docker ps进去改名php.ini),找到其中的两项设置并修改:

    ;extension=php_intl.dll ;extension=php_imap.dll ;extension=php_interbase.dll ;extension=php_ldap.dll ;extension=php_mbstring.dll ;extension=php_exif.dll      ; Must be after mbstring as it depends on itextension=mysql.so extension=mysqli.so ;extension=php_oci8_12c.dll  ; Use with Oracle Database 12c Instant Client ;extension=php_openssl.dll ;extension=php_pdo_firebird.dll ;extension=php_pdo_mysql.dll ;extension=php_pdo_oci.dll ;extension=php_pdo_odbc.dll  

    重启php容器:

    docker restart php

     

    4.部署nginx容器


    启动nginx container:

    docker run --name nginx -v /home/ubuntu/nginx/conf.d:/etc/nginx/conf.d -v /home/ubuntu/nginx/www:/usr/share/nginx/html -p 7001:80 -p 7002:8081 --link php:php --link mysql:mysql -itd nginx:1.17.6

    -v /home/ubuntu/nginx/conf.d:/etc/nginx/conf.d :将nginx的服务配置目录挂载到主机实际目录上,方便修改服务配置文件。

    -v /home/ubuntu/nginx/www:/usr/share/nginx/html :挂载项目工程位置,注意这里相当于和php容器是共享目录了,

    -p :端口映射,上面看到我映射了两个端口,80映射到7002用于测试,8081映射到7001用于目标项目。

    --link:连接mysql docker和php docker(其实我觉得应该不用为nginx连接mysql?毕竟是由php负责连接数据库通信,我也是看教程使用的命令,感兴趣的读者可以试一下)。

     可以看到运行的三个容器:

    root@localhost:/home/ubuntu# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 78f0f83970d6 nginx:1.17.6 "nginx -g 'daemon of…" 2 days ago Up 2 days 0.0.0.0:7001->80/tcp, 0.0.0.0:7002->8081/tcp nginx fbed8943def9 php:5.6-fpm "docker-php-entrypoi…" 2 days ago Up 2 days 9000/tcp php 33536c36bcb mysql/mysql-server "/entrypoint.sh mysq…" 3 days ago Up 2 days (healthy) 0.0.0.0:3306->3306/tcp, 33060/tcp mysql

     在进入项目页面之前,我们可以测试一下nginx、php与mysql之间的通信是否有问题。

     

    5.测试


    测试nginx是否成功连接php

    创建一个文件,命名index.php,内容如下:

    <?php phpinfo(); ?>

    懒得弄新的测试目录,直接在/home/ubuntu/nginx/www下新建测试目录,把此文件放入:

    mkdir /home/ubuntu/nginx/www/phptest cp index.php /home/ubuntu/nginx/www/phptest/

    我们进入为nginx配置文件挂载的/home/ubuntu/nginx/conf.d目录下,编辑一个名为phpinfo.conf的文件,文件内容:

    server {     listen       8081;             # docker中的8081端口映射到了实体主机的7002端口,可通过7002访问服务     server_name  localhost;

        location / {         root   /usr/share/nginx/html/phptest;   #此服务的文件配置目录         index  index.html index.htm index.php;     }

        error_page   500 502 503 504  /50x.html;     location = /50x.html {         root   /usr/share/nginx/html;     }

        location ~ \.php$ {         fastcgi_pass   php:9000;         fastcgi_index  index.php;         fastcgi_param  SCRIPT_FILENAME  /www/phptest/$fastcgi_script_name;      # php搜索目录         include        fastcgi_params;     } }

     PS:这里要注意的是fastcgi_pass参数,默认配置为localhost:9000,但由于这里都使用的docker,我们已经事先为nginx容器link了php的容器,因此将localhost改为php。后面的fastcgi_param  SCRIPT_FILENAME同样要改成我们为php容器指定的项目目录/www/phptest。

    重启nginx

    docker restart nginx

    打开浏览器,搜索栏输入主机ip:7002,看到以下页面,表示nginx成功连接php:

     

    测试php与mysql是否成功连接、成功登陆

    重新编辑测试目录/home/ubuntu/nginx/www/phptest/下的index.php文件,内容如下:

    <?php $con = mysql_connect("mysql","root","123456"); $select_db = mysql_select_db('erp_database'); if (!$select_db) {     die("could not connect to the db:\n" .  mysql_error()); } //查询代码 $sql = "select * from ci_goods_img"; $res = mysql_query($sql); if (!$res) {     die("could get the res:\n" . mysql_error()); } while ($row = mysql_fetch_assoc($res)) {     print_r($row); } //查询代码 //关闭数据库连接 mysql_close($con); ?>

    再打开浏览器,输入ip:7002,如果网页显示一片空白,说明php容器和mysql能顺利连接、登陆、操作数据了。

    所有验证完毕,最后就是我们的目标搭建项目的运行,同样根据上面的流程,在/home/ubuntu/nginx/conf.d下面新建一个服务配置文件,内容如下:

    server {     listen       80;             # docker中的80端口映射到了实体主机的7001端口,可通过7001访问服务     server_name  localhost;

        location / {         root   /usr/share/nginx/html;             # erp项目文件目录         index  index.html index.htm index.php;         try_files $uri $uri/ /index.php?$query_string;

            if (!-e $request_filename){                 rewrite ^/(.*) /index.php last;         }     }

        error_page   500 502 503 504  /50x.html;     location = /50x.html {         root   /usr/share/nginx/html;     }

        location ~ \.php$ {         fastcgi_pass   php:9000;         fastcgi_index  index.php;         fastcgi_param  SCRIPT_FILENAME  /www/$fastcgi_script_name;       # erp项目文件目录         include        fastcgi_params;     } }

     标黄处是因为此次涉及到php中的页面跳转,需要添加这两处以顺利加载页面。

    根据erp安装说明,还需修改application\config\database.php文件相关配置:

    $db['default']['hostname'] = 'mysql'; $db['default']['username'] = 'root'; $db['default']['password'] = '123456'; $db['default']['database'] = 'erp_database';

    重启nginx,在浏览器中输入ip:7001,可以成功看到登陆界面:

    输入安装说明中给的账号密码,进入看到页面:

    如果没提示错误,说明系统跑成功了,大功告成。

    由于我的能力问题,可能有许多表述不充分及错误之处,欢迎大家在评论中指出。

    Processed: 0.019, SQL: 10