前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我掌握的新兴技术:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务

我掌握的新兴技术:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务

原创
作者头像
Java4ye
发布2024-02-04 09:33:15
4281
发布2024-02-04 09:33:15
举报
文章被收录于专栏:云原生云原生

小伙伴们好呀,这篇文章记录了本次的小实验:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务

阅读的话,可以重点看看 3个 流程解析 以及文末的收获

k8s 搭建

国外镜像太慢了,特别是 google 和 docker 有竞争,不把镜像弄到 docker hub 上,下载真的特别麻烦。

用云服务

代码语言:sh
复制
minikube start --image-mirror-country='cn'

创建 ns,deployment,svc

ns.yaml
代码语言:yaml
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns
deployment.yaml
代码语言:yaml
复制
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
svc.yaml
代码语言:yaml
复制
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。

流程解析1

ingress

之前一直卡在这里,就是这个镜像的问题,现在速度非常快!

代码语言:sh
复制
minikube addons enable ingress

默认使用的是 ingress-nginx

ingress-demo.yaml
代码语言:yaml
复制
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 的地址了,用域名就好了。

流程解析2

底层

Ingress 创建成功后,会在 pod 中的 nginx.conf 文件中创建 Server :java4ye.test 和 java4ye2.test,并配置相应的路由规则

k8s dashboard

接下来就可以通过 UI 直接操作这些 POD 了,比如查看 logs 或者 exec 等命令,方便多了

暴露到外网

我是在云服务器上搭建的,所以我先得修改服务器的防火墙,放开 8001 端口

接着利用 kubectl proxy 命令,在 8001 端口上启动代理服务,将请求转发到 10.0.8.8 上的 k8s 的 API Server

注意这里的 address 要改成内网的 IP 地址。不能用 127.0.0.1 的,也不能写 minikube 的地址。

代码语言:ssh
复制
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/

那怎么将 minikube 中的 service 暴露到公网上呢

其实,通过上面的 kubectl proxy ,我们可以有这么一个思路,监听公网某个端口,将它转发到 k8s 的某个service。

比如,利用 nginx,监听某个端口,再根据访问路径的不同进行转发。

这里可选的有 Nginx,HAproxy, Traefik 等等。

听过这个 Traefik 是后起之秀,所以这次我打算用它来实现。(折磨之旅🐷)

https://docs.traefik.cn/

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是一个开源的边缘路由器,它可以让发布你的服务成为一种有趣而简单的体验。它代表您的系统接收请求,并找出哪些组件负责处理它们。

这个上手也比较简单,所以基本的用法我就不多介绍了。

docker compose 文件
代码语言:dockerfile
复制
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 容器连接在同一个网络才行,才能互相通信

yaml 配置文件
代码语言:yaml
复制
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 这些是静态的,不能放在动态配置里面,不会有效果

这个配置文件也是不断地修修改改,折磨了两天后,终于成功了!🐖

bug 折磨我的过程

一开始搭建成功后,出现了一个很神奇的问题。

就是上面配置文件中 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

流程解析3

收获

做项目果然是最快的学习方式,有点当年做毕设的感觉 哈哈。(目前打算用之前买的服务器搭建一些项目玩玩,这是小项目的开端,实验成功~)😝

这次实验为:用 k8s+Ingress+Traefik 搭建一个外网可以访问的 Web 服务

通过它很好地熟悉了 k8s 中 Deloyment,Service,Pod,Namespace ,Ingress 这些概念。

比如 为啥要用到 Ingress 呢?Service 不就可以访问到 Pod 吗

这其实涉及到 四层代理和七层代理 的问题,Service 只能代理到 4 层,而这个在我们日常开发中,往往会不够用了,毕竟我们经常得去到应用层 http

Service 通过标签去匹配要 Pod

关于 Service 的更多知识可以看官网

https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

最重要的收获,网络知识

细心的小伙伴会发现,这里不仅仅有 容器间通信 ,还有 pod 间通信 以及 Service 到 Pod 通信

在文中我也简单提到过 桥接,网卡配对,网段 这些东西,但是我感触最大的还是 iptables

了解到它的 四表五链 ,也稍微知道了他们之间通过 nat 表做了目标地址转换等操作

那为啥用 Traefik 呢

这个也很简单,Nginx 配置起来嫌麻烦,openresty 还没用过。 这个 Traefik 用 GO 写的(快~),而且还集成了很多,如 k8s,docker 等等,还有个 dashboard 可以看看,更改一些配置也不用自己重启,挺轻松的用起来,但是后续怎样还得再看看了…… (感觉服务器,网关好多选择)

最痛苦的感悟,看了那么多次日志,无数次看到 host 是空的,但是楞是没想到这个点,这可能就是对这些工具比较陌生,以及没有仔细思考这些配置后面的原理,就跟着傻瓜式CV了,确实有点不应该,浪费了很多时间在这🐖,但是好处也有一点,,就是对官网文档熟悉些了😂 还有顺便把 nginx 的官网也翻熟了🙃

云原生进度+1 🐷

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • k8s 搭建
    • ns.yaml
      • deployment.yaml
        • svc.yaml
        • 流程解析1
        • ingress
          • ingress-demo.yaml
          • 流程解析2
            • 底层
            • k8s dashboard
            • 暴露到外网
            • 那怎么将 minikube 中的 service 暴露到公网上呢
            • Traefik
              • docker compose 文件
                • yaml 配置文件
                • bug 折磨我的过程
                • 流程解析3
                • 收获
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档