对另一个 Kubernetes 容器的 GET 请求的正确 URL 是多少?
What is the correct URL to use for GET requests to another Kubernetes container?
我正在尝试创建一个简单的微服务,其中一个 Docker 容器中的 JQuery 应用程序使用此代码从另一个(分析)应用程序获取 JSON 对象在不同的容器中运行:
<script type="text/javascript">
$(document).ready(function(){
$('#get-info-btn').click(function(){
$.get("http://localhost:8084/productinfo",
function(data, status){
$.each(data, function(i, obj) {
//some code
});
});
});
});
</script>
另一个应用程序将其用于 Deployment
容器端口。
ports:
- containerPort: 8082
这些用于 Service
端口。
type: ClusterIP
ports:
- targetPort: 8082
port: 8084
'analytics' 应用程序是一个监听 8082 的 golang 程序。
func main() {
http.HandleFunc("/productinfo", getInfoJSON)
log.Fatal(http.ListenAndServe(":8082", nil))
}
当 运行 在 Minikube 上执行此操作时,我遇到了 CORS 问题,当 return 将 JSON 对象作为响应时,通过在 golang 代码中使用此问题得到了解决:
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
所有这些在 Minikube 上运行良好(尽管在 Minikube 中我使用的是 localhost:8082
)。第一个应用程序将向 http://localhost:8084/productinfo
发送 GET 请求,第二个应用程序将 return 一个 JSON 对象。
但是当我通过 : 访问第一个应用程序在云 Kubernetes 设置上尝试它时,当我打开浏览器控制台时,我不断收到错误 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8084/productinfo
。
问题:
为什么它在 Minikube 上工作而不在云 Kubernetes 工作节点上工作?使用 localhost
是访问另一个容器的正确方法吗?我怎样才能让它工作?实施微服务的人如何跨容器使用他们的 GET 和 POST 请求?我发现的所有微服务示例都是为 Minikube 上的简单演示而构建的,因此很难掌握这种细微差别。
@P.... 完全正确,我只是想提供一些关于 DNS for Services 和同一 Pod 中容器之间通信的更多细节。
服务的 DNS
正如我们在 documentation 中发现的那样,Kubernetes 服务被分配了一个 DNS A(或 AAAA)记录,其名称形式为 <serviceName>.<namespaceName>.svc.<cluster-domain>
。这解析为服务的集群 IP。
"Normal" (not headless) Services are assigned a DNS A or AAAA record, depending on the IP family of the service, for a name of the form my-svc.my-namespace.svc.cluster-domain.example. This resolves to the cluster IP of the Service.
让我们将表格 <serviceName>.<namespaceName>.svc.<cluster-domain>
分解为各个部分:
<serviceName>
- 您要连接的服务的名称。
<namespaceName>
- 要连接的服务所在的命名空间的名称。
svc
- 这不应更改 - svc
代表服务。
<cluster-domain>
- 集群域,默认为cluster.local
.
我们可以使用 <serviceName>
访问同一命名空间中的服务,但是我们也可以使用 <serviceName>.<namespaceName>
或 <serviceName>.<namespaceName>.svc
或 FQDN <serviceName>.<namespaceName>.svc.<cluster-domain>
.
如果Service在不同的Namespace中,一个<serviceName>
是不够的,我们需要使用<serviceName>.<namespaceName>
(我们也可以使用:<serviceName>.<namespaceName>.svc
或<serviceName>.<namespaceName>.svc.<cluster-domain>
).
在以下示例中,app-1
和 app-2
位于同一命名空间中,并且 app-2
在端口 8084
上通过 ClusterIP 公开(如您的情况):
$ kubectl run app-1 --image=nginx
pod/app-1 created
$ kubectl run app-2 --image=nginx
pod/app-2 created
$ kubectl expose pod app-2 --target-port=80 --port=8084
service/app-2 exposed
$ kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/app-1 1/1 Running 0 45s
pod/app-2 1/1 Running 0 41s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/app-2 ClusterIP 10.8.12.83 <none> 8084/TCP 36s
注意: app-2
与 app-1
在同一个命名空间中,因此我们可以使用 <serviceName>
从 app-1
,您还可以注意到我们得到了 app-2
(app-2.default.svc.cluster.local
) 的 FQDN:
$ kubectl exec -it app-1 -- bash
root@app-1:/# nslookup app-2
Server: 10.8.0.10
Address: 10.8.0.10#53
Name: app-2.default.svc.cluster.local
Address: 10.8.12.83
注意: 我们需要提供端口号,因为 app-2
正在侦听 8084
:
root@app-1:/# curl app-2.default.svc.cluster.local:8084
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
让我们在不同的命名空间中创建 app-3
,看看如何从 app-1
:
连接到它
$ kubectl create ns test-namespace
namespace/test-namespace created
$ kubectl run app-3 --image=nginx -n test-namespace
pod/app-3 created
$ kubectl expose pod app-3 --target-port=80 --port=8084 -n test-namespace
service/app-3 exposed
注意: 使用app-3
(<serviceName>
)是不够的,我们还需要提供[=45=所在的命名空间的名称] 驻留 (<serviceName>.<namespaceName>
):
# nslookup app-3
Server: 10.8.0.10
Address: 10.8.0.10#53
** server can't find app-3: NXDOMAIN
# nslookup app-3.test-namespace
Server: 10.8.0.10
Address: 10.8.0.10#53
Name: app-3.test-namespace.svc.cluster.local
Address: 10.8.12.250
# curl app-3.test-namespace.svc.cluster.local:8084
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
同一 Pod 中容器之间的通信
我们可以使用localhost
与其他容器通信,但是只能在同一个Pod(多容器pods)内。
我用两个容器创建了一个简单的多容器 Pod:nginx-container
和 alpine-container
:
$ cat multi-container-app.yml
apiVersion: v1
kind: Pod
metadata:
name: multi-container-app
spec:
containers:
- image: nginx
name: nginx-container
- image: alpine
name: alpine-container
command: ["sleep", "3600"]
$ kubectl apply -f multi-container-app.yml
pod/multi-container-app created
我们可以连接到 alpine-container
容器并检查我们是否可以使用 localhost
:
访问位于 nginx-container
的 nginx 网络服务器
$ kubectl exec -it multi-container-app -c alpine-container -- sh
/ # netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::80 :::* LISTEN -
/ # curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
有关同一 Pod 中容器之间通信的更多信息,请参见 。
我正在尝试创建一个简单的微服务,其中一个 Docker 容器中的 JQuery 应用程序使用此代码从另一个(分析)应用程序获取 JSON 对象在不同的容器中运行:
<script type="text/javascript">
$(document).ready(function(){
$('#get-info-btn').click(function(){
$.get("http://localhost:8084/productinfo",
function(data, status){
$.each(data, function(i, obj) {
//some code
});
});
});
});
</script>
另一个应用程序将其用于 Deployment
容器端口。
ports:
- containerPort: 8082
这些用于 Service
端口。
type: ClusterIP
ports:
- targetPort: 8082
port: 8084
'analytics' 应用程序是一个监听 8082 的 golang 程序。
func main() {
http.HandleFunc("/productinfo", getInfoJSON)
log.Fatal(http.ListenAndServe(":8082", nil))
}
当 运行 在 Minikube 上执行此操作时,我遇到了 CORS 问题,当 return 将 JSON 对象作为响应时,通过在 golang 代码中使用此问题得到了解决:
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
所有这些在 Minikube 上运行良好(尽管在 Minikube 中我使用的是 localhost:8082
)。第一个应用程序将向 http://localhost:8084/productinfo
发送 GET 请求,第二个应用程序将 return 一个 JSON 对象。
但是当我通过 : 访问第一个应用程序在云 Kubernetes 设置上尝试它时,当我打开浏览器控制台时,我不断收到错误 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8084/productinfo
。
问题:
为什么它在 Minikube 上工作而不在云 Kubernetes 工作节点上工作?使用 localhost
是访问另一个容器的正确方法吗?我怎样才能让它工作?实施微服务的人如何跨容器使用他们的 GET 和 POST 请求?我发现的所有微服务示例都是为 Minikube 上的简单演示而构建的,因此很难掌握这种细微差别。
@P.... 完全正确,我只是想提供一些关于 DNS for Services 和同一 Pod 中容器之间通信的更多细节。
服务的 DNS
正如我们在 documentation 中发现的那样,Kubernetes 服务被分配了一个 DNS A(或 AAAA)记录,其名称形式为 <serviceName>.<namespaceName>.svc.<cluster-domain>
。这解析为服务的集群 IP。
"Normal" (not headless) Services are assigned a DNS A or AAAA record, depending on the IP family of the service, for a name of the form my-svc.my-namespace.svc.cluster-domain.example. This resolves to the cluster IP of the Service.
让我们将表格 <serviceName>.<namespaceName>.svc.<cluster-domain>
分解为各个部分:
<serviceName>
- 您要连接的服务的名称。<namespaceName>
- 要连接的服务所在的命名空间的名称。svc
- 这不应更改 -svc
代表服务。<cluster-domain>
- 集群域,默认为cluster.local
.
我们可以使用 <serviceName>
访问同一命名空间中的服务,但是我们也可以使用 <serviceName>.<namespaceName>
或 <serviceName>.<namespaceName>.svc
或 FQDN <serviceName>.<namespaceName>.svc.<cluster-domain>
.
如果Service在不同的Namespace中,一个<serviceName>
是不够的,我们需要使用<serviceName>.<namespaceName>
(我们也可以使用:<serviceName>.<namespaceName>.svc
或<serviceName>.<namespaceName>.svc.<cluster-domain>
).
在以下示例中,app-1
和 app-2
位于同一命名空间中,并且 app-2
在端口 8084
上通过 ClusterIP 公开(如您的情况):
$ kubectl run app-1 --image=nginx
pod/app-1 created
$ kubectl run app-2 --image=nginx
pod/app-2 created
$ kubectl expose pod app-2 --target-port=80 --port=8084
service/app-2 exposed
$ kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/app-1 1/1 Running 0 45s
pod/app-2 1/1 Running 0 41s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/app-2 ClusterIP 10.8.12.83 <none> 8084/TCP 36s
注意: app-2
与 app-1
在同一个命名空间中,因此我们可以使用 <serviceName>
从 app-1
,您还可以注意到我们得到了 app-2
(app-2.default.svc.cluster.local
) 的 FQDN:
$ kubectl exec -it app-1 -- bash
root@app-1:/# nslookup app-2
Server: 10.8.0.10
Address: 10.8.0.10#53
Name: app-2.default.svc.cluster.local
Address: 10.8.12.83
注意: 我们需要提供端口号,因为 app-2
正在侦听 8084
:
root@app-1:/# curl app-2.default.svc.cluster.local:8084
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
让我们在不同的命名空间中创建 app-3
,看看如何从 app-1
:
$ kubectl create ns test-namespace
namespace/test-namespace created
$ kubectl run app-3 --image=nginx -n test-namespace
pod/app-3 created
$ kubectl expose pod app-3 --target-port=80 --port=8084 -n test-namespace
service/app-3 exposed
注意: 使用app-3
(<serviceName>
)是不够的,我们还需要提供[=45=所在的命名空间的名称] 驻留 (<serviceName>.<namespaceName>
):
# nslookup app-3
Server: 10.8.0.10
Address: 10.8.0.10#53
** server can't find app-3: NXDOMAIN
# nslookup app-3.test-namespace
Server: 10.8.0.10
Address: 10.8.0.10#53
Name: app-3.test-namespace.svc.cluster.local
Address: 10.8.12.250
# curl app-3.test-namespace.svc.cluster.local:8084
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
同一 Pod 中容器之间的通信
我们可以使用localhost
与其他容器通信,但是只能在同一个Pod(多容器pods)内。
我用两个容器创建了一个简单的多容器 Pod:nginx-container
和 alpine-container
:
$ cat multi-container-app.yml
apiVersion: v1
kind: Pod
metadata:
name: multi-container-app
spec:
containers:
- image: nginx
name: nginx-container
- image: alpine
name: alpine-container
command: ["sleep", "3600"]
$ kubectl apply -f multi-container-app.yml
pod/multi-container-app created
我们可以连接到 alpine-container
容器并检查我们是否可以使用 localhost
:
nginx-container
的 nginx 网络服务器
$ kubectl exec -it multi-container-app -c alpine-container -- sh
/ # netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::80 :::* LISTEN -
/ # curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
有关同一 Pod 中容器之间通信的更多信息,请参见