Docker & ASP.NET Core 2.0 微服務跨平臺實踐

来源:http://www.cnblogs.com/xishuai/archive/2017/11/15/ubuntu-docker-consul-fabio-aspnet-core.html
-Advertisement-
Play Games

相關博文: "Ubuntu 簡單安裝 Docker" "Mac OS、Ubuntu 安裝及使用 Consul" "Consul 服務註冊與服務發現" "Fabio 安裝和簡單使用" 閱讀目錄: Docker 運行 Consul 環境 Docker 運行 Fabio 環境 使用 Consul 註冊 A ...


相關博文:

閱讀目錄:

  • Docker 運行 Consul 環境
  • Docker 運行 Fabio 環境
  • 使用 Consul 註冊 ASP.NET Core 2.0 服務
  • 使用 Docker 發佈部署 ASP.NET Core 2.0 服務

本篇博文的目的:在 Mac OS 中使用 VS Code 開發 ASP.NET Core 2.0 應用程式,然後在 Ubuntu 伺服器配置 Docker 環境,並使用 Docker 運行 Consul 和 Fabio 環境,最後使用 Docker 運行 ASP.NET Core 2.0 應用程式。

你要的項目源碼:https://github.com/yuezhongxin/HelloDocker.Sample

上面配置看起來還蠻簡單,但實際去操作的時候,還是遇到了蠻多的問題,並且花了很多的時間去解決,比如 Docker 運行 Consul 和 Fabio,下麵詳細說下過程。

1. Docker 運行 Consul 環境

關於 Consul 的概念:

Consul 是 HashiCorp 公司推出的開源工具,用於實現分散式系統的服務發現與配置。與其他分散式服務註冊與發現的方案,比如 Airbnb 的 SmartStack 等相比,Consul 的方案更“一站式”,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,不再需要依賴其他工具(比如 ZooKeeper 等)。使用起來也較 為簡單。Consul 用 Golang 實現,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X);安裝包僅包含一個可執行文件,方便部署,與 Docker 等輕量級容器可無縫配合。

Consul Docker 鏡像地址:https://hub.docker.com/_/consul/

配置 Consul 的微服務集群環境,需要先配置下 Server 服務端(需要獨立伺服器環境),配置命令(沒有使用 Docker):

$ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -ui-dir=./dist  -config-dir /etc/consul.d -bind=10.9.10.110

一開始,我想在 Mac OS 環境中使用 Docker 配置 Consul Client 客戶端,但遇到了一些問題,配置命令:

$ docker run -d --net=host --name=consul-client consul agent -bind=10.9.10.190 -client=0.0.0.0 -node=mac-xishuai -retry-join=10.9.10.236

先解析下命令的意思:

  • --net=hosthost網路模式,容器的網路介面和主機一樣,也就是共用一個 IP 地址,如果沒有此命令,預設是bridge網路模式,也就是我們常用的橋接模式,Docker 會分配給容器一個獨立的 IP 地址(埠也是獨立的),並且容器和主機之間可以相互訪問。
  • -bind=:Consul Client 綁定的 IP 地址,一般是內網的私有 IP 地址,需要內網伺服器之前可以相互訪問到,註意並不是127.0.0.1
  • -retry-join=:加入 Consul 集群中,地址是 Consul Server 的 IP 地址,也可以是-join=,加上retry會不斷進行重試。

一臺伺服器一般會配置一個 Consul Client,所以我們可以直接讓 Consul 容器和主機的 IP 地址一樣(我使用的),但使用了 Docker 之後,一臺伺服器就可以配置多個 Consul Client,我們就可以使用bridge網路模式,一臺伺服器可以完成配置整個 Consul 集群環境。

這裡需要再重點說下-client=,一開始我沒有理解,先看下官方說明:

If you want to expose the Consul interfaces to other containers via a different network, such as the bridge network, use the-clientoption for Consul.
With this configuration, Consul's client interfaces will be bound to the bridge IP and available to other containers on that network, but not on the host network. Note that we still keep the cluster address out on the host network for performance. Consul will also accept the-client=0.0.0.0option to bind to all interfaces.

啥意思呢?Consul 服務註冊的時候,一般是通過 HTTP API 介面進行註冊,比如:http://10.9.10.190:8500/v1/agent/service/register,就是往 Consul 集群中註冊服務,需要註意的是,10.9.10.190一般是 Consul Client 的 IP 地址(也可以是 Consul Server),-client配置的就是此地址,簡單來說,就是用來服務註冊並能訪問到的地址,換句話說,服務註冊可以跨伺服器(服務和 Consul Client 並不需要在同一臺伺服器上),0.0.0.0表示任何本機的相關 IP 地址都可以訪問,推薦此配置。

這裡需要再說明下,Docker 部署 ASP.NET Core 2.0、Consul 和 Fabio 有兩種方式:

  • 使用一個 Docker 容器:很簡單,在一個容器中完成服務部署,並且配置 Consul 和 Fabio 環境,這樣容器就會很臃腫,並且每次發佈的時候都得重新配置 Consul 和 Fabio 環境,如果服務很多的話,想想就覺得恐怖。
  • 分別獨立 Docker 容器:服務部署、配置 Consul 和 Fabio 環境,都是獨立容器實現,互不影響,也可以跨服務實現,簡單靈活。

顯而易見,推薦第二種方式。

回到正題,上面配置命令,在 Mac OS 報如下錯誤:

$ docker logs consul-client
==> Starting Consul agent...
==> Error starting agent: Failed to start Consul client: Failed to start lan serf: Failed to create memberlist: Could not set up network transport: failed to obtain an address: Failed to start TCP listener on "10.9.10.190" port 8301: listen tcp 10.9.10.190:8301: bind: cannot assign requested address

這個問題花了很多時間也沒有解決,奇怪的是不使用 Docker,直接運行 Consul Client 配置命令,卻是可以的,後來沒辦法,我就在 Mac OS 中使用 Ubuntu 虛擬機了(版本 14.04),使用的 Vagrant 管理工具。

再重新運行配置命令:

$ docker run -d --net=host --name=consul-client consul agent -bind=10.9.10.89 -client=0.0.0.0 -node=vagrant-ubuntu-xishuai -retry-join=10.9.2.236

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
9c4988cf475f        consul              "docker-entrypoint..."   2 seconds ago       Up 2 seconds                            consul-client

$ docker logs consul-client
==> Starting Consul agent...
==> Consul agent running!
           Version: 'v1.0.0'
           Node ID: '34e63f0a-d361-f152-3803-b9fda0642e4d'
         Node name: 'vagrant-ubuntu-xishuai'
        Datacenter: 'dc1' (Segment: '')
            Server: false (Bootstrap: false)
       Client Addr: [0.0.0.0] (HTTP: 8500, HTTPS: -1, DNS: 8600)
      Cluster Addr: 10.9.10.89 (LAN: 8301, WAN: 8302)
           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false

==> Log data will now stream in as it occurs:

    2017/11/14 06:40:52 [INFO] serf: EventMemberJoin: vagrant-ubuntu-xishuai 10.9.10.89
    2017/11/14 06:40:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (udp)
    2017/11/14 06:40:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (tcp)
    2017/11/14 06:40:52 [INFO] agent: Started HTTP server on [::]:8500 (tcp)
    2017/11/14 06:40:52 [INFO] agent: Retry join LAN is supported for: aws azure gce softlayer
    2017/11/14 06:40:52 [INFO] agent: Joining LAN cluster...
    2017/11/14 06:40:52 [INFO] agent: (LAN) joining: [10.9.2.236]
    2017/11/14 06:40:52 [WARN] manager: No servers available
    2017/11/14 06:40:52 [ERR] agent: failed to sync remote state: No known Consul servers
    2017/11/14 06:40:52 [INFO] serf: EventMemberJoin: agent_1 10.9.2.236
    2017/11/14 06:40:52 [INFO] agent: (LAN) joined: 1 Err: <nil>
    2017/11/14 06:40:52 [INFO] agent: Join LAN completed. Synced with 1 initial agents
    2017/11/14 06:40:52 [INFO] consul: adding server agent_1 (Addr: tcp/10.9.2.236:8300) (DC: dc1)

打開 Consul UI 界面,就可以看到我們配置的 Consul Client 了:

2. Docker 運行 Fabio 環境

Fabio 是一個快速、現代、zero-conf 負載均衡 HTTP(S) 路由器,用於部署 Consul 管理的微服務。

Fabio Docker 鏡像地址:https://hub.docker.com/r/magiconair/fabio/

配置命令:

$ docker run -d --net=host --name=fabio -e 'registry_consul_addr=10.9.10.89:8500' magiconair/fabio

執行日誌:

$ docker logs fabio
2017/11/14 09:43:49 [INFO] Setting log level to INFO
2017/11/14 09:43:49 [INFO] Runtime config
{
    "Proxy": {
        "Strategy": "rnd",
        "Matcher": "prefix",
        "NoRouteStatus": 404,
        "MaxConn": 10000,
        "ShutdownWait": 0,
        "DialTimeout": 30000000000,
        "ResponseHeaderTimeout": 0,
        "KeepAliveTimeout": 0,
        "FlushInterval": 1000000000,
        "LocalIP": "10.0.2.15",
        "ClientIPHeader": "",
        "TLSHeader": "",
        "TLSHeaderValue": "",
        "GZIPContentTypes": null,
        "RequestID": ""
    },
    "Registry": {
        "Backend": "consul",
        "Static": {
            "Routes": ""
        },
        "File": {
            "Path": ""
        },
        "Consul": {
            "Addr": "10.9.10.89:8500",
            "Scheme": "http",
            "Token": "",
            "KVPath": "/fabio/config",
            "TagPrefix": "urlprefix-",
            "Register": true,
            "ServiceAddr": ":9998",
            "ServiceName": "fabio",
            "ServiceTags": null,
            "ServiceStatus": [
                "passing"
            ],
            "CheckInterval": 1000000000,
            "CheckTimeout": 3000000000,
            "CheckScheme": "http",
            "CheckTLSSkipVerify": false
        },
        "Timeout": 10000000000,
        "Retry": 500000000
    },
    "Listen": [
        {
            "Addr": ":9999",
            "Proto": "http",
            "ReadTimeout": 0,
            "WriteTimeout": 0,
            "CertSource": {
                "Name": "",
                "Type": "",
                "CertPath": "",
                "KeyPath": "",
                "ClientCAPath": "",
                "CAUpgradeCN": "",
                "Refresh": 0,
                "Header": null
            },
            "StrictMatch": false,
            "TLSMinVersion": 0,
            "TLSMaxVersion": 0,
            "TLSCiphers": null
        }
    ],
    "Log": {
        "AccessFormat": "common",
        "AccessTarget": "",
        "RoutesFormat": "delta",
        "Level": "INFO"
    },
    "Metrics": {
        "Target": "",
        "Prefix": "{{clean .Hostname}}.{{clean .Exec}}",
        "Names": "{{clean .Service}}.{{clean .Host}}.{{clean .Path}}.{{clean .TargetURL.Host}}",
        "Interval": 30000000000,
        "Timeout": 10000000000,
        "Retry": 500000000,
        "GraphiteAddr": "",
        "StatsDAddr": "",
        "Circonus": {
            "APIKey": "",
            "APIApp": "fabio",
            "APIURL": "",
            "CheckID": "",
            "BrokerID": ""
        }
    },
    "UI": {
        "Listen": {
            "Addr": ":9998",
            "Proto": "http",
            "ReadTimeout": 0,
            "WriteTimeout": 0,
            "CertSource": {
                "Name": "",
                "Type": "",
                "CertPath": "",
                "KeyPath": "",
                "ClientCAPath": "",
                "CAUpgradeCN": "",
                "Refresh": 0,
                "Header": null
            },
            "StrictMatch": false,
            "TLSMinVersion": 0,
            "TLSMaxVersion": 0,
            "TLSCiphers": null
        },
        "Color": "light-green",
        "Title": "",
        "Access": "rw"
    },
    "Runtime": {
        "GOGC": 800,
        "GOMAXPROCS": 1
    },
    "ProfileMode": "",
    "ProfilePath": "/tmp"
}

需要註意的兩個屬性值:

  • Proxy.LocalIP:10.0.2.15:綁定本機的 IP 地址,伺服器的 IP 地址是10.9.10.89,所以配置的10.0.2.15是錯誤的,這個 IP 地址內網是訪問不了的。
  • Registry.Consul.Addr:10.9.10.89:8500:綁定 Consul 地址,我們上面已經完成的 Consul Client 地址就是10.9.10.89:8500,所以是正確的。

這個配置命令研究了好久,也沒有解決綁定本機 IP 地址的問題,後來又找到了另外一種方式。

首先,在/etc/fabio/目錄下創建一個fabio.properties文件(示例配置),然後vim fabio.properties增加下麵配置:

registry.consul.register.addr = 10.9.10.89:9998

registry.consul.addr = 10.9.10.89:8500

registry.consul.register.addr綁定 Fabio 地址(本機 IP 地址),registry.consul.addr綁定 Consul 地址。

然後切換到/etc/fabio/目錄,執行配置命令:

$ docker run -d -p 9999:9999 -p 9998:9998 --net=host --name=fabio -v $PWD/fabio.properties:/etc/fabio/fabio.properties magiconair/fabio

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
301fe4a5b40b        magiconair/fabio    "/fabio -cfg /etc/..."   About a minute ago   Up About a minute                       fabio
9c4988cf475f        consul              "docker-entrypoint..."   4 hours ago          Up 4 hours                              consul-client

查看執行日誌:

$ docker logs fabio
2017/11/14 10:10:58 [INFO] Version 1.5.3 starting
2017/11/14 10:10:58 [INFO] Go runtime is go1.9.2
2017/11/14 10:10:58 [INFO] Metrics disabled
2017/11/14 10:10:58 [INFO] Setting GOGC=800
2017/11/14 10:10:58 [INFO] Setting GOMAXPROCS=1
2017/11/14 10:10:58 [INFO] consul: Connecting to "10.9.10.89:8500" in datacenter "dc1"
2017/11/14 10:10:58 [INFO] Admin server access mode "rw"
2017/11/14 10:10:58 [INFO] Admin server listening on ":9998"
2017/11/14 10:10:58 [INFO] Waiting for first routing table
2017/11/14 10:10:58 [INFO] consul: Using dynamic routes
2017/11/14 10:10:58 [INFO] consul: Using tag prefix "urlprefix-"
2017/11/14 10:10:58 [INFO] consul: Watching KV path "/fabio/config"
2017/11/14 10:10:58 [INFO] consul: Manual config changed to #3723938
2017/11/14 10:10:58 [INFO] HTTP proxy listening on :9999
2017/11/14 10:10:58 [INFO] Access logging disabled
2017/11/14 10:10:58 [INFO] Using routing strategy "rnd"
2017/11/14 10:10:58 [INFO] Using route matching "prefix"
2017/11/14 10:10:58 [INFO] consul: Health changed to #3727339
2017/11/14 10:10:59 [INFO] consul: Registered fabio with id "fabio-vagrant-ubuntu-trusty-9998"
2017/11/14 10:10:59 [INFO] consul: Registered fabio with address "10.9.10.89"
2017/11/14 10:10:59 [INFO] consul: Registered fabio with tags ""
2017/11/14 10:10:59 [INFO] consul: Registered fabio with health check to "http://[10.9.10.89]:9998/health"
2017/11/14 10:11:00 [INFO] Config updates

可以通過 Consul UI,進行查看 Fabio 是否正常:

也可以直接瀏覽 http://10.9.10.89:9998/routes?filter=,查看已經註冊的服務:

其實,如果不清楚配置命令的話,我們也可以查看 Consul 源碼,有可能會幫助我們熟悉命令,比如(https://github.com/fabiolb/fabio/blob/master/registry/consul/register.go):

3. 使用 Consul 註冊 ASP.NET Core 2.0 服務

在 Mac OS 中使用 VS Code 開發 ASP.NET Core 2.0 應用程式,就像寫 Markdown 一樣方便。

Consul 註冊 ASP.NET Core 2.0 服務,使用的是 Consul 組件,地址:https://github.com/PlayFab/consuldotnet

安裝程式包(VS Code 需要使用NuGet Pakcage Manager命令安裝):

> install-package Conusl

然後添加一個RegisterWithConsul擴展服務:

using System;
using System.Collections.Generic;
using System.Linq;
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;

public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder RegisterWithConsul(this IApplicationBuilder app, IApplicationLifetime lifetime)
    {
        //var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{Program.IP}:8500"));//如果服務和 Consul 在同一臺伺服器上,使用此代碼
        var consulClient = new ConsulClient(x => x.Address = new Uri($"http://10.9.10.89:8500"));//請求註冊的 Consul 地址
        var httpCheck = new AgentServiceCheck()
        {
            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動多久後註冊
            Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔,或者稱為心跳間隔
            HTTP = $"http://{Program.IP}:{Program.Port}/health",//健康檢查地址
            Timeout = TimeSpan.FromSeconds(5)
        };

        // Register service with consul
        var registration = new AgentServiceRegistration()
        {
            Checks = new[] { httpCheck },
            ID = Guid.NewGuid().ToString(),
            Name = Program.ServiceName,
            Address = Program.IP,
            Port = Program.Port,
            Tags = new[] { $"urlprefix-/{Program.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 標簽,以便 Fabio 識別
        };

        consulClient.Agent.ServiceRegister(registration).Wait();//服務啟動時註冊,內部實現其實就是使用 Consul API 進行註冊(HttpClient發起)
        lifetime.ApplicationStopping.Register(() =>
        {
            consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服務停止時取消註冊
        });
        return app;
    }
}

Start.cs配置代碼:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
              ILoggerFactory loggerFactory, IApplicationLifetime lifetime)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMvc();
    app.RegisterWithConsul(lifetime);//here
}

Program.cs配置代碼:

public class Program
{
    public static string IP = "";
    public const int Port = 54917;
    public const string ServiceName = "hello-docker";
    public const string Version = "v1";

    public static void Main(string[] args)
    {
        //Program.IP = LocalIPAddress;//使用 Docker 的時候,獲取的是 IP 地址不正確,需要進行完善
        Program.IP = "10.9.10.190";//Docker 容器中的 IP 地址,如果使用 host 網路模式,也是主機的 IP 地址
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseUrls($"http://*:{Program.Port}")
            .UseStartup<Startup>()
            .Build();

    public static string LocalIPAddress
    {
        get
        {
            UnicastIPAddressInformation mostSuitableIp = null;
            var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

            foreach (var network in networkInterfaces)
            {
                if (network.OperationalStatus != OperationalStatus.Up)
                    continue;
                var properties = network.GetIPProperties();
                if (properties.GatewayAddresses.Count == 0)
                    continue;

                foreach (var address in properties.UnicastAddresses)
                {
                    if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                        continue;
                    if (IPAddress.IsLoopback(address.Address))
                        continue;
                    return address.Address.ToString();
                }
            }
            return mostSuitableIp != null
                ? mostSuitableIp.Address.ToString()
                : "";
        }
    }
}

健康檢查配置代碼:

[Route("[controller]")]
public class HealthController : Controller
{
    private static readonly HttpClient _httpClient;

    static HealthController()
    {
        _httpClient = new HttpClient();
    }

    [HttpGet]
    public IActionResult Get() => Ok("ok");

    //或者使用fabio進行健康檢查
    //[Route("")]
    //[HttpGet]
    //public async Task<HttpResponseMessage> GetWithFabio() => await _httpClient.GetAsync("http://127.0.0.1:9998/health");
}

4. 使用 Docker 發佈部署 ASP.NET Core 2.0 服務

我們需要在 ASP.NET Core 2.0 應用程式目錄下,添加一個Dockerfile文件,用來構建自定義鏡像(命令參考:使用 Dockerfile 定製鏡像),示例:

FROM microsoft/aspnetcore-build AS build-env
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# build runtime image
FROM microsoft/aspnetcore
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "HelloDocker.Web.dll"]

簡單來說,就是先使用microsoft/aspnetcore-build鏡像,還原程式包併發布,然後再使用microsoft/aspnetcore鏡像,運行 ASP.NET Core 2.0 應用程式。

構建鏡像命令:

$ docker build -t hello-docker:v1 .
Sending build context to Docker daemon  41.98kB
Step 1/10 : FROM microsoft/aspnetcore-build AS build-env
 ---> d6273f7c44d4
Step 2/10 : WORKDIR /app
 ---> e37f90cd9aaf
Removing intermediate container a4e4db93ea06
Step 3/10 : COPY *.csproj ./
 ---> 56278755f94c
Step 4/10 : RUN dotnet restore
 ---> Running in 3b7e8c5d01f4
  Restoring packages for /app/HelloDocker.Web.csproj...
  Restore completed in 411.99 ms for /app/HelloDocker.Web.csproj.
  Installing System.Security.Principal.Windows 4.4.0-preview1-25305-02.
  Installing Microsoft.NETCore.Platforms 2.0.0-preview1-25305-02.
  Installing System.Security.AccessControl 4.4.0-preview1-25305-02.
  Installing Microsoft.Win32.Registry 4.3.0.
  Installing System.Security.Permissions 4.4.0-preview1-25305-02.
  Installing System.Diagnostics.Process 4.3.0.
  Installing Newtonsoft.Json 10.0.2.
  Installing System.Net.Http.WinHttpHandler 4.0.0.
  Installing CoreCompat.System.Drawing.v2 5.2.0-preview1-r131.
  Installing System.Data.Common 4.3.0.
  Installing System.Security.Cryptography.Pkcs 4.3.0.
  Installing System.Xml.XPath.XmlDocument 4.3.0.
  Installing Pomelo.EntityFrameworkCore.MySql 2.0.0.
  Installing MySqlConnector 0.26.4.
  Installing Pomelo.JsonObject 1.1.1.
  Installing Consul 0.7.2.3.
  Installing EPPlus.Core 1.5.2.
  Generating MSBuild file /app/obj/HelloDocker.Web.csproj.nuget.g.props.
  Generating MSBuild file /app/obj/HelloDocker.Web.csproj.nuget.g.targets.
  Restore completed in 5.71 sec for /app/HelloDocker.Web.csproj.
 ---> cdf6ca65acf6
Removing intermediate container 3b7e8c5d01f4
Step 5/10 : COPY . ./
 ---> fffa81d15ddc
Step 6/10 : RUN dotnet publish -c Release -o out
 ---> Running in 291c8eea750f
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  HelloDocker.Web -> /app/bin/Release/netcoreapp2.0/HelloDocker.Web.dll
  HelloDocker.Web -> /app/out/
 ---> 078311772175
Removing intermediate container 291c8eea750f
Step 7/10 : FROM microsoft/aspnetcore
 ---> b97d3cf55223
Step 8/10 : WORKDIR /app
 ---> b0637e3d706b
Removing intermediate container 7095565fbbca
Step 9/10 : COPY --from=build-env /app/out .
 ---> c3cb8a708c4b
Step 10/10 : ENTRYPOINT dotnet HelloDocker.Web.dll
 ---> Running in d4111dc055f8
 ---> 29121f0eb2b0
Removing intermediate container d4111dc055f8
Successfully built 29121f0eb2b0
Successfully tagged hello-docker:v1

上面構建鏡像的過程,非常詳細,我們可以得到很多的信息,這邊就不敘述了,構建完鏡像之後,我們可以查看下是否成功:

$ docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
hello-docker                 v1                  29121f0eb2b0        Less than a second ago   284MB
<none>                       <none>              078311772175        Less than a second ago   1.9GB
microsoft/aspnetcore-build   latest              d6273f7c44d4        4 days ago          1.85GB
microsoft/aspnetcore         latest              b97d3cf55223        4 days ago          280MB
consul                       latest              dff07cab6abd        9 days ago          51.8MB
magiconair/fabio             latest              b0d96559369f        10 days ago         11.8MB

hello-docker下麵沒命名的鏡像,是臨時生成的,作用是使用microsoft/aspnetcore-build鏡像,還原程式包的時候,不需要重新安裝了。

另外,我們可以在 ASP.NET Core 2.0 應用程式目錄下,添加.dockerignore文件,來減少我們構建的鏡像文件大小,示例:

bin/*
obj/*

需要說明下,Consul 和 Fabio 我都是部署在虛擬機的 Docker 容器中,ASP.NET Core 2.0 應用程式,我打算運行在 Mac OS 系統中,也就是說服務和 Consul 是跨伺服器的。

運行命令:

$ docker run -d -p 54917:54917 --name hello-docker-web hello-docker:v1

查看下是否運行成功:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS                      NAMES
396d42f37185        hello-docker:v1        "dotnet Hello-Dock..."   Less than a second ago   Up 2 seconds        0.0.0.0:54917->54917/tcp   hello-docker-web

$ docker logs hello-docker-web
Hosting environment: Production
Content root path: /app
Now listening on: http://[::]:54917
Application started. Press Ctrl+C to shut down.

可以看到,運行是成功的。

我們可以請求驗證下:

$ curl http://10.9.10.190:54917/api/values
["value1","value2"]

或者使用 Fabio 的網關請求(Fabio 可以用作負載均衡):

$ curl http://10.9.10.89:9999/hello-docker/api/values
["value1","value2"]

我們可以查看 Consul UI 中的服務是否運行正常:

或者查看 Fabio UI 中的服務是否存在(通過健康檢查後會出現):

查看資料:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 配置環境: linux版本:Centos6.4 httpd版本: [root@centos64Study init.d]# pwd/etc/init.d[root@centos64Study init.d]# httpd -vServer version: Apache/2.2.15 (Unix)S ...
  • 最近又碰到一起Linux下SendMail發送郵件失敗的案例,郵件發送後,郵箱收不到具體郵件, 查看日誌/var/log/maillog 發現有"DSN: User unknown"以及“dsn=5.1.1, stat=User unknown”等錯誤信息,脫敏後的具體日誌如下所示: Nov 1 0... ...
  • 1. 首先查看自己的ubuntu系統的codename,這一步很重要,直接導致你更新的源是否對你的系統起效果,查看方法: lsb_release -a 如,我的系統顯示: Description: Ubuntu 17.04 Release: 17.04 Codename: zesty 2. 確認阿裡 ...
  • 這個是Linux下連接VFS文件系統框架和不同文件/文件系統底層實現之間的一個核心數據結構,雖然它只是一個指針,但是一個指針可以解決所有問題,有了它,媽媽再也不用擔心我的學習。我們回想一下用戶態線程的創建結構,函數的入口同樣是一個void*指針,而千言萬語彙成一根指針,詩可以興、可以觀、可以群、可以 ...
  • 遞歸時候每次調用自身在堆棧上要記錄返回地址,而堆棧的空間很少,調用次數多了後會產生堆棧溢出,以下代碼是實際項目中,通過Queue<T>來避免遞歸演算法的代碼: /// <summary> /// 獲取某個節點下特定屬性的所有子孫節點 /// </summary> /// <param name="gr ...
  • UNIT_PRICE :資料庫原先類型為: NUMBER(18,4) AMOUNT : 資料庫原先類型為: NUMBER(18,4) 如果直接進行修改會報錯,因為原先欄位中已經有數據了。 ALTER TABLE CLOUD_RELEASE.CONTRACT_PRODUCT_ITEM MODIFY(U ...
  • 我真的很喜歡在前端使用 Vue.js,Vue 服務端渲染直到第二個版本才被支持。 在本例中,我想展示如何將 Vue.js 2 服務端渲染功能整合 ASP.NET Core ...
  • 電商平臺和傳統店鋪相比,確實方便不少,直接在網上下單,快遞直接送貨到家。這其中,做電商平臺的童鞋表示壓力很大,因為可能同時開很多店鋪,每個店鋪都要登錄、查看訂單量、發貨揀貨等,非常辛苦。 多店鋪同時操作,需要打開很多瀏覽器,每個店鋪的帳號和密碼也要記清楚,腦子一定要夠用,不然就會頭暈腦漲。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...