Service
Service存在的意义
- 防止pod失联(服务发现)
- 定义一组pod的访问策略(负载均衡)
Pod 与Service的关系
- 通过label-selector相关联
- 通过Service实现Pod的负载均衡(TCP/UDP 4层)
Service的三种类型
ClusterIP
- 默认类型: 分配一个稳定的IP地址,即VIP,只能在集群内部访问(通Namespace内的POD)
NodePort
- 在每个节点上启用一个端口来暴露服务,可以在集群外部访问,也会分配一个稳定的内部集群IP地址
- 访问地址: <NodeIP>:<NodePort>
LoadBalancer
- 与NodePort类似,在每个节点上启用一个端口来暴露服务
- kubernetes会请求底层云平台上的负载均衡器,将每个node(nodeip:port)作为后端添加进去
Service代理模式
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 > /etc/sysconfig/modules/ipvs.modules <<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名称
- CoreDNS:是一个dns服务器,kubernetes默认采用,以POD部署在集群中,coredns服务监视kubernetesAPI,为每一个service创建DNS记录用来作为域名解析
- CoreDNS YAML文件:https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns
- ClusterIP 的A记录格式:
<service-name>.<namespace-name>.svc.cluster.local
深入理解ingress
ingress为弥补NodePort的不足而生
- NodePort 存在的不足
- 一个端口只能一个服务使用,端口需要提前规划
- 只支持四层负载均衡
pod与ingress的关系
- 通过service相关联
- 通过ingress controller实现Pod的负载均衡
- 支持TCP/UDP四层和HTTP(S)七层
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:服务治理,控制入口流量
- 工作原理
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
单域名基础配置
- 官方文档: https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
- 单域名yml
$ 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这个资源类型保存证书文件
找个文件夹自签证书
代码语言:javascript复制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
代码语言:javascript复制$ 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 -> 192.168.56.14 -> / 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-基于名称的虚拟主机
代码语言:javascript复制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个性化配置
- 官方文档:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md
- 个性化定制proxy配置
$ 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高可用方案
管理应用程序配置
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类似)