Kubernetes之十九: Service服务

认识Service

1)为什么要使用service

kubernetes pod是有生命周期的,可以被创建,也可以被销毁;一旦被销毁,通过控制器能够动态创建新的pod,每次pod都会获取自己的IP地址会变动

2)service介绍


Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们不同的策略—通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Sekector实现的;

 

对Kubernetes集群中的应用,Kubernetes提供了简单的Endpoints API,只要service中的一组Pod发生变更,应用程序就会被更新。

对非Kubernetes集群中的应用,Kubernetes提供了基本VIP的网桥的方式访问Service,再由Service重定向到backend Pod


3)三种代理模式
userspace 代理模式
iptables 代理模式
ipvs 代理模式

(下图为iptables代理模式)

 

 (下图为ipvs的代理模式)

 

 

iptables:

客户端IP请求时,直接请求本地内核service ip,根据iptables的规则直接将请求转发到到各pod上,因为使用iptable NAT来完成转发,也存在不可忽视的性能损耗。

另外,如果集群中存在上万的Service/Endpoint,那么Node上的iptables rules将会非常庞大,性能还会再打折扣。

 

ipvs:

客户端IP请求时到达内核空间时,根据ipvs的规则直接分发到各pod上。kube-proxy会监视Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs规则并定期与Kubernetes Service对象和Endpoints对象同步ipvs规则,

以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。

 

Service类型

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType
  • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持
  •  无 selector 的Services  (需要手工配置Endpoints)
  • 无 ClusterIP的Service (headless service)

 

第二部分: 案例

1)创建clusterIP类型的service

#定义deployment和svc
apiVersion: apps/v1
kind: Deployment
metadata:
    name: redis
    namespace: default
spec:
    replicas: 1
    selector:
       matchLabels:
           app: redis
           role: logstor
    template:
       metadata:
           labels:
              app: redis
              role: logstor
       spec:
          containers:
          - name: redis
            image: redis:4.0-alpine
            ports:
            - name: redis
              containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
    name: redis
    namespace: default
spec:
   selector:
      app: redis
      role: logstor
   type: ClusterIP
   ports:
   - port: 6380
     targetPort: 6379

#kubectl apply -f redis-svc.yaml
验证
[root@master01 mainfest]# kubectl get pods
NAME READY STATUS RESTARTS AGE
redis-85b846ff9c-x2f48 1/1 Running 0 35s
[root@master01 mainfest]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis ClusterIP 10.20.227.191 <none> 6380/TCP 38s
[root@master01 mainfest]# redis-cli -h 10.20.227.191 -p 6380
10.20.227.191:6380> keys *
(empty list or set)
10.20.227.191:6380> set name aaa
OK

  

2)创建NodePort类型的Service

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
      ports:
      - name: http
        containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 31180

#kubectl apply -f myapp-svc.yaml
验证
[root@master01 mainfest]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-65df64765c-27gj6 1/1 Running 0 23s
myapp-deploy-65df64765c-2wv2t 1/1 Running 0 23s
myapp-deploy-65df64765c-9nmwb 1/1 Running 0 23s
[root@master01 mainfest]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.20.0.1 <none> 443/TCP 4d14h
myapp NodePort 10.20.44.7 <none> 80:31180/TCP 31s

#打补丁修改sessionAffinity为clientip;实现会话连接
[root@master01 mainfest]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/myapp patched

[root@master01 mainfest]# kubectl describe svc myapp
Name: myapp
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"nodePort":31180,...
Selector: app=myapp,release=canary
Type: NodePort
IP: 10.20.44.7
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 31180/TCP
Endpoints: 172.31.219.219:80,172.31.67.144:80,172.31.67.145:80
Session Affinity: ClientIP
External Traffic Policy: Cluster
Events: <none>
[root@master01 mainfest]# while true;do curl 192.168.10.211:31180/hostname.html;sleep 1;done
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-2wv2t
[root@master01 mainfest]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
service/myapp patched
[root@master01 mainfest]# while true;do curl 192.168.10.211:31180/hostname.html;sleep 1;done
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-9nmwb
myapp-deploy-65df64765c-27gj6
myapp-deploy-65df64765c-9nmwb
myapp-deploy-65df64765c-2wv2t
myapp-deploy-65df64765c-9nmwb

  

3)创建无头service(headless)

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: None
  ports:
  - port: 80
    targetPort: 80

返回后端所有pod的地址
[root@master01 mainfest]# dig -t A myapp-svc.default.svc.ziioffice.com. @10.20.254.254
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -t A myapp-svc.default.svc.ziioffice.com. @10.20.254.254
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6273
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;myapp-svc.default.svc.ziioffice.com. IN A
;; ANSWER SECTION:
myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.67.146
myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.219.220
myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.67.147

 

4)没有selector的service(指定外部)
Service抽象了该如何访问Kubernetes Pod,但也能抽象其他类型的backend,例如:

希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
希望服务指向另一个Namespace中或其他集群中的服务。

apiVersion: v1
kind: Endpoints
metadata:
  name: mysql-service
  namespace: default
subsets:
  - addresses:
    - ip: 192.168.10.204
    ports:
    - port: 3306
---
kind: Service
apiVersion: v1
metadata:
  name: mysql-service
  namespace: default
spec:
  ports:
  - protocol: TCP
    port: 3336
    targetPort: 3306
                    


#测试pod内部,通过service,访问外部的数据库
[root@web-55fff97c7-gsrl5 /]# mysql -h mysql-service.default.svc.ziioffice.com -u aa -p -P 3336
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 249
Server version: 5.6.40 MySQL Community Server (GPL)
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

 

apiVersion: v1
kind: Endpoints
metadata:
  name: redis-service
  namespace: default
subsets:
  - addresses:
    - ip: 192.168.10.204
    ports:
    - port: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  ports:
   - port: 6380
     targetPort: 6379


#kubectl apply -f redis-svc.yaml

[root@web-55fff97c7-7mdf9 /]# redis-cli -h redis-service.default.svc.ziioffice.com -p 6380
redis-service.default.svc.ziioffice.com:6380>

  

5) externalname

引入rds数据库到集群内部

apiVersion: v1
kind: Service
metadata:
  name: prod-mysql-service
  namespace: default
spec:
  type: ExternalName
  externalName: rm-uf665jsp7111111.mysql.rds.aliyuncs.com

测试:
[root@master03-171 mainfest]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prod-mysql-service ExternalName <none> rm-uf665jsp7vwk4lz83.mysql.rds.aliyuncs.com <none> 20m

[root@master03-171 mainfest]# kubectl exec -it pod test-centos-6979f6bc4c-clbz7 -- /bin/bash
[root@test-centos-6979f6bc4c-clbz7 /]# yum -y install mysql
[root@test-centos-6979f6bc4c-clbz7 /]# mysql -h prod-mysql-service.default.svc.ziioffice.com -u xionghh -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 60
Server version: 5.7.26-log Source distribution
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

连接阿里云redis

apiVersion: v1
kind: Service
metadata:
   name: prod-redis-service
   namespace: default
spec:
  type: ExternalName
  externalName: r-uf6d6wb8111111.redis.rds.aliyuncs.com

验证:
[root@master03-171 mainfest]# kubectl describe svc prod-redis-service
Name: prod-redis-service
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"prod-redis-service","namespace":"default"},"spec":{"externalName"...
Selector: <none>
Type: ExternalName
IP:
External Name: r-uf6d6wb8wj63ru7vtm.redis.rds.aliyuncs.com
Session Affinity: None
Events: <none>
[root@test-centos-6979f6bc4c-clbz7 /]# redis-cli -h prod-redis-service.default.svc.ziioffice.com -p 6379 prod-redis-service.default.svc.ziioffice.com:6379> keys * (error) NOAUTH Authentication required.

  

 连接mongodb服务

apiVersion: v1
kind: Service
metadata:
  name: prod-mongodb-service
  namespace: defalut
spec:
  type: ExternalName
  externalName: dds-uf618b111111.mongodb.rds.aliyuncs.com

  

posted @ 2020-08-13 16:39  个人成长之路  阅读(544)  评论(0编辑  收藏  举报