init
This commit is contained in:
@@ -0,0 +1 @@
|
||||
charts/
|
||||
@@ -0,0 +1,24 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.wait
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v2
|
||||
name: hrbox
|
||||
description: Simplified HRBox application Helm chart
|
||||
type: application
|
||||
|
||||
# Версия самого чарта. Увеличивается при каждом изменении чарта
|
||||
version: 1.0.0
|
||||
|
||||
# Версия приложения, которое деплоится. Не обязательно увеличивать при изменении чарта
|
||||
appVersion: "1.0.0"
|
||||
|
||||
# Ключевые слова для поиска
|
||||
keywords:
|
||||
- hrbox
|
||||
- hr
|
||||
- application
|
||||
|
||||
# Домашняя страница проекта
|
||||
home: https://hrbox.io
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-nats-config
|
||||
data:
|
||||
nats.conf: |
|
||||
# PID file shared with configuration reloader.
|
||||
pid_file: "/var/run/nats/nats.pid"
|
||||
|
||||
###############
|
||||
# #
|
||||
# Monitoring #
|
||||
# #
|
||||
###############
|
||||
http: 8222
|
||||
server_name: $POD_NAME
|
||||
|
||||
{{- if .Values.nats.jetstream.enabled }}
|
||||
###################################
|
||||
# #
|
||||
# NATS JetStream #
|
||||
# #
|
||||
###################################
|
||||
jetstream {
|
||||
{{- if .Values.nats.jetstream.memStorage.enabled }}
|
||||
max_mem: {{ .Values.nats.jetstream.memStorage.size }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.nats.jetstream.fileStorage.enabled }}
|
||||
store_dir: {{ .Values.nats.jetstream.fileStorage.storageDirectory }}
|
||||
max_file: {{ .Values.nats.jetstream.fileStorage.size }}
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.nats.cluster.enabled }}
|
||||
###################################
|
||||
# #
|
||||
# NATS Full Mesh Clustering Setup #
|
||||
# #
|
||||
###################################
|
||||
cluster {
|
||||
port: 6222
|
||||
name: {{ .Chart.Name }}-nats-cluster
|
||||
|
||||
routes = [
|
||||
{{- range $i := until (int .Values.nats.cluster.replicas) }}
|
||||
nats://{{ $.Chart.Name }}-nats-{{ $i }}.{{ $.Chart.Name }}-nats.{{ $.Release.Namespace }}.svc.cluster.local:6222,
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
cluster_advertise: $CLUSTER_ADVERTISE
|
||||
connect_retries: 120
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
lame_duck_duration: 120s
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: web-configuration
|
||||
data:
|
||||
nginx.conf: |
|
||||
user www-data;
|
||||
worker_processes 6;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 10000;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
|
||||
##
|
||||
# Basic Settings
|
||||
##
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 0;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
limit_conn_zone $binary_remote_addr zone=addr:10m;
|
||||
server_names_hash_bucket_size 64;
|
||||
server_name_in_redirect off;
|
||||
|
||||
fastcgi_buffer_size 256k;
|
||||
fastcgi_buffers 4 256k;
|
||||
|
||||
client_body_buffer_size 1024k;
|
||||
client_max_body_size 20m;
|
||||
|
||||
client_header_buffer_size 1024k;
|
||||
large_client_header_buffers 16 1024k;
|
||||
|
||||
|
||||
default_type application/octet-stream;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
##
|
||||
# SSL Settings
|
||||
##
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
rewrite_log on;
|
||||
|
||||
##
|
||||
# Gzip Settings
|
||||
##
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
server {
|
||||
listen 80 default;
|
||||
server_name _ ;
|
||||
root /app/web;
|
||||
index index.php;
|
||||
|
||||
keepalive_timeout 70;
|
||||
client_body_temp_path /nginx-tmp 1 2;
|
||||
client_body_timeout 22s;
|
||||
client_header_timeout 22s;
|
||||
|
||||
limit_conn addr 10000;
|
||||
|
||||
location ~ /\.(git) {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Permissions-Policy "browsing-topics=()" always;
|
||||
|
||||
# Redirect everything that isn't a real file to index.php
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
|
||||
# uncomment to avoid processing of calls to non-existing static files by Yii
|
||||
#location ~* \.(js|css|png|jpg|gif|ico|pdf|mov|fla|zip|rar)$ {
|
||||
location ~* \.(js|css|png|jpg|gif|ico)$ {
|
||||
|
||||
expires 30d;
|
||||
add_header Vary Accept-Encoding;
|
||||
add_header Pragma "public";
|
||||
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
|
||||
access_log off;
|
||||
tcp_nodelay off;
|
||||
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
|
||||
open_file_cache max=3000 inactive=120s;
|
||||
open_file_cache_valid 45s;
|
||||
open_file_cache_min_uses 2;
|
||||
open_file_cache_errors off;
|
||||
}
|
||||
|
||||
#error_page 404 /404.html;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
fastcgi_pass localhost:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_read_timeout 20s;
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 60s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: job-scripts
|
||||
data:
|
||||
wait.sh: |
|
||||
until pg_isready -h $POSTGRES_VHOST -p $POSTGRES_PORT -U $POSTGRES_USER
|
||||
do
|
||||
echo "Waiting for postgres"
|
||||
sleep 2;
|
||||
done
|
||||
@@ -0,0 +1,42 @@
|
||||
{{- if .Values.dragonfly.enabled }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-dragonfly
|
||||
spec:
|
||||
revisionHistoryLimit: 3
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
component: {{ .Chart.Name }}-dragonfly
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
component: {{ .Chart.Name }}-dragonfly
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: dragonfly
|
||||
image: cr.yandex/crpnn6fi85p3dauha6nc/dragonflydb:1.15.1
|
||||
ports:
|
||||
- name: dragonfly
|
||||
containerPort: 6379
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 6379
|
||||
initialDelaySeconds: 30
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-dragonfly
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
component: {{ .Chart.Name }}-dragonfly
|
||||
ports:
|
||||
- port: 6379
|
||||
{{- end }}
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-nats
|
||||
labels:
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
replicas: {{ .Values.nats.replicas }}
|
||||
serviceName: {{ .Chart.Name }}-nats
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: {{ .Chart.Name }}-nats-config
|
||||
- name: pid
|
||||
emptyDir: {}
|
||||
shareProcessNamespace: true
|
||||
terminationGracePeriodSeconds: {{ .Values.nats.terminationGracePeriodSeconds }}
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: nats
|
||||
image: {{ .Values.nats.image }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 4222
|
||||
name: client
|
||||
- containerPort: 6222
|
||||
name: cluster
|
||||
- containerPort: 8222
|
||||
name: monitor
|
||||
- containerPort: 7777
|
||||
name: metrics
|
||||
command:
|
||||
- "nats-server"
|
||||
- "--config"
|
||||
- "/etc/nats-config/nats.conf"
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: SERVER_NAME
|
||||
value: $(POD_NAME)
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: CLUSTER_ADVERTISE
|
||||
value: $(POD_NAME).{{ .Chart.Name }}-nats.$(POD_NAMESPACE).svc.cluster.local
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/nats-config
|
||||
- name: pid
|
||||
mountPath: /var/run/nats
|
||||
{{- if .Values.nats.jetstream.fileStorage.enabled }}
|
||||
- name: {{ .Chart.Name }}-nats-js-pvc
|
||||
mountPath: {{ .Values.nats.jetstream.fileStorage.storageDirectory }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 8222
|
||||
initialDelaySeconds: 10
|
||||
timeoutSeconds: 5
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 8222
|
||||
initialDelaySeconds: 10
|
||||
timeoutSeconds: 5
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- "nats-server -sl=ldm=/var/run/nats/nats.pid && /bin/sleep 120"
|
||||
|
||||
{{- if .Values.nats.reloader.enabled }}
|
||||
- name: reloader
|
||||
image: natsio/nats-server-config-reloader:0.6.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- "nats-server-config-reloader"
|
||||
- "-pid"
|
||||
- "/var/run/nats/nats.pid"
|
||||
- "-config"
|
||||
- "/etc/nats-config/nats.conf"
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/nats-config
|
||||
- name: pid
|
||||
mountPath: /var/run/nats
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.nats.jetstream.fileStorage.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: {{ .Chart.Name }}-nats-js-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.nats.jetstream.fileStorage.size }}
|
||||
{{- if .Values.nats.jetstream.fileStorage.storageClassName }}
|
||||
storageClassName: {{ .Values.nats.jetstream.fileStorage.storageClassName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-nats
|
||||
labels:
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: client
|
||||
port: 4222
|
||||
- name: cluster
|
||||
port: 6222
|
||||
- name: monitor
|
||||
port: 8222
|
||||
- name: metrics
|
||||
port: 7777
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-web
|
||||
labels:
|
||||
app: web
|
||||
spec:
|
||||
minReadySeconds: 5
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
replicas: {{ .Values.app.replicas.web }}
|
||||
selector:
|
||||
matchLabels:
|
||||
service: {{ .Chart.Name }}-web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: {{ .Chart.Name }}-web
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
prometheus.io/port: '9253'
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: fpm
|
||||
image: {{ .Values.app.image }}
|
||||
command: ["/usr/local/sbin/php-fpm", "-c", "/usr/local/etc/php-fpm"]
|
||||
ports:
|
||||
- name: fpm
|
||||
containerPort: 9000
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
{{- include "app_resources" . | indent 10 }}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- '-c'
|
||||
- sleep 5 && kill -SIGQUIT 1
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 9000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 9000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
- name: nginx
|
||||
image: {{ .Values.app.image }}
|
||||
command: ["/usr/sbin/nginx", "-g", "daemon off;"]
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
{{- include "nginx_resources" . | indent 10}}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- '-c'
|
||||
- sleep 5 && /usr/sbin/nginx -s quit
|
||||
volumeMounts:
|
||||
- name: configs
|
||||
mountPath: /etc/nginx/nginx.conf
|
||||
subPath: nginx.conf
|
||||
- name: phpfpm-exporter
|
||||
image: cr.yandex/crpnn6fi85p3dauha6nc/php-fpm_exporter:latest
|
||||
ports:
|
||||
- containerPort: 9253
|
||||
env:
|
||||
- name: PHP_FPM_SCRAPE_URI
|
||||
value: "tcp://127.0.0.1:9000/hrbox-fpm-status"
|
||||
volumes:
|
||||
- name: configs
|
||||
configMap:
|
||||
name: web-configuration
|
||||
defaultMode: 420
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-web
|
||||
spec:
|
||||
selector:
|
||||
service: {{ .Chart.Name }}-web
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-websocket
|
||||
labels:
|
||||
app: websocket
|
||||
spec:
|
||||
minReadySeconds: 5
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
replicas: {{ .Values.app.replicas.websocket }}
|
||||
selector:
|
||||
matchLabels:
|
||||
service: {{ .Chart.Name }}-websocket
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: {{ .Chart.Name }}-websocket
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
prometheus.io/port: '9797'
|
||||
prometheus.io/path: "/info"
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: websocket
|
||||
{{- include "websocket_resources" . | indent 10}}
|
||||
image: cr.yandex/crphnph9c2s776j32sjd/hrbox-websocket:2.1
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-websocket
|
||||
spec:
|
||||
selector:
|
||||
service: {{ .Chart.Name }}-websocket
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 9797
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-worker
|
||||
labels:
|
||||
app: worker
|
||||
spec:
|
||||
minReadySeconds: 5
|
||||
strategy:
|
||||
type: Recreate
|
||||
replicas: {{ .Values.app.replicas.worker }}
|
||||
selector:
|
||||
matchLabels:
|
||||
service: {{ .Chart.Name }}-worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: {{ .Chart.Name }}-worker
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
prometheus.io/port: '9253'
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: worker
|
||||
image: {{ .Values.app.image }}
|
||||
command: ["hrbox-worker"]
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
{{- include "worker_resources" . | indent 10}}
|
||||
terminationGracePeriodSeconds: 600
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-conductor
|
||||
labels:
|
||||
app: conductor
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
service: {{ .Chart.Name }}-conductor
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: {{ .Chart.Name }}-conductor
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- conductor
|
||||
topologyKey: kubernetes.io/hostname
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: conductor
|
||||
{{- include "conductor_resources" . | indent 10 }}
|
||||
image: cr.yandex/crphnph9c2s776j32sjd/hrbox-conductor:2.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-geonames
|
||||
labels:
|
||||
app: geonames
|
||||
spec:
|
||||
minReadySeconds: 5
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
replicas: {{ .Values.app.replicas.geonames }}
|
||||
selector:
|
||||
matchLabels:
|
||||
service: {{ .Chart.Name }}-geonames
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: {{ .Chart.Name }}-geonames
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
prometheus.io/port: '9797'
|
||||
prometheus.io/path: "/info"
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: geonames
|
||||
{{- include "geonames_resources" . | indent 10}}
|
||||
image: cr.yandex/crphnph9c2s776j32sjd/hrbox-geonames:3.1
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-geonames
|
||||
spec:
|
||||
selector:
|
||||
service: {{ .Chart.Name }}-geonames
|
||||
ports:
|
||||
- name: http
|
||||
port: 8181
|
||||
targetPort: 8181
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: {{ .Values.ingress.className }}
|
||||
nginx.org/websocket-services: {{ .Chart.Name }}-websocket
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
proxy_set_header X-Forwarded-For "$remote_addr, $server_addr";
|
||||
proxy_set_header X-Forwarded-Port $pass_port;
|
||||
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host | quote }} # something.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /ws/
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ .Chart.Name }}-websocket
|
||||
port:
|
||||
number: 80
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ .Chart.Name }}-web
|
||||
port:
|
||||
number: 80
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.ingress.host | quote }}
|
||||
secretName: {{ .Values.ingress.tls.secretName | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-migrate
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
|
||||
"helm.sh/hook-weight": "10"
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 100
|
||||
template:
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
initContainers:
|
||||
- name: wait-postgres
|
||||
image: postgres:14-alpine
|
||||
command:
|
||||
- bash
|
||||
- /wait.sh
|
||||
volumeMounts:
|
||||
- name: configs
|
||||
mountPath: /wait.sh
|
||||
subPath: wait.sh
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
containers:
|
||||
- name: run-migrations
|
||||
image: {{ .Values.app.image }}
|
||||
command: ["php", "yii", "migrate", "--interactive=0"]
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
{{- include "jobs_resources" . | indent 10 }}
|
||||
volumes:
|
||||
- name: configs
|
||||
configMap:
|
||||
name: job-scripts
|
||||
defaultMode: 420
|
||||
restartPolicy: OnFailure
|
||||
terminationGracePeriodSeconds: 5
|
||||
backoffLimit: 6
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ .Chart.Name }}-update-cluster
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
|
||||
"helm.sh/hook-weight": "20"
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regsecret
|
||||
containers:
|
||||
- name: run-update
|
||||
image: {{ .Values.app.image }}
|
||||
command: [ "php", "yii", "util/update-cluster" ]
|
||||
env:
|
||||
{{- include "envs_all" . | indent 12 }}
|
||||
{{- include "jobs_resources" . | indent 10 }}
|
||||
restartPolicy: OnFailure
|
||||
terminationGracePeriodSeconds: 5
|
||||
backoffLimit: 6
|
||||
@@ -0,0 +1,197 @@
|
||||
{{- define "envs_all" }}
|
||||
# Основные настройки приложения
|
||||
- name: INSTANCE_NAME
|
||||
value: {{ .Values.app.instanceName | quote }}
|
||||
- name: DEFAULT_TENANT_HOSTNAME
|
||||
value: {{ .Values.app.defaultTenantHostname | quote }}
|
||||
- name: APP_ENV
|
||||
value: "prod"
|
||||
- name: YII_DEBUG
|
||||
value: {{ .Values.app.debug | quote }}
|
||||
- name: YII_TRACE_LEVEL
|
||||
value: "0"
|
||||
- name: APP_COOKIE_VALIDATION_KEY
|
||||
value: {{ .Values.secrets.cookieValidationKey | quote }}
|
||||
- name: APP_ENCRYPTION_KEY
|
||||
value: {{ .Values.secrets.encryptionKey | quote }}
|
||||
- name: APP_PORT
|
||||
value: "80"
|
||||
- name: AUTH_HOST
|
||||
value: {{ .Values.app.authHost | quote }}
|
||||
- name: LAUNCHPAD_TOPICS
|
||||
value: {{ .Values.app.launchpad.topics | quote }}
|
||||
- name: SMS_SENDER_NAME
|
||||
value: "HRBOX"
|
||||
|
||||
# NATS
|
||||
- name: BROKER
|
||||
value: "nats"
|
||||
- name: NATS_URL
|
||||
value: {{ .Values.app.nats.url | quote }}
|
||||
|
||||
# Sentry (опционально)
|
||||
{{- if .Values.app.sentry.dsn }}
|
||||
- name: SENTRY_DSN
|
||||
value: {{ .Values.app.sentry.dsn | quote }}
|
||||
- name: SENTRY_DSN_LAUNCHPAD
|
||||
value: {{ .Values.app.sentry.dsn | quote }}
|
||||
- name: SENTRY_DSN_CONDUCTOR
|
||||
value: {{ .Values.app.sentry.dsn | quote }}
|
||||
- name: SENTRY_ENVIRONMENT
|
||||
value: {{ .Values.app.sentry.environment | quote }}
|
||||
- name: SENTRY_RELEASE
|
||||
value: {{ .Values.app.image | quote }}
|
||||
{{- end }}
|
||||
|
||||
# PostgreSQL
|
||||
- name: POSTGRES_VHOST
|
||||
value: {{ .Values.app.postgres.host | quote }}
|
||||
- name: POSTGRES_PORT
|
||||
value: {{ .Values.app.postgres.port | quote }}
|
||||
- name: POSTGRES_DB
|
||||
value: {{ .Values.app.postgres.database | quote }}
|
||||
- name: POSTGRES_USER
|
||||
value: {{ .Values.app.postgres.user | quote }}
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: {{ .Values.app.postgres.password | quote }}
|
||||
- name: POSTGRES_CITUS
|
||||
value: {{ .Values.app.postgres.citus | quote }}
|
||||
|
||||
# Redis
|
||||
- name: REDIS_HOST
|
||||
value: {{ .Values.app.redis.host | quote }}
|
||||
- name: REDIS_PORT
|
||||
value: {{ .Values.app.redis.port | quote }}
|
||||
- name: REDIS_CONNECTION
|
||||
value: {{ printf "tcp://%s:%s" .Values.app.redis.host .Values.app.redis.port | quote }}
|
||||
|
||||
# Yandex API (опционально)
|
||||
{{- if .Values.app.yandex.clientId }}
|
||||
- name: YANDEX_CLIENT_ID
|
||||
value: {{ .Values.app.yandex.clientId | quote }}
|
||||
- name: YANDEX_CLIENT_PASSWORD
|
||||
value: {{ .Values.app.yandex.clientPassword | quote }}
|
||||
{{- end }}
|
||||
|
||||
# Slack (опционально)
|
||||
{{- if .Values.app.slack.clientId }}
|
||||
- name: SLACK_APP_CLIENT_ID
|
||||
value: {{ .Values.app.slack.clientId | quote }}
|
||||
- name: SLACK_APP_CLIENT_SECRET
|
||||
value: {{ .Values.app.slack.clientSecret | quote }}
|
||||
- name: SLACK_APP_VERIFICATION_TOKEN
|
||||
value: {{ .Values.app.slack.verificationToken | quote }}
|
||||
{{- end }}
|
||||
|
||||
# Email
|
||||
- name: SENDER_ENV
|
||||
value: "PROD"
|
||||
- name: SENDER_DEV_EMAIL
|
||||
value: ""
|
||||
- name: SENDGRID_API_KEY
|
||||
value: ""
|
||||
|
||||
# SMTP
|
||||
- name: SMTP_USERNAME
|
||||
value: {{ .Values.app.smtp.user | quote }}
|
||||
- name: SMTP_PASSWORD
|
||||
value: {{ .Values.app.smtp.password | quote }}
|
||||
- name: SMTP_HOST
|
||||
value: {{ .Values.app.smtp.host | quote }}
|
||||
- name: SMTP_PORT
|
||||
value: {{ .Values.app.smtp.port | quote }}
|
||||
- name: SMTP_FROM
|
||||
value: {{ .Values.app.smtp.from | quote }}
|
||||
- name: SMTP_FROM_HOST
|
||||
value: {{ .Values.app.smtp.fromHost | quote }}
|
||||
- name: SMTP_SECURITY_TYPE
|
||||
value: {{ .Values.app.smtp.securityType | quote }}
|
||||
- name: SMTP_SSL_ALLOW_SELF_SIGNED
|
||||
value: {{ .Values.app.smtp.sslAllowSelfSigned | quote }}
|
||||
- name: SMTP_SSL_VERIFY_PEER
|
||||
value: {{ .Values.app.smtp.sslVerifyPeer | quote }}
|
||||
|
||||
# S3
|
||||
- name: S3_ENDPOINT
|
||||
value: {{ .Values.app.s3.endpoint | quote }}
|
||||
- name: S3_BUCKET
|
||||
value: {{ .Values.app.s3.bucket | quote }}
|
||||
- name: S3_KEY
|
||||
value: {{ .Values.app.s3.key | quote }}
|
||||
- name: S3_SECRET
|
||||
value: {{ .Values.app.s3.secret | quote }}
|
||||
- name: S3_PREFIX
|
||||
value: {{ .Values.app.s3.prefix | quote }}
|
||||
- name: S3_REGION
|
||||
value: {{ .Values.app.s3.region | quote }}
|
||||
- name: S3_VERSION
|
||||
value: {{ .Values.app.s3.version | quote }}
|
||||
- name: S3_PATH_STYLE
|
||||
value: {{ .Values.app.s3.pathStyle | quote }}
|
||||
- name: S3_MULTIPART
|
||||
value: {{ .Values.app.s3.multipart | quote }}
|
||||
|
||||
# Hub
|
||||
- name: HUB_URL
|
||||
value: {{ .Values.app.hub.url | quote }}
|
||||
- name: HUB_TOKEN
|
||||
value: {{ .Values.app.hub.token | quote }}
|
||||
|
||||
# Geonames
|
||||
- name: GEONAMES_URL
|
||||
value: {{ .Values.app.geonames.url | quote }}
|
||||
|
||||
# Статические переменные
|
||||
- name: CONDUCTOR_TOPIC_CONDUCTOR
|
||||
value: "conductor"
|
||||
- name: CONDUCTOR_TOPIC_LAUNCHER
|
||||
value: "launcher"
|
||||
- name: GOOGLE_CLIENT_ID
|
||||
value: "692956564858-ccapt35khk7tmadl17b3879ht2cropp6.apps.googleusercontent.com"
|
||||
- name: GOOGLE_CLIENT_SECRET
|
||||
value: "nW4pl4YsVWAR371gMRStW9qg"
|
||||
- name: FORCE_HTTPS
|
||||
value: "true"
|
||||
- name: GLAGOL_PARTNER_ID
|
||||
value: "ab230ee1-6946-43b9-8kfa-447beb8348b0"
|
||||
- name: GLAGOL_API_URL
|
||||
value: "https://api.glagol.online/glagol-api"
|
||||
- name: LDAPTLS_REQCERT
|
||||
value: "never"
|
||||
- name: IFRAME_FULL_ACCESS
|
||||
value: "false"
|
||||
|
||||
# Метаданные пода
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
- name: NODE_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.nodeName
|
||||
|
||||
# AI (опционально)
|
||||
{{- if .Values.app.ai.yandex.folderId }}
|
||||
- name: YANDEX_CLOUD_AI_FOLDER_ID
|
||||
value: {{ .Values.app.ai.yandex.folderId | quote }}
|
||||
- name: YANDEX_CLOUD_AI_API_KEY
|
||||
value: {{ .Values.app.ai.yandex.apiKey | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.ai.openai.apiKey }}
|
||||
- name: OPENAI_API_KEY
|
||||
value: {{ .Values.app.ai.openai.apiKey | quote }}
|
||||
- name: OPENAI_PROXY_KEY
|
||||
value: {{ .Values.app.ai.openai.proxyKey | quote }}
|
||||
- name: OPENAI_BASE_URI
|
||||
value: {{ .Values.app.ai.openai.baseUri | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,110 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "nats.name" -}}
|
||||
{{- default .Chart.Name .Values.nats.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{- define "nats.fullname" -}}
|
||||
{{- if .Values.nats.fullnameOverride -}}
|
||||
{{- .Values.nats.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nats.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "nats.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "nats.labels" -}}
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
helm.sh/chart: {{ include "nats.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "nats.selectorLabels" -}}
|
||||
app.kubernetes.io/name: nats
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
|
||||
{{/*
|
||||
Return the proper NATS image name
|
||||
*/}}
|
||||
{{- define "nats.clusterAdvertise" -}}
|
||||
{{- printf "$(POD_NAME).%s.$(POD_NAMESPACE).svc.%s" (include "nats.fullname" . ) $.Values.nats.k8sClusterDomain }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the NATS cluster routes.
|
||||
*/}}
|
||||
{{- define "nats.clusterRoutes" -}}
|
||||
{{- $name := (include "nats.fullname" . ) -}}
|
||||
{{- range $i, $e := until (.Values.nats.cluster.replicas | int) -}}
|
||||
{{- printf "nats://%s-%d.%s.%s.svc.%s:6222," $name $i $name $.Release.Namespace $.Values.nats.k8sClusterDomain -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "nats.extraRoutes" -}}
|
||||
{{- range $i, $url := .Values.nats.cluster.extraRoutes -}}
|
||||
{{- printf "%s," $url -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "nats.tlsConfig" -}}
|
||||
tls {
|
||||
{{- if .cert }}
|
||||
cert_file: {{ .secretPath }}/{{ .secret.name }}/{{ .cert }}
|
||||
{{- end }}
|
||||
{{- if .key }}
|
||||
key_file: {{ .secretPath }}/{{ .secret.name }}/{{ .key }}
|
||||
{{- end }}
|
||||
{{- if .ca }}
|
||||
ca_file: {{ .secretPath }}/{{ .secret.name }}/{{ .ca }}
|
||||
{{- end }}
|
||||
{{- if .insecure }}
|
||||
insecure: {{ .insecure }}
|
||||
{{- end }}
|
||||
{{- if .verify }}
|
||||
verify: {{ .verify }}
|
||||
{{- end }}
|
||||
{{- if .verifyAndMap }}
|
||||
verify_and_map: {{ .verifyAndMap }}
|
||||
{{- end }}
|
||||
{{- if .curvePreferences }}
|
||||
curve_preferences: {{ .curvePreferences }}
|
||||
{{- end }}
|
||||
{{- if .timeout }}
|
||||
timeout: {{ .timeout }}
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{/*
|
||||
Renders a value that contains template.
|
||||
Usage:
|
||||
{{ include "tplvalues.render" ( dict "value" .Values.nats.path.to.the.Value "context" $) }}
|
||||
*/}}
|
||||
{{- define "tplvalues.render" -}}
|
||||
{{- if typeIs "string" .value }}
|
||||
{{- tpl .value .context }}
|
||||
{{- else }}
|
||||
{{- tpl (.value | toYaml) .context }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,83 @@
|
||||
{{- define "app_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.app.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.app.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.app.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.app.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.app.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.app.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "nginx_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.nginx.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.nginx.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.nginx.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.nginx.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.nginx.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.nginx.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "worker_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.worker.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.worker.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.worker.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.worker.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.worker.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.worker.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "websocket_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.websocket.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.websocket.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.websocket.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.websocket.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.websocket.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.websocket.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "geonames_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.geonames.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.geonames.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.geonames.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.geonames.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.geonames.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.geonames.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "conductor_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.conductor.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.conductor.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.conductor.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.conductor.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.conductor.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.conductor.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "jobs_resources" }}
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .Values.resources.jobs.requests.memory | quote }}
|
||||
cpu: {{ .Values.resources.jobs.requests.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.jobs.requests.ephemeralStorage | quote }}
|
||||
limits:
|
||||
memory: {{ .Values.resources.jobs.limits.memory | quote }}
|
||||
cpu: {{ .Values.resources.jobs.limits.cpu | quote }}
|
||||
ephemeral-storage: {{ .Values.resources.jobs.limits.ephemeralStorage | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,371 @@
|
||||
---
|
||||
# Основные настройки приложения HRBox
|
||||
app:
|
||||
# Docker образ приложения HRBox
|
||||
# Получите доступ к реестру у сотрудников HRBox
|
||||
image: "cr.yandex/crphnph9c2s776j32sjd/hrbox:latest"
|
||||
|
||||
# Настройки домена
|
||||
# defaultTenantHostname - основной домен вашей HRBox инсталляции
|
||||
# Например: hrbox.company.com
|
||||
# Должен совпадать с ingress.host
|
||||
defaultTenantHostname: "hrbox.example.com"
|
||||
|
||||
# Уникальное имя инстанса для идентификации
|
||||
instanceName: "onprem"
|
||||
|
||||
# Домен для единой авторизации (SSO)
|
||||
# Оставьте пустым, если не используете единую точку входа
|
||||
authHost: ""
|
||||
|
||||
# Режим отладки
|
||||
# "0" - production режим (рекомендуется)
|
||||
# "1" - debug режим (только для разработки)
|
||||
debug: "0"
|
||||
|
||||
# Количество реплик для каждого сервиса
|
||||
# Рекомендации по масштабированию:
|
||||
# - web: 2-10 реплик в зависимости от количества пользователей
|
||||
# - worker: 2-5 реплик для обработки фоновых задач
|
||||
# - websocket: 2-6 реплик для real-time функционала
|
||||
# - geonames: 1-2 реплики (сервис не требователен к ресурсам)
|
||||
replicas:
|
||||
web: 2
|
||||
worker: 2
|
||||
websocket: 2
|
||||
geonames: 1
|
||||
|
||||
# PostgreSQL база данных
|
||||
# Требования: PostgreSQL 14+
|
||||
# Рекомендуется настроить репликацию для отказоустойчивости
|
||||
postgres:
|
||||
host: "postgresql"
|
||||
port: "5432"
|
||||
database: "hrbox"
|
||||
user: "hrbox"
|
||||
# Пароль для подключения к БД
|
||||
password: ""
|
||||
# Использование Citus для шардирования
|
||||
# "true" - если используете Citus расширение
|
||||
# "false" - для обычного PostgreSQL
|
||||
citus: "false"
|
||||
|
||||
# Redis для кеша и сессий
|
||||
# Потеря данных не критична - хранятся только сессии и кеш
|
||||
# При перезапуске Redis все пользователи будут разлогинены
|
||||
redis:
|
||||
host: "hrbox-dragonfly"
|
||||
port: "6379"
|
||||
|
||||
# NATS JetStream - брокер сообщений
|
||||
# Для отказоустойчивости используйте кластер из 3+ нод
|
||||
# Формат для кластера: nats://node1:4222,nats://node2:4222,nats://node3:4222
|
||||
nats:
|
||||
url: "nats://hrbox-nats:4222"
|
||||
|
||||
# S3-совместимое хранилище для файлов
|
||||
# Поддерживаются: AWS S3, MinIO, Yandex Object Storage, VK Cloud Storage
|
||||
s3:
|
||||
# URL endpoint вашего S3
|
||||
# Примеры:
|
||||
# - MinIO: http://minio:9000
|
||||
# - Yandex: https://storage.yandexcloud.net
|
||||
# - VK Cloud: https://hb.vkcloud-storage.ru
|
||||
endpoint: "https://storage.example.com"
|
||||
|
||||
# Название bucket для хранения файлов
|
||||
bucket: "hrbox"
|
||||
|
||||
# Access Key для доступа к S3
|
||||
key: ""
|
||||
|
||||
# Secret Key для доступа к S3
|
||||
secret: ""
|
||||
|
||||
# Регион S3 (обычно us-east-1 для MinIO)
|
||||
region: "us-east-1"
|
||||
|
||||
# Версия API (оставьте "latest")
|
||||
version: "latest"
|
||||
|
||||
# Использовать path-style URLs
|
||||
# "true" для MinIO и self-hosted S3
|
||||
# "false" для AWS S3
|
||||
pathStyle: "true"
|
||||
|
||||
# Включить multipart загрузку для больших файлов
|
||||
multipart: "true"
|
||||
|
||||
# Префикс для всех объектов (опционально)
|
||||
prefix: ""
|
||||
|
||||
# SMTP настройки для отправки email
|
||||
smtp:
|
||||
# SMTP сервер
|
||||
host: "smtp.example.com"
|
||||
|
||||
# Порт SMTP
|
||||
# 25 - без шифрования
|
||||
# 587 - STARTTLS
|
||||
# 465 - SSL/TLS
|
||||
port: "587"
|
||||
|
||||
# Логин для SMTP авторизации
|
||||
user: "noreply@example.com"
|
||||
|
||||
# Пароль для SMTP
|
||||
password: ""
|
||||
|
||||
# Email отправителя
|
||||
from: "noreply@example.com"
|
||||
|
||||
# Домен отправителя для HELO/EHLO
|
||||
fromHost: "example.com"
|
||||
|
||||
# Тип шифрования: "", "tls", "ssl"
|
||||
securityType: "tls"
|
||||
|
||||
# Разрешить самоподписанные сертификаты
|
||||
sslAllowSelfSigned: "true"
|
||||
|
||||
# Проверять SSL сертификат сервера
|
||||
sslVerifyPeer: "false"
|
||||
|
||||
# Sentry для мониторинга ошибок (опционально)
|
||||
sentry:
|
||||
# DSN для отправки ошибок
|
||||
# Оставьте пустым, чтобы отключить
|
||||
dsn: ""
|
||||
|
||||
# Окружение для группировки ошибок
|
||||
environment: "production"
|
||||
|
||||
# Настройки сервиса геолокации
|
||||
geonames:
|
||||
# URL внутреннего сервиса geonames
|
||||
# Не меняйте, если используете стандартный деплой
|
||||
url: "http://hrbox-geonames:8181"
|
||||
|
||||
# Настройки воркеров Launchpad
|
||||
# Формат: "название-топика:количество-воркеров"
|
||||
launchpad:
|
||||
topics: "launcher:1,file-processor:1,image-processor:1,send-mail:1,send-im:1,send-bell:1,send-push:1,backup:1,cleaning:1"
|
||||
|
||||
# Интеграция с Yandex (опционально)
|
||||
yandex:
|
||||
# Client ID для Yandex OAuth
|
||||
clientId: ""
|
||||
# Client Secret для Yandex OAuth
|
||||
clientPassword: ""
|
||||
|
||||
# Интеграция со Slack (опционально)
|
||||
slack:
|
||||
# Slack App Client ID
|
||||
clientId: ""
|
||||
# Slack App Client Secret
|
||||
clientSecret: ""
|
||||
# Slack Verification Token
|
||||
verificationToken: ""
|
||||
|
||||
# HRBox Hub
|
||||
hub:
|
||||
# URL Hub сервиса
|
||||
url: "https://hub.hrbox.io"
|
||||
# Токен для авторизации в Hub, получите от сотрудника HrBox
|
||||
token: ""
|
||||
|
||||
# AI интеграции (опционально)
|
||||
ai:
|
||||
# Yandex Cloud AI
|
||||
yandex:
|
||||
# ID каталога в Yandex Cloud
|
||||
folderId: ""
|
||||
# API ключ для Yandex Cloud
|
||||
apiKey: ""
|
||||
|
||||
# OpenAI интеграция
|
||||
openai:
|
||||
# API ключ OpenAI
|
||||
apiKey: ""
|
||||
# Прокси ключ (если используете прокси)
|
||||
proxyKey: ""
|
||||
# Base URL для API (можно указать прокси)
|
||||
baseUri: ""
|
||||
|
||||
# Секретные ключи приложения
|
||||
secrets:
|
||||
# Ключ валидации cookie (32 символа)
|
||||
# Используется для защиты от XSS атак
|
||||
# Генерация: openssl rand -hex 16
|
||||
cookieValidationKey: ""
|
||||
|
||||
# Ключ шифрования данных (64 символа)
|
||||
# ВАЖНО: Не теряйте этот ключ! Без него невозможно расшифровать данные
|
||||
# Используется для шифрования паролей интеграций (S3, ADFS и др.)
|
||||
# Генерация: openssl rand -base64 48
|
||||
encryptionKey: ""
|
||||
|
||||
# Настройки Ingress
|
||||
ingress:
|
||||
# Включить Ingress
|
||||
enabled: true
|
||||
|
||||
# Класс Ingress контроллера
|
||||
# Обычно: "nginx" или "traefik"
|
||||
className: "nginx"
|
||||
|
||||
# Хост для доступа к приложению
|
||||
# Используйте wildcard для мультитенантности: *.hrbox.company.com
|
||||
# Или конкретный домен: hrbox.company.com
|
||||
host: "hrbox.example.com"
|
||||
|
||||
# Настройки TLS/HTTPS
|
||||
tls:
|
||||
# Включить HTTPS
|
||||
# ВАЖНО: В production всегда используйте HTTPS
|
||||
enabled: true
|
||||
|
||||
# Имя Kubernetes Secret с SSL сертификатом
|
||||
# Создайте через: kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
||||
# Или используйте cert-manager для автоматического получения сертификатов
|
||||
secretName: "hrbox-tls"
|
||||
|
||||
# Настройки ресурсов для контейнеров
|
||||
# Указаны рекомендуемые значения для production
|
||||
resources:
|
||||
# Web-сервер (PHP-FPM + Nginx)
|
||||
# Обрабатывает HTTP запросы, API, веб-интерфейс
|
||||
app:
|
||||
requests:
|
||||
cpu: "0.5" # Минимум 0.5 CPU
|
||||
memory: "512Mi" # Минимум 512MB RAM
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "2" # Максимум 2 CPU
|
||||
memory: "2Gi" # Максимум 2GB RAM
|
||||
ephemeralStorage: "256Mi"
|
||||
|
||||
# Nginx (в составе web pod)
|
||||
# Проксирует запросы к PHP-FPM
|
||||
nginx:
|
||||
requests:
|
||||
cpu: "0.1"
|
||||
memory: "64Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "0.5"
|
||||
memory: "256Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
|
||||
# Worker - обработчик фоновых задач
|
||||
# Выполняет: конвертацию файлов, отправку email, генерацию отчетов
|
||||
worker:
|
||||
requests:
|
||||
cpu: "0.5"
|
||||
memory: "512Mi"
|
||||
ephemeralStorage: "1Gi" # Больше места для обработки файлов
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: "2Gi"
|
||||
ephemeralStorage: "2Gi"
|
||||
|
||||
# WebSocket сервер
|
||||
# Обеспечивает real-time функционал, например, уведомления
|
||||
websocket:
|
||||
requests:
|
||||
cpu: "0.1"
|
||||
memory: "128Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: "512Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
|
||||
# Geonames - сервис геолокации
|
||||
# Определяет города, страны, часовые пояса
|
||||
geonames:
|
||||
requests:
|
||||
cpu: "0.1"
|
||||
memory: "196Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "0.5"
|
||||
memory: "256Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
|
||||
# Conductor - планировщик задач
|
||||
# ВАЖНО: Всегда должен быть в единственном экземпляре!
|
||||
# Запускает задачи по расписанию (cron)
|
||||
conductor:
|
||||
requests:
|
||||
cpu: "0.1"
|
||||
memory: "64Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "0.5"
|
||||
memory: "256Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
|
||||
# Jobs - одноразовые задачи (миграции, инициализация)
|
||||
jobs:
|
||||
requests:
|
||||
cpu: "0.5"
|
||||
memory: "512Mi"
|
||||
ephemeralStorage: "64Mi"
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: "2Gi"
|
||||
ephemeralStorage: "256Mi"
|
||||
|
||||
# Настройки NATS JetStream
|
||||
nats:
|
||||
# Включить NATS (обязательно для работы HRBox)
|
||||
enabled: true
|
||||
|
||||
# Docker образ NATS
|
||||
image: "nats:2.8"
|
||||
|
||||
# Количество реплик NATS
|
||||
# Для отказоустойчивости используйте 3 или 5
|
||||
replicas: 3
|
||||
|
||||
# JetStream - персистентные очереди сообщений
|
||||
jetstream:
|
||||
enabled: true
|
||||
|
||||
# Хранилище в памяти (для небольших инсталляций)
|
||||
memStorage:
|
||||
enabled: true
|
||||
size: "2Gi"
|
||||
|
||||
# Хранилище на диске (для production)
|
||||
fileStorage:
|
||||
enabled: false
|
||||
size: "4Gi"
|
||||
storageDirectory: "/data"
|
||||
# StorageClass для PVC
|
||||
# Используйте SSD для лучшей производительности
|
||||
storageClassName: "fast-ssd"
|
||||
|
||||
# Настройки кластера NATS
|
||||
cluster:
|
||||
# Включить кластеризацию для отказоустойчивости
|
||||
enabled: true
|
||||
# Должно совпадать с replicas
|
||||
replicas: 3
|
||||
|
||||
# Prometheus exporter (для мониторинга)
|
||||
exporter:
|
||||
enabled: false
|
||||
|
||||
# Config reloader - автоматическая перезагрузка конфигурации
|
||||
reloader:
|
||||
enabled: true
|
||||
|
||||
# Время ожидания graceful shutdown в секундах
|
||||
terminationGracePeriodSeconds: 120
|
||||
|
||||
dragonfly:
|
||||
# Включает или отключает развёртывание Dragonfly (Redis).
|
||||
# Установите в true, чтобы активировать, или в false, чтобы отключить.
|
||||
enabled: true
|
||||
@@ -1,93 +1,70 @@
|
||||
# helm-chart
|
||||
# HRBox Helm Chart
|
||||
|
||||
Helm-чарт для развертывания приложения HRBox в Kubernetes.
|
||||
|
||||
---
|
||||
|
||||
## Getting started
|
||||
## Быстрый старт
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
### 1. Создайте секрет для доступа к Docker-реестру
|
||||
|
||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
||||
Для скачивания приватного Docker-образа создайте Kubernetes Secret с помощью предоставленного JSON-ключа:
|
||||
|
||||
## Add your files
|
||||
|
||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
||||
|
||||
```
|
||||
cd existing_repo
|
||||
git remote add origin https://git.hrenot.com/hrbox-public/helm-chart.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```bash
|
||||
kubectl create secret docker-registry regsecret \
|
||||
--docker-username=json_key \
|
||||
--docker-password="$(cat key-puller.json)" \
|
||||
--docker-server=cr.yandex \
|
||||
--docker-email=not@used.com
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
### 2. Создайте TLS-секрет с сертификатом для домена
|
||||
|
||||
- [ ] [Set up project integrations](https://git.hrenot.com/hrbox-public/helm-chart/-/settings/integrations)
|
||||
```bash
|
||||
kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
||||
```
|
||||
|
||||
## Collaborate with your team
|
||||
### 3. Сгенерируйте секретные ключи приложения
|
||||
|
||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
||||
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
||||
Для обеспечения безопасности необходимо сгенерировать и указать в `values.yaml` следующие ключи:
|
||||
|
||||
## Test and Deploy
|
||||
- **cookieValidationKey** — 32 байта в hex (например: `openssl rand -hex 16`)
|
||||
- **encryptionKey** — 64 байта в base64 (например: `openssl rand -base64 48`)
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
Эти ключи используются для защиты cookie и шифрования данных.
|
||||
|
||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
### 4. Заполните обязательные параметры в `values.yaml`
|
||||
|
||||
***
|
||||
Обязательно укажите в конфигурации:
|
||||
|
||||
# Editing this README
|
||||
- Параметры подключения к базе данных PostgreSQL (`app.postgres.host`, `port`, `database`, `user`, `password`).
|
||||
- Настройки S3-совместимого хранилища (`app.s3.endpoint`, `bucket`, `key`, `secret`).
|
||||
- SMTP-настройки для отправки почты (`app.smtp.host`, `port`, `user`, `password`, `from`, `fromHost`).
|
||||
- Домен для приложения (`app.defaultTenantHostname`) и Ingress (`ingress.host`).
|
||||
- Имя TLS-секрета для HTTPS (`ingress.tls.secretName`), созданного на шаге 2.
|
||||
- Ключ для hrbox hub (предоставляется сотрудниками hrbox)
|
||||
|
||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
||||
### 5. Установите или обновите Helm-релиз
|
||||
|
||||
## Suggestions for a good README
|
||||
```bash
|
||||
helm upgrade --install hrbox . -f values.yaml
|
||||
```
|
||||
|
||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
||||
### 6. Дождитесь завершения миграций
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
Job `hrbox-migrate-xxxxx` должна завершиться
|
||||
|
||||
## Description
|
||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
||||
### 7. При первом развертывании - создайте суперпользователя
|
||||
|
||||
## Badges
|
||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
||||
```bash
|
||||
kubectl get pods
|
||||
|
||||
## Visuals
|
||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
...
|
||||
hrbox-worker-7898b77b85-5ppwm 1/1 Running 0 53s
|
||||
hrbox-worker-7898b77b85-9fnkc 1/1 Running 0 53s
|
||||
|
||||
## Installation
|
||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
||||
kubectl exec -it hrbox-worker-7898b77b85-5ppwm bash
|
||||
|
||||
## Usage
|
||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
||||
|
||||
## Support
|
||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
State if you are open to contributions and what your requirements are for accepting them.
|
||||
|
||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
||||
|
||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
||||
|
||||
## Authors and acknowledgment
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
php yii user/create-admin youremail@hrbox.io --tenant-id=1
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user