Como criar seu primeiro aplicativo de contêiner do Service Fabric no Windows

Executar um aplicativo existente em um contêiner do Windows em um cluster do Service Fabric não requer alterações no seu aplicativo. Este artigo mostra como criar uma imagem do Docker que contém um aplicativo Web Python Flask e como implantá-lo em um cluster do Azure Service Fabric. Você também compartilhará seu aplicativo em contêineres pelo Registro de Contêiner do Azure. Este artigo pressupõe uma compreensão básica sobre o Docker. Saiba mais sobre o Docker lendo a Visão geral de Docker.

Observação

Este artigo se aplica a um ambiente de desenvolvimento do Windows. O runtime do cluster do Service Fabric e o runtime do Docker devem estar em execução no mesmo sistema operacional. Você não pode executar contêineres do Windows em um cluster do Linux.

Observação

Este artigo usa o módulo do PowerShell Azure Az, que é o módulo do PowerShell recomendado para interagir com o Azure. Para começar a usar o módulo do Az PowerShell, confira Instalar o Azure PowerShell. Para saber como migrar para o módulo Az PowerShell, confira Migrar o Azure PowerShell do AzureRM para o Az.

Pré-requisitos

Observação

A implantação de contêineres em um cluster do Service Fabric em execução no Windows 10 tem suporte. Consulte este artigo para obter informações sobre como configurar o Windows 10 para executar contêineres do Windows.

Observação

O Service Fabric versões 6.2 e posteriores dá suporte para implantação de contêineres em clusters em execução no Windows Server versão 1709.

Defina o contêiner Docker

Crie uma imagem com base na imagem do Python localizada no Hub do Docker.

Especifique o contêiner do Docker em um Dockerfile. O Dockerfile é composto por instruções para configurar o ambiente do seu contêiner, carregar o aplicativo que você deseja executar e mapear portas. O Dockerfile é a entrada para o comando docker build, que cria a imagem.

Crie um diretório vazio e crie o arquivo Dockerfile (sem extensão de arquivo). Adicione o seguinte ao Dockerfile e salve as alterações:

# Use an official Python runtime as a base image
FROM python:2.7-windowsservercore

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Leia a referência do Dockerfile para saber mais informações.

Criar um aplicativo Web básico

Crie um aplicativo Web Flask que escuta a porta 80 retornar Hello World!. No mesmo diretório, crie o arquivo requirements.txt. Adicione o seguinte e salve as alterações:

Flask

Crie também o arquivo app.py e adicione o seguinte snippet:

from flask import Flask

app = Flask(__name__)


@app.route("/")
def hello():

    return 'Hello World!'


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

Fazer logon no Docker e criar a imagem

Em seguida, criaremos a imagem que executa seu aplicativo Web. Ao efetuar pull de imagens públicas do Docker (como python:2.7-windowsservercore em nosso Dockerfile), a melhor prática é autenticar com sua conta do Docker Hub em vez de fazer uma solicitação de pull anônima.

Observação

Ao fazer solicitações de pull anônimas frequentes, você poderá ver erros de Docker semelhantes a ERROR: toomanyrequests: Too Many Requests. ou You have reached your pull rate limit.. Faça a autenticação no Docker Hub para evitar esses erros. Consulte Gerenciar conteúdo público com o Registro de Contêiner do Azure para obter mais informações.

Abra uma janela do PowerShell e acesse o diretório que contém o Dockerfile. Em seguida, execute os comandos a seguir:

docker login
docker build -t helloworldapp .

Esse comando cria a nova imagem usando as instruções no seu Dockerfile de nomeando (marcação -t) a imagem helloworldapp. Para criar uma imagem de contêiner, primeiro a imagem base é baixada do Hub do Docker ao qual o aplicativo foi adicionado.

Depois de concluir o comando de compilação, execute o comando docker images para ver informações sobre a nova imagem:

$ docker images

REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
helloworldapp                 latest              8ce25f5d6a79        2 minutes ago       10.4 GB

Executar o aplicativo localmente

Verifique a imagem localmente antes de enviá-la ao registro de contêiner.

Execute o aplicativo:

docker run -d --name my-web-site helloworldapp

name fornece um nome para o contêiner em execução (em vez da ID do contêiner).

Depois que o contêiner iniciar, localize seu endereço IP para que você pode se conectar ao seu contêiner em execução em um navegador:

docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" my-web-site

Se esse comando não retorna nada, execute o seguinte comando e inspecione o elemento NetworkSettings->Networks para ver o endereço IP:

docker inspect my-web-site

Conectar-se ao contêiner em execução. Abra um navegador da Web apontando para o endereço IP retornado, por exemplo “http://172.31.194.61"”. Você deve ver o título "Olá, Mundo!" exibido no navegador.

Para interromper o contêiner, execute:

docker stop my-web-site

Exclua o contêiner do seu computador de desenvolvimento:

docker rm my-web-site

Enviar a imagem para o registro de contêiner

Depois de verificar que o contêiner é executado na máquina de desenvolvimento, envie a imagem para seu registro no Registro de Contêiner do Azure.

Execute docker login para entrar em seu registro de contêiner com as credenciais de registro.

O seguinte exemplo passa a ID e senha de uma entidade de serviço do Azure Active Directory. Por exemplo, você pode atribuir uma entidade de serviço ao registro para um cenário de automação. Ou, você pode entrar usando o nome de usuário e a senha do registro.

docker login myregistry.azurecr.io -u xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -p myPassword

O comando a seguir cria uma marca ou alias imagem, com um caminho totalmente qualificado para o registro. Este exemplo coloca a imagem no namespace samples para evitar confusão na raiz do registro.

docker tag helloworldapp myregistry.azurecr.io/samples/helloworldapp

Enviar a imagem para o eu registro de contêiner:

docker push myregistry.azurecr.io/samples/helloworldapp

Crie o serviço em contêineres no Visual Studio

As ferramentas e o SDK do Service Fabric oferecem um modelo de serviço para ajudar você a criar um aplicativo em contêineres.

  1. Inicie o Visual Studio. Selecione Arquivo>Novo>Projeto.
  2. Selecione Aplicativo do Service Fabric, nomeie-o como "MyFirstContainer" e clique em OK.
  3. Selecione Contêiner na lista de modelos de serviço.
  4. Em Nome da imagem insira "myregistry.azurecr.io/samples/helloworldapp", a imagem é enviada para o seu repositório de contêiner.
  5. Dê um nome ao seu serviço e clique em OK.

Configurar a comunicação

O serviço em contêineres precisa de um ponto de extremidade para comunicação. Adicione um elemento Endpoint com o protocolo, a porta e o tipo ao arquivo ServiceManifest.xml. Neste exemplo, uma porta fixa 8081 é usada. Se nenhuma porta for especificada, uma porta aleatória do intervalo de portas de aplicativo é escolhida.

<Resources>
  <Endpoints>
    <Endpoint Name="Guest1TypeEndpoint" UriScheme="http" Port="8081" Protocol="http"/>
  </Endpoints>
</Resources>

Observação

Endpoints adicionais para um serviço podem ser adicionados declarando elementos EndPoint adicionais com valores de propriedade aplicáveis. Cada porta só pode declarar um valor de protocolo.

Definindo um ponto de extremidade, o Service Fabric publica o ponto de extremidade para o Serviço de nomeação. Outros serviços em execução no cluster podem resolver este contêiner. Você também pode executar a comunicação de contêiner para contêiner usando o proxy reverso. A comunicação é realizada fornecendo a porta de escuta de proxy reverso HTTP e o nome dos serviços com os quais você deseja se comunicar como variáveis de ambiente.

O serviço está ouvindo em uma porta específica (8081 neste exemplo). Quando o aplicativo for implantado para um cluster no Azure, o cluster e o aplicativo executam atrás de um balanceador de carga do Azure. A porta do aplicativo deve estar aberta no balanceador de carga do Microsoft Azure para que o tráfego de entrada pode obter por meio para o serviço. Você pode abrir essa porta no balanceador de carga do Microsoft Azure usando um script do PowerShell ou o portal do Azure.

Configurar e definir as variáveis de ambiente

Variáveis de ambiente podem ser especificadas para cada pacote de códigos no manifesto do serviço. Esse recurso está disponível para todos os serviços, independentemente de eles serem implantados como contêineres ou processos ou executáveis convidados. Você pode substituir valores de variáveis de ambiente no manifesto do aplicativo ou especificá-los durante a implantação como parâmetros de aplicativo.

O snippet XML do manifesto do serviço a seguir mostra um exemplo de como especificar variáveis de ambiente para um pacote de códigos:

<CodePackage Name="Code" Version="1.0.0">
  ...
  <EnvironmentVariables>
    <EnvironmentVariable Name="HttpGatewayPort" Value=""/>    
  </EnvironmentVariables>
</CodePackage>

Essas variáveis de ambiente podem ser substituídas no manifesto do aplicativo:

<ServiceManifestImport>
  <ServiceManifestRef ServiceManifestName="Guest1Pkg" ServiceManifestVersion="1.0.0" />
  <EnvironmentOverrides CodePackageRef="FrontendService.Code">
    <EnvironmentVariable Name="HttpGatewayPort" Value="19080"/>
  </EnvironmentOverrides>
  ...
</ServiceManifestImport>

Configurar mapeamento de porta para host e descoberta de contêiner para contêiner

Configure uma porta de host usada para se comunicar com o contêiner. A associação de porta mapeia a porta na qual o serviço está escutando dentro do contêiner para uma porta no host. Adicionar um elemento PortBinding no elemento ContainerHostPolicies do arquivo ApplicationManifest.xml. Para este artigo, ContainerPort é 80 (o contêiner expõe a porta 80, conforme especificado no Dockerfile) e EndpointRef é "Guest1TypeEndpoint" (o ponto de extremidade definido anteriormente no manifesto do serviço). As solicitações de entrada para o serviço na porta 8081 são mapeadas para a porta 80 no contêiner.

<ServiceManifestImport>
    ...
    <Policies>
        <ContainerHostPolicies CodePackageRef="Code">
            <PortBinding ContainerPort="80" EndpointRef="Guest1TypeEndpoint"/>
        </ContainerHostPolicies>
    </Policies>
    ...
</ServiceManifestImport>

Observação

PortBindings adicionais para um serviço podem ser adicionados, declarando elementos PortBinding adicionais com valores de propriedade aplicável.

Configurar a autenticação do repositório de contêiner

Consulte Autenticação de repositório de contêiner para saber como configurar diferentes tipos de autenticação para download de imagem de contêiner.

Configurar o modo de isolamento

O Windows dá suporte a dois modos de isolamento para contêineres: processo e Hyper-V. Com o modo de isolamento de processo, todos os contêineres em execução no mesmo computador host compartilham o kernel com o host. Com o modo de isolamento do Hyper-V, os kernels são isolados entre cada contêiner do Hyper-V e o host do contêiner. O modo de isolamento é especificado no elemento ContainerHostPolicies no arquivo de manifesto do aplicativo. Os modos de isolamento que podem ser especificados são process, hyperv e default. O padrão é o modo de isolamento de processo nos hosts do Windows Server. Em hosts do Windows 10, somente o modo de isolamento do Hyper-V tem suporte, assim o contêiner é executado no modo de isolamento do Hyper-V, independentemente de sua configuração de modo de isolamento. O snippet a seguir mostra como o modo de isolamento é especificado no arquivo de manifesto do aplicativo.

<ContainerHostPolicies CodePackageRef="Code" Isolation="hyperv">

Observação

O modo de isolamento do Hyper-v está disponível nas SKUs do Azure Ev3 e Dv3 que têm suporte para virtualização aninhada.

Configurar governança de recursos

A governança de recursos restringe os recursos que o contêiner pode usar no host. O elemento ResourceGovernancePolicy, especificado no manifesto do aplicativo, é usado para declarar os limites de recurso para um pacote de códigos de serviço. Os limites de recursos podem ser definidos para os seguintes recursos: Memory, MemorySwap, CpuShares (CPU relative weight), MemoryReservationInMB, BlkioWeight (BlockIO relative weight). Neste exemplo, o pacote de serviço Guest1Pkg obtém um núcleo nos nós de cluster em que ele é colocado. Os limites de memória são absolutos e, portanto, o pacote de códigos é limitado a 1024 MB de memória (e a uma reserva de garantia reversível da mesma). Os pacotes de códigos (contêineres ou processos) não podem alocar mais memória do que esse limite. A tentativa de fazer isso resultará em uma exceção de memória insuficiente. Para que a imposição do limite de recursos funcione, todos os pacotes de códigos em um pacote de serviço devem ter limites de memória especificados.

<ServiceManifestImport>
  <ServiceManifestRef ServiceManifestName="Guest1Pkg" ServiceManifestVersion="1.0.0" />
  <Policies>
    <ServicePackageResourceGovernancePolicy CpuCores="1"/>
    <ResourceGovernancePolicy CodePackageRef="Code" MemoryInMB="1024"  />
  </Policies>
</ServiceManifestImport>

Configurar o HEALTHCHECK do Docker

Iniciando a versão 6.1, o Service Fabric integra automaticamente os eventos do HEALTHCHECK do Docker em seu relatório de integridade do sistema. Isso significa que, se o contêiner tiver o HEALTHCHECK habilitado, o Service Fabric relatará a integridade sempre que o status de integridade do contêiner for alterado conforme relatado pelo Docker. Um relatório de integridade OK será exibido no Service Fabric Explorer quando o health_status for íntegro e um AVISO aparecerá quando o health_status for não íntegro.

Com a atualização mais recente da v6.4, você tem a opção de especificar que as avaliações de HEALTHCHECK do Docker devem ser relatadas como um erro. Se essa opção estiver habilitada, um relatório de integridade OK será exibido quando health_status for healthy e ERROR será exibido quando health_status for unhealthy.

A instrução do HEALTHCHECK apontando para a verificação real que é executada para monitorar a integridade do contêiner deve estar presente no Dockerfile usado ao gerar a imagem de contêiner.

Screenshot shows details of the Deployed Service Package NodeServicePackage.

HealthCheckUnhealthyApp

HealthCheckUnhealthyDsp

Você pode configurar o comportamento do HEALTHCHECK para cada contêiner especificando as opções do HealthConfig como parte do ContainerHostPolicies no ApplicationManifest.

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="ContainerServicePkg" ServiceManifestVersion="2.0.0" />
    <Policies>
      <ContainerHostPolicies CodePackageRef="Code">
        <HealthConfig IncludeDockerHealthStatusInSystemHealthReport="true"
		      RestartContainerOnUnhealthyDockerHealthStatus="false" 
		      TreatContainerUnhealthyStatusAsError="false" />
      </ContainerHostPolicies>
    </Policies>
</ServiceManifestImport>

Por padrão, IncludeDockerHealthStatusInSystemHealthReport é definido como true, RestartContainerOnUnhealthyDockerHealthStatus é definido como false e TreatContainerUnhealthyStatusAsError é definido como false.

Se o RestartContainerOnUnhealthyDockerHealthStatus for definido como true, um contêiner relatando repetidamente um estado não íntegro será reiniciado (possivelmente em outros nós).

Se TreatContainerUnhealthyStatusAsError for definido como true, os relatórios de integridade com ERROR serão exibidos quando o health_status do contêiner for unhealthy.

Se você deseja desabilitar a integração do HEALTHCHECK para todo o cluster do Service Fabric, precisará definir o EnableDockerHealthCheckIntegration como false.

Como implantar o aplicativo de contêiner

Salve todas as suas alterações e compile o aplicativo. Para publicar o seu aplicativo, clique o botão direito do mouse em MyFirstContainer no Gerenciador de Soluções e selecione Publicar.

Em Ponto de Extremidade de Conexão, insira o ponto de extremidade de gerenciamento para o cluster. Por exemplo, containercluster.westus2.cloudapp.azure.com:19000. Você pode encontrar o ponto de extremidade de conexão do cliente na guia de Visão geral para o cluster no portal do Azure.

Clique em Publicar.

O Service Fabric Explorer é uma ferramenta baseada na Web para inspecionar e gerenciar aplicativos e nós em um cluster do Service Fabric. Abra um navegador e navegue até http://containercluster.westus2.cloudapp.azure.com:19080/Explorer/ e siga a implantação do aplicativo. O aplicativo é implantado, mas fica em estado de erro até que a imagem seja baixada nos nós de cluster (o que pode levar algum tempo, dependendo do tamanho da imagem): Error

O aplicativo está pronto quando ele está em Ready estado: Ready

Abra um navegador e navegue até http://containercluster.westus2.cloudapp.azure.com:8081. Você deve ver o título "Olá, Mundo!" exibido no navegador.

Limpeza

Você continua a incorrer em encargos enquanto o cluster estiver em execução, considere excluir o cluster.

Depois que você enviar a imagem para o registro de contêiner, você pode excluir a imagem local do seu computador de desenvolvimento:

docker rmi helloworldapp
docker rmi myregistry.azurecr.io/samples/helloworldapp

Compatibilidade do sistema operacional do contêiner e do sistema operacional do host do Windows Server

Os contêineres do Windows Server não são compatíveis em todas as versões de um sistema operacional do host. Por exemplo:

  • Os contêineres do Windows Server criados usando o Windows Server versão 1709 não funcionam em um host executando o Windows Server versão 2016.
  • Os contêineres do Windows Server são criados usando o Windows Server 2016 no modo de isolamento Hyper-V somente em um host que executa o Windows Server versão 1709.
  • Com contêineres do Windows Server criados usando o Windows Server 2016, pode ser necessário garantir que a revisão do sistema operacional do contêiner e sistema operacional do host são as mesmas durante a execução no modo de isolamento do processo em um host executando o Windows Server 2016.

Para obter mais informações, consulte Compatibilidade de versão de contêiner do Windows.

Considere a compatibilidade do sistema operacional do host e do sistema operacional do contêiner ao compilar e implantar contêineres para o cluster do Service Fabric. Por exemplo:

  • Verifique se que você implanta os contêineres com um sistema operacional compatível com o sistema operacional nos nós do cluster.
  • Certifique-se de que o modo de isolamento especificado para o aplicativo de contêiner é consistente com o suporte para o sistema operacional do contêiner no nó onde ele está sendo implantado.
  • Considere como as atualizações do sistema operacional para os nós do cluster ou contêineres podem afetar sua compatibilidade.

Recomendamos as seguintes práticas para certificar-se de que os contêineres são implantados corretamente no cluster do Service Fabric:

  • Use a marcação de imagem explícita com as imagens do Docker para especificar a versão do sistema operacional do Windows Server a partir da qual um contêiner é criado.
  • Use a marcação do SO em seu arquivo de manifesto do aplicativo para certificar-se de que seu aplicativo é compatível com versões e atualizações diferentes do Windows Server.

Observação

Com o Service Fabric versão 6.2 e posterior, você pode implantar contêineres baseados no Windows Server 2016 localmente em um host do Windows 10. No Windows 10, os contêineres são executados no modo de isolamento do Hyper-V, independentemente do modo de isolamento definido no manifesto do aplicativo. Para obter mais informações, consulte Configurar o modo de isolamento.

Especifique a compilação do sistema operacional das imagens de contêiner específicas

Os contêineres do Windows Server podem não ser compatíveis entre diferentes versões do sistema operacional. Por exemplo, os contêineres do Windows Server criados usando o Windows Server 2016 não funcionam na versão 1709 do Windows Server no modo de isolamento do processo. Portanto, se os nós do cluster forem atualizados para a versão mais recente, os serviços de contêiner criados com versões anteriores do sistema operacional poderão falhar. Para contornar isso com a versão 6.1 do runtime e mais recente, o Service Fabric oferece suporte à especificação de várias imagens do sistema operacional por contêiner e marca-as com as versões de compilação do sistema operacional no manifesto do aplicativo. Você pode obter a versão do sistema operacional executando winver em um prompt de comando do Windows. Atualize os manifestos do aplicativo e especificar as substituições de imagem por versão do sistema operacional antes de atualizar o sistema operacional nos nós. O snippet de código a seguir mostra como especificar várias imagens de contêiner no manifesto do aplicativo, ApplicationManifest.xml:

      <ContainerHostPolicies> 
         <ImageOverrides> 
	       <Image Name="myregistry.azurecr.io/samples/helloworldappDefault" /> 
               <Image Name="myregistry.azurecr.io/samples/helloworldapp1701" Os="14393" /> 
               <Image Name="myregistry.azurecr.io/samples/helloworldapp1709" Os="16299" /> 
         </ImageOverrides> 
      </ContainerHostPolicies> 

A versão de build do Windows Server 2016 é a 14393 e a versão de build da versão 1709 do Windows Server é a 16299. O manifesto do serviço continua a especificar apenas uma imagem por serviço de contêiner, como mostra o seguinte:

<ContainerHost>
    <ImageName>myregistry.azurecr.io/samples/helloworldapp</ImageName> 
</ContainerHost>

Observação

Os recursos de marcação da versão de compilação do sistema operacional só estão disponíveis para o Service Fabric no Windows

Se o sistema operacional subjacente na VM é a compilação 16299 (versão 1709), o Service Fabric escolherá a imagem do contêiner correspondente a essa versão do Windows Server. Se uma imagem de contêiner sem marcas também for fornecida junto com as imagens de contêiner marcadas no manifesto do aplicativo, o Service Fabric tratará a imagem não marcada como uma que funciona entre versões diferentes. Marque as imagens de contêiner explicitamente para evitar problemas durante as atualizações.

A imagem de contêiner sem marcas funcionará como substituição da fornecida em ServiceManifest. Portanto, a imagem myregistry.azurecr.io/samples/helloworldappDefault"imagem" substituirá ImageName "myregistry.azurecr.io/samples/helloworldapp" no ServiceManifest.

Exemplo completo de manifestos de serviço e aplicativo do Service Fabric

Aqui estão os manifestos de aplicativo e serviço completos usados neste artigo.

ServiceManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Guest1Pkg"
                 Version="1.0.0"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="https://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
    <!-- This is the name of your ServiceType.
         The UseImplicitHost attribute indicates this is a guest service. -->
    <StatelessServiceType ServiceTypeName="Guest1Type" UseImplicitHost="true" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <!-- Follow this link for more information about deploying Windows containers to Service Fabric: https://aka.ms/sfguestcontainers -->
      <ContainerHost>
        <ImageName>myregistry.azurecr.io/samples/helloworldapp</ImageName>
        <!-- Pass comma delimited commands to your container: dotnet, myproc.dll, 5" -->
        <!--Commands> dotnet, myproc.dll, 5 </Commands-->
        <Commands></Commands>
      </ContainerHost>
    </EntryPoint>
    <!-- Pass environment variables to your container: -->    
    <EnvironmentVariables>
      <EnvironmentVariable Name="HttpGatewayPort" Value=""/>
      <EnvironmentVariable Name="BackendServiceName" Value=""/>
    </EnvironmentVariables>

  </CodePackage>

  <!-- Config package is the contents of the Config directory under PackageRoot that contains an
       independently-updateable and versioned set of custom configuration settings for your service. -->
  <ConfigPackage Name="Config" Version="1.0.0" />

  <Resources>
    <Endpoints>
      <!-- This endpoint is used by the communication listener to obtain the port on which to
           listen. Please note that if your service is partitioned, this port is shared with
           replicas of different partitions that are placed in your code. -->
      <Endpoint Name="Guest1TypeEndpoint" UriScheme="http" Port="8081" Protocol="http"/>
    </Endpoints>
  </Resources>
</ServiceManifest>

ApplicationManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="MyFirstContainerType"
                     ApplicationTypeVersion="1.0.0"
                     xmlns="http://schemas.microsoft.com/2011/01/fabric"
                     xmlns:xsd="https://www.w3.org/2001/XMLSchema"
                     xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <Parameters>
    <Parameter Name="Guest1_InstanceCount" DefaultValue="-1" />
  </Parameters>
  <!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
       should match the Name and Version attributes of the ServiceManifest element defined in the
       ServiceManifest.xml file. -->
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Guest1Pkg" ServiceManifestVersion="1.0.0" />
    <EnvironmentOverrides CodePackageRef="FrontendService.Code">
      <EnvironmentVariable Name="HttpGatewayPort" Value="19080"/>
    </EnvironmentOverrides>
    <ConfigOverrides />
    <Policies>
      <ContainerHostPolicies CodePackageRef="Code">
        <RepositoryCredentials AccountName="myregistry" Password="MIIB6QYJKoZIhvcNAQcDoIIB2jCCAdYCAQAxggFRMIIBTQIBADA1MCExHzAdBgNVBAMMFnJ5YW53aWRhdGFlbmNpcGhlcm1lbnQCEFfyjOX/17S6RIoSjA6UZ1QwDQYJKoZIhvcNAQEHMAAEg
gEAS7oqxvoz8i6+8zULhDzFpBpOTLU+c2mhBdqXpkLwVfcmWUNA82rEWG57Vl1jZXe7J9BkW9ly4xhU8BbARkZHLEuKqg0saTrTHsMBQ6KMQDotSdU8m8Y2BR5Y100wRjvVx3y5+iNYuy/JmM
gSrNyyMQ/45HfMuVb5B4rwnuP8PAkXNT9VLbPeqAfxsMkYg+vGCDEtd8m+bX/7Xgp/kfwxymOuUCrq/YmSwe9QTG3pBri7Hq1K3zEpX4FH/7W2Zb4o3fBAQ+FuxH4nFjFNoYG29inL0bKEcTX
yNZNKrvhdM3n1Uk/8W2Hr62FQ33HgeFR1yxQjLsUu800PrYcR5tLfyTB8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBybgM5NUV8BeetUbMR8mJhgFBrVSUsnp9B8RyebmtgU36dZiSObDsI
NtTvlzhk11LIlae/5kjPv95r3lw6DHmV4kXLwiCNlcWPYIWBGIuspwyG+28EWSrHmN7Dt2WqEWqeNQ==" PasswordEncrypted="true"/>
        <PortBinding ContainerPort="80" EndpointRef="Guest1TypeEndpoint"/>
      </ContainerHostPolicies>
      <ServicePackageResourceGovernancePolicy CpuCores="1"/>
      <ResourceGovernancePolicy CodePackageRef="Code" MemoryInMB="1024"  />
    </Policies>
  </ServiceManifestImport>
  <DefaultServices>
    <!-- The section below creates instances of service types, when an instance of this
         application type is created. You can also create one or more instances of service type using the
         ServiceFabric PowerShell module.

         The attribute ServiceTypeName below must match the name defined in the imported ServiceManifest.xml file. -->
    <Service Name="Guest1">
      <StatelessService ServiceTypeName="Guest1Type" InstanceCount="[Guest1_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>
</ApplicationManifest>

Configurar o intervalo de tempo antes do contêiner ser forçado a terminar

Você pode configurar um intervalo de tempo para a execução aguardar antes do contêiner ser removido após a exclusão do serviço (ou um movimento para outro nó) ter iniciado. Configurar o intervalo de tempo envia o comando docker stop <time in seconds> para o contêiner. Para obter mais detalhes, consulte parar docker. O intervalo de tempo de espera é especificado na seção Hosting. A seção Hosting pode ser adicionada na criação do cluster ou posteriormente em uma atualização de configuração. O snippet de manifesto do cluster a seguir mostra como definir o intervalo de espera:

"fabricSettings": [
	...,
	{
        "name": "Hosting",
        "parameters": [
          {
                "name": "ContainerDeactivationTimeout",
                "value" : "10"
          },
	      ...
        ]
	}
]

O intervalo de tempo padrão é definido para 10 segundos. Como essa configuração é dinâmica, uma configuração somente atualiza no cluster que atualiza no tempo limite.

Configurar a execução para remover as imagens de contêiner não utilizadas

Você pode configurar o cluster do Service Fabric para remover as imagens de contêiner não utilizadas do nó. Essa configuração permite que o espaço em disco seja recapturado se houver imagens de contêiner demais no nó. Para habilitar esse recurso, atualize a seção Hosting no manifesto do cluster, conforme mostrado no seguinte snippet:

"fabricSettings": [
	...,
	{
        "name": "Hosting",
        "parameters": [
          {
                "name": "PruneContainerImages",
                "value": "True"
          },
          {
                "name": "ContainerImagesToSkip",
                "value": "mcr.microsoft.com/windows/servercore|mcr.microsoft.com/windows/nanoserver|mcr.microsoft.com/dotnet/framework/aspnet|..."
          }
          ...
          }
        ]
	} 
]

Para as imagens que não devem ser excluídas, você pode especificá-las no parâmetro ContainerImagesToSkip.

Configurar o tempo de download de imagem de contêiner

O runtime do Service Fabric aloca 20 minutos para baixar e extrair as imagens de contêiner, o que funciona para a maioria das imagens de contêiner. Para imagens grandes, ou quando a conexão de rede estiver lenta, talvez seja necessário aumentar o tempo de espera antes de cancelar o download e a extração da imagem. Esse tempo limite é definido usando o atributo ContainerImageDownloadTimeout na seção Hospedagem do manifesto do cluster, conforme mostrado no snippet de código a seguir:

"fabricSettings": [
	...,
	{
        "name": "Hosting",
        "parameters": [
          {
              "name": "ContainerImageDownloadTimeout",
              "value": "1200"
          }
        ]
	}
]

Definir política de retenção de contêiner

Para ajudar a diagnosticar as falhas de inicialização do contêiner, o Service Fabric (versão 6.1 ou superiores) oferece suporte à retenção de contêineres que encerraram ou falharam na inicialização. Essa política pode ser definida no arquivo ApplicationManifest.xml conforme mostrado no snippet de código a seguir:

 <ContainerHostPolicies CodePackageRef="NodeService.Code" Isolation="process" ContainersRetentionCount="2"  RunInteractive="true"> 

A configuração ContainersRetentionCount especifica o número de contêineres mantidos quando ocorre uma falha. Se um valor negativo for especificado, todos os contêineres com falha serão mantidos. Quando o atributo ContainersRetentionCount não for especificado, nenhum contêiner será retido. O atributo ContainersRetentionCount também oferece suporte a Parâmetros de Aplicativo para que os usuários possam especificar valores diferentes para clusters de teste e produção. Use restrições de posicionamento para direcionar o serviço de contêiner para um determinado nó quando esses recursos forem usados com a finalidade de impedir que o serviço de contêiner se mova para outros nós. Todos os contêineres retidos usando esse recurso devem ser removidos manualmente.

Iniciar o daemon do Docker com argumentos personalizados

Com a versão 6.2, e superiores, do runtime do Service Fabric, você pode iniciar o daemon do Docker com argumentos personalizados. Ao especificar argumentos personalizados, o Service Fabric não passa outro argumento para o mecanismo do docker, com exceção do argumento --pidfile. Portanto, não passe --pidfile como um argumento. Além disso, o argumento deve manter a escuta do daemon do docker no pipe de nome padrão no Windows (ou um soquete de domínio do unix no Linux) para o Service Fabric se comunicar com o Daemon. Os argumentos personalizados são passados no manifesto do cluster na seção Hospedagem em ContainerServiceArguments conforme mostrado no snippet de código a seguir:

"fabricSettings": [
	...,
	{ 
        "name": "Hosting", 
        "parameters": [ 
          { 
            "name": "ContainerServiceArguments", 
            "value": "-H localhost:1234 -H unix:///var/run/docker.sock" 
          } 
        ] 
	} 
]

Substituição de EntryPoint

Com a versão 8.2 do ServiceFabric Runtime, o ponto de entrada para o contêiner e o pacote de código do host exe podem ser substituídos. Isso pode ser usado nos casos em que todos os elementos de manifesto permanecem os mesmos, mas a imagem de contêiner precisa ser alterada e, em seguida, o provisionamento de uma versão de tipo de aplicativo diferente não é mais necessário ou argumentos diferentes precisam ser passados com base no cenário de teste ou de produção e o ponto de entrada permanece o mesmo.

Veja o seguinte exemplo de como substituir o ponto de entrada do contêiner:

ApplicationManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="MyFirstContainerType"
                     ApplicationTypeVersion="1.0.0"
                     xmlns="http://schemas.microsoft.com/2011/01/fabric"
                     xmlns:xsd="https://www.w3.org/2001/XMLSchema"
                     xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <Parameters>
    <Parameter Name="ImageName" DefaultValue="myregistry.azurecr.io/samples/helloworldapp" />
    <Parameter Name="Commands" DefaultValue="commandsOverride" />
    <Parameter Name="FromSource" DefaultValue="sourceOverride" />
    <Parameter Name="EntryPoint" DefaultValue="entryPointOverride" />
  </Parameters>
  <!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
       should match the Name and Version attributes of the ServiceManifest element defined in the
       ServiceManifest.xml file. -->
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Guest1Pkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides />
    <Policies>
      <CodePackagePolicy CodePackageRef="Code">
        <EntryPointOverride>
         <ContainerHostOverride>
            <ImageOverrides>
              <Image Name="[ImageName]" />
            </ImageOverrides>
            <Commands>[Commands]</Commands>
            <FromSource>[Source]</FromSource>
            <EntryPoint>[EntryPoint]</EntryPoint>
          </ContainerHostOverride>
        </EntryPointOverride>
      </CodePackagePolicy>
    </Policies>
  </ServiceManifestImport>
</ApplicationManifest>

ServiceManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Guest1Pkg"
                 Version="1.0.0"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="https://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
    <!-- This is the name of your ServiceType.
         The UseImplicitHost attribute indicates this is a guest service. -->
    <StatelessServiceType ServiceTypeName="Guest1Type" UseImplicitHost="true" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <!-- Follow this link for more information about deploying Windows containers to Service Fabric: https://aka.ms/sfguestcontainers -->
      <ContainerHost>
        <ImageName>default imagename</ImageName>
        <Commands>default cmd</Commands>
        <EntryPoint>default entrypoint</EntryPoint>
        <FromSource>default source</FromSource>
      </ContainerHost>
    </EntryPoint>
  </CodePackage>

  <ConfigPackage Name="Config" Version="1.0.0" />
</ServiceManifest>

Depois que as substituições no manifesto do aplicativo são especificadas, o contêiner com o nome de imagem myregistry.azurecr.io/samples/helloworldapp, comando commandsOverride, fonte sourceOverride e ponto de entrada entryPointOverride será iniciado.

Da mesma forma, abaixo está um exemplo de como substituir o ExeHost:

<?xml version="1.0" encoding="utf-8"?>
<Policies>
  <CodePackagePolicy CodePackageRef="Code">
    <EntryPointOverride>
      <ExeHostOverride>
        <Program>[Program]</Program>
        <Arguments>[Entry]</Arguments>
      </ExeHostOverride>
    </EntryPointOverride>
  </CodePackagePolicy>
</Policies>

Observação

Não há suporte para a substituição do ponto de entrada no SetupEntryPoint.

Próximas etapas