前文信息
第一章: Docker 下的 OpenResty 三部曲之一: 极速体验
第二章: Docker 下的 OpenResty 三部曲之二: 细说开发
kubernetes 下实战 Nginx 和 Tomcat 的参考文章
您可以通过以下文章了解更详细的 kubernetes 实战:
kubernetes 下的 Nginx 加 Tomcat 三部曲之一: 极速体验
kubernetes 下的 Nginx 加 Tomcat 三部曲之二: 细说开发
kubernetes 下的 Nginx 加 Tomcat 三部曲之三: 实战扩容和升级
环境信息
本次实战搭建的环境如下所示:
本次实战的 web 服务
本次实战的 web 服务, 主要功能为: 浏览器发起 http 请求到 OpenResty,OpenResty 负责去处理业务, 处理过程中向 Tomcat 发起 http 请求, 将 Tomcat 响应的信息返回给浏览器;
和常见的 Nginx 加 Tomcat 有什么不同?
上图的架构和常见的 Nginx 加 Tomcat 很相似, 不过还是有区别的:
1. Nginx 节点主要工作是将请求转发到 Tomcat, 由 Tomcat 去执行具体业务;
2. OpenResty 节点上的 lua 脚本可以执行具体业务, 处理的过程中如有必要可以主动发起 http 请求到 Tomcat, 调用 Tomcat 提供的服务;
3. 关于 OpenResty 加 Tomcat 架构的更多特性和优点请移步开涛大神的博客: 跟我学 Nginx+Lua 开发;
实战源码和 Docke 镜像材料下载
本次构建镜像所需的材料我已准备齐全, 您可以在 github 下载到:
名称 | 链接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blog_demos | 该项目在 GitHub 上的主页 |
git 仓库地址 (https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https 协议 |
git 仓库地址 (ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh 协议 |
这个 git 项目中有多个目录, 本次所需的资源放在 tomcat_openresty_docker_image_files, 如下图红框所示:
注意, 本章用到的资源目录是 tomcat_openresty_docker_image_files, 上一章用的是 nginx_lua_docker_image_files, 里面是不同资源;
Tomcat 上的 web 工程源码在 k8stomcatdemo 目录下, 是个普通的 springboot 工程, 提供一个 http 接口可以返回 Tomcat 所在机器的 IP 地址, 这个 web 工程已经被制作成镜像文件 bolingcavalry/k8stomcatdemo:0.0.1-SNAPSHOT, 有关这个工程的更多信息, 请参照 kubernetes 下的 Nginx 加 Tomcat 三部曲之二: 细说开发;
列举步骤
今天的整个实战, 我们要做以下事情:
1. 在前一章的基础上重做 OpenResty 的 Docker 镜像, 新增一些内容;
2. 在 kubernetes 创建 Tomcat 的副本集和 service;
3. 在 kubernetes 创建 OpenResty 的副本集和 service;
4. 通过浏览器验证 kubernetes 环境中的 OpenResty 加 Tomcat 提供的服务;
为什么要重做 Docker 镜像
在上一章我们已经做了 OpenResty 的镜像并体验过了, 为何本章还要重做呢?
1. 在镜像中安装 vim, 并解决 vim 显示中文乱码的问题;
2. 新增一个 http 接口和 lua 脚本, 浏览器访问这个接口时, 对应的 lua 脚本会向 Tomcat 发请求;
3. 将 OpenResty 的 http 模块集成到镜像中;
4. 曲折的解决 OpenResty 的 http 模块无法解析域名的问题;
关于 kubernetes 环境
kubernetes 环境的搭建和使用, 您可以参照以下的文章:
1. rancher 下的 kubernetes 之一: 构建标准化 vmware 镜像;
2. rancher 下的 kubernetes 之二: 安装 rancher 和 kubernetes;
3. rancher 下的 kubernetes 之三: 在 linux 上安装 kubectl 工具;
前期铺垫说了这么多, 接下来我们就开始实战吧;
制作 OpenResty 镜像
本次的镜像是在 Docker 下的 OpenResty 三部曲之二: 细说开发中的 Dockerfile 的基础上添加了一些内容做成的, 接下来详细说明这些新增的内容, 完整的 Dockerfile 在 GitHub 资源的 tomcat_openresty_docker_image_files 文件夹下;
安装 vim, 并解决 vim 显示中文乱码的问题
以下是 Dockerfile 中 vim 相关的内容:
- # 创建安装命令
- RUN apt-get install -y make vim gcc libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl
- # 修改 vim 的配置信息, 修复中文乱码问题
- RUN sed -i '$a\set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936' /etc/vim/vimrc
- RUN sed -i '$a\set termencoding=utf-8' /etc/vim/vimrc
- RUN sed -i '$a\set encoding=utf-8' /etc/vim/vimrc
如上所示, 通过 sed 命令向 / etc/vim/vimrc 文件中追加了三行, 以保证中文显示;
添加 OpenResty 的 http 模块
首先下载 http.lua 和 http_headers.lua 这两个文件, 放在 Dockerfile 所在目录, 然后在 Dockerfile 添加以下内容:
- # 将 http 库文件复制到默认库
- COPY ./http.lua $INSTALL_PATH/lualib/resty
- COPY ./http_headers.lua $INSTALL_PATH/lualib/resty
增加一个 http 接口
为了对外新增一个 http 接口 lua_http, 在 boling_cavalry.conf 文件中增加了以下内容,
- location ~ /lua_http/(\d+)/(\d+) {
- # 设置 nginx 变量
- set $a $1;
- set $b $host;
- default_type "text/html";
- #nginx 内容处理
- content_by_lua_file /usr/local/work/lua/test_http.lua;
- }
如上所示, 当浏览器输入 http://192.168.119.150:9000/lua_http/333/666 这样 URL 时, 就会由 test_http.lua 这个脚本来处理, test_http.lua 的内容如下所示:
- ngx.say("---------------------------------------------------------<br/>");
- local http = require("resty.http")
-- 创建 http 客户端实例
- local httpc = http.new()
- local resp, err = httpc:request_uri("http://127.0.0.1:80",{
- method = "GET",
- path = "/tomcat_proxy/getserverinfo",
- headers = {
- ["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
- }
- })
- if not resp then
- ngx.say("request error :", err)
- return
- end
- ngx.say("resp status--", resp.status)
- ngx.say("<br/><br/>resp body--", resp.body)
- httpc:close()
如上所示, 该脚本的处理很简单: 发起一个 http 请求, 将收到响应的 code 和 body 在页面上显示出来;
你们注意到了吗? 请求的地址是 127.0.0.1, 是 OpenResty 自己, 不是 Tomcat!!!
为什么要向自己发 http 请求呢? 不是应该发请求给 Tomcat 么? 我们一起来梳理一下吧:
按照原本的设计, 此处的 URL 应该是 http://tomcathost:8080/getserverinfo,tomcathost 是 Tomcat 的 Pod 在 kubernetes 暴露的 service 名称, 在 kubernetes 环境中 tomcathost 会被解析成 Tomcat 的 Pod 地址, 请求就到了 Tomcat 了;
但是, OpenResty 的 httpc:request_uri 这个 API 无法将 tomcathost 这个 hostname 解析成 Tomcat 的 Pod 地址, 或者说不会用到 kubernetes 提供的 DNS 服务, 因此请求无法到达 Tomcat 的 Pod;
开涛大神的实例也用到了这个 API, 他在 nginx.conf 中配置了 resolver 8.8.8.8, 访问的是外网 hostname:s.taobao.com, 但我这里是 kubernetes 环境内的 hostname, 试过此方法, 失败;
网上也有遇到此类问题的, 写了脚本定时扫描 / etc/hosts, 将 hostname 对应的 IP 保存来下, 在 OpenResty 中发起 http 请求时直接从这个对应关系中取 IP, 这个方法在 Docker 环境使用是 OK 的, Docker 的 link 用的就是 / etc/hosts 中的关系, 但是在 kubernetes 下, OpenResty 的 / etc/hosts 中并没有写入 Tomcat 的 IP, 所以, 失败;
我的笨办法, 让 OpenResty 请求到 Tomcat
我用的是笨办法, 能将请求发到 Tomcat, 但是很曲折, 理论上存在性能损失, 亲爱的读者如果您有更科学的方法, 期望能得到您的指点;
笨办法的思路如下:
在 nginx.conf 中新建一个 upstream:
- upstream tomcat_client {
- server tomcathost:8080;
- }
此 upstream 中的 server 用到了 tomcathost, 这是 kubernetes 中 Tomcat 的 service 的名字, 能被成功的解析成 Tomcat 的 Pod 的 IP;
2. 再增加一个 http 接口 tomcat_proxy,boling_cavalry.conf 文件中增加了以下内容:
- location ~ /tomcat_proxy/(.*) {
- rewrite /tomcat_proxy(/.*) $1 break;
- proxy_pass http://tomcat_client;
- proxy_redirect default;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- }
如上所示, 如此一来, 所有 url 是 tomcat_proxy/xxxxxxx 的请求都会被转发到 Tomcat 了;
注意这一行: rewrite /tomcat_proxy(/.*) $1 break;, 可以这么理解:
a. http://127.0.0.1:80/tomcat_proxy/getserverinfo 这个请求可以被 tomcat_proxy(/.*) 这个正则表达式匹配;
b. 因为 / getserverinfo 和第一个圆括号中的表达式匹配, 所以 $1 的值就是 / getserverinfo;
c. 因此请求 / tomcat_proxy/getserverinfo 被 rewrite 成了 $1, 也就是 / getserverinfo, 带上 IP 的完整的 url 就是 http://127.0.0.1:80/getserverinfo;
d. 所以, http://127.0.0.1:80/tomcat_proxy/getserverinfo 被转发到了 http://tomcathost:8080/getserverinfo, 在 rewrite 的时候将 tomcat_proxy 抹去了;
最终, 在调用 OpenResty 的 request_uri 方法的时候, 请求的 URL 是 http://127.0.0.1:80/tomcat_proxy/getserverinfo, 可以被成功转发到 Tomcat, 关键是 Nginx 中的 upstream 的 hostname 在 kubernetes 可以被成功解析成 IP 地址;
最后, 在制作 Dockerfile 的时候, 记得将新增的 test_http.lua 复制到镜像中:
COPY ./test_http.lua $WORK_PATH/lua
以上就是制作新的 Dockerfile 时要新增的内容了, 在 Dockerfile 所在目录执行以下命令构建镜像, 注意 TAG 是 0.0.2, 区别于上一章镜像的 0.0.1:
docker build -t bolingcavalry/ubuntu16-openresty:0.0.2 .
让 kubernetes 的机器用上 web 工程的 Docker 镜像
现在的镜像只存在于开发和构建 web 工程的电脑上, 为了让 kubernetes 的 node 机器能用上这个镜像, 可以用以下四种方式实现:
1. 用 docker push 命令将本机镜像推送到 hub.docker.com 网站, 这样其他机器都可以通过 docker pull 命令取得了, 我就是用的这种方法, 需要在 hub.docker.com 上注册;
2. 用 docker save 命令导出镜像文件, 再用 docker load 命令导入到 kubernetes 的 node 机器;
3. kubernetes 所在机器安装 java 和 maven 环境, 将工程在这里编译构建;
4. 使用 docker 私有仓库, 例如搭建局域网私有仓库或者阿里云私有仓库, 参考 maven 构建 docker 镜像三部曲之三: 推送到远程仓库 (内网和阿里云);
在 kubernetes 创建 Tomcat 的副本集和 service
1. 登录到一台可以执行 kubectl 命令的机器, 创建文件 tomcat.yaml:
- apiVersion: extensions/v1beta1
- kind: Deployment
- metadata:
- name: tomcathost
- spec:
- replicas: 3
- template:
- metadata:
- labels:
- name: tomcathost
- spec:
- containers:
- - name: tomcathost
- image: bolingcavalry/k8stomcatdemo:0.0.1-SNAPSHOT
- tty: true
- ports:
- - containerPort: 8080
以上文件用来定义 Tomcat 的 Pod 的副本集;
2. 在 tomcat.yaml 所在目录创建 tomcat-svc.yaml 文件, 内容如下:
- apiVersion: v1
- kind: Service
- metadata:
- name: tomcathost
- spec:
- type: ClusterIP
- ports:
- - port: 8080
- selector:
- name: tomcathost
以上文件将 Tomcat 的 Pod 副本包装成 service, 名字是 tomcathost, 这样 kubernetes 环境中的其他 Pod 通过 tomcathost 这个 hostname 就能访问到 Tomcat 的 Pod 副本了;
3. 在 tomcat.yaml 文件所在目录下执行以下命令, 创建 Pod 和 service:
kubectl create -f tomcat.yaml,tomcat-svc.yaml
以上命令依次创建 Pod 和 service;
4. 执行 kubectl get service 查看 service 情况, 如下:
- root@maven:/usr/local/work/openrest_rewrite# kubectl create -f tomcat.yaml,tomcat-svc.yaml
- deployment "tomcathost" created
- service "tomcathost" created
- root@maven:/usr/local/work/openrest_rewrite# kubectl get service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 62d
- tomcathost ClusterIP 10.43.192.125 <none> 8080/TCP 1m
至此, Tocmat 服务就 OK 了, 接下来我们创建 OpenResty 服务吧;
在 kubernetes 创建 OpenResty 的副本集和 service
1. 在 tomcat.yaml 所在目录下, 创建文件 openresty.yaml:
- apiVersion: extensions/v1beta1
- kind: Deployment
- metadata:
- name: openresty001
- spec:
- replicas: 1
- template:
- metadata:
- labels:
- name: openresty001
- spec:
- containers:
- - name: openresty001
- image: bolingcavalry/ubuntu16-openresty:0.0.2
- ports:
- - containerPort: 80
以上文件用来定义 OpenResty 的 Pod 的副本集;
2. 在 openresty.yaml 所在目录创建 openresty-svc.yaml 文件, 内容如下:
- apiVersion: v1
- kind: Service
- metadata:
- name: openresty001
- spec:
- type: NodePort
- ports:
- - port: 80
- nodePort: 30007
- selector:
- name: openresty001
以上文件将 openresty 的 Pod 副本包装成 service, 名字是 openresty001, 并且将 80 端口和所在节点机器的 30007 端口建立映射;
3. 在 openresty.yaml 文件所在目录下执行以下命令, 创建 Pod 和 service:
kubectl create -f openresty.yaml,openresty-svc.yaml
以上命令依次创建 Pod 和 service;
4. 执行 kubectl get service 查看 service 情况, 如下:
- root@maven:/usr/local/work/openrest_rewrite# kubectl create -f openresty.yaml,openresty-svc.yaml
- deployment "openresty001" created
- service "openresty001" created
- root@maven:/usr/local/work/openrest_rewrite# kubectl get service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 62d
- openresty001 NodePort 10.43.148.118 <none> 80:30007/TCP 8s
- tomcathost ClusterIP 10.43.192.125 <none> 8080/TCP 43m
终于将所有的服务都创建好了, 接下来开始验证吧;
验证服务
OpenResty 服务所在的机器 IP 是 192.168.119.153, 所以在浏览器输入: http://192.168.119.153:30007/lua_http/333/666, 可以看到如下效果:
如上所示, 结合 test_http.lua 的源码来看, 200 是 Tomcat 的返回 code,10.42.11.12 是 Tomcat 所在 Pod 的 IP 地址, 我们去 kubernetes 的 dashboard 印证一下, 如下图, 红框 1 是查看信息的路径, 红框 2 是 Pod 的 IP 地址, 果然有 10.42.11.12:
至此, Docker 下的 OpenResty 三部曲就全部结束了
来源: http://blog.csdn.net/boling_cavalry/article/details/79311164