在之前的内容中,我们已经完成了 KT-env 的环境搭建。
同时,也了解了请求路由的基本原理。

下面,我们就来具体使用 KT-env 来实现对应的虚拟环境。

QuickStart

如果是一个新的 namespace,需要在新的 namespace 下部署 operator 和 role 相关信息,参考 deploy

Step1: 创建虚拟环境。

创建一个virtual-environment-cr.yaml 文件:

  1. apiVersion: env.alibaba.com/v1alpha2
  2. kind: VirtualEnvironment
  3. metadata:
  4. name: demo-virtualenv
  5. spec:
  6. envHeader:
  7. name: ali-env-mark
  8. autoInject: true
  9. envLabel:
  10. name: virtual-env
  11. splitter: "."
  12. defaultSubset: dev

实例创建后,会自动监听所在Namespace中的所有Service、Deployment和StatefulSet对象并自动生成路由隔离规则,形成虚拟环境。

  1. kubectl apply -n default -f virtual-environment-cr.yaml

Step2: 拉取Git仓库,进入示例代码目录。

  1. git clone https://github.com/alibaba/virtual-environment.git
  2. cd virtual-environment/examples

Step3: 设置 default namespace 自动注入 sidecar 并使得 webhook 能够为 Envoy 自动注入环境变量。

  1. kubectl label namespace default environment-tag-injection=enabled
  2. kubectl label namespace default istio-injection=enabled

Step4: 在集群随意创建一个临时的Pod作为发送测试请求的客户端。

  1. kubectl create deployment sleep --image=virtualenvironment/sleep --dry-run -o yaml | kubectl apply -n default -f -

Step5: 部署相关应用

KtEnv支持Deployment和StatefulSet对象的路由隔离,
在这个例子中将部署3种不同语言实现的示例应用,
其中app-js和app-java被部署为Deployment,而app-go被部署为StatefulSet。

修改 app.sh 脚本中 apply_pods 函数如下:

  1. apply_pods() {
  2. type=${1}
  3. ee=`echo ${e} | sed -e "s/\./-/g"`
  4. echo $s
  5. cat ${basepath}/${type}.yaml | sed -e "s/service-name-env-placeholder/${s}-${ee}/g" \
  6. -e "s/service-name-placeholder/${s}/g" \
  7. -e "s/app-env-placeholder/${e}/g" \
  8. -e "s/app-image-placeholder/`hget images ${s}`/g" \
  9. -e "s#app-url-placeholder#`hget urls ${s}`#g" \
  10. | kubectl ${action} --validate=false -n ${namespace} -f -
  11. }

使用app.sh脚本快速创建示例所需的VirtualEnvironment、Deployment、StatefulSet和Service资源:

  1. # default namespace 下启动演示的服务实例
  2. deploy/app.sh apply default

依次使用kubectl get virtualenvironmentkubectl get deploymentkubectl get statefulsetkubectl get service
命令查看各资源的创建情况,等待所有资源部署完成。

Step6: 进入同Namespace的任意一个Pod,例如前面步骤创建的sleep容器。

  1. # 进入集群中的容器
  2. kubectl exec -n default -it $(kubectl get -n default pod -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- /bin/sh

Step7: 实验一下

分别在请求头加上不同的虚拟环境名称,使用curl工具调用app-js服务。

3个服务的关系是: app-js -> app-go -> app-java

注意该示例创建的VirtualEnvironment实例配置使用.作为环境层级分隔符,同时配置了传递标签Header的键名为ali-env-mark

已知各服务输出文本结构为[项目名 @ 响应的Pod所属虚拟环境] <- 请求标签上的虚拟环境名称。

观察实际响应的服务实例情况:

  1. # 使用dev.proj1标签
  2. > curl -H 'ali-env-mark: dev.proj1' app-js:8080/demo
  3. [springboot @ dev.proj1] <-dev.proj1
  4. [go @ dev] <-dev.proj1
  5. [node @ dev.proj1] <-dev.proj1
  6. # 使用dev.proj1.feature1标签
  7. > curl -H 'ali-env-mark: dev.proj1.feature1' app-js:8080/demo
  8. [springboot @ dev.proj1.feature1] <-dev.proj1.feature1
  9. [go @ dev] <-dev.proj1.feature1
  10. [node @ dev.proj1] <-dev.proj1.feature1
  11. # 使用dev.proj2标签
  12. > curl -H 'ali-env-mark: dev.proj2' app-js:8080/demo
  13. [springboot @ dev] <-dev.proj2
  14. [go @ dev.proj2] <-dev.proj2
  15. [node @ dev] <-dev.proj2
  16. # 不带任何标签访问
  17. # 由于启用了AutoInject配置,经过node服务后,请求自动加上了Pod所在虚拟环境的标签
  18. > curl app-js:8080/demo
  19. [springboot @ dev] <-dev
  20. [go @ dev] <-dev
  21. [node @ dev] <-empty

VirtualEnvironment 配置文件解读

虚拟环境实例通过VirtualEnvironment类型的Kubernetes资源定义。其内容结构示例如下:

  1. apiVersion: env.alibaba.com/v1alpha2
  2. kind: VirtualEnvironment
  3. metadata:
  4. name: demo-virtualenv
  5. spec:
  6. envHeader:
  7. name: ali-env-mark
  8. autoInject: true
  9. envLabel:
  10. name: virtual-env
  11. splitter: "."
  12. defaultSubset: dev

参数作用如下表所示:

配置参数 默认值 说明
envHeader.name X-Virtual-Env 用于透传虚拟环境名的HTTP头名称(虽然有默认值,建议显性设置)
envHeader.autoInject false 是否为没有虚拟环境HTTP头记录的请求自动注入HTTP头(建议开启)
envLabel.name virtual-env Pod上标记虚拟环境名用的标签名称(除非确实必要,建议保留默认值)
envLabel.splitter . 虚拟环境名中用于划分环境默认路由层级的字符(只能是单个字符)
envLabel.defaultSubset 请求未匹配到任何存在的虚拟环境时,进行兜底虚拟环境名(默认为随机路由)

注意:VirtualEnvironment实例只对其所在的Namespace有效。如有需要,可以通过在多个Namespace分别创建相同配置的实例。