# 借助 Calico，管窥 Kubernetes 网络策略

Kubernetes 提出了一系列 CXI 的标准容器接口，其中的 CNI 以插件方式支持多种网络。新增的 networkpolicy API 对象，提供了对网络策略的支持，本文以 Calico 为例，实际操作一个网络策略的创建和测试。

## 环境准备

- 一个 Kubernetes 集群
- Kubelet 和 API Server 都开启了 `--allow_privileged=true`
- Kubelet 指定使用 CNI ：`--network-plugin=cni`
- 为了避免某些不可描述的网络设施的影响，建议下载几个镜像
  - quay.io/calico/node:v1.0.2
  - calico/cni:v1.5.6
  - calico/kube-policy-controller:v0.5.2
  - calico/ctl:v1.0.2

## 运行 Calico

- 下载 `http://docs.projectcalico.org/v2.0/getting-started/kubernetes/installation/hosted/calico.yaml`
- 如果用私库镜像，需要修改其中的几个镜像地址
- 修改 `data/etcd_endpoints` 的数据为可访问的 etcd 的地址。

`kubectl create -f calico.yaml`

这里在 kube-system 中创建了一个 DaemonSet 和一个 Deployment，分别用于提供 CNI 支持和网络策略支持。

    $ kubectl get deployment,daemonset,svc --all-namespaces                                          [9:55:14]
    NAMESPACE     NAME                              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    kube-system   deploy/calico-policy-controller   1         1         1            1           10h

    NAMESPACE     NAME             DESIRED   CURRENT   READY     NODE-SELECTOR   AGE
    kube-system   ds/calico-node   2         2         2         <none>          10h

    NAMESPACE   NAME             CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
    default     svc/kubernetes   172.200.0.1       <none>        443/TCP   19h
    default     svc/nginx        172.200.183.204   <none>        80/TCP    9h

## 网络策略

为测试效果，我们首先创建一个 Namespace

`kubectl create ns policy`

然后是 Nginx 部署和服务：

~~~yaml
---
kind: ReplicationController
apiVersion: v1
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  replicas: 1
  selector:
    name: nginx
  template:
    metadata:
      labels:
        name: nginx
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          protocol: TCP

---
kind: Service
apiVersion: v1
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  selector:
    name: nginx
~~~

然后我们用 alpine 镜像测试一下对这一服务进行访问：

`kubectl run alpine --rm -it --image=alpine sh`

运行成功后，在 Alpine 的 Shell 中输入：

`wget -O - -T 5 http://nginx`

会出现 Nginx 的缺省页面的代码。

接下来我们给 Default Namespace 加一个缺省拒绝访问的注解：

`$ kubectl annotate ns default "net.beta.kubernetes.io/network-policy={\"ingress\": {\"isolation\": \"DefaultDeny\"}}"`

重复测试过程，会发现超时错误。

我们来创建一条策略：

~~~yaml
kind: NetworkPolicy
apiVersion: extensions/v1beta1
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      run: nginx
  ingress:
    - from:
      - podSelector:
          matchLabels:
            access: "true"
~~~

很容易理解，对于符合 "run=nginx" 的 Pod，只有 "access=true" 的 Pod 能够访问

给 Alpine 带上标签重新运行：

`kubectl run alp --image=alpine --labels="access=true" --rm -ti sh`

重新 wget，会发现访问能力已经恢复。

本文主要线索来自官方示例：`https://kubernetes.io/docs/getting-started-guides/network-policy/walkthrough/`

安装方法来自 Calico 官网。

这只是一个很入门的介绍，后续会有更多进一步的尝试。
