CoreOS那些事之Rkt容器尝鲜(上)

Stella981
• 阅读 909

从CoreOS发布Rocket应用容器项目到现在,已经过去半年时间了。为了增加辨识度,项目更名为了Rkt。在沉寂了许久后,最近又开始在社区里出现了一些新鲜的声音。

首先是4月7日的一条新闻,Google领头投资CoreOS公司1200万美元以共同合作发展旗下的Kubernetes组件。此次合作除了促成新的商业发行版Tectonic的诞生,也使得Rkt容器与Kubernetes的关系拉近了一步:Kubernetes将提供对Rkt的友好支持,而Rkt则将沿用Kubernetes的Pods等概念来规划容器。

随后的4月20日,VMWare发布了旗下的通过容器部署应用的开源操作系统发行版:Photon。这个项目比较闪亮的地方在于,除了最知名的Docker容器,Photon还支持另外两种容器标准:CloudFoundry旗下的Garden,以及我们即将介绍的AppC/Rkt。CoreOS也在多篇博客中暗示VMWare其实以已经是AppC规范社区的一员。

就在5月4日的CoreOS Fest大会上,Linux大鳄红帽公司(Red Hat)联合谷歌(Google)、VMware和Apcera共同宣布,将大力支持AppC社区的发展。红帽和谷歌甚至确认将派出工程师协助维护AppC项目

一个还在Alpha阶段的项目获得如此高的关注,对于CoreOS公司确实是个好兆头。这个系列接下来的两篇里,将带大家走进Rkt容器和它所代表的AppC容器规范,且做抛砖引玉之用。

Rkt的前世今生

作为一个年轻的应用容器新秀,开源的Rkt并不是一个人在战斗,在它的背后支撑的是一支俨然有序的庞大社区力量。

诞生背景

Rkt项目最初的发起者是CoreOS公司。

CoreOS公司与其核心产品CoreOS操作系统是实至名归的最早一批Docker企业级用户,伴随着Docker从最初的0.1版本一直走到正式发布的1.0版本。起初两者相互促进,合作甚好。然而,随着Docker在容器界一家独大的趋势越来越明显,其周边的生态逐渐的从单纯的围绕构建容器化应用服务,发展成了自上而下的集群规范体系,甚至部分取代了操作系统的服务进程调度工作。这种臃肿而受Docker单方面控制的容器规范,是CoreOS系统所不待见的,他们想要一个更加开放而中立的容器标准。

2014年12月,CoreOS公布了自己的容器计划,并在几个月后结合社区中的容器实践,着手制定新的开放应用容器规范,Rkt则作为此规范中的一个具体实现而继续发展。

AppC标准应用容器规范

AppC的全称是“Application Container Specification(标准应用容器规范)”,这个规范的制定不是为了服务于特定的Linux系统环境,其初衷在于制定一组不依赖于具体平台、技术、操作系统和编程语言的容器虚拟化规范,解除已经初露端倪的企业容器产品互不兼容、各自封闭发展的危机,防止更多技术壁垒的产生。

正在制定中的AppC容器规范设计目标包括:

  • 组件式工具:用于下载、部署和运行虚拟容器环境的操作工具应该相互独立、互不依赖且可被替换。
  • 镜像安全性:镜像在因特网下载传输时应当使用加密协议,容器工具应当内置验证机制,以拒绝不安全来源的镜像。
  • 操作去中心化:镜像分发应该支持可扩展的传输协议,未来允许引入P2P,甚至BitTorrent协议来提升镜像分发效率,且容器使用前不应需要登录特定的镜像仓库。
  • 开放性标准:容器镜像的格式与元数据定义应该由社区设立统一协商制定,使得符合这一规范的不同容器产品能够共享镜像文件。

为了确保规范的开放并兼顾多方利益,CoreOS作为规范的倡导者、参与者和实施者,但并不会成为其唯一的制定者。

目前已经在遵循AppC的开源应用容器除了Rkt,还有FreeDBSD平台的容器Jet Pack和Linux平台通过C++实现的容器Nose Cone。更好的通用性,更小的入侵性,以及更高的开放性,正是由于这些AppC规范的独具匠心,使得它在Docker如日中天之时,恰逢其时的给业界带来一阵清风,引发许多技术玩家和企业的驻足和思考。

Rkt容器使用尝鲜

且不论AppC的未来发展究竟会如何,远水不解近渴,既然Rkt容器本身是开源免费的,何不自己动手尝试一番。

作为开放式容器标准的样板项目,Rkt自然不会只能用在CoreOS的自家系统里。与Docker相似,Rkt虽然也被预装在了CoreOS系统中,但其他的任何Linux发行版都可以安装并使用它。在接下来的部分里,我们将以比较常见的64位Ubuntu系统为例,演示Rkt的安装和使用方法。

在64位Ubuntu中安装Rkt

事实上,在任何Intel架构的64位Linux中,安装Rkt都简单到极致。这得益于Golang语言原生的静态编译方式,几乎所有编译过的Golang程序都可以下载即运行,而不需要安装额外依赖。

从GitHub网站可以直接下载到打包好的Rkt的二进制文件,目前最新的版本是v0.5.4。Rkt只提供了64位的编译版本,虽然通过自行编译源代码的方式也能够得到32位的可执行文件,但在32位系统上运行Rkt是不被官方推荐和支持的。

wget https://github.com/coreos/rkt/releases/download/v0.5.4/rkt-v0.5.4.tar.gz

下载后得到一个压缩文件。然后,恩,解压它。

tar xzvf rkt-v0.5.4.tar.gz

将解压后得到的文件统统放到系统的可执行目录里面,安装就算完成了。

sudo cp rkt-v0.5.4/* /usr/local/bin/

接下来,试在命令行下执行不带任何参数的rkt version命令,可以看到程序返回了Rkt工具和AppC标准的版本信息,说明Rkt已经正确的安装了。

$ rkt version
rkt version 0.5.4
appc version 0.5.1+git

Rkt工具的组成

工欲善其事,必先利其器。在前面安装Rkt时,我们还没来得及多看一眼,就直接将解压后的文件一股脑儿丢进了系统目录里。这种部署方式虽然方便,但也实在简单粗暴。现在安装完了,至少还是得回头瞅瞅这个目录里到底提供了哪些东西。

不过,这一瞅简直让人失望,偌大一个压缩包,里面就这么俩文件。

$ ls rkt-v0.5.4
rkt  stage1.aci

第一个文件刚刚已经试过了,它是Rkt容器的主程序,所有操作容器的命令都会通过这个命令作为入口。而第二个文件是个非常巧妙的设计。首先它的aci后缀已经表明了它的身份,是一个标准的AppC镜像。如果将这个镜像解包就会看到里面包含的是一套完整的systemd运行环境,其实它的作用,是为Rkt提供了可替换的容器虚拟化实现组件。

Rkt容器默认是采用基于systemd-nspawn命令的机制来处理与内核cgroup和namespace相关操作的,而这个部分正是提供整个容器虚拟化能力的核心环节。Rkt通过将这部分的功能分离到一个可以快速外挂和替换的容器中,从而支持扩展其他的虚拟化实现方式(官方的举例是比如novm或qemu-kvm),并能快速的在这些实现间切换使用。具体来说,只在运行容器时指定--stage1-image参数,设置成其他符合要求的虚拟化实现的镜像地址即可。

此外,AppC规范还提供了一套用于制作和转换“符合AppC容器标准的”镜像的工具,这部分内容将会在系列的下篇中进行详述。

权限与镜像签名

在目前阶段的Rkt还必须通过root用户来执行大多数的命令,不过未来也计划支持如Docker那样使用普通用户运行。在运行Rkt命令时如果出现“permission denied”的错误,请检查是否忘记了sudo。

使用Docker的用户,大多比较习惯在网上随便找到一个镜像地址,就直接pull下来使用。因此,即便Docker官方发现了一些恶意镜像的发布者,也无法有效的阻止这些镜像在网络的传播。

AppC规范中,特别强调了镜像的安全性。为此,在默认情况下,所有镜像在下载和运行前,都必须明确的添加镜像发布者的签名信任,以确保镜像的来源不会被伪造。下面的命令将从官方仓库中获取前缀为“coreos.com/etcd”的签名信息,并添加到本地信任列表中。

$ sudo rkt trust --prefix coreos.com/etcd
Prefix: "coreos.com/etcd"
Key: "https://coreos.com/dist/pubkeys/aci-pubkeys.gpg"
GPG key fingerprint is: 8B86 DE38 890D DB72 9186  7B02 5210 BD88 8818 2190
  CoreOS ACI Builder 
Are you sure you want to trust this key (yes/no)? yes <--输入"yes"回车
Trusting "https://coreos.com/dist/pubkeys/aci-pubkeys.gpg" for prefix "coreos.com/etcd".
Added key for prefix "coreos.com/etcd" at "/etc/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190"

在命令输出的最后一行,Rkt显示了签名在本地保存的位置。查看文件的内容就会发现,这个签名实际上是一个标准的GunPG签名公钥。GunPG是著名RSA非对称加密算法PGP的开源实现,关于PGP算法的介绍可以参考这篇百度百科。

$ cat /etc/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQINBFTCnMQBEAC/49bGbStCpa3peej+/42mobfuGbTcdmcGGwYZmigP0Kl0TPZK
... 省略部分输出 ...
fMkBtaM3knaFonHZc19BD1FOishRThCCq2Ty8HUoN2Fk7w0l
=bYl7
-----END PGP PUBLIC KEY BLOCK-----

获取远程镜像

通过rkt fetch命令可以获取远程的镜像,和Docker的pull命令类似。下面这个命令会从CoreOS的GitHub仓库中下载预装了Etcd的示例容器。

$ sudo rkt fetch coreos.com/etcd:v2.0.9
rkt: searching for app image coreos.com/etcd:v2.0.9
rkt: fetching image from https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
Downloading signature from https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci.asc
Downloading ACI: [=============================================] 3.79 MB/3.79 MB
rkt: signature verified:
  CoreOS ACI Builder 
sha512-91e98d7f1679a097c878203c9659f2a2

值得一提的是,如果用户在上一步中没有添加签名信任,则镜像在下载完成后会由于无法正确的验证来源,而被直接丢弃(不会进入Rkt的本地仓库)。并提示镜像没有签名,或镜像的签名没有被信任。

$ sudo rkt fetch coreos.com/etcd:v2.0.9
...
Downloading ACI: [=============================================] 3.79 MB/3.79 MB
openpgp: signature made by unknown entity

有的时候,用户确实希望下载或导入一个没有签名认证的镜像。可以明确的使用--insecure-skip-verify参数来告诉Rkt不要验证镜像的来源。

$ sudo rkt --insecure-skip-verify fetch coreos.com/etcd:v2.0.9
rkt: searching for app image coreos.com/etcd:v2.0.9
rkt: fetching image from https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
Downloading ACI: [=============================================] 3.79 MB/3.79 MB
sha512-91e98d7f1679a097c878203c9659f2a2

下载完成的镜像会被存储在本地的/var/lib/rkt/cas/blob/sha512/仓库目录中,具体的命名规则是将镜像SHA512哈希值的前两位作为目录名,并以完成的SHA512哈希值作为镜像的文件名。例如刚刚下载的Etcd镜像哈希值为:sha512-91e98d7f1679a097c878203c9659f2a2,它存储的路径如下:

$ tree /var/lib/rkt/cas/blob/sha512/
/var/lib/rkt/cas/blob/sha512/
└── 91
    └── sha512-91e98d7f1679a097c878203c9659f2a26ae394656b3147963324c61fa3832f15

目前Rkt还没有提供一个命令能够快速列出本地仓库里所有镜像名字的方法。这看起来是一个比较匪夷所思的缺失功能。

运行容器

运行Rkt容器的命令是rkt run,可以通过几种方式指定容器使用的镜像。

最常用,也是最方便的方法是使用标准的镜像的命名。比如例子中的coreos.com/etcd:v2.0.9名称:

$ sudo rkt run coreos.com/etcd:v2.0.9
rkt: searching for app image coreos.com/etcd:v2.0.9
rkt: fetching image from https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
...
Press ^] three times to kill container

也可以直接使用镜像的哈希值指定:

$ sudo rkt run sha512-91e98d7f1679a097c878203c9659f2a26ae394656b3147963324c61fa3832f15
...
Press ^] three times to kill container

或者直接指定镜像文件的完整地址,这个地址可以是本地文件,也可以是网络文件,比如这样:

$ sudo rkt run https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
rkt: fetching image from https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
...
Press ^] three times to kill container

使用时可以根据具体情况,哪种方便就用哪种。容器启动后就会自动运行镜像制作时指定的入口程序,连续按Ctrl+]组合键3次则会退出当前容器。

通过--help参数可以显示rkt run命令的可用选项。

$ sudo rkt run --help
Usage:
  -inherit-env=false: inherit all environment variables not set by apps
  -interactive=false: run pod interactively
  -local=false: use only local images (do not discover or download from remote URLs)
  -no-overlay=false: disable overlay filesystem
  -pod-manifest="": the path to the pod manifest. If it's non-empty, then only '--private-net', '--no-overlay' and '--interactive' will have effects
  -port=: ports to expose on the host (requires --private-net)
  -private-net=false: give pod a private network
  -set-env=: an environment variable to set for apps in the form name=value
  -signature=: local signature file to use in validating the preceding image
  -stage1-image="/usr/local/bin/stage1.aci": image to use as stage1. Local paths and http/https URLs are supported. If empty, rkt will look for a file called "stage1.aci" in the same directory as rkt itself
  -volume=: volumes to mount into the pod

比较常用的选项有:

  • --volume外挂分区,类似于Docker的-v参数
  • --port暴露容器中的端口,类似于Docker的-p参数
  • --interactive启用交互模式,类似于Docker的-i加上-t参数的效果
  • --set-env向容器里添加环境变量,类似于Docker的-e参数

对于经常在使用Docker的用户,有两点值得注意的Rkt与Docker运行镜像时不同的地方:

  • 目前还没有与Docker的-d参数相当的运行选项,要后台运行镜像先将就用nohup和&吧。
  • 在任意容器中连续按Ctrl+]组合键3次,都会结束当前容器,不论是否启用了交互模式。

导入本地镜像文件

Rkt导入本地镜像的命令和下载远程镜像是一样的,同样使用rkt fetch。需要留意的是,即便是导入本地镜像,Rkt仍然会强制验证签名(除非指定--insecure-skip-verify参数)。

$ wget https://github.com/coreos/etcd/releases/download/v2.0.9/etcd-v2.0.9-linux-amd64.aci
...
aving to: ‘etcd-v2.0.9-linux-amd64.aci’
100%[=================================>] 3,788,138   1.00MB/s   in 5.1s
‘etcd-v2.0.9-linux-amd64.aci’ saved [3788138/3788138]
$ sudo rkt run etcd-v2.0.9-linux-amd64.aci
error opening signature file: open /home/ubuntu/etcd-v2.0.9-linux-amd64.aci.asc: no such file or directory

默认的签名文件应该和镜像在同一目录下,并且文件名应为镜像名加后缀.asc。如果签名文件的位置或名字与此规范不符,则可以用--signature指定。例如:

sudo rkt run image.aci --signature sign.asc

下载Docker仓库的镜像

Rkt支持直接下载Docker镜像,并自动转换为AppC镜像。这一设计在Docker基础资源如此丰富的当下,真的是很贴心。操作起来也非常简单,只需要在Docker的标准镜像路径前面加上docker://前缀即可。

不过,颇具讽刺意味的是,由于Docker镜像本来是没有签名验证机制的,因此下载任何Docker镜像时,都必须使用--insecure-skip-verify参数。仿佛时刻在提醒用户:这个镜像可能是不安全的!

例如,下载Docker官方仓库的CentOS镜像:

$ sudo rkt --insecure-skip-verify fetch docker://centos
rkt: fetching image from docker://centos
Downloading layer: 6941bfcbbfca7f4f48becd38f2639157042b5cf9ab8c080f1d8b6d047380ecfc
Downloading layer: 41459f052977938b824dd011e1f2bec2cb4d133dfc7e1aa0e90f7c5d337ca9c4
Downloading layer: fd44297e2ddb050ec4fa9752b7a4e3a8439061991886e2091e7c1f007c906d75
sha512-94b712e21c2f88aebcbe67b7e97911c9

直接通过哈希值试运行容器,注意加上--interactive选项:

$ sudo rkt run --interactive sha512-94b712e21c2f88aebcbe67b7e97911c9ed3be062f976cefcebed8baab826ed32
[root@rkt-0ff47941-3934-4dcd-9b9d-3db558f62cd9 /]#

同样的,按三下Ctrl+]则会退出容器。

对于需要登录的Docker仓库,Rkt也提供了下载镜像的解决办法。首先需要在/etc/rkt/auth.d/目录下添加一个用户名命名的配置文件。

$ sudo cat /etc/rkt/auth.d/myuser.json 
{
    "rktKind": "dockerAuth",
    "rktVersion": "v1",
    "registries": ["quay.io"],
    "credentials": {
        "user": "myuser",
        "password": "sekr3tstuff"
    }
}

然后就可以执行fetch了。很方便有木有。

$ sudo rkt --insecure-skip-verify fetch docker://quay.io/myuser/privateapp
rkt: fetching image from docker://quay.io/myuser/privateapp
Downloading layer: cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff
Downloading layer: 6ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea
....

更多功能

通过rkt help命令可以查看到Rkt的更多操作和参数,其中的一些功能还在开发中,具体的进度可以查阅官方文档

$ rkt help
...
COMMANDS:
    enter           Enter the namespaces of an app within a rkt pod
    fetch           Fetch image(s) and store them in the local cache
    gc          Garbage-collect rkt pods no longer in use
    help            Show a list of commands or help for one command
    install         Set up rkt data directories with correct permissions
    list            List pods
    metadata-service    Run metadata service
    prepare         Prepare to run image(s) in a pod in rkt
    run         Run image(s) in a pod in rkt
    run-prepared        Run a prepared application pod in rkt
    status          Check the status of a rkt pod
    trust           Trust a key for image verification
    version         Print the version and exit
GLOBAL OPTIONS:
    --debug=false           Print out more debug information to stderr
    --dir=/var/lib/rkt      rkt data directory
    --help=false            Print usage information and exit
    --insecure-skip-verify=false    skip image or key verification
    --local-config=/etc/rkt     local configuration directory
    --system-config=/usr/lib/rkt    system configuration directory

小结&下期预告

Rkt是CoreOS公司继Etcd后,为Linux社区输出的又一利器。值得指出的是,Rkt项目当前依然处于开发的Alpha时期,距离作为产品发布还有相当的差距。即便如此,其项目本身以及AppC规范在应用容器社区引发的讨论日渐强烈。

AppC规范与Docker的差异到底有多大?在这个系列的下一期中,我们将重点介绍AppC提供的一些标准工具,以及制作AppC容器的方法。并揭秘更多AppC容器与Docker的异同之处。感谢您的阅读。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这