在 AMI 中预拉取 docker 映像以减少节点和 Pod 的全新启动时间,在使用 nvidia-docker 和启用 GPU 的 Pod 时会减慢其执行速度

问题描述 投票:0回答:1

在 AWS 上使用 Kubernetes v1.16,我在尝试减少在新生成的节点上启动 pod 所需的时间时遇到了一个奇怪的问题。

默认情况下,节点 AMI 不包含任何预缓存的 docker 镜像,因此当 pod 被调度到其上时,它的第一个工作是拉取 docker 镜像。

拉取大型 docker 镜像可能需要一段时间,因此 pod 需要很长时间才能运行。

最近我想到了将大型 docker 镜像预先拉入 AMI 的想法,这样当 pod 被安排到它上面时,就不必下载它。事实证明,很多人都在做这个 dor 一段时间,被称为“烘焙 AMI”:

我的问题是,当我生成一个带有大映像的 AMI 并使用该 AMI 时,一切都按预期运行,并且 docker 映像不会像已经存在的那样下载,因此 pod 几乎在 1 秒内启动,但 pod 本身运行了 1000 次比未在 AMI 上预先拉取 docker 映像的速度慢。

我在做什么:

  • 在 EC2 实例上启动基本工作 AMI
  • 通过 ssh 访问它
  • 运行 docker pull myreposiroty/myimage
  • 从 AWS 控制台右键单击 EC2 实例并生成 AMI

如果我不预拉我的 docker 镜像,那么只有当我使用生成的新 AMI 预拉它时,它才能正常运行,然后如果它在一秒钟内运行,那么容器将变得前所未有的缓慢。

我的docker镜像使用GPU资源,它基于tensorflow/tensorflow:1.14.0-gpu-py3镜像。这似乎与使用nvidia-docker和tensorflow om GPU启用的EC2有关。

如果有人知道这种极端的运行延迟从何而来,我们将不胜感激。

编辑#1

从那时起,我现在使用 Packer 来构建我的 AMI。 这是我的模板文件:

{
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key": "{{user `aws_access_key`}}",
      "secret_key": "{{user `aws_secret_key`}}",
      "ami_name": "compute-{{user `environment_name`}}-{{timestamp}}",
      "region": "{{user `region`}}",
      "instance_type": "{{user `instance`}}",
      "ssh_username": "admin",
      "source_ami_filter": {
        "filters": {
          "virtualization-type": "hvm",
          "name": "debian-stretch-hvm-x86_64-gp2-*",
          "root-device-type": "ebs"
        },
        "owners":"379101102735",
        "most_recent": true
      }
    }
  ],
  "provisioners": [
    {
      "execute_command": "sudo env {{ .Vars }} {{ .Path }}",
      "scripts": [
        "ami/setup_vm.sh"
      ],
      "type": "shell",
      "environment_vars": [
        "ENVIRONMENT_NAME={{user `environment_name`}}",
        "AWS_ACCOUNT_ID={{user `aws_account_id`}}",
        "AWS_REGION={{user `region`}}",
        "AWS_ACCESS_KEY_ID={{user `aws_access_key`}}",
        "AWS_SECRET_ACCESS_KEY={{user `aws_secret_key`}}",
        "DOCKER_IMAGE_NAME={{user `docker_image_name`}}"
      ]
    }
  ],
  "post-processors": [
    {
      "type": "manifest",
      "output": "ami/manifest.json",
      "strip_path": true
    }
  ],
  "variables": {
    "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
    "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
    "environment_name": "",
    "region": "eu-west-1",
    "instance": "g4dn.xlarge",
    "aws_account_id":"",
    "docker_image_name":""
  }
}

这是为 Docker 和 Nvidia Docker 配置 AMI 的相关脚本:

#!/bin/bash
cd /tmp

export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=noninteractive

# docker
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian stretch stable"
apt-get update
apt-get install -y docker-ce
usermod -a -G docker $USER

# graphical drivers
apt-get install -y software-properties-common
wget http://us.download.nvidia.com/XFree86/Linux-x86_64/440.64/NVIDIA-Linux-x86_64-440.64.run
bash NVIDIA-Linux-x86_64-440.64.run -sZ

# nvidia-docker
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | tee /etc/apt/sources.list.d/nvidia-docker.list
apt-get update
apt-get install -y nvidia-container-toolkit
apt-get install -y nvidia-docker2
cat > /etc/docker/daemon.json <<EOL
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
EOL
systemctl restart docker

# enable nvidia-persistenced service
cat > /etc/systemd/system/nvidia-persistenced.service <<EOL
[Unit]
Description=NVIDIA Persistence Daemon
Wants=syslog.target

[Service]
Type=forking
PIDFile=/var/run/nvidia-persistenced/nvidia-persistenced.pid
Restart=always
ExecStart=/usr/bin/nvidia-persistenced --verbose
ExecStopPost=/bin/rm -rf /var/run/nvidia-persistenced

[Install]
WantedBy=multi-user.target
EOL
systemctl enable nvidia-persistenced

# prepull docker
apt-get install -y python3-pip
pip3 install awscli --upgrade
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
docker pull $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$ENVIRONMENT_NAME

# Clean up
apt-get -y autoremove
apt-get -y clean

无论如何,一旦我写下这句话:

docker pull $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$ENVIRONMENT_NAME

我面临着同样奇怪的问题,当 Pod 被调度到从此 AMI 启动的节点上时,它会显示“图像已存在于机器上”,因此它不会再次拉取它,但是使用 TensorFlow 时容器会非常慢,例如。 ts.Session() 需要大约一分钟的时间来运行。

编辑#2

添加有关 pod 上执行内容的额外信息:

Dockerfile

FROM tensorflow/tensorflow:1.14.0-gpu-py3
CMD ["python", "main.py"]

主.py

import tensorflow as tf

config = tf.ConfigProto(allow_soft_placement=True)
config.gpu_options.allow_growth = True
return tf.Session(graph=tf.Graph(), config=config)

仅使用这些行,当图像被预拉时,TF 会话初始化最多需要 1 分钟才能完成,而当图像未预拉时,则需要 1 秒。

amazon-web-services docker tensorflow kubernetes amazon-ami
1个回答
2
投票

这很可能是由于新实例没有“完全下载”磁盘的所有部分。 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-initialize.html 有这方面的详细信息。

对于从快照创建的卷,必须先从 Amazon S3 拉取存储块并将其写入卷,然后才能访问它们。此初步操作需要时间,并且可能会导致首次访问每个块时 I/O 操作的延迟显着增加。所有块下载并写入卷后,即可实现卷性能。

当图像从S3完全下载后,我假设一切都会恢复正常速度。

© www.soinside.com 2019 - 2024. All rights reserved.