IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 2、深入掌握Service -> 正文阅读

[系统运维]2、深入掌握Service

2、深入掌握Service

Service是Kubernetes中访问应用容器的入口,可以为一组相同功能容器提供一个统一的入口地址,提供负载均衡服务。

关键:服务访问入口、负载均衡、一组容器

1、基本用法

apiVersion: v1
kind: ReplicationController  # 副本控制器RC
metadata:
  name: nginx  # RC的名称,全局唯一
spec:
  replicas: 2   # Pod副本的期待数量
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  template:     # 根据此模板创建pod的副本
    metadata:
      labels:
        app: nginx  # pod副本拥有的标签,===1此处应当一致
    spec:
      initContainers:
        - name: init-nginx-index
          image: busybox
          # 修改nginx主页
          command:
            - /bin/sh
            - -c
            - 'ls /; echo "this is $(hostname)" > /work-dir/index.html; ls /;'
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
          - containerPort: 80
        volumeMounts:
            - name: workdir
              mountPath: /usr/share/nginx/html
      volumes:
        - name: workdir
          emptyDir: {}
---
apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: nginx  # Service的名称,全局唯一
spec:
  type: NodePort  # 使用Node结点IP+端口的方式暴露给外部调用
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  ports:
    - port: 80  # Service提供服务的端口号
      nodePort: 30001 # 暴露给外部的端口,范围在30000-32767

1、根据RC快速创建Service

kubectl expose rc [rc-name]

2、多端口Service

一个容器应用可以暴露多个端口服务,一个Service也能映射多个端口

1、一个Service映射容器多个端口也可以映射不同协议

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP # 协议
      port: 80 # Servcice的虚拟端口号
      targetPort: 9376 # 后端Pod的端口号
    - protocol: TCP
      port: 80
      targetPort: 9376

2、一个Service映射同一端口的

3、负载策略

1、默认是轮训(每个IP都是独立的轮训)

2、设置基于IP的会话保持

apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: nginx  # Service的名称,全局唯一
spec:
  type: NodePort  # 使用Node结点IP+端口的方式暴露给外部调用
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  ports:
    - port: 80  # Service提供服务的端口号
      nodePort: 30001 # 暴露给外部的端口,范围在30000-32767
  sessionAffinity: ClientIP # 启用sessionAffinity策略,同一IP会被转发到固定的某个Pod上

4、指向固定IP的Service

上面的所有Service都是通过Label Selector负载到指向Pod的IP,Pod的IP发生改变时,Service中的IP集合也会发生改变。

这个IP集合就是EndPoint对象,EndPoint的内容是动态的。

Service创建时会创建一个EndPoint,EndPoint和Service的Name相同,我们可以通过Service的Name找到对应的EndPoint

我们可以创建没有Label Selector的Service,然后添加一个Name和Service一样的EndPoint,就可以得倒一个固定IP的Service了。

apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: endpoint-test  # Service的名称,全局唯一
spec:
  type: NodePort  # 使用Node结点IP+端口的方式暴露给外部调用
  ports:
    - port: 80  # Service提供服务的端口号
      nodePort: 30002 # 暴露给外部的端口,范围在30000-32767
  sessionAffinity: ClientIP # 启用sessionAffinity策略,同一IP会被转发到固定的某个Pod上
---
apiVersion: v1
kind: Endpoints
metadata:
  name: endpoint-test
subsets:
- addresses:
  - ip: 8.8.8.8  # 固定IP,可以是集合,类似Nginx的upstream
  ports:
  - port: 80
    protocol: TCP
# 查看endpoint
kubectl get ep

# 修改endpoint,运行时修改,IP集合修改立即生效
kubectl edit ep [ep-name]

5、Headless Service

一个Service包括:1、service IP 2、Endpoint

没有Service IP的Service就是Headless Service,没有Service IP,就不能通过该Service IP对EndPoint中的Pod IP集合进行负载均衡访问。而只是存放着Pod的IP集合,Pod变动IP时,该集合也会变。

类似于注册中心,可以获取某个RC或者Deployment下的所有Pod的地址,可以在此基础上实现自定义的负载均衡。

1、创建一个Headless Service

apiVersion: v1
kind: ReplicationController  # 副本控制器RC
metadata:
  name: nginx  # RC的名称,全局唯一
spec:
  replicas: 2   # Pod副本的期待数量
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  template:     # 根据此模板创建pod的副本
    metadata:
      labels:
        app: nginx  # pod副本拥有的标签,===1此处应当一致
    spec:
      initContainers:
        - name: init-nginx-index
          image: busybox
          # 修改nginx主页
          command:
            - /bin/sh
            - -c
            - 'ls /; echo "this is $(hostname)" > /work-dir/index.html; ls /;'
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
          - containerPort: 80
        volumeMounts:
            - name: workdir
              mountPath: /usr/share/nginx/html
      volumes:
        - name: workdir
          emptyDir: {}
---
apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: headless-service  # Service的名称,全局唯一
spec:
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  ports:
    - port: 80  # Service提供服务的端口号
  clusterIP: None # HeadLess-Service

2、程序中获取Service中的Endpoint

API文档:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpoints-v1-core

不同语言调用:https://kubernetes.io/zh/docs/reference/using-api/client-libraries/

https://{ip}:{port}/api/v1/namespaces/{namespace}/endpoints

ip和port在kube-api-server启动参数中配置,–advertise-address和–secure-port

如果是kubeadm的方式配置的,可以通过kubectl edit修改或者在/etc/kubernetes/manifests路径下进行修改

6、集群外部访问Pod或Service

Pod和Service是Kubernetes集群内部的一个虚拟网络环境,主要由docker网络和网络插件CNI 配置Linux网络提供集群机器间内部网络的通信,但是集群外部无法通过Pod和Service的IP进行通信。

集群外部要想访问内部的地址,主要是通过NodePort的方式,即类似docker容器做端口映射的方式将容器的端口映射到Kubernetes集群的Node节点上的某个节点,实现可以通过Node节点的IP+端口的方式实现通信。

docker容器只能做本机的映射,但是Kubernetes通过网络插件CNI的方式可以将一个Service映射到所有Node节点的端口上。

1、Pod通过NodePort向外暴露服务(只能通过Pod部署的那台Node节点的IP+Port访问)

apiVersion: v1
kind: Pod
metadata:
  name: external-pod
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          hostPort: 80

或者

apiVersion: v1
kind: Pod
metadata:
  name: external-pod
spec:
  hostNetwork: true
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80

2、Service通过NodePort向外暴露服务(所有Node节点包括Master的IP+Port都可以访问)

apiVersion: v1
kind: ReplicationController  # 副本控制器RC
metadata:
  name: nginx  # RC的名称,全局唯一
spec:
  replicas: 2   # Pod副本的期待数量
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  template:     # 根据此模板创建pod的副本
    metadata:
      labels:
        app: nginx  # pod副本拥有的标签,===1此处应当一致
    spec:
      initContainers:
        - name: init-nginx-index
          image: busybox
          command:
            - /bin/sh
            - -c
            - 'ls /; echo "this is $(hostname)" > /work-dir/index.html; ls /;'
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
          - containerPort: 80
        volumeMounts:
            - name: workdir
              mountPath: /usr/share/nginx/html
      volumes:
        - name: workdir
          emptyDir: {}
---
apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: external-service  # Service的名称,全局唯一
spec:
  selector:
    app: nginx  # 符合目标的pod拥有此标签,===1此处应当一致
  type: NodePort # 指定Service暴露的类型,默认ClusterIP
  ports:
    - port: 80  # Service提供服务的端口号
      nodePort: 30000 # Node暴露的端口,端口有限制30000-32767,可以通过修改api-server服务的启动参数解除限制

我们创建以NodePort方式暴露的Service时,就算只有一个Pod运行在某台Node节点上,我们也是可以通过其他Node节点的IP+Service的nodePort端口进行访问的。

如果有需求是只能通过Pod所在Node的IP+Service的nodePort端口进行访问的话,可以在Service的配置中加上externalTrafficPolicy: Local

7、DNS服务

前面我们使用Service访问服务都是通过ServiceIP的方式,但是service ip和pod ip都是kubernetes的内部网络,属于动态可变的,我们需要一种机制能够使用固定的服务名对这些ip进行访问。

Pod的IP集合被Service动态管控,Pod的变化也会导致Service映射的Pod IP发生变化。而Service的IP变化,在Kubernetes中是通过DNS的方式进行管控的。

Kubernetes中,通过coredns服务管控service,域名是service的name,ip是service的ip,我们可以通过固定的service name去访问这个service。

CoreDNS是Kubernetes的DNS服务器和服务发现的参考解决方案。

1、配置core-dns服务

我前面是用的kubeadm安装的集群,默认已经安装了core-dns,这里贴一下主要的配置

1、configMap,这里知道coredns的配置文件

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  Corefile: |
    cluster.local: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
        loop
        reload
        loadbalance
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2021-07-03T20:01:41Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "215"
  uid: 179254c8-aa87-4867-8174-a27a0686571f

2、Deployment

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2021-07-03T20:01:41Z"
  generation: 1
  labels:
    k8s-app: kube-dns
  name: coredns
  namespace: kube-system
  resourceVersion: "3534"
  uid: a9ce8038-1431-4c0a-bdf6-f6c4e43d361f
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kube-dns
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        k8s-app: kube-dns
    spec:
      containers:
      - args:
        - -conf
        - /etc/coredns/Corefile
        image: registry.aliyuncs.com/google_containers/coredns:1.7.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5

3、Service

# reopened with the relevant failures.
#
apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  creationTimestamp: "2021-07-03T20:01:41Z"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: KubeDNS
  name: kube-dns
  namespace: kube-system
  resourceVersion: "221"
  uid: 9edd5e0e-6fdb-48c6-8d72-11ff73449b68
spec:
  clusterIP: 10.30.0.10  # 固定的Service IP地址,在node节点的kubelet服务启动参数上配置
  clusterIPs:
  - 10.30.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dns-tcp
    port: 53
    protocol: TCP
    targetPort: 53
  - name: metrics
    port: 9153
    protocol: TCP
    targetPort: 9153
  selector:
    k8s-app: kube-dns
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

2、Node节点修改启动参数

通过修改kubelet服务的启动参数,在其中指定DNS即可实现集群全局范围内的DNS服务。

--cluster-dns=10.30.0.10 # kube-dns service中配置的cluster ip
--cluster-domain=cluster.local # 为在DNS服务中设置的域名

3、测试效果

1、用之前nginx的例子,新建一个rc和service

2、开启一个测试容器

apiVersion: v1
kind: Pod
metadata:
  name: test-contaienr
spec:
  containers:
    - name: busybox
      image: busybox
      command: 
        - sleep
        - "3600"

3、进入容器,执行nslookup service名称就可以看到能正常解析service name。

kubectl exec test-contaienr -- nslookup external-service

这个主要是通过修改容器内的DNS服务器实现的

kubectl exec test-contaienr -- cat /etc/resolv.conf 

我们通过查看容器内的dns服务器,可以看到就是我们在kubelet中设置的coredns的service ip

4、Pod级别的DNS配置

前面我们通过修改kubelet的启动参数实现集群范围内的DNS,我们也可以指定单个Pod的dns策略

apiVersion: v1
kind: Pod
metadata:
  name: test-contaienr
spec:
  containers:
    - name: busybox
      image: busybox
      command: 
        - sleep
        - "3600"
  dnsPolicy: Default

这里Pod的dns策略有:

  • Default:继承Pod所在宿主机的DNS设置。
  • ClusterFirst:优先使用Kubernetes环境的DNS服务,无法解析的转发到宿主机继承的DNS服务器。
  • ClusterFirstWithHostNet:同上,以hostNetwork模式运行的Pod需要明确指定。
  • None:忽略Kubernetes的DNS配置,有spec.dnsConfig自定义DNS配置。

以前面的test-contaienr容器为例,指定不同dnsPolicy的效果:

1、不指定dnsPolicy,则默认使用kubernetes的DNS服务,可以解析coredns配置的service name,无法解析外网域名。

2、dnsPolicy=Default,则默认使用宿主机的DNS服务,可以解析外网域名,无法解析coredns配置的service name。

3、dnsPolicy=ClusterFirst/ClusterFirstWithHostNet,可以解析coredns配置的service name,可以解析外网域名。

4、None,自己指定Pod容器中的dns服务器配置,全由配置的dns服务器解析。

None配置同下面resolve.conf文件一样,分为nameserver、searches、options

nameserver 10.30.0.10
search default.svc.cluster.local svc.cluster.local cluster.local 
options ndots:5

8、Ingress

Kubernetes官方文档地址:https://kubernetes.io/zh/docs/concepts/services-networking/ingress/

Ingress是Kubernetes对外暴露服务的一种方式,主要是通过Controller和Ingress规则实现。

Controller是一个Pod,他作为Kubernetes集群外部流量的入口,通过配置的不同Ingress规则让不同的流量转发到Service,然后Service通过负载均衡到Pod上。

Ingress Controller有多种选择,我们选择安装常用的Nginx Controller

官方文档地址:https://kubernetes.github.io/ingress-nginx/deploy/

1、通过容器的方式部署Controller

yaml文件地址:https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.48.1/deploy/static/provider/cloud/deploy.yaml

这里需要修改一些配置

1、容器镜像的地址

我们需要从国内镜像源中下载,可以直接从dockerhub上搜索对应的ingress-controller镜像。

2、向外通过NodePort的方式暴露Controller服务

官网下载的默认配置文件,contoller对应的Service是通过LoadBalancer的方式对外暴露服务的,LoadBalancer依赖于云提供商的外部负载均衡方案,我们测试时使用NodePort的方式暴露服务。

官方提供的配置是使用Deployment的方式去创建的Controller,且Controller对应的Service是只能在Controller的Pod所在的那台Node机器的IP+Service的nodePort端口才能访问,我们如果想每个node节点的IP+Service的nodePort端口都能访问的话,可以

1、通过DaemonSet的方式在每一个Node节点上进行部署。

2、去掉Controller的Service中的externalTrafficPolicy: Local配置。

2、创建测试容器

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-deployment
  template:
    metadata:
      labels:
        app: nginx-deployment
    spec:
      initContainers:
        - name: init-nginx-index
          image: busybox
          command:
            - /bin/sh
            - -c
            - 'ls /; echo "this is $(hostname)" > /work-dir/index.html; ls /;'
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "250m"
        ports:
          - containerPort: 80
        volumeMounts:
            - name: workdir
              mountPath: /usr/share/nginx/html
      volumes:
        - name: workdir
          emptyDir: {}
---
apiVersion: v1
kind: Service  # 表明是 Kubernets Service
metadata:
  name: nginx-service  # Service的名称,全局唯一
spec:
  selector:
    app: nginx-deployment  # 符合目标的pod拥有此标签,===1此处应当一致
  type: ClusterIP # 指定Service暴露的类型,默认ClusterIP
  ports:
    - port: 80  # Service提供服务的端口号

3、添加Ingress规则

主要是配置对某个路径的访问,转发到那个Service上

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

4、访问

此时我们就向添加了ingress规则,我们访问kubernetes中的服务,都去访问nginx-controller的service服务,然后controller会根据ingress规则访问context对应的service,然后service转发到对应的Pod容器。

使用虚拟机部署Kubernetes集群的话,我们就可以在本机通过Kubernetes集群的某个节点IP+Controller Service端口和Ingress配置的path访问到对应Kubernetes容器中的服务了。

如果想要使用域名的方式去访问的话,可以在Ingress规则中配置host,例如

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: 10.211.55.30.sslip.io
    http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

10.211.55.30是我内网的虚拟机master节点IP地址;sslip.io是一个公网的DNS服务,我们可以使用其做域名测试。详情见

http://sslip.io

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 13:08:37  更:2021-07-30 13:09:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 11:44:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计