.NetCoreLinuxDockerPortainer踩坑历险记

最近有一个云服务器和数据库的迁移任务,踩坑爬坑无数次,觉得必须要记录一下。大家瓜子花生准备好,听我慢慢讲故事#手动笑哭#。

故事背景

公司是做电商业务的,在天猫有几家旗舰店数据量也很大。阿里有一个称为聚石塔的平台,专门给这些ISV提供各种云资源,强制绑定了一些业务,原本我们在聚石塔中有一台ECS和一台RDS部署在华东杭州节点,本月初突然收到阿里的邮件说是要整体迁移到张北节点,华东节点将会在9月底全部停止服务,并附带发了一份迁移文档,要我们尽快迁移。好在我们用到的资源不多,最初觉得迁移过程并不会太复杂,实际还是太天真了。像我这样只有一台服务器和一台数据库的用户迁移过程都谓之艰辛,对于那些有几十甚至上百实例的ISV,那真是欲哭无泪了。每天看着迁移群里大家的各种吐槽、抱怨、焦急、无可奈何,还有那几位一整天都在被艾特的阿里技术支持,说起来都是泪。

于是接下来制定好迁移计划,发邮件购买要用到的资源,等过了两天东西到位,就撸起袖子开干了。

忘了说了,这些东西原先是由另外一位同事负责,然而年后他就开溜了,上级指示我扛过大旗(guo)。

开胃菜

我们的RDS是SQL Server 08 R2版本,阿里在迁移通知中专门提到了这个产品,而且用到了重要提示字样,大意是说微软已经对这个版本的数据库停止了安全更新,所以张北节点已经不再售卖这个版本的实例,要先在当前节点完成版本升级后再迁移。看了下他的迁移手册,觉得异常复杂和危险重重,于是果断放弃官方方案,决定在张北节点买好2016版本数据库,直接切换数据推送,后来找阿里的技术支持咨询了这个方案,也表示可以执行。当然了,我能这样做是有一个前提的,我们的这个库是只读库,用来接收阿里的数据推送然后给业务系统查询,可以理解为只是一个过渡不存储实际的业务数据,对安全性要求不高,就算丢失也能通过淘宝开放平台的API去查询。如果是业务库,那就只能老老实实的按官方文档摸着石头过河了,看群里的反馈,这道开胃菜不好吃,我也算是幸运跳过了第一个坑。

初进坑

RDS处理完毕,那就着手开始折腾服务器,这是一台Linux的机器,系统是Centos7,主要跑了3个服务:上文提到的RDS数据查询API(一个dotnetcore2.1的程序)、Rabbitmq实例和它的管理工具、Portainer,由Docker统一管理,而Docker又由Portainer来管理。按照官方文档,先在原服务器上创建镜像,经过漫长的等待(大概40分钟吧,有的人反映等了大半天最后生成失败的,心态崩…),然后把镜像复制到张北节点,然后通过镜像生成实例,按理说新机器和原机器是完全一样的,各项服务都应该运行正常,并且专门找技术支持确认了,可实际真的不是这样。

聚石塔的服务器只开放30001-30005这几个端口,于是尝试访问一下Portainer所在的30003端口。浏览器输入地址再回车,等了几十秒后显示超时无法访问,一脸懵逼。Ping了一下服务器IP,没毛病,又登录服务器查看docker和container的运行状态以及端口映射,都没问题,又查看端口监听和防火墙,还是正常,二脸懵逼。

640?wx_fmt=png

查一下container的日志,提示运行正常,三脸懵逼。

640?wx_fmt=png

我的招已经用完了,没办法转向群里咨询技术支持,回复说这几个端口要走工单申请开通,WTF……老实写工单提交再到群里艾特帮忙快点处理,又陷入漫长的等待中,当时大概2点钟的样子。下午5点多工单状态更新了说正在转给技术处理请耐心等待,然后,就没有然后了接着等,到7点还是没消息决定先下班。

第二天上班发现还是没有消息,又去群里艾特技术支持,几分钟后回复叫我去给ECS绑定一个安全组,照做后再次访问30003端口依然不行,长叹一口气。又尝试访问了一下webapi所在的30001端口,神奇般的成功了#手动黑人问号脸#。咨询了公司运维,教我几个命令简单排查了下,后来因为太忙没回复我了,后来又一顿百度谷歌无果,陷入僵局。心理暗自把这个锅丢给了阿里,觉得是他们哪里配置有问题。

640?wx_fmt=gif

事情不能就这样僵着啊,Portainer起不来程序不能更新,于是打算直接在宿主机上跑一下修改后的dotnetcore程序看数据库访问是否正常。按照微软文档安装对应版本的SDK:

640?wx_fmt=png

安装好后把发布文件上传到服务器,然后用dotnet命令启动了程序,一切正常。访问我的测试入口:

Curl http://locahost:5000/api/values/testdb/123

看到返回了数据库的测试数据,信心重拾。回过头重新折腾docker,发现docker死活起不来了,囧:

640?wx_fmt=png

640?wx_fmt=png

  640?wx_fmt=png

拿着错误信息又是一顿百度谷歌,不断的照网上改配置重启系统,几个小时过去依然不行,决定卸载docker重装。于是依次执行:

yum remove docker*
reboot
yum install docker
docker version
systemctl start docker

然而启动的时候问题依旧,又是长叹一口气。仔细回想了一下,只有yum update对系统做了大的改动,难道是这个问题么?不知不觉又到了晚上7点多,脑子懵的很决定先下班第二天接着搞。

真所谓一波未平一波又起。

再进坑

早上到公司和微信群的小伙伴吐糟着遭遇,大家劝我重装系统,我一边发着捂脸笑哭的表情,一边默默地上聚石塔后台点了磁盘初始化,docker启动不了的问题就算翻篇了,一切从头再来。

依然还是端口的问题,实在没辙了只有给阿里提工单问为什么端口不通,阿里工程师先后叫我排查了iptables、端口监听情况、清除iptables等等还是不行,最后要了我的服务器账号上去排查,在工单中看到阿里的工程师晚上11点多还在帮我排查问题,也真不容易。

640?wx_fmt=png

终于,在阿里后面的回复中事情迎来了转机,给了我非常大的提示:

640?wx_fmt=png

从中我捕捉到了2个重要信息,一个是容器的IP,一个是路由解析问题。我马上百度如何查容器的IP地址,然后试着去ping容器的IP,发现30001端口绑定的容器(172.22.0网段)正常,30003端口绑定的容器(192.168.0网段)无法访问,那么这就说明是宿主机和容器网络不通导致的问题。又查看了系统的路由表:

640?wx_fmt=png

这个路由表有个奇怪的现象,就是192.168.0这个网段指向了2个不同的网卡,分别是eth0和docker0。我知道,eth0是宿主机默认的网关,docker0是docker启动时自动创建的虚拟网关,但是还不清楚这样的配置会有什么影响,于是百度了一下Linux路由的详细介绍,得知相同的配置会有优先级的问题,又尝试着删除eth0的配置:

1

route del -net 192.168.0.0 netmask 255.255.255.0

再次用公网访问30003端口,成功了!!!终于看到了熟悉的页面:

640?wx_fmt=png

没那么简单

以为事情就此告一段落后面都是平坦大道,想不到问题又来了。通过docker run我新镜像后发现容器总是自动退出,于是寻找各种让容器持续运行的办法,一阵折腾没有效果,去微信群问小伙伴,问我是不是程序抛异常了,我顿时一种柳暗花明的感觉,立马查看容器日志:

果然是报错了:

640?wx_fmt=png

很显然,是说我的framework版本不对,但是我的dockerfile中确实引入的2.1版本运行时:

FROM microsoft/dotnet:2.1-runtime
COPY . /app
WORKDIR /app
EXPOSE 5000 80
ENTRYPOINT ["dotnet", "DRP.API.dll"]

退一万步说,宿主机我也已经安装过SDK,而且直接在宿主机上运行都是可以的,为什么通过docker来运行就挂了,百思不得解。只能按照提示中的信息排查是不是少装了什么组件,一阵yum install下来还是失败:

640?wx_fmt=png

去广州微软.net俱乐部的微信群请教别人,两位大佬给我分析解答了一下,一位说是我的dockerfile在copy文件时漏了一些引用文件,要我重新修改dockerfile,不过经过多次调整测试依然无效,不得不采用第二位的办法,就是把运行时改为2.2版本:

640?wx_fmt=png

修改dockerfile为如下内容:

# 添加基础镜像
FROM microsoft/dotnet:2.2-aspnetcore-runtime

#容器中系统的工作空间
WORKDIR /app

#拷贝当前文件夹下的文件到容器中系统的工作空间
COPY . /app

#设置Docker容器对外暴露的端口
EXPOSE 5000 80

#运行应用程序
ENTRYPOINT ["dotnet", "DRP.API.dll"]

重新打包镜像,然后run起来,这次一切都是那么的自然,docker ps查看容器已经状态是up了。欣喜若狂,以为即将看到胜利的曙光,接着用浏览器打开我的测试入口:

http://xxx.xxx.xxx.xxx:30001/api/values/testdb/123

尴尬的报了500,心中万马奔腾….

这次学机灵了,第一时间docker logs,发现是数据库报错了:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
=> ConnectionId:0HLM4DDINAGJC => RequestId:0HLM4DDINAGJC:00000001 RequestPath:/api/values/testdb/123
Connection id
"0HLM4DDINAGJC", Request id "0HLM4DDINAGJC:00000001": An unhandled exception was thrown by the application.
SqlSugar.UtilExceptions: English Message : Connection open error . A network
-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)
Chinese Message : 连接数据库过程中发生错误,检查服务器是否正常连接字符串是否正确,实在找不到原因请先Google错误信息:A network
-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server).
at SqlSugar.AdoProvider.GetDataReader(String sql, SugarParameter[] parameters)
at SqlSugar.QueryableProvider`
1.GetData[TResult](KeyValuePair`2 sqlObj)
at SqlSugar.QueryableProvider`
1._ToList[TResult]()

很明显是数据库连接不上,检查连接字符串,没毛病,再次进入僵局。

正在苦恼时,突然想起前面删掉的那条路由,尝试重启网络恢复路由:

再次访问测试地址,确实成功了。可问题又进入了死循环,容器内的应用无法访问。

终见天日

经过以上的种种分析后,最终把问题定在了路由这儿。既然是因为同一网段有2个网关,那么我修改一下docker的默认网段不就可以了吗?再次面向百度编程,得到两种方案:

第一种方案,创建新的的网关和路由,然后分配给docker:

service docker stop

ip addr add
192.168.1.1/24 dev bridge0
ip link set dev bridge0 up

vim
/etc/docker/daemon.json

加上"bridge": "bridge0"节点并保存退出,再重启docker:

第二种方案,直接修改docker0的默认网段:

service docker stop

vim
/etc/docker/daemon.json

加上"bip": "192.168.1.1/24"节点并保存退出,再重启docker即可。

我这里采用第二种方式,修改后的路由表为:

640?wx_fmt=png

重新访问各种服务,全部都正常运行,到此总算是拨开云雾见青天。

有个小细节不知大家是否发现,也是我当时存在的一个疑惑,就是前面有提过两个容器的网段不一样,按理说通过docker run来的容器应该都是相同的网段,为什么会这样呢?后来在折腾Portainer的时候找到了这个问题。

Portainer是一款docker管理工具,简而言之的说就是把用命令操作的东西可视化,当然功能远不止这些。Portainer中有一个Stack功能,我并不清楚这是干什么用的,只是看到旧的Portainer中的容器绑定了一个stack所以想依葫芦画瓢也搞一个:

640?wx_fmt=png

于是拿stack的配置文件新创建一个,没想到居然报错,提示已存在相同名称的容器。我马上意识到这个特殊的容器应该是通过stack创建,我删掉已存在的容器再次创建stack,这次成功了。出于好奇,仔细分析了stack的配置文件:

640?wx_fmt=png

发现里面主要是定义了镜像名、容器名、网络模式、端口映射这些,而其中vhnet这个网络配置让我很感兴趣,转而查看docker已经配置好的网关:

640?wx_fmt=png

看到这里,一种恍然大悟的感觉,你懂的。

除此之外,从前任留下的文档里可以知道,stack有一种类似热更新的功能,修改配置文件中的镜像名后update stack就能实现对应的容器更新,不用起新的容器,这点确实很不错。更多强大的功能日后也会慢慢学习。

我的收获

经过前面几天的折腾,我更加熟悉了docker的各种基本操作和配置,也学会了使用新的命令,像docker inspect查看容器信息、docker attach进入容器内部,也加深了在Linux上排查问题的思路理解,学到了新的操作命令。也实际使用docker在Linux上部署了一次dotnetcore的生产环境,收获颇丰。

遗留的问题

1、     yum update后到底经历了什么让docker跪地不起,报错原因至今没搞明白。

2、    为什么2.1的dotnetcore程序在2.1运行时跑不起来,换成2.2版本就可以。

3、stack是怎么实现修改镜像后容器就能生效的呢?

有知道的大佬还请多多指导。

总结

表面上全篇都在讲才踩坑的事,但追根究底还是因为自己在Linux方面的知识欠缺和经验不足。还是那句话,多踩坑,会让你记忆深刻,会让你学到意想不到的东西,会让你的身体变得足够大,下次碰到坑能一脚踏过去。

原文地址:https://www.cnblogs.com/hohoa/p/10743552.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 
640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

F - Parenthesis Checking

​​​​​​​1 . ( - > 1 , ) - > -1; 先想前缀和,求出l,r中的最小值,如果最小值小于l-1的前缀和,那么说明有某个点的 ) 大于 ( 数量 不满足条件; 用线段树优化区间修改和区间查询; 2 . …

cf208E. Blood Cousins

cf208E. Blood Cousins 题意: 给你一个森林,m次询问,每次询问(v,p),问v的p-cousin有多少?p-cousin指的是与v在同一层且他们到lca的距离都是p 题解: 对于每次询问(v,p),我们都可以通过其找到v的p距离的父亲节点fa&a…

深入源码理解.NET Core中Startup的注册及运行

开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程序的起点。通过使用Startup,可以配置化处理所有向应用程序所做的请求的管道,同时也可以减少.NET应用程序对单一服务器的依赖性,使我们…

并查集虚拟节点

​ HDU 3234 Exclusive-OR AC代码简洁版 AC代码不好看的 Almost Union-Find UVA - 11987 AC代码 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <sstream> using namespace std; typedef long …

cf246E. Blood Cousins Return

cf246E. Blood Cousins Return 题意&#xff1a; 给你一个森林&#xff0c;每个点都有自己的种类&#xff0c;问以v为根节点的子树中&#xff0c;与v距离为k的节点有多少种 题解&#xff1a; 和cf208E. Blood Cousins这个题差不多&#xff0c;就是多了一个种类&#xff0c;…

Python、Java、TypeScript 和 Perl 作者谈语言设计

Python 作者 Guido van Rossum、Java 作者 James Gosling、Turbo Pascal 和 TypeScript 作者 Anders Hejlsberg&#xff0c;以及 Perl 作者 Larry Wall 本月早些时候齐聚一堂&#xff0c;讨论了(YouTube)编程语言设计的过去和未来。Guido van Rossum 说&#xff0c;设计一种语言…

线段树+树状数组

感觉这东西就是每棵线段树管的区间变了&#xff0c;以前学的时候线段树总是只管一个点或者管&#xff08;1-i&#xff09;这些点&#xff0c;但是这东西如果加上树状数组的思想&#xff0c;每棵线段树管&#xff08; i-(i&-i)1 ~ i &#xff09;这些区间&#xff0c;那么动…

cf1009F. Dominant Indices

cf1009F. Dominant Indices 题意&#xff1a; 1号节点为根&#xff0c;问对于以每个点为根的子树种&#xff0c;求某个深度节点最多的层数。如果多个相等&#xff0c;输出深度小的。 题解&#xff1a; 直接dsu就完事了&#xff0c;相当于是求子树的众数&#xff0c;但是注意…

Asp.Net Core Web应用程序—探索

前言作为一个Windows系统下的开发者&#xff0c;我对于Core的使用机会几乎为0&#xff0c;但是考虑到微软的战略规划&#xff0c;我觉得&#xff0c;Core还是有先了解起来的必要。因为&#xff0c;目前微软已经搞出了两个框架了&#xff0c;一个是Net标准(.NetFramework)&#…

智能优化算法应用:基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.跳蛛算法4.实验参数设定5.算法结果6.参考文献7.MA…

Transformation HDU - 4578

思路&#xff1a;三种改变的顺序&#xff0c;先变 后乘 再 加。 #include <iostream> #include <algorithm> #include <cstring> #include <sstream> using namespace std; typedef long long LL; const int N 5e5 4, mod 1e4 7; int n, m;struct…

cf375D. Tree and Queries

cf375D. Tree and Queries 题意&#xff1a; 给你一颗有根树&#xff0c;每个点都有一个颜色&#xff0c;有m次询问&#xff0c;问以u为根的子树中&#xff0c;相同颜色数量超过k的有多少种颜色&#xff1f; 题解&#xff1a; 这个题做法很多&#xff0c;有莫队分块&#x…

让你的ASP.NET Core应用程序更安全

对于ASP.NET Core应用程序&#xff0c;除了提供认证和授权机制来保证服务的安全性&#xff0c;还需要考虑下面的一些安全因素&#xff1a;CSRF强制HTTPS安全的HTTP HeadersCSRFASP.NET Core通过AntiForgeryToken来阻止CSRF攻击&#xff0c;一般来说&#xff0c;当用户做表单提交…

201409-5 拼图

七十分超时代码&#xff0c;具体思路可以仿照acwing蒙德里安的梦想 就是枚举第i层放 a &#xff0c;第i-1层放b的合法方案其中b和a都是同一块&#xff1b; #include <iostream> #include <algorithm> #include <cstring> #include <sstream> using nam…

.net core 中间件管道底层剖析

.net core 管道&#xff08;Pipeline&#xff09;是什么&#xff1f;由上图可以看出&#xff0c;.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程&#xff0c;如果我们简化一下成下图来看的话&#xff0c;.net core 的管道其实就是中间件的部分。微软中…

Codeforces Round #741 (Div. 2)

Codeforces Round #741 (Div. 2) 题号题目知识点AThe Miracle and the SleeperBScenes From a MemoryCRingsD1Two Hundred Twenty One (easy version)D2Two Hundred Twenty One (hard version)ERescue Niwen!FTubular Bells

201609-5 祭坛

超时暴力60分 #include <iostream> #include <algorithm> #include <cstring> #include <sstream> using namespace std; typedef long long LL; const int N 5e5 4, mod 1e9 7;vector<int> v[N]; int y[N], sizy, x[N], sizx, numx[N], a[…

cf1562E. Rescue Niwen!

cf1562E. Rescue Niwen! 题意&#xff1a; 我们定义一个字符串s1s2s3…sn的展开为:s1,s1s2,s1s2…sn,s2,s2s3,s2s3…sn,…,sn 找到字符串s“扩展”的最大递增子序列的大小(根据字典序大小比较) 题解&#xff1a; 第一感觉就是求最长上升子序列的变形 按照字典序大小比较规则…

架构为什么要以领域为核心

很久以前, 人们以为地球是太阳系的中心.然后一位聪明人, 哥白尼, 他改变了我们对太阳系的看法. 他认为太阳是太阳系的中心:这是对太阳更好的一个解释, 更简单也更具说服力. 事实上, 以太阳为中心的模型确实是更优雅的.上面这件事也发生在软件开发里. 下面这个就是很多开发者惯用…

201403-5 任务调度

哇&#xff0c;ccf csp认证考试 历年真题解&#xff08;一本书&#xff09;真厉害。 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring>using namespace std;typedef long long LL; typedef pair<int,int> PII; con…