2.2.4 Service
集群内部访问方式(ClusterIP)
Pod虽然实现了集群内部互相通信,但是Pod是不稳定的,比如通过Deployment管理Pod,随时可能对Pod进行扩缩容,这时候Pod的IP地址是变化的。能够有一个固定的IP,使得集群内能够访问。也就是之前在架构描述的时候所提到的,能够把相同或者具有关联的Pod,打上Label,组成Service。而Service有固定的IP,不管Pod怎么创建和销毁,都可以通过Service的IP进行访问 k8s用service来解决这个问题,因为service会对应一个不会的ip,然后内部通过负载均衡到相同label上的不同pod机器上
(1)创建whoami-deployment.yaml文件
apiVersion: apps/v1 ## 定义了一个版本 kind: Deployment ##资源类型是Deployment metadata: ## metadata这个KEY对应的值为一个Maps name: whoami-deployment ##资源名字 labels: ##将新建的Pod附加Label app: whoami ##key=app:value=whoami spec: ##资源它描述了对象的 replicas: 3 ##副本数为1个,只会有一个pod selector: ##匹配具有同一个label属性的pod标签 matchLabels: ##匹配合适的label app: whoami template: ##template其实就是对Pod对象的定义 (模板) metadata: labels: app: whoami spec: containers: - name: whoami ##容器名字 下面容器的镜像 image: jwilder/whoami ports: - containerPort: 8000 ##容器的端口
jwilder/whoami这是一个可以在docker仓库里面拉取到的镜像,是官方提供的一个演示的镜像
(1)执行命令
kubectl apply -f whoami-deployment.yaml
(2)查看详情
kubectl get pods -o wide
(3)在集群内正常访问
curl 192.168.221.80:8000/192.168.14.6:8000/192.168.14.7:8000
(5)测试:删除其中一个pod,查看重新生成的ip有没有变化
kubectl delete pod whoami-deployment-678b64444d-jdv49
新加的pod地址发生了变化
(6) Service 登场
查询svc命名空间下的资源
kubectl get svc
(7)创建自己的service空间
创建:kubectl expose deployment deployment名字 例如:kubectl expose deployment whoami-deployment
(8)重新查询service空间,会发现有一个whoami-deployment的service,ip为10.107.4.74
[root@m k8s]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d12h whoami-deployment ClusterIP 10.107.4.74 <none> 8000/TCP 3s
(9)访问service:curl 10.107.4.74:8000
多试几次会发现service会负载到其中的一个pod上
(10)查看service
kubectl describe svc service名字 例如:kubectl describe svc whoami-deployment
[root@m k8s]# kubectl describe svc whoami-deployment Name: whoami-deployment Namespace: default Labels: app=whoami Annotations: <none> Selector: app=whoami Type: ClusterIP IP: 10.107.4.74 Port: <unset> 8000/TCP TargetPort: 8000/TCP Endpoints: 192.168.190.86:8000,192.168.190.87:8000,192.168.190.89:8000 Session Affinity: None Events: <none> # 说白了 service下面挂在了Endpoints节点
(11)将原来的节点扩容到5个
kubectl scale deployment whoami-deployment --replicas=5
(12)删除service命令
kubectl delete service service名字 kubectl delete service whoami-deployment
总结:其实Service存在的意义就是为了Pod的不稳定性,而上述探讨的就是关于Service的一种类型Cluster IP
外部服务访问集群中的Pod(NodePort)
也是Service的一种类型,可以通过NodePort的方式说白了,因为外部能够访问到集群的物理机器IP,所以就是在集群中每台物理机器上暴露一个相同的端口锁,比如32008
操作
(1)先删除之前的service
kubectl delete svc whoami-deployment
(2)再次查看命令
kubectl get svc 发现whoami-deployment已被删除
(3)查看pod命令
kubectl get pods
(4)创建type为NodePort的service
kubectl expose deployment whoami-deployment --type=NodePort
查看:kubectl get svc
并且生成了一个port端口,会有一个8000端口映射成宿主机的31504端口
注意上述的端口31504,实际上就是暴露在集群中物理机器上的端口
lsof -i tcp:31504 netstat -ntlp|grep 31504
浏览器通过物理机器的IP访问
http://192.168.187.137:31504/ curl 192.168.187.137:31504/
NodePort虽然能够实现外部访问Pod的需求,但是需要占用了各个物理主机上的端口
删除资源
kubectl delete -f whoami-deployment.yaml kubectl delete svc whoami-deployment
2.2.5 Ingress
前面我们也学习可以通过service nodeport方式实现外部访问Pod的需求,但是会占用了各个物理主机上的端口,所以 这种方式不好
删除资源
# 删除pod kubectl delete -f whoami-deployment.yaml # 删除service kubectl delete svc whoami-deployment
那接下来还是基于外部访问内部集群的需求,使用Ingress实现访问whoami需求。
(1)创建whoami-service.yaml文件
创建pod和service
apiVersion: apps/v1 ## 定义了一个版本 kind: Deployment ##资源类型是Deployment metadata: ## metadata这个KEY对应的值为一个Maps name: whoami-deployment ##资源名字 labels: ##将新建的Pod附加Label app: whoami ##key=app:value=whoami spec: ##资源它描述了对象的 replicas: 3 ##副本数为1个,只会有一个pod selector: ##匹配具有同一个label属性的pod标签 matchLabels: ##匹配合适的label app: whoami template: ##template其实就是对Pod对象的定义 (模板) metadata: labels: app: whoami spec: containers: - name: whoami ##容器名字 下面容器的镜像 image: jwilder/whoami ports: - containerPort: 8000 ##容器的端口 --- apiVersion: v1 kind: Service metadata: name: whoami-service spec: ports: - port: 80 protocol: TCP targetPort: 8000 selector: app: whoami
(2)执行资源命令
kubectl apply -f whoami-service.yaml
(3)创建whoami-ingress.yaml文件
apiVersion: extensions/v1beta1 kind: Ingress # 资源类型 metadata: name: whoami-ingress # 资源名称 spec: rules: # 定义规则 - host: whoami.qy.com # 定义访问域名 http: paths: - path: / # 定义路径规则,/ 表示能够命中任何路径规则 backend: serviceName: whoami-service # 把请求转发给service资源,这个service就是我们前面运行的service servicePort: 80 # service的端口
(4)执行命令:
kubectl apply -f whoami-ingress.yaml
(5)、查看ingress资源:
kubectl get ingress
(6)查看ingress资源详细:
kubectl describe ingress whoami-ingress
(7)、修改win的hosts文件,添加dns解析
192.168.187.137 whoami.qy.com
(8)、打开浏览器,访问whoami.qy.com
流程总结
浏览器发送请求给ingress,ingress根据规则配置把请求转发给对应的service,由于service配置了pod,所以请求最终发给了pod内对应的服务
总结
ingress转发请求更加灵活,而且不需要占用物理机的端口,所以建议使用这种方式转发外部请求到集群内部
2.3 初步感受istio
在docker中是通过container来部署业务的,在k8s里面是通过pod来部署业务的,那么在istio里面如何体现sidecar呢?
猜想:
会不会在pod中除了业务需要的container之外还会有一个sidecar的container存在呢?
验证猜想
(1)准备一个资源 first-istio.yaml
apiVersion: apps/v1 ## 定义了一个版本 kind: Deployment ##资源类型是Deployment metadata: name: first-istio spec: selector: matchLabels: app: first-istio replicas: 1 template: metadata: labels: app: first-istio spec: containers: - name: first-istio ##容器名字 下面容器的镜像 image: registry.cn-hangzhou.aliyuncs.com/sixupiaofei/spring-docker-demo:1.0 ports: - containerPort: 8080 ##容器的端口 --- apiVersion: v1 kind: Service ##资源类型是Service metadata: name: first-istio ##资源名字first-istio spec: ports: - port: 80 ##对外暴露80 protocol: TCP ##tcp协议 targetPort: 8080 ##重定向到8080端口 selector: app: first-istio ##匹配合适的label,也就是找到合适pod type: ClusterIP ## Service类型ClusterIP
创建文件夹istio,然后把first-istio放进去,按照正常的创建流程里面只会有自己私有的containers,不会有sidecar
#执行,会发现 只会有一个containers在运行 kubectl apply -f first-istio.yaml #查看first-isitio service kubectl get svc # 查看pod的具体的日志信息命令 kubectl describe pod first-istio-8655f4dcc6-dpkzh #删除 kubectl delete -f first-istio.yaml
查看pod命令
kubectl get pods
思考:怎么让pod里面自动增加一个Sidecar呢?
有两种方式:手动注入和自动注入
2.4 手动注入
(1)删除上述资源,重新创建,使用手动注入sidecar的方式
istioctl kube-inject -f first-istio.yaml | kubectl apply -f -
**注意:**istioctl 命令需要先在/etc/profile配置PATH
- vim /etc/profile
- 增加isito安装目录配置
export ISTIO_HOME=/home/tools/istio-1.0.6 export PATH=$PATH:$ISTIO_HOME/bin
- 加载profile文件
source profile
(2)查看pod数量
kubectl get pods # 注意该pod中容器的数量 ,会发现容器的数量不同了,变成了2个
(3) 查看service
kubectl get svc
思考:
我的yaml文件里面只有一个container,执行完之后为什么会是两个呢?
我的猜想另外一个会不会是Sidecar,那么我描述一下这个pod,看看这两个容器到底是什么
# 查看pod执行明细 kubectl describe pod first-istio-75d4dfcbff-qhmxj
发现竟然除了我的容器之外还多了一个代理容器,此时我们大胆猜想这个代理会不会就是sidecar呢
接着往上翻
此时已经看到了我们需要的答案了
查看yaml文件内容
kubectl get pod first-istio-75d4dfcbff-qhmxj -o yaml
总结
这个yaml文件已经不是我们原来的yaml文件了,会发现这个yaml文件还定义了一个proxy的image,这个image是我们提前就已经准备好了的,所以istio是通过改变yaml文件来实现注入一个代理
(4)删除资源
istioctl kube-inject -f first-istio.yaml | kubectl delete -f -
**思考:**难道我以后每次都要写那么一大串命令创建sidecar吗,有没有正常的命令来直接创建sidecar呢?
2.5 自动注入sidecar
首先自动注入是需要跟命名空间挂钩,所以需要创建一个命名空间,只需要给命名空间开启自动注入,后面创建的资源只要挂载到这个命名空间下,那么
(1)创建命名空间
kubectl create namespace my-istio-ns
(2)给命名空间开启自动注入
kubectl label namespace my-istio-ns istio-injection=enabled
(3)创建资源,指定命名空间即可
# 查询 istio-demo命名空间下面是否存在资源 kubectl get pods -n my-istio-ns # 在istio-demo命名空间创建资源 kubectl apply -f first-istio.yaml -n my-istio-ns
(4)查看资源
kubectl get pods -n my-istio-ns
(5)查看资源明细
kubectl describe pod pod-name -n my-istio-ns
发现除了我的容器之外依旧多了一个代理容器
(6)查看service
kubectl get svc -n my-istio-ns
(7)删除资源
kubectl delete -f first-istio.yaml -n my-istio-ns
大家应该都已经明白了istio怎么注入sidecar的了吧
sidecar注入总结:
不管是自动注入还是手动注入原理都是在yaml文件里面追加一个代理容器,这个代理容器就是sidecar,这里更推荐自动注入的方式来实现 sidecar 的注入