是否有這樣的場景,你搞了一個項目,在本地開發時須要搭建環境,放到線上時也須要搭建環境,到公司想暗戳戳玩一下要搭建環境,不搭還不行,由於你的環境依賴還挺多。這個時候若是有了Docker,只須要在機器上裝個Docker,放上寫好的Dickerfile,一行命令就自動完成這個事,方便又高效,豈不是很爽?php
接下來,本文介紹如何搭建一個PHP的開發環境,將用 zPhal-dockerfiles 作爲例子,這是我爲個人博客系統準備的一套Dockerfile。html
如今不論是windows,mac仍是linux,docker均可以很好支持,包括Windows系統,在win10系統下Docker for Windows 其實仍是挺不錯的,就是比較吃內存。mysql
經過Docker命令行,咱們能夠作不少事情,拉取鏡像,運行容器,容器內執行命令等,可是如今,咱們要用更加簡單粗暴的方式,編寫好dockerfiles文件,而後經過docker-compose管理好這些文件,簡化操做流程。linux
什麼是Dockerfile?
Dockerfile是由一系列命令和參數構成的腳本,這些命令應用於拉取的基礎鏡像並最終建立一個新的鏡像,經過Dockerfile咱們能夠建立一個你須要的鏡像,裏面是包含了你要安裝的軟件,至關因而提早定製好要安裝的拓展,執行的命令等,而後一鍵執行,極大地簡化操做流程。
按照本文來搭建環境,你須要:nginx
注意,編寫 dockerfile 是活的,不是死的,每一個人寫出來的 dockerfile 都會不同,取決於你的需求。git
Docker的官方文檔很是清楚,雖然是英文,可是基本上什麼都有,有問題上文檔翻是很是明智的:Docker Documentationgithub
接下來都是以 zPhal-dockerfiles 爲例子,完整的能夠點連接進去看,下面的只是片斷。web
首先,咱們來看一下,我建立的這個dockerfile項目,我大概分紅了下面的目錄(固然這個是本身定的,並非要求這麼去排版你的文件):redis
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拓展等。sql
總的來講,咱們作這件事有三個流程:編寫好各個軟件的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
第一行定義了基礎鏡像,這裏咱們用了PHP7.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 timezome ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
MySQL也沒有什麼特別之處,直接使用官方的鏡像。
下面是 Redis 的,也直接使用官方鏡像:
FROM redis:3.2 # set timezome ENV 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 的部分:
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
目錄下。
其它的參數:
image:mysql:5.7
;php-fpm:php-fpm
,後面是別名;80:80
表示將80端口映射到宿主機的80端口restart: always
表示將自動重啓參數不少,更多的能夠參考官方文檔。
下面是一個完整的 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
本文首發在個人博客:徒手用 Docker 構建本身的 PHP 開發環境