重要
此功能不稳定。随着此功能的不断发展,API 可能无法维护,并且功能可能会更改或删除。
启用此功能并在集群中运行 runC 容器会产生安全影响。鉴于 runC 与许多强大的内核功能集成,因此管理员在启用此功能之前必须了解 runC 安全性。
runC是一个 CLI 工具,用于根据开放容器计划 (OCI) 规范生成和运行容器。runC 最初是 从原始 Docker 基础设施中 分离出来的。结合通过 squashFS 映像创建的 rootfs 挂载点,runC 使用户能够将应用程序与其首选执行环境捆绑在一起,以便在目标计算机上执行。有关 OCI 的更多信息,请参阅其 网站。
Linux 容器执行器 (LCE) 允许 YARN NodeManager 启动 YARN 容器,以便直接在主机上、Docker 容器内以及现在 runC 容器内运行。请求资源的应用程序可以为每个容器指定其执行方式。LCE 还提供增强的安全性,并且在部署安全集群时需要。当 LCE 启动 YARN 容器在 runC 容器中执行时,应用程序可以指定要使用的 runC 映像。这些 runC 映像可以从 Docker 映像构建。
runC 容器提供了一个自定义执行环境,应用程序的代码在其中运行,与 NodeManager 和其他应用程序的执行环境隔离。这些容器可以包含应用程序所需的特殊库,并且它们可以具有不同版本的原生工具和库,包括 Perl、Python 和 Java。runC 容器甚至可以运行不同版本的 Linux,而不是在 NodeManager 上运行的版本。
用于 YARN 的 runC 提供了一致性(所有 YARN 容器都将具有相同的软件环境)和隔离性(不会干扰物理机上安装的任何内容)。
LCE 中的 runC 支持仍在不断发展。要跟踪进度并查看 runC 设计文档,请查看 YARN-9014,这是 runC 支持改进的总括性 JIRA。
LCE 要求容器执行器二进制文件归 root:hadoop 所有并具有 6050 权限。为了启动 runC 容器,必须在将启动 runC 容器的所有 NodeManager 主机上安装 runC。
应在 yarn-site.xml 中设置以下属性
<configuration> <property> <name>yarn.nodemanager.container-executor.class</name> <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value> <description> This is the container executor setting that ensures that all applications are started with the LinuxContainerExecutor. </description> </property> <property> <name>yarn.nodemanager.linux-container-executor.group</name> <value>hadoop</value> <description> The POSIX group of the NodeManager. It should match the setting in "container-executor.cfg". This configuration is required for validating the secure access of the container-executor binary. </description> </property> <property> <name>yarn.nodemanager.linux-container-executor.nonsecure-mode.limit-users</name> <value>false</value> <description> Whether all applications should be run as the NodeManager process' owner. When false, applications are launched instead as the application owner. </description> </property> <property> <name>yarn.nodemanager.runtime.linux.allowed-runtimes</name> <value>default,runc</value> <description> Comma separated list of runtimes that are allowed when using LinuxContainerExecutor. The allowed values are default, docker, runc, and javasandbox. </description> </property> <property> <name>yarn.nodemanager.runtime.linux.type</name> <value></value> <description> Optional. Sets the default container runtime to use. </description> </property> <property> <description>The runC image tag to manifest plugin class to be used.</description> <name>yarn.nodemanager.runtime.linux.runc.image-tag-to-manifest-plugin</name> <value>org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.runc.ImageTagToManifestPlugin</value> </property> <property> <description>The runC manifest to resources plugin class to be used.</description> <name>yarn.nodemanager.runtime.linux.runc.manifest-to-resources-plugin</name> <value>org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.runc.HdfsManifestToResourcesPlugin</value> </property> <property> <description>The HDFS location under which the oci image manifests, layers, and configs directories exist.</description> <name>yarn.nodemanager.runtime.linux.runc.image-toplevel-dir</name> <value>/runc-root</value> </property> <property> <description>Target count of layer mounts that we should keep on disk at one time.</description> <name>yarn.nodemanager.runtime.linux.runc.layer-mounts-to-keep</name> <value>100</value> </property> <property> <description>The interval in seconds between executions of reaping layer mounts.</description> <name>yarn.nodemanager.runtime.linux.runc.layer-mounts-interval-secs</name> <value>600</value> </property> <property> <description>Image to be used if no other image is specified.</description> <name>yarn.nodemanager.runtime.linux.runc.image-name</name> <value></value> </property> <property> <description>Allow or disallow privileged containers.</description> <name>yarn.nodemanager.runtime.linux.runc.privileged-containers.allowed</name> <value>false</value> </property> <property> <description>The set of networks allowed when launching containers using the RuncContainerRuntime.</description> <name>yarn.nodemanager.runtime.linux.runc.allowed-container-networks</name> <value>host,none,bridge</value> </property> <property> <description>The set of runtimes allowed when launching containers using the RuncContainerRuntime.</description> <name>yarn.nodemanager.runtime.linux.runc.allowed-container-runtimes</name> <value>runc</value> </property> <property> <description>ACL list for users allowed to run privileged containers.</description> <name>yarn.nodemanager.runtime.linux.runc.privileged-containers.acl</name> <value></value> </property> <property> <description>Allow host pid namespace for runC containers. Use with care.</description> <name>yarn.nodemanager.runtime.linux.runc.host-pid-namespace.allowed</name> <value>false</value> </property> <property> <description>The default list of read-only mounts to be bind-mounted into all runC containers that use RuncContainerRuntime.</description> <name>yarn.nodemanager.runtime.linux.runc.default-ro-mounts</name> <value></value> </property> <property> <description>The default list of read-write mounts to be bind-mounted into all runC containers that use RuncContainerRuntime.</description> <name>yarn.nodemanager.runtime.linux.runc.default-rw-mounts</name> <value></value> </property> <property> <description>Path to the seccomp profile to use with runC containers</description> <name>yarn.nodemanager.runtime.linux.runc.seccomp-profile</name> <value></value> </property> <property> <description>The HDFS location where the runC image tag to hash file exists.</description> <name>yarn.nodemanager.runtime.linux.runc.image-tag-to-manifest-plugin.hdfs-hash-file</name> <value>/runc-root/image-tag-to-hash</value> </property> <property> <description>The local file system location where the runC image tag to hash file exists.</description> <name>yarn.nodemanager.runtime.linux.runc.image-tag-to-manifest-plugin.local-hash-file</name> <value></value> </property> <property> <description>The interval in seconds between refreshing the hdfs image tag to hash cache.</description> <name>yarn.nodemanager.runtime.linux.runc.image-tag-to-manifest-plugin.cache-refresh-interval-secs</name> <value>60</value> </property> <property> <description>The number of manifests to cache in the image tag to hash cache.</description> <name>yarn.nodemanager.runtime.linux.runc.image-tag-to-manifest-plugin.num-manifests-to-cache</name> <value>10</value> </property> <property> <description>The timeout value in seconds for the values in the stat cache.</description> <name>yarn.nodemanager.runtime.linux.runc.hdfs-manifest-to-resources-plugin.stat-cache-timeout-interval-secs</name> <value>360</value> </property> <property> <description>The size of the stat cache which stores stats of the layers and config.</description> <name>yarn.nodemanager.runtime.linux.runc.hdfs-manifest-to-resources-plugin.stat-cache-size</name> <value>500</value> </property> </configuration>
此外,必须存在一个 container-executor.cfg 文件并包含容器执行器的设置。该文件必须归 root 所有,权限为 0400。该文件的格式是标准 Java 属性文件格式,例如
`key=value`
启用 runC 支持需要以下属性
配置名称 | 说明 |
---|---|
yarn.nodemanager.linux-container-executor.group |
NodeManager 的 Unix 组。它应与 yarn-site.xml 文件中的 yarn.nodemanager.linux-container-executor.group 匹配。 |
container-executor.cfg 必须包含一个部分来确定允许容器的功能。它包含以下属性
配置名称 | 说明 |
---|---|
module.enabled |
必须为“true”或“false”以分别启用或禁用启动 runC 容器。默认值为 0。 |
runc.binary |
用于启动 runC 容器的二进制文件。默认情况下为 /usr/bin/runc。 |
runc.run-root |
将放置所有运行时挂载和覆盖挂载的目录。 |
runc.allowed.ro-mounts |
允许容器以只读模式挂载的逗号分隔目录。默认情况下,不允许挂载任何目录。 |
runc.allowed.rw-mounts |
允许容器以读写模式挂载的逗号分隔目录。默认情况下,不允许挂载任何目录。 |
请注意,如果您希望运行需要访问 YARN 本地目录的 runC 容器,则必须将它们添加到 runc.allowed.rw-mounts 列表中。
此外,容器不允许以读写模式挂载 container-executor.cfg 目录的任何父目录。
以下属性是可选的
配置名称 | 说明 |
---|---|
min.user.id |
允许启动应用程序的最小 UID。默认情况下没有最小值 |
banned.users |
不允许启动应用程序的用户名列表,以逗号分隔。默认设置是:yarn、mapred、hdfs 和 bin。 |
allowed.system.users |
即使用户的 UID 低于配置的最小值,也允许其启动应用程序的用户名列表,以逗号分隔。如果用户出现在 allowed.system.users 和 banned.users 中,则该用户将被视为被禁止。 |
feature.tc.enabled |
必须为“true”或“false”。“false”表示禁用流量控制命令。“true”表示允许流量控制命令。 |
feature.yarn.sysfs.enabled |
必须为“true”或“false”。有关详细信息,请参阅 YARN sysfs 支持。默认设置为禁用。 |
允许启动 runC 容器的 container-executor.cfg 的一部分如下
yarn.nodemanager.linux-container-executor.group=yarn [runc] module.enabled=true runc.binary=/usr/bin/runc runc.run-root=/run/yarn-container-executor runc.allowed.ro-mounts=/sys/fs/cgroup runc.allowed.rw-mounts=/var/hadoop/yarn/local-dir,/var/hadoop/yarn/log-dir
runC 容器在源自 Docker 镜像的镜像中运行。Docker 镜像会转换为一组 squashFS 文件镜像,并上传到 HDFS 中。为了与 YARN 配合使用,这些 Docker 镜像有一些要求。
runC 容器将明确地以应用程序所有者作为容器用户启动。如果应用程序所有者不是 Docker 镜像中的有效用户,应用程序将失败。容器用户由用户的 UID 指定。如果用户 UID 在 NodeManager 主机和 Docker 镜像之间不同,则容器可能会以错误的用户启动,或者可能因为 UID 不存在而无法启动。有关更多详细信息,请参阅runC 容器中的用户管理部分。
Docker 镜像必须具备应用程序执行所需的任何内容。对于 Hadoop(MapReduce 或 Spark),Docker 镜像必须包含 JRE 和 Hadoop 库,并设置必要的环境变量:JAVA_HOME、HADOOP_COMMON_PATH、HADOOP_HDFS_HOME、HADOOP_MAPRED_HOME、HADOOP_YARN_HOME 和 HADOOP_CONF_DIR。请注意,Docker 镜像中提供的 Java 和 Hadoop 组件版本必须与群集上安装的版本以及用于同一作业的其他任务的任何其他 Docker 镜像中安装的版本兼容。否则,在 runC 容器中启动的 Hadoop 组件可能无法与外部 Hadoop 组件通信。
/bin/bash
必须在镜像内可用。这通常是正确的,但是,微型 Docker 镜像(例如,使用 busybox 执行 shell 命令的镜像)可能未安装 bash。在这种情况下,将显示以下错误
Container id: container_1561638268473_0015_01_000002 Exit code: 7 Exception message: Launch container failed Shell error output: /usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:235: starting container process caused "exec: \"bash\": executable file not found in $PATH". Shell output: main : command provided 4
find
命令也必须在镜像内可用。没有 find
会导致此错误
Container exited with a non-zero exit code 127. Error file: prelaunch.err. Last 4096 bytes of prelaunch.err : /tmp/hadoop-systest/nm-local-dir/usercache/hadoopuser/appcache/application_1561638268473_0017/container_1561638268473_0017_01_000002/launch_container.sh: line 44: find: command not found
如果 Docker 镜像设置了入口点,则入口点将作为其参数使用容器的启动命令执行。
从 Docker 镜像派生的 runC 镜像会本地化到 runC 容器将执行的主机上,就像任何其他本地化资源一样。MapReduce 和 Spark 都假定需要花费 10 分钟以上报告进度的任务已停止,因此,如果本地化花费的时间过长,指定一个较大的镜像可能会导致应用程序失败。
每个 Docker 镜像由 3 件事组成:- 创建文件系统的层集。- 包含与镜像环境相关信息的配置文件。- 描述该镜像所需的层和配置的清单。
这 3 个部分结合在一起创建了符合开放容器计划 (OCI) 的镜像。runC 在 OCI 兼容容器之上运行,但有小小的不同。runC 运行时使用的每个层都压缩到 squashFS 文件系统中。squashFS 层以及配置和清单将与 image-tag-to-hash 映射
文件一起上传到 HDFS,该文件描述了镜像标记与该镜像关联的清单之间的映射。完成所有这些设置是一个复杂且繁琐的过程。在 YARN-9564 上有一个补丁,其中包含一个名为 docker-to-squash.py
的非官方 Python 脚本,以帮助完成转换过程。此工具将 Docker 镜像作为输入,将其所有层转换为 squashFS 文件系统,并将 squashFS 层、配置和清单上传到 runc-root 下方的 HDFS。它还将创建或更新 image-tag-to-hash
映射文件。以下是该脚本的一个示例调用,用于将名为 centos:latest
的镜像上传到 HDFS,runC 镜像名为 centos
[user@foobar sbin]$ pwd /home/user/hadoop/hadoop-dist/target/hadoop-3.3.0-SNAPSHOT/sbin [user@foobar sbin]$ ls distribute-exclude.sh hadoop-daemons.sh refresh-namenodes.sh start-dfs.cmd start-yarn.sh stop-dfs.cmd stop-yarn.sh docker_to_squash.py httpfs.sh start-all.cmd start-dfs.sh stop-all.cmd stop-dfs.sh workers.sh FederationStateStore kms.sh start-all.sh start-secure-dns.sh stop-all.sh stop-secure-dns.sh yarn-daemon.sh hadoop-daemon.sh mr-jobhistory-daemon.sh start-balancer.sh start-yarn.cmd stop-balancer.sh stop-yarn.cmd yarn-daemons.sh [user@foobar sbin]$ hadoop fs -ls / Found 3 items drwxrwx--- - user supergroup 0 2019-08-07 19:35 /home drwx------ - user supergroup 0 2019-08-07 19:35 /tmp drwx------ - user supergroup 0 2019-08-07 19:35 /user [user@foobar sbin]$ ./docker_to_squash.py --working-dir /tmp --log=DEBUG pull-build-push-update centos:latest,centos DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'version'] DEBUG: command: ['skopeo', '-v'] DEBUG: command: ['mksquashfs', '-version'] DEBUG: args: Namespace(LOG_LEVEL='DEBUG', check_magic_file=False, force=False, func=<function pull_build_push_update at 0x7fe6974cd9b0>, hadoop_prefix='/hadoop-2.8.6-SNAPSHOT', hdfs_root='/runc-root', image_tag_to_hash='image-tag-to-hash', images_and_tags=['centos:latest,centos'], magic_file='etc/dockerfile-version', pull_format='docker', replication=1, skopeo_format='dir', sub_command='pull-build-push-update', working_dir='/tmp') DEBUG: extra: [] DEBUG: image-tag-to-hash: image-tag-to-hash DEBUG: LOG_LEVEL: DEBUG DEBUG: HADOOP_BIN_DIR: /hadoop-2.8.6-SNAPSHOT/bin DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root'] ls: `/runc-root': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-mkdir', '/runc-root'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '755', '/runc-root'] DEBUG: Setting up squashfs dirs: ['/runc-root/layers', '/runc-root/config', '/runc-root/manifests'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/layers'] ls: `/runc-root/layers': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-mkdir', '/runc-root/layers'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/layers'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '755', '/runc-root/layers'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/config'] ls: `/runc-root/config': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-mkdir', '/runc-root/config'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/config'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '755', '/runc-root/config'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/manifests'] ls: `/runc-root/manifests': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-mkdir', '/runc-root/manifests'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/manifests'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '755', '/runc-root/manifests'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/image-tag-to-hash'] ls: `/runc-root/image-tag-to-hash': No such file or directory INFO: Working on image centos:latest with tags ['centos'] DEBUG: command: ['skopeo', 'inspect', '--raw', 'docker://centos:latest'] DEBUG: skopeo inspect --raw returned a list of manifests DEBUG: amd64 manifest sha is: sha256:ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66 DEBUG: command: ['skopeo', 'inspect', '--raw', u'docker://centos@sha256:ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] INFO: manifest: {u'layers': [{u'mediaType': u'application/vnd.docker.image.rootfs.diff.tar.gzip', u'digest': u'sha256:8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df', u'size': 75403831}], u'schemaVersion': 2, u'config': {u'mediaType': u'application/vnd.docker.container.image.v1+json', u'digest': u'sha256:9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1', u'size': 2182}, u'mediaType': u'application/vnd.docker.distribution.manifest.v2+json'} INFO: manifest: {u'layers': [{u'mediaType': u'application/vnd.docker.image.rootfs.diff.tar.gzip', u'digest': u'sha256:8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df', u'size': 75403831}], u'schemaVersion': 2, u'config': {u'mediaType': u'application/vnd.docker.container.image.v1+json', u'digest': u'sha256:9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1', u'size': 2182}, u'mediaType': u'application/vnd.docker.distribution.manifest.v2+json'} DEBUG: Layers: [u'8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df'] DEBUG: Config: 9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1 DEBUG: hash_to_tags is null. Not removing tag centos DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] ls: `/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', u'/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1'] ls: `/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] ls: `/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh': No such file or directory DEBUG: skopeo_dir: /tmp/docker-to-squash/centos:latest INFO: Pulling image: centos:latest DEBUG: command: ['skopeo', 'copy', 'docker://centos:latest', 'dir:/tmp/docker-to-squash/centos:latest'] INFO: Squashifying and uploading layer: 8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] ls: `/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh': No such file or directory DEBUG: command: ['sudo', 'tar', '-C', u'/tmp/docker-to-squash/expand_archive_8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df', '--xattrs', "--xattrs-include='*'", '-xzf', u'/tmp/docker-to-squash/centos:latest/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df'] DEBUG: command: ['sudo', 'find', u'/tmp/docker-to-squash/expand_archive_8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df', '-name', '.wh.*'] DEBUG: command: ['sudo', 'mksquashfs', u'/tmp/docker-to-squash/expand_archive_8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df', u'/tmp/docker-to-squash/centos:latest/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] DEBUG: command: ['sudo', 'rm', '-rf', u'/tmp/docker-to-squash/expand_archive_8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] ls: `/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-put', u'/tmp/docker-to-squash/centos:latest/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-setrep', '1', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '444', u'/runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh'] INFO: Uploaded file /runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh with replication 1 and permissions 444 DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', u'/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1'] ls: `/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-put', u'/tmp/docker-to-squash/centos:latest/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1', u'/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-setrep', '1', u'/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '444', u'/runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1'] INFO: Uploaded file /runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1 with replication 1 and permissions 444 DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-ls', '/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] ls: `/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66': No such file or directory DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-put', '/tmp/docker-to-squash/centos:latest/manifest.json', '/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-setrep', '1', '/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '444', '/runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66'] INFO: Uploaded file /runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66 with replication 1 and permissions 444 DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-put', '-f', '/tmp/docker-to-squash/image-tag-to-hash', '/runc-root/image-tag-to-hash'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-setrep', '1', '/runc-root/image-tag-to-hash'] DEBUG: command: ['/hadoop-2.8.6-SNAPSHOT/bin/hadoop', 'fs', '-chmod', '444', '/runc-root/image-tag-to-hash'] DEBUG: command: ['sudo', 'rm', '-rf', '/tmp/docker-to-squash'] [user@foobar sbin]$ hadoop fs -ls / Found 4 items drwxrwx--- - user supergroup 0 2019-08-07 19:35 /home drwxr-xr-x - user supergroup 0 2019-08-08 22:38 /runc-root drwx------ - user supergroup 0 2019-08-07 19:35 /tmp drwx------ - user supergroup 0 2019-08-07 19:35 /user [user@foobar sbin]$ hadoop fs -ls /runc-root/* Found 1 items -r--r--r-- 1 user supergroup 2182 2019-08-08 22:38 /runc-root/config/9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1 -r--r--r-- 1 user supergroup 86 2019-08-08 22:38 /runc-root/image-tag-to-hash Found 1 items -r--r--r-- 1 user supergroup 73625600 2019-08-08 22:38 /runc-root/layers/8ba884070f611d31cb2c42eddb691319dc9facf5e0ec67672fcfa135181ab3df.sqsh Found 1 items -r--r--r-- 1 user supergroup 529 2019-08-08 22:38 /runc-root/manifests/ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66
在尝试启动 runC 容器之前,请确保 LCE 配置对请求常规 YARN 容器的应用程序有效。如果启用 LCE 后一个或多个 NodeManager 无法启动,最可能的原因是容器执行程序二进制文件的所有权和/或权限不正确。检查日志以确认。
要在 runC 容器中运行应用程序,请在应用程序的环境中设置以下环境变量
环境变量名称 | 说明 |
---|---|
YARN_CONTAINER_RUNTIME_TYPE |
确定是否在 runC 容器中启动应用程序。如果值为“runc”,则应用程序将在 runC 容器中启动。否则将使用常规进程树容器。 |
YARN_CONTAINER_RUNTIME_RUNC_IMAGE |
命名将用于启动 runC 容器的映像。 |
YARN_CONTAINER_RUNTIME_RUNC_CONTAINER_HOSTNAME |
设置 runC 容器要使用的主机名。 |
YARN_CONTAINER_RUNTIME_RUNC_MOUNTS |
向 runC 容器添加其他卷装载。环境变量的值应为装载的逗号分隔列表。所有此类装载都必须指定为“source:dest:mode”,并且模式必须为“ro”(只读)或“rw”(读写)以指定所请求的访问类型。如果未指定任何模式,则假定为读写。容器执行程序将根据 container-executor.cfg 中为 runc.allowed.ro-mounts 和 runc.allowed.rw-mounts 设置的值验证请求的装载。 |
前两个是必需的。其余的可以根据需要设置。虽然通过环境变量控制容器类型不太理想,但它允许不了解 YARN 的 runC 支持的应用程序(例如 MapReduce 和 Spark)通过其对配置应用程序环境的支持来利用它。
注意 如果在容器中将任何内容装载到 /tmp 或 /var/tmp,则运行时将不起作用。
一旦提交应用程序在 runC 容器中启动,该应用程序的行为将与任何其他 YARN 应用程序完全相同。日志将被聚合并存储在相关的历史记录服务器中。应用程序生命周期将与非 runC 应用程序相同。
警告 启用此功能时应小心。不建议访问诸如(但不限于)/, /etc, /run 或 /home 等目录,这会导致容器对主机产生负面影响或泄露敏感信息。警告
runC 容器中通常需要来自主机的文件和目录,runC 通过将它们挂载到容器中来提供这些文件和目录。示例包括本地化资源、Apache Hadoop 二进制文件和套接字。
要将任何内容挂载到容器中,必须配置以下内容。
runc.allowed.ro-mounts
和 runc.allowed.rw-mounts
设置为允许挂载的父目录列表,在 container-executor.cfg 中定义卷白名单。管理员提供的白名单定义为允许挂载到容器中的目录的逗号分隔列表。用户提供的源目录必须与指定目录匹配或为其子目录。
用户提供的挂载列表定义为逗号分隔列表,格式为 source:destination 或 source:destination:mode。源是主机上的文件或目录。目标是源将被绑定挂载到的容器中的路径。模式定义用户对挂载的预期模式,可以是 ro(只读)或 rw(读写)。如果未指定,则假定为 rw。模式还可以包括绑定传播选项(shared、rshared、slave、rslave、private 或 rprivate)。在这种情况下,模式应为 option、rw+option 或 ro+option。
以下示例概述了如何使用此功能将通常需要的 /sys/fs/cgroup 目录挂载到在 YARN 上运行的容器中。
管理员在 container-executor.cfg 中将 runc.allowed.ro-mounts 设置为 “/sys/fs/cgroup”。现在,应用程序可以请求将 “/sys/fs/cgroup” 从主机以只读模式挂载到容器中。
Nodemanager 有权通过 yarn-site.xml 中的 yarn.nodemanager.runtime.linux.runc.default-ro-mount
" 和 yarn.nodemanager.runtime.linux.runc.default-rw-mounts
设置要添加到容器的默认只读或读写挂载列表。在此示例中,yarn.nodemanager.runtime.linux.runc.default-ro-mounts
将设置为 /sys/fs/cgroup:/sys/fs/cgroup
。
YARN 的 runC 容器支持使用 NodeManager 主机上定义的 uid:gid 标识来启动容器进程。NodeManager 主机和容器之间的用户和组名称不匹配可能导致权限问题、容器启动失败,甚至安全漏洞。集中管理主机和容器的用户和组可以极大地降低这些风险。在 YARN 上运行容器化应用程序时,有必要了解将用于启动容器进程的 uid:gid 对。
以下是一个 uid:gid 对含义的示例。默认情况下,在非安全模式下,YARN 将以用户 nobody
启动进程(请参阅 在 YARN 中使用 CGroups 底部的表格,了解如何在非安全模式下确定运行用户)。在基于 CentOS 的系统上,nobody
用户的 uid 为 99
,nobody
组为 99
。因此,YARN 将使用 uid 99
和 gid 99
调用 runC。如果容器中 nobody
用户没有 uid 99
,则启动可能会失败或产生意外结果。
有许多方法可以解决用户和组管理问题。默认情况下,runC 将在容器内的 /etc/passwd
(和 /etc/shadow
)中对用户进行身份验证。使用 runC 映像中提供的默认 /etc/passwd
不太可能包含适当的用户条目,并且会导致启动失败。强烈建议集中管理用户和组。以下概述了用户和组管理的几种方法。
管理用户和组的最基本方法是在 runC 映像中修改用户和组。此方法仅适用于非安全模式,其中所有容器进程都将作为单个已知用户(例如 nobody
)启动。在这种情况下,唯一的要求是 nobody 用户和组的 uid:gid 对必须在主机和容器之间匹配。在基于 CentOS 的系统上,这意味着容器中的 nobody 用户需要 UID 99
,容器中的 nobody 组需要 GID 99
。
更改 UID 和 GID 的一种方法是利用 usermod
和 groupmod
。以下为 nobody 用户/组设置正确的 UID 和 GID。
usermod -u 99 nobody groupmod -g 99 nobody
鉴于添加用户的灵活性不高,因此不建议在测试之外使用此方法。
当组织已具备在每个系统上创建本地用户的自动化功能时,将 /etc/passwd 和 /etc/group 绑定挂载到容器中可能是修改容器映像的替代方案。要启用绑定挂载 /etc/passwd 和 /etc/group 的功能,请更新 container-executor.cfg
中的 runc.allowed.ro-mounts
以包括这些路径。要在 runC 上执行此操作,“yarn.nodemanager.runtime.linux.runc.default-ro-mounts”需要包括 /etc/passwd:/etc/passwd:ro
和 /etc/group:/etc/group:ro
。
这种绑定挂载方法存在几个需要考虑的挑战。
鉴于修改正在运行的容器的灵活性不高,不建议在测试之外采用此方法。
一种允许集中管理用户和组的替代方法是 SSSD。系统安全服务守护程序 (SSSD) 提供对不同身份和身份验证提供程序(例如 LDAP 或 Active Directory)的访问。
Linux 身份验证的传统架构如下
application -> libpam -> pam_authenticate -> pam_unix.so -> /etc/passwd
如果我们使用 SSSD 进行用户查找,则变为
application -> libpam -> pam_authenticate -> pam_sss.so -> SSSD -> pam_unix.so -> /etc/passwd
我们可以将 SSSD 通过 UNIX 套接字绑定挂载到容器中。这将允许 SSSD 客户端库对在主机上运行的 SSSD 进行身份验证。因此,用户信息不需要存在于 docker 镜像的 /etc/passwd 中,而是由 SSSD 提供服务。
主机和容器的分步配置
# yum -y install sssd-common sssd-proxy
# cat /etc/pam.d/sss_proxy auth required pam_unix.so account required pam_unix.so password required pam_unix.so session required pam_unix.so
# cat /etc/sssd/sssd/conf [sssd] services = nss,pam config_file_version = 2 domains = proxy [nss] [pam] [domain/proxy] id_provider = proxy proxy_lib_name = files proxy_pam_target = sss_proxy
# systemctl start sssd
# getent passwd -s sss localuser
由于 SSSD UNIX 套接字位于那里,因此将 /var/lib/sss/pipes 目录从主机绑定挂载到容器非常重要。
-v /var/lib/sss/pipes:/var/lib/sss/pipes:rw
以下所有步骤都应在容器本身上执行。
仅安装 sss 客户端库
# yum -y install sssd-client
确保在中为 passwd 和 group 数据库配置 sss
/etc/nsswitch.conf
配置应用程序用于调用 SSSD 的 PAM 服务
# cat /etc/pam.d/system-auth #%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required pam_env.so auth sufficient pam_unix.so try_first_pass nullok auth sufficient pam_sss.so forward_pass auth required pam_deny.so account required pam_unix.so account [default=bad success=ok user_unknown=ignore] pam_sss.so account required pam_permit.so password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow password sufficient pam_sss.so use_authtok password required pam_deny.so session optional pam_keyinit.so revoke session required pam_limits.so -session optional pam_systemd.so session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid session required pam_unix.so session optional pam_sss.so
保存 docker 镜像,并将 docker 镜像用作应用程序的基本镜像。
测试在 YARN 环境中启动的 docker 镜像。
$ id uid=5000(localuser) gid=5000(localuser) groups=5000(localuser),1337(hadoop)
此示例假定 Hadoop 已安装到 /usr/local/hadoop
。
在使用该镜像运行之前,你还需要将 Docker 镜像压缩并上传到 HDFS。请参阅 将 Docker 镜像转换为 runC 镜像,了解如何将 Docker 镜像转换为 runC 可用的镜像。对于此示例,我们将假设你已使用名为 hadoop-image
的镜像完成了该操作。
此外,container-executor.cfg
中的 runc.allowed.ro-mounts
已更新,包含以下目录:/usr/local/hadoop,/etc/passwd,/etc/group
。
要提交 pi 作业以在 runC 容器中运行,请运行以下命令
HADOOP_HOME=/usr/local/hadoop YARN_EXAMPLES_JAR=$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar MOUNTS="$HADOOP_HOME:$HADOOP_HOME:ro,/etc/passwd:/etc/passwd:ro,/etc/group:/etc/group:ro" IMAGE_ID="hadoop-image" export YARN_CONTAINER_RUNTIME_TYPE=runc export YARN_CONTAINER_RUNTIME_RUNC_IMAGE=$IMAGE_ID export YARN_CONTAINER_RUNTIME_RUNC_MOUNTS=$MOUNTS yarn jar $YARN_EXAMPLES_JAR pi \ -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_TYPE=runc \ -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_RUNC_MOUNTS=$MOUNTS \ -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_RUNC_IMAGE=$IMAGE_ID \ -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_TYPE=runc \ -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_RUNC_MOUNTS=$MOUNTS \ -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_RUNC_IMAGE=$IMAGE_ID \ 1 40000
请注意,应用程序主控、映射任务和归约任务是独立配置的。在此示例中,我们对所有三个任务都使用 hadoop-image
镜像。
此示例假定 Hadoop 已安装到 /usr/local/hadoop
,Spark 已安装到 /usr/local/spark
。
在使用该镜像运行之前,你还需要将 Docker 镜像压缩并上传到 HDFS。请参阅 将 Docker 镜像转换为 runC 镜像,了解如何将 Docker 镜像转换为 runC 可用的镜像。对于此示例,我们将假设你已使用名为 hadoop-image
的镜像完成了该操作。
此外,container-executor.cfg
中的 runc.allowed.ro-mounts
已更新,包含以下目录:/usr/local/hadoop,/etc/passwd,/etc/group
。
要在 runC 容器中运行 Spark shell,请运行以下命令
HADOOP_HOME=/usr/local/hadoop SPARK_HOME=/usr/local/spark MOUNTS="$HADOOP_HOME:$HADOOP_HOME:ro,/etc/passwd:/etc/passwd:ro,/etc/group:/etc/group:ro" IMAGE_ID="hadoop-image" $SPARK_HOME/bin/spark-shell --master yarn \ --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=runc \ --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_RUNC_IMAGE=$IMAGE_ID \ --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_RUNC_MOUNTS=$MOUNTS \ --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=runc \ --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_RUNC_IMAGE=$IMAGE_ID \ --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_RUNC_MOUNTS=$MOUNTS
请注意,应用程序主控和执行器是独立配置的。在此示例中,我们对两者都使用 hadoop-image
镜像。