runC コンテナを使用したアプリケーションの起動

セキュリティに関する警告

重要

この機能は不安定です。この機能は進化し続けているため、API は維持されない可能性があり、機能が変更または削除される可能性があります。

この機能を有効にしてクラスタで runC コンテナを実行すると、セキュリティ上の問題が発生する可能性があります。runC は多くの強力なカーネル機能と統合されているため、管理者はこの機能を有効にする前に runC のセキュリティを理解することが不可欠です。

概要

runC は、Open Container Initiative (OCI) 仕様に従ってコンテナを生成して実行するための CLI ツールです。runC は元々 Docker の元のインフラストラクチャから分離されました。squashFS イメージを介して作成された rootfs マウントポイントと合わせて、runC を使用すると、ユーザーはアプリケーションを好ましい実行環境と共にバンドルして、ターゲットマシンで実行できます。OCI の詳細については、ウェブサイトを参照してください。

Linux Container Executor (LCE) を使用すると、YARN NodeManager は、ホストマシンで直接実行される YARN コンテナ、Docker コンテナ内、および runC コンテナ内で実行される YARN コンテナを起動できます。リソースを要求するアプリケーションは、各コンテナの実行方法を指定できます。LCE はセキュリティも強化しており、セキュアクラスタを展開する場合に必要です。LCE が runC コンテナで実行される YARN コンテナを起動する場合、アプリケーションは使用する runC イメージを指定できます。これらの runC イメージは、Docker イメージから構築できます。

runC コンテナは、アプリケーションのコードが実行されるカスタム実行環境を提供し、NodeManager や他のアプリケーションの実行環境から隔離されます。これらのコンテナには、アプリケーションに必要な特別なライブラリを含めることができ、Perl、Python、Java を含むネイティブツールとライブラリの異なるバージョンを持つことができます。runC コンテナでは、NodeManager で実行されているものとは異なるバージョンの Linux を実行することもできます。

YARN の runC は、一貫性(すべての YARN コンテナは同じソフトウェア環境を持つ)と分離(物理マシンにインストールされているものとの干渉がない)の両方を提供します。

LCE の runC のサポートはまだ進化しています。進捗状況を追跡し、runC の設計ドキュメントを参照するには、runC のサポートの改善に関する包括的な JIRA である YARN-9014 を確認してください。

クラスタ設定

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 runC コンテナの起動を有効または無効にするには、「true」または「false」にする必要があります。デフォルト値は 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 イメージにはいくつかの要件があります。

  1. runC コンテナは、アプリケーション所有者をコンテナユーザーとして明示的に起動されます。アプリケーション所有者が Docker イメージで有効なユーザーでない場合、アプリケーションは失敗します。コンテナユーザーはユーザーの UID で指定されます。NodeManager ホストと Docker イメージの間でユーザーの UID が異なる場合、コンテナは間違ったユーザーとして起動されるか、UID が存在しないために起動に失敗する可能性があります。詳細については、runC コンテナでのユーザー管理セクションを参照してください。

  2. 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 コンポーネントと通信できなくなる可能性があります。

  3. /bin/bash はイメージ内で使用可能である必要があります。これは一般的に当てはまりますが、小さな Docker イメージ(シェルコマンドに busybox を使用するものなど)には 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
    
  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イメージのrunCイメージへの変換

すべてのDockerイメージは、以下の3つの要素で構成されています。- ファイルシステムを作成する一連のレイヤー。- イメージの環境に関する情報を保持する設定ファイル。- どのようなレイヤーと設定がそのイメージに必要なかを記述するマニフェスト。

これら3つの要素が組み合わさり、Open Container Initiative (OCI)準拠のイメージが作成されます。runCはOCI準拠のコンテナ上で動作しますが、小さな違いがあります。runCランタイムが使用する各レイヤーは、squashFSファイルシステムに圧縮されます。squashFSレイヤー、設定ファイル、マニフェストは、イメージタグとそれに関連付けられたマニフェストのマッピングを記述するimage-tag-to-hash mappingファイルと共にHDFSにアップロードされます。これらすべてを設定するのは複雑で面倒なプロセスです。変換プロセスを支援するための、docker-to-squash.pyという非公式のPythonスクリプトを含むパッチがYARN-9564にあります。このツールは、入力としてDockerイメージを受け取り、そのすべてのレイヤーをsquashFSファイルシステムに変換し、squashFSレイヤー、設定ファイル、マニフェストをrunc-rootの下にあるHDFSにアップロードします。また、image-tag-to-hashマッピングファイルを作成または更新します。以下は、centos:latestという名前のイメージをrunCイメージ名centosでHDFSにアップロードするためのスクリプトの呼び出し例です。

[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コンテナの起動を試みる前に、通常のYARNコンテナを要求するアプリケーションに対してLCE構成が機能していることを確認してください。LCEを有効にした後に1つ以上の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」(読み書き)で、要求されるアクセスタイプを指定します。どちらも指定されていない場合は、読み書きが想定されます。要求されたマウントは、runc.allowed.ro-mountsとrunc.allowed.rw-mountsで設定された値に基づいて、container-executorによって検証されます。

最初の2つは必須です。残りは必要に応じて設定できます。環境変数を通じてコンテナの種類を制御することは、理想的ではありませんが、YARNのrunCサポートを認識していないアプリケーション(MapReduceやSparkなど)でも、アプリケーション環境の設定をサポートすることで、runCの利点を活用できます。

注記コンテナ内の/tmpまたは/var/tmpに何かをマウントすると、ランタイムは機能しません。

runCコンテナで起動されるようにアプリケーションが提出されると、そのアプリケーションは他のYARNアプリケーションとまったく同じように動作します。ログは集約され、関連する履歴サーバーに保存されます。アプリケーションのライフサイクルは、非runCアプリケーションの場合と同じです。

runCバインドマウントボリュームの使用

警告この機能を有効にする際には注意が必要です。/、/etc、/run、/homeなど(これらに限定されません)のディレクトリへのアクセスを有効にすることはお勧めできません。ホストに悪影響を与えたり、機密情報を漏洩したりする可能性があります。警告

ホストからのファイルとディレクトリは、runCコンテナ内では一般的に必要であり、runCはコンテナへのマウントを通じてこれらを供給します。例としては、ローカライズされたリソース、Apache Hadoopバイナリ、ソケットなどがあります。

コンテナに何かをマウントするには、以下の設定が必要です。

  • 管理者は、runc.allowed.ro-mountsrunc.allowed.rw-mountsをマウントを許可する親ディレクトリのリストに設定することで、container-executor.cfgでボリュームホワイトリストを定義する必要があります。

管理者によって提供されたホワイトリストは、コンテナにマウントを許可するディレクトリのコンマ区切りリストとして定義されます。ユーザーが提供したソースディレクトリは、指定されたディレクトリと一致するか、その子である必要があります。

ユーザーが提供したマウントリストは、ソース:宛先またはソース:宛先:モードの形式でコンマ区切りリストとして定義されます。ソースはホスト上のファイルまたはディレクトリです。宛先は、ソースがバインドマウントされるコンテナ内のパスです。モードは、ユーザーがマウントに期待するモードを定義し、「ro」(読み取り専用)または「rw」(読み書き)にすることができます。指定しない場合は、「rw」が想定されます。モードには、バインドプロパゲーションオプション(shared、rshared、slave、rslave、private、rprivate)を含めることもできます。その場合、モードはオプション、rw+オプション、またはro+オプションの形式にする必要があります。

次の例は、この機能を使用して、YARNで実行されているコンテナに一般的に必要な/sys/fs/cgroupディレクトリをマウントする方法を示しています。

管理者は、container-executor.cfgでrunc.allowed.ro-mountsを「/sys/fs/cgroup」に設定します。アプリケーションは、読み取り専用モードでホストからコンテナに「/sys/fs/cgroup」をマウントすることを要求できるようになります。

NodeManagerは、yarn-site.xmlのyarn.nodemanager.runtime.linux.runc.default-ro-mountyarn.nodemanager.runtime.linux.runc.default-rw-mountsを介して、コンテナに追加される読み取り専用または読み書きマウントのデフォルトリストを設定するオプションがあります。この例では、yarn.nodemanager.runtime.linux.runc.default-ro-mounts/sys/fs/cgroup:/sys/fs/cgroupに設定されます。

runCコンテナでのユーザー管理

YARNのrunCコンテナサポートは、NodeManagerホストで定義されているユーザーのuid:gid IDを使用してコンテナプロセスを起動します。NodeManagerホストとコンテナ間のユーザー名とグループ名の不一致は、パーミッションの問題、コンテナ起動の失敗、またはセキュリティホールにつながる可能性があります。ホストとコンテナの両方でユーザーとグループの管理を集中化することで、これらのリスクを大幅に軽減できます。YARNでコンテナ化されたアプリケーションを実行する際には、コンテナのプロセスを起動するために使用されるuid:gidペアを理解する必要があります。

uid:gidペアの意味の例として、以下を検討してください。デフォルトでは、非セキュアモードでは、YARNはユーザーnobodyとしてプロセスを起動します(ユーザーとしての起動方法については、YARNでのcgroupの使用の一番下の表を参照してください)。CentOSベースのシステムでは、nobodyユーザーのuidは99nobodyグループは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を変更する1つの方法は、usermodgroupmodを利用することです。以下は、nobodyユーザー/グループに正しいUIDとGIDを設定します。

usermod -u 99 nobody
groupmod -g 99 nobody

このアプローチは、ユーザーを追加する柔軟性が低いことを考慮すると、テスト以外では推奨されません。

バインドマウント

組織がすでに各システムにローカルユーザーを作成するための自動化を導入している場合、コンテナイメージを直接変更する代わりに、/etc/passwdと/etc/groupをコンテナにバインドマウントする方が適切な場合があります。/etc/passwdと/etc/groupのバインドマウント機能を有効にするには、container-executor.cfgrunc.allowed.ro-mountsを更新して、これらのパスを含めます。runCでこれを機能させるには、「yarn.nodemanager.runtime.linux.runc.default-ro-mounts」に/etc/passwd:/etc/passwd:ro/etc/group:/etc/group:roを含める必要があります。

このバインドマウントアプローチには、考慮すべきいくつかの課題があります。

  1. イメージに定義されているユーザーとグループは、ホストのユーザーとグループによって上書きされます。
  2. /etc/passwdと/etc/groupはコンテナ内では変更不可であるため、コンテナが起動された後は、ユーザーとグループを追加することはできません。これらを読み書きモードでマウントしないでください。ホストが動作不能になる可能性があります。

このアプローチは、実行中のコンテナを変更する柔軟性が低いことを考慮すると、テスト以外では推奨されません。

SSSD

ユーザーとグループを一元的に管理できる代替アプローチとして、SSSDがあります。System Security Services Daemon (SSSD)は、LDAPやActive DirectoryなどのさまざまなIDと認証プロバイダーへのアクセスを提供します。

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によってサービスされるようになります。

ホストとコンテナのステップバイステップ設定

  1. ホストの設定
  • パッケージのインストール
    # yum -y install sssd-common sssd-proxy
    
  • コンテナ用のPAMサービスを作成します。
    # 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
    
  • SSSD設定ファイルを作成します(/etc/sssd/sssd.conf)。パーミッションは0600、所有者はroot:rootである必要があります。
    # 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
    
  • sssdを起動します
    # systemctl start sssd
    
  • sssdでユーザーを取得できることを確認します
    # getent passwd -s sss localuser
    
  1. コンテナの設定

SSSDのUNIXソケットがそこに存在するため、ホストの/var/lib/sss/pipesディレクトリをコンテナにバインドマウントすることが重要です。

-v /var/lib/sss/pipes:/var/lib/sss/pipes:rw
  1. コンテナの設定

以下の手順はすべてコンテナ自体で実行する必要があります。

  • 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イメージを保存し、アプリケーションのベースイメージとして使用します。

  • YARN環境で起動したDockerイメージをテストします。

    $ id
    uid=5000(localuser) gid=5000(localuser) groups=5000(localuser),1337(hadoop)
    

例:MapReduce

この例では、Hadoopが/usr/local/hadoopにインストールされていることを前提としています。

また、Dockerイメージを圧縮してHDFSにアップロードする必要があります。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

アプリケーションマスター、マップタスク、およびリデュースタスクは個別に構成されていることに注意してください。この例では、3つすべてにhadoop-imageイメージを使用しています。

例:Spark

この例では、Hadoopが/usr/local/hadoopに、Sparkが/usr/local/sparkにインストールされていることを前提としています。

また、Dockerイメージを圧縮してHDFSにアップロードする必要があります。runCで使用できるイメージに変換する方法については、DockerイメージをrunCイメージに変換するを参照してください。この例では、hadoop-imageという名前のイメージが既に準備されていると仮定します。

さらに、container-executor.cfg内のrunc.allowed.ro-mountsが、/usr/local/hadoop,/etc/passwd,/etc/groupディレクトリを含むように更新されています。

runCコンテナでSparkシェルを実行するには、次のコマンドを実行します。

  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イメージを使用しています。