完成 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
| $ 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
|
先只配置 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
| $ docker-compose exec mysql /bin/bash mysql -u root -p show databases
$ docker-compose exec nginx bash cat /etc/nginx/conf.d/mysites.conf
$ docker-compose exec wordpress bash ls -al
|
实际上容器跑起来的时候这些目录都已经备份了 /var/www/html
即外部的 /home/git/wordpress
目录,
数据库的备份(包括文章,用户名密码啥的)放在 /home/mysql/data
下面的 wordpress
目录,内部对应 /var/lib/mysql
。
Merlin 2018.3 折腾了两天,终于弄好了