65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Docker 中运行 ASP.NET Web API 解决方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (16投票s)

2018年8月24日

CPOL

5分钟阅读

viewsIcon

75299

本文介绍了如何使用 Visual Studio 将 ASP.NET WebApi 解决方案容器化,如何通过环境变量传递数据,以及如何在没有 Visual Studio 的情况下在 Docker 中运行这些镜像。

引言

在 Docker 容器中运行具有 Web API 的 Web 解决方案时,棘手的部分在于如何映射 URL 和端口,以便可以从外部访问在 Docker 容器内运行的代码。这是一个 Docker 配置和少量代码更改的问题。

背景

本文是为 这篇文章 中描述的 Docker 大赛提供的投稿。

必备组件

  • Visual Studio 2017,社区版。最新版本。
  • 您已在计算机上安装了“Docker For Windows”:https://download.docker.com/win/stable/Docker for Windows Installer.exe
  • 您有一个现有的解决方案,其中包含一个 Web API 和一个 Web “模型-视图-控制器”项目,并且 MVC 项目能够通过 REST HTTP 接口与 Web API 进行通信。如果不是,您可以按照(下面)使用 CarApiCarClient 项目来实现自己的解决方案。

本文的代码是 这篇文章CarClientCarApi 的容器化版本。

在本文中,已添加 Docker 支持,并更新了 Docker 配置文件,以便 CarClient(前端和后端)能够访问 API。

如何容器化现有项目

要为现有 Web 项目(例如 CarApi)添加 Docker 支持,请在 Visual Studio 中打开该项目,右键单击项目,然后选择“添加” -> “Docker 支持”:

1257705/Containerize.jpg

将创建一个 Docker 配置文件“Dockerfile”,其内容如下:

# For more info see: http://aka.ms/VSContainerToolingDockerfiles
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.0 AS builder
WORKDIR /src
COPY *.sln ./
COPY CarApi/CarApi.csproj CarApi/
RUN dotnet restore
COPY . .
WORKDIR /src/CarApi
RUN dotnet build -c Release -o /app

FROM builder AS publish
RUN dotnet publish -c Release -o /app

FROM base AS production
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "CarApi.dll"

对现有解决方案中的两个项目都执行此操作,即 Web API 项目和 Web MVC 项目。完成后,您需要向解决方案中添加一个 docker-compose 项目。

添加 Docker Compose 项目

要向解决方案添加 Docker Compose 项目,请右键单击其中一个项目,然后选择“添加” -> “容器编排器支持” -> “Docker Compose” -> “目标操作系统:Linux”。

1257705/Docker-compose.jpg

添加的项目类型为“.dcproj”,并创建了以下文件:

1257705/Docker-composeFiles.jpg

下一步是右键单击另一个项目,同样选择“添加” -> “容器编排器支持” -> “Docker Compose” -> “目标操作系统:Linux”。

假设您的两个项目名为“CarClient”和“CarApi”,那么生成的 docker-compose.yml 内容如下:

version: '3.4'

services:
  web:
    image: ${DOCKER_REGISTRY}carclient
    build:
      context: .
      dockerfile: CarClient/Dockerfile

  api:
    image: ${DOCKER_REGISTRY}carapi
    build:
      context: .
      dockerfile: CarApi/Dockerfile

带 Docker Compose 的容器化解决方案

在为每个项目添加了 Dockerfile 并为解决方案添加了 docker-compose 项目后,解决方案将包含三个项目:一个 Web MVC 项目、一个 Web API 项目和一个 docker-compose 项目。

添加环境变量

为了使容器化版本正常工作,我们需要进行一些配置更改。

后端

在原始 CarClient 项目中,Web API 通过以下 URL 访问:

private static readonly Uri Endpoint = new Uri("https://:54411/");

此处,URL 被硬编码,但我们也可以在 launchSettings.json 中定义一个 environment 变量:

  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "CarApiUrl": "http//:54411/"
      }

environment 变量的读取方式如下:

var carApiUrl = Environment.GetEnvironmentVariable("CarApiUrl");

对于容器化解决方案,我们使用“DNS 发现”。Docker 网络以及 Kubernetes 会处理所有这些魔术。我们使用在 docker-compose 中定义的服务的名称,而不是 localhost。要调用 CarApi,请使用 http://carapi。您无需设置端口号,因为端口号是外部属性。

我们将使用名为 CarApiUrl 的环境变量。该变量在 docker-compose.yml 文件中定义如下:

version: '3.4'

services:
...
  carclient:
    image: ${DOCKER_REGISTRY}carclient
    environment:
      - CarApiUrl=http://carapi/
    build:
      context: .
      dockerfile: CarClient/Dockerfile

环境变量在 Utils.cs 文件中读取:

private static readonly Uri Endpoint = 
        new Uri(Environment.GetEnvironmentVariable("CarApiUrl"));

通过使用环境变量,我们无需更改代码,只需更改配置即可容器化解决方案。

前端

浏览器中运行的 JavaScript 使用端口 54411。我们必须通过更改 CarApi 的 Docker 配置文件来公开端口 54411,如下所示:

在 Web API Dockerfile 中,写入 EXPOSE 54411

# For more info see: http://aka.ms/VSContainerToolingDockerfiles
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 54411
...

docker-compose.yml 中,将外部端口 54411 映射到内部端口 80

version: '3.4'

services:
  carapi:
    image: ${DOCKER_REGISTRY}carapi
    ports:
      - 54411:80
...

原始 JavaScript 代码保持不变。

xmlhttp.open("GET", "https://:54411/api/car", true);

这就完成了。您现在可以在 Visual Studio 中运行容器化解决方案了。

在没有 Visual Studio 的情况下运行您的应用

使用 Visual Studio 将解决方案以 Release 配置重新生成。按 F5 运行 docker-compose 项目,以确保镜像已更新。

在 Visual Studio 之外,您需要使用 docker-compose 命令而不是 docker run。在 PowerShell 中,将目录更改 (cd) 到 docker-compose.yml 所在的解决方案文件夹。然后像这样运行 docker-compose 命令:

…> docker-compose --no-ansi up -d  --force-recreate --remove-orphans

然后使用 docker ps 检查 carclient 正在运行的端口:

…> docker ps

CONTAINER ID  IMAGE     COMMAND                CREATED      STATUS      PORTS   …

5c5c3a6fa376  carclient "dotnet CarClient.dll" 12 hours ago Up 12 hours 0.0.0.0:32781->80/tcp

20cf31344091  carapi    "dotnet CarApi.dll"    12 hours ago Up 12 hours 54411/tcp, ….

Carclient 运行在端口 32781 上。然后应用程序将可以通过 https://:32781 访问。

解释

如果设置了 Debug 配置,则 Visual Studio 会创建的、不可用的镜像。它会手动将空容器映射到文件系统,以支持调试、“编辑并继续”等功能。因此,开发镜像在没有 Visual Studio 的情况下是无用的。在 Release 配置中构建镜像,使其可用。

完整的发布过程在文档中有描述:Visual Studio Tools for Docker

运行您的应用并使用 Docker 网络

无需 YAML,即可通过 Docker 网络进行容器通信。

首先是一些有用的 Docker 命令:

全部终止,(启动、运行、删除所有)

>>docker kill $(docker ps -aq)

在容器内启动 shell

>>docker exec -i -t container_name /bin/bash

不使用 docker-compose,而是使用 Docker 网络运行解决方案:

cd to carapi
>>docker build -t carapi .

>>docker run -e ASPNETCORE_ENVIRONMENT=Development -d -p 54411:80 --name carapi carapi

检查 Docker 桥接网络,找到 carapi 使用的 IP 地址;

>> docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "fce049eb23e5fb1a7b5c801a082d8809efd4d369f18de4693b35e6524f1d55c0",
        "Created": "2019-03-04T15:13:40.1528498Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "cbf2ae63374659b4a9c8e341e22b20a7f3e6d7b6593d289d7ffa4db415d6e8b6": {
                "Name": "carapi",
                "EndpointID": "0c25cdaa8403c928b12efc1e5f6bb40b71e76acc438f8b95d2ba7a135eb333e9",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "f1abe1fdb72a23b61f7160aa49aca06f9c849dd3fca9432257168175625589a2": {
                "Name": "carclient",
                "EndpointID": "aa4dd99b8045e5a0c77f6dadd17ad9d3579c82c3cf7ee2af45461e6284523739",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

您会看到 carapi 使用的 IP 地址是 172.17.0.3。在下面的 docker run 命令中使用此 IP 地址作为环境变量 CarApiUrl

cd to carclient
>>docker build -t carclient .

>>docker run -e ASPNETCORE_ENVIRONMENT=Development 
  -e CarApiUrl=http://172.17.0.3 -d -p 8080:80 --name carclient carclient

然后,在浏览器中通过 localhost:8080 启动客户端。

现在,容器无需 YAML 即可通过 Docker 桥接网络进行通信。

关注点

在本文中,我们讨论了如何使用 Visual Studio 将 ASP.NET WebApi 解决方案容器化,如何通过环境变量传递数据,以及如何在没有 Visual Studio 的情况下在 Docker 中运行这些镜像。我们还介绍了如何使用 Docker 网络作为 docker-compose 和 YAML 文件的替代方案。

历史

  • 2018 年 8 月 24 日 - 本文的第一个修订版发布
  • 2018 年 9 月 1 日 - 引入了环境变量
  • 2018 年 9 月 6 日 - 在没有 Visual Studio 的情况下运行应用程序
  • 2019 年 3 月 6 日 - 在没有 docker-compose 的情况下使用 Docker 网络运行应用程序

代码可在 此处 获取。

© . All rights reserved.