# Istio 尾行记

Istio 一直没有什么像样的更新，Conduit 也迟迟不出来怼，眼看 2017 就要过去，安装试用也不新鲜了，补一篇 Istio 的笔记，算做个收尾了。

Istio 最大的亮点之一，就是使用 Pilot 将集群控制语言翻译成为 Envoy 配置，利用 Sidecar 的方式对服务通信进行控制，下面就是对这一过程的跟踪尝试。

## `kubectl apply -f install/kubernetes/istio.yaml`

`cat istio.yaml| grep ^kind`

会看到，这里生成了相当多的内容，除去 Deployment、Service 和 ConfigMap 老几样之外，还有当前集群必须的 RBAC 几要素：Service Account、ClusterRole 以及 ClusterRoleBinding。然后就是 Kubernetes 世界里强力扩展的标志：各种 CRD(CustomResourceDefinition) 了。

## `kubectl apply -f install/kubernetes/addons/`

这里会生成一系列的监控用具，包括了 Prometheus、Grafana、ZipKin 以及 ServiceGraph，原则上这些并非必须组件。不过为了监控方便，一般还是会加上。

另外这里的 Prometheus 以及 Grafana 的监控、仪表盘配置都可以保存下来，方便同现有设施进行融合。

## `istioctl kube-inject -f ...`

### 运行这个命令之前，务必注意几个对 Workload 的要求：

1. 目前，Pod 对应单一服务的情况才能得到支持。
2. 服务端口必须命名，[协议]-[后缀] 的方式，后缀部分可以忽略，写一部分可以使用 http, http2, grpc, mongo 以及 redis。如果不进行合理的命名，又没有显示声明这一端口是 UDP 端口，那么就会被当做普通 TCP 端口处理。
3. Deployment 需要有 App 标签，注意看示例应用的标签方法。
4. 目前的缺省安装不支持 `cluster.local` 之外的 Kubernetes 域名。

在安装好 Istio 之后，一般会使用这一命令对服务进行注入（同样也有自动注入的能力），使之称为被 istio 加持的 Service Mesh 成员服务。注入之后的 YAML 会变得比较丰腴：

- 一组注解
- 两个 Init
- 一个同 Pod 容器
- 两个卷

下面分别讲解一下多出来的这些部分：

### Annotation

为 Deployment 和 Pod 加入了同样的注解：

`sidecar.istio.io/status: injected-version...`，目前理解是，标注了这一部署和 Pod 是否已经被注入，被什么版本注入。

### Init 1

使用 Alpine 镜像，设置内核 Dump 模板，以及 ulimit。

### Init 2

使用 `docker.io/istio/proxy_init:0.4.0` 进行初始化，参数为 `-p 15001 -u 1337`

### Sidecar

镜像为： `docker.io/istio/proxy_debug:0.4.0`

其中定义了大量的服务关系，包括：

- Istio Pilot
- Zipkin
- Mixer
- 管理端口

### 卷

- 内存卷用于存储配置；
- Secret 卷用于后面的 TLS。

## 运行

利用 `kubectlapply -f`，将注入后的 yaml 文件运行起来，接下来就可以使用各个 Pod 来查看刚才注入的内容的行迹了。

列出 Pod：

    NAME                          READY     STATUS    RESTARTS   AGE
    httpbin-7965799df7-ll75q      2/2       Running   0          53m

通过前面的 yaml 定义，我们知道这个 Pod 的两个容器分别是 `httpbin` 和 `istio-proxy`，Istio 强调的是 Sidecar 模式的无侵入管理，因此我们可以认为 `httpbin` 是没有变化的，Service Mesh 的 Sidecar 功能会体现在 `istio-proxy` 这一容器中。

### 初始化

上一节中提到了，使用 `proxy_init` 进行的初始化（Alpine 部分修改内核参数，就不用多说了），我们可以进入源码，查查他的初始化做了什么。

Dockerfile 中我们看到，这一容器的入口命令为 `istio-start.sh`，找出这个文件，会看到其中使用这两个参数对 iptables 的 nat 部分做了配置，另外还可以看到，其中加入了 iptables 命令，这里我们可以进行验证：`kubectl exec httpbin-7965799df7-ll75q -c istio-proxy  sudo iptables-save`，输出内容可以这样解读：

1. 跳过和 Proxy 进程用户一致的用户进程的流量处理；
2. 跳过 Loopback 流量处理；
3. 所有流量转发到 15001 端口。

和脚本初始化内容一致。

### istio-proxy

启动之后，我们可以使用 `kubectl exec -it [httpbin] -c istio-proxy sh` 进入 Proxy 容器，执行命令 `ps -ef`，会发现有两个正在运行的进程：

- /usr/local/bin/pilot-agent
- /usr/local/bin/envoy

并且 Envoy 的父进程就是这个 pilot-agent。其运行参数和我们前面注入到 YAML 中的参数一致。

另外还可以查看 `/etc/istio/proxy/` 下面的配置文件，可以看出：

- Envoy 通过 pilot-agent 传递的参数运行
- 服务发现是通过 Pilot 完成的
- Envoy 开放了 15000 端口进行管理

## 验证路由规则

执行 `kubectl exec [Pod] -c istio-proxy curl localhost:15000/routes`

可以看到 httpbin 的路由如下：

```json
{
    "version_info": "hash_35afd004f717e588",
    "route_config_name": "8000",
    "cluster_name": "rds",
    "route_table_dump": {"name":"8000","virtual_hosts":[{"name":"httpbin.default.svc.cluster.local|http","domains":["httpbi
n:8000","httpbin","httpbin.default:8000","httpbin.default","httpbin.default.svc:8000","httpbin.default.svc","httpbin.defaul
t.svc.cluster:8000","httpbin.default.svc.cluster","httpbin.default.svc.cluster.local:8000","httpbin.default.svc.cluster.loc
al","10.0.34.255:8000","10.0.34.255"],"routes":[{"match":{"prefix":"/"},"route":{"cluster":"out.httpbin.default.svc.cluster
.local|http","timeout":"0s"},"decorator":{"operation":"default-route"}}]}]}
}
```

新建缺省路由：

```yaml
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: rule-all-http
spec:
  destination:
    name: httpbin
  precedence: 1
  route:
  - labels:
      app: httpbin
    weight: 100
```

再次查询路由，可以看到其中发生了变化：

```json
{
    "version_info": "hash_146c02ed176ff12b",
    "route_config_name": "8000",
    "cluster_name": "rds",
    "route_table_dump": {"name":"8000","virtual_hosts":[{"name":"httpbin.default.svc.cluster.local|http","domains":["httpbi
n:8000","httpbin","httpbin.default:8000","httpbin.default","httpbin.default.svc:8000","httpbin.default.svc","httpbin.defaul
t.svc.cluster:8000","httpbin.default.svc.cluster","httpbin.default.svc.cluster.local:8000","httpbin.default.svc.cluster.loc
al","10.0.34.255:8000","10.0.34.255"],"routes":[{"match":{"prefix":"/"},"route":{"cluster":"out.httpbin.default.svc.cluster
.local|http|app=httpbin","timeout":"0s"},"decorator":{"operation":"rule-all-http"}}]}]}
}
```

### cluster

`kubectl exec [pod] -c istio-proxy curl localhost:15000/routes`

可以看到所有对应的服务信息，以及可能存在的断路器信息。
