Контейнеризація конфігурації
Конфігурація, створена через kandra-new-config, уже містить усе потрібне, щоб зібрати й запустити власний
образ контейнера: Dockerfile, .dockerignore, .env.example і по одному compose-файлу на кожного
провайдера бази даних, якого ви обрали. Ця сторінка проводить крізь ці файли, щоб ви знали, що змінювати, а що
залишити як є. Створення та розгортання конфігурації описує, що застосунок робить після
запуску; ця сторінка — лише про те, як покласти його в контейнер.
Файли такі самі, як у еталонної конфігурації Kandra WMS; шаблон підставляє в них назву вашої конфігурації. Їх перевірено наскрізно на всіх трьох провайдерах (збірка з публічного фіду, застосування міграцій, відповідь HTTP 200 на порту 8080). У конкретній хмарі чи оркестраторі нічого з цього не запускали.
Майстер питає «Include Docker files?». З dotnet new kandra-config --IncludeDocker false жодного з файлів
нижче не буде створено, а кожен compose.<provider>.yml також залежить від прапорця Include<Provider>:
конфігурація без PostgreSQL не має compose.postgres.yml.
Що ви отримуєте
| Файл | Призначення |
|---|---|
Dockerfile | Дві стадії: образ SDK публікує веб-хост, образ ASP.NET runtime його запускає |
.dockerignore | Не пускає в контекст збірки bin/, obj/, .git, локальні бази та секрети |
.env.example | Змінні, які читають compose-файли; скопіюйте в .env (ніколи не комітьте .env) |
compose.sqlite.yml | Один контейнер і один том |
compose.sqlserver.yml | Застосунок плюс SQL Server Express |
compose.postgres.yml | Застосунок плюс PostgreSQL 18 |
compose.demo.yml | Необов'язкове накладення для заповненої демо-системи (див. нижче) |
.gitattributes | Фіксує для цих файлів закінчення рядків LF, щоб checkout у Windows не зламав скрипти в образі |
Для конфігурації Acme образ називається kandra-acme; так само називаються файл SQLite і база даних у SQL
Server та PostgreSQL.
Збірка й запуск
docker compose -f compose.sqlite.yml up -d --build
Відкрийте http://localhost:8080. Перший запуск застосовує міграції та сіди так само, як dotnet run, а майстер
першого запуску питає пароль адміністратора.
docker compose -f compose.sqlite.yml down # зупинити, дані лишаються в томі
docker compose -f compose.sqlite.yml down -v # зупинити І видалити всі дані
down -v видаляє іменовані томи, разом з базою даних і ключем підпису. Для скидання це те, що треба, а на
сервері, який вам дорогий, — ніколи.
Щоб зібрати образ без compose:
docker build -t acme .
docker buildx build --platform linux/amd64,linux/arm64 --build-arg VERSION=1.0.0 -t acme:1.0.0 .
Dockerfile крок за кроком
Restore іде з публічного фіду. Збірка в Docker копіює всю теку (крім виключеного .dockerignore) і виконує
dotnet publish для src/Acme.WebApi. Пакети відновлюються анонімно з фіду у вашому nuget.config
(https://nugets.kandra.tech/index.json з packageSourceMapping), тож збірці не потрібні ні токен, ні секрет.
Якщо ви замінили цей фід приватним дзеркалом, дайте збірці доступ до нього звичайним для Docker способом
(секрет BuildKit), а не копіюванням облікових даних в образ.
Один образ для всіх провайдерів. Про базу даних в образ нічого не зашито. Provider=Sqlite, SqlServer або
PostgreSql і відповідний рядок підключення — це звичайні змінні середовища під час запуску, тож той самий образ
працює з будь-яким із провайдерів, яких ви обрали.
Аргументи збірки.
| Аргумент | За замовчуванням | Дія |
|---|---|---|
VERSION | 0.0.0 | Потрапляє в інформаційну версію та мітку org.opencontainers.image.version |
KANDRA_CORE_VERSION | порожньо | Перевизначає точну версію Kandra Core з Directory.Build.props; порожньо — збірка з прив'язаною версією |
TARGETARCH задає BuildKit. Публікація за ним обирає x64 або arm64, а стадія SDK виконується на платформі
машини збірки (--platform=$BUILDPLATFORM), тож багатоархітектурна збірка не запускає компілятор під емуляцією.
Тека даних. Стадія runtime створює /data з власником app, задає Kandra__DataPath=/data і оголошує її
VOLUME. Усе, що екземпляр зберігає на власному диску (файл SQLite, завантажені вкладення, згенерований
JWT-ключ, резервні копії перед міграціями), лежить у цій одній теці; див.
Папка даних. Змонтуйте туди том, і повторне розгортання нічого не втратить.
Не root. Образ завершується USER app (uid 1654 в офіційному образі ASP.NET). Саме тому /data створюється
й передається app в образі. Bind mount з хоста належить тому, хто створив теку, тож застосунок не зможе
писати в неї, поки ви не виконаєте chown 1654; іменований том успадковує власника теки з образу і просто
працює. Compose-файли використовують іменовані томи.
Порт. ASPNETCORE_URLS=http://+:8080: контейнер говорить простим HTTP на 8080 (користувач без прав root не
може зайняти порт нижче 1024). TLS завершується перед ним.
Forwarded headers. ASPNETCORE_FORWARDEDHEADERS_ENABLED=true змушує застосунок довіряти X-Forwarded-For і
X-Forwarded-Proto, тож за зворотним проксі він бачить справжню адресу клієнта й схему https. Від цього
залежать і перенаправлення на HTTPS, і згенеровані URL. Але це також означає, що застосунок довіряє цим
заголовкам від будь-кого, хто дотягнеться до порту 8080, тож відкривайте 8080 лише проксі (приватна мережа,
127.0.0.1:8080:8080), ніколи в інтернет.
Server GC вимкнено. DOTNET_gcServer=0 обирає workstation GC, який тримає малим споживання пам'яті для
схеми «один екземпляр на контейнер».
Мітки. Шаблон задає org.opencontainers.image.title і version. Додайте source, vendor і licenses
для вашої конфігурації у позначеному місці. Файли належать вам з моменту створення: образ не містить копії EULA
Kandra чи мітки ліцензії Kandra.
Вибір провайдера під час запуску
Кожен compose-файл задає одні й ті самі три речі:
environment:
Provider: PostgreSql
ConnectionStrings__PostgreSql: "Host=db;Database=kandra-acme;Username=kandra;Password=${POSTGRES_PASSWORD}"
JwtOptions__Audience: ${APP_PUBLIC_URL:-http://localhost:8080}
Provider обирає провайдера бази даних, а ConnectionStrings__<Provider> — його рядок підключення
(див. Конфігурація). Щоб запустити готовий образ із базою, яку ви розміщуєте
деінде, задайте ці дві змінні й приберіть сервіс db з compose.
| Compose-файл | Сервіс бази даних | Томи |
|---|---|---|
compose.sqlite.yml | немає: файл лежить у /data/db | app-data |
compose.sqlserver.yml | mcr.microsoft.com/mssql/server:2025-latest, MSSQL_PID=Express | sql-data у /var/opt/mssql, app-data |
compose.postgres.yml | postgres:18 | pg-data у /var/lib/postgresql, app-data |
Образ SQL Server зібрано лише для x64. На машині з arm64 (Mac з Apple Silicon, Windows on Arm, Raspberry Pi,
AWS Graviton, віртуальні машини Azure Ampere) compose.sqlserver.yml прив'язує сервіс db до
platform: linux/amd64, тож Docker запускає його під емуляцією: це повільно, перший запуск може тривати хвилини,
а залежно від середовища Docker він може збоїти чи впасти. Не використовуйте це ні для чого, крім швидкої
локальної проби.
- На arm64 використовуйте
compose.postgres.ymlабоcompose.sqlite.yml. Сам образ застосунку багатоархітектурний (linux/amd64іlinux/arm64), лише образ бази SQL Server — ні. - Для production-хоста на arm64 потрібна база, що не є цим контейнером: PostgreSQL або керований SQL Server (Azure SQL, Amazon RDS), до якого ви підключаєтеся рядком підключення.
Деталі, у яких легко помилитися:
- Застосунок чекає на базу. Для SQL Server і PostgreSQL сервіс
dbмає healthcheck, а застосунок —depends_on: condition: service_healthy. Міграції виконуються під час старту, і застосунок, що стартував раніше за базу, падає. Зберігайте цю залежність, якщо редагуєте файл. - PostgreSQL 18 змінив том. Монтуйте том у
/var/lib/postgresql(дані лежать у підтеці з версією). Шлях/var/lib/postgresql/data, який діяв до 17, на 18 не працює. - Образ SQL Server. Він великий (близько 2,4 ГБ), тож перше завантаження повільне (див. попередження про
arm64 вище). Compose-файл задає редакцію Express, бо Developer не ліцензовано для промислового
використання. Пароль
saмає відповідати вимогам складності SQL Server (MSSQL_SA_PASSWORDу.env), аTrustServerCertificate=Trueу рядку підключення призначений лише для приватної мережі compose: з керованим SQL Server використовуйте довірений сертифікат і приберіть його. - Завантажені файли лишаються в
/data. У SQL Server і PostgreSQL у базі зберігаються лише вкладення до 8 КБ; більші йдуть у/data/blobs, тож на цих провайдерах також зберігайте томapp-data. - Назва бази з дефісом — нормально.
kandra-acmeпрацює без лапок у згенерованих міграціях на обох серверах. - У compose-файлах немає healthcheck для самого застосунку. Хост відповідає на
/health/liveі/health/ready(Ендпоінти стану); спрямуйте на них HTTP-проби оркестратора, а не додавайте команднийHEALTHCHECK, якому потрібен інструмент, якого в образі немає.
Змінні
.env.example перелічує змінні, які читають compose-файли:
| Змінна | За замовчуванням | Що робить |
|---|---|---|
POSTGRES_PASSWORD | обов'язкова для PostgreSQL | Пароль бази даних |
MSSQL_SA_PASSWORD | обов'язкова для SQL Server | Пароль sa |
APP_TAG / APP_IMAGE | latest / kandra-acme | Тег і назва образу; у всьому, що розгортаєте, фіксуйте тег |
APP_PORT | 8080 | Порт на хості |
APP_PUBLIC_URL | http://localhost:8080 | Стає JwtOptions__Audience |
APP_JWT_SECRET | порожньо | Порожньо: ключ екземпляра генерується в /data/keys |
APP_ADMIN_PASSWORD | порожньо | Задає пароль адміністратора лише при свіжій установці; порожньо: питає майстер |
Compose-файл відмовляється стартувати без пароля бази (${POSTGRES_PASSWORD:?...}), тож забутий .env
призводить до гучної помилки, а не до запуску з порожнім паролем.
Демо-накладення
compose.demo.yml додає два налаштування до сервісу застосунку:
docker compose -f compose.sqlite.yml -f compose.demo.yml up -d --build
ACCEPT_EULA=Y приймає ліцензійну угоду без майстра, а Kandra__Setup__Mode=Demo змушує перший запуск
застосувати демо-пакет імпорту й створити демо-користувачів. Шаблон постачає пакет імпорту
(src/Acme.Application/ImportPackages) і список демо-користувачів (Seeding/AcmeDemoUsers.cs) порожніми:
заповніть їх, і одна команда дасть оцінювачу заповнену систему. Див. Імпорт даних і демодані.
Ніколи не використовуйте накладення для справжньої установки: воно наперед приймає ліцензію й створює
користувачів зі відомими паролями.
Чекліст безпечних для production налаштувань
Compose-файли призначені стартувати однією командою; деякі їхні значення за замовчуванням не для production. Пройдіть цей список разом із Перед тим, як відкривати доступ до першого справжнього розгортання:
- Не використовуйте демо-накладення і не задавайте
ACCEPT_EULAчиKandra__Setup__Modeна справжній установці. - Задайте пароль адміністратора при першому запуску (
APP_ADMIN_PASSWORDабо відповідь у майстрі) і потім приберіть змінну. Вона діє лише на свіжу установку. - Фіксуйте тег образу (
APP_TAG=1.4.2), а неlatest, і зберігайте старі теги, щоб мати змогу відкотитися (але див. історія міграцій — це контракт: відкіт після міграції потребує відновлення бази). - Тримайте секрети поза репозиторієм і образом:
.envу.dockerignoreі має бути в.gitignore. Надавайте перевагу сховищу секретів вашої платформи, а не файлу.envна сервері. - Задайте справжній
APP_PUBLIC_URL(JwtOptions__Audience) і вирішіть, чи задаватиAPP_JWT_SECRETсамостійно. Це обов'язково, якщо ви колись запускатимете більше одного контейнера, бо вони мають ділити один ключ. - Завершуйте TLS у зворотному проксі і відкривайте порт 8080 лише йому (
127.0.0.1:8080:8080або приватна мережа). Контейнер говорить простим HTTP. - Не відкривайте порт бази даних. Compose-файли цього не роблять, а доданий запис
ports:уdbвідкриває її в мережу. - Робіть резервні копії томів:
app-dataзавжди (вкладення, ключ підпису, копії SQLite) і том бази (pg-data,sql-data) або керовану базу. Том — не резервна копія; див. Папка даних та Резервні копії перед міграціями. - Вимкніть Swagger (
Kandra__Swagger__Enabled=false), якщо не хочете публічної документації API, і перелічіть будь-які інші origin уKandra__Cors__AllowedOrigins__0. - Запускайте один контейнер. Планувальник і кеш звітів існують у межах процесу; див. Запуск кількох екземплярів.
- Використовуйте базу, яку ви відпрацювали. SQLite в одному контейнері підходить для невеликої установки; для SQL Server чи PostgreSQL пройдіть увесь шлях (міграції, сіди, ваші дані) до того, як покладатися на них.
- Перезбирайте при оновленні базових образів. Образ runtime — звичайний
mcr.microsoft.com/dotnet/aspnet:10.0; перезбірка підтягує патчі ОС і runtime.
Підводні камені
- Закінчення рядків. Checkout у Windows з
core.autocrlf=trueпереписує файли на CRLF;.gitattributesфіксує для файлів контейнера LF. Збережіть його, якщо переносите репозиторій. - Образ застосовує міграції, з якими його зібрано. Після
kandra-migrate add(див. Міграції бази даних) перезберіть образ; перезапуск старого нічого не змінить. down -v— повне скидання, разом із JWT-ключем. Усі відкриті сесії стають недійсними.- Кешовані шари збірки.
docker compose up -d --buildвикористовує шари повторно; змінилиDirectory.Build.propsабо версію Kandra і підозрюєте застарілий шар — додайте--no-cache. - Перший запуск SQL Server повільний. Healthcheck має 30 секунд початкового періоду й 20 повторів саме через це; на повільнішій машині може знадобитися більше.
Див. також
- Створення та розгортання конфігурації: що застосунок робить на старті, ендпоінти стану, тека даних, резервні копії, ліцензування.
- Як почати: створення конфігурації, фід NuGet, майстер.
- Міграції бази даних: як база отримує схему, і
kandra-migrate. - Імпорт даних і демодані: що наповнює демо-накладення.