众所周知k8s的网络一直是个很头疼的问题,这两天我也遇到了网络的问题.本文记录这几天所遇到的问题,以及解决方案

场景(前提)

我们公司适用的基础开发框架是spring cloud. 由于只有部分小组开始适用k8s,所以我们公司目前开发环境是虚拟机和k8s环境结合,eureka server也是部署在虚拟机环境中的. 我部署在k8s上的服务需要被容器外(即虚拟机)的服务调用,而且也需要被k8s集群内的服务调用.

需要说一句的重点

简单的说一下eureka的服务注册和服务发现机制.我们将做服务注册的服务称为生产服务,做服务发现的服务为消费服务

生产服务在注册时会使用当前服务的ip(spring cloud的eureka.instance.ip-address配置)和端口注册到eureka server中。

消费服务做服务发现时,eureka server会把ip:port返回.然后消费服务会用http://ip:port的形式访问生产服务.

面临的问题

由于生产服务在k8s内,所以它使用的是k8s集群内部的ip. 然后它注册时也是使用该ip去注册.所以当消费服务通过该ip:port访问生产服务时因为众所周知的网络问题(k8s集群外无法直接访问k8s内的ip)将无法访问。如下图:

Ingress

k8s外无法访问k8s内的网络问题,很自然的就想到了ingress.所以我的想法是让生产服务注册的ip-address变成(通过eureka.instance.ip-address参数更改)域名加端口的形式(host:80).为何端口要是80呢? 因为ingress是用host转发到容器内的ip:port去。假设你使用其他端口,那么消费服务会使用http://host:port 访问,然后ingress无法将host:port转到ip:port上. 所以就做成了下图这样:

但是由于使用了host:port,消费服务A内没有Hosts映射所以无法访问到生产服务。那怎么办?当然是往消费服务A容器中添加host映射.但是真有那么容易?请继续往下看.

添加hosts遇到的问题

在容器中添加host无法这几种方案:

  1. 在Dockerfile中echo ‘ip host’ >> /etc/hosts.
  2. 在pod中使用hostAliases(k8s 1.7开始支持)添加映射
  3. 在deployment中添加

首先我是尝试第一种方式的,但是发现不行.后来查询了docker官网和k8s官网,都说如果这样做,在容器启动之后会失效(具体原因没深究,以后补回来)。所以只好作罢.第二种方式,一般我们在使用k8s时,不直接使用pod.所以只好作罢. 那只剩下第三种方式了. 在github上搜索到了如下可行配置:

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: service-a
  labels:
    app: service-a
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: service-a
  template:
    metadata:
      labels:
        app: service-a
    spec:
      containers:
        - name: service-a
          image: "{{ .Values.image.schedule.repository }}:{{ .Values.image.schedule.tag }}"
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh", "-c", "echo \"10.100.13.30  host\" >> /etc/hosts"]

至此才算把容器内外的网络打通