Docker & Consul & Fabio & ASP.NET Core 2.0 微服务跨平台实践

简介:

相关博文:

阅读目录:

  • 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 中的服务是否存在(通过健康检查后会出现):






本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/ubuntu-docker-consul-fabio-aspnet-core.html,如需转载请自行联系原作者

相关文章
|
6月前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
2110 10
|
5月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
501 6
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
422 5
|
9月前
|
存储 缓存
.NET 6中Startup.cs文件注入本地缓存策略与服务生命周期管理实践:AddTransient, AddScoped, AddSingleton。
记住,选择正确的服务生命周期并妥善管理它们是至关重要的,因为它们直接影响你的应用程序的性能和行为。就像一个成功的建筑工地,工具箱如果整理得当,工具选择和使用得当,工地的整体效率将会大大提高。
328 0
|
11月前
|
Cloud Native Serverless 流计算
云原生时代的应用架构演进:从微服务到 Serverless 的阿里云实践
云原生技术正重塑企业数字化转型路径。阿里云作为亚太领先云服务商,提供完整云原生产品矩阵:容器服务ACK优化启动速度与镜像分发效率;MSE微服务引擎保障高可用性;ASM服务网格降低资源消耗;函数计算FC突破冷启动瓶颈;SAE重新定义PaaS边界;PolarDB数据库实现存储计算分离;DataWorks简化数据湖构建;Flink实时计算助力风控系统。这些技术已在多行业落地,推动效率提升与商业模式创新,助力企业在数字化浪潮中占据先机。
577 12
|
监控 Kubernetes Cloud Native
基于阿里云容器服务Kubernetes版(ACK)的微服务架构设计与实践
本文介绍了如何基于阿里云容器服务Kubernetes版(ACK)设计和实现微服务架构。首先概述了微服务架构的优势与挑战,如模块化、可扩展性及技术多样性。接着详细描述了ACK的核心功能,包括集群管理、应用管理、网络与安全、监控与日志等。在设计基于ACK的微服务架构时,需考虑服务拆分、通信、发现与负载均衡、配置管理、监控与日志以及CI/CD等方面。通过一个电商应用案例,展示了用户服务、商品服务、订单服务和支付服务的具体部署步骤。最后总结了ACK为微服务架构提供的强大支持,帮助应对各种挑战,构建高效可靠的云原生应用。
|
搜索推荐 NoSQL Java
微服务架构设计与实践:用Spring Cloud实现抖音的推荐系统
本文基于Spring Cloud实现了一个简化的抖音推荐系统,涵盖用户行为管理、视频资源管理、个性化推荐和实时数据处理四大核心功能。通过Eureka进行服务注册与发现,使用Feign实现服务间调用,并借助Redis缓存用户画像,Kafka传递用户行为数据。文章详细介绍了项目搭建、服务创建及配置过程,包括用户服务、视频服务、推荐服务和数据处理服务的开发步骤。最后,通过业务测试验证了系统的功能,并引入Resilience4j实现服务降级,确保系统在部分服务故障时仍能正常运行。此示例旨在帮助读者理解微服务架构的设计思路与实践方法。
852 17
|
消息中间件 运维 安全
后端开发中的微服务架构实践与挑战####
在数字化转型的浪潮中,微服务架构凭借其高度的灵活性和可扩展性,成为众多企业重构后端系统的首选方案。本文将深入探讨微服务的核心概念、设计原则、关键技术选型及在实际项目实施过程中面临的挑战与解决方案,旨在为开发者提供一套实用的微服务架构落地指南。我们将从理论框架出发,逐步深入至技术细节,最终通过案例分析,揭示如何在复杂业务场景下有效应用微服务,提升系统的整体性能与稳定性。 ####
291 32
|
运维 监控 Java
后端开发中的微服务架构实践与挑战####
在数字化转型加速的今天,微服务架构凭借其高度的灵活性、可扩展性和可维护性,成为众多企业后端系统构建的首选方案。本文深入探讨了微服务架构的核心概念、实施步骤、关键技术考量以及面临的主要挑战,旨在为开发者提供一份实用的实践指南。通过案例分析,揭示微服务在实际项目中的应用效果,并针对常见问题提出解决策略,帮助读者更好地理解和应对微服务架构带来的复杂性与机遇。 ####
|
监控 Cloud Native Java
基于阿里云容器服务(ACK)的微服务架构设计与实践
本文介绍如何利用阿里云容器服务Kubernetes版(ACK)构建高可用、可扩展的微服务架构。通过电商平台案例,展示基于Java(Spring Boot)、Docker、Nacos等技术的开发、容器化、部署流程,涵盖服务注册、API网关、监控日志及性能优化实践,帮助企业实现云原生转型。