小伙伴们好呀,这篇文章记录了本次的小实验:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务。
阅读的话,可以重点看看 3个 流程解析 以及文末的收获
国外镜像太慢了,特别是 google 和 docker 有竞争,不把镜像弄到 docker hub 上,下载真的特别麻烦。
用云服务
minikube start --image-mirror-country='cn'
创建 ns,deployment,svc
apiVersion: v1
kind: Namespace
metadata:
name: test-ns
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-dep
name: my-dep
namespace: test-ns
spec:
replicas: 3
selector:
matchLabels:
app: my-dep
template:
metadata:
labels:
app: my-dep
spec:
containers:
- image: nginx
name: nginx
apiVersion: v1
kind: Service
metadata:
labels:
app: my-dep
name: my-dep
namespace: test-ns
spec:
selector:
app: my-dep
ports:
- port: 8000
protocol: TCP
targetPort: 80
type: NodePort
按照顺序创建
进入 pod,修改 nginx 默认页面
查看 pod,svc 情况
进入 minikube 访问 svc
在 minikube 节点中,还可以直接访问 pod 的 ip 地址,因为这里通过 docker 做了桥接。
而在宿主机,通过 ip a 可以看到下面的信息,网卡是一对的(25和26),会将 192.168.49.2 转发到 minikube 上
从外部访问 minikube 中的 service。
之前一直卡在这里,就是这个镜像的问题,现在速度非常快!
minikube addons enable ingress
默认使用的是 ingress-nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
namespace: test-ns
spec:
rules:
- host: java4ye.test
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-dep
port:
number: 8000
这里我卡了很久,最后不知道怎么的,这个 address 终于有了,一开始一直是空的。
期间的操作包括重新创建 ingress ,以及重启 minikube 等。
果然搭建环境真的很折磨人,有时都不知道这个官方文档到底有没有用的🙃
反正我跟着下面的链接操作了没有效果,最后还是得手动往宿主机的 /etc/hosts 中配置。
https://minikube.sigs.k8s.io/docs/handbook/addons/ingress-dns/
通过 describe 命令查看 ingress
可以看到其中的路由规则。
配置完成后,我们只需要访问 java4ye.test 即可访问到后端的 service,不用再访问 API
再进一步,我们创建一个 my-dep2 标签的 pod,svc,然后修改下 ingress ,同时配置 /etc/hosts 文件,
这时候便可以发现 ingress 的另一个好处了。
在微服务下,可以方便的将各个服务间的请求划分开,代码里也不用写死这个 service 的地址了,用域名就好了。
Ingress 创建成功后,会在 pod 中的 nginx.conf 文件中创建 Server :java4ye.test 和 java4ye2.test,并配置相应的路由规则
接下来就可以通过 UI 直接操作这些 POD 了,比如查看 logs 或者 exec 等命令,方便多了
我是在云服务器上搭建的,所以我先得修改服务器的防火墙,放开 8001 端口
接着利用 kubectl proxy 命令,在 8001 端口上启动代理服务,将请求转发到 10.0.8.8 上的 k8s 的 API Server
注意这里的 address 要改成内网的 IP 地址。不能用 127.0.0.1 的,也不能写 minikube 的地址。
kubectl proxy --port=8001 --address='10.0.8.8' --accept-hosts='^.*'
最后,直接访问云服务器公网 IP + 8001 端口,即可。
kubectl proxy 的更多解释可以看这里 👇
https://loft.sh/blog/when-and-how-to-use-kubectl-proxy/
其实,通过上面的 kubectl proxy ,我们可以有这么一个思路,监听公网某个端口,将它转发到 k8s 的某个service。
比如,利用 nginx,监听某个端口,再根据访问路径的不同进行转发。
这里可选的有 Nginx,HAproxy, Traefik 等等。
听过这个 Traefik 是后起之秀,所以这次我打算用它来实现。(折磨之旅🐷)
https://doc.traefik.io/traefik/
Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them. Traefik是一个开源的边缘路由器,它可以让发布你的服务成为一种有趣而简单的体验。它代表您的系统接收请求,并找出哪些组件负责处理它们。
这个上手也比较简单,所以基本的用法我就不多介绍了。
version: '3'
services:
traefik:
# The official v2 Traefik docker image
image: traefik:v2.9
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker --providers.file.directory=/etc/traefik/conf --api.insecure=true --providers.docker --providers.file.directory=/etc/traefik/conf --log.filePath=/var/log/traefik/traefik.log --log.format=json --log.level=DEBUG --accesslog=true --accesslog.filepath=/var/log/traefik/access.log --accesslog.format=json
ports:
# The HTTP port
- "8002:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
- /home/yang4ye/traefik-docker/conf:/etc/traefik/conf
- /home/yang4ye/logs/traefik:/var/log/traefik
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
networks:
- minikube
extra_hosts:
- "java4ye.test:192.168.49.2"
- "java4ye2.test:192.168.49.2"
networks:
minikube:
external: true
细节注意,这里我们的 minikube 运行在宿主机的 docker 容器中,我们新起的这个 traefik 容器也要和 minikube 容器连接在同一个网络才行,才能互相通信
http:
# Add the router
routers:
router0:
middlewares:
- my-basic-auth
- my-dep-stripPrefixRegex
- myHeader1
service: my-dep
rule: PathPrefix(`/my-dep/`) || PathPrefix(`/my-dep{a:/*$}`)
router1:
middlewares:
- my-dep-stripPrefixRegex
- my-basic-auth
- myHeader2
service: my-dep2
rule: PathPrefix(`/my-dep2/`) || PathPrefix(`/my-dep2{b:/*$}`)
# Add the middleware
middlewares:
my-basic-auth:
basicAuth:
users:
- xxx:$apr1$/bZ/nSB0$xxxxxxxxx/
my-dep-stripPrefixRegex:
stripPrefixRegex:
regex: "/my-dep\\d*"
myHeader1:
headers:
customRequestHeaders:
host: "java4ye.test" # Adds
#X-Custom-Request-Header: "" # Removes
# customResponseHeaders:
# X-Custom-Response-Header: "" # Removes
myHeader2:
headers:
customRequestHeaders:
host: "java4ye2.test"
services:
my-dep:
loadBalancer:
servers:
- url: "http://java4ye.test"
#- url: "http://192.168.49.2:30181"
my-dep2:
loadBalancer:
servers:
# - url: "http://192.168.49.2:30571"
- url: "http://java4ye2.test"
# log 这些是静态的,不能放在动态配置里面,不会有效果
这个配置文件也是不断地修修改改,折磨了两天后,终于成功了!🐖
一开始搭建成功后,出现了一个很神奇的问题。
就是上面配置文件中 service 的 url。
当我用自定义的 域名 时,它一直返回 404 给我 👇
但是如果改成 IP 地址的话,就能正常访问到我们 k8s 中的 service。
此时此刻,我已经把 traefik 的日志文件翻烂了,对比了一遍又一遍,都没看出啥问题。
没办法,我把目光转移到 nginx 容器上,到上面翻看日志时,我又产生了 N 多疑惑,这 404 日志去哪了!
为啥就记录这些 200 的,404 你就不记录了!!(内心在咆哮!)
无奈之下,我把 url 换成 ip 的那种,再多次尝试下,我发现了一个疑点!
可以看到这里 404 的 nginx 是有版本号的!
这时我发现 nginx 容器的 log 也正常记录了这个 404 日志。
我开始怀疑这个请求根本没打到 k8s 容器上。
于是,我脑瓜子一转,不会是 traefik 中用到了 nginx 了吧,我得翻翻它的源码去(佩服自己的脑瓜子🙄,此时此刻我还以为这个 traefik 就是个组装怪,底层用了 nginx,然后加了些 dashboard,集成 k8s ,docker 等等)
在 GitHub 上搜查一番后,发现人家就是用 go 写的,哪有什么 nginx 的影子 🐖
此时,我已经很懵圈了,想不出哪里还有啥问题,甚至把官网和它的论坛翻了又翻,把有关 404 的问题都仔细看了一遍又一遍,差点就在 GitHub 上提 issue 了(要不是步骤有点麻烦🐖)
终于,在刚刚吃根冰棍降降火后,我想到了 ingress
好家伙,这里也是用到了 nginx 的,差点忘了!
我火速来进入到这个容器中,迫不及待的执行了 curl 命令测试下,结果它居然正常返回了。(我不能接受!🐖)
只能去翻翻 ingress 的文档了😮
思路再次中断。
没办法,再吃点零食好了。
突然,我看到了 ingress 的配置文件。
这里指定了这个 host !!
这一刻,我恍然大悟,肯定是 traefik 转发的时候,header 中没有这个 host。
在中间件中把这个 host 补上去
结果终于正常了!😄
这里还有点不顺畅的体验,就是正则表达式的使用(写法比较奇怪),以及路由匹配(没有好例子参考。。而且 Path 和 PathPrefix 的匹配范围不太明确)
正则表达式:
https://regex101.com/r/58sIgx/2
做项目果然是最快的学习方式,有点当年做毕设的感觉 哈哈。(目前打算用之前买的服务器搭建一些项目玩玩,这是小项目的开端,实验成功~)😝
这次实验为:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务。
通过它很好地熟悉了 k8s 中 Deloyment,Service,Pod,Namespace ,Ingress 这些概念。
比如 为啥要用到 Ingress 呢?Service 不就可以访问到 Pod 吗?
这其实涉及到 四层代理和七层代理 的问题,Service 只能代理到 4 层,而这个在我们日常开发中,往往会不够用了,毕竟我们经常得去到应用层 http
Service 通过标签去匹配要 Pod
关于 Service 的更多知识可以看官网
最重要的收获,网络知识
细心的小伙伴会发现,这里不仅仅有 容器间通信 ,还有 pod 间通信 以及 Service 到 Pod 通信
在文中我也简单提到过 桥接,网卡配对,网段 这些东西,但是我感触最大的还是 iptables
了解到它的 四表五链 ,也稍微知道了他们之间通过 nat 表做了目标地址转换等操作
那为啥用 Traefik 呢
这个也很简单,Nginx 配置起来嫌麻烦,openresty 还没用过。 这个 Traefik 用 GO 写的(快~),而且还集成了很多,如 k8s,docker 等等,还有个 dashboard 可以看看,更改一些配置也不用自己重启,挺轻松的用起来,但是后续怎样还得再看看了…… (感觉服务器,网关好多选择)
最痛苦的感悟,看了那么多次日志,无数次看到 host 是空的,但是楞是没想到这个点,这可能就是对这些工具比较陌生,以及没有仔细思考这些配置后面的原理,就跟着傻瓜式CV了,确实有点不应该,浪费了很多时间在这🐖,但是好处也有一点,,就是对官网文档熟悉些了😂 还有顺便把 nginx 的官网也翻熟了🙃
云原生进度+1 🐷
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。