江春霞 發表於 2020-8-31 19:33:00

Kubernetes Service 详解

<h1 id="深入了解kubernetes-service" data-source-line="1">深入了解Kubernetes Service</h1>
<p data-source-line="2"> Service是Kubernetes最核心的概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求进行负载分发到后端的各个容器应用上。</p>
<h3 id="service的四种类型" data-source-line="3">Service的四种类型</h3>
<ol data-source-line="4">
<li>Clusterip: 默认类型,自动分配一个仅cluster内部可以访问的虚拟ip</li>
<li>NodePort: 在clusterip基础上为service在每台机器上绑定一个端口,这样就可以通过Nodeip:port方式来访问该服务</li>
<li>Loadbalance: 在NodePort基础上,接触cloud provider创建一个外部负载均衡器,并将请求转发到nodeip:port</li>
<li>externalName: 把集群外部的服务引入到集群内部,在集群内中直接使用,没有任何类型的代理被创建</li>
</ol>
<h3 id="yaml格式的pod配置文件内容及属性说明" data-source-line="8">yaml格式的pod配置文件内容及属性说明</h3>
<pre data-source-line="9"><code class="hljs"><span class="hljs-attribute">apiVersion: v1          <span class="hljs-comment">// <span class="zh-hans">必选,版本: v1
<span class="hljs-attribute">kind: Service         <span class="hljs-comment">// <span class="zh-hans">必选,Service
<span class="hljs-attribute">metadata:         <span class="hljs-comment">// <span class="zh-hans">必选,元数据
<span class="hljs-attribute">name: string          <span class="hljs-comment">// <span class="zh-hans">必选,Service<span class="zh-hans">名称
<span class="hljs-attribute">namespace: string   <span class="hljs-comment">// <span class="zh-hans">命令空间,不指定时系统系统默认的空间"default"
<span class="hljs-attribute">labels:         <span class="hljs-comment">// <span class="zh-hans">自定义属性标签列表
    - <span class="hljs-attribute">name: string      <span class="hljs-comment">// <span class="zh-hans">自定义注释属性列表
<span class="hljs-attribute">spec:               <span class="hljs-comment">// <span class="zh-hans">详细描述
<span class="hljs-attribute">selector: []          <span class="hljs-comment">// label Selector<span class="zh-hans">配置,选择具有指定label<span class="zh-hans">标签的Pod<span class="zh-hans">作为管理范围
<span class="hljs-attribute">type: string          <span class="hljs-comment">// Service<span class="zh-hans">的类型,默认为ClusterIP<span class="zh-hans">,可选NodePort<span class="zh-hans">和Loadbalancer<span class="zh-hans">。
<span class="hljs-attribute">clusterIP: string   <span class="hljs-comment">// <span class="zh-hans">虚拟服务IP<span class="zh-hans">地址,类型为ClusterIP<span class="zh-hans">时,如不指定,则系统自动分配
<span class="hljs-attribute">sessionaffinity: string   <span class="hljs-comment">// <span class="zh-hans">是否支持session<span class="zh-hans">,默认为空,可选ClusterIP<span class="zh-hans">,表示同一个客户端的访问请求转发到同一个口段Pod
<span class="hljs-attribute">ports:            <span class="hljs-comment">// Service<span class="zh-hans">需要暴露的端口列表
- <span class="hljs-attribute">name: string      <span class="hljs-comment">// <span class="zh-hans">端口名称
    <span class="hljs-attribute">protocol: string      <span class="hljs-comment">// <span class="zh-hans">端口协议,支持tcp<span class="zh-hans">和udp<span class="zh-hans">,默认tcp
    <span class="hljs-attribute">port: int         <span class="hljs-comment">// <span class="zh-hans">服务监听的端口号
    <span class="hljs-attribute">targetPort: int   <span class="hljs-comment">// <span class="zh-hans">需要转发到后端Pod<span class="zh-hans">的顿口号
    <span class="hljs-attribute">nodePort: int       <span class="hljs-comment">// <span class="zh-hans">当type<span class="zh-hans">为NodePort<span class="zh-hans">时,指定映射到物理机的端口号介于<span class="zh-hans">间
<span class="hljs-attribute">status:         <span class="hljs-comment">// <span class="zh-hans">当type<span class="zh-hans">为loadbalancer<span class="zh-hans">时,设置尾部负载均衡的地址,用于公有云环境
    <span class="hljs-attribute">loadBalancer:       <span class="hljs-comment">// <span class="zh-hans">外部负载均衡器
      <span class="hljs-attribute">ingress:          <span class="hljs-comment">// <span class="zh-hans">外部负载均衡器
      <span class="hljs-attribute">ip: string      <span class="hljs-comment">// <span class="zh-hans">外部负载均衡器的Ip
      <span class="hljs-attribute">hostname: string    <span class="hljs-comment">// <span class="zh-hans">外部负载均衡器的主机名
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="service的基本用法" data-source-line="34">Service的基本用法</h3>
<p data-source-line="35"> 一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最方便的方式就是通过TCP/IP及监听IP和端口号的方式来实现。直接通过Pod的IP地址和端口号访问应用,但是Pod的IP地址是不可靠的,当Pod所在的Node发生故障,Kubernetes会了重新调度到另一台Node上,这样Pod的IP将发生变化。重要的是,容器本身是分布式的部署方式,通过多个实例共同提供服务,需要在这些实例的前端设置一个负载均衡器来实现请求的分发,Kubernetes中的Service就师用来解决该问题的核心组件。<br> Kubernetes提供一种快速的方法,即通过kubectl expose命令来创建Service<br>如:</p>
<pre data-source-line="38"><code class="hljs"><span class="hljs-selector-id">#kubectl expose rc webapp
</span></code></pre>
<p data-source-line="41">查看新创建的Service,可以看到系统为它分配了一个虚拟的IP地址(Cluster IP),而Service所需的端口号则从Pod中的containerPort复制而来.</p>
<pre data-source-line="42"><code class="hljs">#kubectl <span class="hljs-keyword">get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webapp<span class="hljs-number">169.169<span class="hljs-number">.235<span class="hljs-number">.79 &lt;none&gt;   <span class="hljs-number">8080/TCP    <span class="hljs-number">3s
</span></span></span></span></span></span></code></pre>
<p data-source-line="47">我们可以通过该Service的IP地址和端口号来访问</p>
<pre data-source-line="48"><code class="hljs"><span class="hljs-selector-id">#curl 169<span class="hljs-selector-class">.169<span class="hljs-selector-class">.235<span class="hljs-selector-class">.79<span class="hljs-selector-pseudo">:8080
</span></span></span></span></span></code></pre>
<p data-source-line="51">对Service地址169.169.235.79:8080的访问会自动负载到后端的两个Pod中的一个。 除了使用命令创建Service,也可以通过配置文件定义Service,在通过kubectl create -f命令来进行创建。</p>
<pre data-source-line="53"><code class="hljs"><span class="hljs-attribute">apiVersion: v1
<span class="hljs-attribute">kind: service
<span class="hljs-attribute">metadata:
<span class="hljs-attribute">name: webapp
<span class="hljs-attribute">spec:
<span class="hljs-attribute">ports:
- <span class="hljs-attribute">port: <span class="hljs-number">8081            <span class="hljs-comment">// Service<span class="zh-hans">所需的虚拟端口号
   <span class="hljs-attribute">targetPort: <span class="hljs-number">8080            <span class="hljs-comment">// <span class="zh-hans">后端Pod<span class="zh-hans">的端口号
<span class="hljs-attribute">selector:
   <span class="hljs-attribute">app: webapp             <span class="hljs-comment">// <span class="zh-hans">后端拥有label: app=webapp<span class="zh-hans">的Pod
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p data-source-line="65"> 目前,Kubernetes提供两种负载分发策略:RoundRobin和SessionAffinity。默认情况下采用RoundRobin模式进行路由选择。</p>
<ol data-source-line="66">
<li>RoundRobin:轮询模式,即轮询将请求转发到后端各个Pod</li>
<li>SessionAffinity:基于客户端Ip地址进行会话保持,即第一次将某个客户端发情的请求转发到后端某个Pod上,之后相同的客户端发起的请求都将被转发到后端相同的Pod上。</li>
</ol>
<p data-source-line="69"> 默认情况下,Kubernetes采用RoundRbin模式进行路由选择,某些应用场景下开发人员系统自己控制负载均衡策略,Kubernetes通过Headless Service的概念来实现这种功能,即不给Service设置ClusterIP,仅通过Label Selector将后端的Pod列表返回给调用的客户端.<br>如:</p>
<pre data-source-line="71"><code class="hljs"><span class="hljs-attribute">apiVsersion: v1
<span class="hljs-attribute">kind: Service
<span class="hljs-attribute">metadata:
<span class="hljs-attribute">name: nginx
<span class="hljs-attribute">label:
    <span class="hljs-attribute">name: nginx
<span class="hljs-attribute">spec:
<span class="hljs-attribute">ports:
- <span class="hljs-attribute">ports: <span class="hljs-number">80
<span class="hljs-attribute">clusterIP: None
<span class="hljs-attribute">selector:
    <span class="hljs-attribute">app: nginx
</span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p data-source-line="85"> 该Service没有虚拟的clusterip地址,对其进行访问将获得具有label "app=nginx"的全部Pod别表,然后客户端程序需要实现自己的负载均衡分发策略。</p>
<h3 id="集群外部访问pod或service" data-source-line="86">集群外部访问Pod或Service</h3>
<p data-source-line="87">由于Pod和Service都是Kubernetes集群范围内的虚拟概念,所以集群外的客户端无法通过Pod的IP或者service的虚拟ip和端口号访问。为了让外部用户可以访问这些服务,可以将Pod和Service的端口映射到宿主机,使客户端通过物理机访问容器应用.</p>
<h4 id="方式将容器应用的端口号映射到物理机" data-source-line="89">方式将容器应用的端口号映射到物理机</h4>
<ol data-source-line="90">
<li>通过设置容器级别的hostport,将容器应用的端口号映射到物理机</li>
</ol>
<pre data-source-line="91"><code class="hljs"><span class="hljs-attribute">apiVersion: v1
<span class="hljs-attribute">kind: Pod
<span class="hljs-attribute">metadata:
<span class="hljs-attribute">name: webapp
<span class="hljs-attribute">labels:
    <span class="hljs-attribute">name: webapp
<span class="hljs-attribute">spec:
<span class="hljs-attribute">containers:
- <span class="hljs-attribute">name: tomcat
    <span class="hljs-attribute">image: tomcat
    <span class="hljs-attribute">ports:
    - <span class="hljs-attribute">containerPort: <span class="hljs-number">8080
      <span class="hljs-attribute">hostPort:<span class="hljs-number">8081
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p data-source-line="106">通过kubectl create创建该pod后即可通过物理机的IP和8081端口访问Pod内的容器服务</p>
<pre data-source-line="107"><code class="hljs"><span class="hljs-selector-id">#curl 10<span class="hljs-selector-class">.0<span class="hljs-selector-class">.0<span class="hljs-selector-class">.23<span class="hljs-selector-pseudo">:8081
</span></span></span></span></span></code></pre>
<ol start="2" data-source-line="110">
<li>通过设置Pod级别的hostNetwork=true,该Pod中所有容器的端口号都将被直接映射到物理机,需要注意的是,在容器的ports定义部分如不指定hostport,则默认hostport等于containerport。</li>
</ol>
<h3 id="使用nodeport类型将service的端口号映射到物理机" data-source-line="111">使用nodePort类型将Service的端口号映射到物理机</h3>
<ol data-source-line="112">
<li>过设置nodePort映射到物理机,同时这是Service的类型为nodePort</li>
</ol>
<pre data-source-line="113"><code class="hljs">apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
type: NodePort
ports:
- port: 8080
    nodePort: 30033
selector:
    name: webapp
</code></pre>
<p data-source-line="126">通过物理机的IP地址和nodePort30033端口访问服务</p>
<pre data-source-line="127"><code class="hljs"><span class="hljs-selector-id">#curl 10<span class="hljs-selector-class">.0<span class="hljs-selector-class">.0<span class="hljs-selector-class">.22<span class="hljs-selector-pseudo">:30033
</span></span></span></span></span></code></pre>
<p data-source-line="130">同样对该Service的访问也将被负载分发到后端的多个Pod上</p>
<ol start="2" data-source-line="132">
<li>通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。该用法仅用于在公有云服务商的平台上设置Service的场景</li>
</ol><br><br>
来源:https://www.cnblogs.com/xhyan/p/13591372.html
頁: [1]
查看完整版本: Kubernetes Service 详解