开篇

提起 Docker,有很多人第一印象会认为它就是一个虚拟化容器,所以大家特别容易陷入到一种误区,就是觉得 Docker 只是在 Linux 操作系统之上又增加了一层,就跟 OS 上跑了一个 VMWare 一样。Docker 一定变得又慢又复杂。还不如原生安装的服务看起来舒服。

实际上这是误区,Docker 管理的各种服务,都是操作系统原生的进程,并不是一个虚拟化产物,它的正确定义是应用容器引擎。

那怎么去理解这个应用容器引擎呢?就要说说 Docker 的核心原理了——其中主要机制之一,通过 Linux 的 namespace 机制实现了资源隔离,这个资源隔离就包括了:

  1. UTS,对主机名和域名的隔离
  2. IPC,对信号量、消息队列和共享内存的隔离
  3. PID,对进程编号的隔离
  4. Network,对网络设备、网络协议栈、网络端口对隔离
  5. Mount,对挂载点(文件系统)的隔离
  6. User,对用户和用户组的隔离。

这些隔离机制都是 Linux 内核的 namespace 机制实现,也是 Docker 容器设计的精髓。

就好像原来是一个 300 平米的大 house,就住着一家人,卧室、厨房、卫生间这一家人独享。可是房子太大完全可以住三个家庭,不仅能公摊一部分费用,还能为主家带来额外的收益。那么就要对这个大 house 重新进行规划设计,满足三个家庭的需要,制定一些生活制度,有些资源是可以共享的,但关键资源就必须隔离开,保护隐私嘛!其实大家说到底还是在一个大房子内平等的生活。

用了这个比喻其实就是告诉大家,你就把 Docker 理解为一个房子多个家庭的规划安排包租婆,Docker 管理了很多的容器服务,容器服务就是在宿主机上跑着的,例如 MySQL、Nginx、微服务等等都是容器服务,大家都是在一个 OS 上平等的运行着,只不过进了自己房间,你对别人房间的情况就一无所知了。那么这不仅保护了各个服务之间不会产生对资源争用,而且还能根据预先入户的协议,分配好 CPU、内存、磁盘的容量。这样大家住在一起也是明明白白的,谁也不能沾了谁的便宜。当然了对外的网络端口还是需要各家分配不同的。

有了这个本事,你就能在有限的云资源上跑很多服务啦!我自己做的公司网站跑在阿里云的 ECS CentOS7,就跑了三个 Docker 容器:Nginx、MySQL、Wordpress,我才给分配了 512M 内存,够抠门吧,但是运行地妥妥的,只是物理内存是在太小,有时候重启服务,OS 报内存资源就不够了,必须把 Docker 也重启,清空一下内存就好了。

我给当时老东家的两个互联网平台产品用了三台 ECS 性能不错的服务器,4 核,16G 内存,足足跑了 50 多个微服务和其他基础服务,真的是把资源榨得是干干净净。关键还有服务日志隔离、环境变量隔离、全局配置隔离等待,好处实在太多了。关键对我们产品在互联网架构上的 Devops 提供了良好的基础支撑,我可以在一台虚拟机上跑两套微服务,一套生产、一套测试,测试好的微服务升级版本号,变成新的生产微服务,老的微服务进入过渡替换期。详见:构建互联网医疗平台的云端 Devops 应用架构

问题集锦

1. Docker 必须联网吗?

连接互联网不是必要的。可以内部搭建 Docker Registry 服务。我曾经就是在阿里云的多台机器的其中一台做了 Registry 服务,然后让其他机器通过内网的 5000 端口访问就可以了,记得给每台服务器的 docker 服务都配置一下都不走 SSL。

我们也只有远程发布才让自己的开发客户端,访问 Nginx 的 HTTP SSL 端口,反向代理到 Registry 仓库,那么就需要在服务端装一个 Docker 版的 nginx,因为公网尽量走 HTTPS。如下图所示:

关于内网怎么装 Docker 的问题,你需要先找一个能上网的机器,通过 docker hub 做好你自己的 Docker images,最好会 dockfile 怎么做,这是个脚本技术,主要有一些本地化和参数优化需要再做一下 Docker images,然后 Docker push 到内网私有 register 服务仓库就可以了,其他内网机器只要 Docker pull 命令,就可以使用你制作的 Docker images 了。

windows 系统下开发,就下载安装 windows 的 Docker desktop 使用和 mac 版本一样。

2. Docker 里面的程序如何实现热更新?

用 Dockerfile 构建一个镜像,并生成了一个容器来运行程序,现在程序代码发生了变更,想要实现热更新如何实现呢?

一般 Docker 更新的方式,都是 pull 下来新的 images,然后重启容器,当然也有一些讨巧的办法,通过对 Docker 内的发布程序目录镜像到本地目录,那么每次只上传程序包,更新服务器本地目录之后再进行 Docker 重启,这种方式免去了 Docker 体量太大,上传慢的问题。

但是这些都需要重启容器,不算真正意义上的热更新,在线业务系统往往允许的抖动时长会很严苛,而且即便是 Docker 镜像在测试环境都已经测试的没有问题了,放到生产服务器上也不能没有经过验证就直接替换,若是 web 系统,我建议用 api 网关+docker-compose+多版本运行的方式来实现热更新,而且这也会使得升级抖动的影响降到最低。如下图所示:T 为测试,P 为生产,v1、v2 就是 docker-compose 的多版本发布,通过 API 网关重定向微服务新版本跳转,实现最小升级抖动。

具体意思我简要说一下,就是让 docker-compose 作为你的应用发布的整体,这样无论是微服务也好,单体应用也好,就都统一作为一个单元部署管理了!

然后对需要更新的新版本程序,发布出新版本的 docker-compose,QA 验证无误后,再由 api 网关实现动态切换,Docker 热更新的大体思路就是这样。

3. Docker 挂载数据卷的时候映射文件会出现不同步?

学习 Docker 的时候发现 映射 redis.conf 会出现这种情况 难道一定要先从容器中拷贝一份再运行 yml 吗

Docker 映射配置文件的时候,一定是先要有这个文件,记住,而不是等其内部会创建这个文件,否则它只会创建出目录。

因此 Docker 映射文件不存在就走映射目录了。

所以第一种方式:是配置文件已经存在,也就是自己上传到服务器自定义配置目录,然后 Docker 直接映射过去,这时候映射文件或者映射目录一个道理。

第二种方式:配置目录映射到自定义目录,容器运行过程脚本自动化写入,那么配置目录的各项文件就需要在容器初始化过程中,由脚本对镜像内的打包配置文件完成写入。

其实我做过一个 Redis 的优化过的生产级的 Docker,走的是第一种方式,需要你自己上传一下配置,可以看看我的 gitee 源代码仓库,gitee 仓库也就做了这一个面向 Redis 中文化、性能调参过的 dockerfile 以及配置文件。·在 gitee 中搜索“读字节” 有个我写得不错的单机版 Redis Dockerfile 文件,里面对性能做过优化,大家可以用来学习。

结束语

总之在目前 Kubernetes 如日中天的时代,我们有时候要冷静思考一下,到底我们有必要搞得那么复杂吗?难道 Docker 还不够用吗?如果配合上 Portainer 这种在线免费的 Docker 管理工具,能让你的云上服务群管理的很好。

但是有一点是有门槛的,那就是玩 Docker 一定要不断历练自己的 Linux 能力,包括脚本编写能力,因为有些 Docker Images 并不能按照你的实际环境满足你的使用需求,需要自建 Dockerfile,我就在以前的工程中配合 Maven 编写了自己的 Dockerfile 和 Shell 脚本,微服务从打包到发布,一气呵成,而且可以灵活去选择哪个微服务进行更新。这就真的需要深刻的去理解 Linux 了。

这些都并不是说会用 Docker 就够了,实际上面对更复杂的 K8s,熟悉 Linux 这个问题一样是绕不过去的。因此还是关键的那一步,容器时代,用好容器引擎是从简单的 Docker 开始,并且在搞定程序之外历练自己的 Linux 功力,你的技术将提升得更快!

余下全文(1/3)

本文最初发表在wkee.net,文章内容属作者个人观点,不代表本站立场。

分享这篇文章:

请关注我们:

发表评论

邮箱地址不会被公开。 必填项已用*标注