macOS 终于可以完美使用 Podman 了!

2024-03-17 00:32

本文主要是介绍macOS 终于可以完美使用 Podman 了!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


更多奇技淫巧欢迎订阅博客:https://fuckcloudnative.io

前言

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

Podman 一直以来只能跑在 Linux 系统上,macOSWindows 只能通过 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 list
Name                    State             IPv4             Image
podman                  Running           192.168.64.2     Ubuntu 20.04 LTS

进入虚拟机:

$ multipass shell podman
Welcome 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/advantageSystem information as of Sun Nov  8 19:30:29 CST 2020System load:  0.0                Processes:               119Usage of /:   13.4% of 11.46GB   Users logged in:         0Memory usage: 11%                IPv4 address for enp0s2: 192.168.64.2Swap 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.1
ubuntu@podman:~$

4. 安装 Podman

在虚拟机中安装 Podman:

ubuntu@podman:~$ . /etc/os-release
ubuntu@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.list
ubuntu@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 update
ubuntu@podman:~$ sudo apt-get -y upgrade
ubuntu@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 Socket
Documentation=man:podman-system-service(1)[Socket]
ListenStream=%t/podman/podman.sock
SocketMode=0660[Install]
WantedBy=sockets.targetubuntu@podman:~$ sudo systemctl cat podman.service
# /lib/systemd/system/podman.service
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0[Service]
Type=notify
KillMode=process
ExecStart=/usr/bin/podman system service

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

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

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

ubuntu@podman:~$ podman --remote info
host:arch: amd64buildahVersion: 1.16.1cgroupManager: systemdcgroupVersion: v1conmon:package: 'conmon: /usr/libexec/podman/conmon'path: /usr/libexec/podman/conmonversion: '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 list
Name     Identity                 URI
podman*  /Users/Ryan/.ssh/id_rsa  ssh://root@192.168.64.2:22/run/podman/podman.sock

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

测试远程连接是否可用:

$ podman ps
CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES$ podman pull nginx:alpine
Trying to pull docker.io/library/nginx:alpine...
Getting image source signatures
Copying blob sha256:188c0c94c7c576fff0792aca7ec73d67a2f7f4cb3a6e53a84559337260b36964
Copying blob sha256:9dd8e8e549988a3e2c521f27f805b7a03d909d185bb01cdb4a4029e5a6702919
Copying blob sha256:85defa007a8b33f817a5113210cca4aca6681b721d4b44dc94928c265959d7d5
Copying blob sha256:f2dc206a393cd74df3fea6d4c1d3cefe209979e8dbcceb4893ec9eadcc10bc14
Copying blob sha256:0ca72de6f95718a4bd36e45f03fffa98e53819be7e75cb8cd1bcb0705b845939
Copying config sha256:e5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16c
Writing manifest to image destination
Storing signatures
e5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16c$ podman image ls
REPOSITORY                TAG     IMAGE ID      CREATED      SIZE
docker.io/library/nginx   alpine  e5dcd7aa4b5e  2 days ago   23.3 MB

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

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

最后,我们来看看 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


你可能还喜欢

点击下方图片即可阅读

天天叨叨云原生,你知道云原生是啥么?

云原生是一种信仰 ????

码关注公众号

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

点击 "阅读原文" 获取更好的阅读体验!

❤️给个「在看」,是对我最大的支持❤️

这篇关于macOS 终于可以完美使用 Podman 了!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/817259

相关文章

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意