Docker 搭建 PHP 運行環境

1. 安裝 Docker、使用 PHP 官方鏡像運行 PHP 程序;

安裝 Docker

# rpm 包安裝
cd /usr/local/src
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm
yum install docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm

Docker 用戶組設置、加速器設置:

使用 PHP 官方鏡像運行 PHP 程序

# 拉取最新版本 PHP 鏡像
# 每個鏡像都是一個操作系統,每個操作系統可以根據自己的需求定製和修改
docker pull php

# 拉取特定版本的 PHP 鏡像(版本參考上方“版本信息”連接)
# alpine 爲精簡版本
docker pull php:7.4.5-cli-alpine3.10

# *刪除鏡像
docker rmi php:latest

# 交互式模式啓動容器,最後可加上起始命令
# php -m 顯示容器內 PHP 安裝的擴展
docker run -it --name myphp php:7.4.5-cli-alpine3.10 php -m

# 由於是交互式方式,容器沒有啓動出來
docker ps -a
# 刪除容器
docker rm myphp
# *刪除所有容器
docker rm $(docker ps -a)

# 把一個 PHP 程序放到容器裏去運行
# 首先創建 PHP 程序
cd /data/php
echo "<?php echo 'test docker';" > test.php

# 啓動容器,命名爲 runphp,把 /data/php 掛載到容器裏
# 加入 --rm,表示程序運行好,容器自動刪除,適用於容器運行臨時任務
docker run -it --name runphp --rm -v /data/php:/php php:7.4.5-cli-alpine3.10 \
php /php/test.php
# 輸出 test docker

2. Docker 多容器運行 PHP + fpm + Apache;

一些知識點

  • 爲什麼容器不能 docker run -d --name myphp php:xxx 後臺運行?運行後 docker ps 後什麼都沒有,其實沒有出錯,通過 docker logs myphp 查詢什麼錯誤日誌都沒有
  • 在 alpine 容器或者鏡像裏面的設置,它的後臺把 PHP 進程作爲 id 爲 1 的進程,一旦 PHP 進程結束,容器就會停止。和官方的 Redis 鏡像一樣,把 Redis 服務作爲 id 爲 1 的進程。一旦 Redis 停止,容器就消失了
# 交互式啓動,不跟任何命令
docker run -it --name myphp php:7.4.5-cli-alpine3.10
# 會進入 shell 窗口,就是一個 PHP 進程,作爲 id 爲 1 的元老進程
# 此時可以做一些操作,比如 echo 一些字符串,phpinfo() 等

PHP + fpm + Apache 聯合運行

## 2.1 拉取 fpm 鏡像(儘可能的使用基於 alpine 的鏡像)
docker pull php:7.4.5-fpm-alpine3.10
# 由於 fpm 是服務,可以後臺運行
docker run -d --rm --name fpm php:7.4.5-fpm-alpine3.10

## 2.2 單單 fpm 沒有用,還需要配置服務器,比如 Apache
# 參考:https://hub.docker.com/_/httpd
docker pull httpd:2.4.43-alpine

# 寫個 html 文件,掛載到容器中
echo "<html>hello world</html>" > index.html
# 把容器的 80 端口映射到宿主機的 8080
docker run -d -p 8080:80 --rm --name myweb -v \
/data/php/:/usr/local/apache2/htdocs/ httpd:2.4.43-alpine
# 訪問
curl localhost:8080
# 返回:<html>hello world</html>

## 2.3 聯合運行操作
# 2.3.1 首先需要修改配置文件
# 查看容器中是否有配置文件
docker exec -it myweb cat /usr/local/apache2/conf/httpd.conf
# 創建本地存放配置文件的目錄
mkdir -p /data/php/conf/
cd /data/php/conf/
# 把容器裏的配置文件拷貝到本地
docker cp myweb:/usr/local/apache2/conf/httpd.conf /data/php/conf/
# 修改配置文件
vim httpd.conf

# 做以下修改
# 把下面四行的 # 去掉
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

# 刪除以下內容
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
...
</Directory>

# 添加以下內容後,保存退出
<VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot "/usr/local/apache2/htdocs"
    ServerName localhost
    <Directory "/usr/local/apache2/htdocs">
     Options None
     Require all granted
    </Directory>
    ProxyRequests Off
    ProxyPassMatch ^/(.*\.php)$ fcgi://172.17.0.4:9000/php/$1
</VirtualHost>
# 添加結束
# ProxyPassMatch 的 ip 爲 172.17.0.4,下面會有說明
# /php:這是一個文件夾名,可以自己設定,在 fpm 容器是沒有的
# 可以把主機的 php 文件夾映射到 fpm 容器的 php 文件夾

# 2.3.2 設置網絡相關
# 查看網絡
docker network ls
# 檢查一下 bridge 網絡
docker network inspect bridge
# Containers 中 fpm 的 IPv4Address 爲 172.17.0.4,填入上面 ProxyPassMatch 相關
# 主機的 IPAM.Config.Gateway 爲 172.17.0.1(ifconfig 查看 docker0 也可以看到)
# 主機和容器都是可以互通的

# 啓動 fpm 的時候把 php 文件夾掛載到 fpm 容器中,因此 fpm 的啓動要修改
docker stop fpm
docker run -d --rm --name fpm \
-v /data/php/:/php \
php:7.4.5-fpm-alpine3.10

# 把新的 httpd 的配置文件映射到容器裏
docker stop myweb
docker run -d -p 8080:80 --name myweb -v /data/php:/usr/local/apache2/htdocs/  \
-v /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf \
httpd:2.4.43-alpine

# 訪問,返回 test docker,成功
curl localhost:8080/test.php

3. 使用 Docker-compose 編排 PHP + fpm + Apache;

之前是手工啓動和刪除容器,很不方便,所以需要使用 docker compose,一款編排工具

# Docker-compose 安裝
# -L:有些網站有多次跳轉,加入此參數隨着網站跳轉而跳轉
# -o:把下載內容輸出到指定路徑的文件
curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose

# 對下載的文件賦予可執行權限
sudo chmod +x /usr/local/bin/docker-compose

# 查看文件版本
docker-compose -v

Compose file 參考(Version 3):https://docs.docker.com/compose/compose-file/

# 創建一個“空的”文件夾,再創建默認的 docker-compose.yml 文件
mkdir -p /data/php/compose
touch /data/php/compose/docker-compose.yml

# 網絡參考:https://docs.docker.com/compose/networking/
# 注意:以下 192.158.0.x 都是子網
# 在 docker-compose.yml 中寫入以下內容
version: "3"
services:
  fpm:
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php/:/php
   networks:
      mywebnet:
       ipv4_address: 192.158.0.2
  
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8080:80
   volumes:
      - /data/php/:/usr/local/apache2/htdocs/  
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf 
   networks:
      mywebnet:
       ipv4_address: 192.158.0.3


networks:
  mywebnet:
     driver: bridge
     ipam:
       config: 
         - subnet: 192.158.0.0/16

# 寫入結束

# 修改 httpd 配置文件
vim /data/php/conf/httpd.conf
# 鎖定 ProxyPassMatch ^/(.*\.php)$ fcgi://172.17.0.4:9000/php/$1,修改 IP 爲
192.158.0.2

# 啓動 compose
cd /data/php/compose/
# 啓動
# 也可以指定一個名稱 -p php:docker-compose -p php -d
# 注意:如果之前創建了相同子網的網絡,要先刪掉之前的,否則衝突
# 如果指定了-p,那麼停止或刪除時也要 docker-compose -p php stop 
docker-compose up -d
# 顯示
Creating network "compose_mywebnet" with driver "bridge"
Creating fpm   ... done
Creating httpd ... done

# 關閉容器(一個)
docker-compose stop fpm
# 關閉容器(所有)
docker-compose stop
# 同理,刪除容器
docker-compose rm

# 查看網絡
docker network ls
# 返回
NETWORK ID          NAME                DRIVER              SCOPE
ab368b5af331        bridge              bridge              local
8e8d27f1d706        compose_mywebnet    bridge              local
...
# compose_mywebnet 就是 docker-compose 創建的網絡
# 刪掉所有沒有使用的網絡
docker network prune
# 刪除指定網絡
docker network rm compose_mywebnet

4. Docker 搭建 Nginx + PHP-fpm;

安裝 Nginx 鏡像,參考:https://hub.docker.com/_/nginx

# 下載(實際生產環境都可以使用 alpine 的操作系統)
docker pull nginx:1.17.10-alpine

# 基本配置:
# 默認網頁文件夾是 /usr/share/nginx/html
# 默認配置文件地址是 /etc/nginx/nginx.conf
# 如果沒有現成的配置文件,那麼可以先胡亂啓動下容器,然後拷貝到本地文件夾中
# 啓動
docker run --name nginx --rm -d nginx:1.17.10-alpine
# 拷貝
docker cp nginx:/etc/nginx/nginx.conf /data/php/conf

支持普通 HTML 訪問

docker run --name nginx -d --rm -v /data/php:/usr/share/nginx/html \
-p 8080:80 nginx:1.17.10-alpine

Nginx + fpm 配置

# 修改 nginx 配置
vim /data/php/conf/nginx.conf
# 修改爲以下內容
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

  #  include /etc/nginx/conf.d/*.conf;
  server{
    listen 80;
    location / {
    root  /usr/share/nginx/html;
     index  index.html index.htm index.php;
   }
   location ~ \.php$ {
        root /php;
        fastcgi_pass 192.138.0.2:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
  }

}

啓動

# 創建網絡
docker network create --driver=bridge --subnet=192.138.0.0/16 nginx_network

# fpm 啓動
# 不需要映射端口,Nginx 容器可以通過內網地址(bridge 橋接模式)訪問這個容器的 fpm 服務
# 調試的時候 -d 參數可以換成 -it 參數
docker run -d --rm --name fpm \
--network nginx_network --ip 192.138.0.2 \
-v /data/php:/php \
php:7.4.5-fpm-alpine3.10

# 啓動 Nginx(自動生成 ip)
docker run --name nginx -d --rm -v /data/php:/usr/share/nginx/html \
-v /data/php/conf/nginx.conf:/etc/nginx/nginx.conf \
--network nginx_network -p 8080:80 \
nginx:1.17.10-alpine

Docker-compose 啓動

# 清除沒用的網絡
docker network prune

# 之前使用過的子網 192.158.x.x 和 192.138.x.x,現在統一改爲 192.138.x.x
# 修改 httpd 配置文件
vim /data/php/conf/httpd.conf
# 鎖定 ProxyPassMatch ^/(.*\.php)$ fcgi://192.158.0.2:9000/php/$1,修改 IP 爲
192.138.0.2

# 修改 docker-compose 文件
vim /data/php/compose/docker-compose.yml
# 修改爲以下內容
version: "3"
services:
  fpm:
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php:/php
   networks:
      mywebnet:
       ipv4_address: 192.138.0.2
  
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8081:80
   volumes:
      - /data/php/:/usr/local/apache2/htdocs/  
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf 
   networks:
      mywebnet:
       ipv4_address: 192.138.0.3

  nginx:
   image: nginx:1.17.10-alpine
   container_name: nginx
   ports:
      - 8082:80
   volumes:
      - /data/php:/usr/share/nginx/html
      - /data/php/conf/nginx.conf:/etc/nginx/nginx.conf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.4

networks:
  mywebnet:
     driver: bridge
     ipam:
       config: 
         - subnet: 192.138.0.0/16

# 修改結束
# 啓動 
docker-compose up -d
# Apache 和 Nginx 都能訪問
curl localhost:8081/test.php
curl localhost:8082/test.php

此時結構如下
在這裏插入圖片描述

5. MySQL 容器;

5.1 創建 MySQL 容器;

參考:https://hub.docker.com/_/mysql/

# 拉取鏡像
docker pull mysql:8.0.20

# 簡單運行
# -e 設置環境變量
# MYSQL_ROOT_PASSWORD 是 root 的密碼
docker run --name mysql --rm \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=asdf -d mysql:8.0.20

# 連接測試
# 使用容器裏的客戶端完成
docker exec -it mysql mysql -u root -pasdf

5.2 MySQL 配置文件方式啓動、導入數據;

在實際開發的時候,肯定要使用配置文件對 MySQL 進行一些參數的優化,不使用配置文件肯定是不方便的

定位到 “Using a custom MySQL configuration file”:配置文件

  • 注意點 1:在 /etc/mysql/conf.d 目錄下也可以加入配置文件,後綴必須是 .cnf
  • 注意點 2:MySQL 5 和 8 版本的一個區別:在 8 版本中,沒有了 /etc/mysql/mysql.conf.d/mysqld.cnf 配置文件(5 版本里有),此配置文件裏的內容合併到了 /etc/mysql/my.cnf

定位到 “Where to Store Data”:數據存儲目錄

# 5.2.1 進入容器的命令行,查看容器裏的配置文件相關目錄
docker exec -it mysql bash
cd /etc/mysql/
ls

# 5.2.2 掛載相關文件
# 根據官網,配置文件在
/etc/mysql/my.cnf
# 數據目錄在
/var/lib/mysql
# 先創建一個文件夾 mysql,裏面包含幾個子文件夾 conf、 data
mkdir -p /data/php/mysql/conf
mkdir -p /data/php/mysql/data

# 創建配置文件(文件名隨便)
# 官方的 my.cnf 加載了conf.d 裏面的文件(!includedir /etc/mysql/conf.d/)
# 只要創建個帶有關鍵配置部分的配置文件,映射 conf.d 文件夾即可
# 在 conf 文件下,隨便創建個文件比如 abc.cnf
touch /data/php/mysql/conf/abc.cnf

# 寫入以下內容(一些基礎配置)
[mysqld]
# 服務 id 唯一(用於主從同步)
server-id = 1 
port = 3306
# 必須是容器裏有的目錄
log-error	= /tmp/error.log
# 只能用IP地址
skip_name_resolve 
# 數據庫默認字符集
character-set-server = utf8mb4
# 數據庫字符集對應一些排序等規則 
collation-server = utf8mb4_general_ci
# 設置 client 連接 mysql 時的字符集,防止亂碼
init_connect='SET NAMES utf8mb4'
# 最大連接數
max_connections=300
# default_authentication_plugin=mysql_native_password

# 寫入完畢

# 5.2.3 啓動掛載目錄
# 先停止容器
docker stop mysql && docker rm mysql
docker run --name mysql --rm \
-v /data/php/mysql/conf:/etc/mysql/conf.d \
-v /data/php/mysql/data:/var/lib/mysql \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=asdf \
-d mysql:8.0.20

# 端口設置
sudo iptables -I INPUT -p tcp --dport 3307 -j ACCEPT

# 測試配置
show variables like 'max_connections'

# 注意!MySQL 8 版本,客戶端連接出現如下報錯解決方式
# ERROR 1045 (28000): Plugin caching_sha2_password could not be loaded: 
# Error loading shared library /usr/lib/mariadb/plugin/caching_sha2_password.so
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'asdf';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'asdf';

導入數據

# 數據準備
vim /data/php/mysql/test.sql
# 內容如下
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(50) NOT NULL,
  `user_qq` varchar(50) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'hualaoshuan', 'asdf');
INSERT INTO `users` VALUES ('2', 'zhangsan', '123456');

# 內容結束

# 拷貝
docker cp /data/php/mysql/test.sql mysql:/tmp

# 進入容器客戶端
docker exec -it mysql mysql -uroot -pasdf
# 導入
mysql> create database test;
mysql> use test;
mysql> source /tmp/test.sql;

5.3 微容器 alpine 之構建基礎鏡像、安裝 MySQL 客戶端;

下載最基礎的 alpine 鏡像:https://hub.docker.com/_/alpine/

# 下載
docker pull alpine:3.11

# 使用 Dockerfile 構建鏡像
# 鏈接:https://hub.docker.com/_/alpine/,鎖定關鍵詞:How to use this image
# 以下爲示例
FROM alpine:3.7
# apk add,類似於 apt-get 和 yum
# 從鏡像庫下載 mysql-client 客戶端
# --no-cache:從遠程直接下載,不使用本地鏡像庫
RUN apk add --no-cache mysql-client
# ENTRYPOINT:啓動容器的時候執行的命令
# mysql:下載下來後的可執行程序,會主動連接本地的 MySQL Server
ENTRYPOINT ["mysql"]
# 示例結束

# 演示
# 創建 Dockerfile 相關文件夾
mkdir -p /data/php/mydocker
vim Dockerfile
# 寫入如下內容
FROM alpine:3.11
RUN apk add --no-cache mysql-client
ENTRYPOINT ["mysql"]
# 寫入結束

# 構建新鏡像
cd /data/php/mydocker
docker build -t mytool:1.0 .

# 測試運行
docker run -it --name tmp --rm mytool:1.0
# 執行會報錯,因爲容器啓動時默認執行的命令是 mysql
# 如果沒任何參數,代表連接它自己本地的 mysql,本地沒有 mysql,所以報錯

# 正確啓動( -it 交互式,直接進入客戶端)
docker run -it --name tmp mytool:1.0 mysql -h 192.168.2.214 -uroot -pasdf

# 注意點
# alpine 使用的是 apk 包管理器命令,如 apk add 、apk update 、apk del
# 默認鏡像源可能比較慢,常用的有 
# 中科大鏡像源:http://mirrors.ustc.edu.cn/alpine/
# 阿里雲鏡像源:http://mirrors.aliyun.com/alpine/

修改數據源

# 查看源文件
docker start tmp
docker exec -it tmp cat /etc/apk/repositories

# 修改方法 1:手動加入阿里鏡像源
docker exec -it tmp sh -c \
"echo \"http://mirrors.aliyun.com/alpine/v3.11/main/\" > /etc/apk/repositories"
docker exec -it tmp sh -c \
"echo \"http://mirrors.aliyun.com/alpine/v3.11/community/\" >> /etc/apk/repositories"
# 設置好後,執行
apk update && apk upgrade

# (推薦)修改方法 2:重新修改 Dockerfile
# 修改內容如下
FROM alpine:3.11
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.11/main > /etc/apk/repositories
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.11/community >> /etc/apk/repositories
RUN apk update && apk upgrade
RUN apk add mysql-client
ENTRYPOINT ["mysql"]

# 重新構造鏡像
docker build -t mytool:1.0 .

# 測試運行
docker run -it --name mysqlclient --rm mytool:1.0 \
mysql -h 192.168.2.214 -uroot -P3307 -pasdf

5.4 製作 MySQL 備份專用鏡像;

5.4.1 動態參數;

數據庫備份命令

mysqldump -u用戶名 -p密碼 數據庫名 > 導出的文件名

# 舉例
mysqldump -h192.168.2.214 -uroot -P3307 -pasdf test > test.sql
# 然後把 test.sql 專門生成在一個文件夾中
# 可以使用掛載的方式生成到本地物理機上

基於之前的 mytool:1.0 鏡像

# 新 Dockerfile 編寫
cd /data/php/mydocker
vim Dockerfile
# 修改爲以下內容
FROM mytool:1.0
RUN mkdir /data
ENTRYPOINT mysqldump -h192.168.2.214 -uroot -P3307 -pasdf test > /data/test.sql
# 編寫完畢
# 註釋:這裏的 ENTRYPOINT 可以覆蓋上一次的
# ENTRYPOINT 後有“[]”  基於參數,相當於直接運行可執行文件
# 沒有 “[]” 相當於在內部啓動了一個 shell 進程:sh -c "xxxx",適用於命令比較複雜的情況

# 編譯鏡像
docker build -t mytool:1.1 .

# 掛載執行
mkdir -p /data/php/mysql/mysqlbak
docker run -it --name bakup --rm -v /data/php/mysql/mysqlbak:/data mytool:1.1

# 優化 Dockerfile
FROM mytool:1.1
ENV mysql_user root
ENV mysql_pass asdf
ENV mysql_host 192.168.2.214
ENV mysql_port 3307
ENV mysql_db test
ENTRYPOINT mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_pass $mysql_db > /data/$mysql_db.sql
# 優化結束

# 編譯
docker build -t mytool:1.2 .
 
# 運行,備份本機數據庫(3306)數據
docker run -it --name bakup --rm \
-v /data/php/mysql/mysqlbak:/data \
-e mysql_pass=asdf \
-e mysql_host=192.168.2.214 \
-e mysql_port=3306 \
-e mysql_db=test \
-e mysql_user=root \
mytool:1.2

6. ThinkPHP5 + Docker 運行;

6.1 結合 Apache 運行;

準備工作

# 下載 thinkphp:http://www.thinkphp.cn/down.html
# 創建相關目錄
# 放程序文件
mkdir -p /data/php/tp5/web/
# 放 docker-compose.yml(compose)
mkdir -p /data/php/tp5/compose/

# 下載後解壓解壓
unzip thinkphp_5.0.24_with_extend.zip -d /data/php/tp5/web/

設置網站目錄
在這裏插入圖片描述
實際操作

# 6.1.1 刪除沒用的網絡
docker network prune

# 6.1.2 修改要掛載的 Apache 配置文件
vim /data/php/conf/httpd.conf
# 修改 <VirtualHost *:80> 標籤裏的 ProxyPassMatch 爲如下內容
ProxyPassMatch ^/(.*\.php)$ fcgi://192.138.0.2:9000/php/public/$
# 修改完畢後保存退出

# 6.1.3 創建 dock-compose
cd /data/php/tp5/compose
vim docker-compose.yml
# 寫入以下內容
version: "3"
services:
  fpm:
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php/tp5/web:/php
   networks:
      mywebnet:
       ipv4_address: 192.138.0.2
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8081:80
   volumes:
      - /data/php/tp5/web/public:/usr/local/apache2/htdocs/
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.3


networks:
  mywebnet:
     driver: bridge
     ipam:
       config:
         - subnet: 192.138.0.0/16

# 寫入完畢,運行
docker-compose up -d

# 訪問
curl http://192.168.2.214:8081/index.php

6.2 配置 Samba 共享;

參考鏡像: https://hub.docker.com/r/dperson/samba

# 下載鏡像
docker pull dperson/samba

# 開放相關端口
iptables -I INPUT -p tcp --dport 139 -j ACCEPT
iptables -I INPUT -p tcp --dport 445 -j ACCEPT

iptables -I INPUT -p udp --dport 137 -j ACCEPT
iptables -I INPUT -p udp --dport 138 -j ACCEPT

# 測試運行
docker run -it -p 139:139 -p 445:445 --name smb -d --rm  \
 -v /data/php/tp5/web:/mount \
 dperson/samba \
 -u "root;asdf" \
 -s "root;/mount/;yes;no;yes;all;all;all" \
 -w "WORKGROUP" 

## 相關調試
# 進入容器
docker exec -it smb sh

# 查看進程
ps -ef | grep samb

# 進入掛載目錄,裏面的內容和主機的文件是同步的
cd /mount

# samba 配置
cd /etc/samba

# 重新配置
docker stop smb
# 完整運行(注意下面的 root 是開發機的當前用戶)
docker run -it -p 139:139 -p 445:445  --name smb -d --rm  \
 -v /data/php/tp5/web:/mount \
 dperson/samba \
 -u "root;asdf" \
 -s "hua;/mount/;yes;no;yes;all;all;all" \
 -w "WORKGROUP" \
 -g "force user= root" \
 -g "guest account= root" 

6.3 添加控制器、url 重寫;

開啓 Apache 重寫

# 編輯配置文件
vim /data/php/conf/httpd.conf

# 修改以下內容
# 以下配置前的 “#” 去掉
LoadModule rewrite_module modules/mod_rewrite.so
# <VirtualHost *:80> - <Directory> 標籤內加入
AllowOverride all
#  ProxyPassMatch 修改爲以下
ProxyPassMatch ^/(.*\.php) fcgi://192.138.0.2:9000/php/public/$1

# 重新構建容器
docker-compose restart

# 修改 /web/application/index/controller/Index.php
# 追加方法
public function test() {}
# 訪問:http://192.168.2.214:8081/index/index/test

6.4 連接數據庫、添加 PHP 擴展;

Docker-compose 編排 MySQL

# 暫停刪除之前的 MySQL 容器
docker stop mysql

# 修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# 修改爲以下內容
version: "3"
services:
  fpm:
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php/tp5/web:/php
   networks:
      mywebnet:
       ipv4_address: 192.138.0.2
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8081:80
   volumes:
      - /data/php/tp5/web/public:/usr/local/apache2/htdocs/
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.3

  mysql:
   image: mysql:8.0.20
   container_name: mysqld
   ports:
     - 3307:3306
   volumes:
     - /data/php/mysql/conf:/etc/mysql/conf.d
     - /data/php/mysql/data:/var/lib/mysql
   environment:
     - MYSQL_ROOT_PASSWORD=asdf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.4

networks:
  mywebnet:
     driver: bridge
     ipam:
       config:
         - subnet: 192.138.0.0/16

# 修改結束

# 運行(追加創建 mysql 容器)
docker-compose up -d mysql

啓動容器後情況如下

  • 可以用數據庫客戶端軟件,連接映射端口的主機地址 192.168.2.214:3307

在這裏插入圖片描述

配置數據庫連接

# 數據庫連接配置
# 可以填主機地址 192.168.2.214:3307
# 但是一般填寫的是 Docker 虛擬出來的 ip
# 查看 Docker 網絡
docker network ls
docker network inspect compose_mywebnet

# 修改 /web/application/database.php
# 修改以下內容
return [
    // 數據庫類型
    'type'            => 'mysql',
    // 服務器地址(Docker 虛擬的 ip)
    'hostname'        => '192.138.0.4',
    // 數據庫名
    'database'        => 'test',
    // 用戶名
    'username'        => 'root',
    // 密碼
    'password'        => 'asdf',
    // 端口
    'hostport'        => '3306'
]

# 打開調試:修改 /web/application/config.php
return [
    // 應用調試模式
    'app_debug'              => true,
];

# 定義模型,參考:https://www.kancloud.cn/manual/thinkphp5/135187
# 創建 /web/application/index/model/UserModel.php
# 寫入以下內容
<?php

namespace app\index\model;

use think\Model;

class UserModel extends Model
{
    protected $table = 'users';
}

# 創建 /web/application/index/controller/UserIndex.php
# 寫入以下內容
<?php

namespace app\index\controller;

use app\index\model\UserModel;

class UserIndex
{
    public function index()
    {
        $users = UserModel::all();
        var_dump($users);

        return "this is userIndex";
    }
}

# 返回:could not find driver
# 因爲默認的 PHP–FPM 容器沒有 PDO_MYSQL 擴展

添加 PHP 擴展

# 進入 PHP–FPM 容器
docker exec -it fpm sh
# 查看 PHP 擴展
php -m
# 沒有 pdo_mysql 擴展,需要安裝
# 文檔:https://github.com/docker-library/docs/blob/master/php/README.md#php-core-extensions
# 以上是核心安裝庫
# 如果需要安裝 swoole 等,查閱 PECL extensions,也可以手工安裝
# pdo_mysql 是屬於核心擴展,只需要執行 docker-php-ext-install(官方鏡像的腳本)

# 安裝前需要修改下 alpine 的鏡像源,否則下載速度太慢
# 查看鏡像源版本
cat /etc/issue
# 查看鏡像源設置文件
cat /etc/apk/repositories
# 返回
http://dl-cdn.alpinelinux.org/alpine/v3.10/main
http://dl-cdn.alpinelinux.org/alpine/v3.10/community
# 把官方鏡像源替換成阿里雲鏡像源(注意對應的版本號要準確)
echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories && \ 
echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
# 更新配置
apk update && apk upgrade

# 安裝擴展
docker-php-ext-install pdo_mysql

# 重啓容器
cd /data/php/tp5/compose
docker-compose restart fpm

# 再訪問
curl http://192.168.2.214:8081/index/user_index/index

持久化

# 剛纔的操作是在容器裏臨時完成的,一旦容器刪除了,所有之前的操作就沒有了
docker-compose stop fpm
docker-compose rm fpm
docker-compose up -d fpm
# 解決方案,兩種方法:
# 1. 再次創建 Dockerfile, 構建一個新鏡像
# 那要是下次還有內容修改呢?一直不斷的構建會很麻煩

# (推薦)2. 在 docker-compose 文件中進行構建
# 一旦有新內容,不會臨時到外部進行構建的,而是直接在 docker-compose 下面執行
# 1) 在當前文件夾下創建一個子文件夾 叫做 build
# 2) 在 build 裏面新建一個 Dockerfile 文件,注意文件名,比如叫做 phpfpm
mkdir -p /data/php/tp5/compose/build/
cd /data/php/tp5/compose/build/
# 創建 Dockerfile
vim phpfpm

# 寫入如下內容
FROM php:7.4.5-fpm-alpine3.10
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories && \
  echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
RUN apk update && apk upgrade
RUN docker-php-ext-install pdo_mysql
# 寫入結束

# 修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# 修改如下(添加了 services - fpm - build 內容)
version: "3"
services:
  fpm:
   build: 
    context: ./build
    dockerfile: phpfpm
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php/tp5/web:/php
   networks:
      mywebnet:
       ipv4_address: 192.138.0.2
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8081:80
   volumes:
      - /data/php/tp5/web/public:/usr/local/apache2/htdocs/
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.3

  mysql:
   image: mysql:8.0.20
   container_name: mysqld
   ports:
     - 3307:3306
   volumes:
     - /data/php/mysql/conf:/etc/mysql/conf.d
     - /data/php/mysql/data:/var/lib/mysql
   environment:
     - MYSQL_ROOT_PASSWORD=asdf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.4

networks:
  mywebnet:
     driver: bridge
     ipam:
       config:
         - subnet: 192.138.0.0/16

# 修改結束

# 重構
docker-compose build fpm
# 完成後顯示
Successfully built 3343fec11dd6
Successfully tagged php:7.4.5-fpm-alpine3.10
# 新構築了一個鏡像並打上標籤,原來的鏡像廢棄
# 停掉原來的 fpm 容器
docker-compose stop fpm 
docker-compose rm fpm 

# 創建新容器
docker-compose up -d fpm

6.5 添加 Redis 擴展;

安裝 Redis,參考:https://hub.docker.com/_/redis/

# 獲取鏡像
docker pull redis:6.0.1-alpine

# 配置文件
# 實例,有各個版本的配置文件:https://redis.io/topics/config
mkdir -p /data/php/tp5/conf
vim redis.conf
## 寫入以下內容
bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300

# 容器方式直接 no
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo yes

save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
# 容器裏的工作目錄
dir /data

slave-serve-stale-data yes
slave-read-only yes

repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no

slave-priority 100

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no

appendonly no

appendfilename "appendonly.aof"

appendfsync everysec
no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

aof-load-truncated yes
aof-use-rdb-preamble no

lua-time-limit 5000

slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing yes

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

aof-rewrite-incremental-fsync yes

## 寫入完畢

# 修改 docker-compose.yml
vim /data/php/tp5/compose/
# 添加 redis 部分配置,如下
version: "3"
services:
  fpm:
   build: 
    context: ./build
    dockerfile: phpfpm
   image: php:7.4.5-fpm-alpine3.10
   container_name: fpm
   volumes:
      - /data/php/tp5/web:/php
   networks:
      mywebnet:
       ipv4_address: 192.138.0.2
  httpd:
   image: httpd:2.4.43-alpine
   container_name: httpd
   ports:
      - 8081:80
   volumes:
      - /data/php/tp5/web/public:/usr/local/apache2/htdocs/
      - /data/php/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.3

  mysql:
   image: mysql:8.0.20
   container_name: mysqld
   ports:
     - 3307:3306
   volumes:
     - /data/php/mysql/conf:/etc/mysql/conf.d
     - /data/php/mysql/data:/var/lib/mysql
   environment:
     - MYSQL_ROOT_PASSWORD=asdf
   networks:
      mywebnet:
       ipv4_address: 192.138.0.4

  redis:
   image: redis:6.0.1-alpine
   container_name: redis
   ports:
     - 6389:6379
   volumes:
     - /data/php/tp5/conf/redis.conf:/usr/local/etc/redis/redis.conf
     - /data/php/tp5/redisdata:/data
   networks:
      mywebnet:
       ipv4_address: 192.138.0.10


networks:
  mywebnet:
     driver: bridge
     ipam:
       config:
         - subnet: 192.138.0.0/16

# 修改完畢

# 啓動
docker-compose up -d
# 進入容器內 redis
docker exec -it redis redis-cli -p 6379

在這裏插入圖片描述

添加 PHP 的 Redis 擴展

# Redis 擴展可以使用 pecl 來安裝
# 參考文檔:https://hub.docker.com/_/php/,鎖定 “PECL extensions”
# 在 build 目錄中 創建 phpredis 文件
vim /data/php/tp5/compose/build/phpredis
# 寫入以下內容
FROM php:7.4.5-fpm-alpine3.10
RUN apk add autoconf gcc g++ make
RUN pecl install redis-5.1.1 \
    && docker-php-ext-enable redis

# 寫入完畢,修改 docker-compose.yml
vim /data/php/tp5/compose/docker-compose.yml
# services - fpm - build - dockerfile 改成 phpredis

# 重構
docker-compose build fpm

# 完成後顯示
Successfully built d7ccf1769bc0
Successfully tagged php:7.4.5-fpm-alpine3.10
# 新構築了一個鏡像並打上標籤,原來的鏡像廢棄
# 停掉原來的 fpm 容器
docker-compose stop fpm 
docker-compose rm fpm 

# 創建新容器
docker-compose up -d fpm

代碼實現

# 參考:https://www.kancloud.cn/manual/thinkphp5/118131
# 修改 /web/application/config.php
'cache'                  => [
    // 驅動方式
    'type'   => 'redis',
    // 容器 ip
    'host'   => '192.138.0.10',
    'port'   => '6379',
    // 緩存保存目錄
    // 'path'   => CACHE_PATH,
    // 緩存前綴
    'prefix' => '',
    // 緩存有效期 0表示永久緩存
    'expire' => 0,
],

# 修改 /web/application/index/controller/UserIndex.php
<?php

namespace app\index\controller;

use app\index\model\UserModel;
use think\Cache;

class UserIndex
{
    public function index()
    {
        //$users = UserModel::all();
        Cache::set("user", "testuser");
        $users = Cache::get("user");
        print_r($users);

        return "this is userIndex";
    }
}

6.6 上傳文件、alpine 環境下的權限問題;

模板設置:https://www.kancloud.cn/manual/thinkphp5/119298

  • 出現的問題
## 問題 1:mkdir(): Permission denied
# 之前是通過“掛載”的方式掛載到容器裏,如果 /web/runtime 裏沒有緩存文件夾,就會出現上述錯誤
# 這個問題和物理機裏的權限是沒有關係的

# 查看物理機用戶
cat /etc/passwd
# 返回,得到用戶組爲 1000,是映射到容器裏的
# 但是這個 1000 在 fpm 裏是沒有的
hualaoshuan:x:1000:1000:hualaoshuan:/home/hualaoshuan:/bin/bash

# 進入容器
docker exec -it fpm sh
# 進入到掛載的目錄
cd /php
ls -l
# 目錄的用戶:羣組分別是 1000:1000
# 這個 1000 就是指物理機用戶

# 查看 php 進程,php-fpm 所有者是 www-data
ps -ef | grep php
# 返回
1 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
6 www-data  0:00 php-fpm: pool www

# 查看所有用戶
cat /etc/passwd 
# 返回
.
www-data:x:82:82:Linux User,,,:/home/www-data:/sbin/nologin

# 解決方案:把 www-data 的用戶和羣組改爲物理機用戶的羣組
# www-data 是 php-fpm 啓動的默認用戶名
# 但是 alpine 沒有 usermod 命令
# 參考:https://pkgs.alpinelinux.org/contents?file=usermod&path=&name=&branch=&repo=&arch=
# alpine < 3.4,在數據源中加入
echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
apk --no-cache add shadow
# alpine > 3.4
apk add shadow

# 修改用戶 www-data 的用戶以及羣組 ID 爲 1000
usermod -u 1000 www-data
groupmod -g 1000 www-data

# 退出容器,重啓容器
docker-compose restart fpm
  • 創建:/web/application/index/controller/Upload.php
<?php
// 訪問:http://192.168.2.214:8081/index/upload/
namespace app\index\controller;

use think\Controller;

class Upload extends Controller
{

    public function index()
    {
        return $this->fetch("up");
    }

	public function up()
	{
	// https://www.kancloud.cn/manual/thinkphp5/155159
	}
}
  • 創建:/web/application/index/view/upload/up.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="/index/user_index/up">
    上傳文件:
    <hr/>
    <input type="file" name="myfile"/>
    <hr/>
    <input type="submit" value="上傳"/>

</form>
</body>
</html>

7. Laravel + Docker 運行;

7.1 Composer 鏡像使用;

# 拉取鏡像
docker pull composer
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章