commit c1e3aae62dcd8e09562d94eca99cd6a276b06db0 Author: don Date: Tue Feb 23 11:35:52 2021 +0800 first commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb10010 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.user +*.suo +.vs/ +*.log +obj/ +bin/ +.idea/ +.vscode/ \ No newline at end of file diff --git a/AmqpTest.sln b/AmqpTest.sln new file mode 100644 index 0000000..ced0123 --- /dev/null +++ b/AmqpTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31005.135 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AmqpTest", "AmqpTest\AmqpTest.csproj", "{305F4286-AD47-48F4-89DD-395A5B05801C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {305F4286-AD47-48F4-89DD-395A5B05801C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {305F4286-AD47-48F4-89DD-395A5B05801C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {305F4286-AD47-48F4-89DD-395A5B05801C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {305F4286-AD47-48F4-89DD-395A5B05801C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C5E935C3-96EC-425E-AAB8-D9409563B328} + EndGlobalSection +EndGlobal diff --git a/AmqpTest/Amqp/AmqpSubscribe.cs b/AmqpTest/Amqp/AmqpSubscribe.cs new file mode 100644 index 0000000..f9ed129 --- /dev/null +++ b/AmqpTest/Amqp/AmqpSubscribe.cs @@ -0,0 +1,177 @@ +using Amqp; +using Amqp.Framing; +using Amqp.Sasl; +using AmqpTest.Configs; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace AmqpTest.Amqp +{ + /// + /// 用于处理阿里云平台amqp消息队列的数据(负责接收) + /// + public class AmqpSubscribe + { + private readonly ILogger _logger; + private readonly IotConfig _configIot; + + public AmqpSubscribe(ILogger logger, IOptions optConfigIot) + { + _logger = logger; + _configIot = optConfigIot.Value; + } + + /// + /// 开始接收iot平台amqp推送的数据 + /// + /// + public async Task BeginListen() + { + try + { + long timestamp = GetCurrentMilliseconds(); + string param = "authId=" + _configIot.AccessKey + "×tamp=" + timestamp; + string password = DoSign(param, _configIot.AccessSecret, "HmacMD5"); + string iotInstanceId = !string.IsNullOrEmpty(_configIot.IotInstanceId) ? "iotInstanceId=" + _configIot.IotInstanceId + "," : ""; + + string username = _configIot.ClientId + "|" + iotInstanceId + "authMode=aksign,signMethod=hmacmd5,consumerGroupId=" + _configIot.ConsumerGroupId + + ",authId=" + _configIot.AccessKey + ",timestamp=" + timestamp + "|"; + + await DoConnectAmqpAsync(username, password); + } + catch (Exception ex) + { + _logger.LogError($"BeginListen 处理AMQP数据发生异常 {ex.Message}\n{ex.StackTrace}"); + } + } + + /// + /// 获取当前时间的时间戳 + /// + /// + private long GetCurrentMilliseconds() + { + DateTime dt1970 = new DateTime(1970, 1, 1); + DateTime current = DateTime.Now; + return (long)(current - dt1970).TotalMilliseconds; + } + + public string DoSign(string param, string accessSecret, string signMethod) + { + byte[] key = Encoding.UTF8.GetBytes(accessSecret); + byte[] signContent = Encoding.UTF8.GetBytes(param); + var hmac = new HMACMD5(key); + byte[] hashBytes = hmac.ComputeHash(signContent); + return Convert.ToBase64String(hashBytes); + } + + private async Task DoConnectAmqpAsync(string username, string password) + { + string host = $"{_configIot.Uid}.iot-amqp.{_configIot.RegionId}.aliyuncs.com"; + int port = Convert.ToInt32(_configIot.Port); + + var address = new Address(host, port, username, password); + //Create Connection + ConnectionFactory cf = new ConnectionFactory(); + //use local tls if neccessary + //cf.SSL.ClientCertificates.Add(GetCert()); + //cf.SSL.RemoteCertificateValidationCallback = ValidateServerCertificate; + cf.SASL.Profile = SaslProfile.External; + cf.AMQP.IdleTimeout = 120000; + cf.AMQP.ContainerId = "client.1.2"; + cf.AMQP.HostName = "contoso.com"; + cf.AMQP.MaxFrameSize = 8 * 1024; + + var connection = await cf.CreateAsync(address); + if (connection.ConnectionState.Equals(ConnectionState.OpenSent)) + { + _logger.LogInformation("Open frame was received."); + } + //Connection Exception Closed + connection.AddClosedCallback(ConnClosed); + + //Receive Message + await DoReceiveAsync(connection); + } + + private async Task DoReceiveAsync(Connection connection) + { + var session = new Session(connection); + var receiver = new ReceiverLink(session, "queueName", null); + _logger.LogInformation("开始接收设备信息!"); + int maxCount = Convert.ToInt32(_configIot.MaxDegreeOfParallelism); + //LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(maxCount); + //TaskFactory taskFactory = new TaskFactory(lcts); + + try + { + int count = 0; + var sw = new Stopwatch(); + sw.Start(); + //var tasks = new List(); + //receiver.SetCredit(10000, false); + + //只是控制该线程不退出 + while (true) + { + receiver.Start(100, (link, message) => + { + var messageId = message.ApplicationProperties["messageId"].ToString(); + var topic = message.ApplicationProperties["topic"].ToString(); + var body = Encoding.UTF8.GetString((byte[])message.Body); + + link.Accept(message); + + _logger.LogInformation($"message arrived, topic= {topic}, messageId= {messageId}, body= {body}"); + count++; + }); + + + //var message = await receiver.ReceiveAsync(new TimeSpan(0, 0, 5)); + //if (message != null) + //{ + // var messageId = message.ApplicationProperties["messageId"].ToString(); + // var topic = message.ApplicationProperties["topic"].ToString(); + // var body = Encoding.UTF8.GetString((byte[])message.Body); + + // _logger.LogInformation($"message arrived, topic= {topic}, messageId= {messageId}, body= {body}"); + + // receiver.Accept(message); + + // count++; + //} + + + if (sw.ElapsedMilliseconds > 60000) + { + _logger.LogWarning($"约1分钟处理 {count} 个请求"); + sw.Restart(); + count = 0; + } + + await Task.Delay(100).ConfigureAwait(false); //睡眠值用于控制计时的准确性,和iot消息处理效率无关 + } + } + catch (Exception) + { + throw; + } + finally + { + connection?.Close(); + } + } + + private void ConnClosed(IAmqpObject _, Error e) + { + _logger.LogError($"连接关闭:{e?.ToString()}"); + } + } +} diff --git a/AmqpTest/AmqpTest.csproj b/AmqpTest/AmqpTest.csproj new file mode 100644 index 0000000..bdfd545 --- /dev/null +++ b/AmqpTest/AmqpTest.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + dotnet-AmqpTest-E73E3A37-DF5F-44BE-A32D-9A5FF9DA0BD9 + Linux + + + + + + + + + + + + + + diff --git a/AmqpTest/Configs/IotConfig.cs b/AmqpTest/Configs/IotConfig.cs new file mode 100644 index 0000000..5435fbf --- /dev/null +++ b/AmqpTest/Configs/IotConfig.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AmqpTest.Configs +{ + /// + /// IOTConfig配置模板类 + /// + public class IotConfig + { + public string AccessKey { get; set; } + public string AccessSecret { get; set; } + public string IotInstanceId { get; set; } + public string ConsumerGroupId { get; set; } + public string RegionId { get; set; } + public string ProductKey { get; set; } + public string Uid { get; set; } + public string ClientId { get; set; } + public string Port { get; set; } + public string ReconnectionTime { get; set; } + public string MaxDegreeOfParallelism { get; set; } + public string SmsSignName { get; set; } + } +} diff --git a/AmqpTest/Dockerfile b/AmqpTest/Dockerfile new file mode 100644 index 0000000..513ef89 --- /dev/null +++ b/AmqpTest/Dockerfile @@ -0,0 +1,24 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +WORKDIR /src +COPY ["AmqpTest/AmqpTest.csproj", "AmqpTest/"] +RUN dotnet restore "AmqpTest/AmqpTest.csproj" +COPY . . +WORKDIR "/src/AmqpTest" +RUN dotnet build "AmqpTest.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "AmqpTest.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENV environment=Development +ENV TimeZone=Asia/Shanghai +ENV LANG C.UTF-8 +RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone +ENTRYPOINT dotnet AmqpTest.dll --environment=$environment \ No newline at end of file diff --git a/AmqpTest/Logs/ThreadInfoEnricher.cs b/AmqpTest/Logs/ThreadInfoEnricher.cs new file mode 100644 index 0000000..0c02da2 --- /dev/null +++ b/AmqpTest/Logs/ThreadInfoEnricher.cs @@ -0,0 +1,30 @@ +using Serilog; +using Serilog.Configuration; +using Serilog.Core; +using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace AmqpTest.Logs +{ + public class ThreadInfoEnricher : ILogEventEnricher + { + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + + logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Thread.CurrentThread.ManagedThreadId)); + } + } + + public static class EnricherExtensions + { + public static LoggerConfiguration WithThreadInfo(this LoggerEnrichmentConfiguration enrich) + { + if (enrich == null) + throw new ArgumentNullException(nameof(enrich)); + return enrich.With(); + } + } +} diff --git a/AmqpTest/Program.cs b/AmqpTest/Program.cs new file mode 100644 index 0000000..b3c3ccd --- /dev/null +++ b/AmqpTest/Program.cs @@ -0,0 +1,72 @@ +using AmqpTest.Configs; +using AmqpTest.Logs; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace AmqpTest +{ + public class Program + { + public Program(IConfiguration configuration) + { + Configuration = configuration; + } + + public static IConfiguration Configuration { get; set; } + + public static void Main(string[] args) + { + //ѡļappsetting.json + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .Build(); + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(config).Enrich.WithThreadInfo() + .CreateLogger(); + + try + { + Log.Information("Starting up"); + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "Application start-up failed"); + } + finally + { + Log.CloseAndFlush(); + } + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .UseSerilog() + .ConfigureServices((hostContext, services) => + { + var configuration = hostContext.Configuration; + services.Configure(configuration.GetSection("IOTConfig")); + + JsonSerializerSettings setting = new JsonSerializerSettings(); + JsonConvert.DefaultSettings = () => + { + setting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + setting.ContractResolver = new CamelCasePropertyNamesContractResolver(); + setting.NullValueHandling = new NullValueHandling(); + + return setting; + }; + }); + } +} + diff --git a/AmqpTest/Properties/launchSettings.json b/AmqpTest/Properties/launchSettings.json new file mode 100644 index 0000000..2a0f023 --- /dev/null +++ b/AmqpTest/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "AmqpTest": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/AmqpTest/Worker.cs b/AmqpTest/Worker.cs new file mode 100644 index 0000000..436f055 --- /dev/null +++ b/AmqpTest/Worker.cs @@ -0,0 +1,51 @@ +using AmqpTest.Amqp; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AmqpTest +{ + public class Worker : BackgroundService + { + private readonly ILogger _logger; + private readonly AmqpSubscribe _subscribe; + + public Worker(ILogger logger, AmqpSubscribe subscribe) + { + _logger = logger; + _subscribe = subscribe; + + } + + public override Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("------StartAsync"); + + return base.StartAsync(cancellationToken); + } + + public override Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("------StopAsync"); + + return base.StopAsync(cancellationToken); + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + _logger.LogInformation("------ExecuteAsync"); + + await _subscribe.BeginListen(); + + _logger.LogWarning("밢AMQPӽ30룬Ȼ..."); + await Task.Delay(30000, stoppingToken); + } + } + } +} diff --git a/AmqpTest/appsettings.Development.json b/AmqpTest/appsettings.Development.json new file mode 100644 index 0000000..e93fc83 --- /dev/null +++ b/AmqpTest/appsettings.Development.json @@ -0,0 +1,17 @@ +{ + "AllowedHosts": "*", + "IOTConfig": { + "AccessKey": "LTAI4FdXhwy1evoHXingMaiZ", + "AccessSecret": "CGmGpzta6ro8Bta4RLiQD18EF8m6Bm", + "iotInstanceId": "", //iot-cn-nif1vosz501 + "ConsumerGroupId": "SKb6q4caxeXfRGQFiLO6000100", // "hJBxHrxY51jZVhu6cCsQ000100", //"8GwMMBJUWz5PWaW0jtb6000100", + "RegionId": "cn-shanghai", + "ProductKey": "a18mXM6Cvx8", + "UId": "1111649216405698", + "clientId": "gateway", + "Port": "5671", + "ReconnectionTime": "10000", + "MaxDegreeOfParallelism": "8", + "SmsSignName": "随手精灵" + } +} diff --git a/AmqpTest/appsettings.debug.json b/AmqpTest/appsettings.debug.json new file mode 100644 index 0000000..a18b619 --- /dev/null +++ b/AmqpTest/appsettings.debug.json @@ -0,0 +1,17 @@ +{ + "AllowedHosts": "*", + "IOTConfig": { + "AccessKey": "LTAI4FdXhwy1evoHXingMaiZ", + "AccessSecret": "CGmGpzta6ro8Bta4RLiQD18EF8m6Bm", + "iotInstanceId": "iot-cn-nif1vosz501", + "ConsumerGroupId": "0ZQFQv0QreC7WALTEWad000100", //"bbQdnXQJIx2eCDjVbCIZ000100", // "hJBxHrxY51jZVhu6cCsQ000100", //"8GwMMBJUWz5PWaW0jtb6000100", + "RegionId": "cn-shanghai", + "ProductKey": "a18mXM6Cvx8", + "UId": "1111649216405698", + "clientId": "gateway", + "Port": "5671", + "ReconnectionTime": "10000", + "MaxDegreeOfParallelism": "8", + "SmsSignName": "随手精灵" + } +} diff --git a/AmqpTest/appsettings.json b/AmqpTest/appsettings.json new file mode 100644 index 0000000..66ee715 --- /dev/null +++ b/AmqpTest/appsettings.json @@ -0,0 +1,68 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "Serilog": { + "Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Async", "Serilog.Sinks.Console" ], + "MinimumLevel": { + "Default": "Verbose", + "Override": { + "Microsoft": "Warning", + "HttpClient": "Information" + } + }, + "WriteTo:Information": { + "Name": "Async", + "Args": { + "Configure": [ + { + "Name": "File", + "Args": { + "RestrictedToMinimumLevel": "Information", + "RollingInterval": "Day", + "RollOnFileSizeLimit": "true", + "OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] {Message:lj}{NewLine}{Exception}", + "Path": "/var/amqp/logs/infos/info.log", + "RetainedFileCountLimit": 7 // "--设置日志文件个数最大值,默认31,意思就是只保留最近的31个日志文件", "等于null时永远保留文件": null + // "FileSizeLimitBytes": 20971520, //设置单个文件大小为3M 默认1G + // "RollOnFileSizeLimit": true //超过文件大小后创建新的 + + } + } + ] + } + }, + "WriteTo:Error": { + "Name": "Async", + "Args": { + "Configure": [ + { + "Name": "File", + "Args": { + "RestrictedToMinimumLevel": "Error", + "RollingInterval": "Day", + "RollOnFileSizeLimit": "true", + "OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss }[{Level:u3}] [Thread-{ThreadId}][{SourceContext:l}] {Message:lj}{NewLine}{Exception}", + "Path": "/var/amqp/logs/errors/error.log", + "RetainedFileCountLimit": 15 // "--设置日志文件个数最大值,默认31,意思就是只保留最近的31个日志文件", "等于null时永远保留文件": null + // "FileSizeLimitBytes": 20971520, //设置单个文件大小为3M 默认1G + // "RollOnFileSizeLimit": true //超过文件大小后创建新的 + } + } + ] + } + }, + "WriteTo:Console": { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Verbose", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] {Message:lj}{NewLine}{Exception}", + "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console" + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/amqp_test_run.sh b/amqp_test_run.sh new file mode 100644 index 0000000..0a0e683 --- /dev/null +++ b/amqp_test_run.sh @@ -0,0 +1,29 @@ +#!/bin/bash +environment=$1 +version=$2 +echo "环境变量为${environment},版本为$version!" +if [[ ${environment} == 'production' ]]; then + echo "开始远程构建容器" + docker stop gps_gateway || true + docker rm gps_gateway || true + docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/gps_card/gps_gateway | awk '{print $3}') + #docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com + docker login --username=telpo_fengjj@1111649216405698 --password=PWDaliyun123 registry.cn-shanghai.aliyuncs.com + docker pull registry.cn-shanghai.aliyuncs.com/gps_card/gps_gateway:$version + docker run -d -e environment=production -v /home/data/gps_gateway/log:/var/gateway/logs --restart=always --name gps_gateway registry.cn-shanghai.aliyuncs.com/gps_card/gps_gateway:$version; + #删除产生的None镜像 + docker rmi -f $(docker images | grep none | awk '{print $3}') + docker ps -a + +elif [[ ${environment} == 'test' ]]; then + echo "开始在测试环境远程构建容器" + docker stop gps_gateway || true + docker rm gps_gateway || true + docker rmi -f $(docker images | grep 139.224.254.18:5000/gps_gateway | awk '{print $3}') + docker pull 139.224.254.18:5000/gps_gateway:$version + docker run -d -e environment=test -v /home/data/gps_gateway/log:/var/gateway/logs --restart=always --name gps_gateway 139.224.254.18:5000/gps_gateway:$version; + #删除产生的None镜像 + docker rmi -f $(docker images | grep none | awk '{print $3}') + docker ps -a + +fi \ No newline at end of file diff --git a/setup_development.sh b/setup_development.sh new file mode 100644 index 0000000..1353561 --- /dev/null +++ b/setup_development.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +image_version=`date +%Y%m%d%H%M`; + +docker stop amqp_test || true; +docker rm amqp_test || true; +# ɾ +docker rmi -f $(docker images | grep telpo/amqp_test | awk '{print $3}') + +docker build -f ./AmqpTest/Dockerfile . -t telpo/amqp_test:$image_version; +# +docker run -d -e environment=Development -v /home/data/amqp_test/log:/var/amqp/logs --name amqp_test telpo/amqp_test:$image_version; +#ɾNone +docker rmi -f $(docker images | grep none | awk '{print $3}') +# 鿴б +docker images; +# 鿴־ +docker logs amqp_test; diff --git a/setup_test.sh b/setup_test.sh new file mode 100644 index 0000000..1ce582f --- /dev/null +++ b/setup_test.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +image_version=$version +# 删除镜像 +docker rmi -f $( + docker images | grep 139.224.254.18:5000/amqp_test | awk '{print $3}' +) +# 构建telpo/mrp:$image_version镜像 +docker build -f ./AmqpTest/Dockerfile . -t telpo/amqp_test:$image_version +#TODO:推送镜像到私有仓库 +echo '=================开始推送镜像=======================' +docker tag telpo/amqp_test:$image_version 139.224.254.18:5000/amqp_test:$image_version +docker push 139.224.254.18:5000/amqp_test:$image_version +echo '=================推送镜像完成=======================' +#删除产生的None镜像 +docker rmi -f $(docker images | grep none | awk '{print $3}') +# 查看镜像列表 +docker images \ No newline at end of file