跳转至

隔离中间件服务

示例

首先创建该项目所用的 Namespace

> kubectl create ns nw-demo

namespace/nw-demo created

切换默认命名空间

kubectl ns nw-demo

隔离中间件服务

  1. 有一个项目,它有自己数据库 MySQL 和缓存 Redis 中间件,只希望这个项目的应用能够访问该中间件
  2. 假如有一个项目需要通过 Ingress 进行对外发布,想要除了 Ingress 外,其他任何 Namespace 下的 Pod 都不能访问该项目。

假设有一个项目叫 nw-demo,里面部署了三个微服务,分别是 MySQL、Redis 和 Nginx。现需要对 MySQL、Redis、Nginx 进行隔离,分别实现如下效果:

  • MySQL、Redis 只能被该 Namespace 下的 Pod 访问;
  • Nginx 可以被 ingress-nginx 命名空间下的 Pod 和该 Namespace 下的 Pod 访问;

创建 MySQL 服务,MySQL 以容器启动时,必须配置 root 的密码,或者设置密码为空,所以需要设置一个 MYSQL_ROOT_PASSWORD 的变量:

kubectl create deploy mysql --image=docker.io/library/mysql:8.0.31

kubectl set env deploy/mysql MYSQL_ROOT_PASSWORD=mysql

创建 redis 服务

kubectl create deploy redis --image=docker.io/library/redis:7.0.5-bullseye

确认容器是否启动:

> kubectl get po -owide

NAME                     READY   STATUS              RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
mysql-664f9868b-5s6g9    1/1     Running             0          14s   10.160.199.5   dev-chhli   <none>           <none>
redis-6466b54d6d-8zpt6   0/1     ContainerCreating   0          69s   10.160.199.10  dev-chhli   <none>           <none>

在没有配置任何网络策略时,测试下网络的连通性,可以在任意 Kubernetes 节点上执行 telnet 命令:

# 进行测试的IP和Pod名字可能与实际测试的不一致,需要与实际情况为准
> telnet 10.160.199.5 3306
Trying 10.160.199.5...
Connected to 10.160.199.5.
Escape character is '^]'.

> telnet 10.160.199.10 6379
Trying 10.160.199.10...
Connected to 10.160.199.10.
Escape character is '^]'.

然后根据标签配置网络策略,本示例的配置将MySQL和Redis进行了拆分,配置了两个网络策略,当然也可以给两个Pod配置一个相同的标签,这样就可以使用同一个网络策略进行限制

但是在生产环境中,并不推荐使用同一个网络策略,因为有时候需要更细粒度的策略,同一个网络策略可能会有局限性,也会导致配置失败,所以本示例采用分开的网络策略进行配置:

  • mysql-nw.yaml mysql-np 是对具有 app=mysql 标签的 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
  • redis-nw.yaml redis-np 是对具有 app=redis 标签的 Pod 进行管理
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

但是需要注意的是该网络策略的 ingress from 是以 namespaceSelector 的标签进行匹配的,并非 podSelector,或者是两者的结合。

因为在生产环境中,同一个 Namespace 下可能会有很多不同类型、不同标签的 Pod,并且它们可能并不具有一个相同的标签,所以如果通过 podSelector 进行选择,可能会比较麻烦,因为 Pod 一旦创建,对其标签的修改是很不方便的(apps/v1 一旦创建就不可修改)

而使用 namespaceSelector 另一个好处是,可以很方便的对某个 Namespace 下的 Pod 进行管控,直接给指定 Namespace 添加标签即可,当然,如果需要更细粒度的管控,也可以结合 podSelector 使用

创建后宿主机和任何 Pod 都已不能访问该 Namespace 下的 MySQL 和 Redis

> telnet 10.160.199.5 3306
Trying 10.160.199.5...

> telnet 10.160.199.10 6379
Trying 10.160.199.10...

在 nw-demo 命名空间下创建一个用于测试连通性的工具,然后进行测试,也是不能访问该服务的:

kubectl run -ti --rm debug-tools --image=docker.io/library/busybox:1.35

> telnet 10.160.199.5 3306

由于之前的 from 配置的是 namespaceSelector,所以如果想要某一个 Namespace 下的 Pod 能够访问,直接给该 Namespace 添加一个 NetworkPolicy 中配置的标签即可,比如允许 nw-demo 命名空间下的所以 Pod 访问该 NetworkPolicy 隔离的服务:

> kubectl label ns nw-demo access-nw-mysql-redis=true

namespace/nw-demo labeled

使用 nw-demo 命名空间下的 debug-tools 再次测试:

> telnet 10.160.199.5 3306

此时 nw-demo 下的 Pod 已经可以访问 MySQL 和 Redis,可以对其他 Namespace 下的 Pod 进行测试,比如在 default 命名空间进行测试:

kubectl run -ti --rm debug-tools --image=docker.io/library/busybox:1.35 -n default 

可以看到此时 default 命名空间下的 Pod 并不能访问 nw-demo 的服务,如果想要 MySQL 和 Redis 对 default 命名空间开放,只需要添加一个 access-nw-mysql-redis=true 的标签即可。

相对于传统架构,对中间件的访问限制,在 Kubernetes 中实现同样的效果,可能配置更加方便且易于管理