惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
IT之家
IT之家
博客园 - 聂微东
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy International News Feed
人人都是产品经理
人人都是产品经理
PCI Perspectives
PCI Perspectives
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
美团技术团队
S
Secure Thoughts
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
腾讯CDC
Application and Cybersecurity Blog
Application and Cybersecurity Blog
雷峰网
雷峰网
B
Blog
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
TaoSecurity Blog
TaoSecurity Blog
N
News and Events Feed by Topic
Blog — PlanetScale
Blog — PlanetScale
C
Check Point Blog
T
Tailwind CSS Blog
月光博客
月光博客
Simon Willison's Weblog
Simon Willison's Weblog
Hacker News: Ask HN
Hacker News: Ask HN
The Last Watchdog
The Last Watchdog
Google DeepMind News
Google DeepMind News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
MongoDB | Blog
MongoDB | Blog
S
Security @ Cisco Blogs
Jina AI
Jina AI
Engineering at Meta
Engineering at Meta
S
Security Affairs
Forbes - Security
Forbes - Security
P
Palo Alto Networks Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
T
Tor Project blog
O
OpenAI News
L
Lohrmann on Cybersecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More

lvbibir's Blog

shell | 磁盘空间分析脚本 Linux cat 和 tee 命令写入文件 python | 使用 uv 管理你的 python 环境 Claude Code 完整配置指南 windows | mihomo 内核独立部署指南 linux | 磁盘扩容 wsl | 释放长久运行占用的磁盘空间 mysql | 线程上限问题处理 麒麟 7.6 安装谷歌 OTP 认证模块 suse 12sp5 升级 openssh 及 openssl suse 12sp5 部署 mysql 5.7 《谁的青春不迷茫》 docker | centos7 部署 docker vim | 基础配置和使用 windows | rime 输入法 & 雾凇方案 shell | sshpass 批量传输文件及执行命令 wsl | 原生 linux 方式安装 docker nodejs | fnm + pnpm 开发环境配置 wsl | 安装配置 miniconda 虚拟环境 wsl | 自动更新系统代理 wsl | bashrc 环境变量不正确加载的处理方法 wsl | win10 安装 wsl2 troubleshooting | ssh 成功但是 scp 失败 linux | 常用命令总结 docker 部署 piclist shell | 检测网站存活并自动钉钉告警 Zabbix | 监控端口连通性并自动追踪 TCP 路由 windows | 自定义开机快速启动项 windows | miniconda 配置 python 虚拟环境 Zabbix | 监控主机到指定 ip 的流量大小 shell | centos 初始化 loki (二) 部署 loki (一) 简介 prometheus (六) Alertmanager prometheus (五) 记录规则与告警规则 prometheus (四) 黑盒监控 prometheus (三) 服务发现 prometheus (二) 静态配置 prometheus (一) 简介及部署 traefik (四) TraefikService 服务 traefik (三) Middleware 中间件 traefik (二) ingressRoute 路由 traefik (一) 简介、部署和配置 kubernetes | Gateway API 简介及部署 linux | dns 配置文件中 search 和 options ndots 详解 kubernetes | command args 和 dockerfile 中的 ENTRYPOINT CMD kubernetes | statefulset 控制器详解 docker | dockerfile 最佳实践 docker | dockerfile 指令详解 linux | kill 命令详解以及 linux 中的信号 troubleshooting | elasticsearch 安装插件报错 shell | if 条件判断 docker | 下载外网镜像的几种方式 python | 鬼谷子数学问题 steam挂刀教程 linux | history 命令的格式化输出 shell | 将本地镜像批量推送到 harbor windows | hosts 文件修复 kubernetes | configmap & secret kubernetes | RBAC 鉴权和 NetworkPolicy kubernetes | 存储 kubernetes | 滚动升级和自动伸缩 kubernetes | 控制器 kubernetes | 日志 kubernetes | 调度 kubernetes | pod kubernetes | 杂记 linux | set 命令详解 ceph | openeuler 部署 ceph-v16 ceph | ceph-v16 离线安装解决方案 pxe 如何应对复杂的服务器硬件环境 python | 批量修改目录下文件名 《微习惯》 ceph | openeuler (aarch64) 部署 ceph-v16 troubleshooting | glibc 误升级后修复 pxe 安装配置大全 《人间失格》 跑步日常 [置顶] Hello, hugo! shell | 检索某 url 中所有文件的内容 shell | 不同执行方式的区别 shell | 开启 debug 模式 vscode | 常见问题 windows & linux 多网卡时设置默认路由以及添加静态路由 mysql (二) 主从复制原理 GTID 并行复制 mysql (一) 部署 mysql | 杂记 cicd | jenkins 部署 mall-swarm 项目 httpd 源码打包编译成 rpm 包 openssl 源码打包编译成 rpm 包 centos7 | 修改网卡名称 ceph | pool pg_num 配置 docker | 脚本方式批量导出/导入镜像 centos 密码尝试次数过多问题处理 centos7 | 升级内核至 5.10 CVE-1999-0526 ceph | centos7 部署 ceph-v12 python | 修改 pip 源 troubleshooting | 安装 cloud-init 后导致 ssh 连接失败 windows | autohotkey 常用脚本
kubernetes | service & ingress
lvbibir · 2022-10-07 · via lvbibir's Blog

0 前言

基于 centos7.9docker-ce-20.10.18kubelet-1.22.3-0

1.1 基本概念

service 存在的意义

  • 服务发现:防止 Pod 失联
  • 负载均衡:定义一组 Pod 的访问策略

service 通过 label-selector 关联 pod

service 的三种类型

  • ClusterIP:集群内部使用

    • 默认,分配一个稳定的 IP 地址,即 VIP,只能在集群内部访问(同 Namespace 内的 Pod)
  • NodePort:对外暴露应用

    • 在每个节点上启用一个端口 (30000-32767) 来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群 IP 地址。
  • LoadBalancer:对外暴露应用,适用公有云

    与 NodePort 类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes 会请求底层云平台上的负载均衡器,将每个 Node([NodeIP]:[NodePort])作为后端添加进去。

示例

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
    - protocol: TCP
      port: 80 # service端口,内部访问端口
      targetPort: 80 # 后端业务镜像实际暴露的端口
      nodePort: 30002 # 内部访问端口映射到节点端口
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.22.1
        ports:
        - containerPort: 80

1.2 代理模式

Iptables:

  • 灵活,功能强大
  • 规则遍历匹配和更新,呈线性时延

IPVS:

  • 工作在内核态,有更好的性能
  • 调度算法丰富:rr,wrr,lc,wlc,ip hash…

image-20221005090953888

1.2.1 iptables 模式

使用 iptables 模式时,根据 iptables 的 --mode random --probability 来匹配每一条请求,每个 pod 收到的流量趋近于平衡,不是完全的轮询

这种模式,kube-proxy 会监听 Kubernetes 对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会安装 iptables 规则,从而捕获到达该 ServiceclusterIP 和端口的请求,进而将请求重定向到 Service 任意一组 backend pod 中。对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend pod 组合。

k8s 默认采用的代理模式是 iptables,可以通过查看 kube-proxy 组件的日志可得

[root@k8s-node1 ~]# kubectl logs kube-proxy-8mf2l -n kube-system  | grep Using
I0412 02:02:29.634610       1 server_others.go:212] Using iptables Proxier.

创建一个上述示例中的 yaml ,查看 iptables 规则

[root@k8s-node1 ~]# kubectl get svc nginx
NAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.105.220.154   <none>        80:30002/TCP   4m40s

# SVC当前共关联三个POD
[root@k8s-node1 ~]# kubectl get pod -o wide -l app=nginx
NAME                    READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
nginx-55f4d8c85-l29wx   1/1     Running   0          4m57s   10.244.169.133   k8s-node2   <none>           <none>
nginx-55f4d8c85-lf5dj   1/1     Running   0          4m57s   10.244.107.205   k8s-node3   <none>           <none>
nginx-55f4d8c85-q4gsx   1/1     Running   0          4m57s   10.244.107.203   k8s-node3   <none>           <none>

[root@k8s-node1 ~]# iptables-save |grep -i nodeport |grep 30002
# NODEPORTS 根据端口将流量转发到 SVC 链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx" -m tcp --dport 30002 -j KUBE-SVC-2CMXP7HKUVJN7L6M

[root@k8s-node1 ~]# iptables-save |grep KUBE-SVC-2CMXP7HKUVJN7L6M
# ClusterIP 相关
-A KUBE-SERVICES -d 10.109.98.33/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M
# 转发到具体 POD 链,每条 POD 链都有一样的概率获取到流量
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-ONLOYCYPTBL5FQH5
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-JABTJNSPARJARZOW
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -j KUBE-SEP-TZBGLRHUI2CFM5CU

# POD链中定义了转发到具体的POD地址,
[root@k8s-node1 ~]# iptables-save |grep KUBE-SEP-ONLOYCYPTBL5FQH5
-A KUBE-SEP-ONLOYCYPTBL5FQH5 -s 10.244.107.252/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-ONLOYCYPTBL5FQH5 -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.107.252:80
[root@k8s-node1 ~]# iptables-save |grep KUBE-SEP-JABTJNSPARJARZOW
-A KUBE-SEP-JABTJNSPARJARZOW -s 10.244.169.135/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-JABTJNSPARJARZOW -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.169.135:80
[root@k8s-node1 ~]# iptables-save |grep KUBE-SEP-TZBGLRHUI2CFM5CU
-A KUBE-SEP-TZBGLRHUI2CFM5CU -s 10.244.169.136/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-TZBGLRHUI2CFM5CU -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.169.136:80

1.2.2 ipvs 模式

ipvsadm 安装配置 (所有节点都要配置)

[root@k8s-node1 ~]# yum install ipvsadm
[root@k8s-node1 ~]# cat > /etc/sysconfig/modules/ipvs.modules << EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
[root@k8s-node1 ~]# chmod 755 /etc/sysconfig/modules/ipvs.modules
[root@k8s-node1 ~]# source /etc/sysconfig/modules/ipvs.modules

修改 service 使用的代理模式为 ipvs

[root@k8s-node1 ~]# kubectl edit configmap kube-proxy -n kube-system
    mode: "ipvs"
    ipvs:
      scheduler: "rr" #rr, wrr, lc, wlc, ip hash等

# 删除所有 kube-proxy,k8s 会重新创建
[root@k8s-node1 ~]# kubectl delete pod -n kube-system -l k8s-app=kube-proxy
[root@k8s-node1 ~]# kubectl logs kube-proxy-8z86w -n kube-system | grep Using
I0412 08:30:21.169231       1 server_others.go:274] Using ipvs Proxier.

查看 ipvs 规则

[root@k8s-node1 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:30002 rr
  -> 10.244.107.252:80            Masq    1      0          0
  -> 10.244.169.135:80            Masq    1      0          0
  -> 10.244.169.136:80            Masq    1      0          0
TCP  1.1.1.1:30002 rr
  -> 10.244.107.252:80            Masq    1      0          0
  -> 10.244.169.135:80            Masq    1      0          0
  -> 10.244.169.136:80            Masq    1      0          0
TCP  10.244.36.64:30002 rr
  -> 10.244.107.252:80            Masq    1      0          0
  -> 10.244.169.135:80            Masq    1      0          0
  -> 10.244.169.136:80            Masq    1      0          0
TCP  10.109.98.33:80 rr
  -> 10.244.107.252:80            Masq    1      0          0
  -> 10.244.169.135:80            Masq    1      0          0
  -> 10.244.169.136:80            Masq    1      0          0

2 Headless Service

Headless Service 相比普通 Service 只是将 spec.clusterIP 定义为 None

Headless Service 几大特点:

  • 不分配 clusterIP

  • 没有负载均衡的功能 (kube-proxy 不会安装 iptables 规则)

  • 可以通过解析 service 的 DNS,返回所有 Pod 的 IP 和 DNS (statefulSet 部署的 Pod 才有 DNS)

    [root@k8s-node1 ~]# kubectl run -it --rm --restart=Never --image busybox:1.28  dns-test -- nslookup statefulset-nginx.default.svc.cluster.local
    Server:    10.96.0.10
    Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
    
    Name:      statefulset-nginx.default.svc.cluster.local
    Address 1: 10.244.107.200 statefulset-nginx-1.statefulset-nginx.default.svc.cluster.local
    Address 2: 10.244.169.188 statefulset-nginx-0.statefulset-nginx.default.svc.cluster.local
    pod "dns-test" deleted
    

Headless Services 应用场景

  1. 自主选择权,client 可以通过查询 DNS 来获取 Real Server 的信息,自己来决定使用哪个 Real Server
  2. Headless Service 的对应的每一个 Endpoints,即每一个 Pod,都会有对应的 DNS域名,这样 Pod 之间就可以互相访问

DNS 解析名称:

  • pod:<pod-name>.<service-name>.<namespace>.svc.cluster.local
  • service: <service-name>.<namespace>.svc.cluster.local

3 Ingress

3.1 基本概念

NodePort 的不足

  • 一个端口只能一个服务使用,端口需提前规划
  • 只支持 4 层负载均衡

Ingress 是什么?

Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。流量路由由 Ingress 资源上定义的规则控制。

下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:

image-20221005140153771

Ingress Controller

Ingress 管理的负载均衡器,为集群提供全局的负载均衡能力。

Ingress Contronler 怎么工作的?

Ingress Contronler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个 service,生成一段 Nginx 配置,应用到管理的 Nginx 服务,然后热加载生效。

以此来达到 Nginx 负载均衡器配置及动态更新的问题

使用流程:

  1. 部署 Ingress Controller
  2. 创建 Ingress 规则

image-20221005141711017

Ingress Contorller 主流控制器:

  • ingress-nginx-controller: nginx 官方维护的控制器
  • Traefik: HTTP 反向代理、负载均衡工具
  • Istio:服务治理,控制入口流量

这里使用 Nginx 官方维护的,项目地址

3.2 安装部署

下载 yaml 文件

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/baremetal/1.22/deploy.yaml --no-check-certificate

修改

# 修改kind, 将原先的Deployment修改为DaemontSet,实现所有物理节点访问
kind: DaemonSet 
spec:
  template:
    spec:
      # 新增 hostNetwork, 将ingress-nginx-controller的端口直接暴露在宿主机上
      hostNetwork: true 
      containers:
        # 修改 image 为国内地址
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0 
      # 新增污点容忍,允许在 master 节点创建pod
      tolerations: 
      - key: "node-role.kubernetes.io/master"
        operator: "Exists"
        effect: "NoSchedule"
---
kind: Job
spec:
  template:
    spec:
      containers:
        # 修改 image 为国内地址
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
---
kind: Job
spec:
  template:
    spec:
      containers:
        # 修改 image 为国内地址
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1

部署

[root@k8s-node1 ~]# kubectl apply -f deploy.yaml

[root@k8s-node1 opt]# kubectl get pods -n ingress-nginx -o wide
NAME                                      READY   STATUS      RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create--1-zfwrz   0/1     Completed   0          12m   10.244.169.135   k8s-node2   <none>           <none>
ingress-nginx-admission-patch--1-8rhjr    0/1     Completed   0          12m   10.244.169.134   k8s-node2   <none>           <none>
ingress-nginx-controller-bb2kd            1/1     Running     0          12m   1.1.1.3          k8s-node3   <none>           <none>
ingress-nginx-controller-bp588            1/1     Running     0          12m   1.1.1.2          k8s-node2   <none>           <none>
ingress-nginx-controller-z2782            1/1     Running     0          12m   1.1.1.1          k8s-node1   <none>           <none>

# 如果出现内部访问报错:failed calling webhook "validate.nginx.ingress.kubernetes.io"
[root@k8s-node1 ~]# kubectl get ValidatingWebhookConfiguration
[root@k8s-node1 ~]# kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

3.3 测试

测试 url 跳转,创建三套 nginx 应用 : test | foo | bar

需要注意的是,代理路径假如是 /foo 的话,后端真实路径也是 /foo

test 应用示例,foo 和 bar 的自行修改

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
  labels:
    app: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      terminationGracePeriodSeconds: 5
      containers:
      - name: test
        image: nginx:1.22.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html/
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: pvc-test
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-test
spec:
  storageClassName: "nfs"
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: test
  labels:
    app: test
spec:
  selector:
    app: test
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

创建 ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-nginx
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: test.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: foo
            port:
              number: 80
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: bar
            port:
              number: 80

查看创建的 ingress

[root@k8s-node1 ~]# kubectl describe ingress demo-nginx
Name:             demo-nginx
Namespace:        default
Address:          1.1.1.1,1.1.1.2,1.1.1.3
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host        Path  Backends
  ----        ----  --------
  test.com
              /      test:80 (10.244.107.209:80,10.244.107.212:80,10.244.169.140:80)
              /foo   foo:80 (10.244.107.210:80,10.244.169.138:80,10.244.169.144:80)
              /bar   bar:80 (10.244.107.211:80,10.244.169.131:80,10.244.169.143:80)
Annotations:  kubernetes.io/ingress.class: nginx
Events:       <none>

修改 index.html

[root@k8s-node1 ~]# echo "test" > /nfs/default-pvc-test-pvc-93a7df14-90f2-4466-8655-6ef42549b760/index.html
[root@k8s-node1 ~]# mkdir /nfs/default-pvc-foo-pvc-75e73500-1a70-4305-8253-d1e7d8c88b49/foo
[root@k8s-node1 ~]# echo "foo" > /nfs/default-pvc-foo-pvc-75e73500-1a70-4305-8253-d1e7d8c88b49/foo/index.html
[root@k8s-node1 ~]# mkdir /nfs/default-pvc-bar-pvc-73d12b15-7c53-46ee-a1b6-d0cb2c25e7e6/bar/
[root@k8s-node1 ~]# echo "bar" > /nfs/default-pvc-bar-pvc-73d12b15-7c53-46ee-a1b6-d0cb2c25e7e6/bar/index.html

访问测试

[root@k8s-node1 ~]# curl http://1.1.1.1/ -H "Host: test.com"
test
[root@k8s-node1 ~]# curl http://1.1.1.2/foo/ -H "Host: test.com"
foo
[root@k8s-node1 ~]# curl http://1.1.1.3/bar/ -H "Host: test.com"
bar

以上