网络空间

网络空间

K8s网络中存在两种IPPod IPService Cluster IPPod IP地址是实际存在于某个网卡(可以是虚拟设备)上的,Service Cluster IP它是一个虚拟IP,是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。每个Pod都拥有一个独立的IP地址(IPper Pod,而且假定所有的pod都在一个可以直接连通的、扁平的网络空间中。用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑将容器端口映射到主机端口等问题。

同一个Pod的容器共享同一个网络命名空间,它们之间的访问可以用localhost地址+容器端口就可以访问。同一NodePod的默认路由都是docker0的地址,由于它们关联在同一个docker0网桥上,地址网段相同,所有它们之间应当是能直接通信的。不同NodePod间通信要满足2个条件:PodIP不能冲突;将PodIP和所在的NodeIP关联起来,通过这个关联让Pod可以互相访问。

image

共享网络

可以通过本地主机访问Pod中的容器,它们使用相同的网络名称空间。对于容器,可观察的主机名是Pod的名称。由于容器共享相同的IP地址和端口空间,因此应在容器中使用不同的端口进行传入连接。因此,Pod中的应用程序必须协调其端口使用情况。

在以下示例中,我们将创建一个多容器Pod,其中一个容器中的nginx充当在第二个容器中运行的简单Web应用程序的反向代理。

共享网络

我们使用Nginx配置文件创建ConfigMap。到端口80的传入HTTP请求将转发到本地主机上的端口5000

apiVersion: v1
kind: ConfigMap
metadata:
  name: mc3-nginx-conf
data:
  nginx.conf: |-
    user  nginx;
    worker_processes  1;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  1024;
    }

    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;
        keepalive_timeout  65;

        upstream webapp {
            server 127.0.0.1:5000;
        }

        server {
            listen 80;

            location / {
                proxy_pass         http://webapp;
                proxy_redirect     off;
            }
        }
    }    

使用简单的Web应用程序和Nginx在单独的容器中创建一个多容器Pod。请注意,对于Pod,我们仅定义了nginx端口80,在Pod外部将无法访问端口5000

apiVersion: v1
kind: Pod
metadata:
  name: mc3
  labels:
    app: mc3
spec:
  containers:
    - name: webapp
      image: training/webapp
    - name: nginx
      image: nginx:alpine
      ports:
        - containerPort: 80
      volumeMounts:
        - name: nginx-proxy-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: nginx-proxy-config
      configMap:
        name: mc3-nginx-conf

然后通过NodePort服务暴露端口:

$ kubectl expose pod mc3 --type=NodePort --port=80
service "mc3" exposed

$ kubectl describe service mc3
...
NodePort:		<unset>	31418/TCP
...

Pause镜像的作用

比如说现在有一个Pod,其中包含了一个容器A和一个容器B,它们两个就要共享Network Namespace。在K8s里的解法是这样的:它会在每个Pod里,额外起一个pause container小容器来共享整个PodNetwork Namespacepause container是一个非常小的镜像,大概100~200KB左右,是一个汇编语言写的、永远处于“暂停”状态的容器。由于有了这样一个pause container之后,其他所有容器都会通过Join Namespace的方式加入到pause containerNetwork Namespace中。

所以说一个Pod里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于Pod第一次创建的这个pause container。这就是Pod解决网络共享的一个解法。在Pod里面,一定有一个IP地址,是这个PodNetwork Namespace对应的地址,也是这个pause containerIP地址。所以大家看到的都是一份,而其他所有网络资源,都是一个Pod一份,并且被Pod中的所有容器共享。这就是Pod的网络实现方式。

由于需要有一个相当于说中间的容器存在,所以整个Pod里面,必然是pause container第一个启动。并且整个Pod的生命周期是等同于pause container的生命周期的,与容器AB是无关的。这也是为什么在K8s里面,它是允许去单独更新Pod里的某一个镜像的,即:做这个操作,整个Pod不会重建,也不会重启,这是非常重要的一个设计。

上一页