使用runc運行alpine_linux容器


上一篇使用runc與oci-image-tool運行容器中雖然成功使用runc運行起來了容器,但遇到了不少問題。本文再次講述使用runc運行alpine linux容器,並解決上一次出現的相關問題。

: 本文命令均在Ubuntu 18.04x64下運行通過

下載 解壓鏡像

skopeo與oci-image-tool分別用來下載與解壓鏡像,Ubuntu上兩個工具需要從源碼編譯安裝,而且需要提前配置好Go語言環境。

  • 使用skopeo copy docker://alpine:latest oci:alpine下載鏡像,skopeo的安裝與使用參考Skopeo-Github,運行結果
    eric@ubuntu:~/images_tmp$ skopeo copy docker://alpine:latest oci:alpine
    Getting image source signatures
    Copying blob 89d9c30c1d48 done
    Copying config 759e71f0d3 done
    Writing manifest to image destination
    Storing signatures
    
  • 使用oci-image-tool create --ref platform.os=linux alpine alpine-bundle製作符合OCI規範的鏡像,oci-image-tool的安裝與使用參考image-tools Github
    eric@ubuntu:~/images_tmp$ ls -l alpine-bundle/
    total 8
    -rw-rw-r--  1 eric eric  217 Nov  9 11:51 config.json
    drwxr-x--- 19 eric eric 4096 Nov  9 11:51 rootfs
    
    rootfs爲根文件系統,config.json爲符合runtime-spec的配置文件

配置 運行

: 此處要運行的是具有root權限的容器,因此不創建新的User Namespace

已知信息

  1. capabilities權限信息: 容器必須具有權限去執行操作,config.json文件中可以現在容器內部權限

  2. mount掛載信息: 系統級容器需要掛載必備的文件系統,如proc sys cgroup

  3. 文件系統中目錄、文件的可讀可執行權限: 從根目錄到容器文件系統內的所有文件夾,以及文件系統內的所有文件/文件夾(/home/.../alpine-bundle/rootfs/*)需要至少具有rwxrwxr-x(775)權限,否則可能會遇到各種各樣的permission denied,可以參考Can’t change to home directory, unable-to-su-with-root-bin-bash-permission-denied的第二個回答

具體過程

  • 刪除image-tool生成的config.json,該json文件缺少必要的mount、capabilities等信息

  • 使用runc spec命令生成一個新的config.json文件,關於runc的使用,參考runc-Github

  • 修改config.json文件,如下爲修改完後的文件,參考rumtime-spec:

    {
        "ociVersion": "1.0.1-dev",
        "process": {
            "terminal": true,
            "user": {
                "uid": 0,
                "gid": 0
            },
            "args": [
                "/bin/ash"
            ],
            "env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "cwd": "/",
            "capabilities": {
                "bounding": [
                    "CAP_AUDIT_WRITE",
                    "CAP_KILL",
                    "CAP_NET_BIND_SERVICE",
                    "CAP_SETUID",
                    "CAP_SETGID",
                    "CAP_CHOWN",
                    "CAP_SYS_ADMIN",
                    "CAP_SETFCAP",
                    "CAP_SETPCAP",
                    "CAP_FOWNER"
                ],
                "effective": [
                    "CAP_AUDIT_WRITE",
                    "CAP_KILL",
                    "CAP_NET_BIND_SERVICE",
                    "CAP_SETUID",
                    "CAP_SETGID",
                    "CAP_CHOWN",
                    "CAP_SYS_ADMIN",
                    "CAP_SETFCAP",
                    "CAP_SETPCAP",
                    "CAP_FOWNER"
                ],
                "inheritable": [
                    "CAP_AUDIT_WRITE",
                    "CAP_KILL",
                    "CAP_NET_BIND_SERVICE",
                    "CAP_SETUID",
                    "CAP_SETGID",
                    "CAP_CHOWN",
                    "CAP_SYS_ADMIN",
                    "CAP_SETFCAP",
                    "CAP_SETPCAP",
                    "CAP_FOWNER"
                ],
                "permitted": [
                    "CAP_AUDIT_WRITE",
                    "CAP_KILL",
                    "CAP_NET_BIND_SERVICE",
                    "CAP_SETUID",
                    "CAP_SETGID",
                    "CAP_CHOWN",
                    "CAP_SYS_ADMIN",
                    "CAP_SETFCAP",
                    "CAP_SETPCAP",
                    "CAP_FOWNER"
                ],
                "ambient": [
                    "CAP_AUDIT_WRITE",
                    "CAP_KILL",
                    "CAP_NET_BIND_SERVICE",
                    "CAP_SETUID",
                    "CAP_SETGID",
                    "CAP_CHOWN",
                    "CAP_SYS_ADMIN",
                    "CAP_SETFCAP",
                    "CAP_SETPCAP",
                    "CAP_FOWNER"
                ]
            }
        },
        "root": {
            "path": "rootfs",
            "readonly": false
        },
        "mounts": [
            {
                "destination": "/proc",
                "type": "proc",
                "source": "proc"
            },
            {
                "destination": "/dev",
                "type": "tmpfs",
                "source": "tmpfs",
                "options": [
                    "nosuid",
                    "strictatime",
                    "mode=755",
                    "size=65536k"
                ]
            },
            {
                "destination": "/dev/pts",
                "type": "devpts",
                "source": "devpts",
                "options": [
                    "nosuid",
                    "noexec",
                    "newinstance",
                    "ptmxmode=0666",
                    "mode=0620",
                    "gid=5"
                ]
            },
            {
                "destination": "/dev/shm",
                "type": "tmpfs",
                "source": "shm",
                "options": [
                    "nosuid",
                    "noexec",
                    "nodev",
                    "mode=1777",
                    "size=65536k"
                ]
            },
            {
                "destination": "/dev/mqueue",
                "type": "mqueue",
                "source": "mqueue",
                "options": [
                    "nosuid",
                    "noexec",
                    "nodev"
                ]
            },
            {
                "destination": "/sys",
                "type": "sysfs",
                "source": "sysfs",
                "options": [
                    "nosuid",
                    "noexec",
                    "nodev",
                    "ro"
                ]
            },
            {
                "destination": "/sys/fs/cgroup",
                "type": "cgroup",
                "source": "cgroup",
                "options": [
                    "nosuid",
                    "noexec",
                    "nodev",
                    "relatime",
                    "ro"
                ]
            }
        ],
        "linux": {
            "namespaces": [
                {
                    "type": "pid"
                },
                {
                    "type": "network"
                },
                {
                    "type": "ipc"
                },
                {
                    "type": "uts"
                },
                {
                    "type": "mount"
                }
            ]
        }
    }
    

    主要在於修改capabilities中的一些CAP_SETUID CAP_SETGID CAP_FOWNER權限以及mount中的信息

  • 確保路徑/.../alpine-bundle的文件夾都有執行權限,沒有的話可以使用chmod +x file_dir_name命令添加

  • 確保alpine-bundle/下的所有文件都有必須的執行權限,這裏我們直接chmod 775 -R alpine-bundle/

  • 由於runc目前存在的問題fix permission denied,我們需要將alpine-bundle的owner改成root,執行chown root:root -R alpine-bundle/,如下爲rootfs下的文件信息

    eric@ubuntu:~/images_tmp$ lsl alpine-bundle/rootfs/
    total 68
    drwxrwxr-x  2 root root 4096 Oct 21 21:39 bin
    drwxrwxr-x  2 root root 4096 Oct 21 21:39 dev
    ...
    drwxrwxr-x  7 root root 4096 Oct 21 21:39 usr
    drwxrwxr-x 11 root root 4096 Oct 21 21:39 var
    
  • 在當前文件夾下alpine-bundle/下執行sudo runc run hello,其中hello爲容器的名字

    eric@ubuntu:~/images_tmp/alpine-bundle$ sudo runc run hello
    / # whoami
    root
    
  • 執行adduser命令並login

    / # adduser jeff
    Changing password for jeff
    New password:
    Bad password: too short
    Retype password:
    passwd: password for jeff changed by root
    / # login jeff
    Password:
    Welcome to Alpine!
    
    The Alpine Wiki contains a large amount of how-to guides and general
    information about administrating Alpine systems.
    See <http://wiki.alpinelinux.org/>.
    
    You can setup the system with the command: setup-alpine
    
    You may change this message by editing /etc/motd.
    
    ubuntu:~$
    

    能夠正常添加用戶並登陸了。

問題與解決

如果按照上述過程執行的話應該不會遇到問題,如下的問題是我在摸索過程中遇到的,感興趣的可以參考。

  1. root運行runc run出現chdir錯誤

    1. 原因是目標目錄的owner與當前用戶(root)不同,一個解決方案是chown,參考#2086
  2. alpine容器內添加用戶adduser出錯 - permission denied

    1. 容器權限 - 容器需要setuid, setgid, setfcap等權限
    2. 目錄可執行位 - 容器文件系統目錄及其父目錄需要有所有用戶的可執行權限(755: rwxrwxr-x)
  3. alpine容器login/su出錯 - login: can't execute '/bin/ash': Permission denied

    1. 目錄可讀、可執行位(chmod 755),使用chmod 755 -R rootfs命令將所有文件權限設爲可讀,參考Can’t change to home directory
    2. 鏈接庫的可執行位,使用ldd命令查看鏈接庫,與1同理,參考unable-to-su-with-root-bin-bash-permission-denied的第二個回答

總結

Linux的權限信息比較複雜,感興趣的可以參考手冊。本文主要以記錄爲主,歡迎評論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章