docker模拟多机环境

Docker基础

这里不多说,借助docker官方文档可以学习到大部分内容,而且很详细。

本次配置中用到的镜像:

并且使用docker-compose来管理容器,它在pdf文档中有介绍,这里不再赘述。

多机结构

为了实现一台真机模拟多台机,引入逻辑主机的概念。例如现在只有一台云主机,但是我们又要把测试环境(dev)正式环境(online)分开。

以下是项目完成后的目录结构,每一个目录对应一个逻辑主机 和独立数据卷

1
2
3
4
5
6
7
8
9
10
11
.
├── dev
│   ├── docker-compose.yml
│   └── php
│   └── Dockerfile
├── online
│   ├── docker-compose.yml
│   └── php
│   └── Dockerfile
└── _self
└── docker-compose.yml

这里需要做以下说明:

  • 测试环境(dev)正式环境(online) 除了数据卷 不一样,其他配置都一样
  • _self 目录表示宿主主机,上面有nginx

dev 配置

dev 环境下有php和mysql,两个app都在独立的容器中,两者通过 sock文件 或网络进行通信,以下是dev环境的docker-compose.yml 文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
php1:
#build: ./php
#image: php:7.1-fpm-alpine
image: php-fpm-composer:1.0
container_name: dev_php1
expose:
- "9000"
volumes:
- "/data-dev/data1/:/data1/"
- "/data-dev/data2/:/data2/"
- "/data-dev/data2/php/conf/:/usr/local/etc/"
links:
- mysql1:server_mysql

mysql1:
image: mysql/mysql-server:5.7.20
container_name: dev_mysql1
expose:
- "11308"
volumes:
- "/data-dev/data1/:/data1/"
- "/data-dev/data2/:/data2/"
- "/data-dev/data2/mysql/conf/:/etc/mysql/"
environment:
- MYSQL_ROOT_PASSWORD=123456789

volumes

先看数据卷。以 dev_php1 容器为例,我们可以看到 宿主/data-dev/data1/data-dev/data2 被映射到了php容器的/data1/data2 目录。是的,宿主的/data-dev 目录就是专门为dev 环境划分的逻辑目录。

再看dev_mysql1 容器,道理和上述一样。

端口配置

先看dev_php1,根据 php-fpm 配置文件中监听了9000 端口,所以开放容器的9000端口。

mysql 配置文件中设置的是11308 端口,所以我们开放容器的11308 端口。

其实在实际使用中,两者也都支持 sock文件方式进行连接。

自定义的php镜像

由于官方的php缺少一些扩展,所以我基于该镜像添加了扩展和compose,Dockerfile如下:

1
2
3
4
5
6
7
8
FROM php:7.1-fpm-alpine
RUN apk add --no-cache \
libpng-dev \
&& docker-php-ext-install pdo_mysql gd zip \
&& php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& php -r "unlink('composer-setup.php');"

为了避免构建多层镜像又保证命令的整洁性,使用 \ (表示换行)把要执行的命令分开。

可以看到我这里添加了pdo_mysqlgdzip 扩展,其中zip 镜像是安装compose必要的,且为了安装gd 扩展,系统必须要先安装libpng-dev 库。

后面四行命令是安装composer的,安装后放在了/usr/local/bin 目录下,文件名是composer

根据这个Dockerfile构建了名为php-fpm-composer:1.0 的镜像。

其他配置

dev_mysql1MYSQL_ROOT_PASSWORD 表示数据库初始密码,如果数据库初始化过了(数据卷中已有数据)则没效了。

online配置

online 环境的docker-compose.yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
php1:
#build: ./php
#image: php:7.1-fpm-alpine
image: php-fpm-composer:1.0
container_name: online_php1
expose:
- "9000"
volumes:
- "/data-online/data1/:/data1/"
- "/data-online/data2/:/data2/"
- "/data-online/data2/php/conf/:/usr/local/etc/"
links:
- mysql1:server_mysql

mysql1:
image: mysql/mysql-server:5.7.20
container_name: online_mysql1
expose:
- "11308"
volumes:
- "/data-online/data1/:/data1/"
- "/data-online/data2/:/data2/"
- "/data-online/data2/mysql/conf/:/etc/mysql/"
environment:
- MYSQL_ROOT_PASSWORD=123456789

部署步骤

可以看到online 环境除了逻辑目录/data-onlie 以外,其他的配置都和dev 一样,当然容器名是不一样的。

如果我们已经成功部署了dev 环境,那么只需把/data-dev copy一份为 /data-online 即可完成数据卷的部署,保证online的数据和dev是一样的(主要是php、mysql等app的配置一样)。

nginx的配置

本项目采取的方式是nginx 单例,所以nginx必须放在宿主主机上,稍后讨论多例nginx的配置。

目前已经有了devonline 两个环境,且分别运行了php和m ysql,单例nginx模式的架构如下:

圆圈 表示逻辑主机矩形框 内是英文的表示容器,英文表示容器名称。

宿主环境 (nginx)的docker-compose.yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nginx1:
image: nginx:1.12-alpine
container_name: nginx1
ports:
- "80:80"
- "443:443"
expose:
- '80'
- '443'
volumes:
- "/data/:/data/"
- "/data1/:/data1/"
- "/data2/:/data2/"
- "/data2/nginx/conf/:/etc/nginx/"
- "/data-dev/:/data-dev/"
- "/data-online/:/data-online/"

可以看到,为了devonline 提供服务,需要将两个逻辑主机数据目录 映射到nginx容器中去,从而达到nginx与宿主主机的文件系统是一样的。

文件路径

在进行nginx配置的时候,需要非常注意的是文件路径。

dev 逻辑主机中,网站根目录是/data1/sites/html,这个目录对应于宿主主机的/data-dev/data1/sites/html ,那么在nginx中配置的时候,就需要特别注意。

下面是nginx 为dev 环境提供服务所写的配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
listen 80;
server_name dev.domain.com;
root /data-dev/data1/sites/html/;
index index.html index.htm index.php;

access_log /data2/nginx/logs/dev/html_access.log main;
error_log /data2/nginx/logs/dev/html_error.log warn;


# use php-fpm.sock
location ~ \.php$ {
fastcgi_pass unix:/data-dev/data2/socks/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data1/sites/html$fastcgi_script_name;
include fastcgi_params;
}
...

由于nginx运行在宿主主机,所以使用的是宿主主机的文件系统:(下面的/data2 是宿主主机上的)

1
2
3
root /data-dev/data1/sites/html/;
access_log /data2/nginx/logs/dev/html_access.log main;
error_log /data2/nginx/logs/dev/html_error.log warn;

根据web请求流程和CGI原理,所以fastcgi在寻找文件时使用的是 dev 主机的文件系统:

1
fastcgi_param  SCRIPT_FILENAME  /data1/sites/html$fastcgi_script_name;

注意:不能写成\$document_root\$fastcgi_script_name,因为$document_root是宿主主机的文件系统

静态文件测试

根据上述配置文件,配置好root 路径即可进行静态文件测试。

现有两个文件,他们在宿主主机 文件系统中的路径如下:

1
2
/data-dev/data1/sites/html/index.html
/data-online/data1/sites/html/index.html

可以看到,一个在 dev 中,一个在 online 环境中

那么在dev 的文件系统中,则是:

1
/data1/sites/html/index.html

文件内容是:

1
This is dev

online 的文件系统中,则是:

1
/data1/sites/html/index.html

文件内容是:

1
This is online

可以发现,在两个逻辑主机中,他们并不知道宿主主机的存在,也就是宿主主机对于他们来说是透明的

/etc/hosts配置如下,同步修改nginxserver_name

1
2
127.0.0.1 dev.domain.com
127.0.0.1 online.domain.com

进行测试:

1
2
curl dev.domain.com
curl online.domain.com

输出:

1
2
This is dev
This is online

php测试

php的测试主要看nginx是否正确使用了对应环境的php-fpm.sock,如果你是用9000端口通信的,那就看ip是否填对了,方式与静态页面类似,不再赘述。

总结

详情:https://github.com/JerryCheese/docker-architecture

坚持原创文章分享,您的支持将鼓励我继续创作!