Kubernetes之NetworkPolicy隔离服务示例
- 有一个项目,它有自己的MySQL数据库核Redis缓存中间件,我们只希望这个项目的应用能够访问该中间件。
- 假如有一个项目需要通过Ingress进行对外发布,我们想要除了Ingress外,其他的Namespace下的Pod都不能访问该项目。
假设有一个项目叫nw-demo,里面部署了三个微服务,分别是MySQL、Redis和Nginx。现需要对MySQL、Redis、Nginx进行隔离,分别实现如下效果:
- MySQL、Redis只能被该Namespace下的Pod访问
- Nginx可以被Ingress-nginx命名空间下的Pod和该Namespace下的Pod访问
首先创建该项目所用的Namespace(如果已经存在,或者用其他Namespace测试,也可以不创建):
kubectl create namespace nw-demo
创建MySQL服务,MySQL以容器启动时,必须root的密码,或者设置密码为空,所以需要设置一个MYSQL_ROOT_PASSWORD
的变量:
kubectl create deployment mysql --image=mysql:5.7.23 -n nw-demo
kubectl set env deployment mysql MYSQL_ROOT_PASSWORD=mysql -n nw-demo
创建Redis服务:
kubectl create deployment redis --image=redis:5.0.9-alpine3.11 -n nw-demo
确认容器是否启动:
# kubectl get pods -n nw-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-69bbd89b95-757dn 1/1 Running 0 2m38s 10.33.125.62 k8s-node01 <none> <none>
redis-64c566c6bf-tv5zz 1/1 Running 0 24s 10.33.125.63 k8s-node01 <none> <none>
在没有配置任何网络策略时,测试网络的连通性,可以在任意Kubernetes节点上执行telnet命令:
# telnet 10.33.125.62 3306
Trying 10.33.125.62...
Connected to 10.33.125.62.
Escape character is '^]'.
J
5.7.23T\:E`:;\x.oy H'Mmysql_native_password^CConnection closed by foreign host.
# telnet 10.33.125.63 6379
Trying 10.33.125.63...
Connected to 10.33.125.63.
Escape character is '^]'.
^]
telnet> quit
Connection closed.
可以看到此时的网络都是可以通信的。接下来可以根据Pod的标签进行网络隔离,首先查看Pod的标签:
# kubectl get pods -n nw-demo --show-labels
NAME READY STATUS RESTARTS AGE LABELS
mysql-69bbd89b95-757dn 1/1 Running 0 8m5s app=mysql,pod-template-hash=69bbd89b95
redis-64c566c6bf-tv5zz 1/1 Running 0 5m51s app=redis,pod-template-hash=64c566c6bf
然后根据标签配置网络策略,本示例的配置将MySQL和Redis进行了拆分,配置了两个网络策略,当然也可以给两个Pod配置一个相同的标签,这样就可以使用同一个网络策略进行限制。但是在生产环境中,并不推荐使用同一个网络策略,因为有时候需要更细粒度的策略,同一个网络策略可能会有局限性,也会导致配置失败,所以本示例采用分开的网络策略进行配置:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-np
namespace: nw-demo
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- "Ingress"
ingress:
- from:
- namespaceSelector:
matchLabels:
access-nw-mysql-redis: "true"
ports:
- protocol: TCP
port: 3306
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: redis-np
namespace: nw-demo
spec:
podSelector:
matchLabels:
app: redis
policyTypes:
- "Ingress"
ingress:
- from:
- namespaceSelector:
matchLabels:
access-nw-mysql-redis: "true"
ports:
- protocol: TCP
port: 6379
该yaml含有两个NetworkPolicy,其中mysql-np是对具有app=mysql标签的Pod进行管理,redis-np是对具有app=redis标签的Pod进行管理。但是需要注意的是该网络策略的ingress from是以namespaceSelector的标签进行匹配的,并非podSelector,或者是两者的结合。因为在生产环境中,同一个Namespace下可能会有很多不同类型、不同标签的Pod,并且它们可能并不具有一个相同的标签,所以如果通过podSelector进行选择,可能会比较麻烦,因为Pod一旦创建,对其标签的修改是很不方便的(apps/v1一旦创建就不可修改)。而使用namespaceSelector另一个好处是,可以很方便的对某个Namespace下的Pod进行管控,直接给指定Namespace添加标签即可,当然,如果需要更细粒度的管控,也可以结合podSelector使用。
接下来创建该NetworkPolicy:
# kubectl create -f mysql-redis-nw.yaml
networkpolicy.networking.k8s.io/mysql-np created
networkpolicy.networking.k8s.io/redis-np created
# kubectl get networkpolicy -n nw-demo
NAME POD-SELECTOR AGE
mysql-np app=mysql 16m
redis-np app=redis 16m
创建后宿主机和任何Pod都不能访问该Namespace下的MySQL和Redis:
# telnet 10.33.125.63 6379
Trying 10.33.125.63...
^C
# telnet 10.33.125.62 3306
Trying 10.33.125.62...
^C
在nw-demo命名空间下创建一个用于测试连通性的工具,然后进行测试,也是不能访问该服务的:
# kubectl run -it busybox --image=busybox:1.28.3 -n nw-demo
If you don't see a command prompt, try pressing enter.
/ # telnet 10.33.125.62 3306
^C
/ #
由于之前的from配置的是namespaceSelector,所以如果想要某一个Namespace下的Pod能够访问,直接给该Namespace添加一个NetworkPolicy中配置的标签即可,比如允许nw-demo命名空间下的所有Pod访问该NetworkPolicy隔离的服务:
# kubectl label namespaces nw-demo access-nw-mysql-redis=true
namespace/nw-demo labeled
使用nw-demo命名空间下的busybox再次测试:
# kubectl exec -it busybox -n nw-demo -- sh
/ # telnet 10.33.125.62 3306
J
5.7.23/(TXs^%bx0
kREn Yqmysql_native_password^C
Console escape. Commands are:
l go to line mode
c go to character mode
z suspend telnet
e exit telnet
/ #
此时nw-demo下的Pod已经可以访问MySQL和Redis,可以对其他Namespace下的Pod进行测试,比如在default命名空间进行测试:
# kubectl run -it busybox --image=busybox:1.28.3 -n default
If you don't see a command prompt, try pressing enter.
/ # telnet 10.33.125.62 3306
^C
/ #
可以看到此时default命名空间下的Pod并不能访问nw-demo的服务,如果想要MySQL和Redis对default命名空间开放,只需添加一个access-nw-mysql-redis=true
的标签即可。
相对于传统架构,对中间件的访问限制,在Kubernetes中实现同样的效果,可能配置更加方便且易于管理。