HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

如何 Docker 化任意一个应用

  • 2018-07-28
  • 本文字数:3085 字

    阅读完需:约 10 分钟

网上有很多关于如何将应用 Docker 化的教程,为什么我还要再写一个呢?

我见过的大部分教程都是限定在某种特定技术(例如 Java 或者 Python),可能无法满足读者的需求。同时,这些教程也没有说清楚关于 Dev 和 Ops 团队之间建立明确约定所涉及到的所有相关方面(这正是容器化的精髓所在)。

我根据最近的经验总结了以下一些步骤。它是一份细节清单,包含了其他指南中忽略的内容。

声明:这不是一份新手指南。我建议读者先掌握一些如何设置和使用 docker 的基础知识,并且创建和运行一些容器之后,再来阅读。

让我们开始吧。

一、选择基础镜像

每种对应技术几乎都有自己的基础镜像,例如:

如果不能直接使用这些镜像,我们就需要从基础操作系统镜像开始安装所有的依赖。

外面有很多教程使用的都是 Ubuntu(例如 ubuntu:16.04)作为基础镜像,这不能算有问题,但是我建议优先考虑 Alpine 镜像:

https://hub.docker.com/_/alpine/

它是一个非常小的基础镜像(大约只有 5MB)。

注意:在基于 Alpine 的镜像中无法使用“apt-get”命令,Alpine 系统有自己的软件包仓库和包管理工具。详细请参考:

https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management

https://pkgs.alpinelinux.org/packages

二、安装必要软件包

这个步骤通常比较琐碎,有一些容易忽略的细节:

  • apt-get update 和 apt-get install 命令应该写在一行(如果使用 Alpine 则对应的是 apk 命令)。这不是常见的做法,但是在 Dockerfile 中应该要这么做,否则“apt-get update”命令产出的临时层可能会被缓存,导致构建时没有更新包信息(参见 https://forums.docker.com/t/dockerfile-run-apt-get-install-all-packages-at-once-or-one-by-one/17191 这个讨论)。
  • 确认是否只安装了实际需要的软件(尤其是这个容器会在生产环境中运行)。我看见过有人在他们的镜像中安装了 vim 和其他开发工具。

如果有必要,针对构建、调试和开发环境创建不同的 Dockerfile。这不仅仅关系到镜像大小,还涉及到安全性、可维护性等等。

三、添加自定义文件

一些优化 Dockerfile 的小提示:

四、定义容器运行时的用户权限

现在可以休息一下,阅读下这篇不错的的文章: Understanding how uid and gid work in Docker containers

读完这篇文章,我们会了解:

  • 仅当应用程序需要访问用户或组数据(/etc/passwd 或 /etc/group)时,才需要在容器启动时指定固定的用户 ID。
  • 尽可能避免容器以 root 权限运行。

不幸的是,不少热门应用程序镜像需要用特定的用户 id 来运行(例如 Elastic Search 需要 uid:gid = 1000:1000)。尽量不要在写出这样的镜像……

五、定义暴露的端口

这也是一个微不足道的小操作,但是不要为了暴露特权端口(例如 80)而将容器以 root 权限运行。如果有这样的需求,可以让容器暴露一个非特权端口(例如 8080),然后在启动时进行端口映射。

关于特权端口和非特权端口的不同: https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html

六、定义入口点(entrypoint)

普通方式:直接运行可执行文件。

更好的方式:创建一个“docker-entrypoint.sh”脚本,可以用来通过环境变量来配置容器的入口点(具体请参照下一节)。

这是一个非常普遍的做法,这里有一些例子:

https://github.com/elastic/elasticsearch-docker/tree/master/build/elasticsearch/bin

https://github.com/docker-library/postgres/tree/de8ba87d50de466a1e05e111927d2bc30c2db36d/10

七、定义一种配置方式

基本上每个应用程序都需要参数化。基本上有两条路可以遵循:

  1. 使用应用程序特定的配置文件:该方式需要通过文档说明配置文件的格式、字段、放置位置等等(当运行环境比较复杂,例如应用程序跨越不同的技术,则不太合适)。
  2. 使用(操作系统)环境变量:简单而有效。

如果读者认为这种方式不够现代,记住这也是 12-factors 推荐的方式:

https://12factor.net/zh_cn/config

这并不意味着我们可以抛开所有的配置文件,并对应用程序进行重构,去除配置文件机制。只需要通过 envsubst 命令来替换配置文件模板(这个流程需要在 docker-entrypoint.sh 文件中完成,因为这需要在运行时完成)。

例如:

https://docs.docker.com/samples/library/nginx/#using-environment-variables-in-nginx-configuration

这种方式可以将应用程序的配置文件封装在容器内部,无须让使用者了解这些细节。

八、外部化数据

关于数据存储有一条黄金法则:绝对不要将任何持久化数据保存到容器内。

容器的文件系统被设计成临时和短暂的。因此任何由应用程序生成的内容、数据文件和处理结果都应该保存到挂载的卷或者操作系统绑定挂载点上(既将宿主机操作系统的目录挂载到容器中)。

对于挂载卷我不太有经验,因此我个人更倾向于将数据保存到绑定挂载点(bind mounts)。这些挂载点一般通过类似 Salt Stack 这样的配置管理工具仔细的在宿主机上创建。

这里说的“仔细创建”,主要包括下面几个步骤:

  1. 在宿主机操作系统上创建非特权用户(和组)。
  2. 所有需要绑定目录的所有者都是该用户。
  3. 根据使用场景给授权(仅针对这个特定的用户和组,其他用户无权访问)。
  4. 容器也以该用户运行。
  5. 此时容器就可以完全控制这些目录。

九、确保处理好日志

前面关于“持久性数据”没有一个明确的定义,日志在这里就是灰色地带。我们该如何处理它们呢?

如果这是一个新的应用程序,并且希望它能够坚持 docker 约定,就不应该将日志写入文件。应用程序应该使用标准输出和标准错误输出日志。和之前推荐使用环境变量一样,这也是 12-factors 之一:

https://12factor.net/zh_cn/logs

Docker 会自动捕捉应用程序的标准输出,并可以通过“docker logs”命令查看:

https://docs.docker.com/engine/reference/commandline/logs/

当然还有一些实际场景下会遇到问题。例如运行一个简单的 nginx 容器,至少会有两种不同的日志文件:

  • HTTP 访问日志(Access Logs)
  • 错误日志(Error Logs)

对于这种日志按照特定结构输出的应用,可能不太适合将它们的日志输出到标准输出。这个例子中,只需要按照前面一节中说的处理好持久化问题,并确保正确配置文件的轮转。

十、轮转日志和其他仅追加文件

如果应用程序将日志写到文件,或者会无限追加内容到文件,就需要关注这些文件的轮转(rotation),这对于防止服务器空间耗尽非常有用(尤其是 GDPR 和其他数据安全条例出来之后)。

如果使用绑定挂载,我们可以依靠宿主机的一些工具来实现文件轮转功能,例如 logrotate(文档参见 https://linux.die.net/man/8/logrotate )。

最近我找到的一个简单且完整的例子:

https://www.aerospike.com/docs/operations/configure/log/logrotate.html

另外一个例子:

https://www.digitalocean.com/community/tutorials/how-to-manage-logfiles-with-logrotate-on-ubuntu-16-04

查看英文原文: How to dockerize any application

感谢张婵对本文的审校。

2018-07-28 19:553813

评论

发布
暂无评论
发现更多内容

时序数据库 TDengine 六周年庆典活动圆满落幕,现场火爆

爱倒腾的程序员

涛思数据 时序数据库 ​TDengine

软件测试 | 巧用监听器—识别性能缺陷

测吧(北京)科技有限公司

测试

软件测试 | 借助Ant实现批量测试和报表生成

测吧(北京)科技有限公司

测试

官宣!XTransfer与全球社交网络服务巨头Meta达成战略合作

XTransfer技术

赋能行业,因云而动 | 山西软件行业CXO思享会在太原成功举办,助力山西软件行业高质量发展

科技热闻

软件测试 | 常见的自动化测试架构

测吧(北京)科技有限公司

测试

.net低代码开发平台 快速实现组织架构数字化

力软低代码开发平台

十大理由,说清企业为何需要 CI/CD

极狐GitLab

DevOps 自动化 CI/CD 降本增效 效能提升

GOTC全球开源技术峰会|Sermant首次亮相,推进云原生微服务治理技术的演进

华为云开源

#云原生

软件测试 | 走出自动化测试认知的误区

测吧(北京)科技有限公司

测试

MobPush 查看推送数据

MobTech袤博科技

开放源代码平台Flynn的架构与实现原理

穿过生命散发芬芳

Flynn 6 月 优质更文活动

软件测试 | 分析确定性能测试指标

测吧(北京)科技有限公司

测试

软件测试 | 自动化测试的基本流程

测吧(北京)科技有限公司

测试

什么是智慧公共厕所?光明源智慧厕所

光明源智慧厕所

什么是双机热备技术?华为和思科如何实现双机热备?

wljslmz

6 月 优质更文活动

ChatGPT赋能产品管理

俞凡

人工智能 产品管理 ChatGPT

软件测试 | 聚合报告(Aggregate Report)

测吧(北京)科技有限公司

测试

首个锚定BTC Mining算力的HAG证券通证,或成传统投资者的另一选择

股市老人

文心一言 VS 讯飞星火 VS chatgpt (34)-- 算法导论5.3 1题

福大大架构师每日一题

福大大 ChatGPT

搞定大模型,AI 大底座系列云智公开课 6 月 20 日开始上线

Baidu AICLOUD

大模型 AI 大底座

软件测试 | 如何分析性能测试结果

测吧(北京)科技有限公司

测试

霍格沃兹测试开发线下班开班啦~

测吧(北京)科技有限公司

测试

回顾|开源之夏校园行兰州大学站

MatrixOrigin

分布式数据库 HTAP MatrixOrigin MatrixOne 超融合数据库

开源“上天入地”的本领都在这!2023开放原子全球开源峰会「开源展览」一文拿捏!

开放原子开源基金会

开源 开放原子全球开源峰会 开源展览

探访官招募 | InfoQ 写作社区 邀您探访 2023 亚马逊云科技中国峰会

InfoQ写作社区官方

热门活动

RocketMQ 学习社区重磅上线!AI 互动,一秒了解 RocketMQ 功能源码

阿里巴巴云原生

阿里云 AI RocketMQ 云原生

1v1视频交友APP的详细搭建部署步骤和视频交友APP核心功能介绍

山东布谷科技胡月

一对一直播源码 一对一直播系统 1v1语音系统搭建 视频社交APP开发 1v1交友app开发

红杉中国独立,艰难时期“美元基金”投资路径浮出水面

B Impact

2023-06-07:Redis 持久化方式有哪些?以及有什么区别?

福大大架构师每日一题

redis 福大大

如何Docker化任意一个应用_语言 & 开发_Henrique Souza_InfoQ精选文章