I have a SPA and a microservices architecture. I am running the program locally on my machine using skaffold dev
and kubernetes with Google Cloud Provider (GCP). I am connecting my frontend to my backend using Ingress-NGINX. When I go to the host name on my browser mavata.dev
(configured on my local machine), I can no longer load the site. I get a "Cannot GET localhost:9000/main.js" net:::ERR_CONNECTION_REFUSED. See below for my config:
Kubernetes Config:
(ingress-srv.yaml)
# RUN: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.1/deploy/static/provider/cloud/deploy.yaml
# for GCP run: kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user $(gcloud config get-value account)
# then run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/cloud/deploy.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-srv
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: 'true'
# certmanager.k8s.io/cluster-issuer: core-prod
# nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
# nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"
# nginx.ingress.kubernetes.io/rewrite-target: /
# nginx.ingress.kubernetes.io/secure-backends: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/websocket-services: core-service
# nginx.org/websocket-services: core-service
#---
# nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
# nginx.ingress.kubernetes.io/server-snippets: |
# location / {
# proxy_set_header Upgrade $http_upgrade;
# proxy_http_version 1.1;
# proxy_set_header X-Forwarded-Host $http_host;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Forwarded-For $remote_addr;
# proxy_set_header Host $host;
# proxy_set_header Connection "upgrade";
# proxy_cache_bypass $http_upgrade;
# }
spec:
rules:
- host: mavata.dev # need to update 'hosts' file on local machine (in VS Code) C:\Windows\System32\drivers\etc
http:
paths:
# - backend:
# pathType: Prefix
# serviceName: tornado-socket
# servicePort: 8000
# - path: /api/company/create
# pathType: Prefix
# backend:
# service:
# name: company-clusterip-srv
# port:
# number: 4000
# - path: /api/company/?(.*)
# pathType: Prefix
# backend:
# service:
# name: company-srv
# port:
# number: 4000
# - path: /api/companies
# pathType: Prefix
# backend:
# service:
# name: companies-srv
# port:
# number: 4000
- path: /api/users/?(.*)
pathType: Prefix
backend:
service:
name: auth-server-srv
port:
number: 4000
# - path: /api/permissions/?(.*)
# pathType: Prefix
# backend:
# service:
# name: permissions-srv
# port:
# number: 4000
- path: /?(.*)
pathType: Prefix
backend:
service:
name: client-srv
port:
number: 9000
(client-depl.yaml)
apiVersion: apps/v1
kind: Deployment # tpye of k8s object we want to create
metadata:
name: client-depl
spec:
replicas: 1
selector:
matchLabels:
app: client
template:
metadata:
labels:
app: client
spec:
containers:
- name: client-container
image: us.gcr.io/mavata/frontend
ports:
- containerPort: 9000
---
apiVersion: v1
kind: Service
metadata:
name: client-srv
spec:
selector:
app: client
ports:
- name: client-container
protocol: TCP
port: 9000
targetPort: 9000
SPA Webpack Dev Config:
(webpack.dev.config)
const { merge } = require('webpack-merge');
// const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const commonConfig = require('./webpack.common');
// const packageJson = require('../package.json');
const globals = require('../src/data-variables/global');
const port = globals.port;
const devConfig = {
mode: 'development',
output: {
publicPath: `http://localhost:${port}/` // don't forget the slash at the end
},
devServer: {
host: '0.0.0.0',
port: port,
allowedHosts: ['mavata.dev'],
historyApiFallback: {
index: 'index.html',
},
},
// plugins: [
// new ModuleFederationPlugin({
// name: 'container',
// filename: 'remoteEntry.js',
// remotes: {
// marketingMfe: 'marketingMod@http://localhost:8081/remoteEntry.js',
// authMfe: 'authMod@http://localhost:8082/remoteEntry.js',
// companyMfe: 'companyMod@http://localhost:8083/remoteEntry.js',
// dataMfe: 'dataMod@http://localhost:8084/remoteEntry.js'
// },
// exposes: {
// './Functions': './src/functions/Functions',
// './Variables': './src/data-variables/Variables'
// },
// shared: {...packageJson.dependencies, ...packageJson.peerDependencies},
// }),
// ],
};
module.exports = merge(commonConfig, devConfig);
(webpack.common.config)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react', '@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(scss)$/,
use: [
{
// Adds CSS to the DOM by injecting a `<style>` tag
loader: 'style-loader'
},
{
// Interprets `@import` and `url()` like `import/require()` and will resolve them
loader: 'css-loader'
},
{
// Loads a SASS/SCSS file and compiles it to CSS
loader: 'sass-loader'
},
]
},
// {
// test: /\.s[ac]ss$/i,
// use: [
// // Creates `style` nodes from JS strings
// "style-loader",
// // Translates CSS into CommonJS
// "css-loader",
// // Compiles Sass to CSS
// "sass-loader",
// ],
// },
{
test: /\.svg$/,
use: ['@svgr/webpack'],
},
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
outputPath: 'fonts/'
}
}
]
},
{
// Load all images as base64 encoding if they are smaller than 8192 bytes
test: /\.(png|jpg|jpeg|gif|ico|svg|webp)$/,
use: [
{
// loader: 'url-loader',
loader: 'file-loader',
options: {
// On development we want to see where the file is coming from, hence we preserve the [path]
name: '[path][name].[ext]?hash=[hash:20]',
//name: '[path][name].[ext]',
limit: 8192
},
},
],
},
{
// Load all icons
test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
use: [
{
loader: 'file-loader',
}
],
},
{
test: /\.(ttf|eot|woff|woff2)$/,
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
resolve: {
extensions: ['', '.js', '.jsx', '.scss', '.eot', '.ttf', '.svg', '.woff'],
modules: ['node_modules', 'src', 'scripts', 'images', 'fonts'],
alias: {
Navbar: path.resolve(__dirname, '../src/components/navbar/'),
containerMfe: path.resolve(__dirname, '../src/'),
Variables: path.resolve(__dirname, '../src/data-variables/Variables.js'),
Functions: path.resolve(__dirname, '../src/functions/Functions.js')
}
},
};