前言

Podman 是一个无守护程序与 Docker 命令兼容的下一代 Linux 容器工具,该项目由 RedHat 主导,其他的细节可以参考 Podman 使用指南[1],本文的重点不是这个。

Podman 一直以来只能跑在 Linux 系统上,macOS 和 Windows 只能通过 CLI 远程连接 Podman 的 API 来管理容器。事实上 Docker 也不支持 macOS 和 Windows,但 Docker 针对 Windows 和 macOS 推出了专门的客户端,客户端里面集成了虚拟化相关的设置,通过嵌套一层虚拟化来支持 Docker。对于 Podman 来说,想要在 macOS 上运行也只能通过虚拟化来实现,网上也有不少方案,基本上都是通过 Virtualbox 来实现,都不太优雅。本文将介绍一种相对更优雅的方案,虽然不是很完美,但我已经尽力做到接近完美了。。

HyperKit 介绍

HyperKit 是一个具有 hyperisor 能力的轻量级虚拟化工具集,包含了基于 xhyve(The BSD Hypervisor)的完整 hypervisor。HyperKit 设计成上层组件诸如 VPNKit[2] 和 DataKit[3] 的接口。xhyve 是 基于 bhyve 的 Mac OS X 移植版本,而 bhyve 又是 FreeBSD 下的虚拟化技术。。。

我们知道,Docker 在 Linux 上利用了 Linux 原生支持的容器方式实现资源和环境的隔离,直接利用宿主内核,性能接近原生。然而,在 macOS 上却仍然需要虚拟化的技术。早期的 Docker 干脆直接在开源的 VirtualBox 中构建虚拟机,性能低下。后期的 Docker 基于轻量化的虚拟化框架 HyperKit[4] 开发,据说性能得到很大提升。

本文将介绍如何通过 HyperKit 来使用 Podman。方法也很简单,先通过 Hyperkit 创建一个轻量级虚拟机,然后在虚拟机中安装 Podman,并开启 remote API,最后在本地通过 CLI 连接虚拟机中的 Podman。这和 macOS 中的 Docker 实现原理是一样的,只不过 Podman 是没有 Daemon 的,与 Docker 相比可以节省不少资源。

2. 安装 HyperKit

你可以自己下载源代码编译 HyperKit,但我不建议这么做,不同的 macOS 版本会遇到各种各样的错误。我这里推荐两种超级简单的方法:

  1. 直接通过安装 Docker 来获得 HyperKit,因为 Docker Desktop on Mac 就是基于 HyperKit 实现的,所以安装 Docker Desktop on Mac 就能够获得完整的 HyperKit 运行环境。整个过程会非常顺畅和简单。安装完 Docker 之后可以永远不用打开 Docker,直接使用 HyperKit 就好。或者你可以直接卸载 Docker,卸载之前先把 hyperkit 二进制文件备份出来,因为卸载 Docker 也会删掉 hyperkit 二进制文件。

  2. 直接通过安装 Multipass 来获得 HyperKit。Multipass 是 Canonical 公司(Ubuntu)开发的基于不同操作系统内建原生 Hypervisor 实现的工作站。由于 Windows(Hyper-V),macOS(hyperkit)和 Linux(KVM)都原生支持 hypervisor,这样通过 multipass shell 命令就能够在一个 shell 中实现创建运行 Ubuntu 虚拟机。在 macOS 平台,默认的后端是 hyperkit,需要 macOS Yosemite (10.10.3) 以上版本并且需要安装在 2010 以后生产的 Mac 设备。安装方法很简单:

$ brew cask install multipass

安装好了之后可以在 /Library/Application Support/com.canonical.multipass/bin/ 目录下找到 hyperkit 二进制文件。

3. 创建虚拟机

你可以直接通过 hyperkit 来创建虚拟机,但参数比较复杂,有兴趣的自己研究吧。我推荐直接通过 multipass 来创建,命令特别简单:

$ multipass launch -c 2 -d 10G -m 2G -n podman
  • -n : 指定启动实例名字
  • -c : 分配 CPU 数量
  • -d : 设置磁盘容量
  • -m : 设置内存容量

第一次启动虚拟机的时候会去拉去镜像,国内网速可能会很慢。

查看已经启动的虚拟机:

$ multipass listName                    State             IPv4             Imagepodman                  Running           192.168.64.2     Ubuntu 20.04 LTS

进入虚拟机:

$ multipass shell podmanWelcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-52-generic x86_64)

 * Documentation:  https://help.ubuntu.com * Management:     https://landscape.canonical.com * Support:        https://ubuntu.com/advantage

  System information as of Sun Nov  8 19:30:29 CST 2020

  System load:  0.0                Processes:               119  Usage of /:   13.4% of 11.46GB   Users logged in:         0  Memory usage: 11%                IPv4 address for enp0s2: 192.168.64.2  Swap usage:   0%

0 updates can be installed immediately.0 of these updates are security updates.

Last login: Sun Nov  8 17:38:31 2020 from 192.168.64.1ubuntu@podman:~$

4. 安装 Podman

在虚拟机中安装 Podman:

ubuntu@podman:~$ . /etc/os-releaseubuntu@podman:~$ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.listubuntu@podman:~$ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -ubuntu@podman:~$ sudo apt-get updateubuntu@podman:~$ sudo apt-get -y upgradeubuntu@podman:~$ sudo apt-get -y install podman

5. 建立 Podman Socket

Podman 依赖于 systemd 的 socket activation[5] 特性。假设 Daemon B 依赖于 Daemon A,那么它就必须等到 Daemon A 完成启动后才能启动。socket activation的思想就是:Daemon B 启动时其实并不需要 Daemon A 真正运行起来,它只需要 Daemon A 建立的 socket 处于 listen 状态就 OK 了。而这个 socket 不必由 Daemon A 建立, 而是由 systemd 在系统初始化时就建立。当 Daemon B 发起启动时发起连接,systemd 再将 Daemon A 启动,当 Daemon A 启动后,再将 socket 归还给 Daemon A。

Podman 会通过 podman.socket 先创建一个处于监听状态的 socket 文件 /run/podman/podman.sock,当有进程向该 socket 发起连接时,systemd 会启动同名的 service:podman.service,以接管该 socket。先看看 podman.socket 和 podman.service 长啥样:

ubuntu@podman:~$ sudo systemctl cat podman.socket# /lib/systemd/system/podman.socket[Unit]Description=Podman API SocketDocumentation=man:podman-system-service(1)

[Socket]ListenStream=%t/podman/podman.sockSocketMode=0660

[Install]WantedBy=sockets.target

ubuntu@podman:~$ sudo systemctl cat podman.service# /lib/systemd/system/podman.service[Unit]Description=Podman API ServiceRequires=podman.socketAfter=podman.socketDocumentation=man:podman-system-service(1)StartLimitIntervalSec=0

[Service]Type=notifyKillMode=processExecStart=/usr/bin/podman system service

设置开机自启 podman.socket,并立即启动:

ubuntu@podman:~$ sudo systemctl enable podman.socket --now

确认 socket 是否正处于监听状态:

ubuntu@podman:~$ podman --remote infohost:  arch: amd64  buildahVersion: 1.16.1  cgroupManager: systemd  cgroupVersion: v1  conmon:    package: 'conmon: /usr/libexec/podman/conmon'    path: /usr/libexec/podman/conmon    version: 'conmon version 2.0.20, commit: '  cpus: 2  ...

3. 客户端 CLI 设置

接下来所有的设置,如不作特殊说明,都在 macOS 本地终端执行。

Podman 远程连接依赖 SSH,所以需要设置免密登录,先生成秘钥文件:

$ ssh-keygen -t rsa   # 一路回车到底

然后将本地的公钥 ~/.ssh/id_rsa.pub 追加到虚拟机的 /root/.ssh/authorized_keys 文件中。

安装 Podman CLI:

$ brew install podman

添加远程连接:

$ podman system connection add ubuntu --identity ~/.ssh/id_rsa ssh://root@192.168.64.2/run/podman/podman.sock

查看已经建立的连接:

$ podman system connection listName     Identity                 URIpodman*  /Users/Ryan/.ssh/id_rsa  ssh://root@192.168.64.2:22/run/podman/podman.sock

由于这是第一个连接,所以被直接设置为默认连接(podman 后面加了 *)。

测试远程连接是否可用:

$ podman psCONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES

$ podman pull nginx:alpineTrying to pull docker.io/library/nginx:alpine...Getting image source signaturesCopying blob sha256:188c0c94c7c576fff0792aca7ec73d67a2f7f4cb3a6e53a84559337260b36964Copying blob sha256:9dd8e8e549988a3e2c521f27f805b7a03d909d185bb01cdb4a4029e5a6702919Copying blob sha256:85defa007a8b33f817a5113210cca4aca6681b721d4b44dc94928c265959d7d5Copying blob sha256:f2dc206a393cd74df3fea6d4c1d3cefe209979e8dbcceb4893ec9eadcc10bc14Copying blob sha256:0ca72de6f95718a4bd36e45f03fffa98e53819be7e75cb8cd1bcb0705b845939Copying config sha256:e5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16cWriting manifest to image destinationStoring signaturese5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16c

$ podman image lsREPOSITORY                TAG     IMAGE ID      CREATED      SIZEdocker.io/library/nginx   alpine  e5dcd7aa4b5e  2 days ago   23.3 MB

现在我们就可以直接在本地用 podman 愉快地玩耍了!

如果你建立了多个连接,可用使用 --connection 参数指定远程连接,或者使用 podman system connection default  来设置默认的远程连接。

最后,我们来看看 hyperkit 的内存占用:


物理内存只占用了 921M,如果你觉得这个内存占用很多,不妨去对比下 Docker Desktop 的内存占用。

总结

本文介绍了在 macOS 中使用 podman 的方法,通过 HyperKit 创建 Ubuntu 虚拟机运行 Podman,并建立 Podman Socket,然后客户端通过 SSH 连接服务端的 Socket,以实现通过远程连接来管理容器。

参考资料

[1]

Podman 使用指南: https://fuckcloudnative.io/posts/podman-sidecar/

[2]

VPNKit: https://github.com/moby/vpnkit

[3]

DataKit: https://github.com/moby/datakit

[4]

HyperKit: https://github.com/moby/hyperkit

[5]

socket activation: http://0pointer.de/blog/projects/socket-activation.html

DD自研的沪牌代拍业务,点击直达

往期推荐

Mysql 都会遭受哪些方面的攻击?

你了解 Java 的 jstat 命令吗?

Git 提交代码之后的几种后悔药

为什么大多数IOC容器使用ApplicationContext,而不用BeanFactory

JIRA、Confluence等产品明年2月停售本地化版本,将影响中国近90%的客户!

妙用 Intellij IDEA 创建临时文件,Git 跟踪不到的那种

云原生是一种信仰 ?

码关注公众号

后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!

深度内容

推荐加入

virtualbox macos_MacOS 终于可以完美使用 Podman 了!相关推荐

  1. MacOS 终于可以完美使用 Podman 了!

    前言 Podman 是一个无守护程序与 Docker 命令兼容的下一代 Linux 容器工具,该项目由 RedHat 主导,其他的细节可以参考 Podman 使用指南[1],本文的重点不是这个. Po ...

  2. 原创:嵌入图片的HTML内容在FLASH AS3中正确显示的最佳解决方案

    做一个项目,遇到这个该死的问题,尝试了几乎所有解决方法,几近崩溃,终于找到完美解决方案.因为在网上,无论中文还是英文,搜索了无数遍,都没人给出正确答案,所以,在此记下,但愿能帮到跟我一样遇到这个问题的 ...

  3. linux 进程间 close-on-exec 机制 简介

    大部分这种问题都能够解决,在文章的最后,提到了一种特殊情况,就是父子进程中的端口占用情况.父进程监听一个端口后,fork出一个子进程,然后kill掉父进程,再重启父进程,这个时候提示端口占用,用net ...

  4. CKEditor代码高亮显示插件Code Snippet安装及使用方法

    CKEditor网页编辑器 CKEditor 即 FCKEDITOR .FCKeditor是目前最优秀的可见即可得网页编辑器之一,它采用JavaScript编写.具备功能强大.配置容易.跨浏览器.支持 ...

  5. linux怎么用两个进程传值,linux下的C开发14,可执行程序如何传递参数?模拟shell执行命令...

    上一节介绍了 linux 中的文件类型,并在文章最后使用 C语言编写了程序,该程序能够接受一个文件名参数,并打印出该文件的类型.不知道大家如何,反正我当初学编程时,发现(编译后的)可执行程序居然也能像 ...

  6. Oxite移植到ASP.NET MVC2 BETA 笔记(关于Html.RenderPartialFromSkin)

    在将Oxite移植到asp.net mvc2 beta平台后,经过一系列有关"方法调用"变更的修正后,终于能够通过编译运行起来了!(移植后的源码参见:http://ecubecms ...

  7. chromedriver 下载_centos7中配置python爬虫selenium+chromium+chromedriver环境

    今天为了爬取某异步加载网站的数据,开始自学了selenium,不得不说selenium还是很方便的工具,适合无脑爬取异步加载的网站.首先我在自己的windows电脑下配置了selenium和chrom ...

  8. Remoting核心类库RealProxy迁移

    在学习.net core的过程中,我们已经明确被告知,Remoting将不会被支持.官方的解释是,.net framework 类型包含了太多的Runtime的内容,是一个非常重量级的服务实现,已被确 ...

  9. 当 Egg 遇到 TypeScript,收获茶叶蛋一枚 #27

    当 Egg 遇到 TypeScript,收获茶叶蛋一枚 #27 前言 TypeScript is a typed superset of JavaScript that compiles to pla ...

最新文章

  1. Jzoj5429 排列
  2. 模板:多项式乘法(FFTNTT)
  3. 在线mod计算机,MOD大师教程 手把手教你改造电脑机箱
  4. 修改服务器时间报错,修改服务器时间linux
  5. 图论 —— 最短路 —— Dijkstra 算法
  6. 【POJ2386】Lake Counting
  7. Linux 脚本编写基础(三)
  8. 组件实例对象与Vue实例对象
  9. oracle 去空格函数未生效,发现ASCII值为49824的字符
  10. BitBake用户手册-3.语法和操作
  11. unity 将 .prefab 转换为 txt 格式
  12. 2022-2027年中国番茄酱行业市场全景评估及发展战略规划报告
  13. 微型计算机中的位置的是什么,电脑基础知识问答卷
  14. 为什么我电脑在线看黄色很慢_为什么我的电脑这么慢?
  15. 嵌入式开发模拟红外测距仪---UDP通信实现无线装置
  16. Blender 建模案例一(2)
  17. 这五个资源网站真的是非常强大 请尽快收藏
  18. 《线性代数及其应用》阅读笔记:一 1.5 线性方程组的解集
  19. 怎么炒原油期货外盘?原油期货外盘入门知识有哪些?
  20. 慕课网Java入门第一季教程(六)数组

热门文章

  1. 漫画:8年估值千亿美金的字节跳动是如何修炼的
  2. 十分钟搞定JeecgBoot 单体升级微服务!
  3. showModalDialog 使用详解
  4. JavaEE基础(06):Servlet整合C3P0数据库连接池
  5. WebSocket知识点总结
  6. 12.2日,第二次团队冲刺开始
  7. centos清楚缓存
  8. [译] Grid 布局完全指南
  9. Python3的tkinter写一个简单的小程序
  10. NET防SQL注入方法