0%

本文使用的版本号:1.4.2

自定义安装组件

参考安装页面,官网给配置分了几个级别,

istio

分别代表:

  • default:根据IstioControlPlaneAPI的默认设置启用组件 (建议用于生产部署)。您可以通过运行命令显示默认设置istioctl profile dump。
  • demo:旨在展示Istio功能且资源需求适中的配置。适合运行Bookinfo应用程序和相关任务。这是随快速入门说明一起安装的配置,但是 如果您想探索更高级的任务,则可以稍后自定义配置以启用其他功能。

    此配置文件可实现高级别的跟踪和访问日志记录,因此不适合进行性能测试。

  • minimal:使用Istio的流量管理功能所需的最少组件集。
  • sds:类似于默认配置文件,但也启用Istio的SDS(​​秘密发现服务)。此配置文件附带默认情况下启用的其他身份验证功能(严格双向TLS)。
  • remote:用于配置共享控制平面的多集群服务网格multicluster mesh。

不同配置安装的的组件也不一样,参考配置,打X是要安装的
istio

当然我们也可以自定义安装组件

cd install/kubernetes/helm/istio
vim values.yaml
gateways:
  enabled: true
 
sidecarInjectorWebhook:
  enabled: true
 
galley:
  enabled: true
 
mixer:
  policy:
    enabled: true
 
  telemetry:
    enabled: true
 
pilot:
  enabled: true
 
security:
  enabled: true
 
nodeagent:
  enabled: false
 
grafana:
  enabled: false
 
prometheus:
  enabled: true
 
tracing:
  enabled: false
 
kiali:
  enabled: false
 
certmanager:
  enabled: false
 
istio_cni:
  enabled: false
 
istiocoredns:
  enabled: false
 
# ...

可以将我们需要安装的组件定义为true之后,参考部署再安装。

所有的配置说明参考官网配置选项.

准备工作

下载istio

下载页面,下载与您的操作系统相对应的安装文件。Linux上可以直接执行下面命令下载并解压最新版

curl -L https://istio.io/downloadIstio | sh -

移至Istio软件包目录

例如,如果软件包为 istio-1.4.2

cd istio-1.4.2

安装目录包含:

  • Kubernetes的安装YAML文件在 install/kubernetes
  • 示例应用程序 samples/
  • 目录中的客户端二进制文件。手动注入Envoy作为Sidecar代理时使用。istioctlbin/istioctl
  • istioctl命令添加到环境变量,如下命令是临时加入
export PATH=$PWD/bin:$PATH

两种安装方式

istio在kubenetes上有两种安装方式,参考官网

helm template方式安装Istio

创建namespace

kubectl create namespace istio-system

安装所有istio的CRD

先将template导出到istio.yaml

helm template install/kubernetes/helm/istio-init --name istio-init --namespace istio-system > istio.yaml

然后执行

kubectl apply -f istio.yaml

或者,两个步骤合二为一

helm template install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl apply -f -

等待所有CRD创建完毕

kubectl -n istio-system wait --for=condition=complete job --all

使用默认配置安装isito,其它配置参考官网,同上,命令也可以分开执行

helm template install/kubernetes/helm/istio --name istio --namespace istio-system | kubectl apply -f -

helm install方式安装Istio

为Tiller创建service-account,如果已安装好Tiller直接跳过。

kubectl apply -f install/kubernetes/helm/helm-service-account.yaml

安装Tiller,如果已安装好Tiller直接跳过。

helm init --service-account tiller

安装istio-init,其中包括了创建istio的CRDs。

helm install install/kubernetes/helm/istio-init --name istio-init --namespace istio-system

等待CRD创建完成。

kubectl -n istio-system wait --for=condition=complete job --all

使用默认配置安装istio,其它配置参考官网

helm install install/kubernetes/helm/istio --name istio --namespace istio-system

确定安装完成

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

卸载Istio

使用helm template安装方式卸载

helm template install/kubernetes/helm/istio --name istio --namespace istio-system | kubectl delete -f -
 
kubectl delete namespace istio-system

使用helm install安装方式卸载

helm delete --purge istio
helm delete --purge istio-init
helm delete --purge istio-cni
kubectl delete namespace istio-system

删除CRDs

kubectl delete -f install/kubernetes/helm/istio-init/files

以上就是通过默认配置安装和卸载istio。

为什么需要服务追踪?

开发和工程团队因为系统组件水平扩展、开发团队小型化、敏捷开发、CD(持续集成)、解耦等各种需求,正在使用现代的微服务架构替换老旧的单片机系统,当一个生产系统面对真正的高并发,或者解耦成大量微服务时,以前很容易实现的重点任务变得困难了,如用户体验优化后台真实错误原因分析分布式系统内各组件的调用情况等。

分布式服务追踪现状

当代分布式跟踪系统(例如,Zipkin, Dapper, HTrace, X-Trace等)旨在解决这些问题,但是他们使用不兼容的API来实现各自的应用需求。尽管这些分布式追踪系统有着相似的API语法,但各种语言的开发人员依然很难将他们各自的系统(使用不同的语言和技术)和特定的分布式追踪系统进行整合。

OpenTracing

OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。 OpenTracing提供了用于运营支撑系统的和针对特定平台的辅助程序库。

典型服务追踪案例

案例

在一个分布式系统中,追踪一个事务或者调用流一般如上图所示。虽然这种图对于看清各组件的组合关系是很有用的,但是,它不能很好显示组件的调用时间,是串行调用还是并行调用,如果展现更复杂的调用关系,会更加复杂,甚至无法画出这样的图。这种图也无法显示调用间的时间间隔以及是否通过定时调用来启动调用.

案例

这种展现方式增加显示了执行时间的上下文,相关服务间的层次关系,进程或者任务的串行或并行调用关系。这样的视图有助于发现系统调用的关键路径。通过关注关键路径的执行过程,项目团队可能专注于优化路径中的关键位置,最大幅度的提升系统性能。例如:可以通过追踪一个资源定位的调用情况,明确底层的调用情况,发现哪些操作有阻塞的情况。

Jaeger 架构

Jaeger是OpenTracing的一种实现。
jaeger

如上图所示,Jaeger 主要由以下几部分组成。

  • Jaeger Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。在 Application 中调用 Jaeger Client Library 记录 Span 的过程通常被称为埋点。
  • Agent - 它是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,部署到所有的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。
  • Collector - 接收 jaeger-agent 发送来的数据,然后将数据写入后端存储。Collector 被设计成无状态的组件,因此您可以同时运行任意数量的 jaeger-collector。
  • Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。
  • Query - 接收查询请求,然后从后端存储系统中检索 trace 并通过 UI 进行展示。Query 是无状态的,您可以启动多个实例,把它们部署在 nginx 这样的负载均衡器后面。

Istio Trace链路追踪方案

  • Envoy原生就支持分布式追踪系统的接入,如支持jaegerzipkin

  • 生成Request Id,填充HTTPheader字段x-request-id;

  • 如果incoming的请求没有trace相关的headers,则会在流量进入pods之前创建一个root span;

  • 如果incoming的请求包含有trace相关的headers,Sidecar的proxy将会extract这些span的上下文信息,然后在流量进入pods之前创建一个继承上一个span的新的span;

  • Jaeger本身支持在client端调整和通过collector调整采样策略,但是在Istio中并没有Jaeger的client,只是envoy里面支持了trace,不过Istio中提供了一个全局的设置,通过设置pilot的参数可以用来控制采用策略。

介绍

Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签。项目受 Prometheus 启发,官方的介绍就是:Like Prometheus, but for logs.,类似于 Prometheus 的日志系统。

与其他日志聚合系统相比,Loki具有下面的一些特性:

  • 不对日志进行全文索引。通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成本。
  • 通过使用与 Prometheus 相同的标签记录流对日志进行索引和分组,这使得日志的扩展和操作效率更高。
  • 特别适合储存 Kubernetes Pod 日志; 诸如 Pod 标签之类的元数据会被自动删除和编入索引。
  • 受 Grafana 原生支持。

Loki 由以下3个部分组成:
Loki

  1. loki是主服务器,负责存储日志和处理查询。
  2. promtail是代理,负责收集日志并将其发送给 loki 。
  3. Grafana用于 UI 展示。

Loki安装

参考官网

添加/更新helm

helm repo add loki https://grafana.github.io/loki/charts
helm repo update

安装loki(使用默认配置)

helm upgrade --install loki loki/loki-stack

安装loki(设置namespace)

helm upgrade --install loki --namespace=loki loki/loki

安装loki(更改一些配置)

helm upgrade --install loki loki/loki-stack  --set grafana.enabled=true,prometheus.enabled=true,prometheus.alertmanager.persistentVolume.enabled=false,prometheus.server.persistentVolume.enabled=false

这边loki使用的镜像是grafana/loki:v1.2.0,建议提前拉取下来。

docker pull grafana/loki:v1.2.0

其它一些信息,可以参考官网配置。

Promtail安装

参考官网

helm upgrade --install promtail loki/promtail --set "loki.serviceName=loki" --namespace=loki

这边loki使用的镜像是grafana/promtail:v1.2.0,建议提前拉取下来。

docker pull grafana/promtail:v1.2.0

其它一些信息,可以参考官网配置。

集成Grafana,实现页面查询日志

前文使用Helm一键安装Prometheus Operator已经安装了grafana服务,我们可以直接使用。

登录grafana,选择添加数据源

添加Loki数据源

数据源列表中选择Loki,配置服务地址

如果grafanaloki在同一个namespace,只需写服务名即可。
如果是在不同的namespace,那么要写完整DNS地址。

添加Loki数据源

切换到grafana左侧区域的Explore,进入loki页面

添加Loki数据源

点击Log labels就可以把当前系统采集的日志标签给显示出来,可以根据这些标签进行日志的过滤查询

添加Loki数据源

常见问题

...........
level=error ts=2019-12-17T05:43:00.189385282Z caller=filetarget.go:272 msg="failed to tail file, stat failed" error="stat /var/log/pods/kube-system_kube-flannel-ds-amd64-btn7m_5088625c-bba8-41d6-86c8-dc738d3b43ab/kube-flannel/3.log: no such file or directory" filename=/var/log/pods/kube-system_kube-flannel-ds-amd64-btn7m_5088625c-bba8-41d6-86c8-dc738d3b43ab/kube-flannel/3.log
level=error ts=2019-12-17T05:43:00.192476724Z caller=filetarget.go:272 msg="failed to tail file, stat failed" error="stat /var/log/pods/kube-system_kube-flannel-ds-amd64-btn7m_5088625c-bba8-41d6-86c8-dc738d3b43ab/install-cni/5.log: no such file or directory" filename=/var/log/pods/kube-system_kube-flannel-ds-amd64-btn7m_5088625c-bba8-41d6-86c8-dc738d3b43ab/install-cni/5.log
......

提示找不到/var/log/pods目录下的日志文件,无法tail

首先我们可以进入promtail容器内,到该目录下查看下是否有该文件,通过cat命令看看是否有日志。

默认安装promtail,它会将主机/var/log/pods/var/lib/docker/containers目录通过volumes方式挂载到promtail容器内。如果安装dockerk8s都是采用默认配置,应该不会存在读不到日志的问题。

{
    "name": "docker",
    "hostPath": {
        "path": "/var/lib/docker/containers",
        "type": ""
    }
},
    {
    "name": "pods",
    "hostPath": {
        "path": "/var/log/pods",
        "type": ""
    }
}

本人因为主机系统盘太小,设置了docker镜像的目录到挂载磁盘/data目录下,所以需要修改默认volumes配置。

{
    "name": "docker",
    "hostPath": {
        "path": "/data/docker/containers",
        "type": ""
    }
},
    {
    "name": "pods",
    "hostPath": {
        "path": "/var/log/pods",
        "type": ""
    }
}
//注意对应的volumeMounts也要修改
"volumeMounts": [
              {
                "name": "docker",
                "readOnly": true,
                "mountPath": "/data/docker/containers"
              },
              {
                "name": "pods",
                "readOnly": true,
                "mountPath": "/var/log/pods"
              }
            ]

上面volumesvolumeMounts都要修改,因为/var/log/pods目录下的日志文件其实是个软链接,指向的是docker/containers目录下的日志文件。如果只修改了volumes,那么promtail容器内可以找到日志文件,但是打开确实空的,因为它只是个软连接。

[root@node1 log]# ll /var/log/pods/monitoring_promtail-bs5cs_5bc5bc90-bac9-480d-b291-4caadeff2236/promtail/
total 4
lrwxrwxrwx 1 root root 162 Dec 17 14:04 0.log -> /data/docker/containers/db45d5118e9508817e1a2efa3c9da68cfe969a2b0a3ed42619ff61a29cc64e5f/db45d5118e9508817e1a2efa3c9da68cfe969a2b0a3ed42619ff61a29cc64e5f-json.log

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
  labels:
    app: nfs-client-provisioner
    chart: nfs-client-provisioner-1.2.8
    release: test-storageclass
  name: nfs-client
parameters:
  archiveOnDelete: "true"
provisioner: cluster.local/test-storageclass-nfs-client-provisioner

注意事项

  • provisioner:这个是安装nfs-client-provisioner是定义的provisionerName,如果配置中没有指明,会自动生成。
  • 添加storageclass.kubernetes.io/is-default-class: "true"表面这是一个默认的StorageClass 资源对象
  • name:它处使用这个StorageClass时要指定的名称。

K8S启动的POD,默认时区与中国相差8小时,在排查问题或者查看日志时非常不方便。

增加容器环境变量,指定时区

docker run -it --rm -e "TZ=Asia/Shanghai" centos

对应k8s中配置:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env-tz
spec:
  containers:
  - name: ngx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    env:
      - name: TZ
        value: Asia/Shanghai

容器启动时,挂载到宿主机时区文件

docker run -it --rm -v /etc/localtime:/etc/localtime  centos

对应k8s中配置

apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-tz
spec:
  containers:
  - name: ngx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: tz-config
      mountPath: /etc/localtime
      readOnly: true
  volumes:
  - name: tz-config
    hostPath:
      path: /etc/localtime

以上两种方法都可以解决问题,但是缺点明显,每次新建POD都需要指定。

推荐使用PodPreset方式

PodPreset(参考中文文档

PodPreset用来给指定标签的Pod注入额外的信息,如环境变量、存储卷等。这样,Pod模板就不需要为每个Pod都显式设置重复的信息。

开启PodPreset

  • 开启API settings.k8s.io/v1alpha1/podpreset
  • 开启准入控制 PodPreset

默认情况下PodPreset不可用

[root@k8s-master ~]# kubectl get podpreset
error: the server doesn't have a resource type "podpreset"

开启之后应该是

[root@k8s-master ~]# kubectl get podpreset
No resources found.

如何开启PodPreset?

编辑/etc/kubernetes/manifests/kube-apiserver.yaml

spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=192.168.1.210
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction,PodPreset
    - --enable-bootstrap-token-auth=true
    - --runtime-config=settings.k8s.io/v1alpha1=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt

添加一行配置- --runtime-config=settings.k8s.io/v1alpha1=true,enable-admission-plugins后面增加PodPreset

等待ApiServer自动重启完成。

创建PodPreset

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-tz-env
  namespace: default
spec:
  selector:
    matchLabels:
  env:
    - name: TZ
      value: Asia/Shanghai
[root@k8s-master ~]# kubectl get podpresets
NAME           CREATED AT
allow-tz-env   2019-12-16T07:57:54Z

现在创建一个新的POD,查看其环境变量。

测试

我这边简单测试,删除一个已有的consul容器,等它重启之后,查看它的环境变量
consul

可以看到,容器最后环境变量确实增加的时区配置。

busybox通过时区设置时间不生效问题

原因参考这篇

解决办法,通过挂载磁盘/etc/localtime,也可以通过PodPreset方式,为每个创建的POD自动添加挂载

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-tz-env
spec:
  selector:
    matchLabels:
  volumeMounts:
    - mountPath: /etc/localtime
      name: tz-config
      readOnly: true
  volumes:
    - name: tz-config
      hostPath: 
        path: /etc/localtime

这样新增的POD会自动挂载宿主机上的时间文件。