Service资源对象的作用

  • 服务发现(发现一组提供了相同服务的Pod):标签选择器,在同一namespace中筛选符合的条件的Pod
    实际上并非由Service资源自己完成,而是借助于另一种称为Endpoints/EndpointSlice完成的;
  • 负载均衡(Service作为流量入口和负载均衡器,其入口为ClusterIP):这组筛选出的Pod的IP地址,将作为该Service的后端服务器;
  • 为该组Pod所代表的服务提供一个名称:依赖于Cluster DNS,对于每个Service,自动生成一个A、PTR和SRV记录

Service资源对象的四种类型

CLusterIP : 集群内部通信类型,默认
ExternalName :通过指定名称从集群内访问集群外部资源
NodePort:通过暴漏节点IP:Port使外面可以访问到集群内的服务
LoadBalancer:云厂商使用的负载均衡器,可通过metallb和openelb来模拟
# 特殊配置项,流量策略
externalTrafficPolicy:
    Cluster: Service会将流量调度至任何一个可用后端Pod之上,而不关心Pod运行于哪个节点
    Local: 外部LB,只能把流量转发给运行有该Service关联的Pod的Node之上;

ClusterIP类型Service示例:

kind: Service
apiVersion: v1
metadata:
  name: demoapp-svc
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: demoapp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80

NodePort其实是个增强版本的ClusterIP
NodePort类型的Service示例:

kind: Service
apiVersion: v1
metadata:
  name: demoapp-nodeport-svc
spec:
  type: NodePort
  selector:
    app: demoapp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 31398
  externalTrafficPolicy: Local # 或者Cluster

LoadBalancer是个增强版的NodePort
LoadBalancer类型Service示例:

kind: Service
apiVersion: v1
metadata:
  name: demoapp-loadbalancer-svc
spec:
  type: LoadBalancer
  selector:
    app: demoapp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80

ExternalName类型的Service示例

kind: Service
apiVersion: v1
metadata:
  name: externalname-redis-svc
  namespace: default
spec:
  type: ExternalName
  externalName: redis.haogedu.com
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
    nodePort: 0
  selector: {}

Service的名称解析 ClusterDNS(CoreDNS)

Cluster DNS(CoreDNS)是Kubernetes集群的必备附件,负责为Kubernetes提供名称解析和服务发现
每个Service资源对象,在CoreDNS上都会自动生成一个遵循“..svc.”格式的名称,k8s默认的域名后缀为cluster.local,全路径域名即为:..svc.cluster.local

示例:

# 登录到pod容器内部,执行域名解析,查看域名解析记录结果:
host -t A demoapp-svc
demoapp.default.svc.cluster.local has address 10.110.19.16
# 反向解析,IP反解为name
host -t PTR 10.110.19.16
16.19.110.10.in-addr.arpa domain name pointer demoapp.default.svc.cluster.local.

Pod上的DNS解析策略

Kubernetes支持在单个Pod资源规范上自定义DNS解析策略和配置,并组合生效

  • spec.dnsPolicy:解析策略
  • spec.dnsConfig:名称解析机制

解析策略

  • Default:从运行在的节点继承DNS名称解析相关的配置
  • ClusterFirst:于集群DNS服务上解析集群域内的名称,其他域名的解析则交由从节点继承而来的上游名称服务器
  • ClusterFirstWithHostNet:专用于在设置了hostNetwork的Pod对象上使用的ClusterFirst策略
  • None:用于忽略Kubernetes集群的默认设定,而仅使用由dnsConfig自定义的配置

名称解析机制

  • nameservers <[]string>:DNS名称服务器列表,附加于由dnsPolicy生成的DNS名称服务器之后
  • searches <[]string>:DNS名称解析时的搜索域,附加由于dnsPolicy生成的搜索域之后
  • options <[]Object>:DNS解析选项列表,同dnsPolicy生成的解析选项合并成最终生效的定义

示例(自定义名称解析机制):

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-dnspolicy
  namespace: default
spec:
  containers:
  - name: demo
    image: ikubernetes/demoapp:v1.0
    imagePullPolicy: IfNotPresent
  dnsPolicy: None
  dnsConfig:
    nameservers:
    - 10.96.0.10
    - 223.5.5.5
    - 223.6.6.6
    searches:
    - svc.cluster.local
    - cluster.local
    - ilinux.io
    options:
    - name: ndots
      value: "5"

Headless Service(无头服务)

Service的各类型中,ClusterIP、NodePort和LoadBalancer都为其Service配置一个ClusterIP,CoreDNS上,这些Service对象的A记录也解析为它的ClusterIP
那些没有ClusterIP的Service则称为Headless Service,它们又可以为分两种情形

  1. 有标签选择器,或者没有标签选择器,但有着与Service对象同名的Endpoint资源
    Service的DNS名称直接解析为后端各就绪状态的Pod的IP地址
    调度功能也将由DNS完成
    各Pod IP相关PTR记录将解析至Pod自身的名称,假设Pod IP为a.b.c.d,则其名称为a-b-c-d...svc.
    这种类型也就是狭义上的Headless Service
  2. 无标签选择器且也没有与Service对象同名的Endpoint资源
    Service的DNS名称将会生成一条CNAME记录,对应值由Service对象上的spec.externalName字段指定

External Service示例:

kind: Service
apiVersion: v1
metadata:
  name: externalname-redis-svc
  namespace: default
spec:
  type: ExternalName
  externalName: redis.haogedu.com
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
    nodePort: 0
  selector: {}

Headless Service示例

kind: Service
apiVersion: v1
metadata:
  name: demoapp-headless-svc
spec:
  clusterIP: None
  selector:
    app: demoapp
  ports:
  - port: 80
    targetPort: 80
    name: http

示例svc通过endpoint访问外部集群外部服务:

apiVersion: v1
kind: Endpoints
metadata:
  name: mysql-external
  namespace: default
subsets:
- addresses:
  - ip: 172.29.9.51
  - ip: 172.29.9.52
  ports:
  - name: mysql
    port: 3306
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-external
  namespace: default
spec:
  type: ClusterIP
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306
    protocol: TCP

CoreDNS配置

CoreDNS的配置都存储在名为coredns的ConfigMap对象中,该对象位于kube-system名称空间中

kubectl get cm -n kube-system coredns -o yaml
apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
           lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf {
           max_concurrent 1000
        }
        cache 30 {
           disable success cluster.local
           disable denial cluster.local
        }
        loop
        reload
        loadbalance
    }
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system

CoreDNS上常用的插件简介

插件名称 插件功能
errors 启用错误日志
health 启用CoreDNS进程自身的健康状态检测功能,默认的端点为8080端口上的/health,路径/health固定,但可使用自定义的套接字,例如“health localhost:8081”
ready 启用CoreDNS进程自身的就绪状态报告功能,默认的端点为8181端口上的/ready,路径/ready固定,但可使用自定义的套接字,例如“health localhost:8082”
kubernetes 用于从kubernetes集群加载区域解析相关的数据,从而为Kubernetes集群提供内部服务解析功能
prometheus 启用CoreDNS内置的Prometheus格式的指标,默认的端点为8181端口上的/metrics”,路径/metrics固定,但可使用自定义的套接字,例如“health localhost:8083”
forward(或proxy) 将DNS名称查询请求转发给指定的其它DNS服务器;Kubernetes CoreDNS 默认配置中的forward指令能够将对所有域名的查询请求转发给(宿主机的)/etc/resolv.conf文件中指定的DNS服务器
cache 启用对DNS查询结果的缓存功能;查询结果来自后端服务且开销较高时能产生高价值;默认缓存时长为3600s
loop 启用DNS查询过程中的环路检测功能,该插件会在检测到环路时停止查询操作
reload 允许自动重载更改的Corefile配置
loadbalance 基于随机算法,为A、AAAA或MX类型的资源记录的多条查询结果上启用负载均衡功能
hosts 使用类似于/etc/hosts网格的文件格式提供区域解析数据,仅支持A、AAAA和PTR记录类型
bind 为服务器配置段指定要监听的IP地址或网络接口,格式为“bind ADDRESS

CoreDNS查询路由概述

  • CoreDNS处理DNS查询的方式
    1、针对每个套接字,CoreDNS会生成一个服务器(dnsserver.Server)
    2、一个套接字上存在多个配置段(Server Block)时,CoreDNS将组合这些配置段生成单个服务器上的多个独立配置段,并将发往该套接字的DNS查询请求路由到最佳匹配的目标配置段
    3、若不存在匹配的服务器配置段,则返回SERVERFAIL
  • CoreDNS的插件可大致分为两类
    1、负责处理请求的常规插件(Normal Plugin),这些插件才是插件链中的有效组成部分,例如errors、kubernetes和forward等
    2、不处理请求的特殊插件,它们仅用来修改Server或Server Block中的配置,例如health、tls、startup、shutdown和root等插件,这类插件不会作为服务器配置段的插件链中的有效组成部署
  • 常规插件可再次划分为两种类型
    1、负责以某种方式处理请求的插件
      这类插件不是区域数据源,它们的运行方式是在自身处理完成后,会将查询传递给下一个插件
    2、后端插件
      用于配置区域数据的来源,例如etcd、file和kubernetes等
      这类插件通常要为其负责的区域生成最终结果,它要么能正常响应查询,要么返回NXDOMAIN
      但也可以使用fallthrough改变这种响应行为:未发现查询的目标资源记录时,将DNS查询请求转交给插件链中的下一个插件,随后终结于另一个后端插件,或再次由fallthrought改变这种行为

CoreDNS查询路由示例

coredns.io:5300 {
    file /etc/coredns/zones/coredns.io.db
}
magedu.com:53 {
    errors
    log
    file /etc/coredns/zones/magedu.com.db
}
magedu.net:53 {
    file /etc/coredns/zones/magedu.net.db
}

.:53 {
  errors
  log
  health
  rewrite name jenkins.haoge.com jenkins.jenkins.svc.cluster.local
  kubernetes cluster.local 10.244.0.0/16
  file /etc/coredns/haoge.db haoge.org
  forward . /etc/resolv.conf
  cache 30
}

CoreDNS的kuberntes插件
插件的配置参数简介

插件名称 插件功能
endpoint 指定kubernetes API Server的URL,默认为CoreDNS Pod所使用的ServiceAccount可接入的自身所在集群的API Server
tls 用于建立远程k8s连接时要使用的tls证书、私钥和CA证书
kubeconfig 用于谁到远程k8s时使用的kubeconfig文件
namespaces 仅对外暴露(提供Service名称解析)的k8s名称空间的列表,默认为所有名称空间
labels namespace资源对象的标签选择器,匹配到的namespace中的Service才会对外暴露
pods 为Pod生成基于IP的资源记录时的处理模式,disabled:不处理Pod级别的名称解析请求,默认配置;insecure:不检查k8s,而直接返回一个带有IP地址的A记录;verified:若同一namespace中存在具有匹配的IP地址的Pod,则返回A记录
noendpoints 禁止endpoint相关的资源记录,所有endpoint查询和headless查询都将生成NXDOMAIN
fallthrough 若当前插件解析失败,则仅将针对指定zone列表中的查询请求继续交由插件链中后续的插件进行处理
ignore empty_service 为没有任何就绪的Service返回NXDOMAIN

CoreDNS的rewrite插件
在CoreDNS内部对查询及响应进行重写,重写过程对客户端透明
语法:rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
一般来说,重写查询的name比较常见

# 语法:rewrite [continue|stop] name [exact|prefix|suffix|substring|regex] STRING STRING [OPTIONS]
示例(1):
rewrite name regex (jenkins.*)\.haoge\.com {1}.jenkins.svc.cluster.local
隐式的响应重写,可以定义在rewrite name规则的OPTIONS中
 rewrite name regex (jenkins.*)\.haoge\.com {1}.jenkins.svc.cluster.local answer auto
显式报文重写,要使用明确定义的answer规则进行
rewrite stop {
  name regex (jenkins.*)\.haoge\.com {1}.jenkins.svc.cluster.local
  answer name (jenkins.*)\.jenkins.\.svc\.cluster\.local {1}.haoge.com
}

CoreDNS配置示例(自定义hosts风格解析库):

Corefile: |
  .:53 {
    errors
    health {
      lameduck 15s
    }
    ready
    hosts {
      192.168.139.20 k8s-master01.haoge.com
      192.168.139.23 k8s-node01.haoge.com
      192.168.139.24 k8s-node02.haoge.com
      fallthrough
    }
    kubernetes cluster.local in-addr.arpa ip6.arpa {
      pods insecure
      fallthrough in-addr.arpa ip6.arpa
      ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf {
      prefer_udp
    }
    cache 30
    loop
    reload
    loadbalance
}

CoreDNS配置示例(将外部域名的解析全部交由指定的外部DNS服务器):

Corefile: |
  .:53 {
    errors
    health {
      lameduck 15s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
      pods insecure
      fallthrough in-addr.arpa ip6.arpa
      ttl 30
    }
    prometheus :9153
    forward . 172.29.9.252 172.29.9.253{
      prefer_udp
    }
    cache 30
    loop
    reload
    loadbalance
}
作者:于浩  创建时间:2025-06-05 13:40
最后编辑:于浩  更新时间:2025-06-10 18:08