Перейти до основного вмісту

Контейнеризація конфігурації

Конфігурація, створена через 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 і відповідний рядок підключення — це звичайні змінні середовища під час запуску, тож той самий образ працює з будь-яким із провайдерів, яких ви обрали.

Аргументи збірки.

АргументЗа замовчуваннямДія
VERSION0.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/dbapp-data
compose.sqlserver.ymlmcr.microsoft.com/mssql/server:2025-latest, MSSQL_PID=Expresssql-data у /var/opt/mssql, app-data
compose.postgres.ymlpostgres:18pg-data у /var/lib/postgresql, app-data
SQL Server не працює нативно на arm64

Образ 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_IMAGElatest / kandra-acmeТег і назва образу; у всьому, що розгортаєте, фіксуйте тег
APP_PORT8080Порт на хості
APP_PUBLIC_URLhttp://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. Пройдіть цей список разом із Перед тим, як відкривати доступ до першого справжнього розгортання:

  1. Не використовуйте демо-накладення і не задавайте ACCEPT_EULA чи Kandra__Setup__Mode на справжній установці.
  2. Задайте пароль адміністратора при першому запуску (APP_ADMIN_PASSWORD або відповідь у майстрі) і потім приберіть змінну. Вона діє лише на свіжу установку.
  3. Фіксуйте тег образу (APP_TAG=1.4.2), а не latest, і зберігайте старі теги, щоб мати змогу відкотитися (але див. історія міграцій — це контракт: відкіт після міграції потребує відновлення бази).
  4. Тримайте секрети поза репозиторієм і образом: .env у .dockerignore і має бути в .gitignore. Надавайте перевагу сховищу секретів вашої платформи, а не файлу .env на сервері.
  5. Задайте справжній APP_PUBLIC_URL (JwtOptions__Audience) і вирішіть, чи задавати APP_JWT_SECRET самостійно. Це обов'язково, якщо ви колись запускатимете більше одного контейнера, бо вони мають ділити один ключ.
  6. Завершуйте TLS у зворотному проксі і відкривайте порт 8080 лише йому (127.0.0.1:8080:8080 або приватна мережа). Контейнер говорить простим HTTP.
  7. Не відкривайте порт бази даних. Compose-файли цього не роблять, а доданий запис ports: у db відкриває її в мережу.
  8. Робіть резервні копії томів: app-data завжди (вкладення, ключ підпису, копії SQLite) і том бази (pg-data, sql-data) або керовану базу. Том — не резервна копія; див. Папка даних та Резервні копії перед міграціями.
  9. Вимкніть Swagger (Kandra__Swagger__Enabled=false), якщо не хочете публічної документації API, і перелічіть будь-які інші origin у Kandra__Cors__AllowedOrigins__0.
  10. Запускайте один контейнер. Планувальник і кеш звітів існують у межах процесу; див. Запуск кількох екземплярів.
  11. Використовуйте базу, яку ви відпрацювали. SQLite в одному контейнері підходить для невеликої установки; для SQL Server чи PostgreSQL пройдіть увесь шлях (міграції, сіди, ваші дані) до того, як покладатися на них.
  12. Перезбирайте при оновленні базових образів. Образ 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 повторів саме через це; на повільнішій машині може знадобитися більше.

Див. також​