在 Windows 上创建第一个 Service Fabric 容器应用程序Create your first Service Fabric container application on Windows

在 Service Fabric 群集上运行 Windows 容器中的现有应用程序不需要对应用程序进行任何更改。Running an existing application in a Windows container on a Service Fabric cluster doesn't require any changes to your application. 本文逐步讲解如何创建包含 Python Flask Web 应用程序的 Docker 映像并将其部署到 Azure Service Fabric 群集。This article walks you through creating a Docker image containing a Python Flask web application and deploying it to an Azure Service Fabric cluster. 此外,会通过 Azure 容器注册表共享容器化的应用程序。You will also share your containerized application through Azure Container Registry. 本文假定读者对 Docker 有一个基本的了解。This article assumes a basic understanding of Docker. 阅读 Docker Overview(Docker 概述)即可了解 Docker。You can learn about Docker by reading the Docker Overview.

备注

本文适用于 Windows 开发环境。This article applies to a Windows development environment. Service Fabric 群集运行时和 Docker 运行时必须在同一 OS 上运行。The Service Fabric cluster runtime and the Docker runtime must be running on the same OS. 不能在 Linux 群集上运行 Windows 容器。You cannot run Windows containers on a Linux cluster.

备注

本文进行了更新,以便使用新的 Azure PowerShell Az 模块。This article has been updated to use the new Azure PowerShell Az module. 你仍然可以使用 AzureRM 模块,至少在 2020 年 12 月之前,它将继续接收 bug 修补程序。You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. 若要详细了解新的 Az 模块和 AzureRM 兼容性,请参阅新 Azure Powershell Az 模块简介To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. 有关 Az 模块安装说明,请参阅安装 Azure PowerShellFor Az module installation instructions, see Install Azure PowerShell.

先决条件Prerequisites

  • 一台运行以下软件的开发计算机:A development computer running:

  • 有三个或更多节点在使用容器的 Windows Server 上运行的 Windows 群集。A Windows cluster with three or more nodes running on Windows Server with Containers.

    在本文中,群集结点上运行的使用容器的 Windows Server 版本必须与开发计算机上的版本相匹配。For this article, the version (build) of Windows Server with Containers running on your cluster nodes must match that on your development machine. 这是因为要在开发计算机上构建 Docker 映像,而容器 OS 和用来部署的主机 OS 的版本之间有兼容性限制。This is because you build the docker image on your development machine and there are compatibility constraints between versions of the container OS and the host OS on which it is deployed. 有关详细信息,请参阅 Windows Server 容器 OS 与主机 OS 的兼容性For more information, see Windows Server container OS and host OS compatibility.

若要确定使用容器的 Windows Server 版本,请在开发计算机上从 Windows 命令提示符运行 ver 命令:To determine the version of Windows Server with Containers you need for your cluster, run the ver command from a Windows command prompt on your development machine:

  • 如果版本包含 x.x.14323.x,创建群集时请选择 WindowsServer 2016-Datacenter-with-Containers 作为操作系统。If the version contains x.x.14323.x, then select WindowsServer 2016-Datacenter-with-Containers for the operating system when creating a cluster.

  • 如果版本包含 x.x.16299.x,创建群集时请选择 WindowsServerSemiAnnual Datacenter-Core-1709-with-Containers 作为操作系统。If the version contains x.x.16299.x, then select WindowsServerSemiAnnual Datacenter-Core-1709-with-Containers for the operating system when creating a cluster.

  • 一个位于 Azure 容器注册表中的注册表 - 在 Azure 订阅中创建容器注册表A registry in Azure Container Registry - Create a container registry in your Azure subscription.

备注

支持将容器部署到在 Windows 10 上运行的 Service Fabric 群集。Deploying containers to a Service Fabric cluster running on Windows 10 is supported. 有关如何配置 Windows 10 以运行 Windows 容器的信息,请参阅此文See this article for information on how to configure Windows 10 to run Windows containers.

备注

Service Fabric 6.2 及更高版本支持将容器部署到在 Windows Server 1709 上运行的群集。Service Fabric versions 6.2 and later support deploying containers to clusters running on Windows Server version 1709.

定义 Docker 容器Define the Docker container

基于 Docker 中心内的 Python 映像生成一个映像。Build an image based on the Python image located on Docker Hub.

在 Dockerfile 中指定 Docker 容器。Specify your Docker container in a Dockerfile. Dockerfile 包含有关在容器中设置环境、加载要运行的应用程序以及映射端口的说明。The Dockerfile consists of instructions for setting up the environment inside your container, loading the application you want to run, and mapping ports. Dockerfile 是 docker build 命令的输入,该命令用于创建映像。The Dockerfile is the input to the docker build command, which creates the image.

创建一个空目录并创建文件 Dockerfile(不带文件扩展名)。Create an empty directory and create the file Dockerfile (with no file extension). 将以下内容添加到 Dockerfile 并保存所做的更改:Add the following to Dockerfile and save your changes:

# 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"]

有关详细信息,请阅读 Dockerfile reference(Dockerfile 参考)。Read the Dockerfile reference for more information.

创建基本 Web 应用程序Create a basic web application

创建一个在端口 80 上进行侦听并返回 Hello World! 的 Flask Web 应用程序。Create a Flask web application listening on port 80 that returns Hello World!. 在同一个目录中,创建文件 requirements.txtIn the same directory, create the file requirements.txt. 添加以下内容并保存所做的更改:Add the following and save your changes:

Flask

此外,创建 app.py 文件并添加以下代码片段:Also create the app.py file and add the following 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)

生成映像Build the image

运行 docker build 命令,创建运行上述 Web 应用程序的映像。Run the docker build command to create the image that runs your web application. 打开 PowerShell 窗口并导航到包含 Dockerfile 的目录。Open a PowerShell window and navigate to the directory containing the Dockerfile. 运行以下命令:Run the following command:

docker build -t helloworldapp .

该命令按 Dockerfile 中的说明生成新映像,并将映像命名为(-t 表示标记)helloworldappThis command builds the new image using the instructions in your Dockerfile, naming (-t tagging) the image helloworldapp. 若要生成容器映像,首先从 Docker Hub 下载基础映像并在其上添加应用程序。To build a container image, the base image is first downloaded down from Docker Hub to which the application is added.

生成命令执行完以后,请运行 docker images 命令,查看有关新映像的信息:Once the build command completes, run the docker images command to see information on the new image:

$ docker images

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

在本地运行应用程序Run the application locally

请先在本地验证映像,然后再将其推送到容器注册表。Verify your image locally before pushing it the container registry.

运行应用程序:Run the application:

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

name 为运行的容器(而不是容器 ID)命名。name gives a name to the running container (instead of the container ID).

容器启动以后,查找其 IP 地址,以便通过浏览器连接到正在运行的容器:Once the container starts, find its IP address so that you can connect to your running container from a browser:

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

如果该命令未返回任何内容,请运行以下命令并检查 IP 地址的 NetworkSettings->Networks 元素:If that command does not return anything, run the following command and inspect the NetworkSettings->Networks element for the IP address:

docker inspect my-web-site

连接到正在运行的容器。Connect to the running container. 打开 Web 浏览器并指向返回的 IP 地址,例如“http://172.31.194.61”。Open a web browser pointing to the IP address returned, for example "http://172.31.194.61". 此时会看到标题“Hello World!”You should see the heading "Hello World!" 显示在浏览器中。display in the browser.

若要停止容器,请运行:To stop your container, run:

docker stop my-web-site

从开发计算机中删除该容器:Delete the container from your development machine:

docker rm my-web-site

将映像推送到容器注册表Push the image to the container registry

验证容器是否在开发计算机上运行以后,即可将映像推送到 Azure 容器注册表的注册表中。After you verify that the container runs on your development machine, push the image to your registry in Azure Container Registry.

运行 docker login,以使用注册表凭据登录到容器注册表。Run docker login to sign in to your container registry with your registry credentials.

以下示例传递了 Azure Active Directory 服务主体的 ID 和密码。The following example passes the ID and password of an Azure Active Directory service principal. 例如,在自动化方案中,可能已向注册表分配了服务主体。For example, you might have assigned a service principal to your registry for an automation scenario. 或者,可以使用注册表用户名和密码登录。Or, you could sign in using your registry username and password.

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

以下命令使用注册表的完全限定路径创建映像的标记或别名。The following command creates a tag, or alias, of the image, with a fully qualified path to your registry. 此示例将映像置于 samples 命名空间,以免注册表根目录中出现混乱。This example places the image in the samples namespace to avoid clutter in the root of the registry.

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

将映像推送到容器注册表:Push the image to your container registry:

docker push myregistry.azurecr.cn/samples/helloworldapp

在 Visual Studio 中创建容器化服务Create the containerized service in Visual Studio

Service Fabric SDK 和工具提供服务模板,用于创建容器化应用程序。The Service Fabric SDK and tools provide a service template to help you create a containerized application.

  1. 启动 Visual Studio。Start Visual Studio. 选择“文件” > “新建” > “项目”。Select File > New > Project.
  2. 选择“Service Fabric 应用程序”,将其命名为“MyFirstContainer”,并单击“确定”。 Select Service Fabric application, name it "MyFirstContainer", and click OK.
  3. 从“服务模板”列表中选择“容器”。 Select Container from the list of service templates.
  4. 在“映像名称”中输入“myregistry.azurecr.cn/samples/helloworldapp”,这是已推送到容器存储库中的映像。 In Image Name enter "myregistry.azurecr.cn/samples/helloworldapp", the image you pushed to your container repository.
  5. 为服务命名,并单击“确定” 。Give your service a name, and click OK.

配置通信Configure communication

容器化服务需要使用终结点进行通信。The containerized service needs an endpoint for communication. 请将 Endpoint 元素以及协议、端口和类型添加到 ServiceManifest.xml 文件。Add an Endpoint element with the protocol, port, and type to the ServiceManifest.xml file. 在此示例中,使用固定端口 8081。In this example, a fixed port 8081 is used. 如果未指定端口,则从应用程序端口范围中选择一个随机端口。If no port is specified, a random port from the application port range is chosen.

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

备注

可以通过使用适用的属性值声明其他 EndPoint 元素来添加服务的其他终结点。Additional Endpoints for a service can be added by declaring additional EndPoint elements with applicable property values. 每个端口可以仅声明一个协议值。Each Port can only declare one protocol value.

定义终结点后,Service Fabric 即可将该终结点发布到命名服务。By defining an endpoint, Service Fabric publishes the endpoint to the Naming service. 在群集中运行的其他服务可以解析此容器。Other services running in the cluster can resolve this container. 还可以使用反向代理执行容器间的通信。You can also perform container-to-container communication using the reverse proxy. 将 HTTP 侦听端口和想要与其通信的服务名称作为环境变量提供给反向代理,以此方式进行通信。Communication is performed by providing the reverse proxy HTTP listening port and the name of the services that you want to communicate with as environment variables.

该服务在特定端口(本例中为 8081)上进行侦听。The service is listening on a specific port (8081 in this example). 当应用程序部署到 Azure 中的群集时,该群集和应用程序都在 Azure 负载均衡器之后运行。When the application deploys to a cluster in Azure, both the cluster and the application run behind an Azure load balancer. 应用程序端口必须在 Azure 负载均衡器中打开,以便入站流量能够通过该服务。The application port must be open in the Azure load balancer so that inbound traffic can get through to the service. 可以在 Azure 负载均衡器中使用 PowerShell 脚本来打开此端口,也可以在 Azure 门户中将其打开。You can open this port in the Azure load balancer using a PowerShell script or in the Azure portal.

配置和设置环境变量Configure and set environment variables

可以针对服务清单中的每个代码包指定环境变量。Environment variables can be specified for each code package in the service manifest. 此功能适用于所有服务,不管它们是作为容器、进程还是来宾可执行文件部署的。This feature is available for all services irrespective of whether they are deployed as containers or processes or guest executables. 可以替代应用程序清单中的环境变量值,或者在部署期间将其指定为应用程序参数。You can override environment variable values in the application manifest or specify them during deployment as application parameters.

以下服务清单 XML 代码片段演示如何指定代码包的环境变量:The following service manifest XML snippet shows an example of how to specify environment variables for a code package:

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

可在应用程序清单中重写这些环境变量:These environment variables can be overridden in the application manifest:

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

配置容器端口到主机端口的映射,以及容器到容器的发现Configure container port-to-host port mapping and container-to-container discovery

配置用来与容器通信的主机端口。Configure a host port used to communicate with the container. 端口绑定可将服务在容器中侦听的端口映射到主机上的端口。The port binding maps the port on which the service is listening inside the container to a port on the host. 在 ApplicationManifest.xml 文件的 ContainerHostPolicies 元素中添加 PortBinding 元素。Add a PortBinding element in ContainerHostPolicies element of the ApplicationManifest.xml file. 在本文中,ContainerPort 为 80(容器根据 Dockerfile 中的指定值公开端口 80),EndpointRef 为“Guest1TypeEndpoint”(以前在服务清单中定义的终结点)。For this article, ContainerPort is 80 (the container exposes port 80, as specified in the Dockerfile) and EndpointRef is "Guest1TypeEndpoint" (the endpoint previously defined in the service manifest). 传入到端口 8081 上的服务的请求映射到容器上的端口 80。Incoming requests to the service on port 8081 are mapped to port 80 on the container.

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

备注

可以通过使用适用的属性值声明其他 PortBinding 元素来添加服务的其他端口绑定。Additional PortBindings for a service can be added by declaring additional PortBinding elements with applicable property values.

配置隔离模式Configure isolation mode

Windows 支持容器的两种隔离模式:进程和 Hyper-V。Windows supports two isolation modes for containers: process and Hyper-V. 使用进程隔离模式时,在同一台主机计算机上运行的所有容器会与主机共享内核。With the process isolation mode, all the containers running on the same host machine share the kernel with the host. 使用 Hyper-V 隔离模式时,内核会在每个 Hyper-V 容器与容器主机之间隔离。With the Hyper-V isolation mode, the kernels are isolated between each Hyper-V container and the container host. 隔离模式在应用程序清单文件中的 ContainerHostPolicies 元素内指定。The isolation mode is specified in the ContainerHostPolicies element in the application manifest file. 可以指定的隔离模式为 processhypervdefaultThe isolation modes that can be specified are process, hyperv, and default. Windows Server 主机上默认采用进程隔离模式。The default is process isolation mode on Windows Server hosts. Windows 10 主机仅支持 Hyper-V 隔离模式,因此无论容器的离模式设置如何,它都在 Hyper-V 隔离模式下运行。On Windows 10 hosts, only Hyper-V isolation mode is supported, so the container runs in Hyper-V isolation mode regardless of its isolation mode setting. 以下代码片段演示如何在应用程序清单文件中指定隔离模式。The following snippet shows how the isolation mode is specified in the application manifest file.

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

备注

hyperv 隔离模式在 Ev3 和 Dv3 Azure SKU 上提供,后者具有嵌套式虚拟化支持。The hyperv isolation mode is available on Ev3 and Dv3 Azure SKUs which have nested virtualization support.

配置资源调控Configure resource governance

资源调控限制容器能够在主机上使用的资源。Resource governance restricts the resources that the container can use on the host. 在应用程序清单中指定的 ResourceGovernancePolicy 元素用于声明服务代码包的资源限制。The ResourceGovernancePolicy element, which is specified in the application manifest, is used to declare resource limits for a service code package. 可以为以下资源设置资源限制:内存、MemorySwap、CpuShares(CPU 相对权重)、MemoryReservationInMB、BlkioWeight(BlockIO 相对权重)。Resource limits can be set for the following resources: Memory, MemorySwap, CpuShares (CPU relative weight), MemoryReservationInMB, BlkioWeight (BlockIO relative weight). 在此示例中,服务包 Guest1Pkg 在放置它的群集节点上获得一个核心。In this example, service package Guest1Pkg gets one core on the cluster nodes where it is placed. 内存限制是绝对的,所以此代码包限制为 1024 MB 内存(和相同的软保证预留)。Memory limits are absolute, so the code package is limited to 1024 MB of memory (and a soft-guarantee reservation of the same). 代码包(容器或进程)无法分配超出此限制的内存,尝试执行此操作会引发内存不足异常。Code packages (containers or processes) are not able to allocate more memory than this limit, and attempting to do so results in an out-of-memory exception. 若要强制执行资源限制,服务包中的所有代码包均应指定内存限制。For resource limit enforcement to work, all code packages within a service package should have memory limits specified.

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

配置 docker HEALTHCHECKConfigure docker HEALTHCHECK

从 v6.1 开始,Service Fabric 自动将 docker HEALTHCHECK 事件集成到其系统运行状况报告。Starting v6.1, Service Fabric automatically integrates docker HEALTHCHECK events to its system health report. 这意味着,如果容器启用了 HEALTHCHECK,则只要容器的运行状况状态如 Docker 所报告的那样更改,Service Fabric 就会报告运行状况。This means that if your container has HEALTHCHECK enabled, Service Fabric will report health whenever the health status of the container changes as reported by Docker. health_status 为“正常” 时,会在 Service Fabric Explorer 中显示运行状况报告“正常”; 当 health_status 为“不正常”时, 会显示“警告”。An OK health report will appear in Service Fabric Explorer when the health_status is healthy and WARNING will appear when health_status is unhealthy.

从 v6.4 的最新更新版开始,可以选择指定应将 Docker HEALTHCHECK 评估报告为错误。Starting with the latest refresh release of v6.4, you have the option to specify that docker HEALTHCHECK evaluations should be reported as an error. 如果此选项已启用,当 health_status 为“正常”时,将显示“正常”运行状况报告;当 health_status 为“不正常”时,将显示“错误”运行状况报告。If this option is enabled, an OK health report will appear when health_status is healthy and ERROR will appear when health_status is unhealthy.

生成容器映像时使用的 Dockerfile 中必须存在 HEALTHCHECK 指令,该指令指向监视容器运行状况时执行的实际检查。The HEALTHCHECK instruction pointing to the actual check that is performed for monitoring container health must be present in the Dockerfile used while generating the container image.

HealthCheckHealthy

HealthCheckUnhealthyApp

HealthCheckUnhealthyDsp

通过在 ApplicationManifest 中将 HealthConfig 选项指定为 ContainerHostPolicies 的一部分,可以为每个容器配置 HEALTHCHECK 行为。You can configure HEALTHCHECK behavior for each container by specifying HealthConfig options as part of ContainerHostPolicies in ApplicationManifest.

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

默认情况下,IncludeDockerHealthStatusInSystemHealthReport 设置为 trueRestartContainerOnUnhealthyDockerHealthStatus 设置为 false,而 TreatContainerUnhealthyStatusAsError 设置为 falseBy default IncludeDockerHealthStatusInSystemHealthReport is set to true, RestartContainerOnUnhealthyDockerHealthStatus is set to false, and TreatContainerUnhealthyStatusAsError is set to false.

如果 RestartContainerOnUnhealthyDockerHealthStatus 设置为 true,则会重启(可能在其他节点上进行)反复报告“不正常”的容器。If RestartContainerOnUnhealthyDockerHealthStatus is set to true, a container repeatedly reporting unhealthy is restarted (possibly on other nodes).

如果 TreatContainerUnhealthyStatusAsError 设置为 true,当容器的 health_status 为“运行不正常”时,将显示“错误”运行状况报告。If TreatContainerUnhealthyStatusAsError is set to true, ERROR health reports will appear when the container's health_status is unhealthy.

若要禁用整个 Service Fabric 群集的 HEALTHCHECK 集成,则需将 EnableDockerHealthCheckIntegration 设置为 falseIf you want to the disable the HEALTHCHECK integration for the entire Service Fabric cluster, you will need to set EnableDockerHealthCheckIntegration to false.

部署容器应用程序Deploy the container application

保存所有更改,生成应用程序。Save all your changes and build the application. 若要发布应用程序,请右键单击解决方案资源管理器中的“MyFirstContainer”,选择“发布”。 To publish your application, right-click on MyFirstContainer in Solution Explorer and select Publish.

在“连接终结点”中 输入群集的管理终结点。In Connection Endpoint, enter the management endpoint for the cluster. 例如,containercluster.chinanorth2.cloudapp.chinacloudapi.cn:19000For example, containercluster.chinanorth2.cloudapp.chinacloudapi.cn:19000. Azure 门户中,可以在群集的“概览”选项卡中查找客户端连接终结点。You can find the client connection endpoint in the Overview tab for your cluster in the Azure portal.

单击“发布”。 Click Publish.

Service Fabric Explorer 是一项基于 Web 的工具,用于检验和管理 Service Fabric 群集中的应用程序和节点。Service Fabric Explorer is a web-based tool for inspecting and managing applications and nodes in a Service Fabric cluster. 打开浏览器,导航到 http://containercluster.chinanorth2.cloudapp.chinacloudapi.cn:19080/Explorer/ ,并执行应用程序部署。Open a browser and navigate to http://containercluster.chinanorth2.cloudapp.chinacloudapi.cn:19080/Explorer/ and follow the application deployment. 将映像下载到群集节点(这可能需要一段时间,具体时间取决于映像大小)之前,应用程序可部署但处于错误状态:错误The application deploys but is in an error state until the image is downloaded on the cluster nodes (which can take some time, depending on the image size): Error

如果应用程序处于 Ready 状态,则表示它已准备就绪:就绪The application is ready when it's in Ready state: Ready

打开浏览器并导航到 http://containercluster.chinanorth2.cloudapp.chinacloudapi.cn:8081Open a browser and navigate to http://containercluster.chinanorth2.cloudapp.chinacloudapi.cn:8081. 此时会看到标题“Hello World!”You should see the heading "Hello World!" 显示在浏览器中。display in the browser.

清理Clean up

只要群集处于运行状态,就会产生费用。若要避免不必要的费用,可考虑删除群集You continue to incur charges while the cluster is running, consider deleting your cluster.

将映像推送到容器注册表以后,可从开发计算机中删除本地映像:After you push the image to the container registry, you can delete the local image from your development computer:

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

Windows Server 容器 OS 与主机 OS 的兼容性Windows Server container OS and host OS compatibility

Windows Server 容器并非在所有主机 OS 版本间都兼容。Windows Server containers are not compatible across all versions of a host OS. 例如:For example:

  • 使用 Windows Server 1709 版本生成的 Windows Server 容器在运行 Windows Server 2016 版本的主机上无效。Windows Server containers built using Windows Server version 1709 do not work on a host running Windows Server version 2016.
  • 使用 Windows Server 2016 生成的 Windows Server 容器仅在运行 Windows Server 1709 版本的主机上以 Hyper-V 隔离模式工作。Windows Server containers built using Windows Server 2016 work in Hyper-V isolation mode only on a host running Windows Server version 1709.
  • 因为 Windows Server 容器使用 Windows Server 2016 生成,所以在运行 Windows Server 2016 的主机上以进程隔离模式运行时,可能需要确保容器 OS 和主机 OS 的版本相同。With Windows Server containers built using Windows Server 2016, it might be necessary to ensure that the revision of the container OS and host OS are the same when running in process isolation mode on a host running Windows Server 2016.

若要了解详细信息,请参阅 Windows 容器版本兼容性To learn more, see Windows Container Version Compatibility.

将容器生成和部署到 Service Fabric 群集时,请考虑主机 OS 和容器 OS 的兼容性。Consider the compatibility of the host OS and your container OS when building and deploying containers to your Service Fabric cluster. 例如:For example:

  • 请确保通过与群集节点上的 OS 兼容的 OS 部署容器。Make sure you deploy containers with an OS compatible with the OS on your cluster nodes.
  • 请确保为容器应用指定的隔离模式与为部署容器的节点上的容器 OS 提供支持的要求一致。Make sure that the isolation mode specified for your container app is consistent with support for the container OS on the node where it is being deployed.
  • 请考虑 OS 升级到群集结点的方式,否则容器可能影响它们的兼容性。Consider how OS upgrades to your cluster nodes or containers may affect their compatibility.

建议采取以下做法,确保容器正确部署在 Service Fabric 群集上:We recommend the following practices to make sure that containers are deployed correctly on your Service Fabric cluster:

  • 对 Docker 映像进行显式映像标记,以指定生成容器的 Windows Server OS 的版本。Use explicit image tagging with your Docker images to specify the version of Windows Server OS that a container is built from.
  • 在应用程序清单文件中使用 OS 标记,确保应用程序与不同 Windows Server 版本和升级兼容。Use OS tagging in your application manifest file to make sure that your application is compatible across different Windows Server versions and upgrades.

备注

使用 Service Fabric 6.2 及更高版本,可以在 Windows 10 主机上本地部署基于 Windows Server 2016 的容器。With Service Fabric version 6.2 and later, you can deploy containers based on Windows Server 2016 locally on a Windows 10 host. 在 Windows 10 上,容器以 Hyper-V 隔离模式运行,不管应用程序清单中设置的隔离模式如何。On Windows 10, containers run in Hyper-V isolation mode, regardless of the isolation mode set in the application manifest. 若要了解详细信息,请参阅配置隔离模式To learn more, see Configure isolation mode.

指定特定于 OS 内部版本的容器映像Specify OS build specific container images

Windows Server 容器在不同 OS 版本中可能不兼容。Windows Server containers may not be compatible across different versions of the OS. 例如,在进程隔离模式中,使用 Windows Server 2016 生成的 Windows Server 容器在 Windows Server 版本 1709 上无效。For example, Windows Server containers built using Windows Server 2016 do not work on Windows Server version 1709 in process isolation mode. 因此,如果将群集节点更新到最新版本,则使用较早版本的 OS 生成的容器服务可能会发生故障。Hence, if cluster nodes are updated to the latest version, container services built using the earlier versions of the OS may fail. 为了避免 6.1 及更新版本的运行时出现这种情况,Service Fabric 允许为每个容器指定多个 OS 映像并为这些映像标记应用程序清单中的 OS 的内部版本。To circumvent this with version 6.1 of the runtime and newer, Service Fabric supports specifying multiple OS images per container and tagging them with the build versions of the OS in the application manifest. 可以通过在 Windows 命令提示符下运行 winver 获取 OS 的内部版本。You can get the build version of the OS by running winver at a Windows command prompt. 更新应用程序清单并为每个 OS 版本指定映像重写项,然后更新节点上的 OS。Update the application manifests and specify image overrides per OS version before updating the OS on the nodes. 以下代码片段演示了如何在应用程序清单 ApplicationManifest.xml 中指定多个容器映像:The following snippet shows how to specify multiple container images in the application manifest, ApplicationManifest.xml:

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

WIndows Server 2016 的内部版本为 14393,Windows Server 版本 1709 的内部版本为 16299。The build version for WIndows Server 2016 is 14393, and the build version for Windows Server version 1709 is 16299. 对于单个容器服务,服务清单仍然只指定一个映像,如下所示:The service manifest continues to specify only one image per container service as the following shows:

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

备注

OS 内部版本标记功能仅适用于 Windows 上的 Service FabricThe OS build version tagging features is only available for Service Fabric on Windows

如果 VM 上的基础 OS 为内部版本 16299(版本 1709),Service Fabric 会根据该 Windows Server 版本选取容器映像。If the underlying OS on the VM is build 16299 (version 1709), Service Fabric picks the container image corresponding to that Windows Server version. 如果应用程序清单中除了标记的容器映像外,还提供了未标记的容器映像,则 Service Fabric 会将未标记的映像视为可以跨版本使用的映像。If an untagged container image is also provided alongside tagged container images in the application manifest, then Service Fabric treats the untagged image as one that works across versions. 请显式对容器映像进行标记以避免在升级过程中出现问题。Tag the container images explicitly to avoid issues during upgrades.

未标记的容器映像将作为在 ServiceManifest 中提供的映像的替代。The untagged container image will work as an override for the one provide in the ServiceManifest. 因此,映像“myregistry.azurecr.cn/samples/helloworldappDefault”将替代 ServiceManifest 中的 ImageName“myregistry.azurecr.cn/samples/helloworldapp”。So image "myregistry.azurecr.cn/samples/helloworldappDefault" will override the ImageName "myregistry.azurecr.cn/samples/helloworldapp" in the ServiceManifest.

Service Fabric 应用程序和服务清单的完整示例Complete example Service Fabric application and service manifests

下面是本文中使用的服务和应用程序完整清单。Here are the complete service and application manifests used in this article.

ServiceManifest.xmlServiceManifest.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.cn/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.xmlApplicationManifest.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>

配置在强制终止容器之前需经历的时间间隔Configure time interval before container is force terminated

可以配置一个时间间隔,目的是在启动服务删除操作(或移动到另一个节点的操作)之后,要求运行时在删除容器之前等待特定的时间。You can configure a time interval for the runtime to wait before the container is removed after the service deletion (or a move to another node) has started. 配置时间间隔时,会向容器发送 docker stop <time in seconds> 命令。Configuring the time interval sends the docker stop <time in seconds> command to the container. 有关更多详细信息,请参阅 docker stopFor more detail, see docker stop. 等待时间间隔在 Hosting 节指定。The time interval to wait is specified under the Hosting section. 可以在群集创建时或配置升级后期添加 Hosting 节。The Hosting section can be added at cluster creation or later in a configuration upgrade. 以下群集清单代码片段显示了如何设置等待时间间隔:The following cluster manifest snippet shows how to set the wait interval:

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

默认时间间隔设置为 10 秒。The default time interval is set to 10 seconds. 由于此配置是动态的,因此对群集进行仅限配置的升级即可更新超时。Since this configuration is dynamic, a config only upgrade on the cluster updates the timeout.

将运行时配置为删除未使用的容器映像Configure the runtime to remove unused container images

可将 Service Fabric 群集配置为从节点删除未使用的容器映像。You can configure the Service Fabric cluster to remove unused container images from the node. 如果节点上存在过多容器映像,则可通过此配置回收磁盘空间。This configuration allows disk space to be recaptured if too many container images are present on the node. 若要启用此功能,请更新群集清单中的 Hosting 节,如以下代码片段所示:To enable this feature, update the Hosting section in the cluster manifest as shown in the following snippet:

"fabricSettings": [
    ...,
    {
        "name": "Hosting",
        "parameters": [
          {
                "name": "PruneContainerImages",
                "value": "True"
          },
          {
                "name": "ContainerImagesToSkip",
                "value": "microsoft/windowsservercore|microsoft/nanoserver|microsoft/dotnet-frameworku|..."
          }
          ...
          }
        ]
    } 
]

对于不应删除的映像,可以在 ContainerImagesToSkip 参数下进行指定。For images that shouldn't be deleted, you can specify them under the ContainerImagesToSkip parameter.

配置容器映像下载时间Configure container image download time

Service Fabric 运行时为下载和解压缩容器映像分配了 20 分钟的时间,这适用于大多数容器映像。The Service Fabric runtime allocates 20 minutes to download and extract container images, which work for the majority of container images. 如果是大型映像,或者网络连接速度较慢,则可能必须延长中止映像下载和解压缩之前的等待时间。For large images, or when the network connection is slow, it might be necessary to increase the time to wait before aborting the image download and extraction. 此超时是使用群集清单的 Hosting 节中的 ContainerImageDownloadTimeout 属性设置的,如以下代码片段所示:This time out is set using the ContainerImageDownloadTimeout attribute in the Hosting section of the cluster manifest as shown in the following snippet:

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

设置容器保留策略Set container retention policy

Service Fabric(6.1 或更高版本)支持保留终止的或无法启动的容器,这样有助于诊断容器启动故障。To assist with diagnosing container startup failures, Service Fabric (version 6.1 or higher) supports retaining containers that terminated or failed to startup. 此策略可以在 ApplicationManifest.xml 文件中设置,如以下代码片段所示:This policy can be set in the ApplicationManifest.xml file as shown in the following snippet:

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

ContainersRetentionCount 设置指定在容器故障时需保留的容器数。The setting ContainersRetentionCount specifies the number of containers to retain when they fail. 如果指定一个负值,则会保留所有故障容器。If a negative value is specified, all failing containers will be retained. 如果不指定 ContainersRetentionCount 属性,则不会保留任何容器。When the ContainersRetentionCount attribute is not specified, no containers will be retained. ContainersRetentionCount 属性还支持应用程序参数,因此用户可以为测试性群集和生产群集指定不同的值。The attribute ContainersRetentionCount also supports Application Parameters so users can specify different values for test and production clusters. 使用此功能时可使用放置约束,将容器服务的目标设置为特定的节点,防止将容器服务移至其他节点。Use placement constraints to target the container service to a particular node when using this feature to prevent the container service from moving to other nodes. 使用此功能保留的容器必须手动删除。Any containers retained using this feature must be manually removed.

使用自定义参数启动 Docker 守护程序Start the Docker daemon with custom arguments

有了 6.2 版和更高版本的 Service Fabric 运行时,可以使用自定义参数启动 Docker 守护程序。With the 6.2 version of the Service Fabric runtime and greater, you can start the Docker daemon with custom arguments. 指定自定义参数时,Service Fabric 不会将 --pidfile 参数以外的任何其他参数传递给 docker 引擎。When custom arguments are specified, Service Fabric does not pass any other argument to docker engine except the --pidfile argument. 因此,--pidfile 不应作为参数传递。Hence, --pidfile shouldn't be passed as an argument. 此外,参数应继续让 docker 守护程序侦听 Windows 上的默认名称管道(或 Linux 上的 unix 域套接字),以便 Service Fabric 与该守护程序通信。Additionally, the argument should continue to have the docker daemon listen on the default name pipe on Windows (or unix domain socket on Linux) for Service Fabric to communicate with the Daemon. 自定义参数是在 Hosting 节中的 ContainerServiceArguments 下的群集清单中传递的,如以下代码片段中所示。The custom arguments are passed in the cluster manifest under the Hosting section under ContainerServiceArguments as shown in the following snippet:

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

后续步骤Next steps