使用Istio Secret/ConfigMap实现外部配置
在使用spring cloud时,我们知道有对应的config进行配置中心的迁移,将应用配置从应用中剥离出来,放到外部,然后进行统一维护,方便管理;并且config通过使用bus实现了热更新的效果。
那么作为要和spring cloud进行对抗的新一代架构代表Istio,自然也存在类似的功能,不过目前该功能还不完善,无法实现热更新的效果,期待未来会有更好的改进吧。
应用部分
首先我们看一下设计应用的时候,我们需要怎么搞。
@SpringBootApplication
@RestController
public class IstioConfigApplication {
public static void main(String[] args) {
SpringApplication.run(IstioConfigApplication.class, args);
}
@Value("${MY_SECRET}")
String secret;
@Value("${MY_CONFIG}")
String config;
@RequestMapping("/secret")
public String getSecret(){
return secret;
}
@RequestMapping("/config")
public String getConfig(){
return config;
}
}
这是用于测试的主函数,这里我们使用了两个环境变量MY_SECRET
和MY_CONFIG
;
再看我们的application文件:
MY_SECRET=""
MY_CONFIG=""
server.port=8848
这里对于MY_SECRET
和MY_CONFIG
这两个环境变量置空了,为什么要做这种多此一举的事呢?
首先我们要知道,当我们使用maven对spring boot应用进行打包的时候,是会启动程序的,如果这时没有对应的环境变量,就无法正常打包;这个对比spring cloud config确实是有很大的不足,但是这是因为spring boot的单方面原因,以及spring对于java的支持过于强大,如果我们使用的是非java语言,可能就不需要多此一举(比如go?)。
总之,后续我们配置ConfigMap/Secret时,是会覆盖之前在application文件中的配置的。
Istio配置
接下来我们看一下在Istio上的几个YAML文件。
首先是创建configMap.yaml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: test-istio
data:
myConfig: lover~ fucker~
接下来我们再看一看secrets.yaml
:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: test-istio
type: Opaque
data:
mySecret: ZG9nd2lu
这块需要稍微解释一下:
Secret主要是用来解决密码、token、**等敏感数据的配置问题,它有三种类型:
-
Service Account :用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的
/run/secrets/kubernetes.io/serviceaccount
目录中; - Opaque : base64编码格式的Secret,用来存储密码、**等;
- kubernetes.io/dockerconfigjson :用来存储私有docker registry的认证信息。
而ConfigMap就是主要针对配置文件这块了。
更加详细的信息,请参考jimmysong的kubernetes-handbook。
上面的Secret中的base64编码可以在Linux下通过如下命令获取:
$ echo -n <string> | base64
需要注意的是:base64并不是一种加密手段,它只是一种编码格式,通过解码可以轻易得到原始值。
这时我们已经准备好了对应的ConfigMap/Secret,我们现在需要开始构建Deployment/Service了。
test-config.yaml
:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: test-config
version: v1
name: test-config
spec:
replicas: 1
selector:
matchLabels:
app: test-config
version: v1
template:
metadata:
labels:
app: test-config
version: v1
spec:
containers:
- image: yubotao/istio-config:test
imagePullPolicy: IfNotPresent
name: test-config
ports:
- containerPort: 8848
env:
- name: MY_SECRET
valueFrom:
secretKeyRef:
name: mysecret
key: mySecret
- name: MY_CONFIG
valueFrom:
configMapKeyRef:
name: env-config
key: myConfig
---
apiVersion: v1
kind: Service
metadata:
name: test-config
labels:
app: test-config
spec:
ports:
- name: http
port: 8848
selector:
app: test-config
之后我们执行:
kubectl apply -f <(istioctl kube-inject -f test-config.yaml) -n test-istio
然后看看我们新建的pod是否正常启动了:
kubectl get pods -n test-istio
同时可以通过查看该pod的日志来确认容器启动完成,可以进行测试了:
kubectl logs <podName> -c test-config -n test-istio
之后我们可以通过进入同命名空间下的pod中,使用curl进行测试。
就不打了,直接看图。
通过图示,可以看到测试成功。
配置热更新?
我们验证一下,是否支持配置热更新。
首先我们修改ConfigMap中的内容:
上图分别列出了上次修改,以及本次修改后的myConfig
的值。
接下来我们再次尝试使用curl请求:
上图能够看出,配置并没有热更新。
我们可以通过以下方式,进行强制热更新:
可以看到,我们通过修改pod的annotation来强制更新pod,进而重启pod中的容器,从而实现了强制配置热更新。
这种方式的弊端就是:麻烦,以及更新pod后,就变更原pod的环境,名称等等之类的。如下图:
更新的两个pod进行更迭。最后只保留其中一个,也就是上面那个最新创建的。
至此,就告一段落,感觉目前Isito的这个功能对于spring boot的应用来说,比较鸡肋,对于不是特别频繁进行配置更换的应用,完全没必要进行这种配置,不如直接使用application文件。
当然如果频繁更新的话,这种方式还是有一定的好处的,最起码,你不用每次更改配置就发布一个镜像版本。 (囧rz)