learn.lianglianglee.com/专栏/Kubernetes 实践入门指南/11 服务发现 DNS 的落地实践.md.html
2022-05-11 18:52:13 +08:00

817 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>11 服务发现 DNS 的落地实践.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/Kubernetes 实践入门指南/00 为什么我们要学习 Kubernetes 技术.md">00 为什么我们要学习 Kubernetes 技术.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/01 重新认识 Kubernetes 的核心组件.md">01 重新认识 Kubernetes 的核心组件.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/02 深入理解 Kubernets 的编排对象.md">02 深入理解 Kubernets 的编排对象.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/03 DevOps 场景下落地 K8s 的困难分析.md">03 DevOps 场景下落地 K8s 的困难分析.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/04 微服务应用场景下落地 K8s 的困难分析.md">04 微服务应用场景下落地 K8s 的困难分析.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/05 解决 K8s 落地难题的方法论提炼.md">05 解决 K8s 落地难题的方法论提炼.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/06 练习篇K8s 核心实践知识掌握.md">06 练习篇K8s 核心实践知识掌握.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/07 容器引擎 containerd 落地实践.md">07 容器引擎 containerd 落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/08 K8s 集群安装工具 kubeadm 的落地实践.md">08 K8s 集群安装工具 kubeadm 的落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/09 南北向流量组件 IPVS 的落地实践.md">09 南北向流量组件 IPVS 的落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/10 东西向流量组件 Calico 的落地实践.md">10 东西向流量组件 Calico 的落地实践.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/Kubernetes 实践入门指南/11 服务发现 DNS 的落地实践.md">11 服务发现 DNS 的落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/12 练习篇K8s 集群配置测验.md">12 练习篇K8s 集群配置测验.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/13 理解对方暴露服务的对象 Ingress 和 Service.md">13 理解对方暴露服务的对象 Ingress 和 Service.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/14 应用网关 OpenResty 对接 K8s 实践.md">14 应用网关 OpenResty 对接 K8s 实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/15 Service 层引流技术实践.md">15 Service 层引流技术实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/16 Cilium 容器网络的落地实践.md">16 Cilium 容器网络的落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/17 应用流量的优雅无损切换实践.md">17 应用流量的优雅无损切换实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/18 练习篇:应用流量无损切换技术测验.md">18 练习篇:应用流量无损切换技术测验.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/19 使用 Rook 构建生产可用存储环境实践.md">19 使用 Rook 构建生产可用存储环境实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/20 有状态应用的默认特性落地分析.md">20 有状态应用的默认特性落地分析.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/21 案例:分布式 MySQL 集群工具 Vitess 实践分析.md">21 案例:分布式 MySQL 集群工具 Vitess 实践分析.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/22 存储对象 PV、PVC、Storage Classes 的管理落地实践.md">22 存储对象 PV、PVC、Storage Classes 的管理落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/23 K8s 集群中存储对象灾备的落地实践.md">23 K8s 集群中存储对象灾备的落地实践.md.html</a>
</li>
<li>
<a href="/专栏/Kubernetes 实践入门指南/24 练习篇K8s 集群配置测验.md">24 练习篇K8s 集群配置测验.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>11 服务发现 DNS 的落地实践</h1>
<p>DNS 服务是 Kubernetes 内置的服务发现组件,它方便容器服务可以通过发布的唯一 App 名字找到对方的端口服务,再也不需要维护服务对应的 IP 关系。这个对传统企业内部的运维习惯也是有一些变革的。一般传统企业内部都会维护一套 CMDB 系统,专门来维护服务器和 IP 地址的对应关系,方便规划管理好应用服务集群。当落地 K8s 集群之后,因为应用容器的 IP 生命周期短暂,通过 App 名字来识别服务其实对运维和开发都会更方便。所以本篇就是结合实际的需求场景给大家详细介绍 DNS 的使用实践。</p>
<h3>CoreDNS 介绍</h3>
<p>Kubernetes 早期的 DNS 组件叫 KubeDNS。CNCF 社区后来引入了更加成熟的开源项目 CoreDNS 替换了 KubeDNS。所以我们现在提到 KubeDNS其实默认指代的是 CoreDNS 项目。在 Kubernetes 中部署 CoreDNS 作为集群内的 DNS 服务有很多种方式,例如可以使用官方 Helm Chart 库中的 Helm Chart 部署,具体可查看 <a href="https://github.com/helm/charts/tree/master/stable/coredns">CoreDNS Helm Chart</a></p>
<pre><code>$ helm install --name coredns --namespace=kube-system stable/coredns
</code></pre>
<p>查看 coredns 的 Pod确认所有 Pod 都处于 Running 状态:</p>
<pre><code>kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-699477c54d-9fsl2 1/1 Running 0 5m
coredns-699477c54d-d6tb2 1/1 Running 0 5m
coredns-699477c54d-qh54v 1/1 Running 0 5m
coredns-699477c54d-vvqj9 1/1 Running 0 5m
coredns-699477c54d-xcv8h 1/1 Running 0 6m
</code></pre>
<p>测试一下 DNS 功能是否好用:</p>
<pre><code>kubectl run curl --image=radial/busyboxplus:curl -i --tty
nslookup kubernetes.default
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
</code></pre>
<h3>服务发现规则</h3>
<p>DNS 支持的服务发现是支持 Service 和 Pod 的。它的规则如下。</p>
<h4><strong>Services</strong></h4>
<p>A 记录:</p>
<ul>
<li>Serviceheadless Service 除外)将被分配一个 DNS A 记录,格式为 my-svc.my-namespace.svc.cluster.local。该 DNS 记录解析到 Service 的 ClusterIP。</li>
<li>Headless Service没有 ClusterIP也将被分配一个 DNS A 记录,格式为 my-svc.my-namespace.svc.cluster.local。该 DNS 记录解析到 Service 所选中的一组 Pod 的 IP 地址的集合。调用者应该使用该 IP 地址集合或者按照轮询round-robin的方式从集合中选择一个 IP 地址使用。</li>
</ul>
<p>SRV 记录Service含 headless Service的命名端口有 name 的端口)将被分配一个 SRV 记录,其格式为 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local。</p>
<ul>
<li>对于一个普通 Service非 headless Service该 SRV 记录解析到其端口号和域名 my-svc.my-namespace.svc.cluster.local。</li>
<li>对于一个 Headless Service该 SRV 记录解析到多个结果:每一个结果都对应该 Service 的一个后端 Pod包含其端口号和 Pod 的域名 auto-generated-pod-name.my-svc.my-namespace.svc.cluster.local。</li>
</ul>
<h4><strong>Pods</strong></h4>
<p>Kubernetes 在创建 Pod 时,将 Pod 定义中的 metadata.name 的值作为 Pod 实例的 hostname。</p>
<ul>
<li>Pod 定义中有一个可选字段 spec.hostname 可用来直接指定 Pod 的 hostname。例如某 Pod 的 spec.hostname 字段被设置为 my-host则该 Pod 创建后 hostname 将被设为 my-host。</li>
<li>Pod 定义中还有一个可选字段 spec.subdomain 可用来指定 Pod 的 subdomain。例如名称空间 my-namespace 中,某 Pod 的 hostname 为 foo并且 subdomain 为 bar则该 Pod 的完整域名FQDN为 foo.bar.my-namespace.svc.cluster.local。</li>
</ul>
<p>备注A 记录不是根据 Pod name 创建的,而是根据 hostname 创建的。如果一个 Pod 没有 hostname 只有 subdomain则 Kubernetes 将只为其 headless Service 创建一个 A 记录 default-subdomain.my-namespace.svc.cluster-domain.example该记录指向 Pod 的 IP 地址。</p>
<h3>DNS 优化</h3>
<p>社区根据压测数据,对 CoreDNS 需要的内存提供了一个计算公式:</p>
<pre><code>MB required (default settings) = (Pods + Services) / 1000 + 54
</code></pre>
<p>注解:</p>
<ul>
<li>30 MB 留给缓存,默认缓存大小为 1 万条记录。</li>
<li>5 MB 留给应用查询操作使用,默认压测单例 CoreDNS 支持大约 30K QPS。</li>
</ul>
<p><img src="assets/aaddf7c0-e123-11ea-9254-2dbb61d9b3dd.jpg" alt="kubedns-perf" /></p>
<h3>集成外部 DNS 服务</h3>
<p>我们在使用 Kubernetes 的场景中,企业经常已经默认有了自己的 DNS 服务,在部署容器集群的时候,肯定期望和外置的 DNS 服务做一些集成,方便企业内部的使用。</p>
<p>默认 DNS 查询策略是 ClusterFirst也就是查询应用名字首先是让集群内部的 CoreDNS 提供名字服务。而我们需要解决的是让指定的别名访问外部的服务,这个时候就需要做如下配置:</p>
<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
name: kube-dns
namespace: kube-system
data:
stubDomains: |
{&quot;consul.local&quot;: [&quot;10.150.0.1&quot;]}
upstreamNameservers: |
[&quot;8.8.8.8&quot;, &quot;8.8.4.4&quot;]
</code></pre>
<p>上面这个例子很好的解释了外置 Consul 服务,也可以很好地集成到 Kubernetes 服务中。如果是正式的域名,直接转向查询 8.8.8.8 上游 DNS 服务器了。</p>
<h3>总结</h3>
<p>CoreDNS 是 Kubernetes 集群中最核心,也是最容易理解的一个组件,它的功能单一,很容易上手。但是名字解析的规则还是需要大家熟悉,避免一些不必要的认知错误。</p>
<p>参考:</p>
<ul>
<li><a href="https://github.com/coredns/deployment/blob/master/kubernetes/Scaling_CoreDNS.md">https://github.com/coredns/deployment/blob/master/kubernetes/Scaling_CoreDNS.md.html</a></li>
<li><a href="https://kuboard.cn/learning/k8s-intermediate/service/dns.html">https://kuboard.cn/learning/k8s-intermediate/service/dns.html</a></li>
</ul>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/Kubernetes 实践入门指南/10 东西向流量组件 Calico 的落地实践.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/Kubernetes 实践入门指南/12 练习篇K8s 集群配置测验.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709972711ec53d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>