我正在创建一个Web应用程序,其中包含一个 React 前端和一个 node.js (表示)服务器。前端对快递服务器进行内部api调用,然后快递服务器进行外部api调用以收集一些数据。前端和服务器位于同一Kubernetes容器内的不同容器中。
前端服务是一张nginx:1.14.0-alpine
图像。静态文件在CI管道中构建(npm build
),并且build
目录在docker build
期间复制到映像。 package.json
包含一个代理密钥"proxy": "http://localhost:8080"
,该代理密钥将流量从应用程序路由到localhost:8080
-这是Express服务器正在侦听内部api调用的端口。我认为proxy
键一旦将文件打包成静态文件并放到nginx
图像上就不会起作用了?
在本地运行(即运行npm start
而不是npm build
时,所有这些都有效。快递服务器接收前端在端口8080
上发出的api请求。
express服务器是一项简单的服务,它将身份验证添加到前端进行的api调用中,仅此而已。但是身份验证依赖于机密作为环境变量,从而使它们与React不兼容。通过运行node server.js
启动服务器;在本地,服务器服务成功侦听(app.listen(8080)
)来自React前端的api调用,向请求添加了一些身份验证,然后将请求发送到外部api,并在收到响应后将响应传递回前端
在生产中,在Kubernetes窗格中,事情并不是那么简单。通过节点服务器来自 React前端代理的流量现在需要由kubernetes处理,而我一直无法弄清。
可能需要注意的是,在任何情况下前端都不会直接进行任何外部api调用,它们都将通过服务器。
> 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/;
}
.....
答案 0 :(得分:3)
在Kubernetes中,thes pod与其中的所有容器共享相同的网络接口,因此对于前端容器 localhost:8080 是后端,对于后端容器 localhost:80 < / strong>是前端。 对于任何容器应用程序,如果需要外部流量,则应确保它们在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/