This commit is contained in:
Vlad Bubnov
2025-05-27 08:03:13 +03:00
parent f47d4feeac
commit fb638f1988
21 changed files with 1639 additions and 68 deletions
+1
View File
@@ -0,0 +1 @@
charts/
+24
View File
@@ -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/
+19
View File
@@ -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
+58
View File
@@ -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
+154
View File
@@ -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;
}
}
}
+12
View File
@@ -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
+42
View File
@@ -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 }}
+144
View File
@@ -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
+100
View File
@@ -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
+50
View File
@@ -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
+33
View File
@@ -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
+40
View File
@@ -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 }}
+50
View File
@@ -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
+40
View File
@@ -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 }}
+42
View File
@@ -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
+24
View File
@@ -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
+197
View File
@@ -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 }}
+110
View File
@@ -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 -}}
+83
View File
@@ -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 }}
+371
View File
@@ -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
+45 -68
View File
@@ -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 ```bash
kubectl create secret docker-registry regsecret \
- [ ] [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 --docker-username=json_key \
- [ ] [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: --docker-password="$(cat key-puller.json)" \
--docker-server=cr.yandex \
``` --docker-email=not@used.com
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
``` ```
## 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/) Для обеспечения безопасности необходимо сгенерировать и указать в `values.yaml` следующие ключи:
- [ ] [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)
## 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) ### 4. Заполните обязательные параметры в `values.yaml`
- [ ] [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)
*** Обязательно укажите в конфигурации:
# 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 Job `hrbox-migrate-xxxxx` должна завершиться
Choose a self-explaining name for your project.
## Description ### 7. При первом развертывании - создайте суперпользователя
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.
## Badges ```bash
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. kubectl get pods
## Visuals NAME READY STATUS RESTARTS AGE
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. ...
hrbox-worker-7898b77b85-5ppwm 1/1 Running 0 53s
hrbox-worker-7898b77b85-9fnkc 1/1 Running 0 53s
## Installation kubectl exec -it hrbox-worker-7898b77b85-5ppwm bash
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.
## Usage php yii user/create-admin youremail@hrbox.io --tenant-id=1
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.