云原生Istio安装和使用


1 Kubernetes集群环境

在这里插入图片描述

Istio支持在不同的平台下安装其控制平面,例如Kubernetes、Mesos和虚拟机等。
课程上以 Kubernetes 为基础讲解如何在集群中安装 Istio (Istio 1.0.6 要求Kubernetes的版本在1.11及以上)。
可以在本地或公有云上搭建Istio环境,也可以直接使用公有云平台上已经集成了Istio的托管服务。

目前有许多软件提供了在本地搭建Kubernetes集群的能力,例如Minikube/kubeadm都可以搭建kubernetes集群,我这边所选用的是kubeadm来安装Kubernetes集群。
Kubeadm 是一个工具,它提供了 kubeadm init 以及 kubeadm join 这两个命令作为快速创建 kubernetes 集群的最佳实践。

准备机器

两台centos7的虚拟机,地址分别为

192.168.187.137

192.168.187.138

大家根据自己的情况来准备centos7的虚拟机。

虚拟机要保证彼此之间能够ping通,也就是处于同一个网络中。

Kubernets官网推荐虚拟机的配置最低要求:2核2G(这边建议最低2核3G配置)

Docker环境

在每一台机器上都安装好Docker,我这边使用的版本为18.09.0

# docker查看版本命令
  docker --version

修改hosts文件

(1)设置master角色,在192.168.187.138打开hosts文件

# 打开hosts文件
vi /etc/hosts
# 设置192.168.187.138为master的hostname,用m来表示
192.168.187.138 m
# 设置192.168.187.137为worker的hostname,用w1来表示
192.168.187.137 w1

(2)设置worker角色,在192.168.187.137打开hosts文件

# 打开hosts文件
vi /etc/hosts
# 设置192.168.187.138为master的hostname,用m来表示
192.168.187.138 m
# 设置192.168.187.137为worker的hostname,用w1来表示
192.168.187.137 w1

(3)使用ping测试一下

ping m

ping w1

kubeadm安装版本

安装的版本是1.14.0

kubernetes集群网络插件-calico

calico网络插件:https://docs.projectcalico.org/v3.9/getting-started/kubernetes/

calico,同样在master节点上操作

Calico为容器和虚拟机工作负载提供一个安全的网络连接。

验证 Kubernetes安装

1)在master节点上检查集群信息

命令:kubectl get nodes

2)监控 w1节点的状态 :kubectl get nodes -w

监控成 ready状态

3)查询pod 命令:kubectl get pods -n kube-system

注意:Kubernetes集群安装方式有很多,大家可以安装自己熟悉的方式搭建Kubernetes, 这里只是介绍本次课程上使用的kubernets集群环境

2 安装Istio

在Istio的版本发布页面https://github.com/istio/istio/releases/tag/1.0.6下载安装包并解压(我用的是一个比较稳定的版本1.0.6版本,放到master上面,以Linux平台的istio-1.0.6-linux.tar.gz为例)

1.解压tar -xzf istio-1.0.6-linux.tar.gz

2.进入istio目录cd istio-1.0.6/

Istio的安装目录及其说明

文件/文件夹 说明
bin 包含客户端工具,用于和Istio APIS交互
install 包含了Consul和Kubernetes平台的Istio安装脚本和文件,在Kubernetes平台上分为YAML资源文件和Helm安装文件
istio.VERSION 配置文件包含版本信息的环境变量
samples 包含了官方文档中用到的各种应用实例如bookinfo/helloworld等等,这些示例可以帮助读者理解Istio的功能以及如何与Istio的各个组件进行交互
tools 包含用于性能测试和在本地机器上进行测试的脚本文件和工具

有以下几种方式安装Istio:

  • 使用install/kubernetes文件夹中的istio-demo.yaml进行安装;
  • 使用Helm template渲染出Istio的YAML安装文件进行安装;
  • 使用Helm和Tiller方式进行安装。

课程中使用的是使用install/kubernetes文件夹中的istio-demo.yaml进行安装

2.1 快速部署Istio

Kubernetes CRD介绍

比如Deployment/Service/etc等资源是kubernetes本身就支持的类型,除了这些类型之外kubernetes还支持资源的扩展,说白了就是可以自定义资源类型,如果没有CRD的支持的话,istio一些资源类型是创建不成功的

#crds.yaml路径:
istio-1.0.6/install/kubernetes/helm/istio/templates/crds.yaml
# 执行
kubectl apply -f crds.yaml
# 统计个数
kubectl get crd -n istio-system | wc -l

Kubernetes平台对于分布式服务部署的很多重要的模块都有系统性的支持,借助如下一些平台资源可以满足大多数 分布式系统部署和管理的需求,但是在不同应用业务环境下,对于平台可能有一些特殊的需求,这些需求可以抽象为Kubernetes的扩展资源,而 Kubernetes的CRD(CustomResourceDefifinition)为这样的需求提供了轻量级的机制

执行安装命令

(1)根据istio-1.0.6/install/kubernetes/istio-demo.yaml创建资源

kubectl apply -f istio-demo.yaml
# 会发现有这么多的资源被创建了,很多很多	,里面的命名空间用的是istio-system

2)查看核心组件资源

kubectl get pods -n istio-system 
kubectl get svc -n istio-system 

在这里插入图片描述

可以看到有3个是completed,其它的组件都必须是running, completed表示的是用的是k8s里面JOB资源,表示这个任务已经执行结束了

可以看到比如citadel有了,pilot有了,sidecar也有了,其它的比如ingress网关都有了,监控也有了

2.2 回顾K8S组件以及使用

回顾课程涉及到的kubernetes组件

2.2.1 Deployment

一旦运行了 Kubernetes 集群,就可以在其上部署容器化应用程序。 为此,需要创建 Kubernetes Deployment 配置。
Deployment 负责 Kubernetes 如何创建和更新应用程序的实例。
创建 Deployment 后,Kubernetes master 将应用程序实例调度到集群中的各个节点上。

创建nginx_deployment.yaml文件

apiVersion: apps/v1 ## 定义了一个版本
kind: Deployment ##k8s资源类型是Deployment
metadata: ## metadata这个KEY对应的值为一个Maps
  name: nginx-deployment ##资源名字 nginx-deployment
  labels: ##将新建的Pod附加Label
    app: nginx ##一个键值对为key=app,valuen=ginx的Label。
spec: #以下其实就是replicaSet的配置
  replicas: 3 ##副本数为3个,也就是有3个pod
  selector: ##匹配具有同一个label属性的pod标签
    matchLabels: ##寻找合适的label,一个键值对为key=app,value=nginx的Labe
      app: nginx
  template: #模板
    metadata:
      labels: ##将新建的Pod附加Label
        app: nginx
    spec:
      containers:  ##定义容器
      - name: nginx ##容器名称
        image: nginx:1.7.9 ##镜像地址
        ports:
        - containerPort: 80 ##容器端口

(1)执行资源文件命令

kubectl apply -f nginx_deployment.yaml

(2)查看pod

kubectl get pods
查看pod详情
kubectl get pods -o wide

(3)查看deployment命令

kubectl get deployment

(4)查看deployment详情命令

kubectl get deployment -o wide

2.2.2 Labels and Selectors

顾名思义,就是给一些资源打上标签的

labels

当资源很多的时候可以用可以用labels标签来对资源分类

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
 
 # 表示名称为nginx-pod的pod,有一个label,key为app,value为nginx。
 #我们可以将具有同一个label的pod,交给selector管理

selectors

如果我想使用这个标签里面的k8s资源,那么需要用到k8s里面selector组件,用selector来匹配到特定的的label

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx-deployment
  labels:  # 定义了一个labels,key=app,value=nginx
    app: nginx
spec:
  replicas: 3
  selector:             # 用selector匹配具有同一个label属性的pod标签
    matchLabels:
      app: nginx         

查看pod的label标签命令:

kubectl get pods --show-labels

2.2.3 Namespace

命名空间就是为了隔离不同的资源。比如:Pod、Service、Deployment等。可以在输入命令的时候指定命名空间`-n`,如果不指定,则使用默认的命名空间:default。

查看一下当前的所用命名空间:kubectl get namespaces/ns

查看一下kube-system命名空间:kubectl get pods -n kube-system

(1)创建自己的namespace

my-namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
    name: myns

(2)执行命令:kubectl apply -f my-namespace.yaml

(3)查看命令

kubectl get ns

删除命名空间

kubectl delete namespaces 空间的名字

注意:
删除一个namespace会自动删除所有属于该namespace的资源。
default和kube-system命名空间不可删除。

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

首先自动注入是需要跟命名空间挂钩,所以需要创建一个命名空间,只需要给命名空间开启自动注入,后面创建的资源只要挂载到这个命名空间下,那么这个命名空间下的所有的资源都会自动注入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 的注入

猜你喜欢

转载自blog.csdn.net/ZGL_cyy/article/details/130470528