Подготовка к Production#
Введение#
Пример исходных данных
Имя кластера =
my-clusterПубличный домен =
dapp.test.un.sbtАдрес пула в Metallb (или используемого внешнего балансировщика) =
<metallb-pool-ip>Ingress-контроллеры соответствуют шаблону:
*.my-cluster.dapp.test.un.sbtУзлы соответствуют шаблону:
dapp-cp-01-my-cluster.dapp.test.un.sbt,dapp-worker-01-my-cluster.dapp.test.un.sbtКластер имеет 3 control plane узла:
<controlplane1-ip>,<controlplane2-ip>,<controlplane3-ip>Кластер имеет 6 worker узлов:
<worker1-ip> - <worker6-ip>(3 из них являются ingress-узлами)
В данном разделе описаны шаги по подготовке высокодоступного кластера для использования в Production-средах.
В качестве хранилища используется NFS-сервер и инструмент Csi-driver-nfs, входящий в состав DropApp. Этот инструмент (Tool) доступен к установке через Dapp-operator.
В разделе описаны настройки:
настройка сервера HAProxy на Platform V SberLinux OS для балансировки запросов к Kube-apiserver;
настройка NFS-сервера на Platform V SberLinux OS для постоянного хранения данных (
PersistentVolumes);настройка
DropAppCongifuration:создание выделенных узлов для Ingress-controller;
увеличение лимитов ресурсов Ingress-controller;
настройка сертификатов: ingressTLS и clusterTLS;
настройка Kube-apiserver (audit, extraSANs);
настройка
controlPlaneEndpoint;включение шифрования Etcd;
настройка
PodSecurityAdmissionпо умолчанию;подключение каталога LDAP для управления пользователями;
настройка подсети для pod и service K8S;
включение Hubble-ui для сетевого мониторинга.
установка инструмента Csi-driver-nfs;
установка компонентов:
Monitoring с постоянным хранением;
Alerting с постоянным хранением;
Logging с постоянным хранением;
Security;
AiOps для автоматического анализа ошибок в кластере;
GitOps, DevOps для работы с пользовательскими приложениями.
Подготовка инфраструктуры#
Кроме стандартных действий, описанных в разделе «Подготовка окружения», необходимо настроить:
серверы, которые будут выполнять функции балансировщиков нагрузки для запросов к API кластера;
NFS-сервер для постоянного хранения данных.
Сервер HAProxy#
Создайте машину на Platform V SberLinux OS с IP-адресом <haproxy-ip>. Подключите на нее репозитории BaseOS и AppStream. Зарегистрируйте в DNS запись:
<haproxy-ip> apiserver.my-cluster.dapp.test.un.sbt
Примечание
В примере указан один сервер HAProxy. Для большей доступности можно создать два сервера и установить на каждый Keepalived. Это позволит автоматически переключаться между серверами в случае сбоя одного из них. Адрес в DNS будет виртуальным IP (VIP), который предоставляет Keepalived.
Для настройки сервера HAProxy выполните следующие шаги:
Создайте скрипт
hp.sh:hp.sh
#!/bin/bash set -euo pipefail # ============================================================================= # Setup HAProxy for Kubernetes API # Mode: TCP passthrough with SNI routing # No TLS termination, no certs required # Stats available on HTTP port 8443 # ============================================================================= SCRIPT_NAME=$(basename "$0") usage() { cat << EOF Usage: $SCRIPT_NAME [OPTIONS] Setup HAProxy to load balance kube-apiserver in TCP passthrough mode. Uses SNI to route traffic for the given hostname. Options: --hostname HOSTNAME DNS name for SNI (e.g. apiserver.my-cluster.dapp.test.un.sbt) --port PORT kube-apiserver port (default: 6443) --stats-port PORT HAProxy stats port (default: 8443) --controlplane LIST Comma-separated list of control-plane IPs --cluster-name NAME Cluster name (used in server names) --help Show this help Example: sudo $SCRIPT_NAME \\ --hostname apiserver.my-cluster.dapp.test.un.sbt \\ --port 6443 \\ --stats-port 8443 \\ --controlplane <controlplane1-ip>,<controlplane2-ip>,<controlplane3-ip> \\ --cluster-name my-cluster EOF } # ============================================================================= # Parse arguments # ============================================================================= HOSTNAME="" API_PORT="6443" STATS_PORT="8443" CONTROLPLANE="" CLUSTER_NAME="" while [[ $# -gt 0 ]]; do case $1 in --hostname) HOSTNAME="$2" shift; shift ;; --port) API_PORT="$2" shift; shift ;; --stats-port) STATS_PORT="$2" shift; shift ;; --controlplane) CONTROLPLANE="$2" shift; shift ;; --cluster-name) CLUSTER_NAME="$2" shift; shift ;; --help) usage exit 0 ;; *) echo "Error: Unknown argument $1" usage exit 1 ;; esac done # Validate required args if [[ -z "$HOSTNAME" ]]; then echo "Error: --hostname is required" usage exit 1 fi if [[ -z "$CONTROLPLANE" ]]; then echo "Error: --controlplane is required" usage exit 1 fi if [[ -z "$CLUSTER_NAME" ]]; then echo "Error: --cluster-name is required" usage exit 1 fi # Split IPs by comma IFS=',' read -r -a CP_ARRAY <<< "$CONTROLPLANE" if [[ ${#CP_ARRAY[@]} -eq 0 ]]; then echo "Error: No control-plane nodes specified" exit 1 fi # Trim whitespace for i in "${!CP_ARRAY[@]}"; do CP_ARRAY[i]=$(echo "${CP_ARRAY[i]}" | xargs) done # ============================================================================= # Check root privileges # ============================================================================= if [[ $EUID -ne 0 ]]; then echo "Error: This script must be run as root (use sudo)" exit 1 fi echo "=== Setting up HAProxy for Kubernetes API ===" echo "Hostname: $HOSTNAME" echo "API Port: $API_PORT" echo "Stats Port: $STATS_PORT" echo "Control-plane nodes: ${CP_ARRAY[*]}" echo "Cluster Name: $CLUSTER_NAME" echo "Mode: TCP passthrough (no TLS termination)" echo # ============================================================================= # 1. Install HAProxy # ============================================================================= echo "=== Installing HAProxy ===" if dnf list installed haproxy &>/dev/null; then echo "HAProxy already installed" else dnf install -y haproxy echo "HAProxy installed" fi # ============================================================================= # 2. Generate HAProxy config # ============================================================================= HAPROXY_CFG="/etc/haproxy/haproxy.cfg" HAPROXY_CFG_BAK="/etc/haproxy/haproxy.cfg.bak" if [[ -f "$HAPROXY_CFG" ]]; then if [[ ! -f "$HAPROXY_CFG_BAK" ]]; then cp "$HAPROXY_CFG" "$HAPROXY_CFG_BAK" echo "Backup saved: $HAPROXY_CFG_BAK" fi fi echo "=== Generating HAProxy configuration ===" # Backend servers BACKEND_SERVERS="" for i in "${!CP_ARRAY[@]}"; do IP=$(echo "${CP_ARRAY[i]}" | xargs) if ! [[ "$IP" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then echo "Error: Invalid IP address: $IP" exit 1 fi printf -v INDEX "%02d" $(($i + 1)) SERVER_NAME="dapp-cp-${INDEX}-${CLUSTER_NAME}" BACKEND_SERVERS+=" server $SERVER_NAME $IP:$API_PORT check fall 3 rise 2\n" done # Generate config cat > "$HAPROXY_CFG" << EOF #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log <local2-ip> local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemon stats socket /var/lib/haproxy/stats #--------------------------------------------------------------------- # Common defaults #--------------------------------------------------------------------- defaults mode tcp log global option tcplog option dontlognull timeout connect 5s timeout client 30s timeout server 30s timeout check 10s retries 3 #--------------------------------------------------------------------- # Frontend: Kubernetes API with SNI #--------------------------------------------------------------------- frontend k8s-api-frontend bind *:$API_PORT tcp-request inspect-delay 5s tcp-request content accept if { req.ssl_hello_type 1 } acl sni_ok req.ssl_sni -i $HOSTNAME tcp-request content reject if !sni_ok use_backend k8s-api-backend if sni_ok #--------------------------------------------------------------------- # Backend: Control-plane nodes #--------------------------------------------------------------------- backend k8s-api-backend balance roundrobin option tcp-check $(echo -e "$BACKEND_SERVERS") #--------------------------------------------------------------------- # Stats page (HTTP) #--------------------------------------------------------------------- listen stats bind *:$STATS_PORT mode http stats enable stats uri /stats stats realm Platform\ V\ DropApp\ Cluster\ Statistics stats auth admin:dapp stats hide-version stats refresh 5s EOF echo "Configuration written to $HAPROXY_CFG" # ============================================================================= # 3. Validate config # ============================================================================= echo "=== Validating HAProxy config ===" haproxy -c -f "$HAPROXY_CFG" if [[ $? -ne 0 ]]; then echo "Error: HAProxy configuration is invalid" exit 1 fi # ============================================================================= # 4. Configure firewalld # ============================================================================= if systemctl is-active --quiet firewalld; then echo "=== Configuring firewalld ===" for PORT in "$API_PORT" "$STATS_PORT"; do if ! firewall-cmd --state &>/dev/null; then continue fi if ! firewall-cmd --list-ports | grep -q "\b$PORT/tcp"; then firewall-cmd --permanent --add-port="$PORT/tcp" echo "Port $PORT/tcp added to firewalld" else echo "Port $PORT/tcp already open" fi done firewall-cmd --reload else echo "firewalld is not active — skipping" fi # ============================================================================= # 5. Configure SELinux # ============================================================================= if command -v getenforce &>/dev/null && [[ $(getenforce) != "Disabled" ]]; then echo "=== Configuring SELinux ===" if ! command -v semanage &>/dev/null; then echo "Installing policycoreutils-python-utils..." dnf install -y policycoreutils-python-utils fi for PORT in "$API_PORT" "$STATS_PORT"; do if ! semanage port -l | grep -q "\b$PORT\b.*http_port_t"; then semanage port -a -t http_port_t -p tcp "$PORT" echo "SELinux: port $PORT added to http_port_t" else echo "SELinux: port $PORT already allowed" fi done else echo "SELinux is disabled or not installed — skipping" fi # ============================================================================= # 6. Enable and start HAProxy # ============================================================================= echo "=== Enabling and starting HAProxy ===" systemctl enable haproxy --now if ! systemctl is-active --quiet haproxy; then echo "Error: HAProxy failed to start" journalctl -u haproxy -n 20 --no-pager exit 1 fi echo "HAProxy is now running and enabled on boot" # ============================================================================= # Final message # ============================================================================= echo echo "SUCCESS: HAProxy setup complete!" echo "Mode: TCP passthrough (no TLS termination)" echo "API endpoint: $HOSTNAME:$API_PORT" echo "Stats page: http://<IP>:$STATS_PORT/stats" echo "Login: admin / dapp" echo "Realm: Platform V DropApp Cluster Statistics" echo "Control-plane nodes: ${CP_ARRAY[*]}" echo "Server names: dapp-cp-01-$CLUSTER_NAME, dapp-cp-02-$CLUSTER_NAME, ..." echo "Note: Ensure DNS resolves $HOSTNAME to this machine"Сделайте файл исполняемым:
chmod +x ./hp.shЗапустите скрипт:
sudo ./hp.sh --hostname apiserver.my-cluster.dapp.test.un.sbt --controlplane <controlplane1-ip>,<controlplane2-ip>,<controlplane3-ip> --cluster-name my-clusterПроверьте службу
haproxy, ее статус должен бытьactive (running):sudo systemctl status haproxyПример вывода:
● haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; vendor preset: disabled) Active: active (running) since Tue 2025-09-02 07:59:30 UTC; 52s ago Process: 13760 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -f $CFGDIR -c -q $OPTIONS (code=exited, status=0/SUCCESS) Main PID: 13763 (haproxy) Tasks: 2 (limit: 10881) Memory: 2.8M CGroup: /system.slice/haproxy.service ├─13763 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -p /run/haproxy.pid └─13765 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -p /run/haproxy.pid Sep 02 07:59:30 dapp-infra-01-my-cluster systemd[1]: Starting HAProxy Load Balancer... Sep 02 07:59:30 dapp-infra-01-my-cluster systemd[1]: Started HAProxy Load Balancer.Перейдите на страницу
http://apiserver.my-cluster.dapp.test.un.sbt:8443/stats(статистика доступна по умолчанию на порту 8443).Используйте для входа данные
admin/dapp(указанные, для примера, в скриптеhp.sh):
Сервер HAProxy настроен.
Сервер NFS#
Создайте машину на Platform V SberLinux OS с IP-адресом <nfs-ip>. Подключите на нее репозитории BaseOS и AppStream. Зарегистрируйте в DNS запись:
<nfs-ip> nfs.dapp.test.un.sbt
Для настройки сервера NFS выполните следующие шаги:
Создайте скрипт
nfs.sh.sh:nfs.sh
#!/bin/bash # ============================================================================= # nfs.sh # Purpose: Install and configure NFS server # ============================================================================= set -euo pipefail # Configuration EXPORT_DIR="/export/nfs" NFS_SERVICE="nfs-server" FIREWALL_SERVICES=("nfs" "mountd" "rpc-bind") # Ensure running as root if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" >&2 exit 1 fi echo "Installing NFS server..." # Step 1: Update and install nfs-utils if ! rpm -q nfs-utils >/dev/null 2>&1; then dnf update -y dnf install -y nfs-utils fi # Step 2: Create export directory mkdir -p "$EXPORT_DIR" # Step 3: Ensure permissions chmod 777 "$EXPORT_DIR" chown nobody:nobody "$EXPORT_DIR" # Step 4: Configure /etc/exports (only if entry not present) EXPORT_ENTRY="$EXPORT_DIR *(rw,sync,no_root_squash,no_all_squash,no_subtree_check)" if ! grep -Fqs "$EXPORT_DIR" /etc/exports; then echo "$EXPORT_ENTRY" > /etc/exports else # Ensure correct export line grep -v "^$EXPORT_DIR" /etc/exports > /tmp/exports.tmp || true echo "$EXPORT_ENTRY" >> /tmp/exports.tmp mv /tmp/exports.tmp /etc/exports fi # Step 5: Reload export configuration exportfs -rav # Step 6: Enable and start NFS server if ! systemctl is-enabled "$NFS_SERVICE" >/dev/null 2>&1; then systemctl enable "$NFS_SERVICE" fi systemctl restart "$NFS_SERVICE" # Step 7: Handle firewalld if active if systemctl is-active firewalld --quiet; then echo "firewalld is active. Adding NFS services to firewall..." for service in "${FIREWALL_SERVICES[@]}"; do if ! firewall-cmd --state >/dev/null 2>&1; then echo "firewalld is not running, starting..." systemctl start firewalld fi if ! firewall-cmd --list-services --permanent | grep -wq "$service"; then firewall-cmd --permanent --add-service="$service" fi done firewall-cmd --reload else echo "firewalld is not active. Skipping firewall configuration." fi # Step 8: Get primary IP address IP_ADDR=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) if [[ -z "$IP_ADDR" ]]; then echo "Failed to detect IP address" >&2 exit 1 fi # Step 9: Output result echo echo "NFS server setup complete" echo "Server IP: $IP_ADDR" echo "Export directory: $EXPORT_DIR" echo "Use in Kubernetes StorageClass:" echo " server: $IP_ADDR" echo " share: $EXPORT_DIR"При необходимости измените права на каталог
export, или иной путь, заданный в переменнойEXPORT_DIRскрипта.Сделайте файл исполняемым:
chmod +x ./nfs.shЗапустите скрипт:
sudo ./nfs.shПроверьте службу
nfs-server, ее статус должен бытьactive (exited):sudo systemctl status nfs-serverПример вывода:
● nfs-server.service - NFS server and services Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled) Drop-In: /run/systemd/generator/nfs-server.service.d └─order-with-mounts.conf Active: active (exited) since Tue 2025-09-02 08:25:39 UTC; 34s ago Process: 13959 ExecStart=/bin/sh -c if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi (code=exited, status=0/SUCCESS) Process: 13946 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS) Process: 13944 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS) Main PID: 13959 (code=exited, status=0/SUCCESS) Sep 02 08:25:39 dapp-infra-01-my-cluster systemd[1]: Starting NFS server and services... Sep 02 08:25:39 dapp-infra-01-my-cluster systemd[1]: Started NFS server and services.Проверьте, что
/export/nfsявляется ресурсом (share):Выполните команду для просмотра конфигурации экспорта NFS:
cat /etc/exportsВывод будет следующим:
/export/nfs *(rw,sync,no_root_squash,no_all_squash,no_subtree_check)В выводе указано, что каталог
/export/nfsдоступен для всех клиентов (*), с правами на чтение и запись (rw), синхронной записью (sync) и опциями, отключающими проверки прав для суперпользователя (no_root_squash), проверки прав для всех пользователей (no_all_squash) и подкаталогов (no_subtree_check).Выполните команду для отображения статуса экспортируемых файловых систем:
sudo exportfs -vВывод будет следующим:
/export/nfs <world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)Вывод показывает, что каталог
/export/nfsэкспортируется с теми же параметрами, включая разрешения для всех клиентов (<world>), синхронность и отсутствие проверки подкаталогов. Опции:syncуказывает на синхронную запись, при которой изменения записываются на диск немедленно.wdelayпозволяет применять изменения с задержкой для оптимизации производительности.hideскрывает определенные файлы и каталоги от клиентов, чтобы они не были видны при доступе.no_subtree_checkотключает проверку подкаталогов, что может улучшить производительность при работе с подкаталогами.sec=sysуказывает на использование стандартной системы безопасности.rwпозволяет клиентам читать и записывать данные в каталог.secureфайл может быть доступен только по защищенным каналам (например, через шифрование).no_root_squashотключает сравнение прав для суперпользователя, позволяя ему получать доступ к каталогу с полными правами.no_all_squashотключает приведение всех пользователей к никому, позволяя клиентам сохранять свои права доступа.
Сервер NFS настроен.
Подготовка DropAppConfiguration#
Настройте конфигурацию для создания кластера со всеми необходимыми секциями.
В качестве основного примера конфигурации используйте данные из документа Руководство по установке DropApp с помощью Dactl. Предполагается, что артефакты уже настроены и секция artifacts подготовлена.
Выделенные ingress-узлы#
В файле конфигурации da.yaml заполните секции compute и components:
Редактирование секций compute и components в da.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_k8s"
userProvisioned:
nodes:
controlPlane:
- ip: "<controlplane1-ip>"
nodePool: "control-plane"
- ip: "<controlplane2-ip>"
nodePool: "control-plane"
- ip: "<controlplane3-ip>"
nodePool: "control-plane"
worker:
- ip: "<worker1-ip>"
nodePool: "worker"
- ip: "<worker2-ip>"
nodePool: "worker"
- ip: "<worker3-ip>"
nodePool: "worker"
- ip: "<worker4-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker5-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker6-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
...
components:
...
- name: load-balancer
tools:
- name: metallb
values:
speaker:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/ingress
operator: Exists
- name: ingress-controller
tools:
- name: ingress-nginx
values:
controller:
kind: DaemonSet
resources:
limits:
cpu: 2000m
memory: 8Gi
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/ingress
operator: Exists
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ingress"
effect: "NoSchedule"
В примере указано:
выделение трех рабочих узлов на
ingressиз шести;настройка компонентов Load-balancer и Ingress-controller на выделенные узлы;
увеличение лимитов для pod
ingress-nginx.
Конфигурация без Metallb#
Если в качестве балансировщика используется не Metallb, а внешний сервер, используйте следующую конфигурацию:
Редактирование секции network в da.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
# в секции network необходимо убрать metallb!
network:
publicDomain: dapp.test.un.sbt
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_k8s"
userProvisioned:
nodes:
controlPlane:
- ip: "<controlplane1-ip>"
nodePool: "control-plane"
- ip: "<controlplane2-ip>"
nodePool: "control-plane"
- ip: "<controlplane3-ip>"
nodePool: "control-plane"
worker:
- ip: "<worker1-ip>"
nodePool: "worker"
- ip: "<worker2-ip>"
nodePool: "worker"
- ip: "<worker3-ip>"
nodePool: "worker"
- ip: "<worker4-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker5-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker6-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
...
components:
...
- name: ingress-controller
tools:
- name: ingress-nginx
values:
controller:
kind: DaemonSet
resources:
limits:
cpu: 2000m
memory: 8Gi
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/ingress
operator: Exists
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ingress"
effect: "NoSchedule"
При такой конфигурации ingress-nginx преднастроится с такими values:
controller:
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
hostPort:
enabled: true
ports:
http: 80
https: 443
kind: DaemonSet
service:
external:
enabled: false
При этом значения из spec.components будут объединены со значениями выше.
Использование своих сертификатов#
Если параметры ingressTLS и clusterTLS не переданы, DropApp сгенерирует сертификаты для ingress и корневые сертификаты для кластера.
В случае необходимости можно предоставить собственные сертификаты, сгенерировать запрос на сертификат (CSR) с помощью скриптов и подписать его в корпоративной системе управления ключами (PKI). Полученный сертификат следует использовать в конфигурации кластера.
Корневые сертификаты Kubernetes#
Генерация корневых сертификатов кластера#
Создайте скрипт
hp.sh:k8s-ca-csr.sh
#!/bin/bash OUTPUT_DIR="./k8s-ca" mkdir -p "$OUTPUT_DIR" # Параметры haproxy HAPROXY_IP="<haproxy-ip3>" HAPROXY_DNS="apiserver.my-cluster.dapp.test.un.sbt" # Создание конфигурационного файла для CSR с дополнительными SAN cat > "$OUTPUT_DIR/ca-csr.conf" <<EOF [ req ] default_bits = 2048 distinguished_name = req_distinguished_name req_extensions = v3_req prompt = no [ req_distinguished_name ] CN = kubernetes-ca [ v3_req ] basicConstraints = CA:true keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign subjectAltName = @alt_names [ alt_names ] IP.1 = <haproxy-ip1> IP.2 = <haproxy-ip2> IP.3 = $HAPROXY_IP DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local DNS.5 = $HAPROXY_DNS EOF # Генерация приватного ключа (этот ключ останется у пользователя) openssl genrsa -out "$OUTPUT_DIR/ca.key" 2048 # Генерация Certificate Signing Request (CSR) - этот файл отправляется на подпись openssl req -new \ -key "$OUTPUT_DIR/ca.key" \ -out "$OUTPUT_DIR/ca.csr" \ -config "$OUTPUT_DIR/ca-csr.conf" \ -extensions v3_req # Вывод информации о созданном CSR echo "CSR создан с дополнительными SAN для haproxy" echo "Файлы:" echo " Приватный ключ: $OUTPUT_DIR/ca.key (храните в секрете)" echo " CSR для подписи: $OUTPUT_DIR/ca.csr (отправьте этот файл на подпись)" echo echo "Добавленные SAN:" echo " IP: $HAPROXY_IP" echo " DNS: $HAPROXY_DNS" # Вывод CSR в base64 для удобства копирования echo echo "-----BEGIN CERTIFICATE REQUEST (ca.csr base64)-----" base64 -w 0 "$OUTPUT_DIR/ca.csr" echo echo "-----END CERTIFICATE REQUEST-----" echo echo "После получения подписанного сертификата от корпоративного PKI:" echo "1. Сохраните подписанный сертификат как $OUTPUT_DIR/ca.crt" echo "2. Убедитесь, что цепочка сертификатов корректна"Сделайте файл исполняемым:
chmod +x ./k8s-ca-csr.shЗапустите скрипт:
sudo ./k8s-ca-csr.sh
Корневые сертификаты сгенерированы.
Подпись сертификатов в корпоративной системе управления ключами (PKI)#
Создайте скрипт
hp.sh:sign-k8s-ca.sh
#!/bin/bash # Шаг 1: Задание переменных для каталогов CSR_DIR="./k8s-ca" CORPORATE_CA_DIR="./corporate-pki" echo "=== Эмуляция корпоративного PKI ===" # Шаг 2: Проверка наличия CSR if [ ! -f "$CSR_DIR/ca.csr" ]; then echo "Ошибка: Не найден файл CSR: $CSR_DIR/ca.csr" echo "Сначала запустите generate-csr.sh" exit 1 fi echo "Найден CSR: $CSR_DIR/ca.csr" # Шаг 3: Подпись CSR корпоративным CA echo "Подпись CSR корпоративным CA..." # Шаг 4: Копирование конфигурации из CSR для использования в расширениях CSR_CONFIG="$CSR_DIR/ca-csr.conf" # Шаг 5: Подпись CSR openssl x509 -req \ -in "$CSR_DIR/ca.csr" \ -CA "$CORPORATE_CA_DIR/corporate-ca.crt" \ -CAkey "$CORPORATE_CA_DIR/corporate-ca.key" \ -CAcreateserial \ -out "$CSR_DIR/ca.crt" \ -days 365 \ -extensions v3_req \ -extfile "$CSR_CONFIG" echo "CSR подписан успешно!" # Шаг 6: Создание полной цепочки сертификатов (если нужно) echo "Создание полной цепочки сертификатов..." cat "$CSR_DIR/ca.crt" "$CORPORATE_CA_DIR/corporate-ca.crt" > "$CSR_DIR/ca-fullchain.crt" # Шаг 7: Вывод результатов echo echo "=== Результаты ===" echo "Корневой сертификат корпоративного PKI: $CORPORATE_CA_DIR/corporate-ca.crt" echo "Приватный ключ Kubernetes CA: $CSR_DIR/ca.key" echo "Подписанный сертификат Kubernetes CA: $CSR_DIR/ca.crt" echo "Полная цепочка сертификатов: $CSR_DIR/ca-fullchain.crt" # Шаг 8: Проверка echo echo "=== Проверка сертификата ===" echo "Subject:" openssl x509 -in "$CSR_DIR/ca.crt" -noout -subject echo "Issuer:" openssl x509 -in "$CSR_DIR/ca.crt" -noout -issuer echo "SAN (Subject Alternative Names):" openssl x509 -in "$CSR_DIR/ca.crt" -noout -text | grep -A 1 "Subject Alternative Name" || echo "SAN не найдены" echo echo "=== Готово! ===" echo "Теперь вы можете использовать:" echo " $CSR_DIR/ca.key - приватный ключ" echo " $CSR_DIR/ca.crt - подписанный сертификат" echo " $CSR_DIR/ca-fullchain.crt - полная цепочка сертификатов"Сделайте файл исполняемым:
chmod +x ./sign-k8s-ca.shЗапустите скрипт:
sudo ./sign-k8s-ca.sh
Сертификаты в корпоративной системе управления ключами (PKI) подписаны.
Сохранение сертификата#
Сохраните сертификат и ключ в base64:
cat k8s-ca/ca.crt | base64 -w0
cat k8s-ca/ca.key | base64 -w0
В выводах команд будут отображены закодированные в Base64 сертификаты.
Добавление сертификатов в DropAppConfiguration описано в пункте «Добавление сертификатов в DropAppConfiguration».
Сертификаты для ingress#
Генерация сертификатов для ingress и подпись в корпоративной системе управления ключами (PKI)#
Создайте скрипт
hp.sh:sign-ingress-tls.sh
#!/bin/bash # Каталоги OUTPUT_DIR="./ingress-cert" CORPORATE_CA_DIR="./corporate-pki" echo "=== Создание сертификата для Ingress (*.my-cluster.dapp.test.un.sbt) ===" # Шаг 1: Создание каталога mkdir -p "$OUTPUT_DIR" # Шаг 2: Проверка наличия корневого CA if [ ! -f "$CORPORATE_CA_DIR/corporate-ca.crt" ] || [ ! -f "$CORPORATE_CA_DIR/corporate-ca.key" ]; then echo "Ошибка: Не найден корневой CA. Сначала запустите эмуляцию корпоративного PKI." exit 1 fi echo "Найден корневой CA: $CORPORATE_CA_DIR/corporate-ca.crt" # Шаг 3: Создание конфигурационного файла для сертификата ingress cat > "$OUTPUT_DIR/ingress.conf" <<EOF [ req ] default_bits = 2048 distinguished_name = req_distinguished_name req_extensions = v3_req prompt = no [ req_distinguished_name ] CN = *.my-cluster.dapp.test.un.sbt [ v3_req ] basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [ alt_names ] DNS.1 = *.my-cluster.dapp.test.un.sbt DNS.2 = my-cluster.dapp.test.un.sbt EOF # Шаг 4: Генерация приватного ключа для ingress echo "Генерация приватного ключа для ingress..." openssl genrsa -out "$OUTPUT_DIR/tls.key" 2048 # Шаг 5: Создание Certificate Signing Request (CSR) echo "Создание CSR для ingress..." openssl req -new \ -key "$OUTPUT_DIR/tls.key" \ -out "$OUTPUT_DIR/tls.csr" \ -config "$OUTPUT_DIR/ingress.conf" \ -extensions v3_req # Шаг 6: Подпись CSR корпоративным CA echo "Подпись CSR корпоративным CA..." openssl x509 -req \ -in "$OUTPUT_DIR/tls.csr" \ -CA "$CORPORATE_CA_DIR/corporate-ca.crt" \ -CAkey "$CORPORATE_CA_DIR/corporate-ca.key" \ -CAcreateserial \ -out "$OUTPUT_DIR/tls.crt" \ -days 365 \ -extensions v3_req \ -extfile "$OUTPUT_DIR/ingress.conf" # Шаг 7: Создание полной цепочки сертификатов echo "Создание полной цепочки сертификатов..." cat "$OUTPUT_DIR/tls.crt" "$CORPORATE_CA_DIR/corporate-ca.crt" > "$OUTPUT_DIR/tls-fullchain.crt" # Шаг 8: Вывод результатов echo echo "=== Результаты ===" echo "Приватный ключ ingress: $OUTPUT_DIR/tls.key" echo "Сертификат ingress: $OUTPUT_DIR/tls.crt" echo "Полная цепочка: $OUTPUT_DIR/tls-fullchain.crt" echo "CSR для ingress: $OUTPUT_DIR/tls.csr" # Шаг 9: Проверка сертификата echo echo "=== Проверка сертификата ===" echo "Subject:" openssl x509 -in "$OUTPUT_DIR/tls.crt" -noout -subject echo "Issuer:" openssl x509 -in "$OUTPUT_DIR/tls.crt" -noout -issuer echo "SAN:" openssl x509 -in "$OUTPUT_DIR/tls.crt" -noout -text | grep -A 2 "Subject Alternative Name" echo "Срок действия:" openssl x509 -in "$OUTPUT_DIR/tls.crt" -noout -dates # Шаг 10: Проверка цепочки echo echo "=== Проверка цепочки ===" if openssl verify -CAfile "$CORPORATE_CA_DIR/corporate-ca.crt" "$OUTPUT_DIR/tls.crt" >/dev/null 2>&1; then echo "✅ Цепочка сертификатов КОРРЕКТНА" else echo "❌ Цепочка сертификатов НЕКОРРЕКТНА" openssl verify -CAfile "$CORPORATE_CA_DIR/corporate-ca.crt" "$OUTPUT_DIR/tls.crt" fi # Шаг 11: Проверка соответствия ключа и сертификата echo echo "=== Проверка соответствия ключа и сертификата ===" KEY_MODULUS=$(openssl rsa -noout -modulus -in "$OUTPUT_DIR/tls.key" 2>/dev/null | openssl md5) CERT_MODULUS=$(openssl x509 -noout -modulus -in "$OUTPUT_DIR/tls.crt" | openssl md5) if [ "$KEY_MODULUS" = "$CERT_MODULUS" ]; then echo "✅ Приватный ключ и сертификат СООТВЕТСТВУЮТ" else echo "❌ Приватный ключ и сертификат НЕ СООТВЕТСТВУЮТ" fi echo echo "=== Готово! ===" echo "Сертификат готов для использования в ingress controller" echo "Для создания Kubernetes secret:" echo "kubectl create secret tls ingress-tls \\" echo " --cert=$OUTPUT_DIR/tls.crt \\" echo " --key=$OUTPUT_DIR/tls.key"Сделайте файл исполняемым:
chmod +x ./sign-ingress-tls.shЗапустите скрипт:
sudo ./sign-ingress-tls.sh
Сертификаты для ingress сгенерированы и подписаны.
Сохранение сертификата#
Сохраните сертификат и ключ в base64:
cat ingress-cert/tls.crt | base64 -w0
cat ingress-cert/tls.key | base64 -w0
В выводах команд будут отображены закодированные в Base64 сертификаты.
Добавление сертификатов в DropAppConfiguration описано в пункте «Добавление сертификатов в DropAppConfiguration».
Добавление сертификатов в DropAppConfiguration#
Добавьте сертификаты в spec.k8s.clusterTLS и spec.k8s.ingressTLS:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
...
clusterTLS:
cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0... # набор символов представлен для примера сертификата
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktL... # набор символов представлен для примера ключа
ingressTLS:
cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1... # набор символов представлен для примера сертификата
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0t... # набор символов представлен для примера ключа
...
Настройка Kube-apiserver в DropAppConfiguration#
Добавьте certSANs и подключите audit:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
...
apiServer:
certSANs:
- <certSANs-ip>
- apiserver.my-cluster.dapp.test.un.sbt
extraArgs:
audit-policy-file: "/etc/kubernetes/policies/audit-policy.yaml"
audit-log-path: "/var/log/kubernetes/audit.log"
audit-log-format: "json"
audit-log-maxbackup: "5"
audit-log-maxsize: "128"
audit-log-maxage: "7"
audit-log-mode: "batch"
extraVolumes:
- name: policies
hostPath: /etc/kubernetes/policies
mountPath: /etc/kubernetes/policies
- name: kube-audit
hostPath: /var/log/kubernetes
mountPath: /var/log/kubernetes
...
...
Настройка сети pod, сервисов и controlPlaneEndpoint#
Сеть pod и адрес control plane будут автоматически переданы в конфигурации статических pod control plane, а также в Cilium. Пример конфигурации:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
podSubnetCIDR: <podSubnetCIDR-ip>/16
serviceSubnetCIDR: <serviceSubnetCIDR-ip>/16
controlPlaneEndpoint: apiserver.my-cluster.dapp.test.un.sbt:6443
...
...
Шифрование Etcd#
Чтобы избежать утечек данных в случае компрометации Etcd, включите шифрование хранимых в Etcd секретов и configmap:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
...
etcd:
encrypt:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- aescbc:
keys:
- name: key1
secret: ...
- identity: {}
...
...
В примере используется алгоритм шифрования aescbc с собственным ключом, который необходимо указать в секции providers.aescbc.keys.secret. Ключ физически хранится в манифестах на узлах control plane.
Включение PodSecurityAdmission#
Для приведения настроек по умолчанию pod в соответствие со стандартами безопасности активируйте следующие параметры:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
...
security:
pods:
enforce: "baseline"
audit: "restricted"
warn: "baseline"
...
...
В примере используется алгоритм шифрования aescbc с собственным ключом, который необходимо указать в секции providers.aescbc.keys.secret. Манифесты AdmissionConfiguration будут автоматически созданы на узлах control plane.
Включение hubble-ui#
для мониторинга сетевых взаимодействий внутри кластера включите Hubble:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
k8s:
...
cni:
cilium:
values:
hubble:
relay:
enabled: true
ui:
enabled: true
...
...
Hubble будет доступен по адресу https://hubble.my-cluster.dapp.test.un.sbt.
Подключение каталога с пользователями#
Для подключения LDAP-каталога настройте компонент Auth. Пользователи в каталоге должны иметь группы, соответствующие ролевой модели DropApp.
Пример конфигурации с подключением IPA Server:
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
...
components:
- name: auth
tools:
- name: dex
values:
config:
connectors:
- type: ldap
name: Ipa Server
id: ldap
config:
bindDN: uid=dapp-sync-svc,cn=users,cn=accounts,dc=dapp,dc=un,dc=sbt
bindPW: ...
groupSearch:
baseDN: cn=groups,cn=accounts,dc=dapp,dc=un,dc=sbt
filter: (objectClass=groupOfNames)
nameAttr: cn
userMatchers:
- groupAttr: member
userAttr: DN
host: freeipa1.dapp.un.sbt:636
insecureNoSSL: false
insecureSkipVerify: true
userSearch:
baseDN: cn=users,cn=accounts,dc=dapp,dc=un,dc=sbt
emailAttr: mail
filter: (objectClass=person)
idAttr: DN
nameAttr: uid
preferredUsernameAttr: uid
username: uid
usernamePrompt: 'Username:'
...
Итоговая конфигурация#
Итоговый конфигурационный файл hp.sh:
complete-da.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: "my-cluster"
spec:
network:
publicDomain: dapp.test.un.sbt
# Если не используется metallb - удалите данную секцию
metallb:
pools:
- addresses: "<metallb-pool-ip>/32"
name: "dapp"
l2Advertisement: true
artifacts:
imageRegistry:
host: ...
path: ...
credentials: ...
rpmRepository:
- name: "dapp-repo"
baseUrl: http://...
gpgCheck: 1
enabled: 1
gpgKey: "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-SberLinux"
- name: "slo-baseos"
baseUrl: http://...
gpgCheck: 1
enabled: 1
gpgKey: "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-SberLinux"
- name: "slo-appstream"
baseUrl: http://...
gpgCheck: 1
enabled: 1
gpgKey: "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-SberLinux"
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_dapp"
userProvisioned:
nodes:
controlPlane:
- ip: "<controlplane1-ip>"
nodePool: "control-plane"
- ip: "<controlplane2-ip>"
nodePool: "control-plane"
- ip: "<controlplane3-ip>"
nodePool: "control-plane"
worker:
- ip: "<worker1-ip>"
nodePool: "worker"
- ip: "<worker2-ip>"
nodePool: "worker"
- ip: "<worker3-ip>"
nodePool: "worker"
- ip: "<worker4-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker5-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
- ip: "<worker6-ip>"
nodePool: "ingress"
taints:
- key: "dedicated"
value: "ingress"
effect: "NoSchedule"
k8s:
podSubnetCIDR: <podSubnetCIDR-ip>/16
serviceSubnetCIDR: <serviceSubnetCIDR-ip>/16
controlPlaneEndpoint: apiserver.my-cluster.dapp.test.un.sbt:6443
apiServer:
certSANs:
- <haproxy-ip>
- apiserver.my-cluster.dapp.test.un.sbt
extraArgs:
audit-policy-file: "/etc/kubernetes/policies/audit-policy.yaml"
audit-log-path: "/var/log/kubernetes/audit.log"
audit-log-format: "json"
audit-log-maxbackup: "5"
audit-log-maxsize: "128"
audit-log-maxage: "7"
audit-log-mode: "batch"
extraVolumes:
- name: policies
hostPath: /etc/kubernetes/policies
mountPath: /etc/kubernetes/policies
- name: kube-audit
hostPath: /var/log/kubernetes
mountPath: /var/log/kubernetes
etcd:
encrypt:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- aescbc:
keys:
- name: key1
secret: ...
- identity: {}
cni:
cilium:
values:
hubble:
relay:
enabled: true
ui:
enabled: true
clusterTLS:
cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS... # набор символов представлен для примера сертификата
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVk... # набор символов представлен для примера ключа
ingressTLS:
cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS... # набор символов представлен для примера сертификата
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRV... # набор символов представлен для примера ключа
components:
- name: auth
tools:
- name: dex
values:
config:
connectors:
- type: ldap
name: Ipa Server
id: ldap
config:
bindDN: uid=dapp-sync-svc,cn=users,cn=accounts,dc=dapp,dc=un,dc=sbt
bindPW: ...
groupSearch:
baseDN: cn=groups,cn=accounts,dc=dapp,dc=un,dc=sbt
filter: (objectClass=groupOfNames)
nameAttr: cn
userMatchers:
- groupAttr: member
userAttr: DN
host: freeipa1.dapp.un.sbt:636
insecureNoSSL: false
insecureSkipVerify: true
userSearch:
baseDN: cn=users,cn=accounts,dc=dapp,dc=un,dc=sbt
emailAttr: mail
filter: (objectClass=person)
idAttr: DN
nameAttr: uid
preferredUsernameAttr: uid
username: uid
usernamePrompt: 'Username:'
- name: load-balancer
tools:
- name: metallb
values:
speaker:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/ingress
operator: Exists
- name: ingress-controller
tools:
- name: ingress-nginx
values:
controller:
kind: DaemonSet
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/ingress
operator: Exists
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ingress"
effect: "NoSchedule"
Сохраните конфигурационный файл как da.yaml и создайте кластер:
dactl create cluster --config ./da.yaml
Установка Csi-driver-nfs#
В качестве постоянного хранилища используйте NFS. Установите Csi-driver-nfs с помощью ресурса Tool:
apiVersion: config.dropapp.ru/v1alpha1
kind: Tool
metadata:
name: csi-driver-nfs
spec:
values:
storageClass:
parameters:
server: <nfs-ip>
share: /export/nfs
mountOptions: # дополнительные опции при необходимости
- nfsvers=4.1
- hard
- proto=tcp
В результате будет создан storageClass с именем nfs-csi и VolumeSnapshotClass для создания снимков томов.
Также будут установлены все Csi-компоненты Kubernetes (Resizer, Attacher, Snapshot-controller, Node-registrar).
Теперь storageclass может быть использован при установке компонентов.
Установка компонентов#
Установка компонентов более подробно описана в разделе «Установка дополнительных компонентов».
Alerting#
Для установки компонента Alerting с постоянным хранением выполните следующие шаги:
Создайте файл
alerting-persistence.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: alerting spec: tools: - name: alertmanager values: persistence: enabled: true storageClass: nfs-csi size: 100Mi # укажите необходимый объем хранилищаПримените файл:
kubectl apply -f alerting-persistence.yaml
Monitoring#
Для установки компонента Monitoring с постоянным хранением выполните следующие шаги:
Создайте файл
monitoring-persistence.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: monitoring spec: tools: - name: grafana values: persistence: enabled: true storageClassName: nfs-csi size: 1Gi # укажите необходимый объем хранилища - name: victoria-metrics-k8s-stack values: vmcluster: spec: vmstorage: storage: volumeClaimTemplate: spec: storageClassName: nfs-csi resources: requests: storage: 10Gi # укажите необходимый объем хранилища vmselect: storage: volumeClaimTemplate: spec: storageClassName: nfs-csi resources: requests: storage: 2Gi # укажите необходимый объем хранилищаПримените файл:
kubectl apply -f monitoring-persistence.yaml
Logging#
Для установки компонента Logging с постоянным хранением выполните следующие шаги:
Создайте файл
logging-persistence.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: logging spec: tools: - name: vector-aggregator values: persistence: enabled: true storageClassName: nfs-csi size: 10Gi # укажите необходимый объем хранилищаПримените файл:
kubectl apply -f logging-persistence.yaml
Security#
Для установки компонента Security выполните следующие шаги:
Создайте файл
component-security.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: securityПримените файл:
kubectl apply -f component-security.yaml
GitOps#
Для установки компонента GitOps выполните следующие шаги:
Создайте файл
gitops.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: gitopsПримените файл:
kubectl apply -f gitops.yaml
DevOps#
Для установки компонента DevOps выполните следующие шаги:
Создайте файл
devops.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: devopsПримените файл:
kubectl apply -f devops.yaml
AiOps#
Для установки компонента AiOps выполните следующие шаги:
Создайте файл
aiops.yaml:apiVersion: config.dropapp.ru/v1alpha1 kind: Component metadata: name: aiopsПримените файл:
kubectl apply -f aiops.yaml