1 了解官方php鏡像
Dockerhub 上 PHP 官方基礎鏡像主要分為三個分支:
-
cli
: 沒有開啟 CGI 也就是說不能運行fpm。只可以運行命令行。 -
fpm
: 開啟了CGI,可以用來運行web服務也可以用來運行cli命令。 -
zts
: 開啟了線程安全的版本。
選擇什么分支的鏡像?
一般在生成環境會使用到 php-fpm
。先了解一下什么是php-fpm?
-
由於nginx本身不能處理PHP,它只是個web服務器,當接收到請求后,如果是php請求,則發給php解釋器處理,並把結果返回給客戶端;
-
nginx 一般是把請求發fastcgi管理進程處理,fascgi管理進程選擇 CGI 子進程處理結果並返回被 nginx ;
-
PHP-FPM 是一個PHP FastCGI管理器,旨在將FastCGI進程管理整合進PHP包中;
-
PHP-FPM提供了更好的PHP進程管理方式,可以有效控制內存和進程、可以平滑重載PHP配置,比spawn-fcgi具有更多優點,所以被PHP官方收錄了。
所以,LNMP架構的一般會選擇 fpm
分支的鏡像。
2 需求分析和鏡像選擇
鏡像選擇
首先是基礎鏡像版本的選擇,我這里選擇的是 php:7.2.34-fpm-alpine
鏡像。php 版本為 7.2.34
(php版本需要結合具體業務代碼進行選擇),這個官方鏡像基於alpine 鏡像進行構建,alpine鏡像體積非常小 ,大小只有5m左右。
需求分析
對於php應用來說,都需要自己額外安裝一些擴展。官方基礎鏡像的擴展一般滿足不我們的需求,所以需要看看官方鏡像有哪些擴展,然后再按需安裝我們要的擴展。
查看官方基礎鏡像有什么擴展:
[root@harbor harbor]# docker run php:7.2.34-fpm-alpine php -m
[PHP Modules]
Core
ctype
curl
date
dom
fileinfo
filter
ftp
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
[Zend Modules]
安裝經驗,一般需要額外安裝的擴展:
redis
:redis是目前主流的Nosql數據庫,常用。zip
:文件壓縮擴展。gd
:圖片處理擴展,一些圖形驗證碼的生成不能沒有這個擴展。bcmath
:沒有這個庫的話可能一些框架或者類庫的composer
依賴校驗會無法通過。pdo_mysql
:連接數據庫擴展。opcache
: 是 PHP 中的 Zend 擴展,可以大大提升 PHP 的性能。swoole
:一個PHP高級Web開發框架,可按需添加。
除了擴展之外,還可以安裝一個php的包管理工具 composer
。composer
是PHP的包管理、包依賴關系管理工具,有了它,我們就很輕松一個命令就可以把他人優秀的代碼用到我們的項目中來,而且很容易管理依賴關系,更新刪除等操作也很輕易的實現。
3 構建准備
- 創建工程目錄
[root@harbor ~]# mkdir lnmp/php -p
[root@harbor ~]# cd lnmp/php/
- 准備
composer
包,放在工程目錄下,下載鏈接:https://github.com/composer/composer/releases
[root@harbor php]# wget https://github.com/composer/composer/releases/download/2.0.13/composer.phar
- 准備
date.ini
文件,設置PHP默認時區為東八區:
[root@harbor php]# mkdir conf.d
[root@harbor php]# echo "date.timezone = Asia/Shanghai" > conf.d/date.ini
- 准備
opcode.ini
文件,用於設置opcode默認的參數,並且設置環境變量OPCODE
以控制其是否被開啟。當環境變量OPCODE的值被設置為1的時候表示開啟opcode,0則關閉。
# 這里加 \EOF 是防止${OPCODE}被轉義
[root@harbor php]# cat >> conf.d/opcode.ini << \EOF
> opcache.enable=${OPCODE}
> enable_clopcache.enable_cli=1
> opcache.revalidate_freq=60
> opcache.max_accelerated_files=100000
> opcache.validate_timestamps=1
> EOF
- 准備
php-fpm.conf
文件
[root@harbor php]# cat www.conf
[www]
user = www
group = www
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 100
pm.start_servers = 30
pm.min_spare_servers = 20
pm.max_spare_servers = 50
准備工作完成,接下來創建Dockerfile進行構建。
4 創建Dockerfile
[root@harbor php]# touch Dockerfile
Dockerfile文件內容如下:
FROM php:7.2.34-fpm-alpine
LABEL MAINTAINER="syushin moliyoyoyo@163.com"
ENV TZ "Asia/Shanghai"
ENV TERM xterm
# 默認關閉opcode
ENV OPCODE 0
COPY ./conf.d/ $PHP_INI_DIR/conf.d/
COPY composer.phar /usr/local/bin/composer
COPY www.conf /usr/local/etc/php-fpm.d/www.conf
# 創建www用戶
RUN addgroup -g 1000 -S www && adduser -s /sbin/nologin -S -D -u 1000 -G www www
# 配置阿里雲鏡像源,加快構建速度
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories
# PHPIZE_DEPS 包含 gcc g++ 等編譯輔助類庫,完成編譯后刪除
RUN apk add --no-cache $PHPIZE_DEPS \
&& apk add --no-cache libstdc++ libzip-dev vim\
&& apk update \
&& pecl install redis-5.3.4 \
&& pecl install zip \
&& pecl install swoole \
&& docker-php-ext-enable redis zip swoole\
&& apk del $PHPIZE_DEPS
# docker-php-ext-install 指令已經包含編譯輔助類庫的刪除邏輯
RUN apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev \
&& apk update \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install -j$(nproc) pdo_mysql \
&& docker-php-ext-install -j$(nproc) opcache \
&& docker-php-ext-install -j$(nproc) bcmath \
&& docker-php-ext-install -j$(nproc) mysqli \
&& chmod +x /usr/local/bin/composer
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
EXPOSE 9000
ENTRYPOINT ["php-fpm"]
說明:
PHP_INI_DIR
: 這個環境變量的定義在php基礎鏡像的Dockerfile有定義,變量值是/usr/local/etc/php
PHPIZE_DEPS
:這個也是定義在基礎鏡像Dockerfile中,包含了擴展編譯安裝時需要但是php運行不需要的linux軟件庫。我們需要把它們挑選出來,在編譯完擴展之后刪除。變量值:autoconf dpkg-dev dpkg
php-fpm.conf
配置文件在/usr/local/etc/
目錄下www.conf
配置文件在/usr/local/etc/php-fpm.d
目錄下
可以編寫一個腳本進行構建,好處是以后可以通過查看腳本知道哪個標簽的鏡像是此次構建的。
[root@harbor php]# cat build-command.sh
#!/bin/bash
docker build -t php-7.2.34-fpm-alpine:v1 .
執行構建
[root@harbor php]# sh build-command.sh
稍等時間即可看到構建完成
# 編譯完成后,鏡像體積是160m
[root@harbor php]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php-7.2.34-fpm-alpine v1 fb3d05761dfa 2 hours ago 160MB
# 檢查擴展
[root@harbor php]# docker run php-7.2.34-fpm-alpine:v1 php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
fileinfo
filter
ftp
gd
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
readline
redis
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
swoole
tokenizer
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
這樣,一個鏡像就構建完成了。
5 推送到Harbor鏡像倉庫
一般在企業,自己構建好鏡像后,需要推送到自己的私有倉庫。我這里本地有個harbor的私有倉庫,倉庫地址:http://192.168.18.100
並且倉庫上面有個項目叫 lnmp
,存放相關鏡像。
將上面構建的鏡像推送到harbor倉庫:
# Docker登錄倉庫
[root@harbor php]# docker login 192.168.18.100:80
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 給鏡像打標簽
[root@harbor php]# docker tag php-7.2.34-fpm-alpine:v1 192.168.18.100:80/lnmp/myphp:7.2
# 上傳鏡像
[root@harbor php]# docker push 192.168.18.100:80/lnmp/myphp:7.2
The push refers to repository [192.168.18.100:80/lnmp/myphp]
7dfdf785728d: Pushed
3ec4258bee2c: Pushed
f01174c9f645: Pushing [================> ] 24.29MB/73.92MB
c21c6905870c: Pushed
752870d17619: Pushed
0e7d6edc15aa: Pushed
c9685eb5cbc9: Pushed
e07b1aa3ce21: Pushed
69e56c02a5f3: Pushed
5ce5d9de209b: Pushed
ee81ef73796d: Pushed
738a430a6dab: Pushing [==============> ] 15.51MB/53.39MB
7d12c6e1d8f1: Pushing [==================================================>] 4.096kB
be80e727dd27: Waiting
24e52497c24f: Waiting
86d905c1f58e: Waiting
22573737ba76: Waiting
777b2c648970: Waiting
等待推送完成,即可看到倉庫上已經有該鏡像了。