技术: 深耕 Docker 生态圈(十一){Docker 实践}

完成 docker 面向应用的哲学实践,来看看什么叫以应用为中心。(折腾 nginx,fast-cgi)

老实说,上手真实环境的时候我还是有点儿点儿害怕的,因为怕把真实环境弄坏了,又得重来配置。

后来弄完了,发现原来的环境根本没有动。(可能后期还需要 fast-cgi 转 nodejs 环境给 hexo 升级数据库支持)

任务描述

具体的任务如下:

  • 把原来的博客配置到 docker 里的 nginx (原来外部已经有了 nginx)
  • 再配置一个 wordpress 站点作为主站点(单独域名)

比较麻烦的是,原来的配置耦合了 hexo deploy 的 git push 配置;
换句话说,现在的改进只能说停止原来 nginx 服务器,但是原来目录 & git库 统统不能改变

更麻烦的是,这个服务器上要配置两个网站,一个 hexo,一个 wordpress,都要在 nginx 下,但是官方的 wp 镜像是自带 apache 的,少不了要调整。(试错)

分析&指定方案

总体思想是:

  • 先配置好一个 nginx 容器,跑起来原来的博客。
  • 配置 mysql 容器
  • 配置 wordpress 容器 & 并且拆分 wordpress 容器(不实用 apach)
  • 配置 compose 可以让三个容器协作 & 管理 (如果三个容器都非常熟悉,其实可以直接编写 yml 配置)

最后检查验收,后期发现问题再进行迭代。

值得说的是:

  • 原来的目录不动,因为它本来就不属于 docker 体系, hexo 自己原来有一个体系了
  • nginx 下 配置两个网站配置不同的域名,但是先按照单个网站配置,再改成多个网站
  • 容器间通信可以使用 links 也可以使用 network 随意就好
  • 现在 docker compose 管理的是 mysql 容器, wp_php 容器,以及 web/nginx 容器

由于是单独的 nginx ,所以一般这样的配置肯定不行的:

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
26
27
version: "3"
services:

db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress

wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:

下面细细展开。

上手实施

其实我也是边做边摸索的,可能我这边儿的方式也不是最好的

保护原来的环境

本来是应该备份的,但是下面的配置不涉及破坏原来的环境(跟原来的环境不搭边,唯一有关系的就是80端口),所以这里只是简单熟悉一下原来的环境:

看来已经非常明显了,只要不动 hexo_public, hexo_source 这两个目录即可。

停止 nginx

安装 docker

以前说过,请直接查看这篇文章 : TODO

(v p s 如果是国外的机器,可以不用设置国内镜像)

配置 nginx 容器

本来应该先安装的,其实没有必要,如果本地没有,你运行的时候,它自动拉去到本地的。

虽然 hexo public 下的都是静态页面,但是也是有配置一些错误以及域名的(并且后期配置两个网站),
所以下面的命令不适用:

1
$ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx

而据我所知 nginx 中 http 配置部分,可以引入多个子配置文件,大概是:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;
gzip_disable "msie6";

# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

所以往里面扔配置文件吧(不用 COPY 指令,而是 -v 或者 –mount):

1
2
3
4
## 原来外部 nginx 的配置全部不用改(至少现在配置单个站点不用改)
$ pwd
/home/git
$ cp /etc/nginx/sites-enabled/default ./merlinblog.conf

然后跑 nginx 容器(注意挂载 volume)

1
$ docker run -d --name nginx -v /home/git/merlinblog.conf:/etc/nginx/conf.d/merlinblog.conf:ro -p 80:80 nginx

然后运行试试看:

1
2
3
4
5
wget localhost
--2018-02-28 13:04:41-- http://localhost/
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:80... failed: Connection refused.
Connecting to localhost (localhost)|127.0.0.1|:80... failed: Connection refused.

重新挂载一下网页内容:

1
2
3
4
5
6
$ docker run
--name nginx-web \
-v /home/git/merlinblog.conf:/etc/nginx/conf.d/merlinblog.conf:ro \
-v /home/git/hexo_public:/home/git/hexo_public:ro \
-p 80:80 \
-d nginx

网页可以正常显示,也就是说,这里还是要配置数据目录的。

那么数据动态增加了呢?经过实践,这里也是 OK 的,目录一旦映射,那么会根据实际的情况兼容文件变化。

相关文档可以参考: github-nginx

下面把容器停止了,开始配置其他容器

1
$ docker stop nginx-web && docker rm nginx-web

配置 Mysql 容器

由于是内部数据库,所以密码干脆设置简单一点儿(禁止非 localhost 登录)。
(意思是,直接不配置了,直接运行即可)

1
2
3
4
5
6
7
$ docker run \
-d \
--rm \
--name wpdb \
--env MYSQL_ROOT_PASSWORD=hello \
--env MYSQL_DATABASE=wordpress \
mysql:mariadb

基本不会出错,它运行在 3306 端口。停止容器吧,已经可以了。

配置 wordpress

只用 compose 来配置,为什么可以直接配置 compose?

因为 wordpress 官方镜像是带有 apach的,本来把 wordpress 网站的压缩包放在 nginx 的指定目录,外加一个 mysqlcli 就可以直接连接数据库完成工作,但是给定 wordpress 官方镜像自己带了 mysqlcli 连接部分,所以配置 compose 拆分出 php-fpm 用于 nginx 运行网站(提供 PHP 环境)。

先安装 compse:

安装之后,做一些准备工作

  • Nginx: 用最新的镜像 latest version ‘nginx: latest’.
  • Wordpress: WordPress 4.7 with PHP-FPM 7.0 on it.
  • MySQL: We will use MariaDB official container, latest version

创建一些数据目录,用于 docker 数据备份:

1
2
3
4
5
$ mkdir wordpress
$ mkdir -p mysql/data
$ mkdir -p logs/nginx
$ touch docker-compose.yml
$ touch mysites.conf ## nginx 配置文件

先只配置 wordpress 博客,所以 mysites.conf 这样配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 80;
server_name server_name www.wannabemaster.com wannabemaster.com wannabemaster.xyz www.wannabemaster.xyz;

root /var/www/html;
index index.php;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wp:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

配置一个 docker-compose.yml,大致如下: (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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
nginx-web:
image: nginx:latest
container_name: nginx-web
ports:
- '80:80'
volumes:
- /home/git/mysites.conf:/etc/nginx/conf.d/mysites.conf
- /home/git/logs/nginx:/var/log/nginx
- /home/git/wordpress:/var/www/html
links:
- wp
restart: always

wpdb:
image: mysql:mariadb
container_name: wpdb
ports:
- '3306:3306'
volumes:
- /home/git/mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always

wp:
image: wordpress:4.7.1-php7.0-fpm
container_name: wp
ports:
- '9000:9000'
volumes:
- /home/git/wordpress:/var/www/html
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_TABLE_PREFIX=wp_
- WORDPRESS_DB_HOST=wpdb
- WORDPRESS_DB_PASSWORD=root
links:
- wpdb
restart: always

然后运行一下 docker-compose,结果是 nginx 正常,但是得到一个这样的明显的错误:

通过域名访问的时候,又可以正常显示。。。(上面的错误有点儿担心啊,万一数据丢了怎么办)

好吧,居然安装上了,那么写一篇文章,停止运行,再重新运行试试,看看数据是否丢了。

运行之后一切正常。。。

配置多个站点

能运行 wordpress 算是目的达成的第一步,但是还要运行多个站点。

已知的方案中,可以采用不同站点分为子级目录存储的方案,不过我更倾向于使用 proxy_pass

修改上面的 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
nginx-web:
image: nginx:latest
container_name: nginx-web
ports:
- '80:80'
volumes:
- /home/git/mysites.conf:/etc/nginx/conf.d/mysites.conf
- /home/git/logs/nginx:/var/log/nginx
- /home/git/wordpress:/var/www/html
- /home/git/hexo_public:/home/git/hexo_public
links:
- wp
restart: always

wpdb:
image: mariadb
container_name: wpdb
ports:
- '3306:3306'
volumes:
- /home/git/mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always

wp:
image: wordpress:4.7.1-php7.0-fpm
container_name: wp
ports:
- '9000:9000'
volumes:
- /home/git/wordpress:/var/www/html
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_TABLE_PREFIX=wp_
- WORDPRESS_DB_HOST=wpdb
- WORDPRESS_DB_PASSWORD=root
links:
- wpdb
restart: always

也就是要多挂载一个目录,其次要修改 conf 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 80;
server_name server_name www.wannabemaster.com wannabemaster.com wannabemaster.xyz www.wannabemaster.xyz;

root /var/www/html;
index index.php;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wp:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

改成下面这样:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
## mysites.conf

# default
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 404; # means filter to other domain request
}

## wordpress
server {
listen 80;
server_name www.wannabemaster.com wannabemaster.com wannabemaster.xyz www.wannabemaster.xyz
location / {
try_files $uri $uri/ /index.php?$args;
}

root /var/www/html;
index index.php;
access_log /var/log/nginx/hakase-access.log;
error_log /var/log/nginx/hakase-error.log;

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wp:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

## hexo
server {
listen 80 ;
server_name www.merlinblog.site merlinblog.site;

root /home/git/hexo_public;
index index.html index.htm index.nginx-debian.html;

error_page 404 /404.html;
location ~ .*\.(ico|gif|jpg|jpeg|png|bmp|swf)$
{
access_log off;
expires 1d;
}

location ~ .*\.(js|css|txt|xml)?$
{
access_log off;
expires 12h;
}

location / {
try_files $uri $uri/ =404;
}
access_log /home/git/blog.log;
}

也就是说,你通过 ip 地址访问,那么肯定给你 404 错误。 但是通过不同的域名其实访问的是不同的目录,多个server同时监听80端口,实际上返回的内容是不同的。

为什么不用反向代理?

1
proxy_pass http://192.168.20.1:8080

首先我是同一个 v p s 服务器,并且我不需要转发到具体的 node,直接本机就可以了。

并且更深层的原因, nginx 本身不支持 php 运行环境,是通过 fast-cgi 转发给 fast-cgi 服务的,也就是 fpm。
如果你要转发到 http 的其他端口,那要确保最终能转发到 fast-cgi 的 9000 端口,但是,何必呢。

(中途数据库的连接问题,貌似和数据库本身,还好我用的是 mariadb,而不是 mysql5.7)

总结

配置 nginx 的时候,主要是映射好配置文件目录以及数据目录,配置 mysql 的时候,直接后台启动即可。

1
2
$ docker run --name nginx-web -v /home/git/merlinblog.conf:/etc/nginx/conf.d/merlinblog.conf:ro -v /home/git/hexo_public:/home/git/hexo_public:ro -p 80:80 -d nginx
$ docker run -d --rm --name wpdb --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress mysql:5.7

三个容器可以通过 –link 通信(貌似统一主机,默认就是可以通信的),只不过这里 wordpress 镜像自带了 apach。

wordpress 需要 php 环境,所以 nginx 需要依赖 wordpress 镜像,但不是完整的 php 镜像,所以而只是 php-fpm。
同时 wordpress 运行需要数据库的支持,所以这里又运行了一个容器 mysql。

多个容器不好管理,所以又改换成了 compose 控制,同时指定了备份内容的目录,这也符合 docker 数据管理的哲学。

其中比较坑爹的有几个地方:

  • mysql 连接问题,可能会报错;根据不同的数据库版本,出现诡异的问题(docker容器问题?)
  • yml 配置文件,需要制定的 version,不然语法解析的时候也会报错
  • nginx 配置多个站点,可以使用反向代理,但是注意用法;也可以直接监听然后指向不同目录即可
  • 原来的外部 nginx 开机就会自动启动,给先停止了,不然80端口占用

真正的觉得有用的是:

Each application (Wordpress, Nginx, and MySQL) will run in its own container

最后一件事儿,修改数据库密码,后台运行 docker-compose up -d,注意这个 -d 是传递给子容器的。

1
2
3
4
5
6
7
8
9
10
11
12
## 登录 mysql 容器
$ docker-compose exec mysql /bin/bash
mysql -u root -p
show databases

## 查看 nginx 服务器
$ docker-compose exec nginx bash
cat /etc/nginx/conf.d/mysites.conf

## 查看 wordpress 容器
$ docker-compose exec wordpress bash
ls -al

实际上容器跑起来的时候这些目录都已经备份了 /var/www/html 即外部的 /home/git/wordpress 目录,
数据库的备份(包括文章,用户名密码啥的)放在 /home/mysql/data 下面的 wordpress 目录,内部对应 /var/lib/mysql


Merlin 2018.3 折腾了两天,终于弄好了

文章目录
  1. 1. 任务描述
  2. 2. 分析&指定方案
  3. 3. 上手实施
    1. 3.1. 保护原来的环境
    2. 3.2. 停止 nginx
    3. 3.3. 安装 docker
    4. 3.4. 配置 nginx 容器
    5. 3.5. 配置 Mysql 容器
    6. 3.6. 配置 wordpress
    7. 3.7. 配置多个站点
  4. 4. 总结
|