在 AMI 中预拉 docker 镜像以减少节点和 pod 的新启动时间会减慢它在使用 nvidia-docker 和启用 GPU 的 pod 时的执行速度

rep*_*pié 9 amazon-web-services docker kubernetes tensorflow

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

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

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

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

我的问题是,当我生成一个带有我的大图像的 AMI 并使用这个 AMI 时,一切都按预期工作,并且 docker 图像没有像已经存在的那样下载,因此 pod 几乎在 1 秒内启动,但 pod 本身运行速度慢了 1000 倍如果 docker 镜像没有预先拉到 AMI 上。

我在做什么:

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

如果我不预拉我的 docker 映像,那么它会正常运行,只有当我预拉它时,才使用生成的新 AMI 然后 eben 如果它在一秒钟内运行,容器将像以前一样慢。

我的 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":""
  }
}
Run Code Online (Sandbox Code Playgroud)

这是为 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
Run Code Online (Sandbox Code Playgroud)

无论如何,只要我放了这条线:

docker pull $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$ENVIRONMENT_NAME
Run Code Online (Sandbox Code Playgroud)

我面临着同样的奇怪问题,当 pod 被安排在从这个 AMI 启动的节点上时,它说“机器上已经存在图像”,所以它不会再次拉它,但是当使用 TensorFlow 时,容器速度非常慢,例如。ts.Session() 需要一分钟才能运行。

编辑#2

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

文件

FROM tensorflow/tensorflow:1.14.0-gpu-py3
CMD ["python", "main.py"]
Run Code Online (Sandbox Code Playgroud)

主文件

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)
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*han 2

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

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

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