在之前的内容中,我们已经完成了 KT-env 的环境搭建。
同时,也了解了请求路由的基本原理。
下面,我们就来具体使用 KT-env 来实现对应的虚拟环境。
QuickStart
如果是一个新的 namespace,需要在新的 namespace 下部署 operator 和 role 相关信息,参考 deploy 。
Step1: 创建虚拟环境。
创建一个virtual-environment-cr.yaml 文件:
apiVersion: env.alibaba.com/v1alpha2kind: VirtualEnvironmentmetadata:name: demo-virtualenvspec:envHeader:name: ali-env-markautoInject: trueenvLabel:name: virtual-envsplitter: "."defaultSubset: dev
实例创建后,会自动监听所在Namespace中的所有Service、Deployment和StatefulSet对象并自动生成路由隔离规则,形成虚拟环境。
kubectl apply -n default -f virtual-environment-cr.yaml
Step2: 拉取Git仓库,进入示例代码目录。
git clone https://github.com/alibaba/virtual-environment.gitcd virtual-environment/examples
Step3: 设置 default namespace 自动注入 sidecar 并使得 webhook 能够为 Envoy 自动注入环境变量。
kubectl label namespace default environment-tag-injection=enabledkubectl label namespace default istio-injection=enabled
Step4: 在集群随意创建一个临时的Pod作为发送测试请求的客户端。
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 函数如下:
apply_pods() {type=${1}ee=`echo ${e} | sed -e "s/\./-/g"`echo $scat ${basepath}/${type}.yaml | sed -e "s/service-name-env-placeholder/${s}-${ee}/g" \-e "s/service-name-placeholder/${s}/g" \-e "s/app-env-placeholder/${e}/g" \-e "s/app-image-placeholder/`hget images ${s}`/g" \-e "s#app-url-placeholder#`hget urls ${s}`#g" \| kubectl ${action} --validate=false -n ${namespace} -f -}
使用app.sh脚本快速创建示例所需的VirtualEnvironment、Deployment、StatefulSet和Service资源:
# default namespace 下启动演示的服务实例deploy/app.sh apply default
依次使用kubectl get virtualenvironment、kubectl get deployment、kubectl get statefulset、kubectl get service
命令查看各资源的创建情况,等待所有资源部署完成。
Step6: 进入同Namespace的任意一个Pod,例如前面步骤创建的sleep容器。
# 进入集群中的容器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所属虚拟环境] <- 请求标签上的虚拟环境名称。
观察实际响应的服务实例情况:
# 使用dev.proj1标签> curl -H 'ali-env-mark: dev.proj1' app-js:8080/demo[springboot @ dev.proj1] <-dev.proj1[go @ dev] <-dev.proj1[node @ dev.proj1] <-dev.proj1# 使用dev.proj1.feature1标签> curl -H 'ali-env-mark: dev.proj1.feature1' app-js:8080/demo[springboot @ dev.proj1.feature1] <-dev.proj1.feature1[go @ dev] <-dev.proj1.feature1[node @ dev.proj1] <-dev.proj1.feature1# 使用dev.proj2标签> curl -H 'ali-env-mark: dev.proj2' app-js:8080/demo[springboot @ dev] <-dev.proj2[go @ dev.proj2] <-dev.proj2[node @ dev] <-dev.proj2# 不带任何标签访问# 由于启用了AutoInject配置,经过node服务后,请求自动加上了Pod所在虚拟环境的标签> curl app-js:8080/demo[springboot @ dev] <-dev[go @ dev] <-dev[node @ dev] <-empty
VirtualEnvironment 配置文件解读
虚拟环境实例通过VirtualEnvironment类型的Kubernetes资源定义。其内容结构示例如下:
apiVersion: env.alibaba.com/v1alpha2kind: VirtualEnvironmentmetadata:name: demo-virtualenvspec:envHeader:name: ali-env-markautoInject: trueenvLabel:name: virtual-envsplitter: "."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分别创建相同配置的实例。
