一、为什么将 Oracle 部署在 docker容器中

我们首先通过 docker 安装了 oracle11g 版本的 Oracle 数据库——不要问我为什么通过 docker 安装数据库,正确做法或者说更合理的做做法不是应该在物理机或者虚拟机上安装数据库吗?

关于以上两个问题,第一个问题的答案是,通过其它方式真的太难了,具体可以参见我的这篇文章:Oracle数据库的安装

第二个问题,你可以去问度娘,可以这么搜素:数据库为什么不适合容器化部署。

二、Oracle 在 docker 容器 中部署情况简介

关于 docker 和 Oracle 容器的主要情况如下:

1.Oracle 的版本是 Oracle11g;

2.创建 Oracle 容器时的命令如下:

docker run -d –p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g

3.以后启动 Oracle 的命令如下:

docker start oracle11g

4.每次虚拟机重启或者挂起后重启,数据库就连接失败。

三、操作情况说明

针对 二 中讲到的情况,下面我们一一说明。

第一点,版本说明,毋庸多言;

第二点,我们做了宿主机和 docker 容器的端口映射,参数是 -p 1521:1521;

第三点,在启动 docker 容器后,直接使用第三条的命令启动oracle11g,这是在Linux端进行的启动,而非docker中。

关于这一点,我们看到很多创建容器、启动应用的命令都是docker run这个命令,关于这个命令我们讲两句,首先说它的基本语法:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

参数如下:

  • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

  • -d: 后台运行容器,并返回容器ID;

  • -i: 以交互模式运行容器,通常与 -t 同时使用;

  • -P: 随机端口映射,容器内部端口随机映射到主机的端口

  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

  • --name="nginx-lb": 为容器指定一个名称;

  • --dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

  • --dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

  • -h "mars": 指定容器的hostname;

  • -e username="ritchie": 设置环境变量;

  • --env-file=[]: 从指定文件读入环境变量;

  • --cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;

  • -m :设置容器使用内存最大值;

  • --net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;

  • --link=[]: 添加链接到另一个容器;

  • --expose=[]: 开放一个端口或一组端口;

  • --volume , -v: 绑定一个卷

其实主要使用的也就那么几个:

  • -d: 后台运行容器,并返回容器ID

  • -i: 以交互模式运行容器,通常与 -t 同时使用

  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用

  • --name="nginx-lb": 为容器指定一个名称

  • -h "mars": 指定容器的hostname

 举例如下:

docker run -it --name mysql -p 3306:3306 -h localhost -d 镜像名

解析:以交互式方式运行新增一个伪终端,将该镜像命名为mysql,并将docker的3306端口和宿主机的33306端口做了映射,指定docker的主机名为localhost,最终以后台方式运行,而非独占方式。

其中-p还可以加上ip,比如:127.0.0.1:80:8080,意思是将docker的8080端口映射到宿主机的127.0.0.1的ip的80端口上。

第四点,就是我们上面这几点操作导致的错误。

四、问题分析

回到 二 中的 2 ,我们创建容器的时候,没有指定docker的主机名,导致的结果就是我们的docker的主机名就是我们的oracle11g的镜像id,简短版的镜像id。

下面是我虚拟机重启后进入docker容器后查看的我们的主机名:

 上图一共有6个红框,我们一一进行说明:

1.Oracle11g的默认用户名,也是我们docker启动Oracle后的用户名;

2.docker中的主机名,这个和Linux中的是一致;

3和4,是我们docker中将172.17.0.3这个ip和15d2eb5b4766这个镜像id做的ip和镜像绑定,类似于linux的ip和域名绑定;

5.我们docker的主机名;

6.网卡情况,其中5和6刚开始都是15d2eb5b4766,后来我们修改过5的值为localhost,但是重启后又变回去了,6的就是修改后的值。

情况说完了,再说下另一个,就是我们 二 中的 3 。我们是通过 docker start 的方式启动的Oracle,而非 docker run的方式,导致的结果就是我们 二 中提到的 4 ,也就是每次重启或挂起并启动虚拟机后数据库连接失败。

个人分析的原因是这样的:

我们初次创建容器并启动容器的时候,也就是执行docker run命令的时候没有指定docker的主机,导致的结果就是每次启动这个Oracle11g容器的时候,由于没有指定docker的主机名,它就默认使用了镜像的id作为主机名。所以就出现了数据库连接失败的情况。

但是这里我有个疑问,如果我们启动多个容器呢?比如一个是Oracle,一个是tomcat,那这个主机名会是什么呢?不能又是Oracle镜像的id又是tomcat的镜像id吧?

这样是不是感觉就和我上面说的矛盾了呢?具体情况我也不是很清楚,这里暂且留个疑问吧!

五、解决方案

说了问题情况,原因分析,下面我们说说解决方案,没有解决方案的问题,纯属耍流氓啊!

我也是在无意这种找到了这个解决方案。通过数据库连接的报错信息,说是网络连接失败,然后问度娘,当然是没有找到答案的,或者是不适合我的这个问题。其中找到一个说是主机域名与ip映射的问题,当然这个说的是在linux连接的时候,而不是通过容器,而且将的也不是数据库连接。但是我感觉可能是这个问题,因为我刚开始的时候数据库连接是好的,过了一天我再开机后就失败了。所以猜测可能是这个原因,通过查看虚拟机和docker的这三个文件发现了问题,可能真的是这个原因。

/etc/hosts
/etc/hostname
/etc/sysconfig/network

分别在linux和docker查看这三个文件,发现了问题。在linux中,三个文件都有localhost的配置;而在docker中,如 四 中的图所示,/etc/hostname和/etc/sysconfig/network的值都是15d2eb5b4766这个Oracle11g的镜像id。修改成localhost之后,数据库果然连接上了。

至此,问题叙述完毕,解决方案也给了,貌似已经很完美了,实际上,发现坑才刚刚开始。

本来以为问题都解决了,等又过了一天,虚拟机当然重启了,发现又连接失败了,我尼玛什么情况,什么鬼啊!本来解决这个问题废了牛鼻子劲,解决了之后又出问题?当时解决的时候其实都不是很确信能不能行,一通乱改的都是,凭感觉了,当然这个也是基于一定经验的。现在又连接失败了,就猜测可能还是那个问题,就返现了docker的/etc/hostname的值又变回去了。这把/etc/hosts的172.17.0.3也改成了我们宿主机的ip,当时不清楚是什么情况,后来才知道,这个是docker分配的ip,一般和宿主机是不一样的,也就是说这个不能修改的。

当然,这么一通乱改,连接自然是失败的,因为已经不记得前一天到底是怎么修改的,最后不停地尝试,才发现了是/etc/hostname的主机名恢复了默认值的缘故。

而且,还有一点,你这个docker的/etc/hostname修改后的主机名,个人感觉要和你的linux的主机名保持一致,也就是说,如果你的Linux的宿主机的主机名是什么,你docker就要修改成什么。不过这一点,我不确信。就是为了告诉大家,如果你的宿主机的主机名不是localhost的时候,要怎么修改,遇到我这种问题的话,起码有个参考依据,知道我这么修改的原理,以及怎么去适配你的情况。

之所以这里啰嗦这么几句,就是因为,很多人的文章:

一、他不经过验证,很可能就是抄袭的,或者直接copy的,更有甚者,直接copy一个链接,屁话不说,这种的真恶心。更恶心的是,有不少这样的文章,阅读量贼高,可能真应了那句话,先到先得,再加上,阅读的越多,百度或者CSDN推荐的就越靠前,最后导致的结果就是,哪怕这篇文章狗屁不通你那个,但是也一样给你排在 最前面。

二、有些人的文章,也真的是自己写的,但是基本的环境什么的都不说,甚至自己的操作都说的稀烂,导致的结果就是别人用的时候,如果和他的基本一直可能没问题,但凡是什么地方不一致,结果就要了亲命了。就比如我为什么在docker中安装Oracle,而不是在linux也不是在Windows中安装,问题当然很多,但是我看了不少文章,尝试了多次,就是因为他们的linux系统要么就是centos 7的,要不就是8的,而我的是centOS 8-Stream的,差异还是很大的,结果就是安装失败。这个不能说他们的文章有问题,而是环境差异比较大,当然这个他们也不用交待环境的问题,他们可能也不知道。但是有一些的还是交待清楚比较好。

到了这里其实问题还没有真正解决,因为每次虚拟机重启后,它又会重置。我也懒得管它了,机器就一直开着吧,反正也是在自己家里。如果是公司的话,公司自然又配置好的。但是从学习的角度来说纠结清楚也是比较好的,但是我这里没有太多时间搞这个了,就先到这里。

其实我还有一种方案,那就是以后不要通过docker start oracle11g的方式启动,而是通过docker run 的命令启动,然后加上-h参数,指定docker的主机名,这样应该是可以的,不过我没有尝试,暂且存疑吧!

结论:

最终我们得出的解决方案如下:

1.每次修改docker的 /etc/hostname 这个文件,取值为localhost——应该是需要和你的宿主机的主机名一致。

2.通过docker run命令指定docker的主机名进行启动——未经过验证,不确定,个人感觉是可以的。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐