init
This commit is contained in:
@@ -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 }}
|
||||
Reference in New Issue
Block a user