1. 简介

kubernets service 是将运行一组pods上的应用程序公开为网络服务的抽象方法。

有了 kubernets service,你就无需修改应用程序即可使用服务发现机制,kubernets 为 pods 提供自己的ip地址,并为一组pod提供相同的DNS名,并且可以在它们之间进行负载均衡。

2. 为什么要用services

创建和销毁 kubernets pod 以匹配集群状态。pod 是非永久性资源。如果你使用 Deployment 来运行你的应用程序,则它可以动态创建和销毁 Pod。

每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。

这导致了一个问题: 如果一组 Pod(称为“后端”)为集群内的其他 Pod(称为“前端”)提供功能, 那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用提供工作负载的后端部分?

3. quick start

3.1 创建svc

资源模板 svc-deploy-nginx.yaml信息如下:

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-test
name: nginx-test-1
spec:
replicas: 3
selector:
matchLabels:
app: nginx-test
template:
metadata:
labels:
app: nginx-test
spec:
containers:
- image: nginx:latest
name: nginx
imagePullPolicy: IfNotPresent --- apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
# must be match pod template .spec.template.labels
app: nginx-test
ports:
- protocol: TCP
port: 8000
targetPort: 80

创建一个deploy,和一个 svc

注意 svc selector 对应的是 deploy 的 .spec.template.labels

创建资源

$ kubectl create -f svc-deploy-nginx.yaml

3.2 查看svc

  1. 使用资源文件查看

    $ kubectl get  -f svc-deploy-nginx.yaml -o wide
    # 输出内容如下
    # deploy 信息
    NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
    deployment.apps/nginx-test-1 3/3 3 3 42m nginx nginx:latest app=nginx-test
    # svc 信息
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    service/my-service ClusterIP 10.96.112.5 <none> 8000/TCP 42m app=nginx-test
  2. 使用命令查看

    查看svc 信息

    $ kubectl get svc/my-service -owide
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    my-service ClusterIP 10.96.112.5 <none> 8000/TCP 45m app=nginx-test

    查看endpoints信息

    可以看到成功的绑定了三个pod endpoint

    $ kubectl get ep/my-service
    NAME ENDPOINTS AGE
    my-service 10.100.132.133:80,10.100.132.139:80,10.100.132.140:80 46m

    查看svc 详细信息

    $ kubectl describe svc/my-service
    Name: my-service
    Namespace: default
    Labels: <none>
    Annotations: <none>
    Selector: app=nginx-test
    Type: ClusterIP
    IP: 10.96.112.5
    Port: <unset> 8000/TCP
    TargetPort: 80/TCP
    Endpoints: 10.100.132.133:80,10.100.132.139:80,10.100.132.140:80
    Session Affinity: None
    Events: <none>

3.3 访问svc

在上面的实例中svc 并没有指定 svc type,其默认为ClusterIP类型(从上面的详情信息中也能看出)。

我们现在访问下实例中的svc

  1. 在集群内部访问

    在集群机器上可以使用ClusterIp 访问服务,但是无法通过 svc name访问

    在集群pod中可以使用任意方式访问服务

  2. 在集群外部访问

    集群外部 没有办法直接访问 svc type=ClusterIp 的svc

4. svc type

svc 有以下的几种类型:

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType

  • NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。

  • LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。

  • ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。

    说明: 需使用 kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 及以上版本才能使用 ExternalName 类型。

4.1 ClusterIp

  1. ClusterIp是默认的svc类型,在创建该资源时,kubernetes会默认分配一个 cluster ip。
  2. svc端口为.spec.ports.port,其代理的后端服务的目标端口为.spec.ports.targetPort
  3. 其cluster ip 只能在集群内部访问,如果想通过svc name 访问其代理的服务,只能在pod中访问。其验证过程可参考3.3 访问svc
  4. 集群外部的资源无法访问ClusterIp类型的svc。

4.2 NodePort

node(节点)port(端口),顾名思义 NodePort类型的svc是通过在集群的宿主机上开放访问的端口,并通过 <节点 IP>:<节点端口>(集群任意节点ip:nodeport 都可以访问)来实现从集群外部访问其svc的。

nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod。(能够将内部服务暴露给外部的一种方式)

  1. 创建资源

    一个deploy 和 一个 nodeport svc,且指定了node 端口为30007(如果不指定,k8s会默认分配一个)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: nginx-deploy-test
    name: nginx-test-2
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: nginx-test-02
    template:
    metadata:
    labels:
    app: nginx-test-02
    spec:
    containers:
    - image: nginx:latest
    name: nginx
    imagePullPolicy: IfNotPresent --- apiVersion: v1
    kind: Service
    metadata:
    name: my-service-2
    spec:
    type: NodePort
    selector:
    app: nginx-test-02
    ports:
    - protocol: TCP
    port: 8000
    targetPort: 80
    # 可选字段
    # 默认情况下,为了方便起见,Kubernetes 会从范围内分配一个端口号(默认:30000-32767)
    nodePort: 30007
  2. 访问svc

4.3 LoadBalancer

使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。

4.4 ExternalName

类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 其他svc 或者 公网域名。 你可以使用 spec.externalName 参数指定这些服务。

  1. 创建服务

    例如,以下 Service 定义将 default 名称空间中的 my-service-2 服务映射到 my-service-1.test.svc.cluster.local(test 名称空间中的 my-service-1 service):

    apiVersion: v1
    kind: Service
    metadata:
    name: my-service-2
    spec:
    type: ExternalName
    externalName: my-service-1.test.svc.cluster.local

    服务信息如下:

    服务是在default namespace 下

    没有分配CLUSTER-IP,但是有我们指定的 EXTERNAL-IP

    $ kubectl get svc -owide
    
    NAME           TYPE           CLUSTER-IP   EXTERNAL-IP                           PORT(S)   AGE    SELECTOR
    kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 170d <none>
    my-service-2 ExternalName <none> my-service-1.test.svc.cluster.local <none> 41s <none>

    为了验证映射效果,我们再创建一个my-service-1.test service

    注意 服务都是在test namespace 下

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: nginx-deploy-test
    name: nginx-test-1
    namespace: test
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: nginx-test
    template:
    metadata:
    labels:
    app: nginx-test
    spec:
    containers:
    - image: nginx:latest
    name: nginx
    imagePullPolicy: IfNotPresent --- apiVersion: v1
    kind: Service
    metadata:
    name: my-service-1
    namespace: test
    spec:
    selector:
    app: nginx-test
    ports:
    - protocol: TCP
    port: 8000
    targetPort: 80

    服务信息如下:

    $ kubectl get -f app-nginx.yaml -owide
    
    NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
    deployment.apps/nginx-test-1 3/3 3 3 48s nginx nginx:latest app=nginx-test NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    service/my-service-1 ClusterIP 10.96.188.235 <none> 8000/TCP 47s app=nginx-test
  2. 访问svc

    首先我们创建一个pod 用来访问 验证 svc

    服务信息如下:

    $ kubectl get po -owide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    helloworld 1/1 Running 0 7d23h 10.100.132.161 k8s-woker-01 <none> <none>

    ok,到这里 资源都以就绪,如果我们进入到 pod/helloworld 去访问 svc/my-service-2,如果能成功访问到naginx 服务,则证明ExternalName svc这种方式是可行的:

4.5 Headless Services

准确来说 Headless Services 并不属于svc的type,而是 clusterip类型的变种

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。

对这无头 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

**无选择算符的服务 **

对没有定义选择算符的无头服务,Endpoint 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:

  • 对于 ExternalName类型的服务,查找其 CNAME 记录
  • 对所有其他类型的服务,查找与 Service 名称相同的任何 Endpoints 的记录

关于Headless Services 在k8s-statefulset博文中 有详细的记录,感兴趣的可以访问了解下。

5. externalIPs

Service 的 externalIPs(spec.externalIPs)可以设置一组外部的 IP 地址,并且将流量导入到集群内部。

如图:

启动一个springboot项目 并初始化一个接口,访问后返回 Hello World~

在本机上访问:

接下来我们就使用externalIPs192.168.0.101流量导入到集群内部

目标:集群pod中访问192.168.0.101:8080时不是访问此时的这个springboot项目,而是访问集群内的externalIPs svc

  1. 首先到集群master节点访问一下springboot项目

    访问成功

    $ curl 192.168.0.101:8080
    Hello World~
  2. 创建externalIPs svc,和想导入到集群的目标pod

    本实例主要是为了展示流量的切换,但其实spec.externalIPs 可以指定符合ip 规则的任意地址(即使设置的ip不可达),k8s都会帮你 在访问设置地址的服务时,将流量导入到spec.selector的服务中去

    实际上就是 如果你把spec.externalIPs地址设置成123.123.123.123,当你在服务中访问123.123.123.123时,其实访问的是spec.selector指定的服务

    其实更像是 给spec.selector到服务指定了一个 ipv4 的别名

    apiVersion: v1
    kind: Service
    metadata:
    name: nginx
    labels:
    app: nginx
    spec:
    ports:
    - port: 8080
    targetPort: 80
    name: web
    externalIPs:
    - "192.168.0.101"
    # 将 192.168.0.101 流量导入到 下面的Deployment中
    selector:
    app: nginx --- apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: web
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: nginx
    template:
    metadata:
    labels:
    app: nginx
    spec:
    containers:
    - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    name: web

    服务信息如下:

    $ kubectl get deploy -owide
    NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
    web 2/2 2 2 3h25m nginx nginx app=nginx $ kubectl get svc/nginx -owide
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
    nginx ClusterIP 10.96.41.170 192.168.0.101 8080/TCP 4m app=nginx
  3. 创建一个pod 并进入pod ,在pod中访问192.168.0.101:8080查看访问的是外部的springboot项目还是集群内的deploy/web

    很显然:k8s成功的将流量导入到了集群内部

    如果在集群节点上访问192.168.0.101:8080,是不能将结果导入到deploy上的,只有在集群服务内部访问才有效

  4. 此时我们将svc/nginx 删除掉,看下访问的结果

    符合预期

6. 管理外部的服务

场景:如果我们的中间件或者数据库服务不是在k8s集群内的,而是在其他的服务器上,但是我们还是想通过访问svc的方式去访问这些外部的服务,我们应该怎么做呢?

  1. 声明一个没有选择符的svc
  2. 创建一个同名(和第一步中的svc name 相同)的 endpoints 服务去管理这些外部的服务地址

实例:

实例通过创建svc 和 endpoints,实现访问svc-name,svc 将流量导出到外部的springboot(项目信息如5.0中提到的)项目中

  1. 创建服务

    apiVersion: v1
    kind: Service
    metadata:
    name: my-service
    spec:
    ports:
    - protocol: TCP
    port: 80
    targetPort: 8080 --- apiVersion: v1
    kind: Endpoints
    metadata:
    # must be match svc-name
    name: my-service
    subsets:
    - addresses:
    # 指向外部的springboot 服务
    - ip: 192.168.0.101
    ports:
    - port: 8080
  2. 访问测试

7. 选择自己的 IP 地址

Service 创建的请求中,可以通过设置 spec.clusterIP 字段来指定自己的集群 IP 地址。

k8s-svc的更多相关文章

  1. 4.1.k8s.svc(Service)

    #Service Service为Pod提供4层负载均衡, 访问 -> Service -> Pod组 #4种类型 ClusterIP 默认,分配一个VIP,只能内部访问 NodePort ...

  2. K8S SVC 转发原理

    在前面的文章中,我们已经多次使用到了 Service 这个 Kubernetes 里重要的服务对象.而 Kubernetes 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另 ...

  3. [k8s]svc里知识点小结

    svc里面涉及到的概念较多一些,总结如下

  4. 办公环境下k8s网络互通方案

    在 kubernetes 的网络模型中,基于官方默认的 CNI 网络插件 Flannel,这种 Overlay Network(覆盖网络)可以轻松的实现 pod 间网络的互通.当我们把基于 sprin ...

  5. 【K8S】基于Docker+K8S+GitLab/SVN+Jenkins+Harbor搭建持续集成交付环境(环境搭建篇)

    写在前面 最近在 K8S 1.18.2 版本的集群上搭建DevOps环境,期间遇到了各种坑.目前,搭建环境的过程中出现的各种坑均已被填平,特此记录,并分享给大家! 服务器规划 IP 主机名 节点 操作 ...

  6. 三万字无坑搭建基于Docker+K8S+GitLab/SVN+Jenkins+Harbor持续集成交付环境

    写在前面 最近在 K8S 1.18.2 版本的集群上搭建DevOps环境,期间遇到了各种坑.目前,搭建环境的过程中出现的各种坑均已被填平,特此记录,并分享给大家! 文章和搭建环境所需要的yml文件已收 ...

  7. 8.4 k8s实现Nginx+Php+WordPress+MySQL实现完全容器化的web站点案例

    1.制作Nginx镜像 1.1 使用nginx:1.21.1官方镜像 # 下载官方镜像 docker pull nginx:1.21.1 # 打本地harbor的tag docker tag 192. ...

  8. 从K8S部署示例进一步理解容器化编排技术的强大

    概念 Kubernetes,也称为K8s,生产级别的容器编排系统,是一个用于自动化部署.扩展和管理容器化应用程序的开源系统.K8s是一个go语言开发,docker也是go语言开发,可见go语言的是未来 ...

  9. sysdig安装和使用介绍

    安装步骤1)安装资源库rpm --import https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.publiccurl -s -o ...

  10. Kubernetes容器集群管理环境 - 完整部署(中篇)

    接着Kubernetes容器集群管理环境 - 完整部署(上篇)继续往下部署: 八.部署master节点master节点的kube-apiserver.kube-scheduler 和 kube-con ...

随机推荐

  1. Java事务与JTA

    一.什么是JAVA事务 通俗的理解,事务是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令.更简答的说就是:要么 ...

  2. Nested Classes in C++

    A nested class is a class which is declared in another enclosing class. A nested class is a member a ...

  3. sql技巧(增册改查)

    1 select * from wyl.t; 2 --将数据从t1导入t2 3 insert into t2(c1,c2) select c1,c2 from t1 where c1= xx and ...

  4. NSString类里有个hash

    实际编程总会涉及到比较两个字符串的内容,一般会用 [string1 isEqualsToString:string2] 来比较两个字符串是否一致.对于字符串的isEqualsToString方法,需要 ...

  5. SVN终端演练(个人开发\多人开发)

    SVN终端演练(个人开发) ### 1. 命令格式 命令行格式: svn <subcommand> [options] [args]       svn 子命令 [选项] [参数]     ...

  6. ssm动态查询向前台传json

    1.数据协议层 public User selectById(Integer id);//通过id值查询用户 2.数据层 <select id="selectById" re ...

  7. Java 多线程的一次整理

    一天没有出过家门,实属无聊,没事瞎写写 1. 基本概念 1.1 多进程和多线程的概念 程序是由指令和数据组成,指令要运行,数据要加载,指令被 CPU 加载运行,数据被加载到内存,指令运行时可由 CPU ...

  8. Mysql资料 存储索引

  9. vue-cli4结合element-ui异常解决(前端小白,文摘取自网络)

    1:将vue-cli4版本退回到vue-cli3 2:使用element-plus 替换 element-ui 传送门 => https://element-plus.gitee.io/#/zh ...

  10. spring security oauth2搭建resource-server demo及token改造成JWT令牌

    我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...