使用自定义镜像创建CGroup V2节点

Kubernetes采用CGroup实现容器的资源隔离。CGroup V2统一了访问资源的路径,支持Pod级别的资源监控、网络重定向,同时在跨多资源协调上具备更强的资源隔离能力。本文介绍如何使用ack-image-builder工具构建CGroup V2的自定义镜像,并在ACK控制台使用自定义镜像创建CGroup V2节点。

背景信息

CGroup

Kubernetes采用CGroup实现容器的资源隔离。CGroup分为V1和V2版本,V2版本提供了更一致的体验和更丰富的功能。主要特性如下。

  • 统一了访问资源的路径,各种资源处于统一路径下。

  • 新增PSI等功能特性。

  • 支持CGroup级别的eBPF挂载,可以实现Pod级别的资源监控、网络重定向等。

  • 在跨多资源协调上具备更强的资源隔离能力。

    • 统一地管理各种类型的内存分配,例如网络内存、Kernel内存等。

    • 支持异步资源变化的统计,例如通过Page Cache的Write-back统计实现异步IO的限制。

Kubernetes在1.18版本中支持CGroup V2,进入Alpha阶段,在1.22版本中进入Beta阶段,在1.25中进入GA。更多信息,请参见About cgroup v2

ack-image-builder

ack-image-builder是阿里云推出的一款镜像构建工具,旨在通过简易的方式自动化构建镜像。利用ack-image-builder可以构建出CGroup V2的系统镜像,方便您在ACK集群中添加CGroup V2的节点。关于ack-image-builder,请参见ack-image-builder

ack-image-builder基于开源工具HashiCorp Packer开发,HashiCorp Packer提供默认配置模板和校验脚本。关于HashiCorp Packer,请参见HashiCorp Packer

使用限制

限制项

说明

操作系统

目前仅Alibaba Cloud Linux 3支持CGroup V2。所以仅支持使用Alibaba Cloud Linux 3作为基础镜像来构建支持CGroup V2的自定义镜像。

运行时

仅支持containerd运行时。

Kubernetes

1.28及以上版本。

应用或组件

如果集群上运行的应用或者组件依赖于CGroup,请确保它们与CGroup V2兼容。

  • 一般监控类的组件依赖CGroup,需要确保它们与CGroup V2兼容。

  • 使用ack-koordinator组件来控制Pod资源,版本需为v1.1.0以上,以便兼容CGroup V2。更多信息,请参见ack-koordinator(ack-slo-manager)

注意事项

如果使用Java的应用,建议采用JDK 11.0.16或者JDK 15之后的版本,以便与CGroup V2兼容。更多信息,请参见JDK-8230305

前提条件

已前往配额平台申请使用自定义镜像。

操作步骤

使用ack-image-builder创建Kubernetes集群自定义节点镜像的步骤如下。

cgroup

  1. 安装Packer。

    1. 单击下载页面,选择操作系统对应的软件版本并安装Packer。关于安装Packer,请参见安装文档

    2. 执行如下命令,查看Packer版本信息。

      packer version

      预期输出:

      Packer v1.*.*

      表示Packer已安装成功。

  2. 执行如下命令,下载CGroup V2的配置模板。

    git clone https://github.com/AliyunContainerService/ack-image-builder.git
    cd ack-image-builder
  3. 构建CGroup V2的节点自定义镜像。

    1. 执行如下命令,导入AccessKey信息用于创建构建镜像过程中的临时资源。

      export ALICLOUD_ACCESS_KEY=XXXXXX
      export ALICLOUD_SECRET_KEY=XXXXXX
    2. 执行如下命令,制作自定义镜像。

      packer build  -var cgroup_mode=CGROUP_MODE_V2 examples/ack-aliyunlinux3.json

      其中cgroup_mode的参数为镜像采用的CGroup模式,默认为CGROUP_MODE_V1。此处指定为CGROUP_MODE_V2,构建出的自定义镜像采用CGroup V2的CGroup模式。

      展开查看预期输出

      salicloud-ecs output will be in this color.
      
      ==> alicloud-ecs: Prevalidating source region and copied regions...
      ==> alicloud-ecs: Prevalidating image name...
          alicloud-ecs: Found image ID: aliyun_3_x64_20G_alibase_20221102.vhd
      ==> alicloud-ecs: Creating temporary keypair: xxxxxx
      ==> alicloud-ecs: Creating vpc...
          alicloud-ecs: Created vpc: xxxxxx
      ==> alicloud-ecs: Creating vswitch...
          alicloud-ecs: Created vswitch: xxxxxx
      ==> alicloud-ecs: Creating security group...
          alicloud-ecs: Created security group: xxxxxx
      ==> alicloud-ecs: Creating instance...
          alicloud-ecs: Created instance: xxxxxx
      ==> alicloud-ecs: Allocating eip...
          alicloud-ecs: Allocated eip: xxxxxx
          alicloud-ecs: Attach keypair xxxxxx to instance: xxxxxx
      ==> alicloud-ecs: Starting instance: xxxxxx
      ==> alicloud-ecs: Using ssh communicator to connect: xx.xx.xx.xx
      ==> alicloud-ecs: Waiting for SSH to become available...
      ==> alicloud-ecs: Connected to SSH!
      ......
      ==> alicloud-ecs: Provisioning with shell script: scripts/set-cgroupv2.sh
          alicloud-ecs: CGROUP_MODE_V2
          alicloud-ecs: set cgroup mode to CGROUP_MODE_V2
      ......
      ==> alicloud-ecs: Stopping instance: xxxxxx
      ==> alicloud-ecs: Waiting instance stopped: xxxxxx
      ==> alicloud-ecs: Creating image: test_image1564110199
          alicloud-ecs: Detach keypair xxxxxx from instance: xxxxxxx
      ==> alicloud-ecs: Cleaning up 'EIP'
      ==> alicloud-ecs: Cleaning up 'instance'
      ==> alicloud-ecs: Cleaning up 'security group'
      ==> alicloud-ecs: Cleaning up 'vSwitch'
      ==> alicloud-ecs: Cleaning up 'VPC'
      ==> alicloud-ecs: Deleting temporary keypair...
      Build 'alicloud-ecs' finished.
      
      ==> Builds finished. The artifacts of successful builds are:
      --> alicloud-ecs: Alicloud images were created:
      
      cn-hangzhou: m-xxxxxxxxxxxxxxxxx

      其中scripts/set-cgroupv2.sh为设置CGroup版本,m-xxxxxxxxxxxxxxxxx为自定义镜像ID。

  4. 采用CGroup V2镜像创建集群。

    下文以创建ACK集群Pro版为例。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击页面右上角的创建集群

    3. ACK托管版页签下,配置使用自定义镜像创建集群的参数,然后按照页面指引完成集群的创建。

      以下仅介绍重点参数的配置方法。关于参数的详细配置,请参见创建ACK托管集群

      1. 完成集群配置后,单击下一步:节点池配置

      2. 节点池配置向导页面,单击显示高级选项。单击自定义镜像后面的选择

      3. 选择自定义镜像页面,选择目标镜像,然后单击使用

      4. 完成集群的其他配置。

      集群创建完成后,该集群的节点会使用了自定义镜像,后续节点池中扩容的节点也均会使用该镜像。

  5. 登录集群节点,执行如下命令查看CGroup类型。验证集群中的节点是否采用了CGroup V2。

    df -T /sys/fs/cgroup

    预期结果:

    Filesystem     Type    1K-blocks  Used Available Use% Mounted on
    cgroup2        cgroup2         0     0         0    - /sys/fs/cgroup

    表示集群中的节点采用了CGroup V2。

CGroup V2常用使用场景

使用CGroup V2限制容器IO速度

"CGroup V1"对异步的"blockio"统计不准确,导致容器的IO的统计和限制通常大大小于实际应用IO的量。

而在"CGroup V2"中会同时将这部分异步的IO统计到正确容器中,所以我们可以采用"CGroup V2"来限制容器的IO。

限制方式:

通过将对应的磁盘的I/O限制写入到容器的"CGroupV2"的"io.max"限制文件中达到限制容器IO的效果。

详细配置内容参考链接

示例:

在容器启动时,我们对容器的"CGroupV2"做IO的限制,随后启动"dd"命令来验证限制后整体io被控制在限制的带宽值:

apiVersion: v1
kind: Pod
metadata:
  name: write-file-pod
spec:
  restartPolicy: Never
  containers:
    - name: dd-container
      image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3
      command:
      - bash
      - -c
      - "yum install -y sysstat; \ 
         echo '253:0 wbps=10485760' > /sys/fs/cgroup$(cat /proc/1/cgroup | awk -F ':' '{print $3}')/io.max; \
         dd if=/dev/zero of=/writefile bs=100M count=10 & iostat -dh 1 30;"
      securityContext:
        privileged: true
# 其中 "echo '253:0 wbps=10485760' > /sys/fs/cgroup/.../io.max"为io限制配置
# "253:0" 为磁盘的设备id,可以根据实际环境中写入的磁盘设备调整
# "wbps"  是磁盘写入带宽限制, 10485760=10MB/s

将如上Pod部署到集群中后,查看Pod日志可以看到磁盘的IO被限制到配置的10MB/s。

# kubectl logs write-file-pod -f  
....
      tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn Device
    91.00         0.0k        10.8M       0.0k      10.8M vda

      tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn Device
    88.00         0.0k         9.6M       0.0k       9.6M vda