架构图
1. 搭建服务发现与注册中心 (Consul)
#服务注册发现 (consul)
docker pull consul
docker run --rm -p 8500:8500 --name myconsul consul agent -server -client=0.0.0.0 -ui -bootstrap
2. 加一个微服务(Nodejs)
docker pull node:11-alpine
//var express = require("express")
var os = require("os")
var net = require('net')
var uuid= require("uuid")
var consul = require('consul')(
{
host: "192.168.56.102",
port: 8500
});
var servicename = "mynode"
const CONSUL_ID = require('uuid').v4();
const http = require('http');
const hostname = '0.0.0.0';
const port = 80;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, I am Nodejs service!\n' + req.url + "\r\n" + getIPAdress());
});
server.on('close', function () {
console.log(' Stopping ...');
consul.agent.service.deregister(servicename, function (err) {
if (err) throw err;
});
});
process.on('SIGINT', function () {
server.close();
});
function start(port) {
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
var option = {
name: servicename,
id: CONSUL_ID,
address: getIPAdress(),
port: port,
check: {
ttl: '10s',
deregister_critical_service_after: '10s'
}
};
consul.agent.service.register(option, function (err) {
err && log(err);
});
setInterval(() => {
consul.agent.check.pass({ id: `service:${CONSUL_ID}` }, err => {
if (err){
throw err;
}
log('told Consul that we are healthy');
});
}, 5 * 1000);
}
portIsOccupied(port, function (realport) {
start(realport);
});
function getIPAdress() {
let localIPAddress = "";
let interfaces = os.networkInterfaces();
for (let devName in interfaces) {
let iface = interfaces[devName];
for (let i = 0; i < iface.length; i++) {
let alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
localIPAddress = alias.address;
log(localIPAddress);
if(localIPAddress.indexOf("192.168.") >= 0){
return localIPAddress;
}
}
}
}
return localIPAddress;
}
function portIsOccupied(port, callback) {
var server2 = net.createServer();
server2.once('listening', function () {
server2.close();
log("local port is ok:" + port);
callback(port);
});
server2.once('error', function (err) {
//log(err);
//if (err.code === 'EADDRINUSE') {
port++;
log("local port is used, will try another:" + port);
portIsOccupied(port, callback);
});
log("testing local port: " + port);
server2.listen(port,'0.0.0.0');
}
function log(str) {
console.log(str);
}
同时开10个nodejs服务:
3. 加 Api 服务网关 (Nginx + Consul-Template)
FROM liberalman/nginx-consul-template
ADD nginx.service /etc/service/nginx/run
RUN chmod a+x /etc/service/nginx/run
ADD consul-template.service /etc/service/consul-template/run
RUN chmod a+x /etc/service/consul-template/run
RUN mkdir /data
#RUN rm -v /etc/nginx/conf.d/*
# ADD nginx.conf.ctmpl /etc/consul-templates/nginx.conf.ctmpl
ADD nginx.conf /data/nginx.conf
ADD app.conf.ctmpl /data/app.conf.ctmpl
ADD www /data/www
RUN chmod 777 /data
WORKDIR /data
RUN ls
ENTRYPOINT ["runsvdir", "/etc/service"]
#ENTRYPOINT ["sh","run.sh"]
#cd /D/git/mydocker/microService/nginx-consul-template
#docker build -t nginx-consul-template .
#docker run --rm -p 80:80 -it -e consul_server="192.168.56.102:8500" nginx-consul-template
{{range services}} {{$name := .Name}} {{$service := service .Name}}
upstream {{$name}} {
zone upstream-{{$name}} 64k;
{{range $service}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502{{end}}
} {{end}}
server {
listen 80 default_server;
location / {
root /data/www/;
index index.html;
}
location /stub_status {
stub_status;
}
{{range services}} {{$name := .Name}}
location /{{$name}} {
proxy_pass http://{{$name}};
}
{{end}}
}
4. 第二个微服务(SpringBoot)
docker pull java:8-jdk-alpine
server.port=8080
spring.application.name=Consul-Server-1
spring.cloud.consul.host=192.168.56.102
spring.cloud.consul.port=8500
spring.cloud.consul.enabled=true
spring.cloud.consul.discovery.enabled=true
spring.cloud.consul.discovery.instanceId=myJavaService
spring.cloud.consul.discovery.serviceName=myJavaService
spring.cloud.consul.discovery.hostname=192.168.56.111
spring.cloud.consul.discovery.port=8080
spring.cloud.consul.discovery.healthCheckUrl=http://192.168.56.111:8080/myJavaService/
spring.cloud.consul.discovery.healthCheckInterval=10s
spring.cloud.consul.discovery.tags=dev
5.第三个微服务(DotNetCore)
docker pull mcr.microsoft.com/dotnet/core/runtime:2.2-alpine
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace netcore
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
var client = new ConsulClient(ConfigurationOverview);
var id = "ServerName" + Guid.NewGuid();
var name = "myNetCoreService";
var ip = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
.Select(p => p.GetIPProperties())
.SelectMany(p => p.UnicastAddresses)
.Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address) && p.Address.ToString().Contains("192.168."))
.FirstOrDefault()?.Address.ToString();
var port = 80;
var tcpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10),
Interval = TimeSpan.FromSeconds(10),
TCP = $"{ip}:{port}"
};
Console.WriteLine("TCP check : " + tcpCheck.TCP);
// var httpcheck = new AgentServiceCheck
// {
// DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10),
// Interval = TimeSpan.FromSeconds(5),
// HTTP = $"https://{ip}:{port}/myNetCoreService/values",
// Timeout = TimeSpan.FromSeconds(5)
// };
client.Agent.ServiceRegister(new AgentServiceRegistration()
{
ID = id,
Name = name,
Address = ip,
Port = port,
Checks = new[] { tcpCheck }
});
}
private static void ConfigurationOverview(ConsulClientConfiguration obj)
{
var consul_server = Environment.GetEnvironmentVariable("consul_server");//"http://192.168.56.108:8500"
Console.WriteLine("sonsul_server is: [" + consul_server + "]");
obj.Address = new Uri(consul_server);
//obj.Datacenter = "dc1";
}
}
}