写点什么

Dockerless 系列文章(三):使用 Podman 将开发环境转到容器

  • 2019-08-28
  • 本文字数:5646 字

    阅读完需:约 19 分钟

Dockerless系列文章(三):使用Podman将开发环境转到容器

什么是 Podman,它有用吗?mkdev.me 的本地开发环境如何?如何使用 Podman?去 Docker:真的值得吗?本文提供了一个非常有力的方案,能够几乎完全替代 Docker,总有更多容器领域内发生的事情需要了解,总有新的东西你需要学习和尝试。


在这个系列中的介绍性文章中,我提到过 Podman 和 Buildah 的一个缺点是其技术仍然很新并且变化很快。因为从 Podman 1.3.1 到 1.4.1 中的一个关键特性被破坏了,所以本文的发布推迟了很久。


幸运的是,Podman 1.4.1 及更高版本不仅修复了被破坏长达几周的功能,而且还最终测试了这些功能。希望未来版本中的功能不会出现如此大的意外。我最开始发出的警告仍然有效,那就是:因为新容器技术的工具链是新的,所以有时不稳定。


阅读本文前需要注意的两点:


1、我的警告可能不再有效,这取决于你阅读本文的时间。本文所述的是截至 2019 年 6 月的状态。如果你在 2019 年底或 2020 年才看到这篇文章,那么 Podman 可能已经足够成熟且稳定了,因此你也不必再担心小版本之间的被破坏的功能。


2、我会简要地提及 Podman 的工作原理,但我不会详细地介绍。如果你是一名基础架构工程师或者好奇,请点击我在文章中提供的所有链接了解更多的信息。如果你是一位不太关心内部构件的开发人员,那么请跳过它们,因为你可能需要花些时间来深入研究此主题,而这并不能立即为你的日常工作带来收益。

什么是 Podman,它有用吗?

Podman是 Docker 的替代品,用于容器化应用程序的本地开发。Podman 命令将 1 对 1 映射 Docker 命令,包括它们的参数。你可以使用 podman 为 docker 添加别名,并且从不会发现管理本地容器的是两种完全不同的工具。


Podman 的核心功能之一是它专注于安全性。使用 Podman 不需要守护进程。相反,它使用传统的fork-exec模型,并且大量地使用用户名称空间网络名称空间。因此,Podman 比 Docker 更加孤立,使用起来也更安全。你甚至可以在容器中充当 root,而无需在主机上授予容器或 Podman 任何 root 权限。同时,容器中的用户无法在主机上执行任何 root 级别的任务。


Podman:一种更安全的运行容器的方法》一文中介绍了 Podman 模型如何提高安全性。如果你想了解关于 Podman 如何使用 Linux 名称空间的更多信息,请从《Podman和用户命名空间:完美联姻》一文开始阅读。最后,如果你想了解 Podman 这种方法可能遇到的障碍,请阅读《无root容器的缺点》。


对于大多数用户来说,Podman 的内部构件在日常使用中应该不太重要。重要的是 Podman 能够在后台以更安全的方式提供与 Docker 相同的开发人员体验。让我们看看这是否属实。

mkdev.me 的本地开发环境

mkdev.me 背后的主要 Web 应用程序是用 Ruby on Rails 编写的。要让开发人员能够在本地运行此应用程序,需要:


  1. PostgreSQL 服务器;

  2. Redis 服务器;

  3. Mattermost实例(对于我们的聊天解决方案而言);

  4. Mattermost 测试实例(在自动化测试期间使用);


总共需要 5 个本地运行的服务(包括 Web 应用程序本身)。可以想象,任何新开发人员手动安装和配置所有这些服务都要相当长的时间。而这些操作一旦完成,我们无法保证生成的本地环境接近于生产环境:开发人员可以安装不同的 PostgreSQL 或 Mattermost 版本,这些版本尚未经过测试其是否可与 mkdev 一同使用。


使用一条命令来引导完整的开发环境并在几秒钟内运行与生产类似的设置,这不是很好吗?而这就是 Docker 和 Docker Compose 为开发人员提供的功能。这也是 Podman 能提供的。

Podman 的 pod 和它们的好处

在普通容器的顶部,Podman 有 pod。如果你听说过 Kubernetes,那么这个概念对你来说很熟悉。在 Kubernetes 中,pod 是一个最小的部署单元,它由单个或多个容器组成。Podman 的 pod 和 Kubernetes 完全一样。pod 中的所有容器共享相同的网络命名空间,因此它们可以通过 localhost 轻松地互相通信,而无需导出任何额外的端口。


pod 的 3 种可能的用例如下:

1.准备好你的应用程序,以使其在 Kubernetes/Openshift 上运行

你可以在 Podman 中使用 pod 作为准备步骤,然后再将应用移至 Kubernetes。在许多情况下,对于真实的 Web 应用程序来说,使用minikube可能会更好,因为这能保证你拥有的 API 和功能和 Kubernetes 相同。你可能希望拥有部署、服务和其他资源,这些东西是你在生产环境中设置的重要组成部分。只是用 Podman 来模拟 pod 对这个没多大好处。

2.在生产中使用 Podman 运行你的应用程序

如果你决定彻底的容器编排对你来说是一种矫枉过正(在许多情况下这也是一个非常好的决定),那么继续使用容器来封装和交付应用程序是有道理的。在某些情况下,你不仅可以从运行多个容器中受益,而且还可以在生产服务器上的 pod 中运行多个容器。但问题是相比于将容器作为单独的系统管理服务来运行,将容器放入 pod 中的好处究竟是什么?在这里我没法给出一个好的答案,但这个功能始终就在那里,有人或许会找到一个它在生产中的用例。

3.简化你的开发环境

对于开发人员来说最终极和最有吸引力的原因是使用 Podman pod 来自动化开发环境。在这种情况下,你需要在同一个 pod 中运行应用程序依赖的所有服务。在真实 Kubernetes 集群上的生产环境中你绝对不应该做这样的事情,因为你的服务应该运行在不同复制控制器和服务端点后方的不同 pod 中。但对于本地开发来说,这样做却很方便。

Podman pod 和 Kubernetes pod

在看真实的例子之前,我们需要了解 Podman 的一个与 pod 相关的功能:play kube。Podman 没有 Docker Compose 的替代品。但第三方工具podman-compose可能会带来这个功能,但 mkdev 还没有来得及测试它。


Podman 拥有 pod 和一种从 YAML 定义来运行 pod 的方法,而不是使用 Docker Compose。此 YAML 定义与 Kubernetes pods YAML 兼容,所以你可以使用此 YAML,将其加载到 Kubernetes 集群中并使某些 pod 运行。


超出范围:支持 docker-compose。我们认为,Kubernetes 是组成 Pod 和编排容器事实上的标准,所以 Kubernetes YAML 可以说是事实上的标准文件格式。- 《Podman 文档》

Podman 的基本使用

我们首先需要创建一个暴露 5432 端口的新 pod:


podman pod create --name postgresql -p 5432 -p 9187
复制代码


我们可以使用 podman pod ps 命令来运行 pod:


POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID235164dd4137 postgresql Created 26 seconds ago 1 229b2a70b8c4
复制代码


当你创建一个新的 pod 时,Podman 会自动启动 infra 容器,运行 podman ps 就可以看到它。


在这个 pod 中启动一个 PostgreSQL 容器:


podman run -d --pod postgresql -e POSTGRES_PASSWORD=password postgres:latest
复制代码


如果你没有 postgres:latest 图像,Podman 将自动从 Docker Hub 中获取它 – 这与 Docker CLI 相同。


在 postgresql pod 中启动另一个容器:通过 PostgreSQL Prometheus 导出器


podman run -d --pod postgresql -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" wrouesnel/postgres_exporter
复制代码


我们可以使用 podman pod top postgresql 命令来查看 pod 中的顶级进程。如果运行 curl localhost:9187/metrics,我们就可以访问 PostgreSQL 指标。


如果我们想在不运行命令式 shell 命令的情况下再次创建相同的设置并将此设置存储为声明性代码,我们可以运行 podman generate kube postgresql > postgresql.yaml,生成一个 Kubernetes 兼容的pod定义。如果你按照该链接检查此 YAML 文件,你会看到 Podman 正确地配置了所有端口,而且还导出了所有环境变量,如果你想使用图像默认值,可以清除这些变量。


使用 podman pod rm postgresql –f 来删除 pod。然后,无需再次运行所有命令,运行 podman play kube postgresql.yaml 即可获得相同的结果。你也可以运行 kubectl apply -f postgresql.yaml 并在 Kubernetes 集群上运行这个 PostgreSQL。


警告:如果你碰巧使用的是 Podman 1.4.2,那么此时你会遇到一个“这个GitHub问题”中描述的错误。希望在你阅读它时,这个问题已经修复。如果没有修复,请按照问题描述中的步骤修复你的 YAML,或者复制“我的要点”的内容,其中包含了已修复过的定义。


由 Podman 生成的 YAML 文件不应该“按原样”使用,因为 Podman 会转储所有环境变量、securityContext 以及你可以在开发环境中丢弃的其他内容,或者可能在 Kubernetes 集群中具有更好默认值的东西。请将它看做是一个实用的脚手架,而不是最终的结果。

在真正的 Ruby on Rails 应用程序中使用 Podman

在 mkdev,我们用 Podman 完全自动化了开发环境。新开发人员(假设他们运行的是 Linux)可以通过运行单个脚本./script/bootstrap.sh 来运行应用程序。该脚本本身看起来像这样:


#!/bin/bashset +eif [ "$(podman pod ps | grep mkdev-dev | wc -l)" == "0" ] ; then  echo "> > > Starting PostgreSQL, Redis and Mattermost"  podman play kube pod.yamlelse  echo "Development pod is already running. Re-create it? Y/N"  read input  if [ $input == "Y" ] ; then    podman pod rm mkdev-dev -f    podman play kube pod.yaml  else    echo "Leaving bootstrap process."    exit 0  fifiecho "> > > Waiting for PostgreSQL to start"until podman exec postgres psql -U postgres -c '\list'do  echo "> > > > > > PostgreSQL is not ready yet"  sleep 1donepodman exec -u postgres postgres psql -U postgres -d template1 -c 'create extension hstore;'echo "> > > Creating development IM database"until podman exec -u postgres postgres createdb mattermost; do sleep 1; doneecho "> > > Creating test IM database"until podman exec -u postgres postgres createdb mattermost_test; do sleep 1; doneecho "> > > Creating and seeding the database"./script/setup.sh./script/exec.sh 'bundle exec rails db:create db:migrate db:test:prepare'./script/seed.shecho "> > > Attempting to start the app"./script/run.sh
复制代码


我们依靠 play kube 功能来创建所有必需的服务,就像你通常运行 docker-compose up 一样。我们的 pod.yaml 定义了 4 个容器 – PostgreSQL、开发和测试 Mattermost 实例以及 Redis 服务器。我们运行 Mattermost 的专用测试实例,因为我们需要在进行集成测试后重置数据库,而且我们不想重置开发实例,因为这无疑是十分低效的。


我们不直接运行 rails 和 rake 命令,而是将它们隐藏在 scripts 文件夹中,类似的设置可参考 GitHub“统管一切的脚本”的文章,了解如何在内部组织这些脚本。


scripts/bootstrap.sh 会调用许多其他脚本,例如填充 (seed) 数据库、下载一些依赖项并触发数据库迁移。其中,开发人员发现有用的一个脚本是 scripts/exec.sh:


#!/bin/bashset -eecho "Running command in new container ..."podman run --pod mkdev-dev -it --rm -v $(pwd):/app:Z docker.io/mkdevme/app:dev $1
复制代码


它会在新的应用程序容器中运行命令,然后删除此容器。这对于运行一次性命令如数据库迁移或 rake 任务等非常有用。


scripts/run.sh 只启动应用程序容器,如果没有启动,它会在内部启动 Rails 服务器:


#!/bin/bashset -eif [ "$(podman ps | grep app | grep mkdevme | wc -l)" == "0" ] ; then  echo "> > > Starting new application container"  podman run --pod mkdev-dev --name app -v $(pwd):/app:Z -d docker.io/mkdevme/app:dev tail -f /app/log/development.logfin=0until [ $n -ge 5 ]do  podman exec app /entrypoint.sh bundle exec rails s -b '0.0.0.0' -P /tmp/mkdev.pid  n=$[$n+1]  echo "Not all components are up. Sleeping for 10 seconds."  sleep 10done
复制代码


请注意,在应用程序容器内执行的命令只是一个 tail -f,它生成了一个永不消亡的容器。这样做主要是为了让开发人员能够快速进入容器并在内部调试内容,以防 Rails 拒绝启动,出现新的错误。


你可能不喜欢我们必须编写许多的 bash 脚本。它绝对不如单个 docker-compose.yaml 文件好。不过,这并不算太糟糕。这些脚本只需要编写一次,它们也不太复杂。最终,这更多的是审美的问题,而不是真正的技术缺陷。


通过这套方便的脚本,我们可以涵盖大多数开发任务,例如重启服务器、执行任何命令等等。但有些东西还需要改进,这是避免不了的,但总的来说结果我们非常满意。因为它,开发人员得到了相同的环境,具有相同的依赖版本,相同的 Ruby 版本以及相同的其它东西,他们可以在几秒钟内就(重新)创建整个本地设置。这些好处与 Docker 完全相同,而且我们根本没有用到 Docker。

去 Docker:值得吗?

这个系列文章到此就结束了。希望你学到了有关容器标准和新工具的新知识。但你可能还是会问一个问题:这值得吗?当然我自己也会问这个问题。应用良好和旧的 Docker 技能和实践肯定会更容易,可能我们会得到同样的结果,而且速度更快。


但重点是,最终我们得到了同样的结果。容器映像被构建,容器在开发和测试环境中被使用,我们取得了与 Docker 相同的优势。而且我们并没在功能上做太多的妥协,尽管我们的确在开始时遇到了 Podman 中的某些 bug。而且就在我写这篇文章时,我仍然发现了 Podman 的另一个 bug!


既然 mkdev 提供了一个关于 Podman 和 Buildah 的可行的解决方案,我们就可能会坚持用下去。虽然有些方法可以将应用程序部署在 Podman 生成的容器中,而且该容器是作为 systemd 服务来进行管理的,但我们没有任何理由将容器编排工具引入堆栈。我们的 pod.yaml 可用来为新的 Pull 请求部署评论应用程序,这将进一步改善我们的测试流程。而且,每个 Podman 版本都会推出更多的功能。


正如我在本系列的第一篇文章做过的那样,我鼓励你了解更多容器领域内发生的事情。总有新的东西你需要学习和尝试,也总有非常好的文章供你阅读,我已经在本系列的所有 3 篇文章中提供了它们的链接。


原文链接:


https://mkdev.me/en/posts/dockerless-part-3-moving-development-environment-to-containers-with-podman


2019-08-28 09:0016112
用户头像

发布了 34 篇内容, 共 19.3 次阅读, 收获喜欢 47 次。

关注

评论

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

Django笔记二十八之数据库查询优化汇总

Hunter熊

Python django 查询优化

Nacos必知必会:这些知识点你一定要掌握!

王中阳Go

Go 微服务 nacos 服务治理 配置管理

软件测试|神操作!用 Python 操作 xmind 绘制思维导图

霍格沃兹测试开发学社

软件测试|PC端应用自动化最佳解决方案——Pywinauto

霍格沃兹测试开发学社

软件测试|Pytest的必会技巧(一)

霍格沃兹测试开发学社

背靠香港影视集团星光文化,StarNFT问世了

西柚子

什么是好代码/坏代码?给普通人的图解示例

越长大越悲伤

后端 好代码的衡量标准

Prompt learning 教学[最终篇]:Chatgpt使用场景推荐、优秀学习资料推荐、AI工具推荐

汀丶人工智能

人工智能 自然语言处理 ChatGPT 人工智能ChatGPT 吗? prompt learning

Prompt工程师指南[从基础到进阶篇]:用于开发和优化提示,以有效地使用语言模型(LMs)进行各种应用和研究主题

汀丶人工智能

人工智能 自然语言处理 ChatGPT prompt learning

ui设计软件Sketch 96.3中文激活版~ 支持m1

真大的脸盆

Mac ui设计 矢量设计

workerman 自定义的协议如何解决粘包拆包

北桥苏

php Unity3D workerman GatewayWorker

软件测试|一步到位教会你Python字典操作(一)

霍格沃兹测试开发学社

MySql 索引的失效与优化

Andy

Java Web实战 | 设计一个监听器

TiAmo

JDBC 事件监听 监听

你管这破玩意叫缓存穿透?还是缓存击穿?

Java你猿哥

redis 缓存 缓存穿透 缓存击穿 缓存雪崩

C语言编程-程序结构

芯动大师

C语言 结构 三周年连更

Zabbix电话短信报警技巧

外滩运维专家

zabbix电话报警 zabbix短信报警 zabbix飞书报警 zabbix钉钉报警 zabbix微信报警

AI DevOps | ChatGPT 与研发效能、效率提升(中)

laofo

DevOps 研发效能 ChatGPT

CSS小技巧之圆形虚线边框

南城FE

CSS css3 前端开发

用友BIP成功入围工信部《2022年信息技术应用创新解决方案》

用友BIP

2023-05-14:你的赛车可以从位置 0 开始,并且速度为 +1 ,在一条无限长的数轴上行驶, 赛车也可以向负方向行驶, 赛车可以按照由加速指令 ‘A‘ 和倒车指令 ‘R‘ 组成的指令序列自动行驶

福大大架构师每日一题

Go 算法 rust 福大大

聊一聊模板方法模式

设计模式 模板方法模式

Unity3D 对接 workerman 实现联机游戏

北桥苏

php socket Gateway Unity3D workerman

从原理到实战,手把手教你在项目中使用RabbitMQ

Java你猿哥

Java ssm RabbitMQ 消息队列 RabbitMQ延时队列

软件测试|Python实用炫酷技能——推导式

霍格沃兹测试开发学社

软件测试|手把手教你用Python来模拟绘制自由落体运动过程中的抛物线

霍格沃兹测试开发学社

设计模式之美--应用LOD法则实现“高内聚低耦合”

GalaxyCreater

设计模式

定风波、渡重山、至未来:2023中国数字能源生态大会开启的新旅程

脑极体

新能源

软件测试|不会Python RPC,一篇文章教你入门

霍格沃兹测试开发学社

Orillusion引擎开源一周,荣登Github Trending榜单

Orillusion

开源 3D 渲染引擎 元宇宙 #WebGPU

如何使用Go语言实现LSP原则

Jack

Dockerless系列文章(三):使用Podman将开发环境转到容器_服务革新_KIRILL SHIRINKIN_InfoQ精选文章