Docker 火了这么多年,我也要学习体验一下。就在阿里云的服务器上部署一个 Nginx+MariaDB+PHP 环境吧。
安装
不同系统的安装方法见官方文档,包括了 Linux 的几个发行版和 Windows、MacOS 的详细步骤。我在 Linux 系统上安装。装完记得运行systemctl enable docker
把 docker 调成自动启动。
Docker Hub
Docker 的各种 images 会发布在 Docker Hub,要善用这个网站来搜索想要的资源。
网络
在创建 docker 容器(container)之前,先考虑一下网络的架构。我打算创建 3 个容器:nginx、mariadb、php,其中,需要暴露的端口只有 nginx 容器的 80 (443) 端口。根据这篇文档中的:
User-defined bridge networks are best when you need multiple containers to communicate on the same Docker host.
我应该选择 bridge 网络,bridge 的具体的使用见此文档。在宿主机上运行
docker network create --driver bridge my_bridge
创建一个名称为 my_bridge 的bridge。
Nginx
先把 Nginx image 拉下来:docker pull nginx
,默认会拉 latest 这个 tag (tags 可以在 Docker Hub 先搜索 nginx 然后点进去找到)。
接下来创建容器:
docker run --name my_nginx --network my_bridge -p 80:80 -v /var/www/php_env:/usr/share/nginx/html -e TZ="Asia/Shanghai" -d --restart always nginx
参数解释:(详情见文档)
--name my_nginx 容器命名为my_nginx --network my_bridge 连接到my_bridge网络 -p 80:80 把容器的80端口(后)暴露为宿主机的80端口(前) -v /var/www/php_env:/usr/share/nginx/html 把宿主机的目录(前)mount到容器的指定路径 -e TZ="Asia/Shanghai" 设置环境变量 -d 在后台运行 --restart always 自动启动、重启 nginx image名称
如无意外,浏览器可以访问http://服务器IP
的网页了。
PHP
pull image:docker pull php:7.4.3-fpm
看别人的教程,都是用 -fpm 的 PHP,我这里选择目前最新版本的 7.4.3-fpm。
创建容器:
docker run --name my_php --network my_bridge -v /var/www/php_env:/var/www/html -d --restart always php:7.4.3-fpm
参数解释:
--name my_php 容器命名 --network my_bridge 连接到my_bridge网络 -v /var/www/php_env:/var/www/html 把宿主机的目录(前)mount到容器的指定路径 -d 在后台运行 --restart always 自动启动、重启 php:7.4.3-fpm image与tag
然后配置 Nginx,让Nginx 可以识别 .php 脚本。首先进入 my_nginx 的容器:
docker exec -i -t my_nginx bash
执行之后可以发现,终端里显示的机器变了,例如变成root@40f3a8c8ae81:/#
开头,证明已经进入了这个容器。接下来
cd /etc/nginx/conf.d 尝试修改 default.conf,然而竟然没有编辑器,我们马上安装一个 apt-get update apt-get install nano # 或者你喜欢vim nano default.conf
打开 default.conf 之后,修改 index 相关的一处和 php 相关的一段:
location / { root /usr/share/nginx/html; # my_nginx容器的路径 index index.php index.html index.htm; # 添加index.php } location ~ \.php$ { root /var/www/html; # my_php容器的路径 fastcgi_pass my_php:9000; # 使用my_php的名称来指定远程机器 fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME document_root$fastcgi_script_name; include fastcgi_params; }
保存文件,service nginx reload
使配置生效,exit
回到宿主机,运行docker restart my_nginx
随手再重启一下容器。
宿主机切换到/var/www/php_env
目录,创建一个xxxxxxxx.php
,里面写
<?php echo phpinfo(); ?>
赶紧去浏览器试一下http://服务器IP/xxxxxxxx.php
吧。
(备注:在我后来的使用过程中,我遇到了一些文件权限的问题,例如我的 php 应用缺少文件写入权限,即写入不了宿主机的/var/www/php_env/*
,稍微找了一下资料,最科学的做法应该是手动指定容器运行的用户的。我比较懒,ps -ef | grep php
看到 php-fpm 是由 UID=33 的用户运行的,然后我chown -R 33:33 /var/www/php_env
暂时解决了。这里应该作为未来改进的地方)
MariaDB
docker pull mariadb docker run --name my_mariadb --network my_bridge --restart always -e MYSQL_ROOT_PASSWORD=123456 -d mariadb
参数解释:
--name my_mariadb 容器命名 --network my_bridge 连接到my_bridge网络 --restart always 自动启动、重启 -e MYSQL_ROOT_PASSWORD=123456 设置环境变量 -d 在后台运行 mariadb image
启动容器之后,docker exec -i -t my_mariadb bash
进入容器,mysql -u root -p
然后输入密码(刚才设定的123456),就可以连入 MariaDB 了。
视乎具体的应用,可能还需要使用docker-php-ext-install
安装一些 PHP 的扩展。
使用时,数据库的主机(host)应填my_mariadb
。由于一开始只有一个 root 用户,可能需要做一些权限配置。
总结
我们先创建了 1 个网络,然后是 3 个容器,它们都在同一个网络中,可以自由地互相通信,并且只暴露一个 80 端口到外部。运行docker ps
的输出大概是这样的:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ade1d8dc3c88 mariadb "docker-entrypoint.s…" 30 minutes ago Up 2 minutes 3306/tcp my_mariadb dc089caca7bd php:7.4.3-fpm "docker-php-entrypoi…" 14 hours ago Up 2 minutes 9000/tcp my_php 3704c48d500b nginx "nginx -g 'daemon of…" 15 hours ago Up 2 minutes 0.0.0.0:80->80/tcp my_nginx
一些参考
- https://www.runoob.com/docker/docker-container-usage.html
- https://www.cnblogs.com/Felix-DoubleKing/p/11583673.html
更新 docker-compose
为了更好地管理这些容器,学习使用 docker-compose,重新实现了上述的操作。感受到 docker-compose 的内在精神和写代码的“动静分离”是有点像的,即不变的逻辑可以写死,可变的输入成为参数或配置文件,这样可以灵活地用不同的参数来调用业务逻辑。下面为 docker-compose.yml:
version: "3.8" services: web: image: nginx restart: always ports: - 443:443 - 80:80 environment: TZ: Asia/Shanghai volumes: - ./nginx_default.conf:/etc/nginx/conf.d/default.conf - /path/to/certs:/etc/nginx/certs - /var/www/php_env:/usr/share/nginx/html php: build: context: . dockerfile: Dockerfile.php-fpm.txt restart: always volumes: - /var/www/php_env:/var/www/html db: image: mariadb:10.4 restart: always environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - ./mariadb_my.cnf:/etc/mysql/my.cnf - ./mariadb_data:/var/lib/mysql
其中 php 用到的 Dockerfile:
FROM php:7.4.7-fpm RUN apt-get update && \ apt-get install -y libzip-dev && \ apt-get install -y libmagickwand-dev --no-install-recommends && \ rm -rf /var/lib/apt/lists/* RUN docker-php-ext-install -j$(nproc) bcmath calendar exif gettext sockets dba mysqli pcntl pdo_mysql shmop sysvmsg sysvsem sysvshm iconv zip RUN printf "\n" | pecl install imagick RUN docker-php-ext-enable imagick
发表评论