這次帶給大家在Docker中建置PHP開發環境,在Docker中建置PHP開發環境的注意事項有哪些,以下就是實戰案例,一起來看一下。
1. 前言
有沒有這樣的場景,你搞了一個項目,在本地開發時需要搭建環境,放到線上時也需要搭建環境,到公司想暗戳戳玩一下要搭建環境,不搭還不行,因為你的環境依賴還蠻多。這時候如果有了Docker,只需要在機器上裝個Docker,放上寫好的Dockerfile,一行指令就自動完成這個事,方便又高效,豈不是很爽?
接下來,本文介紹如何建構一個PHP的開發環境,將用 zPhal-dockerfiles 做為例子,這是我為我的部落格系統準備的一套Dockerfile。
現在不管是Windows、Mac還是Linux,Docker都可以很好支持,包括Windows系統,在Win 10系統下Docker for Windows 其實還是挺不錯的,就是比較吃記憶體。
透過Docker命令列,我們可以做很多事情,拉取鏡像,運行容器,容器內執行命令等,但是現在,我們要用更加簡單粗暴的方式,編寫好Dockerfiles文件,然後通過docker -compose管理好這些文件,簡化操作流程。
什麼是Dockerfile?
Dockerfile是由一系列命令和參數構成的腳本,這些命令應用於拉取的基礎鏡像並最終創建一個新的鏡像,透過Dockerfile我們可以創建一個你需要的鏡像,裡面是包含了你要安裝的軟體,相當於事先自訂好要安裝的拓展,執行的指令等,然後一鍵執行,大幅簡化操作流程。
依照本文來建構環境,你需要:
先了解Docker以及Docker的一些基本操作,還有docker-compose是什麼。
然後需要安裝Docker和docker-compose,我將使用docker-compose來管理我的Dockerfiles。
注意,寫Dockerfile是活的,不是死的,每個人寫出來的Dockerfile都會不一樣,取決於你的需求。
Docker的官方文件非常清楚,雖然是英文,但是基本上什麼都有,有問題上文檔翻是非常明智的: Docker Documentation 。
接下來都是以 zPhal-dockerfiles 為例子,完整的可以點連結進去看,下面的只是片段。
首先,我們來看一下,我創建的這個Dockerfile項目,我大概分成了下面的目錄(當然這個是自己定的,並不是要求這麼去排版你的檔案):
zPhal-dockerfiles app/ index.php phpinfo.php data/ .gitignore files/ mysql/ conf.d/ mysql-file.cnf Dockerfile nginx/ conf.d/ default.conf zphal.conf Dockerfile nginx.conf php/ pkg/ .gitignore Dockerfile php.ini php-dev.ini php-fpm.conf redis/ Dockerfile docker-compose.yml logs/ .gitgnore README.md
在這個專案裡,我用到PHP、MySQL、Nginx、Redis以及Composer、Phalcon拓展等。
總的來說,我們做這件事有三個流程:編寫好各個軟體的Dockerfile;編寫好設定檔;透過docker-compose處理所有的Dockerfile,包括將配置設定檔丟進去Dockerfile檔案將建置的映像中。
#下面是PHP的Dockerfile:
FROM php:7.2-fpm
# MAINTAINER goozp "gzp@goozp.com"
設定時區
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
更新安裝依賴包和PHP核心拓展
RUN apt-get update && apt-get install -y \ git \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-install zip \ && docker-php-ext-install pdo_mysql \ && docker-php-ext-install opcache \ && docker-php-ext-install mysqli \ && rm -r /var/lib/apt/lists/*
將預先下載好的拓展包從宿主機拷貝進去
COPY ./pkg/redis.tgz /home/redis.tgz COPY ./pkg/cphalcon.tar.gz /home/cphalcon.tar.gz
安裝PECL 拓展,這裡我們安裝的是Redis
RUN pecl install /home/redis.tgz && echo "extension=redis.so" > /usr/local/etc/php/conf.d/redis. ini
安裝第三方拓展,這裡是Phalcon 拓展
RUN cd /home \ && tar -zxvf cphalcon.tar.gz \ && mv cphalcon-* phalcon \ && cd phalcon/build \ && ./install \ && echo "extension=phalcon.so" > /usr/local/etc/php/conf.d/phalcon.ini
安裝Composer
ENV COMPOSER_HOME /root/composer RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer ENV PATH $COMPOSER_HOME/vendor/bin:$PATH RUN rm -f /home/redis.tgz \ rm -f /home/cphalcon.tar.gz WORKDIR /data Write Permission RUN usermod -u 1000 www-data
第一行定義了基礎鏡像,這裡我們用了PHP 7.2的fpm版本,這裡第二行定義了一個維護者。
接下來定義了時區,在每一個Dockerfile都定義了這一句,主要是為了讓所有的容器的時間都與宿主機同步,其實我們可以在docker-composer.yml檔案中這麼定義:
services:
php-fpm:
volumes:
- /etc/localtime:/etc/localtime:ro
#但是在非Linux系統,例如Windows中執行時,我們不能取到/etc/localtime,為了更大相容於所有平台,我把時間同步寫到Dockerfile中。
接下來安裝一些拓展,其實安裝拓展的過程類似我們徒手在Linux中安裝PHP拓展,值得一提的是Composer。我將Composer直接安裝在了php-fpm的鏡像中,其實官方也提供了Composer的鏡像,拉取Composer鏡像執行也可以達到目的,因為我們使用Composer只是為了執行Composer命令來管理我們的包,如果Composer單獨是一個容器的話,我們在不用時,還可以將容器關掉;但是在這裡,我直接將Composer裝進php-fpm鏡像中,主要是我的項目安裝了一些PHP拓展,在編寫composer.json檔案時,我定義了extension的依賴,這樣Composer執行時會檢查環境是否安裝了這些依賴,所有如果我直接用Composer鏡像的話,還需要把我用的拓展安裝到鏡像裡,就麻煩多了,所以我直接在PHP鏡像就把這件事做了,其實沒什麼差別,取決於你怎麼用。
下面是Nginx的Dockerfile:
FROM nginx:1.12
set timezome
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
這個就簡單多了,我只設定了一個時間。因為我不需要安裝其它的東西,可以直接使用官方的鏡像。
當然,我們需要修改配置文件,只要事先寫好配置文件就行,最後在docker-compose.yml 文件中,將配置文件扔進去,這個下面會講,包括PHP的配置文件,MySQL的設定文件,都是一樣的。
下面是MySQL 的Dockerfile:
FROM mysql:5.7
set timezomeENV TZ=Asia /Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
MySQL也沒什麼特別之處,直接使用官方的鏡像。
下面是Redis 的,也直接使用官方鏡像:
FROM redis:3.2
set timezomeENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
如何處理設定檔呢,我將設定檔進行歸類,PHP的設定檔放在PHP目錄下,Nginx的設定檔放在Nginx目錄下,至於要不要再新建一個子文件夾就看情況了,例如conf.d資料夾。
下面以Nginx設定檔為例,首先Nginx目錄是這樣的:
nginx/
conf.d/
default.conf
zphal.conf
Dockerfile
nginx.conf
#除了nginx.conf外,還有一個子資料夾conf.d用來存放所有的域名設定文件,在Linux下搭建過PHP環境的應該都比較熟悉。這些設定檔就是我們到時候要傳進去容器中的文件,我們不會在宿主機上使用這些文件。
所以需要注意的最重要一點就是,設定檔中出現的路徑是容器內環境的路徑,而不是宿主機的路徑,每個容器內都有一個運作環境,都是一台微型小系統,這些路徑都是容器內的路徑。我們可以透過掛載與容器內通訊來同步文件,在命令列啟動容器也需要掛載文件路徑,而現在掛載這一步驟我們也用docker-compose來解決。
下面是一個設定檔範例:
server { listen 80 default; index index.html index.htm; server_name localhost docker; root /data/www; index index.php index.html index.htm; location / { try_files $uri $uri/ /index.html; } location ~ \.php { include fastcgi_params; fastcgi_pass php-fpm:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /data/www/$fastcgi_script_name; } }
而root /data/www中,/data/www路径,是到时候Nginx容器的路径,而不是当前在操作的宿主机的路径,所以到时候我们要挂载Web程序放的位置到这个路径。
在PHP、Nginx等目录的同级,我们创建一个docker-compose.yml,我们在执行docker-compose相关命令时,会自动找到这个文件,并根据里面的内容来执行。
接上面Nginx的例子,我们先谈挂载,因为这是最重要的一步。在docker-compose.yml中,Nginx的部分:
build: ./nginx depends_on: - php-fpm links: - php-fpm:php-fpm volumes: - ../app:/data/www:rw - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ../logs/nginx:/var/log/nginx ports: - "80:80" - "8080:8080" - "443:443" restart: always command: nginx -g 'daemon off;'
有一个volumes参数,这里就是我们要挂载的目录的相关配置,第一条我们将../app挂载到/data/www之中,也是我们配置文件中定义的默认监听的root,而APP目录是我们宿主机中的一个目录,通过这样挂载我们可以直接将我们的项目文件放到APP中,Docker会帮你传输到容器内的/data/www目录下。
其它的参数:
build定义了你的Dockerfile在哪里,如果没有写Dockerfile可以不用build,可以用images参数定义官方镜像,比如image:mysql:5.7;
depends_on表示将依赖其它镜像,比如Nginx依赖php-fpm,没有它我Nginx没法玩;
links定义连接,比如要连接到php-fpm容器,就是php-fpm:php-fpm,后面是别名;
ports表示端口映射,80:80表示将80端口映射到宿主机的80端口;
restart重启,restart: always表示将自动重启;
command是自动执行的命令;
……
参数很多,更多的可以参考官方文档。
下面是一个完整的 docker-compose.yml 文件:
version: '3.2' services: php-fpm: build: ./php/ ports: - "9000:9000" links: - mysql-db:mysql-db - redis-db:redis-db volumes: - ../app:/data/www:rw - ./php/php-dev.ini:/usr/local/etc/php/php.ini:ro - ./php/php-fpm.conf:/usr/local/etc/php-fpm.conf:ro - ../logs/php-fpm:/var/log/php-fpm:rw restart: always command: php-fpm nginx: build: ./nginx depends_on: - php-fpm links: - php-fpm:php-fpm volumes: - ../app:/data/www:rw - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ../logs/nginx:/var/log/nginx ports: - "80:80" - "8080:8080" - "443:443" restart: always command: nginx -g 'daemon off;' mysql-db: build: ./mysql ports: - "3306:3306" volumes: - ../data/mysql:/var/lib/mysql:rw - ../logs/mysql:/var/lib/mysql-logs:rw - ./mysql/conf.d:/etc/mysql/conf.d:ro environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: zphaldb MYSQL_USER: zphal MYSQL_PASSWORD: zphal123 restart: always command: "--character-set-server=utf8" redis-db: build: ./redis ports: - "6379:6379" volumes: - ../data/redis:/data restart: always
这一套编写下来,我们怎么用呢?
首先,进入项目Dockerfiles的目录下,这里是files目录:
cd zPhal-dockerfiles/files
wget https://pecl.php.net/get/redis-3.1.6.tgz -O php/pkg/redis.tgz
wget https://codeload.github.com/phalcon/cphalcon/tar.gz/v3.3.1 -O php/pkg/cphalcon.tar.gz
然后下载我们会用到的PHP拓展包。
执行命令:
docker-compose up
Docker会自动通过编写好的docker-compose.yml内容构建镜像,并且启动容器。
如果没问题,下次启动时可以以守护模式启用,所有容器将后台运行:
docker-compose up -d
关闭容器:
可以这样关闭容器并删除服务:
docker-compose down
使用 docker-compose 基本上就这么简单,用stop,start等这些命令来操纵容器服务。而更多的工作是在于编写Dockerfile和docker-compose.yml文件。
当我们要使用Composer时怎么做呢? 我们已经在php-fpm里安装了Composer。
用docker-compose进行操作:
docker-compose run --rm -w /data/www/zPhal php-fpm composer update
-w /data/www/zPhal为在php-fpm的工作区域,zPhal项目也是挂载在里面,所有我们可以直接在容器里运行Composer。
或者进入宿主机APP目录下用Docker命令:
cd zPhal-dockerfiles/app
docker run -it --rm -v `pwd`:/data/www/ -w /data/www/zPhal files_php-fpm composer update
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是在Docker中建置PHP開發環境的詳細內容。更多資訊請關注PHP中文網其他相關文章!