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

故事背景

公司是做电商业务的,在天猫有几家旗舰店数据量也很大。阿里有一个称为聚石塔的平台,专门给这些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的运行状态以及端口映射,都没问题,又查看端口监听和防火墙,还是正常,二脸懵逼。

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

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

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

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

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

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

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

  

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

yum remove docker*rebootyum install dockerdocker versionsystemctl start docker

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

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

再进坑

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

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

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

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

这个路由表有个奇怪的现象,就是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端口,成功了!!!终于看到了熟悉的页面:

没那么简单

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

果然是报错了:

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

FROM microsoft/dotnet:2.1-runtimeCOPY . /appWORKDIR /appEXPOSE 5000 80ENTRYPOINT ["dotnet", "DRP.API.dll"]

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

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

修改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 bridge0ip 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即可。

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

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

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

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

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

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

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

除此之外,从前任留下的文档里可以知道,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 

.NetCoreLinuxDockerPortainer踩坑历险记相关推荐

  1. 群晖从windows迁移到esxi+直通踩坑历险记

    前言 以下坑虽然不代表每个人都会碰到,但至少我碰到了,相信很多跟我一样实用主义的同学只要可以绕路,都不会愿意再去碰一次.另外,部分坑我没有解决,有些是绕过了,有些当前不是主要矛盾,因此如果有能解决的同 ...

  2. 【golang程序包推荐分享】分享亿点点golang json操作及myJsonMarshal程序包开发的踩坑经历 :)

    目录[阅读时间:约5分钟] 一.概述 1.Json的作用 2.Go官方 encoding/json 包 3. golang json的主要操作 二.Json Marshal:将数据编码成json字符串 ...

  3. java调用clang编译的so_写Java这么久,JDK源码编译过没?编译JDK源码踩坑纪实

    好奇害死羊 很多小伙伴们做Java开发,天天写Java代码,肯定离不开Java基础环境:JDK,毕竟我们写好的Java代码也是跑在JVM虚拟机上. 一般来说,我们学Java之前,第一步就是安装JDK环 ...

  4. python导入类有红线_python踩坑系列之导入包时下划红线及报错“No module named”问题...

    python踩坑系列之导入包时下划红线及报错"No module named"问题 使用pycharm编写Python时,自己写了一个包(commontool),在同级另一个路径下 ...

  5. mysql运维工资_MySQL运维踩坑

    image ZERO 背景 本文主要是介绍在MySQL使用运维过程中所遇到的一些坑爹的地方,予自己以做记录! 前言 因操作系统重装之后,安装了mysql5.7,而由此带来了一系列的问题,现将解决这些m ...

  6. 微信跳一跳高分辅助踩坑

    旧博文,搬到 csdn 原文:http://rebootcat.com/2018/01/08/wechat_jump_hack/ 最近挺火的微信跳一跳 最近新版微信的『跳一跳』小程序着实火了一把,也把 ...

  7. 【踩坑记录】记一次MySQL主从复制延迟的坑

    最近开发中遇到的一个MySQL主从延迟的坑,记录并总结,避免再次犯同样的错误. 情景 一个活动信息需要审批,审批之后才能生效.因为之后活动要编辑,编辑后也可能触发审批,审批中展示的是编辑前的活动内容, ...

  8. 分布式深度学习最佳入门(踩坑)指南

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者丨Lyon@知乎(已授权) 来源丨https://zhuanla ...

  9. python array赋值_从踩坑学Python内部原理(5):执行时机的差异

    (给Python开发者加星标,提升Python技能) 英文:Satwik Kansal,翻译:暮晨 Python开发者整理自 GitHub [导读]:Python 是一个设计优美的解释型高级语言,它提 ...

最新文章

  1. SVO: 视觉SLAM中特征点法与直接法结合
  2. git错误“无法推送一些引用到xxx“的解决方法
  3. LiteOS内核源码分析:消息队列Queue
  4. Flex3与BlazeDS HelloWorld 详解
  5. 在SharePoint Server 2007中创建定制的用户管理模块
  6. Java学完哪些内容能够出去找工作
  7. 敏捷开发(Agile)
  8. 深度揭秘安全领域的那些“大牛” 竟过半在360
  9. Pray for 京阿尼——愿逝者安息,伤者早日康复
  10. MyApps平台为政企数据保驾护航,筑牢办公安全防线
  11. 阿里90后运营的工作总结,细致而深刻!
  12. c# 屏幕取词的方法
  13. STM32驱动NRF24L01
  14. python证书过期_简单python脚本监控SSL证书到期提醒
  15. 弘辽科技:如何获取淘宝推广链接?有哪些推广方法?
  16. 故事,零落,,,,,
  17. 板子ping不通主机
  18. 第四十一章 贪心算法——排序不等式
  19. 阿里P8架构师深度概述分布式架构
  20. EffectiveJava读书笔记01

热门文章

  1. 如何使自己的不和谐机器人
  2. 如何使用wink框架_如何解决Wink Hub的Z-Wave连接问题
  3. android页面布局 如何让中间的listview填充剩余部分_谷歌驾驶设计—界面设计布局...
  4. Windows 7 自动更新失败导致无法进系统解决方案
  5. 99. Recover Binary Search Tree
  6. 搭建 vue2 单元测试环境(karma+mocha+webpack3)
  7. python之新式类与经典类
  8. QT中VideoProbe的简介和实现
  9. MySQL - Found option without preceding group in config file
  10. window server2008 r2