Istio1.1.0下的TCP流量控制

栏目: 后端 · 发布时间: 6年前

内容简介:在本文中,我们将用

Istio 通过 虚拟服务 , 目标规则 , Gateway 等概念提供了复杂的路由机制。Istio 1.0通过 加权路由定义 启用了HTTP流量转移。我提交的 EnvoyIstio 的pull request为TCP/TLS服务提供了类似的特性。这一特性已经在Envoy 1.8.0 中发布了。Istio中的这一特性也会在即将发布的 1.1.0 版本中提供使用。

Istio1.1.0下的TCP流量控制

在本文中,我们将用 Go 编写的一个简单的TCP Echo服务,用 Docker 将其容器化并部署到 Kubernetes 上,并通过练习Istio的加权TCP路由特性来理解其在生产服务中的行为。

TCP Echo服务

在本文中,我们将创建一个简单的监听连接的TCP服务,并在客户端的请求数据加上一个简单的前缀,将其作为响应返回。图示如下:

Istio1.1.0下的TCP流量控制

让我们看一下TCP Echo服务端的 Go 代码:

package main

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"os"
)

// main作为程序入口点
func main() {
	// 通过程序入参获得端口和前缀
	port := fmt.Sprintf(":%s", os.Args[1])
	prefix := os.Args[2]

	// 在给定端口上创建tcp监听
	listener, err := net.Listen("tcp", port)
	if err != nil {
		fmt.Println("failed to create listener, err:", err)
		os.Exit(1)
	}
	fmt.Printf("listening on %s, prefix: %s\n", listener.Addr(), prefix)

	// 监听新的连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("failed to accept connection, err:", err)
			continue
		}

		// 启用goroutine处理连接
		go handleConnection(conn, prefix)
	}
}

// handleConnection 处理连接的生命周期
func handleConnection(conn net.Conn, prefix string) {
	defer conn.Close()
	reader := bufio.NewReader(conn)
	for {
		// 读取客户端请求数据
		bytes, err := reader.ReadBytes(byte('\n'))
		if err != nil {
			if err != io.EOF {
				fmt.Println("failed to read data, err:", err)
			}
			return
		}
		fmt.Printf("request: %s", bytes)

		// 添加前缀作为response返回
		line := fmt.Sprintf("%s %s", prefix, bytes)
		fmt.Printf("response: %s", line)
		conn.Write([]byte(line))
	}
}

要测试这个程序,复制上面代码并命名为 main.go ,执行命令如下:

$ go run -v main.go 9000 hello
listening on [::]:9000, prefix: hello

我们可以通过 nc ( Netcat )在TCP层面上和这段程序交互。要发送请求,可以使用BusyBox容器,如下所示:

$ docker run -it --rm busybox sh -c 'echo world | nc docker.for.mac.localhost 9000'
hello world

就像你看到的,在请求“world”前面加上了“hello”,“hello world”作为响应。注意,正在执行的BusyBox容器基于 Docker for Mac ,这就是为什么我访问Echo服务端时用 docker.for.mac.localhost 代替了 localhost

容器化TCP Echo服务

因为我们最终想要在Kubernetes集群上运行TCP Echo服务,现在让我们将它容器化并发布镜像到 Docker Hub

首先,用下面的内容创建 Dockerfile

# 使用golang容器构建可执行文件
FROM golang:1.11 as builder
WORKDIR /go/src/github.com/venilnoronha/tcp-echo-server/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main main.go

# 负责bin文件到基于alpine的分离容器
FROM alpine:3.8
RUN apk --no-cache add ca-certificates
WORKDIR /bin/
COPY --from=builder /go/src/github.com/venilnoronha/tcp-echo-server/main .
ENTRYPOINT [ "/bin/main" ]
CMD [ "9000", "hello" ]
EXPOSE 9000

构建容器并发布镜像到Docker Hub:

$ docker build -t vnoronha/tcp-echo-server:latest .
Sending build context to Docker daemon  60.93kB
...
Successfully built d172af115e18
Successfully tagged vnoronha/tcp-echo-server:latest

$ docker push vnoronha/tcp-echo-server:latest
The push refers to repository [docker.io/vnoronha/tcp-echo-server]
b4cc76510de6: Pushed
...
latest: digest: sha256:0a45b5a0d362db6aa9154717ee3f2b... size: 949

部署TCP Echo服务到Kubernetes

服务配置

我们需要部署2个版本的TCP ECHO服务,用不同的前缀展示路由行为。创建 service.yaml ,用Kubernetes Service 和2个 Deployments 构建2个版本的TCP ECHO服务。

apiVersion: v1
kind: Service
metadata:
  name: tcp-echo-server
  labels:
    app: tcp-echo-server
    istio: ingressgateway # use istio default controller
spec:
  selector:
    app: tcp-echo-server
  ports:
  - port: 9000
    name: tcp
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tcp-echo-server-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: tcp-echo-server
        version: v1
    spec:
      containers:
      - name: tcp-echo-server
        image: vnoronha/tcp-echo-server:latest
        args: [ "9000", "one" ] # prefix: one
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9000
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tcp-echo-server-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: tcp-echo-server
        version: v2
    spec:
      containers:
      - name: tcp-echo-server
        image: vnoronha/tcp-echo-server:latest
        args: [ "9000", "two" ] # prefix: two
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9000

部署Minikube

Minikube 是Kubernetes本地开发的最佳工具。用下面的命令启动Minikube实例:

$ minikube start --bootstrapper kubeadm       \
                 --memory=8192                \
                 --cpus=4                     \
                 --kubernetes-version=v1.10.0 \
                 --vm-driver=virtualbox
Starting local Kubernetes v1.10.0 cluster...
...
Kubectl is now configured to use the cluster.
Loading cached images from config file.

安装 Istio

在撰写本文时,Istio 1.1.0还没有发布。因此我使用了Istio的 Daily Pre-Release 来演示这个新特性。请参考 Istio文档 学习下载和配置Istio。

一旦配置完成,这里有一个完全部署Istio组件的简单方法:

$ kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml
customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created
...
customresourcedefinition.apiextensions.k8s.io/templates.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/handlers.config.istio.io created

$ kubectl apply -f install/kubernetes/istio-demo.yaml
namespace/istio-system created
...
destinationrule.networking.istio.io/istio-policy created
destinationrule.networking.istio.io/istio-telemetry created

使用Istio代理部署TCP Echo服务

为了演示Istio的路由机制,我们以sidecar模式部署 tcp-echo-server

$ kubectl apply -f <(istioctl kube-inject -f service.yaml)
service/tcp-echo-server created
deployment.extensions/tcp-echo-server-v1 created
deployment.extensions/tcp-echo-server-v2 created

通过下面的命令来验证服务运行:

$ kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
tcp-echo-server-v1-78684f5697-sv5r5   2/2       Running   0          56s
tcp-echo-server-v2-74bf9999c8-hhhf9   2/2       Running   0          56s

$ kubectl logs tcp-echo-server-v1-78684f5697-sv5r5 tcp-echo-server
listening on [::]:9000, prefix: one

$ kubectl logs tcp-echo-server-v2-74bf9999c8-hhhf9 tcp-echo-server
listening on [::]:9000, prefix: two

Istio加权TCP路由

这是本练习的最后一部分,定义 VirtualServiceDestinationRule 和带有权重路由的 Gateway ,并验证系统行为。

路由配置

创建带有两个 subsetDestinationRule 来代表两个版本的 TCP Echo服务。 Gateway 容许流量通过端口 31400 访问服务。最后, VirtualService 限定了80%的流量必须被路由到TCP Echo服务的v1版本,20%被路由到v2版本。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: destination
spec:
  host: tcp-echo-server
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400
      name: tcp
      protocol: TCP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: route
spec:
  hosts:
  - "*"
  gateways:
  - gateway
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo-server
        port:
          number: 9000
        subset: v1
      weight: 80
    - destination:
        host: tcp-echo-server
        port:
          number: 9000
        subset: v2
      weight: 20

部署路由配置

为了让配置生效,复制上面的配置内容并创建文件 route-config.yaml ,用下面的命令进行安装:

kubectl apply -f route-config.yaml
destinationrule.networking.istio.io/destination created
gateway.networking.istio.io/gateway created
virtualservice.networking.istio.io/route created

验证Istio的TCP路由行为

先来确定一下 Ingress的IP

$ minikube ip
192.168.99.100

现在可以通过Ingress发送一些请求到加权负载均衡的TCP Echo服务:

$ for i in {1..10}; do
for> docker run -it --rm busybox sh -c '(date; sleep 1) | nc 192.168.99.100 31400'
for> done
one Sat Oct 20 04:38:05 UTC 2018
two Sat Oct 20 04:38:07 UTC 2018
two Sat Oct 20 04:38:09 UTC 2018
one Sat Oct 20 04:38:12 UTC 2018
one Sat Oct 20 04:38:14 UTC 2018
one Sat Oct 20 04:38:17 UTC 2018
one Sat Oct 20 04:38:19 UTC 2018
one Sat Oct 20 04:38:22 UTC 2018
one Sat Oct 20 04:38:24 UTC 2018
two Sat Oct 20 04:38:27 UTC 2018

如你所见,大约80%的请求带有“one”前缀,剩下20%带有“two”前缀。这证明了加权TCP路由器确实生效了。

下图能让你很好地了解这个示范的情景:

Istio1.1.0下的TCP流量控制

清理

只需要像下面一样删除Minikube的部署:

$ minikube stop && minikube delete
Stopping local Kubernetes cluster...
Machine stopped.
Deleting local Kubernetes cluster...
Machine deleted.

总结

如本文所示,即将发布的Istio 1.1.0版本配置加权TCP路由非常容易。本文提供了构建一个加权TCP路由的思路,让你学会如何从头开始控制TCP流量。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Beginning ASP.NET 4 in C# and Vb

Beginning ASP.NET 4 in C# and Vb

Imar Spaanjaars / Wrox / 2010-3-19 / GBP 29.99

This book is for anyone who wants to learn how to build rich and interactive web sites that run on the Microsoft platform. With the knowledge you gain from this book, you create a great foundation to ......一起来看看 《Beginning ASP.NET 4 in C# and Vb》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换