首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

通过填坑来学习 Docker

是的,都8102年了,我才开始接触 docker。

原由

为什么想要学习 docker 呢?首要原因当然是冲着 docker 的各种优点,其中最吸引我的就是简化部署,真可谓是「一次构建,四处部署」。

之前朋友一直在怂恿我使用 docker,当时在和他合作一个网站,后期出现一个需求是增加一个 简单的 CMS,而且是个非常急的需求,我觉得这东西连开发带测试没有三五天肯定搞不定,但是他却在一个晚上就搞定了,用的就是 WordPress + Docker。

接下来肯定要接受一个小程序的服务端的开发,回想起来以前每次部署的种种麻烦,我决定未雨绸缪,先把这个 docker 搞定再说,于是我就花了五天专门研究,资质愚钝的我这才多多少少会使用这个神器了。

学习过程

学习一门技术,不能是看看就完了,像我以前对各种东西都是走马观花看一遍,但是不怎么上手,所以基本什么也没记住,当然也没什么收获。现在每次接触一个新东西,我都是给自己定一个小目标,就是用这个新东西做出一个小玩意儿,这样才是对自己有个交代。所以学习 docker 给自己定下的目标就是搞一套 Node.js + MySQL 的容器实例。

可能已经掌握 docker 的人会说,这不简单吗,不就是两行命令行的事吗。没错,学会了之后确实觉得很简单。但是一开始作为小白的我还是有点儿懵的,走了点弯路,而且又犯了典型的学生式思维错误。

一开始自然是通过官网的教程,一行行照着敲(典型的学生式学习方法)。而且在一开始的几天我都是在 Linode VPS 上实战 docker 的,由于你懂的原因,Linode 有时不太稳定。Linode 还有一个关于 Docker 的小坑,那就是我在看的官方教程的 Part 3 时,部署多个 service 的副本总是死活不成功,没有一个 service 可以正常工作,经过一番搜索,最后确诊是 Linode 的内核和 Docker 不太兼容,在 Linode 的控制台修改内核就解决了。

就在我过了一遍官网的教程,并且看了一遍《Docker - 从入门到实践》后,我对各种概念和操作都有了一些了解,我终于忍受不了 VPS 上敲一个字符还要等上半天的体验了(其实国外的 VPS 还有一个好处,那就是用官方的 hub 也能速度飞起,你懂的),于是就在自己的电脑上装了 Docker for Mac(我也不知道自己脑袋一开始是怎么想的)。

因为自己的需求是搞一个最简单的 Web 开发容器,所以 swarm 和 machine 都是我用不上的,就没有深入研究。然而一开始因为囫囵吞枣,我连 Dockerfile 和 docker-compose.yml 这两个文件的区别是什么都搞不清楚。

Dockerfile 是用来创建 image 的

docker-compose.yml 是用来组合 image 的

后来自己一遍遍敲各种命令,理解各种参数,各种 SO + Google,终于算是理解了个七七八八。

Express.js Practice

官网给的 Node.js 例子是 Sails.js,我也尝试看了一遍官网这个教程和 Sails.js 的官网介绍,但是这个教程是很久之前的了,用目前版本的 Docker 有些例子是无法运行的。而且 Sails.js 这个框架好像用的人也不是太多,资料特别少,也想过尝试用一下 Koa 或者其他框架,但是想着这次实践的主要目的是为了学习 Docker 的用法而不是学习一门新的框架,所以最后就决定使用最熟悉的 Express.js 了。

其实创建 Express 的 image 十分简单,网上有着无数的 blog 都有写。这里我只想说一点,就是 Dockerfile 中有很多人在使用 WORKDIR 命令前都会创建 app 所需的根目录,可能以前必须这样吧,但是现在的 Docker(v18.03)只需 WORKDIR 这一个命令就行了,如果目录不存在会自动创建的,这样构建 image 时就减少了一层 layer。

下面是我的 Dockerfile:

上面的 entrypoint.sh 是启动脚本,会在 docker-compose.yml 中用到。而 knex 是用来迁移数据库的,这个后面会提到,我遇到了一个好几天都没搞定的大坑。

MySQL Practice

MySQL 我没有自己写一个 image,就用的官方的 image。Docker 容器的特点是停止运行后,所有产生的数据都会被清空,就像内存断电一样,所以必须要搭载一个数据卷(volume)才可以使用。关于数据存储,Docker 有三种方式,分别是 volume、mount 和 tmpfs。关于这三种方式的差异和特点我就不赘述了,而我的容器用到了前两种。volume 用来存表数据,mount 用来加载启动脚本。下面就是创建 MySQL 容器的命令,不过这个命令只是用来了解各个参数以及测试效果,最后我是用 docker-compose.yml 来创建容器的。

Docker 官方对于挂载推荐的命令是,而不是,但是网上有很多旧的资料还都是使用,这两者在大多数情况下可以通过语法互相转换,不过在 service 中使用 volume 的话必须使用。上面的命令中第一个是挂载一个 volume,而第二个是加载一个 mysql 的启动脚本。关于这个启动脚本官方有详细的介绍,既可以加载一个文件也可以加载一个文件夹中的所有文件,只要是放到 /docker-entrypoint-initdb.d 中即可。还有一点是我使用的 image 是 mysql 5.7,并不是最新的 8.x,不知道为什么,我的 Sequel Pro 死活连不上 8.x 的容器。

Docker Compose Practice

好了,web 和 db 两个容器都搞定了,接下来就是组合到一起。写 compose 文件我先是参考了许多 blog 中的例子,但是最后还回归官方文档了,因为 blog 中的例子版本不一而且有许多都是旧版本的。举几个例子:

基本上10个里面8个都会用到 ,但是官方现在已经不推荐使用了。

的 long syntax 只有 v3.2 才支持。

在 v3 后就不支持 了。一开始我想等 mysql 容器的 healthycheck 满足条件后再启动 web app,但是这在 v3 中就无法通过 compose 的文件语法做到了(通过第三方脚本倒是可以)。

所以许多别人写的 docker-compose.yml 的具体内容还要对照官网的最新版介绍来进行取舍(我个人是喜欢用最新版)。

因为数据库的表需要初始化和迁移,一开始我参照了一个 SO 中的做法,就是增加一个 service 专门用来做 initialization 和 migration,就像下面这样:

但是 knex 执行的结果是无法连接到数据库……而用 Sequel Pro 是可以连接到的,于是我就开始了漫长的探索,为了这个大坑,我前前后后花了三天多(其实是三个上午,每天也就两个小时),做了以下种种尝试:

各种修改 knexfile 和 mysql 的端口(其实很接近真相了)

去掉 migration 这一个 service ,直接在 web app 的 service 中执行 knex

以为是没等到 myqsl 容器完全启动就执行 knex,修改了 entrypoint.sh,但还是不行

进入到 web 容器里执行 knex,还是失败

后来我发现 knex 的 repo 中有这么一个 issue(url 在下面参考资料),就是我遇到的这个问题,发帖的小哥觉得是 knex 的问题,但是开发者坚信不是 knex 的问题,而且 close 了这个 issue,但是提出者小哥不依不饶继续解释,还说会继续研究,但是到现在也没有回复。最后一个回复者其实给出了解决方法,但是没说原因是什么。我继续搜了一些资料,终于让我找到了原因:docker 的容器是一个个相互独立隔离的系统,包括网络,所以 knexfile 中如果 host 设置的是 localhost 或者 0.0.0.0 其实指向的是容器本身而不是宿主。更多的解释可以去看我在 issue 下的回复。

最后附上我的 docker-compose.yml:

结语

docker 初体验到此可以收工了,当然还有很多可以优化和改进的地方,但我还是等到真正开发的时候再去研究吧,毕竟真实的需求和自己模拟的需求还是差很多的。而且 docker 还有很多特性我还没用到,我个人感觉就像一大箱子新玩具一样等着我去挖掘。

参考资料

Docker 官网

《Docker - 从入门到实践》

Developing and Testing Microservices with Docker

https://medium.com/@niratattri/building-a-node-js-application-and-deploying-through-docker-meet-docker-aa8ae677ea12

https://github.com/tgriesser/knex/issues/1939

https://hub.docker.com/r/mysql/mysql-server/

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180602G0JH8B00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券