通过 kubernetes 单节点集群创建服务没有 'ingress' 外部 IP,但是 google 容器引擎可以(?)
creating a service via kubernetes single node cluster gives me no 'ingress' external IP, but google container engine does (?)
我正在尝试设置一个单节点 kubernetes 集群用于演示和测试目的,我希望它能够正常运行
像 'full blown' k8s 集群(像 google 容器引擎)。我的客户有自己的 k8s 安装,
对于此讨论,我们可以假设行为非常类似于 google 容器引擎的 k8s 安装。
在完整的 K8s 上获取 Ingress IP
我正在创建一个 wordpress pod 并将其公开为服务,如本教程中所述:
https://cloud.google.com/container-engine/docs/tutorials/hello-wordpress
如果你想重现这个问题,只需复制粘贴下面的命令,我从教程中提取了这些命令:
(假设您有一个名为 'stellar-access-117903' 的项目。如果没有,请设置为您的 Google 容器的名称
引擎项目。)
# set up the cluster (this will take a while to provision)
#
gcloud config set project stellar-access-117903
gcloud config set compute/zone us-central1-b
gcloud container clusters create hello-world \
--num-nodes 1 \
--machine-type g1-small
# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer
# Describe the service
kubectl describe services wordpress
describe 命令的输出包含一行 'LoadBalancer Ingress: {some-ip-address}',它是
正是我所期望的。现在,当我对单节点集群设置做同样的事情时 我不
得到那条线。我能够在出现在输出中的 IP 上访问 wordpress 服务
'describe service'命令..但是在'single node'模式下,打印出来的IP是>集群IP<
的服务,通常(据我所知)是不可公开访问的。出于某种原因,它是
在单节点模式下可公开访问。我们可以通过以下步骤复制它。
在单节点 K8s 上未获取 Ingress IP
首先设置单节点 k8s,如本教程所述:
https://github.com/kubernetes/kubernetes/blob/master/docs/getting-started-guides/docker.md
为了便于重现,我在下面包含了所有命令,因此您只需 copy/paste:
K8S_VERSION=1.1.1
sudo docker run --net=host -d gcr.io/google_containers/etcd:2.0.12 /usr/local/bin/etcd --addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data
sudo docker run \
--volume=/:/rootfs:ro \
--volume=/sys:/sys:ro \
--volume=/dev:/dev \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
--volume=/var/run:/var/run:rw \
--net=host \
--pid=host \
--privileged=true \
-d \
gcr.io/google_containers/hyperkube:v${K8S_VERSION} \
/hyperkube kubelet --containerized --hostname-override="127.0.0.1" --address="0.0.0.0" --api-servers=http://localhost:8080 --config=/etc/kubernetes/manifests
sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v${K8S_VERSION} /hyperkube proxy --master=http://127.0.0.1:8080 --v=2
# set your context to use the locally running k8s API server
#
kubectl config set-cluster dev --server=http://localhost:8080
kubectl config set-context dev --cluster=dev --namespace=$NS
kubectl config use-context dev
现在,执行与 Google Container Engine 的 k8s
相同的命令
# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer
# Describe the service
kubectl describe services wordpress
最后一条命令的输出(您将看到没有 'Ingress' 信息)是:
Name: wordpress
Namespace: default
Labels: run=wordpress
Selector: run=wordpress
Type: LoadBalancer
IP: 10.0.0.61
Port: <unnamed> 80/TCP
NodePort: <unnamed> 31795/TCP
Endpoints: 172.17.0.30:80
Session Affinity: None
No events.
在 google 容器引擎的 k8s 中,我看到诸如“正在创建负载均衡器”、“已创建负载均衡器”之类的事件。但一点也不像
这发生在单节点实例中。
我想知道...我需要做一些配置才能让它们以相同的方式工作吗?非常重要的是,他们
工作方式相同......仅在可扩展性方面有所不同,因为我们希望 运行 针对单节点版本进行测试,并且
如果它的行为不同,将会非常混乱。
在此先感谢您的帮助
-克里斯
LoadBalancer 是由后端云提供商实施的一项功能,因此您看不到在本地设置中创建的功能
(查看云提供商:https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider/providers)
这是我们提出的解决方案。当我们 运行 针对单节点 Kubernetes 时,我们通过反复试验意识到,当您公开服务时,外部 IP 不会通过 IngressIP 返回;相反,它通过 clusterIP 返回,如上所述,它是公开可见的。所以,我们只是修改了我们的代码来处理它。我们在单节点情况下使用 clusterIP。这是我们用来在服务上建立监视的代码,以确定 k8s 何时分配了我们的外部可见 IP:
首先我们使用 fabric8 API 创建服务配置:
case "Service" =>
val serviceConf = mapper.readValue(f, classOf[Service])
val service = kube.services().inNamespace(namespaceId).create(serviceConf)
watchService(service)
'watchService'方法定义如下:
private def watchService(service: Service) = {
val namespace = service.getMetadata.getNamespace
val name = service.getMetadata.getName
logger.debug("start -> watching service -> namespace: " + namespace + " name: " + name)
val kube = createClient()
try {
@volatile var complete = false
val socket = kube.services().inNamespace(namespace).withName(name).watch(new Watcher[Service]() {
def eventReceived(action: Action, resource: Service) {
logger.info(action + ":" + resource)
action match {
case Action.MODIFIED =>
if (resource.getMetadata.getName == name) {
complete = isServiceComplete(resource)
}
// case Action.DELETED =>
// complete = true
case _ =>
}
}
})
while (!complete) {
Thread.sleep(5000)
complete = isServiceComplete(kube.services().inNamespace(namespace).withName(name).get)
}
logger.info("Closing socket connection")
socket.close()
} finally {
logger.info("Closing client connection")
kube.close()
}
logger.debug("complete -> watching services , namespace: " + namespace + " name: " + name)
}
我们介绍的关键 hack 是在方法 'isServiceComplete' 中。当使用单节点 k8s 时,'isUsingMock' 的值为真。这样我们就可以使用 clusterIP 来确定服务配置是否已完成。
private def isServiceComplete(service: Service) = {
!service.getStatus.getLoadBalancer.getIngress.isEmpty || mockServiceComplete(service)
}
def mockServiceComplete(service: Service): Boolean = {
val clusterIP = service.getSpec.getClusterIP
logger.trace(s"mockServiceComplete: $isUsingMock / $clusterIP / $KUBE_SERVER" )
isUsingMock && ! clusterIP.isEmpty
}
抱歉,如果这里没有太多额外的上下文。最终我们的项目应该是开源的,我们可以 post 一个完整的解决方案。
-克里斯
我正在尝试设置一个单节点 kubernetes 集群用于演示和测试目的,我希望它能够正常运行 像 'full blown' k8s 集群(像 google 容器引擎)。我的客户有自己的 k8s 安装, 对于此讨论,我们可以假设行为非常类似于 google 容器引擎的 k8s 安装。
在完整的 K8s 上获取 Ingress IP
我正在创建一个 wordpress pod 并将其公开为服务,如本教程中所述: https://cloud.google.com/container-engine/docs/tutorials/hello-wordpress
如果你想重现这个问题,只需复制粘贴下面的命令,我从教程中提取了这些命令: (假设您有一个名为 'stellar-access-117903' 的项目。如果没有,请设置为您的 Google 容器的名称 引擎项目。)
# set up the cluster (this will take a while to provision)
#
gcloud config set project stellar-access-117903
gcloud config set compute/zone us-central1-b
gcloud container clusters create hello-world \
--num-nodes 1 \
--machine-type g1-small
# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer
# Describe the service
kubectl describe services wordpress
describe 命令的输出包含一行 'LoadBalancer Ingress: {some-ip-address}',它是 正是我所期望的。现在,当我对单节点集群设置做同样的事情时 我不 得到那条线。我能够在出现在输出中的 IP 上访问 wordpress 服务 'describe service'命令..但是在'single node'模式下,打印出来的IP是>集群IP< 的服务,通常(据我所知)是不可公开访问的。出于某种原因,它是 在单节点模式下可公开访问。我们可以通过以下步骤复制它。
在单节点 K8s 上未获取 Ingress IP
首先设置单节点 k8s,如本教程所述: https://github.com/kubernetes/kubernetes/blob/master/docs/getting-started-guides/docker.md
为了便于重现,我在下面包含了所有命令,因此您只需 copy/paste:
K8S_VERSION=1.1.1
sudo docker run --net=host -d gcr.io/google_containers/etcd:2.0.12 /usr/local/bin/etcd --addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data
sudo docker run \
--volume=/:/rootfs:ro \
--volume=/sys:/sys:ro \
--volume=/dev:/dev \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
--volume=/var/run:/var/run:rw \
--net=host \
--pid=host \
--privileged=true \
-d \
gcr.io/google_containers/hyperkube:v${K8S_VERSION} \
/hyperkube kubelet --containerized --hostname-override="127.0.0.1" --address="0.0.0.0" --api-servers=http://localhost:8080 --config=/etc/kubernetes/manifests
sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v${K8S_VERSION} /hyperkube proxy --master=http://127.0.0.1:8080 --v=2
# set your context to use the locally running k8s API server
#
kubectl config set-cluster dev --server=http://localhost:8080
kubectl config set-context dev --cluster=dev --namespace=$NS
kubectl config use-context dev
现在,执行与 Google Container Engine 的 k8s
相同的命令# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer
# Describe the service
kubectl describe services wordpress
最后一条命令的输出(您将看到没有 'Ingress' 信息)是:
Name: wordpress
Namespace: default
Labels: run=wordpress
Selector: run=wordpress
Type: LoadBalancer
IP: 10.0.0.61
Port: <unnamed> 80/TCP
NodePort: <unnamed> 31795/TCP
Endpoints: 172.17.0.30:80
Session Affinity: None
No events.
在 google 容器引擎的 k8s 中,我看到诸如“正在创建负载均衡器”、“已创建负载均衡器”之类的事件。但一点也不像 这发生在单节点实例中。
我想知道...我需要做一些配置才能让它们以相同的方式工作吗?非常重要的是,他们 工作方式相同......仅在可扩展性方面有所不同,因为我们希望 运行 针对单节点版本进行测试,并且 如果它的行为不同,将会非常混乱。
在此先感谢您的帮助 -克里斯
LoadBalancer 是由后端云提供商实施的一项功能,因此您看不到在本地设置中创建的功能
(查看云提供商:https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider/providers)
这是我们提出的解决方案。当我们 运行 针对单节点 Kubernetes 时,我们通过反复试验意识到,当您公开服务时,外部 IP 不会通过 IngressIP 返回;相反,它通过 clusterIP 返回,如上所述,它是公开可见的。所以,我们只是修改了我们的代码来处理它。我们在单节点情况下使用 clusterIP。这是我们用来在服务上建立监视的代码,以确定 k8s 何时分配了我们的外部可见 IP:
首先我们使用 fabric8 API 创建服务配置:
case "Service" =>
val serviceConf = mapper.readValue(f, classOf[Service])
val service = kube.services().inNamespace(namespaceId).create(serviceConf)
watchService(service)
'watchService'方法定义如下:
private def watchService(service: Service) = {
val namespace = service.getMetadata.getNamespace
val name = service.getMetadata.getName
logger.debug("start -> watching service -> namespace: " + namespace + " name: " + name)
val kube = createClient()
try {
@volatile var complete = false
val socket = kube.services().inNamespace(namespace).withName(name).watch(new Watcher[Service]() {
def eventReceived(action: Action, resource: Service) {
logger.info(action + ":" + resource)
action match {
case Action.MODIFIED =>
if (resource.getMetadata.getName == name) {
complete = isServiceComplete(resource)
}
// case Action.DELETED =>
// complete = true
case _ =>
}
}
})
while (!complete) {
Thread.sleep(5000)
complete = isServiceComplete(kube.services().inNamespace(namespace).withName(name).get)
}
logger.info("Closing socket connection")
socket.close()
} finally {
logger.info("Closing client connection")
kube.close()
}
logger.debug("complete -> watching services , namespace: " + namespace + " name: " + name)
}
我们介绍的关键 hack 是在方法 'isServiceComplete' 中。当使用单节点 k8s 时,'isUsingMock' 的值为真。这样我们就可以使用 clusterIP 来确定服务配置是否已完成。
private def isServiceComplete(service: Service) = {
!service.getStatus.getLoadBalancer.getIngress.isEmpty || mockServiceComplete(service)
}
def mockServiceComplete(service: Service): Boolean = {
val clusterIP = service.getSpec.getClusterIP
logger.trace(s"mockServiceComplete: $isUsingMock / $clusterIP / $KUBE_SERVER" )
isUsingMock && ! clusterIP.isEmpty
}
抱歉,如果这里没有太多额外的上下文。最终我们的项目应该是开源的,我们可以 post 一个完整的解决方案。
-克里斯