Docker 컨테이너를 사용한 애플리케이션 실행

Docker 컨테이너를 사용한 애플리케이션 실행 (Launching Applications Using Docker Containers)

YARN NodeManager가 YARN 컨테이너를 호스트 머신에서 직접 또는 Docker 컨테이너 안에서 실행하도록 하는 Linux Container Executor (LCE) 와 Docker 통합을 설명하는 문서예요. 클러스터 구성, Docker 이미지 요구사항, 애플리케이션 제출, 볼륨 마운트, 사용자 관리, 예시를 다룹니다.

출처: 문서

본문

보안 경고 (Security Warning)

중요 이 기능을 활성화하고 클러스터에서 Docker 컨테이너를 실행하는 것은 보안 영향이 있습니다. Docker가 많은 강력한 커널 기능과 통합된다는 점을 감안할 때, 관리자는 이 기능을 활성화하기 전에 반드시 Docker 보안을 이해해야 합니다.

개요 (Overview)

Docker는 Linux 컨테이너에 대한 사용하기 쉬운 인터페이스와 그 컨테이너를 위한 쉽게 만들 수 있는 이미지 파일을 결합합니다. 간단히 말해 Docker는 사용자가 애플리케이션을 선호하는 실행 환경과 함께 묶어 대상 머신에서 실행할 수 있게 해 줍니다. Docker에 대한 자세한 내용은 문서를 참고하세요.

Linux Container Executor(LCE)는 YARN NodeManager가 호스트 머신에서 직접 또는 Docker 컨테이너 안에서 YARN 컨테이너를 실행할 수 있게 합니다. 자원을 요청하는 애플리케이션은 각 컨테이너를 어떻게 실행해야 하는지 지정할 수 있어요. LCE는 또한 향상된 보안을 제공하며 보안 클러스터를 배포할 때 필요합니다. LCE가 Docker 컨테이너에서 실행할 YARN 컨테이너를 실행할 때 애플리케이션은 사용할 Docker 이미지를 지정할 수 있습니다.

Docker 컨테이너는 애플리케이션의 코드가 실행되는 사용자 정의 실행 환경을 제공하며, NodeManager와 다른 애플리케이션의 실행 환경에서 격리됩니다. 이 컨테이너는 애플리케이션이 필요로 하는 특수 라이브러리를 포함할 수 있고, Perl, Python, Java를 포함한 네이티브 도구와 라이브러리의 다른 버전을 가질 수 있습니다. Docker 컨테이너는 심지어 NodeManager에서 실행되는 것과 다른 Linux 배포판을 실행할 수도 있습니다.

YARN용 Docker는 일관성(모든 YARN 컨테이너가 같은 소프트웨어 환경을 가짐)과 격리(물리 머신에 설치된 것과 간섭 없음)를 모두 제공합니다.

클러스터 구성 (Cluster Configuration)

LCE는 container-executor 바이너리가 root:hadoop 소유이고 6050 권한을 가져야 합니다. Docker 컨테이너를 실행하려면 Docker 컨테이너가 실행될 모든 NodeManager 호스트에서 Docker 데몬이 실행 중이어야 해요. Docker 클라이언트도 Docker 컨테이너가 실행될 모든 NodeManager 호스트에 설치되고 Docker 컨테이너를 시작할 수 있어야 합니다.

작업 시작 중 타임아웃을 막으려면 애플리케이션이 사용할 큰 Docker 이미지를 미리 NodeManager 호스트의 Docker 데몬 캐시에 로드해야 합니다. 이미지를 로드하는 간단한 방법은 Docker pull 요청을 보내는 것입니다. 예:

sudo docker pull library/openjdk:8

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,docker</value>
    <description>
      Comma separated list of runtimes that are allowed when using
      LinuxContainerExecutor. The allowed values are default, docker, 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>
    <name>yarn.nodemanager.runtime.linux.docker.image-name</name>
    <value></value>
    <description>
      Optional. Default docker image to be used when the docker runtime is
      selected.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.image-update</name>
    <value>false</value>
    <description>
      Optional. Default option to decide whether to pull the latest image
      or not.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.allowed-container-networks</name>
    <value>host,none,bridge</value>
    <description>
      Optional. A comma-separated set of networks allowed when launching
      containers. Valid values are determined by Docker networks available from
      `docker network ls`
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.default-container-network</name>
    <value>host</value>
    <description>
      The network used when launching Docker containers when no
      network is specified in the request. This network must be one of the
      (configurable) set of allowed container networks.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.host-pid-namespace.allowed</name>
    <value>false</value>
    <description>
      Optional. Whether containers are allowed to use the host PID namespace.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed</name>
    <value>false</value>
    <description>
      Optional. Whether applications are allowed to run in privileged
      containers. Privileged containers are granted the complete set of
      capabilities and are not subject to the limitations imposed by the device
      cgroup controller. In other words, privileged containers can do almost
      everything that the host can do. Use with extreme care.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.delayed-removal.allowed</name>
    <value>false</value>
    <description>
      Optional. Whether or not users are allowed to request that Docker
      containers honor the debug deletion delay. This is useful for
      troubleshooting Docker container related launch failures.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.stop.grace-period</name>
    <value>10</value>
    <description>
      Optional. A configurable value to pass to the Docker Stop command. This
      value defines the number of seconds between the docker stop command sending
      a SIGTERM and a SIGKILL.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.privileged-containers.acl</name>
    <value></value>
    <description>
      Optional. A comma-separated list of users who are allowed to request
      privileged containers if privileged containers are allowed.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.capabilities</name>
    <value>CHOWN,DAC_OVERRIDE,FSETID,FOWNER,MKNOD,NET_RAW,SETGID,SETUID,SETFCAP,SETPCAP,NET_BIND_SERVICE,SYS_CHROOT,KILL,AUDIT_WRITE</value>
    <description>
      Optional. This configuration setting determines the capabilities
      assigned to docker containers when they are launched. While these may not
      be case-sensitive from a docker perspective, it is best to keep these
      uppercase. To run without any capabilities, set this value to
      "none" or "NONE"
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.enable-userremapping.allowed</name>
    <value>true</value>
    <description>
      Optional. Whether docker containers are run with the UID and GID of the
      calling user.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.userremapping-uid-threshold</name>
    <value>1</value>
    <description>
      Optional. The minimum acceptable UID for a remapped user. Users with UIDs
      lower than this value will not be allowed to launch containers when user
      remapping is enabled.
    </description>
  </property>

  <property>
    <name>yarn.nodemanager.runtime.linux.docker.userremapping-gid-threshold</name>
    <value>1</value>
    <description>
      Optional. The minimum acceptable GID for a remapped user. Users belonging
      to any group with a GID lower than this value will not be allowed to
      launch containers when user remapping is enabled.
    </description>
  </property>

</configuration>

또한 container-executor.cfg 파일이 존재하고 컨테이너 실행기에 대한 설정을 담아야 합니다. 파일은 root 소유에 0400 권한이어야 합니다. 파일 형식은 표준 Java properties 파일 형식입니다. 예:

key=value

Docker 지원을 활성화하는 데 필요한 속성은 다음과 같습니다.

구성 이름 설명
yarn.nodemanager.linux-container-executor.group NodeManager의 Unix 그룹. yarn-site.xml의 yarn.nodemanager.linux-container-executor.group과 일치해야 함.

container-executor.cfg는 컨테이너에 허용된 기능을 결정하는 섹션을 포함해야 합니다. 다음 속성을 담습니다.

구성 이름 설명
module.enabled Docker 컨테이너 실행을 활성화/비활성화하려면 "true" 또는 "false"여야 함. 기본값 0.
docker.binary Docker 컨테이너 실행에 사용하는 바이너리. 기본 /usr/bin/docker.
docker.allowed.capabilities 컨테이너가 추가할 수 있는 기능을 쉼표로 구분. 기본적으로 추가 허용 기능 없음.
docker.allowed.devices 컨테이너가 마운트할 수 있는 장치를 쉼표로 구분. 기본적으로 추가 허용 장치 없음.
docker.allowed.networks 컨테이너가 사용할 수 있는 네트워크를 쉼표로 구분. 컨테이너 실행 시 네트워크를 지정하지 않으면 기본 Docker 네트워크 사용.
docker.allowed.ro-mounts 컨테이너가 읽기 전용 모드로 마운트할 수 있는 디렉터리를 쉼표로 구분. 기본적으로 마운트 허용 디렉터리 없음.
docker.allowed.rw-mounts 컨테이너가 읽기-쓰기 모드로 마운트할 수 있는 디렉터리를 쉼표로 구분. 기본적으로 마운트 허용 디렉터리 없음.
docker.allowed.volume-drivers 사용이 허용된 볼륨 드라이버 목록을 쉼표로 구분. 기본적으로 허용 볼륨 드라이버 없음.
docker.host-pid-namespace.enabled 호스트의 PID 네임스페이스 사용을 활성화/비활성화하려면 "true" 또는 "false" 설정. 기본값 "false".
docker.privileged-containers.enabled privileged 컨테이너 실행을 활성화/비활성화하려면 "true" 또는 "false". 기본값 "false".
docker.privileged-containers.registries privileged docker 컨테이너 실행을 위한 privileged docker 레지스트리 목록을 쉼표로 구분. 기본적으로 정의된 레지스트리 없음.
docker.trusted.registries 신뢰되는 privileged docker 컨테이너 실행을 위한 신뢰 docker 레지스트리 목록을 쉼표로 구분. 기본적으로 정의된 레지스트리 없음.
docker.inspect.max.retries docker 컨테이너 준비 상태를 확인하는 정수 값. 각 검사는 3초 지연으로 설정. 기본값 10은 컨테이너 실패로 표시되기 전에 30초를 기다림.
docker.no-new-privileges.enabled docker run의 no-new-privileges 플래그 활성화/비활성화. "true"로 활성화, 기본 비활성화.
docker.allowed.runtimes 컨테이너가 사용할 수 있는 런타임을 쉼표로 구분. 기본적으로 추가 허용 런타임 없음.
docker.service-mode.enabled docker 컨테이너 서비스 모드를 활성화/비활성화하려면 "true" 또는 "false". 기본값 "false".

YARN 로컬 디렉터리에 접근해야 하는 Docker 컨테이너를 실행하려면 그것들을 docker.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에 모두 있으면 banned로 간주.
feature.tc.enabled "true" 또는 "false"여야 함. "false"는 traffic control 명령 비활성화, "true"는 허용
feature.yarn.sysfs.enabled "true" 또는 "false"여야 함. 자세한 내용은 YARN sysfs 지원 참고. 기본 비활성화

Docker 컨테이너 실행을 허용하는 container-executor.cfg 일부는 아래와 같습니다.

yarn.nodemanager.linux-container-executor.group=yarn
[docker]
  module.enabled=true
  docker.privileged-containers.enabled=true
  docker.privileged-containers.registries=local
  docker.trusted.registries=centos
  docker.allowed.capabilities=SYS_CHROOT,MKNOD,SETFCAP,SETPCAP,FSETID,CHOWN,AUDIT_WRITE,SETGID,NET_RAW,FOWNER,SETUID,DAC_OVERRIDE,KILL,NET_BIND_SERVICE
  docker.allowed.networks=bridge,host,none
  docker.allowed.ro-mounts=/sys/fs/cgroup
  docker.allowed.rw-mounts=/var/hadoop/yarn/local-dir,/var/hadoop/yarn/log-dir

Docker 이미지 요구사항 (Docker Image Requirements)

YARN과 함께 동작하려면 Docker 이미지에 대한 두 가지 요구사항이 있습니다.

첫째, Docker 컨테이너는 컨테이너 사용자로서 애플리케이션 소유자로 명시적으로 실행됩니다. 애플리케이션 소유자가 Docker 이미지의 유효한 사용자가 아니면 애플리케이션은 실패합니다. 컨테이너 사용자는 사용자의 UID로 지정됩니다. 사용자의 UID가 NodeManager 호스트와 Docker 이미지 사이에서 다르면, 컨테이너가 잘못된 사용자로 실행되거나 UID가 존재하지 않아 실행에 실패할 수 있어요. 자세한 내용은 Docker Container User Management 절을 참고하세요.

둘째, 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 이미지와 호환되어야 합니다. 그렇지 않으면 Docker 컨테이너에서 시작된 Hadoop 구성 요소가 외부 Hadoop 구성 요소와 통신하지 못할 수 있어요.

Docker 이미지에 command가 설정되어 있으면, 동작은 YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE이 true로 설정됐는지에 따라 달라집니다. true이면 LCE가 YARN의 컨테이너 실행 스크립트로 이미지를 실행할 때 명령이 대체됩니다.

Docker 이미지에 entry point가 설정되고 YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE이 true로 설정되면, launch_command가 Docker에서 CMD 파라미터로 ENTRYPOINT 프로그램에 전달됩니다. launch_command 형식은 param1,param2처럼 보이며, 이는 Docker에서 CMD [ "param1","param2" ]로 변환됩니다.

애플리케이션이 실행될 호스트의 Docker 데몬이 아직 로드하지 않은 Docker 이미지를 요청하면, Docker 데몬이 암시적으로 Docker pull 명령을 수행합니다. MapReduce와 Spark 둘 다 진행 보고에 10분 이상 걸리는 작업은 정지된 것으로 간주하므로, 큰 Docker 이미지를 지정하면 애플리케이션이 실패할 수 있습니다.

CGroups 구성 요구사항

Docker 플러그인은 cgroups를 사용해 개별 컨테이너의 자원 사용을 제한합니다. 실행된 컨테이너가 YARN에 속하므로 --cgroup-parent 명령줄 옵션으로 적절한 제어 그룹을 정의합니다.

Docker는 cgroupfs와 systemd의 두 cgroups 드라이버를 지원합니다. cgroupfs만 지원된다는 점에 유의하세요. systemd로 Docker 컨테이너를 실행하려 시도하면 다음과 비슷한 오류 메시지가 생깁니다.

Container id: container_1561638268473_0006_01_000002
Exit code: 7
Exception message: Launch container failed
Shell error output: /usr/bin/docker-current: Error response from daemon: cgroup-parent for systemd cgroup should be a valid slice named as "xxx.slice".
See '/usr/bin/docker-current run --help'.
Shell output: main : command provided 4

이것은 systemd 드라이버를 사용하는 각 호스트에서 Docker 데몬을 재구성해야 한다는 뜻입니다.

Hadoop이 실행되는 OS에 따라 재구성이 다른 단계를 요구할 수 있습니다. 하지만 cgroups 드라이버에 systemd를 선택했다면 시스템에 systemctl 명령이 있을 가능성이 높습니다.

Docker 데몬의 ExecStart 속성을 확인하세요.

~$ systemctl show --no-pager --property=ExecStart docker.service
ExecStart={ path=/usr/bin/dockerd-current ; argv[]=/usr/bin/dockerd-current --add-runtime
docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd
--userland-proxy-path=/usr/libexec/docker/docker-proxy-current
--init-path=/usr/libexec/docker/docker-init-current
--seccomp-profile=/etc/docker/seccomp.json
$OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY $REGISTRIES ;
ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }

이 예시는 native.cgroupdriver가 systemd임을 보여줍니다. 데몬의 유닛 파일에서 그것을 수정해야 합니다.

~$ sudo systemctl edit --full docker.service

이것은 편집을 위해 전체 구성을 띄웁니다. systemd 문자열을 cgroupfs로 바꾸기만 하면 됩니다. 변경을 저장하고 systemd와 Docker 데몬을 모두 재시작합니다.

~$ sudo systemctl daemon-reload
~$ sudo systemctl restart docker.service

애플리케이션 제출 (Application Submission)

Docker 컨테이너 실행을 시도하기 전에 일반 YARN 컨테이너를 요청하는 애플리케이션에 LCE 구성이 동작하는지 확인하세요. LCE 활성화 후 하나 이상의 NodeManager가 시작에 실패하면, 원인은 대부분 container-executor 바이너리의 소유권/권한이 잘못된 것입니다. 로그로 확인하세요.

애플리케이션을 Docker 컨테이너에서 실행하려면 애플리케이션 환경에 다음 환경 변수를 설정합니다.

환경 변수 이름 설명
YARN_CONTAINER_RUNTIME_TYPE 애플리케이션이 Docker 컨테이너에서 실행될지 결정. 값이 "docker"면 Docker 컨테이너에서 실행. 아니면 일반 프로세스 트리 컨테이너 사용.
YARN_CONTAINER_RUNTIME_DOCKER_IMAGE Docker 컨테이너 실행에 사용할 이미지 이름 지정. Docker 클라이언트의 run 명령에 전달할 수 있는 어떤 이미지 이름이든 사용 가능. 이미지 이름은 repo 접두어를 포함할 수 있음.
YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE Docker 컨테이너의 기본 명령이 대체되는지 제어. true로 설정하면 Docker 컨테이너의 명령은 "bash path_to_launch_script". 설정 안 하거나 false로 설정하면 Docker 컨테이너의 기본 명령 사용.
YARN_CONTAINER_RUNTIME_DOCKER_CONTAINER_NETWORK Docker 컨테이너가 사용할 네트워크 유형 설정. yarn.nodemanager.runtime.linux.docker.allowed-container-networks 속성이 결정한 유효한 값이어야 함.
YARN_CONTAINER_RUNTIME_DOCKER_PORTS_MAPPING bridge 네트워크 Docker 컨테이너의 포트 매핑을 지정. 환경 변수 값은 포트 매핑의 쉼표 구분 목록이어야 함. Docker run 명령의 "-p" 옵션과 동일. 값이 비어 있으면 "-P"가 추가됨.
YARN_CONTAINER_RUNTIME_DOCKER_CONTAINER_PID_NAMESPACE Docker 컨테이너가 사용할 PID 네임스페이스 제어. 기본적으로 각 Docker 컨테이너는 자신의 PID 네임스페이스를 가짐. 호스트의 네임스페이스를 공유하려면 yarn.nodemanager.runtime.linux.docker.host-pid-namespace.allowed 속성을 true로 설정해야 함. 호스트 PID 네임스페이스가 허용되고 이 환경 변수가 host로 설정되면 Docker 컨테이너는 호스트의 PID 네임스페이스를 공유. 다른 값은 허용되지 않음.
YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER Docker 컨테이너가 privileged 컨테이너인지 제어. privileged 컨테이너를 쓰려면 yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed 속성을 true로, 애플리케이션 소유자가 yarn.nodemanager.runtime.linux.docker.privileged-containers.acl 속성 값에 있어야 함. 이 환경 변수가 true로 설정되면 허용되면 privileged Docker 컨테이너 사용. 다른 값은 허용되지 않으므로 false로 설정하는 대신 설정하지 않은 채 두는 것이 좋음.
YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS Docker 컨테이너에 추가 볼륨 마운트 추가. 환경 변수 값은 마운트의 쉼표 구분 목록이어야 함. 모든 마운트는 source:dest[:mode]로 주어져야 하고 mode는 접근 유형을 지정하는 "ro"(읽기 전용) 또는 "rw"(읽기-쓰기)여야 함. 둘 다 지정하지 않으면 읽기-쓰기로 간주. mode는 bind propagation 옵션을 포함할 수 있음. 그 경우 mode는 [option], rw+[option], 또는 ro+[option] 형식. 유효한 bind propagation 옵션은 shared, rshared, slave, rslave, private, rprivate. 요청된 마운트는 container-executor.cfg의 docker.allowed.ro-mounts와 docker.allowed.rw-mounts 값에 따라 container-executor가 검증.
YARN_CONTAINER_RUNTIME_DOCKER_TMPFS_MOUNTS Docker 컨테이너에 추가 tmpfs 마운트 추가. 환경 변수 값은 컨테이너 내부 절대 마운트 지점의 쉼표 구분 목록이어야 함.
YARN_CONTAINER_RUNTIME_DOCKER_DELAYED_REMOVAL 컨테이너별로 Docker 컨테이너의 지연 삭제를 요청할 수 있게 함. true이면 yarn.nodemanager.delete.debug-delay-sec이 정의한 기간이 지날 때까지 Docker 컨테이너가 제거되지 않음. 관리자는 yarn-site 속성 yarn.nodemanager.runtime.linux.docker.delayed-removal.allowed로 이 기능을 비활성화할 수 있음. 기본 비활성화. 비활성화되거나 false로 설정되면 컨테이너는 종료되는 즉시 제거됨.
YARN_CONTAINER_RUNTIME_YARN_SYSFS_ENABLE 컨테이너 작업 디렉터리 sysfs 하위 디렉터리를 Docker 컨테이너 /hadoop/yarn/sysfs에 마운트 활성화. 클러스터 정보를 컨테이너에 채우는 데 유용.
YARN_CONTAINER_RUNTIME_DOCKER_SERVICE_MODE 이미지가 정의한 대로 docker 컨테이너를 실행하되 사용자를 설정하지 않는 Service Mode를 활성화(–user와 –group-add).
YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG docker 컨테이너 실행기가 원격 docker 이미지에 접근하는 데 사용할 docker 클라이언트 구성을 설정.

처음 두 개는 필수입니다. 나머지는 필요에 따라 설정할 수 있습니다. 환경 변수로 컨테이너 유형을 제어하는 것은 다소 이상적이지 않지만, YARN의 Docker 지원을 인식하지 못하는 애플리케이션(MapReduce와 Spark 등)이 애플리케이션 환경 구성 지원을 통해 그 이점을 활용할 수 있게 합니다.

애플리케이션이 Docker 컨테이너에서 실행되도록 제출되면 다른 YARN 애플리케이션과 정확히 동일하게 동작합니다. 로그는 집계되어 관련 히스토리 서버에 저장됩니다. 애플리케이션 수명 주기는 비-Docker 애플리케이션과 같습니다.

Docker 바인드 마운트 볼륨 사용 (Using Docker Bind Mounted Volumes)

경고 이 기능 활성화 시 주의해야 합니다. /, /etc, /run, /home 등(이에 국한되지 않음) 디렉터리에 대한 접근을 활성화하는 것은 권장되지 않으며 컨테이너가 호스트에 부정적 영향을 주거나 민감한 정보를 누출할 수 있습니다. 경고

호스트의 파일·디렉터리는 Docker가 volumes를 통해 제공하는 Docker 컨테이너 안에서 흔히 필요합니다. 로컬화된 자원, Apache Hadoop 바이너리, 소켓이 예시입니다. 이 필요를 지원하기 위해 YARN-6623은 관리자에게 컨테이너에 볼륨으로 바인드 마운트가 허용된 호스트 디렉터리의 화이트리스트를 설정하는 기능을 추가했습니다. YARN-5534는 관리 화이트리스트가 허용하면 사용자가 컨테이너에 마운트될 마운트 목록을 제공할 수 있게 추가했습니다.

이 기능을 사용하려면 다음이 구성되어야 합니다.

  • 관리자는 container-executor.cfg에서 docker.allowed.ro-mounts와 docker.allowed.rw-mounts를 마운트가 허용된 부모 디렉터리 목록으로 설정해 볼륨 화이트리스트를 정의합니다.
  • 애플리케이션 제출자는 애플리케이션 제출 시 YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS 환경 변수로 필요한 볼륨을 요청합니다.

관리자가 제공한 화이트리스트는 컨테이너에 마운트가 허용된 디렉터리의 쉼표 구분 목록으로 정의됩니다. 사용자가 제공한 소스 디렉터리는 지정된 디렉터리와 일치하거나 그 자식이어야 합니다.

사용자가 제공한 마운트 목록은 source :destination 또는 source :destination :mode 형식의 쉼표 구분 목록으로 정의됩니다. source는 호스트의 파일·디렉터리입니다. destination은 source가 바인드 마운트될 컨테이너 안의 경로입니다. mode는 사용자가 기대하는 마운트 모드를 정의하며 ro(읽기 전용) 또는 rw(읽기-쓰기)일 수 있습니다. 지정하지 않으면 rw로 간주합니다. mode는 bind propagation 옵션(shared, rshared, slave, rslave, private, rprivate)도 포함할 수 있습니다. 그 경우 mode는 option, rw+option, 또는 ro+option 형식이어야 합니다.

다음 예시는 이 기능을 사용해 자주 필요한 /sys/fs/cgroup 디렉터리를 YARN에서 실행되는 컨테이너에 마운트하는 방법을 설명합니다.

관리자는 container-executor.cfg에서 docker.allowed.ro-mounts를 "/sys/fs/cgroup"으로 설정합니다. 애플리케이션은 이제 "/sys/fs/cgroup"이 호스트에서 컨테이너로 읽기 전용 모드로 마운트되도록 요청할 수 있습니다.

애플리케이션 제출 시 YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS 환경 변수를 이 마운트를 요청하도록 설정할 수 있습니다. 이 예시에서 환경 변수는 "/sys/fs/cgroup:/sys/fs/cgroup:ro"로 설정됩니다. 대상 경로는 제한되지 않으므로, 주어진 관리 화이트리스트에서 "/sys/fs/cgroup:/cgroup:ro"도 유효합니다.

Docker 컨테이너의 사용자 관리 (User Management in Docker Container)

YARN의 Docker 컨테이너 지원은 NodeManager 호스트에 정의된 사용자의 uid:gid 정체성으로 컨테이너 프로세스를 실행합니다. NodeManager 호스트와 컨테이너 사이의 사용자·그룹 이름 불일치는 권한 문제, 컨테이너 실행 실패, 심지어 보안 허점을 초래할 수 있어요. 호스트와 컨테이너 모두에 대한 사용자·그룹 관리를 중앙화하면 이런 위험을 크게 줄입니다. YARN에서 컨테이너화된 애플리케이션을 실행할 때 어떤 uid:gid 쌍이 컨테이너의 프로세스를 실행하는 데 사용될지 이해하는 것이 필요합니다.

uid:gid 쌍이 무엇을 의미하는지 예를 들어 봅시다. 기본적으로 비보안 모드에서 YARN은 nobody 사용자로 프로세스를 실행합니다(비보안 모드에서 실행 사용자가 어떻게 결정되는지는 Using Cgroups with YARN 아래 표 참고). CentOS 기반 시스템에서 nobody 사용자의 uid는 99이고 nobody 그룹은 99입니다. 결과적으로 YARN은 docker run을 --user 99:99로 호출합니다. 컨테이너에서 nobody 사용자가 uid 99를 갖지 않으면 실행이 실패하거나 예상치 못한 결과가 생길 수 있어요.

이 규칙의 한 예외는 Privileged Docker 컨테이너 사용입니다. Privileged 컨테이너는 컨테이너 실행 시 uid:gid 쌍을 설정하지 않고 Dockerfile의 USER 또는 GROUP 항목을 존중합니다. 이는 privileged 컨테이너를 어떤 사용자로든 실행할 수 있게 하며 보안 영향이 있습니다. Privileged Docker 컨테이너를 활성화하기 전에 이런 영향을 이해하세요.

사용자·그룹 관리를 해결하는 방법은 많습니다. Docker는 기본적으로 컨테이너 안의 /etc/passwd(와 /etc/shadow)로 사용자를 인증합니다. Docker 이미지에서 제공하는 기본 /etc/passwd를 사용하면 적절한 사용자 항목이 없을 가능성이 높고 실행 실패로 이어질 수 있어요. 사용자·그룹 관리 중앙화를 강력히 권장합니다. 아래에 몇 가지 접근 방식을 설명합니다.

정적 사용자 관리 (Static user management)

사용자·그룹을 관리하는 가장 기본적인 접근은 Docker 이미지 안의 사용자·그룹을 수정하는 것입니다. 이 접근은 모든 컨테이너 프로세스가 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

이 접근은 사용자 추가의 유연성이 없어 테스트를 넘어서는 권장되지 않습니다.

바인드 마운팅 (Bind mounting)

조직이 각 시스템에 로컬 사용자를 만드는 자동화를 이미 갖고 있다면, 컨테이너 이미지를 직접 수정하는 대안으로 /etc/passwd와 /etc/group을 컨테이너에 바인드 마운트하는 것이 적절할 수 있습니다. /etc/passwd와 /etc/group 바인드 마운트를 활성화하려면 container-executor.cfg의 docker.allowed.ro-mounts를 갱신해 그 경로를 포함시키세요. 애플리케이션 제출 시 YARN_CONTAINER_RUNTIME_DOCKER_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 같은 다양한 정체성·인증 프로바이더에 대한 접근을 제공합니다.

전통적인 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
      
  2. 컨테이너 설정

SSSD UNIX 소켓이 있는 호스트의 /var/lib/sss/pipes 디렉터리를 컨테이너에 바인드 마운트하는 것이 중요합니다.

-v /var/lib/sss/pipes:/var/lib/sss/pipes:rw
  1. 컨테이너 구성

아래 모든 단계는 컨테이너 자체에서 실행해야 합니다.

  • sss 클라이언트 라이브러리만 설치
    # yum -y install sssd-client
    
  • /etc/nsswitch.conf에서 passwd와 group 데이터베이스에 sss가 구성됐는지 확인
  • 애플리케이션이 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)
    

Privileged 컨테이너 보안 고려 사항 (Privileged Container Security Consideration)

Privileged docker 컨테이너는 호스트 시스템 장치와 상호작용할 수 있습니다. 적절한 주의 없이 호스트 운영체제에 해를 끼칠 수 있어요. Hadoop 클러스터에서 privileged 컨테이너 실행을 허용하는 위험을 완화하기 위해, 인가되지 않은 privileged docker 이미지를 샌드박스로 막는 통제된 프로세스를 구현했습니다.

기본 동작은 어떤 privileged docker 컨테이너도 허용하지 않습니다. Privileged docker는 ENTRYPOINT가 활성화된 docker 이미지에서만, 그리고 docker.privileged-containers.enabled가 enabled로 설정됐을 때만 허용됩니다. Docker 이미지는 docker 컨테이너 안에서 root 권한으로 실행될 수 있지만, 호스트 레벨 장치 접근은 비활성화됩니다. 이는 개발자·테스터가 호스트 운영체제에 대한 해를 막는 일부 제한으로 인터넷의 docker 이미지를 실행할 수 있게 합니다.

docker 이미지가 개발자·테스터에 의해 신뢰할 수 있다고 인증되면, 신뢰되는 이미지를 신뢰 docker 레지스트리로 승격할 수 있습니다. 시스템 관리자는 docker.trusted.registries를 정의하고 개인 docker 레지스트리 서버를 설정해 신뢰 이미지를 승격할 수 있습니다. 시스템 관리자는 Docker Hub의 공식 docker 이미지가 신뢰 레지스트리의 일부가 되도록 허용할 수 있습니다. "library"는 공식 docker 이미지를 신뢰하는 데 사용할 이름입니다. container-executor.cfg 예시:

[docker]
  docker.privileged-containers.enabled=true
  docker.trusted.registries=library

docker.privileged-containers.registries를 사용해 Docker 이미지의 부분집합만 privileged 컨테이너로 실행되도록 세밀한 접근 제어를 정의할 수 있습니다. docker.privileged-containers.registries가 정의되지 않으면 YARN은 docker.trusted.registries를 privileged Docker 이미지의 접근 제어로 폴백합니다. 세밀한 접근 제어 예시:

[docker]
  docker.privileged-containers.enabled=true
  docker.privileged-containers.registries=local/centos:latest
  docker.trusted.registries=library

개발 환경에서 로컬 이미지에 신뢰를 활성화하려면 저장소 이름 접두어로 태그할 수 있습니다. 저장소 이름을 선택할 때는 Docker Hub에서 실수로 이미지를 pull 하지 않도록 로컬 호스트명과 포트 번호를 사용하거나 예약된 Docker Hub 키워드 "local"을 사용하는 것이 권장됩니다. Docker run은 이미지가 로컬에 없으면 Docker Hub에서 docker 이미지를 찾습니다. 이미지 이름에 로컬 호스트명·포트를 사용하면 docker hub에서 정식 이미지를 실수로 pull 하는 것을 막을 수 있어요. localhost:5000을 신뢰 레지스트리로 태그하는 예시:

docker tag centos:latest localhost:5000/centos:latest

로컬 저장소에 변경이 있는 Ubuntu 기반 이미지가 있고 사용하려 한다고 합시다. 다음 예시는 local_ubuntu 이미지에 태그합니다.

docker tag local_ubuntu local/ubuntu:latest

다음으로 docker.trusted.registries에 local을 추가해야 합니다. 이미지는 local/ubuntu로 참조할 수 있습니다.

신뢰 이미지는 NFS 게이트웨이를 통한 HDFS 같은 외부 장치나 호스트 레벨 Hadoop 구성을 마운트할 수 있습니다. 시스템 관리자가 docker.allow.rw-mounts 지시문으로 외부 볼륨 쓰기를 허용하면, privileged docker 컨테이너가 미리 정의된 볼륨의 호스트 레벨 파일을 완전히 제어할 수 있습니다.

YARN Service HTTPD 예시를 위해 container-executor.cfg는 예시가 실행되도록 centos docker 레지스트리가 신뢰된다고 정의해야 합니다.

컨테이너 재인수 요구사항 (Container Reacquisition Requirements)

재시작 시 NodeManager는 NodeManager 복구 과정의 일부로 /proc 파일 시스템에서 컨테이너의 PID 디렉터리 존재를 확인해 컨테이너가 여전히 실행 중인지 검증합니다. 보안 목적으로 OS 관리자는 /proc 파일 시스템에 대해 hidepid 마운트 옵션을 활성화할 수 있습니다. hidepid 옵션이 활성화되면 _yarn_ 사용자의 기본 그룹이 아래처럼 gid 마운트 플래그 설정으로 화이트리스트되어야 합니다. _yarn_ 사용자의 기본 그룹이 화이트리스트되지 않으면 컨테이너 재인수가 실패하고 NodeManager 재시작 시 컨테이너가 종료됩니다.

proc     /proc     proc     nosuid,nodev,noexec,hidepid=2,gid=yarn     0 0

Docker 신뢰 레지스트리 연결 (Connecting to a Docker Trusted Registry)

Docker 클라이언트 명령은 NodeManager 호스트의 기본 위치인 $HOME/.docker/config.json에서 구성을 읽습니다. Docker 구성은 보안 저장소 자격 증명이 저장되는 곳이므로, 이 방법으로 보안 Docker 리포지토리와 LCE를 사용하는 것은 권장되지 않습니다.

YARN-5428은 Distributed Shell에 Docker 클라이언트 구성을 안전하게 공급하는 지원을 추가했습니다. 사용 방법은 Distributed Shell 도움말을 참고하세요. 추가 프레임워크 지원이 계획되어 있습니다.

우회 방법으로 매 NodeManager 호스트에서 Docker 로그인 명령으로 Docker 데몬을 수동으로 보안 repo에 로그인할 수 있습니다.

  docker login [OPTIONS] [SERVER]

  Register or log in to a Docker registry server, if no server is specified
  "https://index.docker.io/v1/" is the default.

  -e, --email=""       Email
  -p, --password=""    Password
  -u, --username=""    Username

이 접근은 모든 사용자가 보안 repo에 접근할 수 있다는 뜻이라는 점에 유의하세요.

Hadoop은 YARN service API를 통해 Docker Trusted Registry와 통합합니다. Docker 레지스트리는 CSI 드라이버를 사용해 HDFS, S3 또는 외부 저장소에 Docker 이미지를 저장할 수 있습니다.

HDFS의 Docker 레지스트리 (Docker Registry on HDFS)

NFS Gateway는 HDFS를 NFS 마운트 지점으로 마운트하는 기능을 제공합니다. Docker Registry는 표준 파일 시스템 API로 HDFS 마운트 지점에 쓰도록 구성할 수 있습니다.

hdfs-site.xml에서 NFS 구성을 구성합니다:

    <property>
      <name>nfs.exports.allowed.hosts</name>
      <value>* rw</value>
    </property>

    <property>
      <name>nfs.file.dump.dir</name>
      <value>/tmp/.hdfs-nfs</value>
    </property>

    <property>
      <name>nfs.kerberos.principal</name>
      <value>nfs/[email protected]</value>
    </property>

    <property>
      <name>nfs.keytab.file</name>
      <value>/etc/security/keytabs/nfs.service.keytab</value>
    </property>

모든 데이터노드에서 hdfs 사용자로 NFS Gateway를 실행합니다:

$ $HADOOP_HOME/bin/hdfs --daemon start nfs3

각 데이터노드에서 nfs 마운트 지점이 /hdfs로 노출됩니다:

# mount -t nfs -o vers=3,proto=tcp,nolock,noacl,sync $DN_IP:/ /hdfs

여기서 DN_IP는 데이터노드의 IP 주소입니다.

container-executor.cfg는 library의 신뢰 Docker 이미지가 허용되도록 구성됩니다.

[docker]
  docker.privileged-containers.enabled=true
  docker.trusted.registries=library,registry.docker-registry.registry.example.com:5000
  docker.allowed.rw-mounts=/tmp,/usr/local/hadoop/logs,/hdfs

Docker Registry는 YARN service로 시작할 수 있습니다: registry.json

{
  "name": "docker-registry",
  "version": "1.0",
  "kerberos_principal" : {
    "principal_name" : "registry/[email protected]",
    "keytab" : "file:///etc/security/keytabs/registry.service.keytab"
  },
  "components" :
  [
    {
      "name": "registry",
      "number_of_containers": 1,
      "artifact": {
        "id": "registry:latest",
        "type": "DOCKER"
      },
      "resource": {
        "cpus": 1,
        "memory": "256"
      },
      "run_privileged_container": true,
      "configuration": {
        "env": {
          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
          "YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS":"/hdfs/apps/docker/registry:/var/lib/registry"
        },
        "properties": {
          "docker.network": "host"
        }
      }
    }
  ]
}

YARN service는 docker 컨테이너 안에서 /hdfs/apps/docker/registry에서 /var/lib/registry로 docker 마운트를 구성합니다.

yarn app -launch docker-registry /tmp/registry.json

Docker trusted registry는 YARN 프레임워크에 배포되며, 레지스트리에 접근하는 URL은 Hadoop Registry DNS 형식을 따릅니다.

registry.docker-registry.$USER.$DOMAIN:5000

docker-registry 애플리케이션이 YARN에서 STABLE 상태에 도달하면, 사용자는 이미지 이름에 registry.docker-registry.registry.example.com:5000/ 접두어를 붙여 Docker Trusted Registry로 docker 이미지를 push·pull할 수 있습니다.

S3의 Docker 레지스트리 (Docker Registry on S3)

Docker Registry는 자체 S3 드라이버와 YAML 구성을 제공합니다. YARN service 구성은 YAML 템플릿을 생성하고 Docker Registry가 S3 저장소로 직접 저장하도록 활성화할 수 있습니다. 이 옵션은 AWS에 Docker Trusted Registry를 배포할 때 최고의 선택입니다. Docker 레지스트리 저장 드라이버를 S3로 구성하려면 /etc/docker/registry/config.yml 파일을 마운트해야 하는데(YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS로), S3 버킷과 해당 accesskey·secretKey를 구성해야 합니다.

샘플 config.yml

version: 0.1
log:
    fields:
        service: registry
http:
    addr: :5000
storage:
    cache:
        blobdescriptor: inmemory
    s3:
        accesskey: #AWS_KEY#
        secretkey: #AWS_SECRET#
        region: #AWS_REGION#
        bucket: #AWS_BUCKET#
        encrypt: #ENCRYPT#
        secure:  #SECURE#
        chunksize: 5242880
        multipartcopychunksize: 33554432
        multipartcopymaxconcurrency: 100
        multipartcopythresholdsize: 33554432
        rootdirectory: #STORAGE_PATH#

Docker Registry는 YARN service로 시작할 수 있습니다: registry.json

{
  "name": "docker-registry",
  "version": "1.0",
  "kerberos_principal" : {
    "principal_name" : "registry/[email protected]",
    "keytab" : "file:///etc/security/keytabs/registry.service.keytab"
  },
  "components" :
  [
    {
      "name": "registry",
      "number_of_containers": 1,
      "artifact": {
        "id": "registry:latest",
        "type": "DOCKER"
      },
      "resource": {
        "cpus": 1,
        "memory": "256"
      },
      "run_privileged_container": true,
      "configuration": {
        "env": {
          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
          "YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS":"<path to config.yml>:/etc/docker/registry/config.yml",
        },
        "properties": {
          "docker.network": "host"
        }
      }
    }
  ]
}

S3 저장 드라이버에서 구성할 수 있는 추가 세부 사항과 파라미터는 https://docs.docker.com/registry/storage-drivers/s3/를 참고하세요.

예시: MapReduce

이 예시는 Hadoop이 /usr/local/hadoop에 설치됐다고 가정합니다.

추가로 container-executor.cfg의 docker.allowed.ro-mounts가 /usr/local/hadoop,/etc/passwd,/etc/group 디렉터리를 포함하도록 갱신됐습니다.

pi 작업을 Docker 컨테이너에서 실행하도록 제출하려면 다음 명령을 실행합니다:

  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="library/openjdk:8"

  export YARN_CONTAINER_RUNTIME_TYPE=docker
  export YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$IMAGE_ID
  export YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=$MOUNTS

  yarn jar $YARN_EXAMPLES_JAR pi \
    -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_TYPE=docker \
    -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=$MOUNTS \
    -Dmapreduce.map.env.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$IMAGE_ID \
    -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_TYPE=docker \
    -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=$MOUNTS \
    -Dmapreduce.reduce.env.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$IMAGE_ID \
    1 40000

application master, map 작업, reduce 작업이 독립적으로 구성된다는 점에 유의하세요. 이 예시에서는 세 가지 모두 openjdk:8 이미지를 사용합니다.

예시: Spark

이 예시는 Hadoop이 /usr/local/hadoop에, Spark가 /usr/local/spark에 설치됐다고 가정합니다.

추가로 container-executor.cfg의 docker.allowed.ro-mounts가 /usr/local/hadoop,/etc/passwd,/etc/group 디렉터리를 포함하도록 갱신됐습니다.

Docker 컨테이너에서 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="library/openjdk:8"

  $SPARK_HOME/bin/spark-shell --master yarn \
    --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
    --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$IMAGE_ID \
    --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=$MOUNTS \
    --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
    --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$IMAGE_ID \
    --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS=$MOUNTS

application master와 executors가 독립적으로 구성된다는 점에 유의하세요. 이 예시에서는 둘 다 openjdk:8 이미지를 사용합니다.

원격 컨테이너 레지스트리를 사용할 때 YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG는 인증에 사용되는 자격 증명이 담긴 config.json 파일을 참조해야 합니다.

  DOCKER_IMAGE_NAME=hadoop-docker
  DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
  spark-submit --master yarn \
  --deploy-mode cluster \
  --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
  --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
  --conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
  --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
  --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
  --conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
  sparkR.R

Docker 컨테이너 ENTRYPOINT 지원

Docker 지원이 Hadoop 2.x에 도입됐을 때 플랫폼은 기존 Hadoop 프로그램을 Docker 컨테이너 안에서 실행하도록 설계됐습니다. 로그 리다이렉션과 환경 설정은 Node Manager와 통합됩니다. Hadoop 3.x에서 Hadoop Docker 지원은 Hadoop 워크로드 실행을 넘어 확장되며, dockerfile의 ENTRYPOINT를 사용해 Docker 네이티브 형태의 Docker 컨테이너를 지원합니다. 애플리케이션은 YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE 환경 변수를 정의해 YARN 모드를 기본으로 할지 Docker 모드를 기본으로 할지 결정할 수 있습니다. 시스템 관리자도 클러스터의 기본 설정으로 설정해 ENTRY_POINT를 기본 동작 모드로 만들 수 있습니다.

yarn-site.xml에서 YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE을 node manager 환경 화이트리스트에 추가합니다:

<property>
        <name>yarn.nodemanager.env-whitelist</name>
        <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,HADOOP_YARN_HOME,HADOOP_HOME,PATH,LANG,TZ,HADOOP_MAPRED_HOME,YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE</value>
</property>

yarn-env.sh에서 정의합니다:

export YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE=true

ENTRYPOINT를 사용하지 않을 때의 요구사항 (YARN mode)

ENTRYPOINT를 사용하지 않을 때 두 가지 요구사항이 있습니다.

  1. 이미지 안에 /bin/bash가 있어야 합니다. 이것은 일반적으로 사실이지만, tiny Docker 이미지(예: shell 명령에 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
    
  2. 이미지 안에 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 컨테이너 YARN SysFS 지원

YARN SysFS는 YARN 프레임워크가 제공하는 유사 파일 시스템으로, 클러스터 정보를 Docker 컨테이너에 내보냅니다. 클러스터 정보는 /hadoop/yarn/sysfs 경로로 내보내집니다. 이 API는 애플리케이션 개발자가 외부 서비스 의존성 없이 클러스터 정보를 얻을 수 있게 해 줍니다. 사용자 정의 애플리케이션 마스터는 node manager REST API를 호출해 클러스터 정보를 채울 수 있습니다. YARN service 프레임워크는 클러스터 정보를 /hadoop/yarn/sysfs/app.json에 자동으로 채웁니다. YARN service에 대한 자세한 내용은 YARN Service를 참고하세요.

Docker 컨테이너 서비스 모드 (Docker Container Service Mode)

Docker Container Service Mode는 이미지가 정의한 대로 컨테이너를 실행하되 사용자(–user와 –group-add)를 설정하지 않습니다. 이 모드는 기본적으로 비활성화되어 있습니다. 관리자는 container-executor.cfg의 docker 섹션에서 docker.service-mode.enabled를 true로 설정해 활성화합니다.

docker 서비스 모드를 허용하는 container-executor.cfg 일부는 아래와 같습니다.

yarn.nodemanager.linux-container-executor.group=yarn
[docker]
  module.enabled=true
  docker.privileged-containers.enabled=true
  docker.service-mode.enabled=true

애플리케이션 사용자는 애플리케이션 환경에 YARN_CONTAINER_RUNTIME_DOCKER_SERVICE_MODE 환경 변수를 true 또는 false 값으로 내보내 작업 레벨에서 서비스 모드를 활성화·비활성화할 수 있습니다.

더 알아보기 (Learn more)