将裸机 kubernetes 集群暴露到互联网

Exposing bare metal kubernetes cluster to internet

我正在尝试在裸机专用服务器上设置自己的单节点 kubernetes 集群。我在开发运营方面经验不足,但我需要为自己的项目部署一些服务。我已经使用 jujuconjure-up kubernetesLXD 上进行了集群设置。我有 运行ning 集群很好。

$ juju status

Model                         Controller                Cloud/Region         Version  SLA          Timestamp
conjure-canonical-kubern-3b3  conjure-up-localhost-db9  localhost/localhost  2.4.3    unsupported  23:49:09Z

App                    Version  Status  Scale  Charm                  Store       Rev  OS      Notes
easyrsa                3.0.1    active      1  easyrsa                jujucharms  195  ubuntu
etcd                   3.2.10   active      3  etcd                   jujucharms  338  ubuntu
flannel                0.10.0   active      2  flannel                jujucharms  351  ubuntu
kubeapi-load-balancer  1.14.0   active      1  kubeapi-load-balancer  jujucharms  525  ubuntu  exposed
kubernetes-master      1.13.1   active      1  kubernetes-master      jujucharms  542  ubuntu
kubernetes-worker      1.13.1   active      1  kubernetes-worker      jujucharms  398  ubuntu  exposed

Unit                      Workload  Agent  Machine  Public address  Ports           Message
easyrsa/0*                active    idle   0        10.213.117.66                   Certificate Authority connected.
etcd/0*                   active    idle   1        10.213.117.171  2379/tcp        Healthy with 3 known peers
etcd/1                    active    idle   2        10.213.117.10   2379/tcp        Healthy with 3 known peers
etcd/2                    active    idle   3        10.213.117.238  2379/tcp        Healthy with 3 known peers
kubeapi-load-balancer/0*  active    idle   4        10.213.117.123  443/tcp         Loadbalancer ready.
kubernetes-master/0*      active    idle   5        10.213.117.172  6443/tcp        Kubernetes master running.
  flannel/1*              active    idle            10.213.117.172                  Flannel subnet 10.1.83.1/24
kubernetes-worker/0*      active    idle   7        10.213.117.136  80/tcp,443/tcp  Kubernetes worker running.
  flannel/4               active    idle            10.213.117.136                  Flannel subnet 10.1.27.1/24

Entity  Meter status  Message
model   amber         user verification pending

Machine  State    DNS             Inst id        Series  AZ  Message
0        started  10.213.117.66   juju-b03445-0  bionic      Running
1        started  10.213.117.171  juju-b03445-1  bionic      Running
2        started  10.213.117.10   juju-b03445-2  bionic      Running
3        started  10.213.117.238  juju-b03445-3  bionic      Running
4        started  10.213.117.123  juju-b03445-4  bionic      Running
5        started  10.213.117.172  juju-b03445-5  bionic      Running
7        started  10.213.117.136  juju-b03445-7  bionic      Running

我还部署了 Hello world 应用程序以在 pod 内的端口 8080 上输出一些 hello,并 nginx-ingress 用于将流量重新路由到指定主机上的此服务。

NAME                               READY   STATUS    RESTARTS   AGE
pod/hello-world-696b6b59bd-fznwr   1/1     Running   1          176m

NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/example-service   NodePort    10.152.183.53   <none>        8080:30450/TCP   176m
service/kubernetes        ClusterIP   10.152.183.1    <none>        443/TCP          10h

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/hello-world   1/1     1            1           176m

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/hello-world-696b6b59bd   1         1         1       176m

当我按预期执行 curl localhost 时,我得到了 connection refused,它看起来仍然很好,因为它没有暴露在群集中。当我在端口 30450 上使用 public 地址 10.213.117.136 卷曲 kubernetes-worker/0(我从 kubectl get all 获得)

$ curl 10.213.117.136:30450
Hello Kubernetes!

一切都像一个魅力(这是显而易见的)。当我做

curl -H "Host: testhost.com" 10.213.117.136
Hello Kubernetes!

它再次发挥魅力!这意味着入口控制器成功地根据 host 规则路由端口 80 以更正服务。在这一点上,我 100% 确定集群正常工作。

现在我正尝试通过 Internet 从外部访问此服务。当我加载 <server_ip> 时,显然没有任何加载,因为它位于自己的 lxd 子网中。因此我在考虑从服务器 eth0 转发端口 80 到这个 IP。所以我将这条规则添加到 iptables

sudo iptables -t nat -A PREROUTING -p tcp -j DNAT --to-destination 10.213.117.136(为了举例,让我们路由所有内容,而不仅仅是端口 80)。现在,当我在计算机上打开 http://<server_ip> 时,它会加载!

所以真正的问题是如何在生产中做到这一点?我应该在 iptables 中设置此转发规则吗?这是正常的方法还是 hacky 解决方案,我缺少 "standard" 的东西?问题是添加带有 static worker 节点的规则将使集群完全静态。 IP最终会改变,我可以remove/add单位给工人,它会停止工作。我正在考虑编写脚本,它将像这样从 juju 获取此 IP 地址:

$ juju status kubernetes-worker/0 --format=json | jq '.machines["7"]."dns-name"'
"10.213.117.136"

并将其添加到 IP 表中,这是比硬编码 IP 更好的解决方案,但我仍然觉得这很棘手,必须有更好的方法。

作为最后一个想法,我在集群外 运行 HAProxy 直接在机器上,只是将流量转发给所有可用的工作人员。这最终可能也会奏效。但是我仍然不知道答案什么是 correct 解决方案以及在这种情况下通常使用什么。谢谢!

So the real question is how to do that on production?

在生产系统中执行此操作的正常方法是使用 Service.

最简单的情况是您只希望您的应用程序可以从您的节点上的外部访问。在这种情况下,您可以使用 Type NodePort 服务。这将创建将流量从主机 IP 地址转发到提供服务的 pod 所需的 iptables 规则。

如果您只有一个节点(不建议在生产中使用!),此时您已准备就绪。

如果您的 Kubernetes 集群中有多个节点,所有这些节点都将由 Kubernetes 配置以提供对服务的访问(您的客户端可以使用其中任何一个来访问该服务)。但是,您必须解决客户端如何知道可以联系哪些节点的问题...

有几种方法可以解决这个问题:

  • 使用客户端理解的协议发布当前可用的IP地址(例如DNS),

  • 使用由您的 Kubernetes 节点上的某些软件管理的浮动(故障转移、虚拟、HA)IP 地址(例如 pacemaker/corosync),并将客户端定向到该地址,

  • 使用单独配置的外部负载均衡器将流量转发到一些运行节点,

  • 使用外部负载均衡器,由 Kubernetes 使用云提供商集成脚本(通过使用 Type LoadBalancer 服务)自动配置,将流量转发到一些运行节点。