Что такое lxcfs? Лучшие практики для lxcfs для достижения изоляции представления ресурсов контейнера

Linux

LXCFS is a small FUSE filesystem written with the intention of making Linux containers feel more like a virtual machine. It started as a side-project of LXC but is useable by any runtime.

"

Объясню по человечески:

xcfs — это реализация FUSE (файловой системы Userland) с открытым исходным кодом для поддержки контейнеров LXC, она также может поддерживать контейнеры Docker. Позвольте приложению в контейнере пройти сопоставление lxcfs при чтении информации о памяти и ЦП и перейти к своим собственным виртуальным данным, прочитанным через информацию определения, связанную с контейнером, в контрольной группе.

"

Что такое изоляция представления ресурсов?

Технология контейнеров обеспечивает изоляцию среды, которая отличается от традиционной технологии виртуальных машин. Обычные контейнеры Linux ускоряют упаковку и запуск контейнера, но также снижают степень изоляции контейнера. Одной из самых известных проблем с контейнерами Linux является проблема изоляции представления ресурсов.

Контейнеры могут использовать контрольные группы для ограничения использования ресурсов, в том числе: памяти, ЦП и т. д. Однако следует отметить, что если процесс в контейнере использует некоторые общие команды мониторинга, такие как: free, top и другие команды, то он фактически видит данные физической машины, а не данные контейнера. Это потому, что контейнер не делает это правильно/proc, /sysИзоляция представлений ресурсов, таких как файловые системы.

Зачем нужна изоляция представления ресурсов контейнера?

  1. С точки зрения контейнеров обычно есть некоторые бизнес-разработчики, которые привыкли использовать традиционные физические машины и виртуальные машины.top, freeДождитесь команд для просмотра использования ресурсов системы, но контейнер не изолирует представление ресурсов, поэтому данные, видимые в контейнере, по-прежнему являются данными физической машины.

  2. С точки зрения приложения среда выполнения процесса в контейнере отличается от среды выполнения процесса на виртуальной машине физической машины. И некоторые приложения, запускающие процессы в контейнерах, будут иметь некоторые риски безопасности:

    Для многих Java-программ на основе JVM размер кучи и стека JVM будет распределяться в соответствии с ограничением системных ресурсов при запуске приложения. Однако при запуске приложения JAVA в контейнере данные памяти, полученные JVM, по-прежнему являются данными физической машины, а квота ресурсов, выделенная контейнером, меньше, чем размер ресурсов, требуемый при запуске JVM, что приведет к программа запускается безуспешно.

    Для программ, которым необходимо получить информацию о процессоре хоста, например, при разработке сервера golang, вам необходимо получить golangruntime.GOMAXPROCS(runtime.NumCPU())Или когда эксплуатация и техническое обслуживание задают количество процессов запуска службы (типа worker_processes auto в конфигурации nginx), они вроде автоматически определяют количество ЦП в запущенной среде через программу. Но процесс внутри контейнера всегда будет начинаться с/proc/cpuinfoКоличество ядер ЦП, полученных в контейнере, и количество ядер в контейнере/procФайловая система по-прежнему находится на физическом компьютере, что влияет на статус работы службы, работающей в контейнере.

    Как сделать изоляцию представления ресурсов контейнера?

    lxcfs был создан, чтобы решить эту проблему.

    lxcfs считывает соответствующую информацию о системе в cgroup посредством монтирования файлов и монтирует ее в систему proc внутри контейнера через том докера. Тогда пусть приложение в докере думает, что это настоящий прок хоста, который читается при чтении информации в проке.

    Ниже приведена архитектурная схема принципа работы lxcfs:

    lxcfs

    Объясните эту картину, когда мы ставим хост/var/lib/lxcfs/proc/memoinfoфайл, смонтированный в контейнер Docker/proc/meminfoПосле расположения, когда процесс в контейнере читает содержимое соответствующего файла, lxcfs/dev/fuseРеализация будет считывать правильный лимит памяти из соответствующей Cgroup контейнера. Это позволяет приложению получать правильные ограничения ресурсов. То же самое верно и для ограничений процессора.

    Изоляция представления ресурсов через lxcfs

    установить lxcfs

    wget https://copr-be.cloud.fedoraproject.org/results/ganto/lxc3/epel-7-x86_64/01041891-lxcfs/lxcfs-3.1.2-0.2.el7.x86_64.rpm;
    rpm -ivh lxcfs-3.1.2-0.2.el7.x86_64.rpm --force --nodeps
    

    Проверьте, прошла ли установка успешно

    [root@ifdasdfe2344 system]# lxcfs -h
    Usage:
    
    lxcfs [-f|-d] [-p pidfile] mountpoint
      -f running foreground by default; -d enable debug output
      Default pidfile is /run/lxcfs.pid
    lxcfs -h
    

    запустить lxcfs

    Начать прямо в фоновом режиме

    lxcfs /var/lib/lxcfs &
    

    Запустить через systemd (рекомендуется)

    touch /usr/lib/systemd/system/lxcfs.service
    
    cat > /usr/lib/systemd/system/lxcfs.service <<EOF
    [Unit]
    Description=lxcfs
    
    [Service]
    ExecStart=/usr/bin/lxcfs -f /var/lib/lxcfs
    Restart=on-failure
    #ExecReload=/bin/kill -s SIGHUP $MAINPID
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
    systemctl daemon-reload
    systemctl start lxcfs.service
    

    Проверьте, был ли запуск успешным

    [root@ifdasdfe2344 system]# ps aux | grep lxcfs
    root      3276  0.0  0.0 112708   980 pts/2    S+   15:45   0:00 grep --color=auto lxcfs
    root     18625  0.0  0.0 234628  1296 ?        Ssl  14:16   0:00 /usr/bin/lxcfs -f /var/lib/lxcfs
    

    Запущен успешно.

    Проверить эффект lxcfs

    lxcfs не включен

    Сначала мы запускаем контейнер на машине, на которой не включена lxcfs, и входим в контейнер, чтобы просмотреть информацию о процессоре и памяти. Чтобы увидеть очевидную разницу, мы использовали сервер высокой конфигурации (32c128g).

    # 执行以下操作
    systemctl stop lxcfs
    
    docker run -it ubuntu /bin/bash # 进入到 nginx 容器中
    
    free -h
    
    image-20200704180911456

    Из приведенных выше результатов видно, что хотя информация о памяти просматривается в контейнере, отображается meminfo хоста.

    # 看一下 CPU 的核数
    cat /proc/cpuinfo| grep "processor"| wc -l
    
    image-20200704181007610

    Результат согласуется с нашей догадкой: если lxcfs не включена, информация о процессоре, видимая контейнером, совпадает с информацией о хосте.

    включить lxcfs

    systemctl start lxcfs
    
    # 启动一个容器,用 lxcfs 的 /proc 文件映射到容器中的 /proc 文件,容器内存设置为 256M:
    docker run -it -m 256m \\
          -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \\
          -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \\
          -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \\
          -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \\
          -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \\
          -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \\
          ubuntu:latest /bin/bash
    
    free -h
    
    image-20200704181044965

    Видно, что память самого контейнера получена корректно, и изоляция представления ресурсов для памяти прошла успешно.

    # --cpus 2,限定容器最多只能使用两个逻辑CPU
    
    docker run -it --rm -m 256m  --cpus 2  \\
          -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \\
          -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \\
          -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \\
          -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \\
          -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \\
          -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \\
          ubuntu:latest /bin/sh
    
    image-20200704181153515

    cpuinfo также является количеством логических процессоров, которые может использовать наш контейнер. Указание того, что контейнер может работать только на указанном количестве ЦП, должно иметь больше преимуществ, чем недостатков, то есть при создании контейнера вам нужно выполнить некоторую дополнительную работу и разумно выделить процессорный набор.

    Kubernetes на практике с lxcfs

    Использование lxcfs в kubernetes требует решения двух проблем:

    Первая проблема заключается в запуске lxcfs на каждом узле;

    Вторая проблема заключается в монтировании файла /proc, поддерживаемого lxcfs, в каждый контейнер;

    Способ DaemonSet для запуска файловой системы lxcfs FUSE

    Для первого вопроса мы используем daemonset для установки lxcfs на каждом узле k8s.

    Используйте следующий файл yaml напрямую:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: lxcfs
      labels:
        app: lxcfs
    spec:
      selector:
        matchLabels:
          app: lxcfs
      template:
        metadata:
          labels:
            app: lxcfs
        spec:
          hostPID: true
          tolerations:
          - key: node-role.kubernetes.io/master
            effect: NoSchedule
          containers:
          - name: lxcfs
            image: registry.cn-hangzhou.aliyuncs.com/denverdino/lxcfs:3.0.4
            imagePullPolicy: Always
            securityContext:
              privileged: true
            volumeMounts:
            - name: cgroup
              mountPath: /sys/fs/cgroup
            - name: lxcfs
              mountPath: /var/lib/lxcfs
              mountPropagation: Bidirectional
            - name: usr-local
              mountPath: /usr/local
          volumes:
          - name: cgroup
            hostPath:
              path: /sys/fs/cgroup
          - name: usr-local
            hostPath:
              path: /usr/local
          - name: lxcfs
            hostPath:
              path: /var/lib/lxcfs
              type: DirectoryOrCreate
    
    kubectl apply -f lxcfs-daemonset.yaml
    
    image-20200704181243710

    Вы можете видеть, что набор демонов lxcfs был развернут на каждом узле.

    Сопоставьте файлы proc lxcfs с контейнерами

    Что касается второй проблемы, у нас есть два метода ее решения.

    Первый — просто объявить хост в yaml-файле развертывания k8s./var/lib/lxcfs/procСерия файловых креплений.

    Второй метод использует механизм расширения Kubernetes Initializer для автоматического монтирования файла lxcfs. ноInitializerConfigurationФункция k8s больше не поддерживается после k8s 1.14 и здесь повторяться не будет. Но мы можем для достижения той же цели реализовать administrator-webhook (управление доступом (Admission Control) для дальнейшей проверки запроса после авторизации или добавить параметры по умолчанию, https://kubernetes.feisky.xyz/extension/auth/admission).

    # 验证你的 k8s 集群是否支持 admission
    $ kubectl api-versions | grep admissionregistration.k8s.io/v1beta1
    admissionregistration.k8s.io/v1beta1
    

    Написание accept-webhook выходит за рамки этой статьи, вы можете перейти к официальной документации, чтобы узнать больше.

    Вот пример реализации веб-хука допуска lxcfs, вы можете обратиться к: https://github.com/hantmac/lxcfs-admission-webhook.

    Суммировать

    В этой статье представлен метод обеспечения изоляции представления ресурсов контейнера с помощью lxcfs, который может помочь некоторым контейнерным приложениям лучше идентифицировать ограничения ресурсов среды выполнения контейнера.

    В то же время в этой статье мы представляем использование контейнеров и DaemonSet для развертывания lxcfs FUSE, что не только значительно упрощает развертывание, но и облегчает использование собственных возможностей управления контейнерами Kubernetes для поддержки автоматического восстановления, когда процесс lxcfs при сбое и при масштабировании кластера.Это также может обеспечить согласованность развертывания узла. Этот метод применим к другому подобному мониторингу или расширению системы.

    Кроме того, мы представили использование веб-перехватчика допуска Kubernetes для автоматизации монтирования файлов lxcfs. Весь процесс прозрачен для разработчиков приложений, что может значительно упростить эксплуатацию и обслуживание.