Service

Service存在的意义

  • 防止pod失联(服务发现)
  • 定义一组pod的访问策略(负载均衡)

Pod 与Service的关系

  • 通过label-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)

kubernetes(十) kubernetes service,ingress&cm,secret

Service的三种类型

ClusterIP

  • 默认类型: 分配一个稳定的IP地址,即VIP,只能在集群内部访问(通Namespace内的POD)

kubernetes(十) kubernetes service,ingress&cm,secret

NodePort

  • 在每个节点上启用一个端口来暴露服务,可以在集群外部访问,也会分配一个稳定的内部集群IP地址
  • 访问地址: <NodeIP>:<NodePort>

kubernetes(十) kubernetes service,ingress&cm,secret

LoadBalancer

  • 与NodePort类似,在每个节点上启用一个端口来暴露服务
  • kubernetes会请求底层云平台上的负载均衡器,将每个node(nodeip:port)作为后端添加进去
    kubernetes(十) kubernetes service,ingress&cm,secret

    Service代理模式

kubernetes(十) kubernetes service,ingress&cm,secret

iptables VS ipvs

  • iptables
    • 默认的代理模式
    • 灵活,功能强大
    • 规则遍历匹配和更新,呈线性时延
  • ipvs
    • 工作在内核态,有更高的性能
    • 调度算法丰富: rr, wrr,lc,wlc,ip hash

ipvs模式在二进制部署的k8s集群中需要调整kube-proxy的配置文件

  • 所有节点配置如下(master 和 node都需要做)

    • 安装ipvs
    yum -y install ipvsadm
    modprobe br_netfilter
    cat &gt; /etc/sysconfig/modules/ipvs.modules &lt;&lt;EOF
    #!/bin/bash
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack_ipv4
    EOF
    chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4

service DNS名称

深入理解ingress

ingress为弥补NodePort的不足而生

  • NodePort 存在的不足
    • 一个端口只能一个服务使用,端口需要提前规划
    • 只支持四层负载均衡

pod与ingress的关系

  • 通过service相关联
  • 通过ingress controller实现Pod的负载均衡
    • 支持TCP/UDP四层和HTTP(S)七层

kubernetes(十) kubernetes service,ingress&cm,secret

ingress controller

Ingress Controller有很多实现,我们这里采用官方维护的Nginx控制器。

部署文档:https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md

  • 注意事项
    • ingress-controller镜像要修改成国内的: registry.cn-hangzhou.aliyuncs.com/acs/aliyun-ingress-controller:v0.30.0.2
    • 使用宿主机网络:hostNetwork:true
  • 其他控制器
    • Traefik: HTTP反向代理、负载均衡工具
    • Istio:服务治理,控制入口流量
  • 工作原理
    kubernetes(十) kubernetes service,ingress&cm,secret

ingress 规则

基础准备

  • 准备两个web service为后续的http和https做准备
$ kubectl create deployment web --image=nginx:1.18-alpine    #创建deploy
$ kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web    #暴露端口并创建svc=web的控制器
$ kubectl create deployment web1 --image=nginx:1.18-alpine
$ kubectl expose deployment web1 --port=80 --type=NodePort --target-port=80 --name=web1

单域名基础配置

$ vim http_demo.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: http-ingress
spec:
  rules:
  - host: test.cropy.cn
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 80
$ kubectl apply -f http_demo.yml
$ kubectl get ingress     #查看对应的ingress
$ kubectl exec -it nginx-ingress-controller-5pn98 -n ingress-nginx -- bash   #进入其中的一个ingressPod即可查看nginx.conf中的配置
www-data@centos7-node7:/etc/nginx$ cat nginx.conf| grep test.cropy.cn
  • https域名配置

这个需要引入secret这个资源类型保存证书文件

找个文件夹自签证书

cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

cat > ca-csr.json <<EOF
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

cat > blog.ctnrs.com-csr.json <<EOF
{
  "CN": "blog.ctnrs.com",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes blog.ctnrs.com-csr.json | cfssljson -bare blog.ctnrs.com 

$ kubectl create secret tls blog.cropy.cn --cert=blog.cropy.cn.pem --key=blog.cropy.cn-key.pem    #创建secret
$ kubectl get secret         #查看secret

创建https的ingress

$ vim https_svc.yml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tls-blog-cropy-cn-ingress
spec:
  tls:
  - hosts:
    - blog.cropy.cn
    secretName: blog.cropy.cn
  rules:
    - host: blog.cropy.cn
      http:
        paths:
        - path: /
          backend:
            serviceName: web
            servicePort: 80
$ kubectl apply -f https_svc.yml 

测试方法

宿主机将域名和对应的ingress-controller控制器的节点ip做hosts解析,即可测试

Ingress – 根据URL路由到多个服务

nginx根据URL路由到多个服务使用的是location 去做区分,nginx-ingress采用的是path去定义不同的后端服务,从而实现根据path路由多个服务

test.cropy.cn -&gt;    192.168.56.14   -&gt; / foo    web:80
                                       / bar    web1:80
  • 修改web和web1对应pod的html内容
$ kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
web-65b7447c7-ctdlr     1/1     Running   0          4d11h
web1-6ff6f9d746-txnw4   1/1     Running   0          107s

$ kubectl exec -it web-65b7447c7-ctdlr -- bash
root@web-65b7447c7-ctdlr:/# echo "foo" > /usr/share/nginx/html/index.html 

$  kubectl exec -it web1-6ff6f9d746-txnw4  -- sh
/ # echo "bar" > /usr/share/nginx/html/index.html 
  • 配置yaml
$ vim location_http.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: location-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: test.cropy.cn
    http:
      paths:
      - path: /foo
        backend:
          serviceName: web
          servicePort: 80
      - path: /bar
        backend:
          serviceName: web1
          servicePort: 80
$ kubectl apply -f location_http.yml
  • 测试访问
http://test.cropy.cn/bar
http://test.cropy.cn/foo

ingress-基于名称的虚拟主机

foo.cropy.cn --|                 |-> foo.cropy.cn web:80
               | 192.168.56.14   |
bar.cropy.cn --|                 |-> bar.cropy.cn web1:80
  • yaml配置
$ vim domain_http.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.cropy.cn
    http:
      paths:
      - backend:
          serviceName: web
          servicePort: 80
  - host: bar.cropy.cn
    http:
      paths:
      - backend:
          serviceName: web1
          servicePort: 80
$ kubectl apply domain_http.yml
$ kubectl get ingress
  • 测试访问
# 修改hosts
192.268.56.14 foo.cropy.cn
192.268.56.14 bar.cropy.cn
# 然后浏览器访问
bar.cropy.cn
foo.cropy.cn

Annotations对Ingress个性化配置

$ vim personal_http.yml           
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress-proxy
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
  rules:
  - host: example.cropy.cn
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 80
$ kubectl apply -f personal_http.yml 
$ kubectl exec  nginx-ingress-controller-5pn98 -n ingress-nginx cat /etc/nginx/nginx.conf | grep proxy # 查看ingress pod下的nginx配置
  • 定制化http跳转https
$ vim rewrite_https.yml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tls-example-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec: 
  tls:
  - hosts:
    - blog.cropy.cn
    secretName: blog.cropy.cn
  rules:
    - host: blog.cropy.cn
      http:
        paths:
        - path: /
          backend:
            serviceName: web
            servicePort: 80

ingress controller高可用方案

kubernetes(十) kubernetes service,ingress&cm,secret

管理应用程序配置

secret

加密数据存放在etcd中,让pod的容器以挂载Volume的方式访问

应用场景: 凭据

  • pod使用secret的两种方式

    • 变量注入: 不适用与随时变动的情况

    • 挂载: 支持随时变动,但是生效需要一定的时间

创建secret

  • secret创建类型
    • docker-registry: Create a secret for use with a Docker registry
    • generic: Create a secret from a local file, directory or literal value
    • tls: Create a TLS secret
$ kubectl create namespace config
$ kubectl create secret generic mysql-root-password -n config --from-literal=password=123456    # 创建环境变量
$ kubectl create secret tls blog.cropy.cn --cert=blog.cropy.cn.pem --key=blog.cropy.cn-key.pem  # 创建证书型变量
$  kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER
--docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL #创建私有仓库类型secret
  • 引用所创建类型的secret
$ vim mysql_pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: mysql
  namespace: config
spec:
  containers:
  - name: mysql
    image: mysql:5.6
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          key: password
          name: mysql-root-password
$ kubectl apply -f mysql_pod.yml 

configmap

与secret类似,区别在于ConfigMap存放的是不需要加密的配置信息

  • 应用场景: 应用程序配置
Examples:
  # Create a new configmap named my-config based on folder bar
  kubectl create configmap my-config --from-file=path/to/bar

  # Create a new configmap named my-config with specified keys instead of file basenames on disk
  kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt

  # Create a new configmap named my-config with key1=config1 and key2=config2
  kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2

  # Create a new configmap named my-config from the key=value pairs in the file
  kubectl create configmap my-config --from-file=path/to/bar

  # Create a new configmap named my-config from an env file
  kubectl create configmap my-config --from-env-file=path/to/bar.env

应用如何动态更新配置

  • ConfigMap更新时,业务也随之更新的方案:

    • 当ConfigMap发生变更时,应用程序动态加载
    • 触发滚动更新,即重启服务
  • 其他方案

    1、inotify 检查文件是否变动 -> 重启应用 (sidecar)
    2、与版本迭代一起(简单粗暴)
    3、进行热加载,需要程序有这块逻辑支持
    4、采用配置中心,例如apollo、disconf (与方法3类似)