七层负载均衡Ingress
回顾: 通过service访问内网服务的,需要在物理机开辟一些端口,当 Service 越来越多的时候,需要开辟的端口也越来越多,这些庞大的端口的管理就会成为的灾难?
Ingress是什么?
Ingress 是 kubernetes 为了实现在应用层进行转发,对 nginx 进行云原生模式的封装(增强),使得 Ingress 可以对Service 实现请求的转发,且实现动态转发规则的改写。
为什么引入Ingress?
我们说 K8S 的服务(Service)时说暴露了 Service 的三种方式 ClusterIP、NodePort 与 LoadBalance,这几种方式都是在 Service 的维度提供的。Service 的作用体现在两个方面:对集群内部,它不断跟踪 POD 的变化,更新 Endpoint 中对应 POD 的对象,提供了 IP 不断变化的 POD 的服务发现机制;对集群外部,它类似负载均衡,可以在集群内外部对 POD 进行访问。但是,单独用 Service 暴露服务的方式,在实际生产环境中不太合适:
ClusterIP 的方式只能在集群内部访问。 NodePort 方式的话,测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort的端口管理是灾难。 LoadBalance 方式受限于云平台,且通常在云平台部署 ELB 还需要额外的费用。 所幸 K8S 还提供了一种集群维度暴露服务的方式,也就是 Ingress。Ingress 可以简单理解为 Service 的 Service。它通过独立的 Ingress 对象来制定请求转发规则,把请求路由到一个或多个 Service 中。这样就把服务与请求规则解耦了,可以从业务维度统一考虑业务的暴露,而不用为每个 Service 单独考虑。 举个例子:现在集群有api、文件存储、前端3个service,可以通过一个 ingress 对象来实现图中的请求转发
ingress规则是很灵活的,可以根据不同域名、不同path转发请求到不同的service,并且支持https/http。
Ingress部署
Ingress-nginx工作流程
Ingress-nginx工作流程: 建立一个统一的入口,根据 Ingress 访问规则(部署的时候建立的)动态修改 nginx 配置文件,通过动态的nginx来进行转发。
部署文件介绍
namespace.yaml :创建独立的命名空间 ingress-nginx。
configmap.yaml :创建 ConfigMap 对象
rbac.yaml :负载 Ingress 的 RBAC 授权控制,其创建了 Ingress 用到的 ServiceAccount、ClusterIP、Role、RoleBinding、ClusterRoleBinding。
with-rbac.yaml :使用带 rbac 的方式创建 ingress-controller,是整个 ingress 的核心部署文件。
mandatory.yaml :该文件整合了前面四项文件的内容,是用于实际部署ingress服务的yaml文件。即只需要使用该文件就可以完成ingress-controller的全部部署工作。
service-nodeport.yaml :建立统一的入口
部署 Ingress-controller
下载所需的 Ingress 相关配置文件,如上图所示。
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
修改service-nodeport.yaml,增加NodePort,固定端口: 执行部署命令:部署nginx-ingress-controller
kubectl apply -f 05-mandatory.yaml
kubectl apply -f 06-service-nodeport.yaml
kubectl get pods -n ingress-nginx
kubectl get pod -n ingress-nginx --show-labels
kubectl get svc -n ingress-nginx
kubectl get daemonset -n ingress-nginx
curl http://192.168.254.108:30080/healthz -I
ingress应用部署
部署一个 Ingress 资源对象:ingress-01.yaml 配置文件如下
apiVersion : extensions/v1beta1
kind : Ingress
metadata :
name : nginx
namespace : default
labels :
app : nginx
spec :
rules :
- host : ingress.veli.com
http :
paths :
- backend :
serviceName : nginx
servicePort : 80
创建一个后端服务的 yaml 配置文件:nginx-app.yaml
apiVersion : v1
kind : Service
metadata :
name : nginx
namespace : default
spec :
selector :
app : nginx
ports :
- port : 80
targetPort : 80
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx
namespace : default
spec :
replicas : 1
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : hub.veli.com/library/nginx: latest
ports :
- containerPort : 80
kubectl apply -f nginx-app.yaml
kubectl apply -f ingress-01.yaml
动态映射
登录到 ingress 控制器动态映射的 nginx.conf 的 POD:
kubectl exec -it nginx-ingress-controller-h65nm -n ingress-nginx -- sh
多个域名、多个服务
配置多个域名,通过配置两个域名进行分别转发到不同的服务上面:ingress-02.yaml 配置文件如下
apiVersion : extensions/v1beta1
kind : Ingress
metadata :
name : nginx
namespace : default
labels :
app : nginx
spec :
rules :
- host : ingress.nginx.veli.com
http :
paths :
- path : /
backend :
serviceName : nginx
servicePort : 80
- host : ingress.tomcat.veli.com
http :
paths :
- path : /
backend :
serviceName : tomcat
servicePort : 8080
部署两个服务:前面已经部署过一个 nginx 服务了,再部署一个 tomcat 服务,tomcat-app.yaml 配置文件如下:
apiVersion : v1
kind : Service
metadata :
name : tomcat
namespace : default
spec :
selector :
app : tomcat
ports :
- port : 8080
targetPort : 8080
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : tomcat
namespace : default
spec :
replicas : 1
selector :
matchLabels :
app : tomcat
template :
metadata :
labels :
app : tomcat
spec :
containers :
- name : tomcat
image : hub.veli.com/library/tomcat: latest
ports :
- containerPort : 8080
kubectl apply -f tomcat-app.yaml
kubectl apply -f ingress-02.yaml
一个域名、多个服务
path: /nginx
ingress.veli.com/nginx ===>> URL: /nginx/xxx/ooo
path: /tomcat
ingress.veli.com/tomcat ===>> URL: /tomcat/xxx/ooo
后端服务 nginx 中没有部署任何的服务程序,tomcat 服务中也没有部署任何服务程序,因此在做请求转发的时候,没有与之对应的映射的请求。
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubectl apply -f ingress-03.yaml
重定向
案例:使用 permanent-redirect 重定向到百度
kubectl apply -f ingress-redirect.yaml
https协议访问
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -subj /C= CN/ST= Shenzhen/L= Shenzhen/O= Veli/CN= ingress.veli.com
kubectl create secret tls https-ingress-secret --cert= tls.crt --key= tls.key
kubectl describe secret https-ingress-secret
apiVersion : extensions/v1beta1
kind : Ingress
metadata :
name : ingress- tomcat- tls
namespace : default
labels :
app : tomcat
annotations :
kubernetes.io/ingress.claa : "nginx"
spec :
tls :
- hosts :
- ingress.veli.com
secretName : https- ingress- secret
rules :
- host : ingress.veli.com
http :
paths :
- backend :
serviceName : tomcat
servicePort : 8080
kubectl apply -f ingress-04.yaml
访问一下:由于证书是自己伪造的一个证书,浏览器任务此证书不是一个受信任的证书
问题
Ingress与微服务的Gateway,是否二选一?还是一起分工使用?
Kubernetes的存储资源对象
ConfigMap资源对象
什么是ConfigMap对象
ConfigMap 就是一个配置中心,类似于微服务架构中(nacos、spring-cloud-confg、zookeeper)配置中心服务,用来存储一些配置文件,或者是环境变量。 例如:部署 Redis,可以将 redis.conf 配置存储在 ConfigMap 对象中。部署 MySQL,可以把 my.cnf 存储在 ConfigMap 中。 ConfigMap 资源对象存储数据结构:Key-Value,Value可以是单个字符串,也可以是文件内容。
Kubenetes 云原生架构体系中提供的一套配置中心对象,使得配置和服务进行解耦,一旦配置发生变化,就不需要重新打包,重新部署,服务立马感知到配置文件变化,立马做出调整。
如何创建ConfigMap
根据目录创建
# game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
# ui.propertes
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kubectl create cm myconf-01 --from-file= docs
kubectl get cm
kubectl get cm myconfig-01 -o yaml
kubectl describe cm
根据文件创建
kubectl create cm myconf-02 --from-file= docs/ui-properties
Key-Value方式创建
kubectl create cm myconf-03 --from-literal= username= zhangsan --from-literal= age= 23
直接创建
apiVersion : v1
data :
game.properties : |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties : |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kind : ConfigMap
metadata :
name : myconf- 04
namespace : default
kubectl apply -f myconf.yaml
POD服务内部应用
POD内部服务获取configmap
方式一:valueFrom 只获取 value 值 方式二:envFrom 获取 configmap 资源对象的 Key、Value。 准备两个用于创建 ConfigMap 资源对象的 yaml 文件
apiVersion : v1
kind : ConfigMap
metadata :
name : special- config
namespace : default
data :
special.how : very
special.type : charm
apiVersion : v1
kind : ConfigMap
metadata :
name : env- config
namespace : default
data :
log_level : INFO
apiVersion : v1
kind : Pod
metadata :
name : test- pod
spec :
containers :
- name : test- pod
image : hub.veli.com/library/nginx: latest
command : [ "/bin/sh" , "-c" , "env" ]
env :
- name : SPECIAL_LEVEL_KEY
valueFrom :
configMapKeyRef :
name : special- config
key : special.how
- name : SPECIAL_TYPE_KEY
valueFrom :
configMapKeyRef :
name : special- config
key : special.type
envFrom :
- configMapRef :
name : env- config
restartPolicy : Never
kubectl apply -f special-conf.yaml
kubectl apply -f env-conf.yaml
kubectl apply -f test-pod.yaml
另外一种方式:通过 ConfigMap 设置命令行参数【用作命令行参数,将 ConfigMap 用作命令行参数时,需要先把 ConfigMap 的数据保存在环境变量中,然后通过 $(VAR_NAME) 的方式引用环境变量】
apiVersion : v1
kind : Pod
metadata :
name : test- pod2
spec :
containers :
- name : test- container
image : hub.veli.com/library/nginx: latest
command : [ "/bin/sh" , "-c" , "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env :
- name : SPECIAL_LEVEL_KEY
valueFrom :
configMapKeyRef :
name : special- config
key : special.how
- name : SPECIAL_TYPE_KEY
valueFrom :
configMapKeyRef :
name : special- config
key : special.type
restartPolicy : Never
数据卷挂载方式
通过数据卷插件使用ConfigMap:在数据卷里面使用这个ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容。 POD的yaml配置文件如下
apiversion : v1
kind : Pod
metadata :
name : test- pod3
spec :
containers :
- name : test- container
image : hub.veli.com/library/nginx: latest
command : [ "/bin/sh" , "-c" , "sleep 600s" ]
volumeMounts :
- name : config- volume
mountPath : /etc/config
volumes :
- name : config- volume
configMap :
name : special- config
restartPolicy : Never
kubectl apply -f test-pod-03.yaml
数据卷挂载方式,发现数据已经被成功挂载到容器内部了。
热更新
apiVersion : v1
kind : ConfigMap
metadata :
name : log- config
namespace : default
data :
log_level : INFO
apiVersion : extensions/v1beta1
kind : Deployment
metadata :
name : my- nginx
spec :
replicas : 1
template :
metadata :
labels :
run : my- nginx
spec :
containers :
- name : my- nginx
image : hub.veli.com/library/nginx: latest
ports :
- containerPort : 80
volumeMounts :
- name : config- volume
mountPath : /etc/config
volumes :
- name : config- volume
configMap :
name : log- config
kubectl apply -f logconf.yaml
kubectl apply -f mynginx.yaml
Secret资源对象
Secret是什么?
Secret对象也是一种存储数据的资源对象,但是Secret仅仅是被用来存储敏感数据,具有安全的作用。例如:秘钥、免密、token 等这些数据信息都需要存储在 Secret 资源对象中。 当 POD 需要获取这些敏感数据的时候,只需要从 Secret 中获取即可(使用数据卷的挂载方式,动态的从 Secret 资源对象中获取数据),这样做的好处是防止直接把敏感数据暴露在镜像中,这样可以提高服务的安全性。
Kubernetes认证模式
Secret对象类型
Secret对象存储数据的方式是以键值方式存储数据,在Pod资源进行调用Secret的方式是通过环境变量或者存储卷的方式进行访问数据,解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。 另外,Secret对象的数据存储和打印格式为Base64编码的字符串,因此用户在创建Secret对象时,也需要提供该类型的编码格式的数据。在容器中以环境变量或存储卷的方式访问时,会自动解码为明文格式。需要注意的是,如果是在Master节点上,Secret对象以非加密的格式存储在etcd中,所以需要对etcd的管理和权限进行严格控制。 Secret有4种类型:Service Account、Opaque、kubernetes.io/dockerconfigjson、kubernetes.io/tls
Service Account
用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 POD 的 /run/secrets/kubernetes.io/serviceaccount 目录中;
Opaque
base64 编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为 generic。 创建示例:
echo - n "admin" | base64
YWRtaW4=
echo - n "abcdefgh" | base64
YWJjZGVmZ2g=
apiVersion : v1
kind : Secret
metadata :
name : secret- test
type : Opaque
data :
username : YWRtaW4=
password : YWJjZGVmZ2g=
kubernetes.io/dockerconfigjson
用来存储私有docker registry的认证信息,类型标识为docker-registry。
kubernetes.io/tls
用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为tls。
Secret使用
apiVersion : v1
kind : Pod
metadata :
name : secret- test
labels :
name : secret- test
spec :
volumes :
- name : secrets
secret :
secretName : secret- test
containers :
- image : hub.veli.com/library/nginx: latest
name : db
volumeMounts :
- name : secrets
mountPath : "/etc/secrets"
readOnly : true
kubectl apply -f secret.yaml
kubectl apply -f secret-pod.yaml
另一种使用 secret 的方式:将secret导出到环境变量中:
apiVersion : extensions/v1beta1
kind : Deployment
metadata :
name : secret- deployment
spec :
replicas : 1
template :
metadata :
labels :
app : pod- deployment
spec :
containers :
- name : pod- 1
image : hub.veli.com/library/nginx: latest
ports :
- containerPort : 80
env :
- name : TEST_USER
valueFrom :
secretKeyRef :
name : mysecret
key : username
- name : TEST_PASSWORD
valueFrom :
secretKeyRef :
name : mysecret
key : password