仅支持Linux!
先使用virtualbox安装centos虚拟机,然后ssh。

  • runC提供了cli+libcontainer,而containerd依赖了runC,但实际只用到了libcontainer。
  • containerd作为一个daemon提供服务。
  • cri(containerd cri plugin)作为containerd的client,并作为gRPC Server,向Kubernetes提供服务。

    runC是什么

    runC的前身实际上是Docker的libcontainer项目演化而来。runC实际上就是libcontainer配上了一个轻型的客户端。

从本质上来说,容器是提供一个与宿主机系统共享内核但与系统中的其它进程资源相隔离的执行环境。Docker通过调用libcontainer包对namespaces、cgroups、capabilities以及文件系统的管理和分配来“隔离”出一个上述执行环境。同样的,runC也是对libcontainer包进行调用,去除了Docker包含的诸如镜像、Volume等高级特性,以最朴素简洁的方式达到符合OCF标准的容器管理实现。

总体而言,从libcontainer项目转变为runC项目至今,其功能和特性并没有太多变化,具体有如下几点。

  1. 把原先的nsinit移除,放到外面,命令名称改为runC,同样使用cli.go实现,一目了然。
  2. 按照开放容器标准把原先所有信息混在一起的一个配置文件拆分成config.json和state.json两个。
  3. 增加了按照开放容器标准设定的容器运行前和停止后执行的hook脚本功能。
  4. 相比原先的nsinit时期的指令,增加了runc kill命令,用于发送一个SIG_KILL信号给指定容器ID的init进程。

镜像规范与容器运行时规范

image.png

runC安装

runC

  • go get github.com/opencontainers/runc
  • cd /go/src/github.com/opencontainers/runc
  • make && make install

    runC使用

    容器镜像组成

    https://github.com/opencontainers/runtime-spec/blob/master/bundle.md

  • config.json: contains configuration data. This REQUIRED file MUST reside in the root of the bundle directory and MUST be named config.json. See config.json for more details.

  • container’s root filesystem: the directory referenced by root.path, if that property is set in config.json.

    创建OCI标准的镜像(Bundle,含config配置文件的规范)

    将busybox镜像导出,然后解压缩 ```shell

    create the top most bundle directory

    mkdir /mycontainer cd /mycontainer

create the rootfs directory

mkdir rootfs

export busybox via Docker into the rootfs directory

docker export $(docker create busybox) | tar -C rootfs -xvf -

  1. ![image.png](https://cdn.nlark.com/yuque/0/2019/png/257642/1549209218693-5829ac13-99ec-44ad-b4a6-3b791562b9a7.png#align=left&display=inline&height=67&name=image.png&originHeight=67&originWidth=523&size=13982&width=523)
  2. OCI有两个规范,一个是容器运行时规范`runtime-spec`,一个是镜像格式规范`image-spec`。一个镜像,简单来说就是一个打包好的符合OCI规范的`filesystem bundle`。而bundle的话,是包含一个配置文件`config.json`和一个rootfs目录。<br />现在我们有了一个rootfs目录,然后需要创建一个config.json
  3. ```shell
  4. runc spec

它在当前目录下创建了一个json文件,来描述这个镜像。
对这个文件格式的详细字段介绍,见:https://github.com/opencontainers/runtime-spec/blob/master/config.md
linux特有的配置,见:https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md
如:

  • terminal (bool, OPTIONAL) specifies whether a terminal is attached to the process, defaults to false.
  • args (array of strings, REQUIRED) with similar semantics to IEEE Std 1003.1-2008 execvp‘s argv. This specification extends the IEEE standard in that at least one entry is REQUIRED, and that entry is used with the same semantics as execvp‘s file.

    1. {
    2. "ociVersion": "1.0.1-dev",
    3. "process": {
    4. "terminal": true,
    5. "user": {
    6. "uid": 0,
    7. "gid": 0
    8. },
    9. "args": [
    10. "sh"
    11. ],
    12. "env": [
    13. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    14. "TERM=xterm"
    15. ],
    16. "cwd": "/",
    17. "capabilities": {
    18. "bounding": [
    19. "CAP_AUDIT_WRITE",
    20. "CAP_KILL",
    21. "CAP_NET_BIND_SERVICE"
    22. ],
    23. "effective": [
    24. "CAP_AUDIT_WRITE",
    25. "CAP_KILL",
    26. "CAP_NET_BIND_SERVICE"
    27. ],
    28. "inheritable": [
    29. "CAP_AUDIT_WRITE",
    30. "CAP_KILL",
    31. "CAP_NET_BIND_SERVICE"
    32. ],
    33. "permitted": [
    34. "CAP_AUDIT_WRITE",
    35. "CAP_KILL",
    36. "CAP_NET_BIND_SERVICE"
    37. ],
    38. "ambient": [
    39. "CAP_AUDIT_WRITE",
    40. "CAP_KILL",
    41. "CAP_NET_BIND_SERVICE"
    42. ]
    43. },
    44. "rlimits": [
    45. {
    46. "type": "RLIMIT_NOFILE",
    47. "hard": 1024,
    48. "soft": 1024
    49. }
    50. ],
    51. "noNewPrivileges": true
    52. },
    53. "root": {
    54. "path": "rootfs",
    55. "readonly": true
    56. },
    57. "hostname": "runc",
    58. "mounts": [
    59. {
    60. "destination": "/proc",
    61. "type": "proc",
    62. "source": "proc"
    63. },
    64. {
    65. "destination": "/dev",
    66. "type": "tmpfs",
    67. "source": "tmpfs",
    68. "options": [
    69. "nosuid",
    70. "strictatime",
    71. "mode=755",
    72. "size=65536k"
    73. ]
    74. },
    75. {
    76. "destination": "/dev/pts",
    77. "type": "devpts",
    78. "source": "devpts",
    79. "options": [
    80. "nosuid",
    81. "noexec",
    82. "newinstance",
    83. "ptmxmode=0666",
    84. "mode=0620",
    85. "gid=5"
    86. ]
    87. },
    88. {
    89. "destination": "/dev/shm",
    90. "type": "tmpfs",
    91. "source": "shm",
    92. "options": [
    93. "nosuid",
    94. "noexec",
    95. "nodev",
    96. "mode=1777",
    97. "size=65536k"
    98. ]
    99. },
    100. {
    101. "destination": "/dev/mqueue",
    102. "type": "mqueue",
    103. "source": "mqueue",
    104. "options": [
    105. "nosuid",
    106. "noexec",
    107. "nodev"
    108. ]
    109. },
    110. {
    111. "destination": "/sys",
    112. "type": "sysfs",
    113. "source": "sysfs",
    114. "options": [
    115. "nosuid",
    116. "noexec",
    117. "nodev",
    118. "ro"
    119. ]
    120. },
    121. {
    122. "destination": "/sys/fs/cgroup",
    123. "type": "cgroup",
    124. "source": "cgroup",
    125. "options": [
    126. "nosuid",
    127. "noexec",
    128. "nodev",
    129. "relatime",
    130. "ro"
    131. ]
    132. }
    133. ],
    134. "linux": {
    135. "resources": {
    136. "devices": [
    137. {
    138. "allow": false,
    139. "access": "rwm"
    140. }
    141. ]
    142. },
    143. "namespaces": [
    144. {
    145. "type": "pid"
    146. },
    147. {
    148. "type": "network"
    149. },
    150. {
    151. "type": "ipc"
    152. },
    153. {
    154. "type": "uts"
    155. },
    156. {
    157. "type": "mount"
    158. }
    159. ],
    160. "maskedPaths": [
    161. "/proc/kcore",
    162. "/proc/latency_stats",
    163. "/proc/timer_list",
    164. "/proc/timer_stats",
    165. "/proc/sched_debug",
    166. "/sys/firmware",
    167. "/proc/scsi"
    168. ],
    169. "readonlyPaths": [
    170. "/proc/asound",
    171. "/proc/bus",
    172. "/proc/fs",
    173. "/proc/irq",
    174. "/proc/sys",
    175. "/proc/sysrq-trigger"
    176. ]
    177. }
    178. }

    启动容器(含运行时规范)

    一种方式是直接启动

  • cd /mycontainer

  • runc run 容器名(自己起,要求唯一)
  • 启动后直接进入终端,exit后容器被关闭

还有一种方式是分步进行:
想要后台启动的话,需要修改config.json:
"terminal": false and "args": ["sleep", "5"].

  1. # run as root
  2. cd /mycontainer
  3. runc create mycontainerid
  4. # view the container is created and in the "created" state
  5. runc list
  6. # start the process inside the container
  7. runc start mycontainerid
  8. # after 5 seconds view that the container has exited and is now in the stopped state
  9. runc list
  10. # now delete the container
  11. runc delete mycontainerid

运行时会在/run/runc下创建一个以容器名为名字的目录,然后下面存放state.json和exec.fifo。
image.png

state.json(create后,start前)

state.json文件中包含的具体信息需要有:

  • 版本信息:存放OCI标准的具体版本号。
  • 容器ID:通常是一个哈希值,也可以是一个易读的字符串。在state.json文件中加入容器ID是为了便于之前提到的运行时hooks只需载入state.json就可以定位到容器,然后检测state.json,发现文件不见了就认为容器关停,再执行相应预定义的脚本操作。
  • PID:容器中运行的首个进程在宿主机上的进程号。
  • 容器文件目录:存放容器rootfs及相应配置的目录。外部程序只需读取state.json就可以定位到宿主机上的容器文件目录。 标准的容器生命周期应该包含三个基本过程。
  • 容器创建:创建包括文件系统、namespaces、cgroups、用户权限在内的各项内容。
  • 容器进程的启动:运行容器进程,进程的可执行文件定义在的config.json中,args项。
  • 容器暂停:容器实际上作为进程可以被外部程序关停(kill),然后容器标准规范应该包含对容器暂停信号的捕获,并做相应资源回收的处理,避免孤儿进程的出现。
    1. {
    2. "id": "busybox",
    3. "init_process_pid": 14222,
    4. "init_process_start": 778857,
    5. "created": "2019-02-03T16:55:14.72045592Z",
    6. "config": {
    7. "no_pivot_root": false,
    8. "parent_death_signal": 0,
    9. "rootfs": "/mycontainer/rootfs",
    10. "readonlyfs": true,
    11. "rootPropagation": 0,
    12. "mounts": [{
    13. "source": "proc",
    14. "destination": "/proc",
    15. "device": "proc",
    16. "flags": 0,
    17. "propagation_flags": null,
    18. "data": "",
    19. "relabel": "",
    20. "extensions": 0,
    21. "premount_cmds": null,
    22. "postmount_cmds": null
    23. }, {
    24. "source": "tmpfs",
    25. "destination": "/dev",
    26. "device": "tmpfs",
    27. "flags": 16777218,
    28. "propagation_flags": null,
    29. "data": "mode=755,size=65536k",
    30. "relabel": "",
    31. "extensions": 0,
    32. "premount_cmds": null,
    33. "postmount_cmds": null
    34. }, {
    35. "source": "devpts",
    36. "destination": "/dev/pts",
    37. "device": "devpts",
    38. "flags": 10,
    39. "propagation_flags": null,
    40. "data": "newinstance,ptmxmode=0666,mode=0620,gid=5",
    41. "relabel": "",
    42. "extensions": 0,
    43. "premount_cmds": null,
    44. "postmount_cmds": null
    45. }, {
    46. "source": "shm",
    47. "destination": "/dev/shm",
    48. "device": "tmpfs",
    49. "flags": 14,
    50. "propagation_flags": null,
    51. "data": "mode=1777,size=65536k",
    52. "relabel": "",
    53. "extensions": 0,
    54. "premount_cmds": null,
    55. "postmount_cmds": null
    56. }, {
    57. "source": "mqueue",
    58. "destination": "/dev/mqueue",
    59. "device": "mqueue",
    60. "flags": 14,
    61. "propagation_flags": null,
    62. "data": "",
    63. "relabel": "",
    64. "extensions": 0,
    65. "premount_cmds": null,
    66. "postmount_cmds": null
    67. }, {
    68. "source": "sysfs",
    69. "destination": "/sys",
    70. "device": "sysfs",
    71. "flags": 15,
    72. "propagation_flags": null,
    73. "data": "",
    74. "relabel": "",
    75. "extensions": 0,
    76. "premount_cmds": null,
    77. "postmount_cmds": null
    78. }, {
    79. "source": "cgroup",
    80. "destination": "/sys/fs/cgroup",
    81. "device": "cgroup",
    82. "flags": 2097167,
    83. "propagation_flags": null,
    84. "data": "",
    85. "relabel": "",
    86. "extensions": 0,
    87. "premount_cmds": null,
    88. "postmount_cmds": null
    89. }],
    90. "devices": [{
    91. "type": 99,
    92. "path": "/dev/null",
    93. "major": 1,
    94. "minor": 3,
    95. "permissions": "",
    96. "file_mode": 438,
    97. "uid": 0,
    98. "gid": 0,
    99. "allow": false
    100. }, {
    101. "type": 99,
    102. "path": "/dev/random",
    103. "major": 1,
    104. "minor": 8,
    105. "permissions": "",
    106. "file_mode": 438,
    107. "uid": 0,
    108. "gid": 0,
    109. "allow": false
    110. }, {
    111. "type": 99,
    112. "path": "/dev/full",
    113. "major": 1,
    114. "minor": 7,
    115. "permissions": "",
    116. "file_mode": 438,
    117. "uid": 0,
    118. "gid": 0,
    119. "allow": false
    120. }, {
    121. "type": 99,
    122. "path": "/dev/tty",
    123. "major": 5,
    124. "minor": 0,
    125. "permissions": "",
    126. "file_mode": 438,
    127. "uid": 0,
    128. "gid": 0,
    129. "allow": false
    130. }, {
    131. "type": 99,
    132. "path": "/dev/zero",
    133. "major": 1,
    134. "minor": 5,
    135. "permissions": "",
    136. "file_mode": 438,
    137. "uid": 0,
    138. "gid": 0,
    139. "allow": false
    140. }, {
    141. "type": 99,
    142. "path": "/dev/urandom",
    143. "major": 1,
    144. "minor": 9,
    145. "permissions": "",
    146. "file_mode": 438,
    147. "uid": 0,
    148. "gid": 0,
    149. "allow": false
    150. }],
    151. "mount_label": "",
    152. "hostname": "runc",
    153. "namespaces": [{
    154. "type": "NEWPID",
    155. "path": ""
    156. }, {
    157. "type": "NEWNET",
    158. "path": ""
    159. }, {
    160. "type": "NEWIPC",
    161. "path": ""
    162. }, {
    163. "type": "NEWUTS",
    164. "path": ""
    165. }, {
    166. "type": "NEWNS",
    167. "path": ""
    168. }],
    169. "capabilities": {
    170. "Bounding": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
    171. "Effective": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
    172. "Inheritable": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
    173. "Permitted": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
    174. "Ambient": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"]
    175. },
    176. "networks": [{
    177. "type": "loopback",
    178. "name": "",
    179. "bridge": "",
    180. "mac_address": "",
    181. "address": "",
    182. "gateway": "",
    183. "ipv6_address": "",
    184. "ipv6_gateway": "",
    185. "mtu": 0,
    186. "txqueuelen": 0,
    187. "host_interface_name": "",
    188. "hairpin_mode": false
    189. }],
    190. "routes": null,
    191. "cgroups": {
    192. "name": "busybox",
    193. "path": "",
    194. "scope_prefix": "",
    195. "Paths": null,
    196. "allowed_devices": [{
    197. "type": 99,
    198. "path": "",
    199. "major": -1,
    200. "minor": -1,
    201. "permissions": "m",
    202. "file_mode": 0,
    203. "uid": 0,
    204. "gid": 0,
    205. "allow": true
    206. }, {
    207. "type": 98,
    208. "path": "",
    209. "major": -1,
    210. "minor": -1,
    211. "permissions": "m",
    212. "file_mode": 0,
    213. "uid": 0,
    214. "gid": 0,
    215. "allow": true
    216. }, {
    217. "type": 99,
    218. "path": "/dev/null",
    219. "major": 1,
    220. "minor": 3,
    221. "permissions": "rwm",
    222. "file_mode": 0,
    223. "uid": 0,
    224. "gid": 0,
    225. "allow": true
    226. }, {
    227. "type": 99,
    228. "path": "/dev/random",
    229. "major": 1,
    230. "minor": 8,
    231. "permissions": "rwm",
    232. "file_mode": 0,
    233. "uid": 0,
    234. "gid": 0,
    235. "allow": true
    236. }, {
    237. "type": 99,
    238. "path": "/dev/full",
    239. "major": 1,
    240. "minor": 7,
    241. "permissions": "rwm",
    242. "file_mode": 0,
    243. "uid": 0,
    244. "gid": 0,
    245. "allow": true
    246. }, {
    247. "type": 99,
    248. "path": "/dev/tty",
    249. "major": 5,
    250. "minor": 0,
    251. "permissions": "rwm",
    252. "file_mode": 0,
    253. "uid": 0,
    254. "gid": 0,
    255. "allow": true
    256. }, {
    257. "type": 99,
    258. "path": "/dev/zero",
    259. "major": 1,
    260. "minor": 5,
    261. "permissions": "rwm",
    262. "file_mode": 0,
    263. "uid": 0,
    264. "gid": 0,
    265. "allow": true
    266. }, {
    267. "type": 99,
    268. "path": "/dev/urandom",
    269. "major": 1,
    270. "minor": 9,
    271. "permissions": "rwm",
    272. "file_mode": 0,
    273. "uid": 0,
    274. "gid": 0,
    275. "allow": true
    276. }, {
    277. "type": 99,
    278. "path": "/dev/console",
    279. "major": 5,
    280. "minor": 1,
    281. "permissions": "rwm",
    282. "file_mode": 0,
    283. "uid": 0,
    284. "gid": 0,
    285. "allow": true
    286. }, {
    287. "type": 99,
    288. "path": "",
    289. "major": 136,
    290. "minor": -1,
    291. "permissions": "rwm",
    292. "file_mode": 0,
    293. "uid": 0,
    294. "gid": 0,
    295. "allow": true
    296. }, {
    297. "type": 99,
    298. "path": "",
    299. "major": 5,
    300. "minor": 2,
    301. "permissions": "rwm",
    302. "file_mode": 0,
    303. "uid": 0,
    304. "gid": 0,
    305. "allow": true
    306. }, {
    307. "type": 99,
    308. "path": "",
    309. "major": 10,
    310. "minor": 200,
    311. "permissions": "rwm",
    312. "file_mode": 0,
    313. "uid": 0,
    314. "gid": 0,
    315. "allow": true
    316. }],
    317. "devices": [{
    318. "type": 97,
    319. "path": "",
    320. "major": -1,
    321. "minor": -1,
    322. "permissions": "rwm",
    323. "file_mode": 0,
    324. "uid": 0,
    325. "gid": 0,
    326. "allow": false
    327. }, {
    328. "type": 99,
    329. "path": "",
    330. "major": -1,
    331. "minor": -1,
    332. "permissions": "m",
    333. "file_mode": 0,
    334. "uid": 0,
    335. "gid": 0,
    336. "allow": true
    337. }, {
    338. "type": 98,
    339. "path": "",
    340. "major": -1,
    341. "minor": -1,
    342. "permissions": "m",
    343. "file_mode": 0,
    344. "uid": 0,
    345. "gid": 0,
    346. "allow": true
    347. }, {
    348. "type": 99,
    349. "path": "/dev/null",
    350. "major": 1,
    351. "minor": 3,
    352. "permissions": "rwm",
    353. "file_mode": 0,
    354. "uid": 0,
    355. "gid": 0,
    356. "allow": true
    357. }, {
    358. "type": 99,
    359. "path": "/dev/random",
    360. "major": 1,
    361. "minor": 8,
    362. "permissions": "rwm",
    363. "file_mode": 0,
    364. "uid": 0,
    365. "gid": 0,
    366. "allow": true
    367. }, {
    368. "type": 99,
    369. "path": "/dev/full",
    370. "major": 1,
    371. "minor": 7,
    372. "permissions": "rwm",
    373. "file_mode": 0,
    374. "uid": 0,
    375. "gid": 0,
    376. "allow": true
    377. }, {
    378. "type": 99,
    379. "path": "/dev/tty",
    380. "major": 5,
    381. "minor": 0,
    382. "permissions": "rwm",
    383. "file_mode": 0,
    384. "uid": 0,
    385. "gid": 0,
    386. "allow": true
    387. }, {
    388. "type": 99,
    389. "path": "/dev/zero",
    390. "major": 1,
    391. "minor": 5,
    392. "permissions": "rwm",
    393. "file_mode": 0,
    394. "uid": 0,
    395. "gid": 0,
    396. "allow": true
    397. }, {
    398. "type": 99,
    399. "path": "/dev/urandom",
    400. "major": 1,
    401. "minor": 9,
    402. "permissions": "rwm",
    403. "file_mode": 0,
    404. "uid": 0,
    405. "gid": 0,
    406. "allow": true
    407. }, {
    408. "type": 99,
    409. "path": "/dev/console",
    410. "major": 5,
    411. "minor": 1,
    412. "permissions": "rwm",
    413. "file_mode": 0,
    414. "uid": 0,
    415. "gid": 0,
    416. "allow": true
    417. }, {
    418. "type": 99,
    419. "path": "",
    420. "major": 136,
    421. "minor": -1,
    422. "permissions": "rwm",
    423. "file_mode": 0,
    424. "uid": 0,
    425. "gid": 0,
    426. "allow": true
    427. }, {
    428. "type": 99,
    429. "path": "",
    430. "major": 5,
    431. "minor": 2,
    432. "permissions": "rwm",
    433. "file_mode": 0,
    434. "uid": 0,
    435. "gid": 0,
    436. "allow": true
    437. }, {
    438. "type": 99,
    439. "path": "",
    440. "major": 10,
    441. "minor": 200,
    442. "permissions": "rwm",
    443. "file_mode": 0,
    444. "uid": 0,
    445. "gid": 0,
    446. "allow": true
    447. }],
    448. "memory": 0,
    449. "memory_reservation": 0,
    450. "memory_swap": 0,
    451. "kernel_memory": 0,
    452. "kernel_memory_tcp": 0,
    453. "cpu_shares": 0,
    454. "cpu_quota": 0,
    455. "cpu_period": 0,
    456. "cpu_rt_quota": 0,
    457. "cpu_rt_period": 0,
    458. "cpuset_cpus": "",
    459. "cpuset_mems": "",
    460. "pids_limit": 0,
    461. "blkio_weight": 0,
    462. "blkio_leaf_weight": 0,
    463. "blkio_weight_device": null,
    464. "blkio_throttle_read_bps_device": null,
    465. "blkio_throttle_write_bps_device": null,
    466. "blkio_throttle_read_iops_device": null,
    467. "blkio_throttle_write_iops_device": null,
    468. "freezer": "",
    469. "hugetlb_limit": null,
    470. "oom_kill_disable": false,
    471. "memory_swappiness": null,
    472. "net_prio_ifpriomap": null,
    473. "net_cls_classid_u": 0
    474. },
    475. "uid_mappings": null,
    476. "gid_mappings": null,
    477. "mask_paths": ["/proc/kcore", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/sys/firmware", "/proc/scsi"],
    478. "readonly_paths": ["/proc/asound", "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger"],
    479. "sysctl": null,
    480. "seccomp": null,
    481. "Hooks": {
    482. "poststart": null,
    483. "poststop": null,
    484. "prestart": null
    485. },
    486. "version": "1.0.1-dev",
    487. "labels": ["bundle=/mycontainer"],
    488. "no_new_keyring": false
    489. },
    490. "rootless": false,
    491. "cgroup_paths": {
    492. "blkio": "/sys/fs/cgroup/blkio/user.slice/busybox",
    493. "cpu": "/sys/fs/cgroup/cpu,cpuacct/user.slice/busybox",
    494. "cpuacct": "/sys/fs/cgroup/cpu,cpuacct/user.slice/busybox",
    495. "cpuset": "/sys/fs/cgroup/cpuset/busybox",
    496. "devices": "/sys/fs/cgroup/devices/user.slice/busybox",
    497. "freezer": "/sys/fs/cgroup/freezer/busybox",
    498. "hugetlb": "/sys/fs/cgroup/hugetlb/busybox",
    499. "memory": "/sys/fs/cgroup/memory/user.slice/busybox",
    500. "name=systemd": "/sys/fs/cgroup/systemd/user.slice/user-0.slice/session-4.scope/busybox",
    501. "net_cls": "/sys/fs/cgroup/net_cls,net_prio/busybox",
    502. "net_prio": "/sys/fs/cgroup/net_cls,net_prio/busybox",
    503. "perf_event": "/sys/fs/cgroup/perf_event/busybox",
    504. "pids": "/sys/fs/cgroup/pids/busybox"
    505. },
    506. "namespace_paths": {
    507. "NEWIPC": "/proc/14222/ns/ipc",
    508. "NEWNET": "/proc/14222/ns/net",
    509. "NEWNS": "/proc/14222/ns/mnt",
    510. "NEWPID": "/proc/14222/ns/pid",
    511. "NEWUSER": "/proc/14222/ns/user",
    512. "NEWUTS": "/proc/14222/ns/uts"
    513. },
    514. "external_descriptors": ["/dev/pts/0", "/dev/pts/0", "/dev/pts/0"],
    515. "intel_rdt_path": ""
    516. }

image.png

容器运行时的规范,见https://github.com/opencontainers/runtime-spec/blob/master/runtime.md
linux特有的规范,见https://github.com/opencontainers/runtime-spec/blob/master/runtime-linux.md

更多命令

使用 create 命令创建容器
进入到 /tmp/mycontainer 目录中:
$ cd /tmp/mycontainer
然后创建名为 mybusybox 的容器: $ sudo runc create mybusybox使用 list 命令查看当前存在的容器 $ sudo runc listrunC使用 - 图4
使用 state 命令查看容器的状态 $ sudo runc state mybusyboxrunC使用 - 图5
注意图中的 “status”: “created”,当通过 create 成功创建了容器后,容器的状态就是 “created”。
使用 ps 命令看看容器内运行的进程 $ sudo runc ps mybusyboxrunC使用 - 图6
此时 mybusybox 容器内有一个名为 init 的进程在运行。
使用 start 命令执行容器中定义的任务 $ sudo runc start使用 start 命令启动容器后,让我们再用 ps 命令看看容器内运行了什么进程:
runC使用 - 图7
此时我们在 config.json 中定义的 sleep 进程在运行。再用 state 命令看看容器此时的状态,此时已经变成了 running!
使用 exec 命令在容器中执行命令
通过 exec 命令我们可以在处于 created 状态和 running 状态的容器中执行命令: $ sudo runc exec mybusybox lsrunC使用 - 图8
当容器中的用户任务结束后,容器会变成 stopped 状态,这时就不能再通过 exec 执行其它的命令了。
使用 delete 命令删除容器
我们可以通过 delete 命令删除容器,当然,一般情况下是删除 stopped 状态的容器: $ sudo runc delete mybusybox使用 run 命令创建并运行容器
就像 docker run 命令一样,它会创建容器并运行容器中的命令: $ sudo runc run mybusybox当容器中的命令退出后容器随即被删除。
使用 kill 命令停止容器中的任务
如果要停止一个容器中正在运行的任务,可以使用 kill 命令: $ sudo runc kill mybusybox默认它会优雅的结束容器中的进程,但是碰到特殊情况,你就得使用终极信号 9: $ sudo runc kill mybusybox 9使用 pause 命令暂停容器中的所有进程
我们先启动容器 mybusybox,然后用 pause 命令暂停它: $ sudo runc pause mybusyboxrunC使用 - 图9
执行 pause 命令后,容器的状态由 running 变成了 paused。然后我们再通过 resume 命令恢复容器中进程的执行: $ sudo runc resume mybusyboxrunC使用 - 图10
此时容器的状态又恢复到了 running。
使用 events 命令获取容器的资源使用情况
events 命令能够向我们报告容器事件及其资源占用的统计信息: $ sudo runc events mybusyboxrunC使用 - 图11

rootless containers
前面我们运行的所有命令都是以 root 权限执行的。能不能以普通用户的权限运行容器呢?答案是可以的,并被称为 rootless。要想以 rootless 的方式运行容器,需要我们在生成容器的配置文件时就为 spec 命令指定 rootless 参数:
$ runc spec —rootless
并且在运行容器时通过 —root 参数指定一个存放容器状态的路径:
$ runc —root /tmp/runc run mybusybox

CLI

USAGE:
runc [global options] command [command options] [arguments…]
VERSION:
1.0.0-rc6+dev
commit: 96ec2177ae841256168fcf76954f7177af9446eb
spec: 1.0.1-dev
COMMANDS:
checkpoint checkpoint a running container
create create a container
delete delete any resources held by the container often used with detached container
events display container events such as OOM notifications, cpu, memory, and IO usage statistics
exec execute new process inside the container
init initialize the namespaces and launch the process (do not call it outside of runc)
kill kill sends the specified signal (default: SIGTERM) to the container’s init process
list lists containers started by runc with the given root
pause pause suspends all processes inside the container
ps ps displays the processes running inside a container
restore restore a container from a previous checkpoint
resume resumes all processes that have been previously paused
run create and run a container
spec create a new specification file
start executes the user defined process in a created container
state output the state of a container
update update container resource constraints
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
—debug enable debug output for logging
—log value set the log file path where internal debug information is written (default: “/dev/null”)
—log-format value set the format used by logs (‘text’ (default), or ‘json’) (default: “text”)
—root value root directory for storage of container state (this should be located in tmpfs) (default: “/run/runc”)
—criu value path to the criu binary used for checkpoint and restore (default: “criu”)
—systemd-cgroup enable systemd cgroup support, expects cgroupsPath to be of form “slice:prefix:name” for e.g. “system.slice:runc:434234”
—rootless value ignore cgroup permission errors (‘true’, ‘false’, or ‘auto’) (default: “auto”)
—help, -h show help
—version, -v print the version

标准容器的5个原则

https://github.com/opencontainers/runtime-spec/blob/master/principles.md

  • 操作标准化:容器的标准化操作包括使用标准容器创建、启动、停止容器,使用标准文件系统工具复制和创建容器快照,使用标准化网络工具进行下载和上传。
  • 内容无关:内容无关指不管针对的具体容器内容是什么,容器标准操作执行后都能产生同样的效果。如容器可以用同样的方式上传、启动,不管是PHP应用还是MySQL数据库服务。
  • 基础设施无关:无论是个人的笔记本电脑还是AWS S3,亦或是OpenStack,或者其它基础设施,都应该对支持容器的各项操作。
  • 为自动化量身定制:制定容器统一标准,是的操作内容无关化、平台无关化的根本目的之一,就是为了可以使容器操作全平台自动化。
  • 工业级交付:制定容器标准一大目标,就是使软件分发可以达到工业级交付成为现实。

    镜像格式规范

    https://github.com/opencontainers/image-spec/blob/master/spec.md

The OCI Image Media Types document is a starting point to understanding the overall structure of the specification.
The high-level components of the spec include:

  • Image Manifest - a document describing the components that make up a container image
  • Image Index - an annotated index of image manifests
  • Image Layout - a filesystem layout representing the contents of an image
  • Filesystem Layer - a changeset that describes a container’s filesystem
  • Image Configuration - a document determining layer ordering and configuration of the image suitable for translation into a runtime bundle
  • Conversion - a document describing how this translation should occur
  • Descriptor - a reference that describes the type, metadata and content address of referenced content

OCI 容器镜像主要包括几块内容: