重要
此功能不穩定。由於此功能持續演進,API 可能無法維護,功能也可能變更或移除。
啟用此功能並在叢集中執行 runC 容器會產生安全性影響。由於 runC 與許多強大的核心功能整合,因此管理員在啟用此功能前,必須了解 runC 安全性。
runC 是一個 CLI 工具,用於根據開放容器計畫 (OCI) 規範產生和執行容器。runC 最初是從原始 Docker 基礎架構中衍生出來的。runC 搭配透過 squashFS 映像建立的 rootfs 掛載點,讓使用者可以將應用程式與其偏好的執行環境打包在一起,並在目標機器上執行。如需 OCI 的更多資訊,請參閱其網站。
Linux 容器執行器 (LCE) 允許 YARN NodeManager 啟動 YARN 容器,以便直接在主機上、Docker 容器內,以及現在在 runC 容器內執行。要求資源的應用程式可以針對每個容器指定執行方式。LCE 也提供增強的安全性,而且在部署安全叢集時是必要的。當 LCE 啟動 YARN 容器在 runC 容器中執行時,應用程式可以指定要使用的 runC 映像。這些 runC 映像可以從 Docker 映像建置。
runC 容器提供一個自訂執行環境,應用程式的程式碼在其中執行,與 NodeManager 和其他應用程式的執行環境隔離。這些容器可以包含應用程式需要的特殊函式庫,而且它們可以有不同版本的原生工具和函式庫,包括 Perl、Python 和 Java。runC 容器甚至可以執行與 NodeManager 上執行的不同的 Linux 版本。
YARN 的 runC 提供一致性(所有 YARN 容器都將有相同的軟體環境)和隔離性(不會干擾實體機器上安裝的任何內容)。
LCE 中的 runC 支援仍在演進中。若要追蹤進度並查看 runC 設計文件,請查看 YARN-9014,這是 runC 支援改善的總括性 JIRA。
LCE 要求 container-executor 二進位檔由 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 層會連同設定檔和清單上傳到 HDFS,以及描述影像標籤和與該影像關聯的清單之間對應關係的 image-tag-to-hash
對應檔。設定所有這些是一個複雜且繁瑣的過程。在 YARN-9564 上有一個修補程式,其中包含一個非官方的 Python 腳本,稱為 docker-to-squash.py
,以協助轉換過程。此工具會輸入 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 容器。環境變數的值應為掛載點的逗號分隔清單。所有此類掛載點都必須以「來源:目標:模式」提供,而模式必須為「ro」(唯讀)或「rw」(讀寫),以指定所要求的存取類型。如果未指定任一模式,將假設為讀寫。請求的掛載點將根據 container-executor.cfg 中針對 runc.allowed.ro-mounts 和 runc.allowed.rw-mounts 設定的值,由 container-executor 驗證。 |
前兩個是必要的。其餘部分可視需要設定。雖然透過環境變數控制容器類型並非理想,但它允許不了解 YARN 的 runC 支援的應用程式(例如 MapReduce 和 Spark)透過支援設定應用程式環境來利用它。
注意 如果您將任何內容掛載至容器中的 /tmp 或 /var/tmp,執行時期將無法運作。
一旦應用程式已提交至在 runC 容器中啟動,應用程式將與任何其他 YARN 應用程式完全相同。記錄將彙總並儲存在相關的歷程伺服器中。應用程式生命週期將與非 runC 應用程式相同。
警告 啟用此功能時應小心。不建議存取目錄(包括但不限於 /、/etc、/run 或 /home),否則可能會導致容器對主機產生負面影響或洩漏敏感資訊。警告
通常需要 runC 容器中的主機檔案和目錄,而 runC 會透過掛載點將其提供給容器。範例包括在地化資源、Apache Hadoop 二進位檔和 socket。
若要將任何內容掛載至容器,必須設定下列事項。
runc.allowed.ro-mounts
和 runc.allowed.rw-mounts
設定為允許掛載的父目錄清單,在 container-executor.cfg 中定義磁碟區白名單。管理員提供的白名單定義為允許掛載至容器的目錄的逗號分隔清單。使用者提供的來源目錄必須與指定的目錄相符或為其子目錄。
使用者提供的掛載清單定義為逗號分隔清單,格式為 來源:目標 或 來源:目標:模式。來源是主機上的檔案或目錄。目標是容器中來源將繫結掛載到的路徑。模式定義使用者預期的掛載模式,可以是 ro(唯讀)或 rw(讀寫)。如果未指定,將假設為 rw。模式也可以包含繫結傳播選項(shared、rshared、slave、rslave、private 或 rprivate)。在這種情況下,模式應為 選項、rw+選項 或 ro+選項 的格式。
下列範例說明如何使用此功能將通常需要的 /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 中使用 CGroup 底部的表格,了解在非安全模式中如何決定以使用者身分執行)。在 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 socket 繫結掛載到容器中。這將允許 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 socket 位於其中,因此將 /var/lib/sss/pipes 目錄從主機繫結掛載到容器中非常重要。
-v /var/lib/sss/pipes:/var/lib/sss/pipes:rw
以下所有步驟都應在容器本身上執行。
僅安裝 sss 客户端程式庫
# yum -y install sssd-client
確保在中為 passwd 和群組資料庫設定 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
映像。