> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/opere/configurar-e-hospedar/container-kubernetes-e-azure.md).

# Container, Kubernetes e Azure

O runtime do skail roda dentro do processo da sua aplicação e precisa de duas coisas: o registro do runtime na aplicação (em TypeScript, com o bundle gerado pelo `skail build`) e as variáveis de ambiente obrigatórias. Este guia começa pelo caso base, o processo da aplicação, e mostra só o que muda em cada modelo de hospedagem.

## Pré-requisitos

Um environment criado no portal (chave, namespace e endereço do skail anotados) e um workload com `nome:versao` definido. Em C#, .NET 8 ou superior e o pacote `Skail.Platform.Runtime`; em TypeScript, Node.js 20, 22 ou 24 em diante e os pacotes `@skail/runtime` e `@skail/build`. As quatro variáveis obrigatórias estão em [Como configurar o runtime](/opere/configurar-e-hospedar/configurar-o-runtime.md). A máquina que roda a aplicação também precisa estar com o relógio sincronizado; ver [Relógio dos servidores](/opere/configurar-e-hospedar/relogio-dos-servidores.md).

## O processo da aplicação (caso base)

O runtime busca trabalho no skail; é a sua aplicação que chama o skail, nunca o contrário. A aplicação não recebe chamadas de entrada, então não precisa expor porta HTTP.

{% tabs %}
{% tab title="C#" %}
Por isso o Worker Service é o modelo de hospedagem mais adequado.

```xml
<!-- Faturamento.Worker.csproj -->
<Project Sdk="Microsoft.NET.Sdk.Worker">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Skail.Platform.Runtime" Version="2.2.*" />
  </ItemGroup>
</Project>
```

{% endtab %}

{% tab title="TypeScript" %}
O host é um processo Node que cria a plataforma com `createSkailPlatform({ ... })` e roda com `platform.run(signal)`. Ele carrega o bundle (`skail-functions.mjs`) e o `manifest.json` que o `skail build` gera, e lê a configuração das variáveis `SKAIL_*`.
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="C#" %}

```csharp
// Program.cs
using Microsoft.Extensions.Hosting;
using Skail.Platform.Runtime;

[assembly: VisibleToSkailPlatform]

var builder = Host.CreateApplicationBuilder(args);

// seus serviços: DbContext, IHttpClientFactory, etc.
builder.UseSkail();

await builder.Build().RunAsync();
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// main.ts
import { createSkailPlatform } from "@skail/runtime";

const controller = new AbortController();

for (const signal of ["SIGINT", "SIGTERM"] as const) {
  process.once(signal, () => controller.abort());
}

const platform = createSkailPlatform({
  bundle: new URL("../.skail/skail-functions.mjs", import.meta.url),
  manifest: new URL("../.skail/manifest.json", import.meta.url),
});

await platform.run(controller.signal);
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="C#" %}
`UseSkail()` registra o `IHostedService` que busca trabalho no skail e registra como transient toda classe que contém métodos decorados, então a injeção por construtor funciona normalmente. Chame `UseSkail()` uma única vez por processo; a segunda chamada lança "The Builder Factory can only be registered once!".

{% hint style="info" %}
O pacote `Skail.Platform.Runtime` traz por dependência o `Skail.Platform.Runtime.Build`, que roda durante o `dotnet build`. Você não precisa configurar nada, mas o build precisa acontecer com esse pacote presente (vale para o build em container, adiante).
{% endhint %}

**Com ASP.NET Core**

Todos os exemplos oficiais usam `Host.CreateApplicationBuilder`, e é essa a estrutura que recomendamos, em dois processos: a API web (controllers, webhooks, telas) em um projeto ASP.NET Core que dispara funções e eventos pela API HTTP, e a aplicação skail em um Worker Service. Os dois compartilham uma biblioteca com os DTOs e as constantes de nome de evento. Essa separação também escala melhor: a API escala por requisições, a aplicação skail escala por execuções.

```
Faturamento.sln
  Faturamento.Contratos/     DTOs, records, class Eventos com as constantes
  Faturamento.Api/           ASP.NET Core: POST /api/v1/trigger e /api/v1/fire via HttpClient "skail"
  Faturamento.Worker/        Worker Service: [SkailFunction] e [SkailCommand], UseSkail()
```

Como a API chama o skail está em [Como disparar uma função pela API HTTP](/construa/como-fazer/disparar-uma-funcao-pela-api.md).
{% endtab %}

{% tab title="TypeScript" %}
O `skail build` varre os fontes, encontra as classes com os decorators e gera o bundle e o `manifest.json` que o host carrega; métodos `static`, `private` ou sem `async` são rejeitados ali. Gere o build antes de subir o host (vale para o build em container, adiante).

O runtime não infere parâmetros de construtor: os serviços entram pelo array `providers` exportado no entry point (com `useFactory`) ou são instanciados na própria classe.
{% endtab %}
{% endtabs %}

{% hint style="success" %}
O que você deve ver: a aplicação sobe sem erro e fica em espera por trabalho; o primeiro trigger aparece como execução no Monitor.
{% endhint %}

## Container

{% tabs %}
{% tab title="C#" %}
Use um build em duas etapas. O `dotnet publish` roda na imagem do SDK, onde o passo de build do skail acontece; a imagem final só precisa do runtime .NET.

```dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish Faturamento.Worker/Faturamento.Worker.csproj -c Release -o /app

FROM mcr.microsoft.com/dotnet/runtime:8.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "Faturamento.Worker.dll"]
```

{% hint style="info" %}
O `dotnet publish` baixa o `Skail.Platform.Runtime` do NuGet.org. Se o build roda sem acesso à internet, espelhe os pacotes `Skail.Platform.*` no feed interno da empresa.
{% endhint %}
{% endtab %}

{% tab title="TypeScript" %}
A imagem roda o host (`main.ts`) e precisa conter o bundle e o `manifest.json` gerados pelo `skail build`, que o host carrega ao subir.
{% endtab %}
{% endtabs %}

Passe a configuração por variável, nunca dentro da imagem:

```bash
docker run --rm \
  -e SKAIL_WORKLOAD=faturamento:v1.0.0 \
  -e SKAIL_NAMESPACE=SEU_NAMESPACE \
  -e SKAIL_KEY=SUA_SKAIL_KEY \
  -e SKAIL_SIDECAR=<endereço do skail> \
  registry.exemplo.com/faturamento-worker:1.0.0
```

Ou com `--env-file skail.env`, mantendo o arquivo fora do repositório.

## Kubernetes

Crie um `Deployment` sem `Service`, porque o worker não recebe tráfego. Chave e namespace vêm de um `Secret`; o restante em `env`.

```bash
kubectl create secret generic skail-faturamento \
  --from-literal=key=SUA_SKAIL_KEY \
  --from-literal=namespace=SEU_NAMESPACE
```

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: faturamento-worker-v1-0-0
spec:
  replicas: 2
  selector:
    matchLabels:
      app: faturamento-worker
      versao: v1-0-0
  template:
    metadata:
      labels:
        app: faturamento-worker
        versao: v1-0-0
    spec:
      containers:
        - name: worker
          image: registry.exemplo.com/faturamento-worker:1.0.0
          env:
            - name: SKAIL_WORKLOAD
              value: "faturamento:v1.0.0"
            - name: SKAIL_SIDECAR
              value: "<endereço do skail>"
            - name: SKAIL_MAX_PARALLEL_TASKS
              value: "4"
            - name: SKAIL_NAMESPACE
              valueFrom:
                secretKeyRef:
                  name: skail-faturamento
                  key: namespace
            - name: SKAIL_KEY
              valueFrom:
                secretKeyRef:
                  name: skail-faturamento
                  key: key
```

Sem `SKAIL_MAX_PARALLEL_TASKS`, cada processo processa uma execução por vez. O máximo de execuções processadas ao mesmo tempo é o número de réplicas vezes esse valor: no exemplo, 2 réplicas com 4 cada processam até 8. Execuções em delay, esperando evento ou esperando uma function filha não ocupam vaga. Para processar mais, suba `SKAIL_MAX_PARALLEL_TASKS` (mais vagas em cada processo) ou `replicas` (mais processos rodando o mesmo workload). Comece com valores baixos e suba conforme o sistema downstream aguentar. O nome do `Deployment` carrega a versão de propósito: no deploy de uma nova versão, o `Deployment` antigo continua vivo até as execuções dele terminarem. Ver [Como fazer deploy de uma nova versão do workload](/opere/configurar-e-hospedar/fazer-deploy-de-uma-nova-versao.md).

## Azure

Container Apps: a mesma imagem do passo anterior, com as variáveis em environment variables e `SKAIL_KEY` como secret reference. Mantenha ao menos uma réplica: com zero réplicas ninguém busca trabalho e as execuções ficam esperando.

App Service: as Application settings viram variáveis de ambiente para o processo; use referência ao Key Vault para `SKAIL_KEY`. O App Service foi feito para processos que atendem HTTP; para um worker que não atende HTTP, prefira Container Apps ou hospede o worker como WebJob contínuo.

## Erros comuns

| Sintoma                                                                        | Causa provável                                                                                                               | Correção                                                                                 |
| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| (C#) `There is not Skail runtime available!`                                   | Faltou `UseSkail()`                                                                                                          | Confira o `Program.cs`                                                                   |
| (C#) `Specified method is not supported.` em `SkailTaskMethodBuilder.Create()` | O passo de build do skail não rodou (build sem o pacote), ou a classe do método está dentro de outra classe                  | Refaça o build com o pacote presente. Ver [Troubleshooting](/opere/troubleshooting.md)   |
| (C#) `StateMachine not registered.`                                            | Método decorado não descoberto: sem `async`, assinatura errada, assembly sem o atributo                                      | Ver [SkailFunction](/referencia/sdk-csharp/skailfunction.md)                             |
| (TypeScript) o `skail build` rejeita o método                                  | Método `static`, `private` ou sem `async`                                                                                    | Ver [SDKs e linguagens](/referencia/sdk-typescript-e-outras-linguagens.md)               |
| `Unauthenticated` no log                                                       | `SKAIL_KEY` ou `SKAIL_NAMESPACE` errados (segredo não montado no container é a causa mais comum)                             | Confira o `Secret` e a referência em `env`                                               |
| Trigger aceito e a execução parada em Na fila no Monitor                       | `SKAIL_WORKLOAD` do processo diferente do workload do trigger                                                                | Alinhe `nome:versao` com o portal e com o caminho do trigger                             |
| Execuções demoram em Na fila com a aplicação rodando                           | Todas as vagas ocupadas: `SKAIL_MAX_PARALLEL_TASKS` não definida (1 por processo) ou baixa para o volume, ou commands lentos | Aumente `SKAIL_MAX_PARALLEL_TASKS` ou `replicas`; veja a duração dos commands no Monitor |
| (C#) `The Builder Factory can only be registered once!`                        | `UseSkail()`/`AddSkail()` chamado duas vezes                                                                                 | Uma chamada por processo                                                                 |

## Próximos passos

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-dollar-sign">:dollar-sign:</i></td><td><strong>Variáveis de ambiente do runtime</strong></td><td>É a referência das variáveis.</td><td><a href="/referencia/variaveis-de-ambiente-do-runtime.md">Variáveis de ambiente do runtime</a></td></tr><tr><td><i class="fa-laptop-code">:laptop-code:</i></td><td><strong>Como rodar localmente</strong></td><td>Cobre a máquina do desenvolvedor.</td><td><a href="/opere/configurar-e-hospedar/rodar-localmente.md">Rodar localmente</a></td></tr><tr><td><i class="fa-arrow-up-right-dots">:arrow-up-right-dots:</i></td><td><strong>Ambientes e promoção</strong></td><td>Explica o que muda entre dev, homologação e produção.</td><td><a href="/opere/configurar-e-hospedar/ambientes-e-promocao.md">Ambientes e promoção</a></td></tr></tbody></table>
