NestJS: Microservices with Docker - docker

I'm working with microservices and I have a problem. I have two NestJS applications with microservices. First one is hybrid appliacation and the second one is just a simple microservices with app.listen() function. Everything is set up in Docker-compose. I just want to send a simple #EventPattern and it fails. Second application don't receive any event. I was following this topic: https://github.com/nestjs/nest/issues/2532 but it didn't help at all. Here is some code I wrote:
docker-compose-dev.yml
# First Server
# --------------------------------------------------
first-server:
container_name: first-server
image: project/firstserver
build:
context: ../first-server/
args:
UUID: ${UUID}
UGID: ${GUID}
environment:
NODE_ENV: ${NODE_ENV:-development}
depends_on:
- db-postgres
- db-mongo
user: "${UUID}:${GUID}"
tty: true
expose:
- "3000"
- "3010"
ports:
- "3000:3000"
- "3010:3010"
volumes:
- ../first-server:/app
networks:
- servers-network
# Second Server
# --------------------------------------------------
second-server:
container_name: second-server
image: project/secondserver
build:
context: ../second-server/
args:
UUID: ${UUID}
UGID: ${GUID}
environment:
NODE_ENV: ${NODE_ENV:-development}
depends_on:
- db-postgres
- db-mongo
user: "${UUID}:${GUID}"
tty: true
expose:
- "3100"
- "3020"
ports:
- "3100:3100"
- "3020:3020"
volumes:
- ../second-server:/app
networks:
- servers-network
# Docker networks
# --------------------------------------------------
networks:
servers-network:
driver: bridge
name: servers-network
first-server:
main.ts
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
const microservice = app.connectMicroservice({
transport: Transport.TCP,
options: {
host: '0.0.0.0',
port: 3010
}
});
await app.startAllMicroservicesAsync();
await app.listen(port);
}
app.module.ts
#Module({
imports: [
TypeOrmModule.forRootAsync({
useClass: TypeOrmPostgresConfigProvider,
name: TypeOrmPostgresConfigProvider.connectionName,
imports: [
ConfigModule
]
}),
TypeOrmModule.forRootAsync({
useClass: TypeOrmMongoConfigProvider,
name: TypeOrmMongoConfigProvider.connectionName,
imports: [
ConfigModule
]
}),
ServeStaticModule.forRoot({
rootPath: join(__dirname, '../..', 'public/app')
}),
ClientsModule.register([
{
name: 'SERVICE_A',
transport: Transport.TCP,
options: {
host: '0.0.0.0',
port: 3010
}
}
])
],
controllers: [
AppController
],
providers: []
})
app.controller.ts
export class AppController {
constructor(
#Inject('SERVICE_A') private readonly client: ClientProxy
) {
}
async onApplicationBootstrap() {
await this.client.connect()
.then(result => {
console.log('result');
})
.catch(error => {
console.log(error);
});
}
#Get('hello')
getHello() {
this.client.emit<any>('message_printed', new Message('Hi there!'));
return 'Hello World printed';
}
#EventPattern('message_printed')
async handleMessagePrinted(data: Record<string, unknown>) {
console.log('first-server event!');
}
}
second-server:
main.ts
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
host: '0.0.0.0',
port: 3020
}
}
);
app.listen(() => console.log('Microservice is listening'));
}
app.controller.ts
export class AppController {
constructor() {
}
#EventPattern('message_printed')
async handleMessagePrinted(data: Record<string, unknown>) {
console.log('second-server event!');
}
}
On both servers I have latest versions of NestJS. Docker version is 19.03.5.

Related

How add rollupNodePolyFill to electron.vite.configs

I need excute 'twilio-client' on electron project
import Twilio from 'twilio-client';
// this line broken when run electron-vite preview or builded app version
const device = new Twilio.Device();
device.setup('xyls', {
debug: true
});
console.log(device);
When I run my app with electron-vite preview or after build, I got an error:
Uncaught TypeError: Failed to resolve module specifier "events"
This also happened when it was executed:
electron-vite dev --watch
I added nodePolifill plugins now it works in dev mode, but on preview or build doesn't
The plugin 'rollup-plugin-node-polyfills' doesn't works on build.rollupOptions.plugins
I need help
My electron.vite.configs.ts:
import { resolve, normalize, dirname } from 'path'
import { defineConfig } from 'electron-vite'
import injectProcessEnvPlugin from 'rollup-plugin-inject-process-env'
import tsconfigPathsPlugin from 'vite-tsconfig-paths'
import reactPlugin from '#vitejs/plugin-react'
import { NodeGlobalsPolyfillPlugin } from '#esbuild-plugins/node-globals-polyfill'
import { NodeModulesPolyfillPlugin } from '#esbuild-plugins/node-modules-polyfill'
import rollupNodePolyFill from "rollup-plugin-node-polyfills";
import { main, resources } from './package.json'
const [nodeModules, devFolder] = normalize(dirname(main)).split(/\/|\\/g)
const devPath = [nodeModules, devFolder].join('/')
const tsconfigPaths = tsconfigPathsPlugin({
projects: [resolve('tsconfig.json')],
})
export default defineConfig({
main: {
plugins: [tsconfigPaths],
build: {
rollupOptions: {
input: {
index: resolve('src/main/index.ts'),
},
output: {
dir: resolve(devPath, 'main'),
},
},
},
},
preload: {
plugins: [tsconfigPaths],
build: {
outDir: resolve(devPath, 'preload'),
},
},
renderer: {
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.platform': JSON.stringify(process.platform),
},
server: {
port: 4927,
},
publicDir: resolve(resources, 'public'),
plugins: [
tsconfigPaths,
reactPlugin(),
],
resolve: {
alias: {
util: 'rollup-plugin-node-polyfills/polyfills/util',
sys: 'util',
stream: 'rollup-plugin-node-polyfills/polyfills/stream',
path: 'rollup-plugin-node-polyfills/polyfills/path',
querystring: 'rollup-plugin-node-polyfills/polyfills/qs',
punycode: 'rollup-plugin-node-polyfills/polyfills/punycode',
url: 'rollup-plugin-node-polyfills/polyfills/url',
string_decoder: 'rollup-plugin-node-polyfills/polyfills/string-decoder',
http: 'rollup-plugin-node-polyfills/polyfills/http',
https: 'rollup-plugin-node-polyfills/polyfills/http',
os: 'rollup-plugin-node-polyfills/polyfills/os',
assert: 'rollup-plugin-node-polyfills/polyfills/assert',
constants: 'rollup-plugin-node-polyfills/polyfills/constants',
_stream_duplex: 'rollup-plugin-node-polyfills/polyfills/readable-stream/duplex',
_stream_passthrough: 'rollup-plugin-node-polyfills/polyfills/readable-stream/passthrough',
_stream_readable: 'rollup-plugin-node-polyfills/polyfills/readable-stream/readable',
_stream_writable: 'rollup-plugin-node-polyfills/polyfills/readable-stream/writable',
_stream_transform: 'rollup-plugin-node-polyfills/polyfills/readable-stream/transform',
timers: 'rollup-plugin-node-polyfills/polyfills/timers',
console: 'rollup-plugin-node-polyfills/polyfills/console',
vm: 'rollup-plugin-node-polyfills/polyfills/vm',
zlib: 'rollup-plugin-node-polyfills/polyfills/zlib',
tty: 'rollup-plugin-node-polyfills/polyfills/tty',
domain: 'rollup-plugin-node-polyfills/polyfills/domain',
events: 'rollup-plugin-node-polyfills/polyfills/events',
buffer: 'rollup-plugin-node-polyfills/polyfills/buffer-es6', // add buffer
process: 'rollup-plugin-node-polyfills/polyfills/process-es6', // add process
}
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: 'globalThis'
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
NodeModulesPolyfillPlugin(),
]
}
},
worker: {
format: "es",
},
build: {
outDir: resolve(devPath, 'renderer'),
rollupOptions: {
plugins: [
injectProcessEnvPlugin({
NODE_ENV: 'production',
platform: process.platform,
}),
rollupNodePolyFill() //this line doesn't works
],
input: {
index: resolve('src/renderer/index.html'),
},
output: {
format: "esm",
dir: resolve(devPath, 'renderer'),
},
},
},
},
})
and the is my project repostitory:
https://github.com/caioregatieri/app-electron
I tried add many polyfills, add twilio import on preload and export to render with
contextBridge.exposeInMainWorld('Twilio', Twilio)
I solved it with:
electron.vite.config.ts
build: {
outDir: resolve(devPath, 'renderer'),
rollupOptions: {
plugins: [
injectProcessEnvPlugin({
NODE_ENV: 'production',
platform: process.platform,
}),
rollupNodePolyFill,
],
},
},
and this:
index.html
<script>
global = globalThis;
</script>

Nuxt ssr asyncData axios request not works on page reload

After 5-6 hours of searching for the solution, I start to give up. I have a project with docker, node & nuxt.I would like to share meta tags on FB and for this, I need SSR && vue-meta and for vue-meta I need asyncData.
it works with different api!
async asyncData({ params, $axios, error }) {
const product = await $axios.$get(`https://api.nuxtjs.dev/posts/1`);
return { product };
},
It is working when i navigate to here with nuxt routing, but if i reload the page (just here) then i get a RuntimeError from the nuxt ssr.
SO THE REAL PROBLEM IS I GET A RuntimeError ON PAGE RELOAD ON LOCALHOST
async asyncData({ params, $axios, error }) {
//axios knows the api
//http://localhost:8080/
const product = await $axios.$get(`products/${params.id}`);
return { product };
},
If I try this with Axios then I get this error:
Cannot read property 'data' of undefined
If I try this with #nuxt/http then I get this error
request to http://localhost:8080/products/some-id failed, reason: connect ECONNREFUSED 127.0.0.1:8080
I think the problem is when I push hard reload on this page, then I cannot make requests on localhost but I don't know why and how to solve it.
my nuxt-config.js
export default {
// Disable server-side rendering (https://go.nuxtjs.dev/ssr-mode)
// ssr: false,
// Global page headers (https://go.nuxtjs.dev/config-head)
head: {
title: '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Josefin+Sans:wght#300;400;600&display=swap' },
]
},
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [
'#/assets/scss/styles.scss',
// '~node_modules/bootstrap/dist/css/bootstrap.css',
// '~node_modules/bootstrap-vue/dist/bootstrap-vue.css',
],
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
plugins: [
'~/plugins/notifier',
'~/plugins/axios',
'~/plugins/dateFilter',
'~/plugins/loading',
],
// Auto import components (https://go.nuxtjs.dev/config-components)
components: true,
// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
buildModules: [
'nuxt-lazysizes', //https://github.com/ivodolenc/nuxt-lazysizes
'#aceforth/nuxt-optimized-images', //https://github.com/juliomrqz/nuxt-optimized-images //only build
],
// Modules (https://go.nuxtjs.dev/config-modules)
modules: [
'#nuxtjs/axios',
'#nuxtjs/auth',
'#nuxtjs/style-resources',
'nuxt-i18n',
'bootstrap-vue/nuxt',
'#nuxt/http',
],
styleResources: {
scss: [
// './assets/scss/*.scss',
'#/assets/scss/_variables.scss',
'#/node_modules/bootstrap/scss/_functions.scss',
'#/node_modules/bootstrap/scss/_variables.scss',
'#/node_modules/bootstrap/scss/mixins/_breakpoints.scss',
]
},
bootstrapVue: {
bootstrapCSS: false,
bootstrapVueCSS: false,
icons: false,
},
axios: {
// baseURL: ``, //built by docker compose from API_PORT && API_HOST variables
},
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/auth/login', method: 'post', propertyName: 'token' },
logout: false,
user: { url: '/auth/user', method: 'get', propertyName: 'user' },
},
}
},
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/admin/products',
},
},
// Build Configuration (https://go.nuxtjs.dev/config-build)
build: {
// babel: {
// compact: true,
// },
},
router: {
extendRoutes(routes, resolve) {
routes.push(
{
name: 'product-edit',
path: '/admin/products/edit/:id',
component: 'pages/admin/products/add.vue',
},
{
name: 'product-image-upload',
path: '/admin/products/product-image-upload/:id',
component: 'pages/admin/products/product-image-upload.vue',
},
{
name: 'gallery-image-upload',
path: '/admin/gallery-image-upload',
component: 'pages/admin/gallery-image-upload.vue',
},
);
}
},
env: {
baseUrl: `${process.env.BASE_URL}`,
imagePath: `${process.env.BASE_URL}:${process.env.API_PORT}/uploads`,
},
publicRuntimeConfig: {
baseUrl: `${process.env.BASE_URL}`,
imagePath: `${process.env.BASE_URL}:${process.env.API_PORT}/uploads`,
},
loading: '~/components/LoadingBar.vue',
i18n: {
locales: [
{ code: 'en', iso: 'en-US', file: 'en.js' },
{ code: 'hu', iso: 'hu-HU', file: 'hu.js' },
{ code: 'de', iso: 'de-DE', file: 'de.js' },
],
defaultLocale: 'en',
lazy: true,
langDir: '/i18n/',
parsePages: false,
vueI18n: {
fallbackLocale: 'en',
},
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
},
seo: false,
vueI18nLoader: true,
strategy: 'no_prefix',
},
lazySizes: {
extendAssetUrls: {
img: 'data-src',
source: 'data-srcset',
// Component with custom props
AppImage: ['source-md-url', 'image-url'],
},
},
optimizedImages: {
inlineImageLimit: 1000,
handleImages: ['jpeg', 'png', 'svg', 'webp', 'gif'],
optimizeImages: false,
optimizeImagesInDev: false,
defaultImageLoader: 'img-loader',
mozjpeg: {
quality: 80,
},
optipng: {
optimizationLevel: 3,
},
pngquant: false,
gifsicle: {
interlaced: true,
optimizationLevel: 3,
},
svgo: {
// enable/disable svgo plugins here
},
webp: {
preset: 'default',
quality: 75,
},
},
};
my docker-compose.yml
version: '3'
services:
server:
build:
context: ./server
env_file: .env
expose:
- $SERVER_PORT
ports:
- $SERVER_PORT:$SERVER_PORT
volumes:
- ./server:/usr/app
- /usr/app/node_modules
client:
build:
context: ./client
env_file: .env
environment:
NUXT_HOST: 0.0.0.0
NUXT_PORT: $CLIENT_PORT
API_HOST: 0.0.0.0
API_PORT: $SERVER_PORT
BASE_URL: $BASE_URL
volumes:
- ./client:/usr/app
- /usr/app/node_modules
expose:
- $CLIENT_PORT
ports:
- $CLIENT_PORT:$CLIENT_PORT
Update: if I start my nuxt project without Docker then everything works fine but this is not a solution for me :D
I have solved my question. I had to use nginx proxy as a container and some nuxt config.
// https://axios.nuxtjs.org/options/
privateRuntimeConfig: {
axios: {
baseURL: 'http://nginx/api' // name of the docker proxy
}
},

post request not working in express app deployed in kubernetes locally with minikube

when I request post handler in the express app it returns Cannot POST / but the post handler is defined in there. When is run this app through docker-compose it worlds perfectly but not in Kubernetes cluster using minikube. Here is the express app code.
const keys = require('./keys');
// Express App Setup
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(bodyParser.json());
// Postgres Client Setup
const { Pool, Client } = require('pg');
const pgClient = new Pool({
user: keys.pgUser,
host: keys.pgHost,
database: keys.pgDatabase,
password: keys.pgPassword,
port: keys.pgPort
});
pgClient.on('error', () => console.log('Lost PG connection'));
pgClient
.query('CREATE TABLE IF NOT EXISTS values (number INT)')
.catch(err => console.log(err));
// Redis Client Setup
const redis = require('redis');
const redisClient = redis.createClient({
host: keys.redisHost,
port: keys.redisPort,
retry_strategy: () => 1000
});
const redisPublisher = redisClient.duplicate();
// Express route handlers
app.get('/', (req, res) => {
res.send('Hi');
});
app.get('/values/all', async (req, res) => {
const {rows} = await pgClient.query('SELECT * from values');
console.log('DATA IN POSTGRES', rows)
res.send(rows);
});
app.get('/values/current', async (req, res) => {
redisClient.hgetall('values', (err, values) => {
res.send(values);
});
});
app.post('/data', (req,res) => {
res.send(req.body.data)
})
app.post('/values', (req, res) => {
console.log("FORM DATA", req.body)
const index = req.body.index;
if (parseInt(index) > 40) {
return res.status(422).send('Index too high');
}
redisClient.hset('values', index, 'Nothing yet!');
redisPublisher.publish('insert', index);
pgClient.query('INSERT INTO values(number) VALUES($1)', [index], (err,ress) => {
if(err){
console.log("PG ERROR ON INSERT")
} else {
console.log('PG DATA', ress.rows[0])
res.send({ working: true });
}
});
});
app.listen(5000, err => {
console.log('Listening');
});
Here is the server deployment config
apiVersion: apps/v1
kind: Deployment
metadata:
name: server-deployment
spec:
replicas: 3
selector:
matchLabels:
component: server
template:
metadata:
labels:
component: server
spec:
containers:
- name: server
image: rajneesh4736/multi-server:v4.0.3
ports:
- containerPort: 5000
env:
- name: REDIS_HOST
value: redis-cluster-ip-service
- name: REDIS_PORT
value: "6379"
- name: PGUSER
value: postgres
- name: PGHOST
value: postgres-cluster-ip-service
- name: PGPORT
value: "5432"
- name: PGDATABASE
value: postgres
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: pgpassword
key: PGPASSWORD
Here is the server cluster IP config
apiVersion: v1
kind: Service
metadata:
name: server-cluster-ip-service
spec:
type: ClusterIP
selector:
component: server
ports:
- port: 5000
targetPort: 5000

AspNet Core doesn't run in Production on docker ["ASPNETCORE_ENVIRONMENT=Production"]

I can't seem to get my aspnet core app to run in docker using ASPNETCORE_ENVIRONMENT=Production, but it works when I change the environment back to Development. In production I can't browse to localhost:port but works okay in dev. My compose file is as below:
version: '3.4'
services:
web:
container_name: aspdemo
image: user/aspdemo
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:22973;
- 'Logging:LogLevel:Default=Debug'
- 'Logging:LogLevel:System=Information'
- 'Logging:LogLevel:Microsoft=Information'
- 'ConnectionStrings:DefaultConnection=Server=dbserver;Database=demoDb;User=sa;Password=MyStrong!Pass;'
ports:
- "22973:22973"
networks:
default: {}
be:
aliases:
- tokenserver
networks:
be:
external:
name: backend
AppSettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=dbserver;Database=demoDb;User=sa;Password=MyStrong!Pass;"
},
"Portal_IP": "http://197.254.91.254",
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
AppSettings.Development.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=dbserver;Database=demoDb;User=sa;Password=MyStrong!Pass;"
},
"Portal_IP": "http://localhost",
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
I couldn't see your AppSettings.Production.json. If you want to add custom configurations, you can add different appSettings jsons. That is your config file name should be AppSettings.Production.json. Because you have changed your environment to production.
{
"ConnectionStrings": {
"DefaultConnection": "Server=dbserver;Database=demoDb;User=sa;Password=MyStrong!Pass;"
},
"Portal_IP": "http://localhost",
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
Look for docker-compose.override.yml and override the
environment:
- ASPNETCORE_ENVIRONMENT=Production
To me, the only place I can control which environment you want to deploy.
I have tried to delete docker-compose.override.yml then control everything in docker-compose.yml but it does not work. Looks like we have a bug then?
Austin

jenkins kubernetes-plugin set idletimeout in pipeline

How to set Time in minutes to retain slave when idle and Max number of instances in pipeline when config podTemplate ?
I see these two config options in System->Could->kubernetes. But I use pipeline and I didn't figure it out how to set them.
Now My pipeline looks like below.
podTemplate(label: 'docker-go',
containers: [
containerTemplate(
name: 'jnlp',
image: 'docker.mydomain.com/library/jnlp-slave:2.62',
command: '',
args: '${computer.jnlpmac} ${computer.name}',
),
containerTemplate(name: 'docker', image: 'docker.mydomain.com/library/docker:1.12.6', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'golang', image: 'docker.mydomain.com/library/golang:1.8.3', ttyEnabled: true, command: '')
],
volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
def image_tag = "docker.mydomain.com/deploy-demo/demo-go:v0.1"
def workdir = "/go/src/demo-go"
node('docker-go') {
stage('setup') {
}
stage('clone') {
}
stage('compile') {
}
stage('build and push image') {
}
}
}
Ok, I figuire it out
Add these two.
idleMinutes: 10
instanceCap: 10
podTemplate(label: 'docker-go',
containers: [
containerTemplate(
name: 'jnlp',
image: 'docker.mydomain.com/library/jnlp-slave:2.62',
command: '',
args: '${computer.jnlpmac} ${computer.name}',
),
containerTemplate(name: 'docker', image: 'docker.mydomain.com/library/docker:1.12.6', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'golang', image: 'docker.mydomain.com/library/golang:1.8.3', ttyEnabled: true, command: '')
],
volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')],
idleMinutes: 10
instanceCap: 10
) {
def image_tag = "docker.mydomain.com/deploy-demo/demo-go:v0.1"
def workdir = "/go/src/demo-go"
node('docker-go') {
stage('setup') {
}
stage('clone') {
}
stage('compile') {
}
stage('build and push image') {
}
}
}

Resources