【问题标题】:How to route all traffic from a container through another container in the same Kubernetes pod?如何将来自容器的所有流量路由到同一个 Kubernetes pod 中的另一个容器?
【发布时间】:2020-07-03 11:37:58
【问题描述】:

我正在创建一个包含 React frontendnode.js (express) server 的 Web 应用程序强>。前端对 express 服务器进行内部 api 调用,然后 express 服务器进行外部 api 调用以收集一些数据。前端和服务器位于同一个 Kubernetes pod 内的不同容器中。

前端服务nginx:1.14.0-alpine 图像。静态文件在 CI 管道中构建 (npm build),build 目录在docker build 期间复制到映像。 package.json 包含一个代理密钥 "proxy": "http://localhost:8080",它将流量从应用程序路由到 localhost:8080 - 这是快速服务器正在侦听内部 api 调用的端口。我认为一旦将文件打包成静态文件并提供到nginx 图像上,proxy 密钥将不起作用?

在本地运行时,即运行npm start 而不是npm build,这一切都有效。 express 服务器在端口8080 上接收前端发出的api请求。

express server 是一个简单的服务,它将身份验证添加到前端进行的 api 调用中,仅此而已。但是身份验证依赖于秘密作为环境变量,这使得它们与 React 不兼容。服务器通过运行node server.js启动;在本地,服务器服务成功侦听(app.listen(8080))来自 React 前端的 api 调用,为请求添加一些身份验证,然后向外部 api 发出请求,并在收到响应后将响应传回前端。

在生产环境中,在 Kubernetes pod 中,事情并非如此简单。来自React前端代理通过节点服务器的流量现在需要kubernetes来处理,我一直没搞清楚。

可能需要注意的是,前端不会直接进行任何外部api调用,它们都将通过服务器。 p>

React frontend Dockerfile

FROM nginx:1.14.0-alpine

# Copy static files
COPY client/build/ /usr/share/nginx/html/

# The rest has been redacted for brevity but is just copying of favicons etc.

Express Node Server

FROM node:10.16.2-alpine

# Create app directory
WORKDIR /app

# Install app dependencies
COPY server/package*.json .

RUN npm install

EXPOSE 8080

CMD [ "node", "server.js" ]

Kubernetes Manifest - 为简洁而编辑

apiVersion: apps/v1beta1
kind: Deployment

containers:
      - name: frontend
        image: frontend-image:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/conf.d/default.conf
          name: config-dir
          subPath: my-config.conf

      - name: server
              image: server-image:1.0.0
              imagePullPolicy: IfNotPresent
              volumes:
              - name: config-tmpl
                configMap:
                  name: app-config
                  defaultMode: 0744
              - name: my-config-directory
                emptyDir: {}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: my-namespace
data:
  my-conf.conf: |-
    server {

        listen 80;

        server_name _;

        location api/ {
          proxy_pass  http://127.0.0.1:8080/;
        }

.....

【问题讨论】:

  • 127.0.0.1:8080 不是快速服务器的地址,因为前端 docker 容器中的端口 8080 上没有运行任何东西。您需要对其中一个快速服务器 pod 的地址执行 proxy_pass。由于所有 pod 都有一个 DNS 地址,因此这可以像 http://<service>.<name-space>.svc.cluster.loca 一样简单
  • 前端应用最终运行在用户的浏览器中;那怎么知道要联系 Express 服务器?

标签: node.js docker nginx kubernetes amazon-eks


【解决方案1】:

在 Kubernetes 中,s pod 与其中的所有容器共享相同的网络接口,因此对于前端容器 localhost:8080 是后端,对于后端容器 localhost:80 是前端。 对于任何容器应用程序,如果您想要来自外部的流量,您应该确保它们正在侦听 127.0.0.1 以外的其他接口。

将应用程序从一台服务器(每个应用程序都从 127.0.0.1 通信)迁移到 Pod 的目的是像在专用机器中一样简单。

你的nginx.conf看起来有点奇怪,应该是location /api/ {

这是功能示例:

nginx.conf

server {
    server_name   localhost;
    listen        0.0.0.0:80;

    error_page    500 502 503 504  /50x.html;

    location      / {
        root      html;
    }
    location /api/ {
      proxy_pass  http://127.0.0.1:8080/;
    }

}

创建这个ConfigMap

kubectl create -f nginx.conf

app.js

const express = require('express')
const app = express()
const port = 8080

app.get('/', (req, res) => res.send('Hello from Express!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Dockerfile

FROM alpine

RUN apk add nodejs npm && mkdir -p /app

COPY . /app

WORKDIR /app

RUN npm install express --save

EXPOSE 8080

CMD node app.js

您可以构建此图像或使用我制作的图像 hectorvido/express

然后,创建 pod YAML 定义:

pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: front-back
  labels:
    app: front-back
spec:
  containers:
  - name: front
    image: nginx:alpine
    volumeMounts:
    - name: nginx-conf
      mountPath: /etc/nginx/conf.d/
    ports:
    - containerPort: 80
  - name: back
    image: hectorvido/express
    ports:
    - containerPort: 8080      
  volumes:
  - name: nginx-conf
    configMap:
      name: nginx

装上集群:

kubectl create -f pod.yml

获取IP:

kubectl get pods -o wide

我用 Minikube 测试过,所以如果 pod IP 是 172.17.0.7 我必须这样做:

minikube ssh
curl -L 172.17.0.7/api

如果前面有入口,它应该仍然可以工作。我在 minikube 上启用了一个 nginx 入口控制器,所以我们需要创建一个服务和一个入口:

服务

kubectl expose pod front-back --port 80

ingress.yml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: front-back
spec:
  rules:
  - host: fb.192-168-39-163.nip.io # minikube ip
    http:
      paths:
      - path: /
        backend:
          serviceName: front-back
          servicePort: 80

测试仍然有效:

curl -vL http://fb.192-168-39-163.nip.io/api/

【讨论】:

  • 嘿赫克托,我将这个答案标记为正确,因为我相信我提出的问题是正确的,但是,它对我不起作用。我突然想到我有一个 Kong Ingress 处理我的命名空间中的流量,由于上述方法不起作用,我用它来路由流量 - 我现在让它工作了。感谢您抽出宝贵时间回答! :)
  • 嗯... ingress 的过程是一样的,如果你愿意,我可以在上面的例子中添加一个 ingress,但是 Minikube 使用 nginx - 应该是同样的功能。
  • 我设法让它与 Kong Ingress 一起工作,谢谢。虽然我不完全明白为什么我不能让它与 nginx 一起工作
  • 奇怪......即使有入口,它仍然可以在这里工作:/我会更新答案。也许一些注释会解决,甚至在 nginx.conf 上使用或不使用斜线进行重定向。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多