使用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的权限信息比较复杂,感兴趣的可以参考手册。本文主要以记录为主,欢迎评论。

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