内容简介:在本文中,我们将用
Istio 通过 虚拟服务 , 目标规则 , Gateway 等概念提供了复杂的路由机制。Istio 1.0通过 加权路由定义 启用了HTTP流量转移。我提交的 Envoy 和 Istio 的pull request为TCP/TLS服务提供了类似的特性。这一特性已经在Envoy 1.8.0 中发布了。Istio中的这一特性也会在即将发布的 1.1.0 版本中提供使用。
在本文中,我们将用 Go 编写的一个简单的TCP Echo服务,用 Docker 将其容器化并部署到 Kubernetes 上,并通过练习Istio的加权TCP路由特性来理解其在生产服务中的行为。
TCP Echo服务
在本文中,我们将创建一个简单的监听连接的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路由
这是本练习的最后一部分,定义 VirtualService
, DestinationRule
和带有权重路由的 Gateway
,并验证系统行为。
路由配置
创建带有两个 subset
的 DestinationRule
来代表两个版本的 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路由器确实生效了。
下图能让你很好地了解这个示范的情景:
清理
只需要像下面一样删除Minikube的部署:
$ minikube stop && minikube delete Stopping local Kubernetes cluster... Machine stopped. Deleting local Kubernetes cluster... Machine deleted.
总结
如本文所示,即将发布的Istio 1.1.0版本配置加权TCP路由非常容易。本文提供了构建一个加权TCP路由的思路,让你学会如何从头开始控制TCP流量。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript语言精髓与编程实践
周爱民 / 电子工业出版社 / 2012-3 / 79.00元
《JavaScript语言精髓与编程实践(第2版)》详细讲述JavaScript作为一种混合式语言的各方面特性,包括过程式、面向对象、函数式和动态语言特性等,在动态函数式语言特性方面有着尤为细致的讲述。《JavaScript语言精髓与编程实践(第2版)》的主要努力之一,就是分解出这些语言原子,并重现将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,读者可了解到语言的本质,以及“层......一起来看看 《JavaScript语言精髓与编程实践》 这本书的介绍吧!