Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef904ca952 | |||
| e8dc61f5a1 | |||
| 62f12c8ce1 | |||
| a9cafb629c | |||
| abdc7bd70e | |||
| 7fd1755a7d |
Submodule beecloud-docs deleted from df88416247
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "docs",
|
"name": "docs",
|
||||||
"version": "0.6.5-main",
|
"version": "0.6.4-link",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "docs",
|
"name": "docs",
|
||||||
"version": "0.6.5-main",
|
"version": "0.6.4-link",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@beeline/design-tokens": "^1.31.6",
|
"@beeline/design-tokens": "^1.31.6",
|
||||||
|
|||||||
+236
-236
@@ -2,7 +2,7 @@ import { defineConfig } from 'vitepress'
|
|||||||
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
|
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
|
||||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||||
import { overrideComponents } from './override-components'
|
import { overrideComponents } from './override-components'
|
||||||
import { resolve } from 'node:path'
|
import { resolve } from 'path'
|
||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
const gitlab = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
const gitlab = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
@@ -41,7 +41,240 @@ const gitlab = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|||||||
`
|
`
|
||||||
|
|
||||||
const new_version = process.env?.VITE_NEW_VERSION;
|
const new_version = process.env?.VITE_NEW_VERSION;
|
||||||
console.log({ base: typeof new_version !== 'undefined' ? '/' : '/docs/' })
|
|
||||||
|
const sidebarConfig = {
|
||||||
|
'/platform/': [
|
||||||
|
{
|
||||||
|
text: 'Платформа Beeline Cloud', link: '/platform/index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Обзор', link: '/platform/about.md'},
|
||||||
|
{text: 'Техническая поддержка', link: '/platform/support/support-overview.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'/start/': [
|
||||||
|
{
|
||||||
|
text: 'Начало работы в Beeline Cloud', link: '/start/index.md',
|
||||||
|
},
|
||||||
|
{text: 'Начать работу', link: '/start/getting-started.md'},
|
||||||
|
{text: 'Бесплатный период', link: '/start/trial.md'},
|
||||||
|
{text: 'Платное использование', link: '/start/organization.md'},
|
||||||
|
],
|
||||||
|
// '/billing/': [
|
||||||
|
|
||||||
|
// ],
|
||||||
|
'/backups/': [
|
||||||
|
{
|
||||||
|
text: 'Резервное копирование', link: '/backups/index.md',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Обзор сервиса', link: '/backups/about.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Квоты и лимиты', link: '/backups/backup-quatos.md'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{text: 'Резервное копирование виртуальных машин Beeline Cloud', link: '/backups/backup-internal-infra.md'},
|
||||||
|
{text: 'Резервное копирование собственной инфраструктуры в Beeline Cloud', link: '/backups/backup-external-infra.md'},
|
||||||
|
{text: 'Каталог резервных копий', link: '/backups/view-backups.md'},
|
||||||
|
|
||||||
|
],
|
||||||
|
'/vdc/': [
|
||||||
|
{
|
||||||
|
text: 'Виртуальные дата-центры на VMware', link: '/vdc/index.md',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Обзор сервиса', link: '/vdc/vdc-overview.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'О сервисе', link: '/vdc/vdc-about.md' },
|
||||||
|
{ text: 'Техническое описание', link: '/vdc/vdc-tech.md' },
|
||||||
|
{ text: 'Квоты и лимиты', link: '/vdc/vdc-quatos.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Быстрый старт', link: '/vdc/vdc-getting-started.md'
|
||||||
|
},
|
||||||
|
|
||||||
|
{ text: 'Виртуальные дата-центры', link: '/vdc/vdc-how-to/vdc-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Создание дата-центра', link: '/vdc/vdc-how-to/vdc-create.md' },
|
||||||
|
{ text: 'Вход в дата-центр', link: '/vdc/vdc-how-to/vdc-enter.md' },
|
||||||
|
{ text: 'Управление дата-центром', link: '/vdc/vdc-how-to/vdc-manage.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Виртуальные машины', link: '/vdc/vdc-how-to/vm/vm-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Создание ВМ', link: '/vdc/vdc-how-to/vm/create-vm.md'},
|
||||||
|
{text: 'Создание vApp', link: '/vdc/vdc-how-to/vm/create-vapp.md'},
|
||||||
|
{text: 'Управление состоянием ВМ', link: '/vdc/vdc-how-to/vm/manage-vm.md'},
|
||||||
|
{text: 'Клонирование ВМ', link: '/vdc/vdc-how-to/vm/clone-vm.md'},
|
||||||
|
{text: 'Изменение конфигурации ВМ', link: '/vdc/vdc-how-to/vm/edit-vm.md'},
|
||||||
|
{text: 'Удаление ВМ', link: '/vdc/vdc-how-to/vm/delete-vm.md'},
|
||||||
|
{text: 'Группы размещения', link: '/vdc/vdc-how-to/vm/create-affinity-rules.md'},
|
||||||
|
{text: 'Снимки ВМ', link: '/vdc/vdc-how-to/vm/create-snapshot.md'},
|
||||||
|
{text: 'VMware Tools', link: '/vdc/vdc-how-to/vm/vmware-tools.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Диски', link: '/vdc/vdc-how-to/disks/disks-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Обзор', link: '/vdc/vdc-how-to/disks/about.md'},
|
||||||
|
{text: 'Создание диска', link: '/vdc/vdc-how-to/disks/create-disk.md'},
|
||||||
|
{text: 'Проверка состояния диска', link: '/vdc/vdc-how-to/disks/view-disk.md'},
|
||||||
|
{text: 'Управление выделенными дисками', link: '/vdc/vdc-how-to/disks/attach-disk.md'},
|
||||||
|
{text: 'Изменение политики хранения дисков ВМ', link: '/vdc/vdc-how-to/disks/change-storage-policy-of-vm.md'},
|
||||||
|
{text: 'Редактирование параметров диска', link: '/vdc/vdc-how-to/disks/edit-disk.md'},
|
||||||
|
{text: 'Удаление диска', link: '/vdc/vdc-how-to/disks/delete-disk.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Сети', link: '/vdc/vdc-how-to/networks/networks-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Обзор', link: '/vdc/vdc-how-to/networks/about.md'},
|
||||||
|
{text: 'Настройка доступа к ВМ из интернета', link: '/vdc/vdc-how-to/networks/allow-external-connections-to-vm.md'},
|
||||||
|
{text: 'Подключение ВМ в vApp к сети', link: '/vdc/vdc-how-to/networks/connect-vapp-to-network.md'},
|
||||||
|
{text: 'Подключение ВМ к интернету', link: '/vdc/vdc-how-to/networks/connect-vm-to-network.md'},
|
||||||
|
{text: 'Создание сети в организации и подключение к Edge Gateway', link: '/vdc/vdc-how-to/networks/create-network.md'},
|
||||||
|
{text: 'Подключение сети к Edge Gateway', link: '/vdc/vdc-how-to/networks/connect-to-edge-gateway.md'},
|
||||||
|
{text: 'Создание Pre-Shared Key', link: '/vdc/vdc-how-to/networks/create-psk.md'},
|
||||||
|
{ text: 'Настройка site-to-site подключения с помощью IPSec', link: '/vdc/vdc-how-to/networks/how-to-setup-ipsec-vpn.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Настройка ASAv', link: '/vdc/vdc-how-to/networks/ipsec/asav.md'},
|
||||||
|
{text: 'Настройка CSR 1000v', link: '/vdc/vdc-how-to/networks/ipsec/csr1000v.md'},
|
||||||
|
{text: 'Настройка Fortigate', link: '/vdc/vdc-how-to/networks/ipsec/fortigate.md'},
|
||||||
|
{text: 'Проверить сетевую связанность', link: '/vdc/vdc-how-to/networks/ipsec/check-vpn-status.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Пользователи и роли', link: '/vdc/vdc-how-to/users/users-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Ролевая модель', link: '/vdc/vdc-how-to/users/roles.md'},
|
||||||
|
{text: 'Создание пользователя', link: '/vdc/vdc-how-to/users/add-user.md'},
|
||||||
|
{text: 'Изменение пароля пользователя', link: '/vdc/vdc-how-to/users/change-users-password.md'},
|
||||||
|
{text: 'Настройка квот', link: '/vdc/vdc-how-to/users/quotas.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Двухфакторная аутентификация', link: '/vdc/vdc-how-to/vdc-2fa.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{text: 'Подключение 2FA', link: '/vdc/vdc-how-to/vdc-2fa-start.md'},
|
||||||
|
{text: 'Управление 2FA', link: '/vdc/vdc-how-to/vdc-2fa-manage.md'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// { text: 'Тарификация', link: '/vdc/vdc-tarif.md' },
|
||||||
|
'/compute/': [
|
||||||
|
{
|
||||||
|
text: 'Виртуальные машины', link: '/compute/index.md',
|
||||||
|
},
|
||||||
|
{ text: 'Обзор сервиса', link: '/compute/compute-overview-index.md' ,
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Техническое описание', link: '/compute/compute-overview.md' },
|
||||||
|
{ text: 'Квоты и лимиты', link: '/compute/compute-quatos.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{text: 'Быстрый старт', link: '/compute/compute-getting-started.md', excludeFromIndex: true },
|
||||||
|
{ text: 'Виртуальные машины', link: '/compute/compute-how-to/compute-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Создание ВМ', link: '/compute/compute-how-to/compute-servers-create.md' },
|
||||||
|
{ text: 'Создание ВМ джамп-хоста', link: '/compute/compute-how-to/compute-servers-jump-create.md' },
|
||||||
|
{ text: 'Подключение к ВМ', link: '/compute/compute-how-to/compute-connect-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Подключение по SSH по внешнему IP-адресу с помощью ключевой пары', link: '/compute/compute-how-to/compute-connect-public.md'},
|
||||||
|
{ text: 'Подключение по SSH по внутреннему IP-адресу с помощью ключевой пары', link: '/compute/compute-how-to/compute-connect-inside.md' },
|
||||||
|
{ text: 'Подключение по SSH по логину и паролю', link: '/compute/compute-how-to/compute-connect-pwd.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'Управление ВМ', link: '/compute/compute-how-to/compute-servers-manage.md' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ text: 'Диски', link: '/compute/compute-how-to/compute-disks/compute-disk-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Обзор', link: '/compute/compute-how-to/compute-disks/compute-disk-about.md' },
|
||||||
|
{ text: 'Создание диска', link: '/compute/compute-how-to/compute-disks/compute-disk-create.md' },
|
||||||
|
{ text: 'Управление дисками', link: '/compute/compute-how-to/compute-disks/compute-disk-manage.md' },
|
||||||
|
{ text: 'Удаление диска', link: '/compute/compute-how-to/compute-disks/compute-disk-del.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Обзор', link: '/compute/compute-how-to/compute-ip/compute-ip-about.md' },
|
||||||
|
{ text: 'Просмотр IP-адресов', link: '/compute/compute-how-to/compute-ip/compute-ip-view.md' },
|
||||||
|
{ text: 'Создание IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-create.md' },
|
||||||
|
{ text: 'Управление IP-адресами', link: '/compute/compute-how-to/compute-ip/compute-ip-manager.md' },
|
||||||
|
{ text: 'Удаление IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-del.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'Группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Обзор', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-about.md'},
|
||||||
|
{ text: 'Создание группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-create.md'},
|
||||||
|
{ text: 'Управление группами размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-manager.md' },
|
||||||
|
{ text: 'Удаление группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-del.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'Сети', link: '/compute/compute-how-to/compute-network/compute-network-index.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Настройка site-to-site VPN с помощью VyOS', link: '/compute/compute-how-to/compute-network/compute-vpn-vyos.md' },
|
||||||
|
{ text: 'Подключение ВМ закрытого контура к интернету', link: '/compute/compute-how-to/compute-network/compute-network-inside.md' },
|
||||||
|
],
|
||||||
|
excludeFromIndex: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'/admin/': [
|
||||||
|
{
|
||||||
|
text: 'Администрирование', link: '/admin/index.md',
|
||||||
|
},
|
||||||
|
{text: 'Управление ключевыми парами', link: '/admin/ssh.md'},
|
||||||
|
],
|
||||||
|
'/vdi/': [
|
||||||
|
{
|
||||||
|
text: 'Виртуальные рабочие столы', link: '/vdi/index.md',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Обзор сервиса', link: '/vdi/vdi-overview.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'О сервисе', link: '/vdi/vdi-about.md' },
|
||||||
|
{ text: 'Техническое описание', link: '/vdi/vdi-tech.md' },
|
||||||
|
{ text: 'Квоты и лимиты', link: '/vdi/vdi-quatos.md' },
|
||||||
|
{ text: 'Тарификация', link: '/vdi/vdi-tarif.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Заказ виртуальных рабочих столов', link: '/vdi/vdi-how-to/vdi-create.md'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Настройка сервиса', link: '/vdi/vdi-how-to/vdi-nastroika.md',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Настройка интеграции с Active Directory', link: '/vdi/vdi-how-to/vdi-connect-to-ad.md' },
|
||||||
|
{ text: 'Настройка сети', link: '/vdi/vdi-how-to/vdi-interconnect.md' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// text: 'Gold-образ', link: '/vdi/vdi-how-to/vdi-gold.md'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
text: 'Подключение к виртуальному рабочему месту', link: '/vdi/vdi-how-to/vdi-connect.md'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
// https://vitepress.dev/reference/site-config
|
// https://vitepress.dev/reference/site-config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -140,240 +373,7 @@ export default defineConfig({
|
|||||||
outline: {
|
outline: {
|
||||||
label: 'Содержание'
|
label: 'Содержание'
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: sidebarConfig,
|
||||||
'/platform/': [
|
|
||||||
{
|
|
||||||
text: 'Платформа Beeline Cloud', link: '/platform/index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Обзор', link: '/platform/about.md'},
|
|
||||||
{text: 'Техническая поддержка', link: '/platform/support/support-overview.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'/start/': [
|
|
||||||
{
|
|
||||||
text: 'Начало работы в Beeline Cloud', link: '/start/index.md',
|
|
||||||
},
|
|
||||||
{text: 'Начать работу', link: '/start/getting-started.md'},
|
|
||||||
{text: 'Бесплатный период', link: '/start/trial.md'},
|
|
||||||
{text: 'Платное использование', link: '/start/organization.md'},
|
|
||||||
],
|
|
||||||
// '/billing/': [
|
|
||||||
|
|
||||||
// ],
|
|
||||||
'/backups/': [
|
|
||||||
{
|
|
||||||
text: 'Резервное копирование', link: '/backups/index.md',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Обзор сервиса', link: '/backups/backups-overview.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'О сервисе', link: '/backups/about.md'},
|
|
||||||
{text: 'Квоты и лимиты', link: '/backups/backup-quatos.md'},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{text: 'Резервное копирование виртуальных машин Beeline Cloud', link: '/backups/backup-internal-infra.md'},
|
|
||||||
{text: 'Резервное копирование собственной инфраструктуры в Beeline Cloud', link: '/backups/backup-external-infra.md'},
|
|
||||||
{text: 'Каталог резервных копий', link: '/backups/view-backups.md'},
|
|
||||||
|
|
||||||
],
|
|
||||||
'/vdc/': [
|
|
||||||
{
|
|
||||||
text: 'Виртуальные дата-центры на VMware', link: '/vdc/index.md',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Обзор сервиса', link: '/vdc/vdc-overview.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'О сервисе', link: '/vdc/vdc-about.md' },
|
|
||||||
{ text: 'Техническое описание', link: '/vdc/vdc-tech.md' },
|
|
||||||
{ text: 'Квоты и лимиты', link: '/vdc/vdc-quatos.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Быстрый старт', link: '/vdc/vdc-getting-started.md'
|
|
||||||
},
|
|
||||||
|
|
||||||
{ text: 'Виртуальные дата-центры', link: '/vdc/vdc-how-to/vdc-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Создание дата-центра', link: '/vdc/vdc-how-to/vdc-create.md' },
|
|
||||||
{ text: 'Вход в дата-центр', link: '/vdc/vdc-how-to/vdc-enter.md' },
|
|
||||||
{ text: 'Управление дата-центром', link: '/vdc/vdc-how-to/vdc-manage.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Виртуальные машины', link: '/vdc/vdc-how-to/vm/vm-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Создание ВМ', link: '/vdc/vdc-how-to/vm/create-vm.md'},
|
|
||||||
{text: 'Создание vApp', link: '/vdc/vdc-how-to/vm/create-vapp.md'},
|
|
||||||
{text: 'Управление состоянием ВМ', link: '/vdc/vdc-how-to/vm/manage-vm.md'},
|
|
||||||
{text: 'Клонирование ВМ', link: '/vdc/vdc-how-to/vm/clone-vm.md'},
|
|
||||||
{text: 'Изменение конфигурации ВМ', link: '/vdc/vdc-how-to/vm/edit-vm.md'},
|
|
||||||
{text: 'Удаление ВМ', link: '/vdc/vdc-how-to/vm/delete-vm.md'},
|
|
||||||
{text: 'Группы размещения', link: '/vdc/vdc-how-to/vm/create-affinity-rules.md'},
|
|
||||||
{text: 'Снимки ВМ', link: '/vdc/vdc-how-to/vm/create-snapshot.md'},
|
|
||||||
{text: 'VMware Tools', link: '/vdc/vdc-how-to/vm/vmware-tools.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Диски', link: '/vdc/vdc-how-to/disks/disks-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Обзор', link: '/vdc/vdc-how-to/disks/about.md'},
|
|
||||||
{text: 'Создание диска', link: '/vdc/vdc-how-to/disks/create-disk.md'},
|
|
||||||
{text: 'Проверка состояния диска', link: '/vdc/vdc-how-to/disks/view-disk.md'},
|
|
||||||
{text: 'Управление выделенными дисками', link: '/vdc/vdc-how-to/disks/attach-disk.md'},
|
|
||||||
{text: 'Изменение политики хранения дисков ВМ', link: '/vdc/vdc-how-to/disks/change-storage-policy-of-vm.md'},
|
|
||||||
{text: 'Редактирование параметров диска', link: '/vdc/vdc-how-to/disks/edit-disk.md'},
|
|
||||||
{text: 'Удаление диска', link: '/vdc/vdc-how-to/disks/delete-disk.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Сети', link: '/vdc/vdc-how-to/networks/networks-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Обзор', link: '/vdc/vdc-how-to/networks/about.md'},
|
|
||||||
{text: 'Настройка доступа к ВМ из интернета', link: '/vdc/vdc-how-to/networks/allow-external-connections-to-vm.md'},
|
|
||||||
{text: 'Подключение ВМ в vApp к сети', link: '/vdc/vdc-how-to/networks/connect-vapp-to-network.md'},
|
|
||||||
{text: 'Подключение ВМ к интернету', link: '/vdc/vdc-how-to/networks/connect-vm-to-network.md'},
|
|
||||||
{text: 'Создание сети в организации и подключение к Edge Gateway', link: '/vdc/vdc-how-to/networks/create-network.md'},
|
|
||||||
{text: 'Подключение сети к Edge Gateway', link: '/vdc/vdc-how-to/networks/connect-to-edge-gateway.md'},
|
|
||||||
{text: 'Создание Pre-Shared Key', link: '/vdc/vdc-how-to/networks/create-psk.md'},
|
|
||||||
{ text: 'Настройка site-to-site подключения с помощью IPSec', link: '/vdc/vdc-how-to/networks/how-to-setup-ipsec-vpn.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Настройка IPSec VPN', link: '/vdc/vdc-how-to/networks/ipsec/setup-ipsec-vpn.md'},
|
|
||||||
{text: 'Настройка ASAv', link: '/vdc/vdc-how-to/networks/ipsec/asav.md'},
|
|
||||||
{text: 'Настройка CSR 1000v', link: '/vdc/vdc-how-to/networks/ipsec/csr1000v.md'},
|
|
||||||
{text: 'Настройка Fortigate', link: '/vdc/vdc-how-to/networks/ipsec/fortigate.md'},
|
|
||||||
{text: 'Проверить сетевую связанность', link: '/vdc/vdc-how-to/networks/ipsec/check-vpn-status.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Пользователи и роли', link: '/vdc/vdc-how-to/users/users-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Ролевая модель', link: '/vdc/vdc-how-to/users/roles.md'},
|
|
||||||
{text: 'Создание пользователя', link: '/vdc/vdc-how-to/users/add-user.md'},
|
|
||||||
{text: 'Изменение пароля пользователя', link: '/vdc/vdc-how-to/users/change-users-password.md'},
|
|
||||||
{text: 'Настройка квот', link: '/vdc/vdc-how-to/users/quotas.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Двухфакторная аутентификация', link: '/vdc/vdc-how-to/vdc-2fa.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{text: 'Подключение 2FA', link: '/vdc/vdc-how-to/vdc-2fa-start.md'},
|
|
||||||
{text: 'Управление 2FA', link: '/vdc/vdc-how-to/vdc-2fa-manage.md'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// { text: 'Тарификация', link: '/vdc/vdc-tarif.md' },
|
|
||||||
'/compute/': [
|
|
||||||
{
|
|
||||||
text: 'Виртуальные машины', link: '/compute/index.md',
|
|
||||||
},
|
|
||||||
{ text: 'Обзор сервиса', link: '/compute/compute-overview-index.md' ,
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Техническое описание', link: '/compute/compute-overview.md' },
|
|
||||||
{ text: 'Квоты и лимиты', link: '/compute/compute-quatos.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{text: 'Быстрый старт', link: '/compute/compute-getting-started.md'},
|
|
||||||
{ text: 'Виртуальные машины', link: '/compute/compute-how-to/compute-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Создание ВМ', link: '/compute/compute-how-to/compute-servers-create.md' },
|
|
||||||
{ text: 'Создание ВМ джамп-хоста', link: '/compute/compute-how-to/compute-servers-jump-create.md' },
|
|
||||||
{ text: 'Подключение к ВМ', link: '/compute/compute-how-to/compute-connect-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Подключение по SSH по внешнему IP-адресу с помощью ключевой пары', link: '/compute/compute-how-to/compute-connect-public.md'},
|
|
||||||
{ text: 'Подключение по SSH по внутреннему IP-адресу с помощью ключевой пары', link: '/compute/compute-how-to/compute-connect-inside.md' },
|
|
||||||
{ text: 'Подключение по SSH по логину и паролю', link: '/compute/compute-how-to/compute-connect-pwd.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ text: 'Управление ВМ', link: '/compute/compute-how-to/compute-servers-manage.md' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ text: 'Диски', link: '/compute/compute-how-to/compute-disks/compute-disk-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Обзор', link: '/compute/compute-how-to/compute-disks/compute-disk-about.md' },
|
|
||||||
{ text: 'Создание диска', link: '/compute/compute-how-to/compute-disks/compute-disk-create.md' },
|
|
||||||
{ text: 'Управление дисками', link: '/compute/compute-how-to/compute-disks/compute-disk-manage.md' },
|
|
||||||
{ text: 'Удаление диска', link: '/compute/compute-how-to/compute-disks/compute-disk-del.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ text: 'IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Обзор', link: '/compute/compute-how-to/compute-ip/compute-ip-about.md' },
|
|
||||||
{ text: 'Просмотр IP-адресов', link: '/compute/compute-how-to/compute-ip/compute-ip-view.md' },
|
|
||||||
{ text: 'Создание IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-create.md' },
|
|
||||||
{ text: 'Управление IP-адресами', link: '/compute/compute-how-to/compute-ip/compute-ip-manager.md' },
|
|
||||||
{ text: 'Удаление IP-адреса', link: '/compute/compute-how-to/compute-ip/compute-ip-del.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ text: 'Группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Обзор', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-about.md'},
|
|
||||||
{ text: 'Создание группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-create.md'},
|
|
||||||
{ text: 'Управление группами размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-manager.md' },
|
|
||||||
{ text: 'Удаление группы размещения', link: '/compute/compute-how-to/compute-placement-groups/compute-placement-groups-del.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ text: 'Сети', link: '/compute/compute-how-to/compute-network/compute-network-index.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Настройка site-to-site VPN с помощью VyOS', link: '/compute/compute-how-to/compute-network/compute-vpn-vyos.md' },
|
|
||||||
{ text: 'Подключение ВМ закрытого контура к интернету', link: '/compute/compute-how-to/compute-network/compute-network-inside.md' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'/admin/': [
|
|
||||||
{
|
|
||||||
text: 'Администрирование', link: '/admin/index.md',
|
|
||||||
},
|
|
||||||
{text: 'Управление ключевыми парами', link: '/admin/ssh.md'},
|
|
||||||
],
|
|
||||||
'/vdi/': [
|
|
||||||
{
|
|
||||||
text: 'Виртуальные рабочие столы', link: '/vdi/index.md',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Обзор сервиса', link: '/vdi/vdi-overview.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'О сервисе', link: '/vdi/vdi-about.md' },
|
|
||||||
{ text: 'Техническое описание', link: '/vdi/vdi-tech.md' },
|
|
||||||
{ text: 'Квоты и лимиты', link: '/vdi/vdi-quatos.md' },
|
|
||||||
{ text: 'Тарификация', link: '/vdi/vdi-tarif.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Заказ виртуальных рабочих столов', link: '/vdi/vdi-how-to/vdi-create.md'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Настройка сервиса', link: '/vdi/vdi-how-to/vdi-nastroika.md',
|
|
||||||
collapsed: true,
|
|
||||||
items: [
|
|
||||||
{ text: 'Настройка интеграции с Active Directory', link: '/vdi/vdi-how-to/vdi-connect-to-ad.md' },
|
|
||||||
{ text: 'Настройка сети', link: '/vdi/vdi-how-to/vdi-interconnect.md' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// text: 'Gold-образ', link: '/vdi/vdi-how-to/vdi-gold.md'
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
text: 'Подключение к виртуальному рабочему месту', link: '/vdi/vdi-how-to/vdi-connect.md'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import type { Plugin } from 'vite'
|
||||||
|
import type { SidebarItem } from './utils/types'
|
||||||
|
import { processAllFiles } from './hook/process-files'
|
||||||
|
|
||||||
|
export const autoSectionLinksPlugin = (
|
||||||
|
srcDir: string,
|
||||||
|
sidebarConfig: Record<string, SidebarItem[]>
|
||||||
|
): Plugin => ({
|
||||||
|
name: 'auto-section-links',
|
||||||
|
buildStart: () => {
|
||||||
|
processAllFiles(srcDir, sidebarConfig)
|
||||||
|
},
|
||||||
|
configureServer: () => {
|
||||||
|
processAllFiles(srcDir, sidebarConfig)
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const INDEX_FILE = 'index.md'
|
||||||
|
export const INDEX_FILE_PATTERN = /-index\.md$|index\.md$/
|
||||||
|
export const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---/
|
||||||
|
export const SECTION_LINK_KEYS = ['title', 'link', 'description'] as const
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { existsSync } from 'fs'
|
||||||
|
import { relative, resolve } from 'path'
|
||||||
|
import type { SidebarItem } from '../utils/types'
|
||||||
|
import { findMarkdownFiles } from '../utils/file-finder'
|
||||||
|
import { processIndexFile, processPageWithItems } from '../utils/file-processor'
|
||||||
|
import { INDEX_FILE, INDEX_FILE_PATTERN } from '../constants'
|
||||||
|
|
||||||
|
export const processAllFiles = (
|
||||||
|
srcDir: string,
|
||||||
|
sidebarConfig: Record<string, SidebarItem[]>
|
||||||
|
) => {
|
||||||
|
const srcPath = resolve(srcDir)
|
||||||
|
|
||||||
|
for (const [folderPath, items] of Object.entries(sidebarConfig)) {
|
||||||
|
const normalizedFolder = folderPath.replace(/^\/+|\/+$/g, '')
|
||||||
|
const folderFullPath = resolve(srcPath, normalizedFolder)
|
||||||
|
|
||||||
|
if (!existsSync(folderFullPath)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const mdFiles = findMarkdownFiles(folderFullPath)
|
||||||
|
|
||||||
|
for (const filePath of mdFiles) {
|
||||||
|
const fileName = filePath.split(/[/\\]/).pop() || ''
|
||||||
|
const relativePath = relative(srcPath, filePath).replace(/\\/g, '/')
|
||||||
|
const normalizedPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`
|
||||||
|
|
||||||
|
if (fileName === INDEX_FILE) {
|
||||||
|
processIndexFile(filePath, items, srcPath)
|
||||||
|
} else if (INDEX_FILE_PATTERN.test(fileName) && fileName !== INDEX_FILE) {
|
||||||
|
processPageWithItems(filePath, items, srcPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { readFileSync, existsSync } from 'fs'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
import { parseFrontmatter } from './frontmatter'
|
||||||
|
|
||||||
|
export const getPageDescription = (filePath: string, srcDir: string) => {
|
||||||
|
try {
|
||||||
|
const fullPath = resolve(srcDir, filePath.replace(/^\//, ''))
|
||||||
|
if (!existsSync(fullPath)) return undefined
|
||||||
|
|
||||||
|
const fileContent = readFileSync(fullPath, 'utf-8')
|
||||||
|
const { frontmatter } = parseFrontmatter(fileContent)
|
||||||
|
|
||||||
|
return frontmatter.description as string | undefined
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { readdirSync, statSync } from 'fs'
|
||||||
|
import { join } from 'path'
|
||||||
|
|
||||||
|
export const findMarkdownFiles = (dir: string) => {
|
||||||
|
const files: string[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const entries = readdirSync(dir)
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = join(dir, entry)
|
||||||
|
const stat = statSync(fullPath)
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
files.push(...findMarkdownFiles(fullPath))
|
||||||
|
} else if (entry.endsWith('.md')) {
|
||||||
|
files.push(fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
|
||||||
|
return files
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
||||||
|
import { relative, resolve } from 'path'
|
||||||
|
import type { SidebarItem } from './types'
|
||||||
|
import { parseFrontmatter, stringifyFrontmatter } from './frontmatter'
|
||||||
|
import { mergeSectionLinks, extractTopLevelLinks, extractItemsForPage } from './links'
|
||||||
|
import { normalizeLink } from './path-utils'
|
||||||
|
import { SectionLinkListItem } from '../../theme/components/SectionLinkList/SectionLinkList.types'
|
||||||
|
|
||||||
|
const removeDuplicates = (links: SectionLinkListItem[]) => {
|
||||||
|
const result: SectionLinkListItem[] = []
|
||||||
|
const seenLinks = new Set<string>()
|
||||||
|
|
||||||
|
for (const link of links) {
|
||||||
|
if (link.link) {
|
||||||
|
const normalized = normalizeLink(link.link)
|
||||||
|
if (!seenLinks.has(normalized)) {
|
||||||
|
seenLinks.add(normalized)
|
||||||
|
result.push(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasChanges = (
|
||||||
|
existingLinks: SectionLinkListItem[],
|
||||||
|
mergedLinks: SectionLinkListItem[]
|
||||||
|
) => {
|
||||||
|
if (existingLinks.length !== mergedLinks.length) return true
|
||||||
|
|
||||||
|
const existingSet = new Set(
|
||||||
|
existingLinks
|
||||||
|
.filter(link => link.link)
|
||||||
|
.map(link => `${normalizeLink(link.link!)}|${link.title}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const mergedSet = new Set(
|
||||||
|
mergedLinks
|
||||||
|
.filter(link => link.link)
|
||||||
|
.map(link => `${normalizeLink(link.link!)}|${link.title}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existingSet.size !== mergedSet.size) return true
|
||||||
|
|
||||||
|
for (const item of existingSet) {
|
||||||
|
if (!mergedSet.has(item)) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export const processIndexFile = (
|
||||||
|
filePath: string,
|
||||||
|
sidebarItems: SidebarItem[],
|
||||||
|
srcDir: string
|
||||||
|
) => {
|
||||||
|
if (!existsSync(filePath)) return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileContent = readFileSync(filePath, 'utf-8')
|
||||||
|
const { frontmatter, content } = parseFrontmatter(fileContent)
|
||||||
|
|
||||||
|
const relativePath = relative(srcDir, filePath).replace(/\\/g, '/')
|
||||||
|
const normalizedPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`
|
||||||
|
|
||||||
|
const existingLinks = removeDuplicates(
|
||||||
|
Array.isArray(frontmatter.section_links) ? [...frontmatter.section_links] : []
|
||||||
|
)
|
||||||
|
const newLinks = extractTopLevelLinks(sidebarItems, normalizedPath, srcDir)
|
||||||
|
|
||||||
|
if (!newLinks.length) return false
|
||||||
|
|
||||||
|
const mergedLinks = removeDuplicates(mergeSectionLinks(existingLinks, newLinks))
|
||||||
|
|
||||||
|
if (!hasChanges(existingLinks, mergedLinks)) return false
|
||||||
|
|
||||||
|
frontmatter.section_links = mergedLinks
|
||||||
|
writeFileSync(filePath, stringifyFrontmatter(frontmatter, content), 'utf-8')
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const processPageWithItems = (
|
||||||
|
filePath: string,
|
||||||
|
sidebarItems: SidebarItem[],
|
||||||
|
srcDir: string
|
||||||
|
) => {
|
||||||
|
if (!existsSync(filePath)) return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileContent = readFileSync(filePath, 'utf-8')
|
||||||
|
const { frontmatter, content } = parseFrontmatter(fileContent)
|
||||||
|
|
||||||
|
const relativePath = relative(srcDir, filePath).replace(/\\/g, '/')
|
||||||
|
const normalizedPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`
|
||||||
|
|
||||||
|
const existingLinks = removeDuplicates(
|
||||||
|
Array.isArray(frontmatter.section_links) ? [...frontmatter.section_links] : []
|
||||||
|
)
|
||||||
|
const newLinks = extractItemsForPage(sidebarItems, normalizedPath, srcDir)
|
||||||
|
|
||||||
|
const mergedLinks = newLinks.length > 0
|
||||||
|
? removeDuplicates(mergeSectionLinks(existingLinks, newLinks))
|
||||||
|
: []
|
||||||
|
|
||||||
|
if (!hasChanges(existingLinks, mergedLinks)) return false
|
||||||
|
|
||||||
|
frontmatter.section_links = mergedLinks
|
||||||
|
writeFileSync(filePath, stringifyFrontmatter(frontmatter, content), 'utf-8')
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import type { Frontmatter } from './types'
|
||||||
|
import { SECTION_LINK_KEYS, FRONTMATTER_REGEX } from '../constants'
|
||||||
|
import { SectionLinkListItem } from '../../theme/components/SectionLinkList/SectionLinkList.types'
|
||||||
|
|
||||||
|
export const parseFrontmatter = (content: string) => {
|
||||||
|
const frontmatterMatch = content.match(FRONTMATTER_REGEX)
|
||||||
|
if (!frontmatterMatch) {
|
||||||
|
const cleanContent = content.replace(/^---[\s\S]*?---\s*\n*/g, '').trim()
|
||||||
|
return { frontmatter: {}, content: cleanContent || content }
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, frontmatterText] = frontmatterMatch
|
||||||
|
const frontmatterEnd = frontmatterMatch[0].length
|
||||||
|
let cleanContent = content.slice(frontmatterEnd)
|
||||||
|
cleanContent = cleanContent.replace(/^---[\s\S]*?---\s*\n*/g, '').trim()
|
||||||
|
if (!cleanContent) {
|
||||||
|
cleanContent = content.slice(frontmatterEnd).replace(/^---[\s\S]*?---\s*\n*/g, '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
const frontmatter: Frontmatter = {}
|
||||||
|
const lines = frontmatterText.split('\n')
|
||||||
|
let currentKey: string | undefined
|
||||||
|
let currentValue: SectionLinkListItem[] = []
|
||||||
|
let currentItem: Record<string, string> | undefined
|
||||||
|
let inArray = false
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const trimmed = line.trim()
|
||||||
|
if (trimmed && !trimmed.startsWith('#')) {
|
||||||
|
const lineIndent = line.match(/^(\s*)/)?.[1]?.length ?? 0
|
||||||
|
|
||||||
|
if (lineIndent === 0 && trimmed.includes(':')) {
|
||||||
|
if (inArray && currentKey) {
|
||||||
|
frontmatter[currentKey] = currentValue
|
||||||
|
currentValue = []
|
||||||
|
inArray = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const colonMatch = trimmed.match(/^([^:]+):\s*(.*)$/)
|
||||||
|
if (colonMatch) {
|
||||||
|
const [, key, value] = colonMatch
|
||||||
|
currentKey = key.trim()
|
||||||
|
const trimmedValue = value.trim()
|
||||||
|
|
||||||
|
if (trimmedValue === '') {
|
||||||
|
inArray = true
|
||||||
|
currentValue = []
|
||||||
|
} else {
|
||||||
|
frontmatter[currentKey] = trimmedValue.replace(/^["']|["']$/g, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lineIndent === 2 && trimmed.startsWith('- ')) {
|
||||||
|
if (!inArray && currentKey) {
|
||||||
|
inArray = true
|
||||||
|
currentValue = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentItem && currentItem.title && currentItem.link !== undefined) {
|
||||||
|
const link: SectionLinkListItem = {
|
||||||
|
title: currentItem.title,
|
||||||
|
link: currentItem.link,
|
||||||
|
description: currentItem.description
|
||||||
|
}
|
||||||
|
if (!currentValue.some(item => item.link === link.link)) {
|
||||||
|
currentValue.push(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemText = trimmed.slice(2).trim()
|
||||||
|
if (itemText.includes(':')) {
|
||||||
|
currentItem = {}
|
||||||
|
const parts = itemText.split(',').map(p => p.trim())
|
||||||
|
for (const part of parts) {
|
||||||
|
const colonMatch = part.match(/^(\w+):\s*(.+)$/)
|
||||||
|
if (colonMatch) {
|
||||||
|
const [, key, value] = colonMatch
|
||||||
|
if (SECTION_LINK_KEYS.includes(key as typeof SECTION_LINK_KEYS[number])) {
|
||||||
|
currentItem[key] = value.replace(/^["']|["']$/g, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentValue.push({ title: itemText, link: '' })
|
||||||
|
}
|
||||||
|
} else if (lineIndent >= 4 && currentItem && trimmed.includes(':')) {
|
||||||
|
const colonIndex = trimmed.indexOf(':')
|
||||||
|
if (colonIndex !== -1) {
|
||||||
|
const key = trimmed.substring(0, colonIndex).trim()
|
||||||
|
const value = trimmed.substring(colonIndex + 1).trim()
|
||||||
|
if (SECTION_LINK_KEYS.includes(key as typeof SECTION_LINK_KEYS[number])) {
|
||||||
|
currentItem[key] = value === '' ? '' : value.replace(/^["']|["']$/g, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentItem && inArray && currentItem.title && currentItem.link !== undefined) {
|
||||||
|
const link: SectionLinkListItem = {
|
||||||
|
title: currentItem.title,
|
||||||
|
link: currentItem.link,
|
||||||
|
description: currentItem.description
|
||||||
|
}
|
||||||
|
if (!currentValue.some(item => item.link === link.link)) {
|
||||||
|
currentValue.push(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inArray && currentKey) {
|
||||||
|
frontmatter[currentKey] = currentValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return { frontmatter, content: cleanContent || content }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stringifyFrontmatter = (frontmatter: Frontmatter, content: string) => {
|
||||||
|
const lines: string[] = []
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(frontmatter)) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
lines.push(`${key}:`)
|
||||||
|
for (const item of value) {
|
||||||
|
if (typeof item === 'object' && item) {
|
||||||
|
const link = item as SectionLinkListItem
|
||||||
|
lines.push(` - title: ${link.title ?? ''}`)
|
||||||
|
if (link.link) lines.push(` link: ${link.link}`)
|
||||||
|
if ('description' in link && link.description !== undefined && link.description !== null && String(link.description).trim() !== '') {
|
||||||
|
lines.push(` description: ${String(link.description)}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lines.push(` - ${item}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value) {
|
||||||
|
const strValue = String(value)
|
||||||
|
const needsQuotes = strValue.includes(':') || (strValue.includes(' ') && !strValue.startsWith('"')) || strValue === ''
|
||||||
|
const escaped = strValue.replace(/"/g, '\\"')
|
||||||
|
lines.push(`${key}: ${needsQuotes ? `"${escaped}"` : strValue}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `---\n${lines.join('\n')}\n---\n\n${content}`
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import type { SidebarItem } from './types'
|
||||||
|
import { getPageDescription } from './descriptions'
|
||||||
|
import { normalizeLink } from './path-utils'
|
||||||
|
import { SectionLinkListItem } from '../../theme/components/SectionLinkList/SectionLinkList.types'
|
||||||
|
|
||||||
|
export const mergeSectionLinks = (
|
||||||
|
existingLinks: SectionLinkListItem[],
|
||||||
|
newLinks: SectionLinkListItem[]
|
||||||
|
) => {
|
||||||
|
const existingLinksMap = new Map<string, SectionLinkListItem>()
|
||||||
|
const result: SectionLinkListItem[] = []
|
||||||
|
const processedLinks = new Set<string>()
|
||||||
|
|
||||||
|
for (const existingLink of existingLinks) {
|
||||||
|
if (existingLink.link) {
|
||||||
|
const normalizedLink = normalizeLink(existingLink.link)
|
||||||
|
if (!existingLinksMap.has(normalizedLink)) {
|
||||||
|
existingLinksMap.set(normalizedLink, existingLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const newLink of newLinks) {
|
||||||
|
if (newLink.link) {
|
||||||
|
const normalizedLink = normalizeLink(newLink.link)
|
||||||
|
|
||||||
|
if (!processedLinks.has(normalizedLink)) {
|
||||||
|
processedLinks.add(normalizedLink)
|
||||||
|
|
||||||
|
if (existingLinksMap.has(normalizedLink)) {
|
||||||
|
const existingLink = existingLinksMap.get(normalizedLink)!
|
||||||
|
result.push({ ...existingLink, title: newLink.title })
|
||||||
|
} else {
|
||||||
|
result.push(newLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export const extractTopLevelLinks = (
|
||||||
|
items: SidebarItem[],
|
||||||
|
currentIndexPath: string,
|
||||||
|
srcDir: string
|
||||||
|
) => {
|
||||||
|
const links: SectionLinkListItem[] = []
|
||||||
|
const normalizedCurrentPath = normalizeLink(currentIndexPath)
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if ('excludeFromIndex' in item && item.excludeFromIndex) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.link) {
|
||||||
|
const normalizedItemPath = normalizeLink(item.link)
|
||||||
|
if (normalizedItemPath === normalizedCurrentPath) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
links.push({
|
||||||
|
title: item.text || '',
|
||||||
|
link: item.link,
|
||||||
|
description: getPageDescription(item.link, srcDir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links
|
||||||
|
}
|
||||||
|
|
||||||
|
const findItemsRecursive = (
|
||||||
|
itemsList: SidebarItem[],
|
||||||
|
pagePath: string,
|
||||||
|
srcDir: string
|
||||||
|
): SectionLinkListItem[] => {
|
||||||
|
const normalizedPagePath = normalizeLink(pagePath)
|
||||||
|
const links: SectionLinkListItem[] = []
|
||||||
|
|
||||||
|
for (const item of itemsList) {
|
||||||
|
if (item.link) {
|
||||||
|
const normalizedItemPath = normalizeLink(item.link)
|
||||||
|
|
||||||
|
if (normalizedItemPath === normalizedPagePath && item.items && Array.isArray(item.items) && item.items.length > 0) {
|
||||||
|
for (const subItem of item.items) {
|
||||||
|
if ('excludeFromIndex' in subItem && subItem.excludeFromIndex) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subItem.link) {
|
||||||
|
links.push({
|
||||||
|
title: subItem.text || '',
|
||||||
|
link: subItem.link,
|
||||||
|
description: getPageDescription(subItem.link, srcDir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return links
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.items && Array.isArray(item.items)) {
|
||||||
|
const found = findItemsRecursive(item.items, pagePath, srcDir)
|
||||||
|
if (found.length > 0) {
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links
|
||||||
|
}
|
||||||
|
|
||||||
|
export const extractItemsForPage = (
|
||||||
|
items: SidebarItem[],
|
||||||
|
pagePath: string,
|
||||||
|
srcDir: string
|
||||||
|
) => findItemsRecursive(items, pagePath, srcDir)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const normalizeLink = (link: string): string =>
|
||||||
|
!link ? '' : link
|
||||||
|
.replace(/^\/+/, '')
|
||||||
|
.replace(/\.md$/, '')
|
||||||
|
.replace(/\\/g, '/')
|
||||||
|
.trim()
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { SectionLinkListItem } from "../../theme/components/SectionLinkList/SectionLinkList.types"
|
||||||
|
|
||||||
|
export type SidebarItem = {
|
||||||
|
text: string
|
||||||
|
link?: string
|
||||||
|
items?: SidebarItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Frontmatter = {
|
||||||
|
section_links?: SectionLinkListItem[]
|
||||||
|
[key: string]: string | number | boolean | string[] | SectionLinkListItem[] | undefined
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ export type SectionLinkListItem = {
|
|||||||
title: string,
|
title: string,
|
||||||
link: string,
|
link: string,
|
||||||
description?: string
|
description?: string
|
||||||
|
collapsed?: boolean
|
||||||
|
excludeFromIndex?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SectionLinkListProps = {
|
export type SectionLinkListProps = {
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
# Cloud PostgreSQL
|
|
||||||
|
|
||||||
## Назначение сервиса
|
|
||||||
|
|
||||||
**Cloud PostgreSQL** - это управляемый облачный сервис реляционной базы данных PostgreSQL. Он позволяет развернуть и использовать отказоустойчивый кластер базы данных без необходимости самостоятельно настраивать серверы, репликацию и механизмы отказоустойчивости.
|
|
||||||
|
|
||||||
PostgreSQL - это современная система управления базами данных, которая поддерживает стандарт SQL и используется для хранения и обработки данных приложений.
|
|
||||||
|
|
||||||
В **Cloud PostgreSQL** все основные операции по управлению кластером выполняются автоматически.
|
|
||||||
|
|
||||||
Сервис самостоятельно:
|
|
||||||
- управляет ролями серверов базы данных (основной сервер и реплики);
|
|
||||||
- отслеживает состояние узлов;
|
|
||||||
- автоматически переключает основной сервер при сбоях.
|
|
||||||
|
|
||||||
Для обеспечения стабильной работы сервиса используется несколько инфраструктурных компонентов:
|
|
||||||
- **Patroni** - управляет кластером PostgreSQL и автоматическим переключением при отказах;
|
|
||||||
- **etcd** - хранит состояние кластера и обеспечивает согласованность работы узлов;
|
|
||||||
- **HAProxy** - обеспечивает единую точку подключения и распределяет клиентские подключения между узлами.
|
|
||||||
|
|
||||||
Подключение к базе данных выполняется через прокси-узлы сервиса. Пользователю не требуется подключаться к отдельным серверам кластера — все операции производятся через единую точку доступа.
|
|
||||||
|
|
||||||
Для управления базами данных и пользователями доступен web-интерфейс **pgAdmin**, позволяющий выполнять администрирование непосредственно через браузер.
|
|
||||||
|
|
||||||
## Конфигурации кластера
|
|
||||||
|
|
||||||
Сервис Cloud PostgreSQL поддерживает версии СУБД с 13 по 17 включительно.
|
|
||||||
|
|
||||||
Кластер предоставляется в архитектуре Primary–Standby, которая обеспечивает:
|
|
||||||
|
|
||||||
- синхронную репликацию данных;
|
|
||||||
- повышенную отказоустойчивость.
|
|
||||||
|
|
||||||
В рамках данной конфигурации создаётся кластер из виртуальных серверов, включающий:
|
|
||||||
|
|
||||||
- **Primary** (основной сервер) — обязательный узел, на котором выполняются операции записи данных;
|
|
||||||
- **Replica** (реплики) — дополнительные узлы (от 0 до 4), создаваемые по желанию пользователя.
|
|
||||||
|
|
||||||
Реплики являются полноценными участниками кластера PostgreSQL и могут использоваться для выполнения запросов, не изменяющих данные (например, SELECT).
|
|
||||||
|
|
||||||
В многоузловой конфигурации серверы кластера размещаются на разных физических хостах гипервизора, что повышает устойчивость сервиса к отказам оборудования.
|
|
||||||
|
|
||||||
## Режимы репликации
|
|
||||||
|
|
||||||
По умолчанию фиксация изменений выполняется в **синхронном режиме**. Это означает, что операция записи считается завершённой только после того, как данные будут зафиксированы как на основном сервере, так и на одной из реплик.
|
|
||||||
|
|
||||||
Если в кластере настроено несколько реплик, синхронный режим применяется только к одной из них. Остальные реплики работают в асинхронном режиме — изменения передаются на них без ожидания подтверждения.
|
|
||||||
|
|
||||||
При необходимости режим репликации может быть изменён на полностью **асинхронный**. В этом случае изменения сначала фиксируются на основном сервере, а затем передаются на реплики с задержкой.
|
|
||||||
|
|
||||||
## Доступ к серверам и оптимизация соединений
|
|
||||||
|
|
||||||
Прямой доступ к серверам кластера (например, по протоколу SSH) не предоставляется. Пользователь взаимодействует с базой данных исключительно через точки подключения, предоставленные сервисом.
|
|
||||||
|
|
||||||
На каждом узле кластера установлен пулер соединений **PgBouncer**, который может использоваться для ускорения работы приложений за счёт оптимизации подключений к базе данных.
|
|
||||||
|
|
||||||
::: warning Примечание
|
|
||||||
|
|
||||||
Использование PgBouncer не является обязательным - подключение возможно как напрямую к PostgreSQL, так и через пулер, а также одновременно обоими способами.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Возможности сервиса
|
|
||||||
|
|
||||||
**Cloud PostgreSQL** предоставляет набор возможностей, позволяющих использовать PostgreSQL в облаке без необходимости самостоятельного администрирования инфраструктуры.
|
|
||||||
|
|
||||||
Сервис обеспечивает:
|
|
||||||
|
|
||||||
- автоматическое управление кластером PostgreSQL;
|
|
||||||
- высокую доступность за счёт репликации и автоматического переключения primary-узла;
|
|
||||||
- единую точку подключения к базе данных через прокси;
|
|
||||||
- автоматическое переключение при отказе узлов кластера без вмешательства пользователя;
|
|
||||||
- web-доступ к управлению базами данных и пользователями через pgAdmin;
|
|
||||||
- совместимость со стандартными клиентскими инструментами PostgreSQL;
|
|
||||||
- возможность установки расширений PostgreSQL в базу данных.
|
|
||||||
|
|
||||||
## Сценарии использования сервиса
|
|
||||||
|
|
||||||
**Cloud PostgreSQL** подходит для использования в системах, где требуется надёжное хранение данных и упрощённое управление инфраструктурой базы данных.
|
|
||||||
|
|
||||||
Сервис может применяться в следующих сценариях:
|
|
||||||
|
|
||||||
- размещение production-баз данных с высокими требованиями к доступности;
|
|
||||||
- использование PostgreSQL в микросервисной архитектуре с единой точкой подключения к базе данных;
|
|
||||||
- хранение критичных данных с минимальным временем простоя при отказах инфраструктуры;
|
|
||||||
- быстрое развёртывание PostgreSQL-кластера без необходимости ручной настройки репликации и failover;
|
|
||||||
- администрирование баз данных через веб-интерфейс без прямого доступа к серверам кластера.
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
# О разделе
|
|
||||||
|
|
||||||
Данный раздел содержит описание технических параметров кластера PostgreSQL и порядок их первичной конфигурации.
|
|
||||||
|
|
||||||
Настройка указанных параметров выполняется администратором облачного провайдера на этапе развёртывания сервиса. Пользователь не имеет прямого доступа к их самостоятельной установке.
|
|
||||||
|
|
||||||
Перед созданием кластера клиент предоставляет перечень требуемых параметров менеджеру. Администратор облачного провайдера выполняет конфигурацию в соответствии с согласованными требованиями.
|
|
||||||
|
|
||||||
## Выбор типа и размера дискового хранилища
|
|
||||||
|
|
||||||
Производительность базы данных напрямую зависит от скорости, с которой она может читать и записывать данные на диск. При заказе кластера необходимо выбрать тип дискового хранилища, который определит максимальную скорость работы (IOPS) и время отклика.
|
|
||||||
|
|
||||||
**IOPS (Input/Output Operations Per Second)** — количество операций чтения или записи, которые диск может выполнить за секунду. Чем выше этот показатель, тем быстрее база данных обрабатывает запросы.
|
|
||||||
|
|
||||||
## Доступные типы хранилищ:
|
|
||||||
|
|
||||||
| Название | Лимит IOPS | Время отклика |
|
|
||||||
| ---------------| ------------------ | ------------- |
|
|
||||||
| **Fast SAS** | до 2 IOPS на 1 ГБ | до 10 мс |
|
|
||||||
| **SSD** | до 5 IOPS на 1 ГБ | до 7 мс |
|
|
||||||
| **Fast SSD** | до 10 IOPS на 1 ГБ | до 5 мс |
|
|
||||||
| **Ultra NVMe** | до 25 IOPS на 1 ГБ | до 3 мс |
|
|
||||||
|
|
||||||
::: warning Примечание
|
|
||||||
|
|
||||||
После выбора типа диска необходимо указать объем дискового хранилища, который будет выделен под данные кластера PostgreSQL. Минимальный объем - 50 ГБ.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Конфигурация вычислительных ресурсов
|
|
||||||
|
|
||||||
В данном разделе определяются вычислительные мощности кластера: процессорные ресурсы, оперативная память и количество серверов (нод), из которых будет состоять кластер PostgreSQL.
|
|
||||||
|
|
||||||
### Количество нод в кластере
|
|
||||||
|
|
||||||
Количество нод определяет отказоустойчивость кластера и возможность распределять запросы на чтение между репликами. Чем больше нод, тем выше надёжность и производительность операций чтения.
|
|
||||||
|
|
||||||
Количество нод выбирается в диапазоне **от 1 до 5**.
|
|
||||||
|
|
||||||
### Процессор (CPU)
|
|
||||||
|
|
||||||
Процессор — это вычислительная мощность, выделяемая каждой ноде кластера. Количество vCPU определяет, насколько быстро база данных сможет:
|
|
||||||
|
|
||||||
- обрабатывать запросы;
|
|
||||||
- выполнять сложные операции (сортировки, объединения таблиц);
|
|
||||||
- обслуживать одновременные подключения.
|
|
||||||
|
|
||||||
Доступный диапазон: **от 2 до 24 vCPU** на ноду.
|
|
||||||
|
|
||||||
### Оперативная память (RAM)
|
|
||||||
|
|
||||||
Оперативная память — один из ключевых ресурсов для производительности базы данных. Данные, помещающиеся в RAM, обрабатываются максимально быстро, без обращения к диску.
|
|
||||||
|
|
||||||
Доступный диапазон: **от 4 до 768 ГБ RAM** на ноду.
|
|
||||||
|
|
||||||
### Доступ в интернет
|
|
||||||
|
|
||||||
При заказе сервиса можно выбрать пропускную способность канала связи, через который будет осуществляться доступ к кластеру PostgreSQL из сети интернет.
|
|
||||||
|
|
||||||
**Доступные варианты скорости:**
|
|
||||||
- 50 Мбит/с;
|
|
||||||
- 100 Мбит/с;
|
|
||||||
- 200 Мбит/с;
|
|
||||||
- 300 Мбит/с;
|
|
||||||
- 400 Мбит/с;
|
|
||||||
- 500 Мбит/с;
|
|
||||||
- 1000 Мбит/с (1 Гбит/с).
|
|
||||||
|
|
||||||
::: warning Примечание
|
|
||||||
|
|
||||||
Для выбранного канала предоставляется статический белый IP-адрес.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Параметры конфигурации IPSEC
|
|
||||||
|
|
||||||
Ниже приведены основные параметры, задаваемые при развёртывании кластера PostgreSQL. Часть параметров определяется клиентом на этапе заказа услуги, часть — фиксирована и не подлежит изменению.
|
|
||||||
|
|
||||||
### Данные о конфигурации IPSEC
|
|
||||||
|
|
||||||
Параметры подключения (имя туннеля, устройство, публичный IP-адрес) заполняются вручную на основании информации, предоставленной заказчиком.
|
|
||||||
|
|
||||||
### Версия IKE (Internet Key Exchange)
|
|
||||||
|
|
||||||
Версия IKE выбирается из выпадающего списка, который содержит два значения:
|
|
||||||
|
|
||||||
- **IKE v1** — более ранняя версия протокола;
|
|
||||||
- **IKE v2** — более современная версия, обеспечивающая лучшую устойчивость соединения и более гибкую обработку ошибок.
|
|
||||||
|
|
||||||
Рекомендуется использовать IKE v2, если оборудование заказчика это поддерживает.
|
|
||||||
|
|
||||||
### Метод аутентификации
|
|
||||||
|
|
||||||
Метод аутентификации выбирается из выпадающего списка, который содержит два варианта:
|
|
||||||
|
|
||||||
- **PSK** (Pre-Shared Key) — аутентификация с использованием заранее согласованного общего ключа;
|
|
||||||
- **Certificate** (сертификат) — аутентификация с использованием цифровых сертификатов.
|
|
||||||
|
|
||||||
## Этап 1 - установка защищенного соединения
|
|
||||||
|
|
||||||
На данном этапе задаются параметры шифрования и аутентификации для защищённого канала связи. Все параметры выбираются вручную из выпадающих списков.
|
|
||||||
|
|
||||||
### Алгоритм хэширования
|
|
||||||
|
|
||||||
Определяет алгоритм хэширования для защиты управляющего канала. Параметр заполняется вручную из выпадающего списка:
|
|
||||||
|
|
||||||
- **SHA1** — формирует хэш длиной 160 бит, имеет коллизии (уязвимости), в современных системах считается устаревшим, используется только для совместимости со старым оборудованием.
|
|
||||||
- **SHA2-256** — формирует хэш длиной 256 бит, существенно более устойчив к атакам, оптимальный баланс между безопасностью и производительностью.
|
|
||||||
- **SHA2-384** — длина хэша составляет 384 бита, имеет повышенную криптостойкость, требует больше вычислительных ресурсов, чем SHA-1 и SHA2-256. Используется в средах с повышенными требованиями к безопасности.
|
|
||||||
- **SHA2-512** — длина хэша составляет 512 бит, обеспечивает самый высокий уровень стойкости из перечисленных, создает наибольшую нагрузку на процессор. Обычно применяется в системах с повышенными требованиями к криптографии.
|
|
||||||
|
|
||||||
### Шифрование (Hash)
|
|
||||||
|
|
||||||
Определяет алгоритм симметричного шифрования. Параметр заполняется вручную из выпадающего списка:
|
|
||||||
|
|
||||||
AES 128 — использует 128-битный ключ, обеспечивает быстрое шифрование, имеет достаточный уровень безопасности для большинства задач.
|
|
||||||
AES 256 — использует 256-битный ключ, обеспечивает более высокую криптостойкость, оказывает немного большую нагрузку на CPU.
|
|
||||||
AES GCM 128 / AES GCM 192 / AES GCM 256 — данные алгоритмы совмещают шифрование и контроль целостности, обладают более современным режимом работы, считаются более эффективными по производительности, рекомендуются в современных конфигурациях. Разница между алгоритмами — в длине ключа.
|
|
||||||
|
|
||||||
### DH Group (группа Диффи — Хеллмана)
|
|
||||||
|
|
||||||
Механизм Diffie-Hellman используется для безопасной генерации общего секретного ключа между сторонами туннеля без передачи этого ключа по сети. Чем выше номер группы и длина ключа, тем выше криптографическая стойкость соединения.
|
|
||||||
|
|
||||||
Параметр заполняется вручную из выпадающего списка:
|
|
||||||
|
|
||||||
group 2;
|
|
||||||
group 5;
|
|
||||||
group 14;
|
|
||||||
group 15;
|
|
||||||
group 16;
|
|
||||||
group 19;
|
|
||||||
group 20;
|
|
||||||
group 21.
|
|
||||||
|
|
||||||
### IKE Mode (только для IKEv1)
|
|
||||||
|
|
||||||
Параметр **IKE Mode** определяет способ установления соединения на этапе 1 при использовании протокола IKEv1.
|
|
||||||
|
|
||||||
Доступны два режима: Main и Aggressive. Они отличаются количеством сообщений при установке соединения и уровнем защиты идентификационных данных.
|
|
||||||
|
|
||||||
- **Main Mode** — стандартный и более безопасный режим работы IKEv1;
|
|
||||||
- **Aggressive Mode** — упрощённый и ускоренный режим установления соединения с более низким уровнем защиты данных.
|
|
||||||
|
|
||||||
### Время жизни (Lifetime)
|
|
||||||
|
|
||||||
Параметр определяет, как долго действуют согласованные ключи в рамках первой фазы. После истечения времени выполняется повторная генерация ключей.
|
|
||||||
|
|
||||||
## Этап 2 - передача данных
|
|
||||||
|
|
||||||
Этап 2 IPsec-соединения отвечает за шифрование и защиту пользовательского трафика после того, как защищённый канал был установлен на этапе 1. Этот этап регулирует передачу данных между сторонами через безопасный туннель, который обеспечивает конфиденциальность и целостность данных.
|
|
||||||
|
|
||||||
### Алгоритм хэширование (Hash)
|
|
||||||
|
|
||||||
Аналогично этапу 1, параметр Hash используется для защиты целостности передаваемых данных. Он обеспечивает проверку того, что данные не были изменены при передаче. Доступны следующие алгоритмы:
|
|
||||||
|
|
||||||
- SHA1;
|
|
||||||
- SHA2-256;
|
|
||||||
- SHA2-384;
|
|
||||||
- SHA2-512.
|
|
||||||
|
|
||||||
## Шифрование
|
|
||||||
|
|
||||||
Этап 2 отвечает за шифрование пользовательского трафика. Это важнейший параметр, который защищает данные при их передаче по сети. Доступны следующие алгоритмы:
|
|
||||||
|
|
||||||
- AES 128;
|
|
||||||
- AES 256;
|
|
||||||
- AES GCM 128;
|
|
||||||
- AES GCM 192;
|
|
||||||
- AES GCM 256.
|
|
||||||
|
|
||||||
### PFS
|
|
||||||
|
|
||||||
**Enable perfect forward secrecy (PFS)** - параметр, активирующий генерацию нового ключа на этапе 2. При включенном PFS группа Diffie-Hellman (DH) будет такая же как и на 1-й фазе.
|
|
||||||
|
|
||||||
Данный параметр представлен в виде чекбокса. При его включении:
|
|
||||||
|
|
||||||
- на этапе 2 выполняется дополнительный обмен ключами DH;
|
|
||||||
- для каждой новой IPsec-сессии формируется новый независимый криптографический секрет;
|
|
||||||
- ключи шифрования пользовательского трафика не зависят от ключей этапа 1.
|
|
||||||
|
|
||||||
### DH Group (группа Диффи — Хеллмана)
|
|
||||||
|
|
||||||
Группа DH определяет параметры обмена ключами между сторонами. Чем выше номер группы, тем выше криптографическая стойкость и безопасность обмена.
|
|
||||||
|
|
||||||
Данный параметр так же содержит в себе выпадающий список, состоящий из следующих значений:
|
|
||||||
|
|
||||||
- group 2;
|
|
||||||
- group 5;
|
|
||||||
- group 14;
|
|
||||||
- group 15;
|
|
||||||
- group 16;
|
|
||||||
- group 19;
|
|
||||||
- group 20;
|
|
||||||
- group 21.
|
|
||||||
|
|
||||||
### Время жизни (Lifetime)
|
|
||||||
|
|
||||||
Определяет, как долго действуют согласованные ключи в рамках второй фазы.
|
|
||||||
|
|
||||||
- рекомендуемое значение: 3600 секунд (1 час);
|
|
||||||
- после истечения времени выполняется повторная генерация ключей.
|
|
||||||
|
|
||||||
### Префиксы локальной сети заказчика
|
|
||||||
|
|
||||||
Этот параметр определяет, какие сети на стороне заказчика будут маршрутизироваться через **IPsec-туннель**. Префиксы задаются в формате `192.168.1.0/24`, который позволяет указать диапазон IP-адресов.
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# Общая схема подключения
|
|
||||||
|
|
||||||
Доступ к кластеру PostgreSQL осуществляется через прокси. Клиентские подключения принимаются прокси, который маршрутизирует трафик к соответствующим узлам кластера (master или replica) в зависимости от выбранного порта. Прямое подключение к узлам базы данных не используется.
|
|
||||||
|
|
||||||
Подключение к кластеру **Cloud PostgreSQL** осуществляется через прокси-сервер. Прокси является единой точкой входа для всех клиентских подключений и принимает входящие соединения от приложений, административных инструментов и пользователей.
|
|
||||||
|
|
||||||
В зависимости от выбранного порта прокси автоматически направляет трафик:
|
|
||||||
- на активный primary-узел - для операций чтения и записи
|
|
||||||
- на реплики - для операций только чтения
|
|
||||||
|
|
||||||
Прямое подключение к отдельным узлам базы данных не используется и не предоставляется. Взаимодействие с кластером всегда выполняется через прокси-сервер.
|
|
||||||
|
|
||||||
## Подключение к базе данных
|
|
||||||
|
|
||||||
Для подключения к базе данных необходимо использовать IP-адрес прокси-сервера, который предоставляется после заказа услуги.
|
|
||||||
|
|
||||||
Этот IP-адрес является единой точкой входа для работы с кластером PostgreSQL. Все подключения к базе данных - как из приложений, так и из клиентских инструментов - выполняются через него.
|
|
||||||
|
|
||||||
Использование других IP-адресов или попытка прямого подключения к отдельным узлам кластера не предусмотрены.
|
|
||||||
|
|
||||||
## Доступные порты
|
|
||||||
|
|
||||||
Для разных типов нагрузки используются разные порты:
|
|
||||||
|
|
||||||
|Порт |Назначение |
|
|
||||||
|------|-----------------------------------------|
|
|
||||||
|5432 |Primary (чтение и запись) |
|
|
||||||
|15432 |Replica (только чтение) |
|
|
||||||
|6432 |Primary через PgBouncer (чтение и запись)|
|
|
||||||
|16432 |Replica через PgBouncer (только чтение) |
|
|
||||||
|
|
||||||
### Особенности работы портов
|
|
||||||
|
|
||||||
- Порты для чтения и записи (5432, 6432) всегда направляют трафик на активный primary-узел. При смене primary переключение происходит автоматически;
|
|
||||||
- Порты только для чтения (15432, 16432) направляют трафик на активные реплики. Если реплик несколько, нагрузка распределяется между ними по принципу round-robin;
|
|
||||||
- Если в кластере отсутствуют реплики, порты для чтения не используются - подключение по ним не устанавливается.
|
|
||||||
|
|
||||||
### Рекомендации по выбору порта
|
|
||||||
|
|
||||||
- Для OLTP-нагрузки и большого количества соединений рекомендуется использовать **порты PgBouncer (6432 или 16432)**;
|
|
||||||
- Для операций записи используйте **master-порты (5432 или 6432)**;
|
|
||||||
- Для read-only запросов можно использовать **replica-порты (15432 или 16432)**.
|
|
||||||
|
|
||||||
## Доступ к pgAdmin
|
|
||||||
|
|
||||||
Для администрирования базы данных используется web-интерфейс pgAdmin.
|
|
||||||
Доступ осуществляется по DNS-имени, которое нужно прописать локально в инфраструктуре откуда будет происходить доступ к web-интерфейсу сервиса:
|
|
||||||
`10.X.X.4 <domain>.cloud-pg.dfcloud.ru`
|
|
||||||
|
|
||||||
После добавления записи pgAdmin будет доступен по адресу:
|
|
||||||
`https://<domain>.cloud-pg.dfcloud.ru`
|
|
||||||
|
|
||||||
Авторизация выполняется с использованием учётных данных, предоставленных вместе с доступом к сервису.
|
|
||||||
|
|
||||||
::: warning Важно
|
|
||||||
|
|
||||||
- подключение к базе данных возможно только через указанный прокси-IP;
|
|
||||||
- в интерфейсе pgAdmin уже добавлен сервер базы данных, созданный для данной инсталляции. Для подключения требуется ввести пароль от учётной записи базы данных;
|
|
||||||
- pgAdmin предназначен для администрирования и не рекомендуется для выполнения тяжёлых или длительных запросов в production-среде.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Примеры подключения к PostgreSQL
|
|
||||||
|
|
||||||
Подключение к primary:
|
|
||||||
`psql -h 10.X.X.4 -p 5432 -U <username> -d <database>`
|
|
||||||
|
|
||||||
Подключение через PgBouncer:
|
|
||||||
`psql -h 10.X.X.4 -p 6432 -U <username> -d <database>`
|
|
||||||
|
|
||||||
### Подключение через DBeaver / DataGrip
|
|
||||||
|
|
||||||
При создании подключения укажите:
|
|
||||||
- Host: 10.X.X.4;
|
|
||||||
- Port: 5432 или 6432;
|
|
||||||
- Database: `<database>`;
|
|
||||||
- User / Password: согласно выданным доступам;
|
|
||||||
- Тип подключения: PostgreSQL.
|
|
||||||
|
|
||||||
### Пример строки подключения
|
|
||||||
|
|
||||||
Primary:
|
|
||||||
`postgresql://<username>:<password>@10.X.X.4:5432/<database>`
|
|
||||||
|
|
||||||
Через PgBouncer:
|
|
||||||
`postgresql://<username>:<password>@10.X.X.4:6432/<database>`
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
|
|
||||||
# Метрики
|
|
||||||
## Инструкция по подключению к Grafana.
|
|
||||||
Для того, чтобы получить доступ к метрикам кластера, предварительно необходимо запросить доступы. Когда доступы будут получены, появится возможность перейти в систему мониторинга.
|
|
||||||
Ссылка для входа - https://metrics.dfcloud.ru.
|
|
||||||
|
|
||||||
При переходе по ссылке откроется главная страница Grafana. Для того чтобы найти нужные метрики, необходимо проделать следующий путь:
|
|
||||||
1. Нажать на кнопку "Dashboards", которая располагается в левом боковом меню.
|
|
||||||
2. В открывшемся списке всех имеющихся дашбордов необходимо выбрать папку "Cloud PostgreSQL".
|
|
||||||
3. Внутри будет элемент **Cloud PostgreSQL** - это именно тот дашборд, который нам нужен.
|
|
||||||
Перейдя на дашборд Cloud PostgreSQL, открываются все метрики кластера.
|
|
||||||
|
|
||||||
В верхней части дашборда расположены все селекторы, с помощью которых можно управлять отображаемыми данными:
|
|
||||||
- **InstallationID** - выбор одного из кластеров. Если у клиента несколько кластеров PostgreSQL, он может выбирать тот кластер, по которому хочет посмотреть информацию;
|
|
||||||
- **Cluster node name** - выбор конкретной ноды кластера. Значения графиков меняются в зависимости от того, какой хост выбран. Этот селектор влияет на все графики, кроме блока Patroni;
|
|
||||||
- **Database** - выбор базы данных, по которой можно смотреть показатели метрик;
|
|
||||||
- **Lock table** - данный селектор применим не для всех графиков. С его помощью можно выбирать, какой тип блокировки использовать для отображения информации;
|
|
||||||
|
|
||||||
## Блок метрик PostgreSQL
|
|
||||||
|
|
||||||
Данный блок отображает ключевые параметры конфигурации и текущие показатели работы экземпляра PostgreSQL.
|
|
||||||
|
|
||||||
| Наименование метрики | Описание метрики |
|
|
||||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| **Version** | Показывает текущую версию PostgreSQL, установленную на кластере. |
|
|
||||||
| **Current fetch data** | Объем данных, извлеченных из базы за текущий период (операции чтения). |
|
|
||||||
| **Current insert data** | Объем данных, вставленных в базу (операции записи новых данных). |
|
|
||||||
| **Current update data** | Объем данных, обновленных в базе. |
|
|
||||||
| **Seq Page Cost** | Стоимость последовательного чтения страницы данных. Влияет на выбор плана запроса: чем выше значение, тем реже оптимизатор будет выбирать последовательное сканирование таблиц. |
|
|
||||||
| **Random Page Cost** | Стоимость чтения случайной страницы данных. Низкое значение говорит о том, что в системе используются быстрые диски, и оптимизатор будет чаще выбирать доступ по индексам. |
|
|
||||||
| **Max Connections** | Максимальное количество одновременных подключений к базе данных, разрешенное на сервере. |
|
|
||||||
| **Shared Buffers** | Объем оперативной памяти, выделенный под кэш данных PostgreSQL. Здесь хранятся часто используемые данные для ускорения доступа к ним. |
|
|
||||||
| **Effective Cache** | Предполагаемый размер системного кэша файлов. Используется оптимизатором для оценки вероятности нахождения данных в кэше операционной системы. |
|
|
||||||
| **Maintenance Work Mem** | Объем памяти для выполнения операций обслуживания. |
|
|
||||||
| **Work Mem** | Объем памяти, выделяемый для внутренних сортировок и хеш-таблиц при выполнении запросов (на каждую операцию). |
|
|
||||||
| **Max WAL Size** | Максимальный размер журнала предзаписи, после достижения которого запускается процесс контрольной точки (checkpoint). |
|
|
||||||
| **Max Worker Processes** | Максимальное количество фоновых процессов, которые могут быть запущены в системе. |
|
|
||||||
| **Max Parallel Workers** | Максимальное количество параллельных процессов, которые могут быть задействованы при выполнении одного запроса. |
|
|
||||||
|
|
||||||
## Блок метрик Database Stats
|
|
||||||
|
|
||||||
Данный блок метрик отражает текущую нагрузку и состояние баз данных в кластере PostgreSQL. Эти метрики позволяют оценить, насколько эффективно работает база данных, отследить скачки нагрузки и своевременно среагировать на потенциальные проблемы до того, как они повлияют на работу приложений.
|
|
||||||
|
|
||||||
| Наименование метрики | Описание метрики |
|
|
||||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| **Average CPU Usage** | Показывает время, затраченное на выполнение пользовательских и системных задач, а также, насколько интенсивно используются вычислительные ресурсы сервера базы данных. |
|
|
||||||
| **Average Memory Usage** | Средний объем оперативной памяти, используемой процессами PostgreSQL за 5-минутные интервалы. Показывает, сколько памяти потребляет база данных в процессе работы. |
|
|
||||||
| **Open File Descriptors** | Количество открытых файловых дескрипторов процессами PostgreSQL. Метрика показывает среднее (Mean), последнее (Last), максимальное (Max) и минимальное (Min) значение за интервал. |
|
|
||||||
| **Active sessions** | Показывает, сколько в данный момент выполняется запросов к PostgreSQL. Метрика показывает среднее (Mean), последнее (Last), максимальное (Max) значение. |
|
|
||||||
| **Transcations** | Количество транзакций в базах данных кластера. Метрика разделена на два типа операций: commits (успешно завершенные транзакции) и rollbacks (откаченные транзакции). |
|
|
||||||
| **Update data** | Объем данных, обновленных в базах данных кластера. Показывает, сколько данных было изменено в результате выполнения операций UPDATE. |
|
|
||||||
| **Fetch data (SELECT)** | Объем данных, извлеченных из базы с помощью запросов SELECT. Показывает, сколько данных было считано из базы в результате операций чтения. |
|
|
||||||
| **Insert data** | Объем данных, вставленных в базы данных кластера. Показывает, сколько данных было добавлено в результате выполнения операций INSERT. |
|
|
||||||
| **Lock tables** | Количество блокировок таблиц в базах данных кластера. Показывает, сколько раз таблицы были заблокированы для выполнения операций.<br>AccessShareLock - это блокировка, которая возникает, когда кто-то читает данные из таблицы (делает SELECT). Данная блокировка не мешает операциям чтения, но не дает удалить в этот момент таблицу или изменить ее структуру. |
|
|
||||||
| **Return data** | Объем данных, возвращаемых клиенту в результате выполнения запросов. Показывает, сколько данных было отправлено обратно клиенту после обработки запросов в базе. |
|
|
||||||
| **Idle sessions** | Количество бездействующих сессий подключения к базе данных. Показывает, сколько открытых подключений в данный момент не выполняют никаких запросов и просто ждут. |
|
|
||||||
| **Delete data** | Объем данных, удаленных из базы данных в результате выполнения операций DELETE. Показывает, сколько данных было удалено из таблиц. |
|
|
||||||
| **Cache Hit Rate** | Показывает процент запросов к данным, которые были удовлетворены из кэша (оперативной памяти), без обращения к диску. Показывает, насколько эффективно используется кэш PostgreSQL. |
|
|
||||||
| **Buffers (bgwriter)** | Метрика, показывающая активность фонового процесса записи, который занимается синхронизацией данных из оперативной памяти на диск. |
|
|
||||||
| **Conflicts/Deadlocks** | Метрика, отслеживающая две проблемы при работе с базой данных: конфликты восстановления и взаимоблокировки. |
|
|
||||||
| **Temp File (Bytes)** | Объем данных, записанных во временные файлы при выполнении запросов в базах данных. PostgreSQL создает временные файлы на диске, когда для выполнения запроса не хватает оперативной памяти. |
|
|
||||||
| **Checkpoint Stats** | Метрика, показывающая время, затрачиваемое на выполнение checkpoints в PostgreSQL, где: <br>- write_time - время, затраченное на запись данных на диск во время checkpoint (сколько миллисекунд ушло на запись файлов).<br>- sync_time - время, затраченное на синхронизацию файлов с диском (чтобы данные гарантированно сохранились). |
|
|
||||||
|
|
||||||
## Блок метрик Patroni
|
|
||||||
|
|
||||||
Данный блок метрик отображает состояние и конфигурацию кластера PostgreSQL под управлением Patroni. Эти метрики позволяют контролировать отказоустойчивость кластера, отслеживать переключения мастера и убеждаться, что репликация работает штатно.
|
|
||||||
|
|
||||||
| Наименование метрики | Описание метрики |
|
|
||||||
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| **Patroni Leader** | Метрика, которая показывает, какая нода в кластере PostgreSQL в данный момент является master-сервером, принимающим запросы на запись. |
|
|
||||||
| **Patroni Replica** | Метрика, которая показывает, какие узлы кластера PostgreSQL в данный момент выполняют роль реплики. |
|
|
||||||
| **Sync Standby** | Метрика, которая показывает, какая из реплик в кластере PostgreSQL назначена синхронной. |
|
|
||||||
| **PostgreSQL WAL Replay** | Метрика, которая показывает, включена ли на узлах кластера синхронизация данных через WAL. |
|
|
||||||
| **PostgreSQL Pending Restart** | Метрика, которая показывает, требуется ли перезагрузка PostgreSQL на узлах кластера после изменения конфигурационных параметров. |
|
|
||||||
| **Patroni Primary Node** | Метрика, которая показывает, какой узел в кластере PostgreSQL в данный момент является основным и принимает запросы на запись. |
|
|
||||||
| **Patroni Secondary Nodes** | Метрика, которая показывает, какие узлы кластера PostgreSQL в определенные моменты времени выполняли роль реплик. |
|
|
||||||
| **Replicas Received WAL Location** | Метрика, показывающая объем журналов предзаписи (WAL), полученных каждой репликой кластера. |
|
|
||||||
| **Primary WAL Location** | Метрика, показывающая объем журналов предзаписи (WAL), на основном сервере кластера PostgreSQL. |
|
|
||||||
| **Replicas Replayed WAL Location** | Метрика, показывающая объем журналов предзаписи (WAL), которые были не просто получены, а уже применены на репликах кластера. |
|
|
||||||
| **WAL Replay Paused** | Метрика, которая отслеживает, не приостановлен ли процесс применения WAL-журналов на узлах кластера. Если передача или применение WAL-файлов останавливается, на графике происходит скачок. |
|
|
||||||
|
|
||||||
## Блок метрик Hosts
|
|
||||||
|
|
||||||
Блок Hosts управляется селектором **Cluster node name**. Данный блок метрик отображает состояние и ресурсы серверов, на которых развернут кластер PostgreSQL. Эти метрики позволяют оценить, хватает ли серверу ресурсов для текущей нагрузки, и своевременно обнаружить проблемы с производительностью или нехваткой места на дисках.
|
|
||||||
|
|
||||||
| Наименование метрики | Описание метрики |
|
|
||||||
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| **CPU Busy** | Метрика, показывающая общую загруженность всех процессорных ядер на сервере, где работает PostgreSQL. |
|
|
||||||
| **RAM Used** | Метрика, показывающая процент оперативной памяти, который занят на сервере всеми процессами. |
|
|
||||||
| **CPU Cores** | Метрика, показывающая общее количество процессорных ядер, доступных на сервере, где работает PostgreSQL. |
|
|
||||||
| **RAM Total** | Метрика, показывающая общий объем оперативной памяти, установленный на сервере. |
|
|
||||||
| **DB Disk Total** | Метрика, показывающая общий объем дискового пространства, выделенного для хранения данных базы данных PostgreSQL на сервере. |
|
|
||||||
| **CPU Basic** | Метрика, которая показывает детальную разбивку загрузки процессора по типам выполняемых задач. Она позволяет увидеть, на что именно тратится процессорное время на сервере. |
|
|
||||||
| **Memory Basic** | Метрика, которая показывает детальную разбивку использования оперативной памяти на сервере, а также информацию о SWAP. |
|
|
||||||
| **Disk IOps** | Метрика, показывающая количество операций чтения и записи, выполняемых на диске сервера в секунду. |
|
|
||||||
| **Disk Space Used Basic** | Метрика, показывающая процент занятого дискового пространства на всех подключенных файловых системах сервера. |
|
|
||||||
| **Disk R/W Data** | Показывает объем данных в байтах, читаемых с диска и записываемых на диск в секунду. |
|
|
||||||
| **Filesystem space available** | Метрика, показывающая объем свободного дискового пространства на файловой системе сервера. |
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# PgAdmin
|
|
||||||
|
|
||||||
После предоставления доступа к сервису Cloud PostgreSQL пользователь получает возможность управлять базами данных через веб-интерфейс pgAdmin. Ниже приведена инструкция по входу в систему и выполнению основных операций.
|
|
||||||
|
|
||||||
## Вход в pgAdmin
|
|
||||||
|
|
||||||
1. Откройте веб-браузер и перейдите по адресу, предоставленному для доступа к pgAdmin;
|
|
||||||
2. На странице авторизации введите **логин и пароль от pgAdmin**;
|
|
||||||
> Учетные данные направляются пользователю на электронную почту при предоставлении доступа.
|
|
||||||
3. После входа в систему в левой панели навигации откройте раздел **Servers**;
|
|
||||||
4. Выберите предварительно настроенный сервер с названием **PostgreSQL**;
|
|
||||||
5. В открывшемся окне введите пароль;
|
|
||||||
> Важно: на данном этапе необходимо указать **пароль учетной записи базы данных**, а не пароль от pgAdmin.
|
|
||||||
6. Нажмите **ОК**;
|
|
||||||
7. После успешной аутентификации станет доступен веб-интерфейс СУБД PostgreSQL.
|
|
||||||
|
|
||||||
## Просмотр реплик и параметров конфигурации
|
|
||||||
|
|
||||||
pgAdmin позволяет осуществлять мониторинг реплик, входящих в состав кластера.
|
|
||||||
|
|
||||||
Чтобы просмотреть список реплик:
|
|
||||||
- Откройте раздел **Replica nodes** в панели навигации.
|
|
||||||
|
|
||||||
Чтобы проверить состояние репликации:
|
|
||||||
1. Выберите нужную реплику в разделе **Replica nodes**;
|
|
||||||
2. Перейдите в подраздел **Replication**;
|
|
||||||
3. Откройте пункт **Replication stats**;
|
|
||||||
4. Разверните раздел **Подробности** - в нем отображаются все параметры и текущее состояние репликации;
|
|
||||||
> Вкладка **Replication** позволяет определить, выполняется ли передача данных на дополнительные узлы кластера.
|
|
||||||
|
|
||||||
Так же, есть возможность посмотреть **параметры конфигурации PostgreSQL**, применённых к конкретной реплике. Для этого необходимо перейти в раздел **Конфигурация**, который расположен в блоке **Replica nodes**.
|
|
||||||
|
|
||||||
Во вкладке отображается таблица со следующими колонками:
|
|
||||||
- **Имя** - наименование конфигурационного параметра;
|
|
||||||
- **Категория** - логическая группа параметра;
|
|
||||||
- **Значение** - текущее установленное значение;
|
|
||||||
- **Единицы** - единицы измерения (если применимо);
|
|
||||||
- **Описание** - краткое пояснение назначения параметра.
|
|
||||||
> Вкладка **Конфигурация** предназначена для просмотра текущих настроек реплики.
|
|
||||||
## Просмотр и управление базами данных
|
|
||||||
|
|
||||||
Для просмотра существующих баз данных:
|
|
||||||
- Откройте раздел **Базы данных** в панели навигации. В этом разделе отображается перечень всех созданных баз.
|
|
||||||
|
|
||||||
Для создания новой базы данных:
|
|
||||||
1. Щелкните правой кнопкой мыши по разделу **Базы данных**;
|
|
||||||
2. В контекстном меню выберите **Создать**, затем - **База данных**;
|
|
||||||
3. Заполните обязательные поля в открывшейся форме;
|
|
||||||
4. Нажмите **Сохранить**.
|
|
||||||
## Роли входа / группы
|
|
||||||
|
|
||||||
В разделе **Роли входа/группы** отображается список пользователей (ролей), имеющих доступ к базам данных кластера.
|
|
||||||
|
|
||||||
Для создания новой роли:
|
|
||||||
1. Щелкните правой кнопкой мыши по разделу **Роли входа/группы**;
|
|
||||||
2. Выберите **Создать**, затем - **Роль входа/группы**;
|
|
||||||
3. Заполните необходимые параметры в форме создания роли;
|
|
||||||
4. Нажмите **Сохранить**.
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
# Создание сервиса Cloud PostgreSQL
|
|
||||||
|
|
||||||
Данный раздел описывает права, которые предоставляются пользователю PostgreSQL при создании сервиса **Cloud PostgreSQ**L**, а также перечень административных операций, доступных ему для самостоятельного выполнения.
|
|
||||||
|
|
||||||
При развертывании сервиса автоматически создаётся пользователь базы данных с преднастроенными атрибутами и привилегиями. Эти права позволяют заказчику самостоятельно управлять своими базами данных, ролями и пользователями в рамках созданного экземпляра PostgreSQL.
|
|
||||||
|
|
||||||
## Общая информация о пользователе
|
|
||||||
|
|
||||||
При инициализации сервиса автоматически создаётся пользователь:
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
client
|
|
||||||
```
|
|
||||||
|
|
||||||
Данный пользователь является основной учётной записью для административной работы в рамках предоставленного экземпляра PostgreSQL. Он предназначен для самостоятельного управления базами данных, ролями и правами доступа в пределах выданных привилегий.
|
|
||||||
|
|
||||||
## Выданные права и ограничения
|
|
||||||
|
|
||||||
Пользователю `client` назначается набор атрибутов и привилегий, позволяющих выполнять административные операции в рамках своего экземпляра базы данных.
|
|
||||||
|
|
||||||
### Атрибуты роли
|
|
||||||
|
|
||||||
Пользователь создаётся со следующими атрибутами:
|
|
||||||
- `CREATEDB` — разрешено создание и удаление баз данных;
|
|
||||||
- `CREATEROLE` — разрешено создание ролей и пользователей, а также управление их.
|
|
||||||
|
|
||||||
Атрибут `SUPERUSER` пользователю не предоставляется. Соответственно, доступ к системным операциям уровня кластера и настройкам сервера отсутствует.
|
|
||||||
|
|
||||||
### Права на системную базу postgres:
|
|
||||||
|
|
||||||
К стандартной базе данных `postgres` пользователю предоставлено только право подключения:
|
|
||||||
- `CONNECT`
|
|
||||||
Иные привилегии (создание объектов, изменение схем и т.д.) на данную базу не выдаются.
|
|
||||||
|
|
||||||
### Мониторинг и системные представления:
|
|
||||||
|
|
||||||
Для выполнения базовых задач мониторинга пользователю дополнительно предоставлены:
|
|
||||||
- членство в роли `pg_monitor`;
|
|
||||||
- право `SELECT` на системное представление:
|
|
||||||
```sql
|
|
||||||
pg_catalog.pg_stat_replication
|
|
||||||
```
|
|
||||||
|
|
||||||
Доступ к системной информации предоставляется исключительно в режиме чтения. Изменение системных представлений и параметров сервера недоступно.
|
|
||||||
|
|
||||||
## Обязательная смена пароля
|
|
||||||
|
|
||||||
После первого подключения к базе данных пользователь `client` обязан выполнить смену пароля.
|
|
||||||
Смена пароля может быть выполнена:
|
|
||||||
- в открытом виде (с передачей нового значения пароля);
|
|
||||||
- с указанием заранее сгенерированного хэша.
|
|
||||||
|
|
||||||
На сервере используется алгоритм шифрования паролей:
|
|
||||||
|
|
||||||
```
|
|
||||||
scram-sha-256
|
|
||||||
```
|
|
||||||
|
|
||||||
При использовании SCRAM применяется следующий формат хэша:
|
|
||||||
|
|
||||||
```
|
|
||||||
$<iterations>:<salt>$<storedkey>:<serverkey>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Пример смены пароля в открытом виде
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER USER client WITH PASSWORD 'new_strong_password';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Пример смены пароля с указанием хэша
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER USER client WITH ENCRYPTED PASSWORD '$4096:...';
|
|
||||||
```
|
|
||||||
|
|
||||||
Рекомендуется использовать сложный уникальный пароль, соответствующий требованиям информационной безопасности, и хранить его в защищённом хранилище.
|
|
||||||
|
|
||||||
## Создание новой базы данных
|
|
||||||
|
|
||||||
Пользователь `client` имеет право создавать новые базы данных в рамках своего экземпляра PostgreSQL.
|
|
||||||
|
|
||||||
### Пример создания базы данных
|
|
||||||
|
|
||||||
Для создания базы данных используется стандартная команда:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE DATABASE app_db;
|
|
||||||
```
|
|
||||||
|
|
||||||
Если необходимо назначить владельца базы данных, можно указать соответствующего пользователя. По умолчанию владельцем создаваемой базы данных является пользователь, который её создает.
|
|
||||||
|
|
||||||
### Пример создания базы данных с указанием владельца
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE DATABASE app_db OWNER client;
|
|
||||||
```
|
|
||||||
|
|
||||||
В этом примере база данных `app_db` будет принадлежать пользователю `client`. Пользователь, указанный как владелец, будет иметь полный контроль над базой данных, включая права на её удаление и изменение.
|
|
||||||
|
|
||||||
## Создание пользователей и ролей
|
|
||||||
|
|
||||||
Пользователь `client` имеет право создавать новые роли и пользователей для приложений, а также управлять их правами доступа.
|
|
||||||
|
|
||||||
### Создание роли без логина
|
|
||||||
|
|
||||||
Если требуется создать роль, которая не будет иметь возможности входа в базу данных (например, для организации прав доступа), можно использовать команду:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE ROLE app_role;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Создание пользователя с паролем
|
|
||||||
|
|
||||||
Для создания пользователя с паролем используется команда:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE USER app_user WITH PASSWORD 'app_password';
|
|
||||||
```
|
|
||||||
|
|
||||||
После этого новый пользователь `app_user` будет иметь возможность входа в базу данных, используя указанный пароль.
|
|
||||||
|
|
||||||
### Назначение роли пользователю
|
|
||||||
|
|
||||||
Для назначения роли пользователю используется команда `GRANT`. Это позволяет управлять правами пользователя в рамках определённой роли:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
GRANT app_role TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
После выполнения этой команды пользователь `app_user` станет членом роли `app_role`, и будет наследовать все права, связанные с этой ролью.
|
|
||||||
|
|
||||||
### Передача владельца базы данных
|
|
||||||
|
|
||||||
Если необходимо передать право владения базой данных другому пользователю, это можно сделать с помощью следующей команды:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER DATABASE app_db OWNER TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
Теперь база данных `app_db` будет принадлежать пользователю `app_user`, и он будет иметь полный контроль над ней.
|
|
||||||
|
|
||||||
### Управление правами доступа
|
|
||||||
|
|
||||||
После создания пользователей и ролей необходимо назначить им соответствующие права доступа.
|
|
||||||
|
|
||||||
### Выдача прав на подключение к базе данных
|
|
||||||
|
|
||||||
Для того чтобы пользователь мог подключаться к базе данных, нужно предоставить ему соответствующие права:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
GRANT CONNECT ON DATABASE app_db TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
Эта команда разрешает пользователю `app_user` подключаться к базе данных `app_db`.
|
|
||||||
|
|
||||||
### Права на схему public
|
|
||||||
|
|
||||||
Для предоставления пользователю прав на использование схемы `public` можно выполнить следующую команду:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
GRANT USAGE, CREATE ON SCHEMA public TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
Эти права позволяют пользователю `app_user` использовать объекты в схеме `public`, а также создавать новые объекты внутри неё.
|
|
||||||
|
|
||||||
### Права на существующие таблицы
|
|
||||||
|
|
||||||
Чтобы предоставить пользователю доступ к существующим таблицам в схеме `public`, можно использовать команду:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
Эта команда позволяет пользователю `app_user` выполнять операции чтения, вставки, обновления и удаления данных в существующих таблицах схемы `public`.
|
|
||||||
|
|
||||||
### Права на будущие таблицы
|
|
||||||
|
|
||||||
Если необходимо автоматически предоставить пользователю права на новые таблицы, создаваемые в схеме `public`, используйте команду:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
|
||||||
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
|
|
||||||
```
|
|
||||||
|
|
||||||
Эта команда обеспечит, что все будущие таблицы, создаваемые в схеме `public`, будут автоматически иметь права для пользователя `app_user` на чтение, вставку, обновление и удаление данных.
|
|
||||||
|
|
||||||
## Мониторинг репликации
|
|
||||||
|
|
||||||
Пользователь `client` имеет доступ к системным представлениям для мониторинга состояния репликации в кластере PostgreSQL.
|
|
||||||
|
|
||||||
### Просмотр состояния репликации
|
|
||||||
|
|
||||||
Для того чтобы просмотреть текущий статус репликации, пользователь может выполнить запрос к системному представлению:
|
|
||||||
|
|
||||||
``` SQL
|
|
||||||
SELECT * FROM pg_stat_replication;
|
|
||||||
```
|
|
||||||
Этот запрос возвращает информацию о всех репликах, подключённых к основному (primary) серверу.
|
|
||||||
|
|
||||||
### Ограничения доступа
|
|
||||||
|
|
||||||
Пользователь `client` имеет доступ к данным в представлении `pg_stat_replication` только в режиме **read-only**. Это означает, что он может просматривать состояние репликации, но не может изменять или вмешиваться в процесс репликации.
|
|
||||||
@@ -7,7 +7,7 @@ section_links:
|
|||||||
link: /compute/compute-how-to/compute-connect-inside.md
|
link: /compute/compute-how-to/compute-connect-inside.md
|
||||||
description: Подключиться к виртуальной машине по SSH с помощью ключевой пары по внутреннему IP-адресу через джамп-хост
|
description: Подключиться к виртуальной машине по SSH с помощью ключевой пары по внутреннему IP-адресу через джамп-хост
|
||||||
- title: Подключение по SSH по логину и паролю
|
- title: Подключение по SSH по логину и паролю
|
||||||
link: /compute/compute-how-to/compute-connect-inside.md
|
link: /compute/compute-how-to/compute-connect-pwd.md
|
||||||
description: Подключиться к виртуальной машине по SSH с помощью логина и пароля
|
description: Подключиться к виртуальной машине по SSH с помощью логина и пароля
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user