徒手用 Docker 构建自己的 PHP 开发环境

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 1. 前言1.1 为什么要用 Docker ?是否有这样的场景,你搞了一个项目,在本地开发时需要搭建环境,放到线上时也需要搭建环境,到公司想暗戳戳玩一下要搭建环境,不搭还不行,因为你的环境依赖还挺多。这个时候如果有了Docker,只需要在机器上装个Docker,放上写好的Dickerfile,一行命令就自动完成这个事,方便又高效,岂不是很爽?1.2 准备接下来,本文介绍如何搭建一个PHP的开发环境,将用 zPhal-dockerfiles 做为例子,这是我为我的博客系统准备的一套Dockerfile。现在不管是windows,mac还是linux,docker都可以很好支持,包
  1. 前言

1.1 为什么要用 Docker ?
是否有这样的场景,你搞了一个项目,在本地开发时需要搭建环境,放到线上时也需要搭建环境,到公司想暗戳戳玩一下要搭建环境,不搭还不行,因为你的环境依赖还挺多。这个时候如果有了Docker,只需要在机器上装个Docker,放上写好的Dickerfile,一行命令就自动完成这个事,方便又高效,岂不是很爽?

1.2 准备
接下来,本文介绍如何搭建一个PHP的开发环境,将用 zPhal-dockerfiles 做为例子,这是我为我的博客系统准备的一套Dockerfile。

现在不管是windows,mac还是linux,docker都可以很好支持,包括Windows系统,在win10系统下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

  1. 开始编写

接下来都是以 zPhal-dockerfiles 为例子,完整的可以点链接进去看,下面的只是片段。

2.1 预览
首先,我们来看一下,我创建的这个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 文件将构建的镜像中。

2.2 编写 Dockerfile 文件
2.2.1 PHP
下面是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镜像中就把这个事做了,其实没什么区别,取决于你怎么用。

2.2.2 Nginx
下面是 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的配置文件,都是一样的。

2.2.3 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也没有什么特别之处,直接使用官方的镜像。

2.2.4 Redis
下面是 Redis 的,也直接使用官方镜像:

FROM redis:3.2

set timezome

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

2.3 编写配置文件
如何处理配置文件呢,我将配置文件进行归类,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程序放的位置到这个路径。

2.4 编写 docker-compose.yml
在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目录下。

其它的参数:

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

  1. 使用

这一套编写下来,我们怎么用呢?

3.1 使用搭建好的环境
首先,进入项目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 文件。

3.2 使用 Composer
当我们要使用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

  1. 注意事项

注意挂载路径
构建失败时,注意容器内是否报错
加速镜像。如果过程下载镜像很慢,可以使用国内的加速镜像服务,比如阿里云,Daocloud。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
12天前
|
运维 Kubernetes Docker
利用Docker和Kubernetes构建微服务架构
利用Docker和Kubernetes构建微服务架构
|
10天前
|
SQL 安全 前端开发
PHP与现代Web开发:构建高效的网络应用
【10月更文挑战第37天】在数字化时代,PHP作为一门强大的服务器端脚本语言,持续影响着Web开发的面貌。本文将深入探讨PHP在现代Web开发中的角色,包括其核心优势、面临的挑战以及如何利用PHP构建高效、安全的网络应用。通过具体代码示例和最佳实践的分享,旨在为开发者提供实用指南,帮助他们在不断变化的技术环境中保持竞争力。
|
12天前
|
PHP 开发者
深入浅出PHP:构建你的第一个Web应用
【10月更文挑战第35天】在数字时代的浪潮中,掌握编程技能已成为通往未来的钥匙。本文将带你从零开始,一步步走进PHP的世界,解锁创建动态网页的魔法。通过浅显易懂的语言和实际代码示例,我们将共同打造一个简单但功能强大的Web应用。无论你是编程新手还是希望扩展技能的老手,这篇文章都将是你的理想选择。让我们一起探索PHP的魅力,开启你的编程之旅!
|
18天前
|
存储 监控 Linux
docker构建镜像详解!!!
本文回顾了Docker的基本命令和管理技巧,包括容器和镜像的增删改查操作,容器的生命周期管理,以及如何通过端口映射和数据卷实现容器与宿主机之间的网络通信和数据持久化。文章还详细介绍了如何使用Docker部署一个简单的Web应用,并通过数据卷映射实现配置文件和日志的管理。最后,文章总结了如何制作自定义镜像,包括Nginx、Python3和CentOS镜像,以及如何制作私有云盘镜像。
90 2
|
19天前
|
关系型数据库 MySQL Docker
docker环境下mysql镜像启动后权限更改问题的解决
在Docker环境下运行MySQL容器时,权限问题是一个常见的困扰。通过正确设置目录和文件的权限,可以确保MySQL容器顺利启动并正常运行。本文提供了多种解决方案,包括在主机上设置正确的权限、使用Dockerfile和Docker Compose进行配置、在容器启动后手动更改权限以及使用 `init`脚本自动更改权限。根据实际情况选择合适的方法,可以有效解决MySQL容器启动后的权限问题。希望本文对您在Docker环境下运行MySQL容器有所帮助。
33 1
|
26天前
|
Kubernetes 负载均衡 Docker
构建高效微服务架构:Docker与Kubernetes的完美搭档
本文介绍了Docker和Kubernetes在构建高效微服务架构中的应用,涵盖基本概念、在微服务架构中的作用及其实现方法。通过具体实例,如用户服务、商品服务和订单服务,展示了如何利用Docker和Kubernetes实现服务的打包、部署、扩展及管理,确保微服务架构的稳定性和可靠性。
77 7
|
25天前
|
Kubernetes 负载均衡 Docker
构建高效微服务架构:Docker与Kubernetes的完美搭档
【10月更文挑战第22天】随着云计算和容器技术的快速发展,微服务架构逐渐成为现代企业级应用的首选架构。微服务架构将一个大型应用程序拆分为多个小型、独立的服务,每个服务负责完成一个特定的功能。这种架构具有灵活性、可扩展性和易于维护的特点。在构建微服务架构时,Docker和Kubernetes是两个不可或缺的工具,它们可以完美搭档,为微服务架构提供高效的支持。本文将从三个方面探讨Docker和Kubernetes在构建高效微服务架构中的应用:一是Docker和Kubernetes的基本概念;二是它们在微服务架构中的作用;三是通过实例讲解如何使用Docker和Kubernetes构建微服务架构。
59 6
|
21天前
|
人工智能 搜索推荐 PHP
PHP在Web开发中的璀璨星辰:构建动态网站的幕后英雄###
【10月更文挑战第25天】 本文将带您穿越至PHP的宇宙,揭示其作为Web开发常青树的奥秘。通过生动实例与深入解析,展现PHP如何以简便、高效、灵活的姿态,赋能开发者打造动态交互式网站,同时不忘探讨其在新时代技术浪潮中面临的挑战与机遇,激发对技术创新与应用的无限思考。 ###
31 1
|
24天前
|
负载均衡 应用服务中间件 nginx
基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细
通过使用Nginx和Consul构建自动发现的Docker服务架构,可以显著提高服务的可用性、扩展性和管理效率。Consul实现了服务的自动注册与发现,而Nginx则通过动态配置实现了高效的反向代理与负载均衡。这种架构非常适合需要高可用性和弹性扩展的分布式系统。
25 4
|
25天前
|
负载均衡 应用服务中间件 nginx
基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细
通过使用Nginx和Consul构建自动发现的Docker服务架构,可以显著提高服务的可用性、扩展性和管理效率。Consul实现了服务的自动注册与发现,而Nginx则通过动态配置实现了高效的反向代理与负载均衡。这种架构非常适合需要高可用性和弹性扩展的分布式系统。
33 3
下一篇
无影云桌面