Skip to content

Instantly share code, notes, and snippets.

@peter-nikitin
Last active January 20, 2023 11:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peter-nikitin/535a1ee1ef8adf1967f510564e9c02af to your computer and use it in GitHub Desktop.
Save peter-nikitin/535a1ee1ef8adf1967f510564e9c02af to your computer and use it in GitHub Desktop.
The article about deploy
export const getAdressessOfPods = async (req: Request, res: Response, next: NextFunction) => {
// Получаем из переменных среды имена сервисов и сортируем их,
// чтобы опрашивать в нужной последовательности.
const headlessServices = getSortedHeadlessNames(Object.keys(process.env));
const reachedModules = [];
const headlessServicePromises =
headlessServices.length === 0
? [getAddressesOfMcf()]
: headlessServices.map((service) => getAddressesOfMcf(process.env[service]));
const modules = await Promise.allSettled([...headlessServicePromises]);
for (const module of modules) {
if (module.status === 'rejected') {
logMessage(`can't get mcfAddressArray; reason: ${module.reason}`, {
host: req.hostname,
});
continue;
}
reachedModules.push(...module.value);
}
if (reachedModules.length === 0) {
const errorMessage = `no headless services found. headlessServices: ${headlessServices}`;
logException(new Error(errorMessage));
res.status(500);
res.send('no modules found');
return;
}
// Складываем полученные адреса в locals,
// чтобы получить их в другой middleware.
res.locals[RES_LOCALS.mcfAddresses] = reachedModules;
next();
};
const createRegExForReplace = (MCFName: string) =>
new RegExp(`\\/\\*!\\s@mcf\\sstart\\s${MCFName}\\s\\*\\/.+\\/*!\\s@mcf\\send\\s${MCFName}\\s\\*\\/`);
export const buildNewInitialJs = ({ modulesArray }: BuildNewInitialJsArgs) => {
let newInitial = initEmptyModulesList;
if (modulesArray.length === 0) {
throw new Error('No MCF array are provided');
}
modulesArray.forEach((moduleCode) => {
const safeNoduleCode = deleteNewLines(moduleCode);
const name = REGEX_FOR_FIND_MCF_NAME.exec(safeNoduleCode);
const moduleName = name?.groups?.['MCF_NAME'];
if (!moduleName) {
logException(INVALID_REMOTE_ENTRY_ERROR);
return;
}
const isMcfNameExistInInitialJs = newInitial.search(createRegExForReplace(moduleName));
if (isMcfNameExistInInitialJs === -1) {
newInitial = newInitial.concat(stub, safeNoduleCode, stub, initModule(moduleName));
} else {
newInitial = newInitial.replace(createRegExForReplace(moduleName), safeNoduleCode);
}
});
newInitial = newInitial.concat(stub, loadModules);
return pasteNewLines(newInitial);
};
export const handleInitialJs = async (_: Request, res: Response) => {
res.type('.js');
try {
// Получаем файлы с метаданными из каждого пода.
const modulesArray = await getRemoteEntries(res.locals[RES_LOCALS.mcfAddresses]);
// Собираем массив с метаданными в один файл и отдаем его пользователю.
const newInitialJs = buildNewInitialJs({
modulesArray,
});
res.send(newInitialJs);
} catch (error) {
Sentry.captureException(error);
res.status(500).send("Can't build initial.js");
}
};
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.name }}-deployment-{{ .Values.environment }}
spec:
replicas: {{ .Values.services.replicas }}
selector:
matchLabels:
product: {{ .Values.name }}
# Помечаем, что этот под содержит в себе код микрофронтенда.
microfrontend-pod: {{ .Values.isMicrofrontendPod | quote }}
template:
metadata:
labels:
product: {{ .Values.name }}
microfrontend-pod: {{ .Values.isMicrofrontendPod | quote }}
deploy-environment: {{ .Values.environment }}
spec:
imagePullSecrets:
- name: image-pull-{{ .Values.environment }}
containers:
- name: {{ .Values.name }}-pod
image: "image-repo/{{ .Values.name }}:{{ $.Values.packageVersion }}"
imagePullPolicy: Always
resources:
requests:
cpu: {{ .Values.services.resources.requests.cpu }}
memory: {{ .Values.services.resources.requests.memory }}
limits:
cpu: {{ .Values.services.resources.limits.cpu }}
memory: {{ .Values.services.resources.limits.memory }}
ports:
- containerPort: 8080
tolerations:
- key: dedicated
operator: Equal
value: mindbox-worker
effect: NoSchedule
- key: dedicated
operator: Equal
value: mindbox-worker
effect: PreferNoSchedule
---
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.name }}-service-{{ .Values.environment }}
spec:
selector:
product: {{ .Values.name }}
microfrontend-pod: {{ .Values.isMicrofrontendPod | quote }}
deploy-environment: {{ .Values.environment }}
ports:
- name: main
protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: {{ .Values.name }}-ingressroute-{{ .Values.environment }}-index-html
labels:
mindbox/traefik: common
spec:
entryPoints:
- websecure
routes:
# Собираем URL, по которому будет отвечать под.
# Нам нужно, чтобы он отвечал по всем запросам по определенному URL
# и заголовку "environment", который проставляется в HAProxy.
- match: HostRegexp(`{tenant:.*}.{{ .Values.host }}`) && (PathPrefix(`/{{ .Values.namespace }}`)) && Headers(`environment`, `{{ .Values.environment }}`)
kind: Rule
priority: 50
services:
- port: 8080
name: frontend-initial-builder-service-{{ .Values.environment }}
tls:
options:
name: agrade-tls-options
namespace: traefik-common
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: {{ .Values.name }}-ingressroute-{{ .Values.environment }}
labels:
mindbox/traefik: common
spec:
entryPoints:
- websecure
routes:
# Собираем URL, по которому будет отвечать под.
# Нам нужно, чтобы он отвечал по всем запросам по определенному URL
# и заголовку "environment", который проставляется в HAProxy.
- match: HostRegexp(`{tenant:.*}.{{ .Values.host }}`) && PathPrefix(`/v2_static/{{ regexReplaceAll "-" .Values.name "_"}}/`) && Headers(`environment`, `{{ .Values.environment }}`)
kind: Rule
priority: 50
services:
- name: {{ .Values.name }}-service-{{ .Values.environment }}
port: 8080
tls:
options:
name: agrade-tls-options
namespace: traefik-common
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment