Как создать 100 виртуальных серверов для тестирования?

Это дешевый и подверженный ошибкам -способ выполнения сопоставления слов .

Обратите внимание, что theс пробелом после него не соответствует слову thereby, поэтому сопоставление с пробелом после theпозволяет избежать сопоставления этой строки в начале слов. Тем не менее, по-прежнему соответствует bathe(, если за ним следует пробел ), и не соответствует theв конце строки.

Чтобы правильно сопоставить слово the(или любое другое слово ), вы не должны использовать пробелы вокруг слова, так как это помешает вам сопоставить его в начале или конце строк или если оно окружено любым другим символом слова, отличным от -, например, любым символом пунктуации или символом табуляции.

Вместо этого используйте шаблон границы слова нулевой -ширины:

sed 's/\<the\>/this/'

\<и \>соответствуют границам до и после слова, то есть пробелу между словесным символом и не -словесным символом . Символ слова обычно представляет собой любой символ, соответствующий[[:alnum:]_](или [A-Za-z0-9_]в локали POSIX ).

В GNU sedвы также можете использовать \bвместо \<и \>:

.
sed 's/\bthe\b/this/'
11
07.07.2020, 23:50
1 ответ

Эта работа может хорошо подходить для контейнеров systemd-nspawn, за исключением X-сервера, если только xvfb недостаточно, и здесь я сделал пару полных сценариев, включая базовое сетевое подключение к локальной сети.

Я сделал их по вашему каркасному сценарию, и они рассчитаны на максимальную скорость -установки.

Первый скрипт создает контейнеры на основе Ubuntu 20.04, предоставляя те же инструменты, что и в вашей dockerпопытке, так как кажется, что вы довольны теми, которые подходят для вашего варианта использования. На одном -ЦП Xeon Silver 4114 2,20 ГГц (10 ядер + HT )с 32 ГБ ОЗУ этот скрипт выполняет полный цикл от установки до уничтожения 100 контейнеров за ~35 секунд, занимая ОЗУ ~600 МБ.

Второй сценарий создает контейнеры, которые больше напоминают настоящую виртуальную машину, с более полным дистрибутивом Ubuntu 20.04, включающим собственный systemdи типичные сервисные демоны, такие как cron, rsyslogи т. д. Это выполняется менее чем за 3 минуты, с занятие около 3,3гб на 100 "машин".

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


Первый скрипт, похожий на докер -:

#!/bin/bash --
# vim: ts=4 noet

install() {
    [ -e /etc/radvd.conf ] || cat > /etc/radvd.conf <<EOF
interface bogus {
    IgnoreIfMissing on;
};
EOF
    apt -y install systemd-container debootstrap wget radvd
}

setup() {
    mkdir -p "$machines"

    # Fetch Ubuntu 20.04 basic system
    #debootstrap focal "$machines/$tmpl" # <-- either this, or the below wget + tar + mount
    wget -P "$machines" https://partner-images.canonical.com/core/focal/current/ubuntu-focal-core-cloudimg-amd64-root.tar.gz
    mkdir -p "$machines/$tmpl"
    tar -C "$machines/$tmpl" -xzf "$machines/ubuntu-focal-core-cloudimg-amd64-root.tar.gz"
    mount --bind /etc/resolv.conf "$machines/$tmpl/etc/resolv.conf"

    # Put our ssh pubkeys
    mkdir -p "$machines/$tmpl/root/.ssh"
    (shopt -s failglob; : ~/.ssh/*.pub) 2>/dev/null \
        && cat ~/.ssh/*.pub > "$machines/$tmpl/root/.ssh/authorized_keys"
    # Let nspawn use our parameterized hostname
    rm -f "$machines/$tmpl/etc/hostname"
    # Allow apt to function in chroot without complaints
    mount -o bind,slave,unbindable /dev "$machines/$tmpl/dev"
    mount -o bind,slave,unbindable /dev/pts "$machines/$tmpl/dev/pts"
    export DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8
    chroot "$machines/$tmpl" sh -c 'apt-get update && apt-get install -y --no-install-recommends apt-utils'
    # No init-scripts are to be run while in chroot
    cat >> "$machines/$tmpl/usr/sbin/policy-rc.d" <<'EOF'
#!/bin/sh --
exit 101
EOF
    chmod +x "$machines/$tmpl/usr/sbin/policy-rc.d"
    # Install additional packages for the use case
    chroot "$machines/$tmpl" apt-get install -y --no-install-recommends \
            bash-completion iproute2 vim iputils-ping \
            openssh-server
    # Uncomment these to allow root in, with password "let-me-in"
#   echo 'PermitRootLogin yes' > "$machines/$tmpl/etc/ssh/sshd_config.d/allow-root-with-password.conf" \
#       && chroot "$machines/$tmpl" chpasswd <<<'root:let-me-in'
    umount -l "$machines/$tmpl/dev/pts" "$machines/$tmpl/dev" "$machines/$tmpl/etc/resolv.conf"
}

start() {
    # Connect to physical LAN by building a temporary bridge over the specified physical interface
    # Of course this is not required if the interface facing the LAN is already a bridge interface, in which case you can just use that as "$mybr" and skip this pipeline
    # TODO: check on possible "$mybr" existence, and/or being already a bridge, and/or enslaving of "$intf" already in place
    # NOTE: be careful how the interface in "$intf" is named, as here it is used in sed's regex
    ip -o -b - <<EOF | awk '{print "route list " $4}' | ip -b - | sed "s/^/route replace /;s/ $intf / $mybr /g" | ip -b -
link add $mybr type bridge
link set $mybr up
link set $intf master $mybr
addr show $intf up
EOF

    # Advertise a temporary private IPv6 network in LAN
    ipv6pfx='fddf:' # this arbitrary pfx is not properly compliant, but very handy for quick use in simple LANs
    cat >> /etc/radvd.conf <<EOF
### $tmpl
interface $mybr {
    AdvSendAdvert on;
    prefix $ipv6pfx:/64 {
        AdvValidLifetime 7200;
        AdvPreferredLifetime 3600;
    };
};
###
EOF
    systemctl start radvd

    for i in $(seq "$vmnum"); do
        # Spawn containers that don't persist on disk
        systemd-run --unit="$tmpl-mini-$i" --service-type=notify \
            systemd-nspawn --notify-ready=no --register=no --keep-unit --kill-signal=RTMIN+3 \
                -M "${tmpl:0:8}$i" \
                -D "$machines/$tmpl" --read-only --link-journal no \
                --overlay +/etc::/etc --overlay +/var::/var \
                --network-bridge="$mybr" \
                --as-pid2 sh -c 'ip link set host0 up && ip addr add '"$ipv6pfx:$i/64"' dev host0 && mkdir -p /run/sshd && exec /usr/sbin/sshd -D' \
                & # Run in bg and wait later; this way we allow systemd's parallel spawning
                # Below is a --as-pid2 alternative for using dhcp, but beware bombing on LAN's dhcp server
                #--as-pid2 sh -c 'udhcpc -fbi host0; mkdir -p /run/sshd && exec /usr/sbin/sshd -D' \
    done
    wait
}

stop() {
    systemctl stop "$tmpl-mini-*"
    systemctl stop radvd
    ip link del "$mybr" 2>/dev/null
    netplan apply
    sed -i "/^### $tmpl/,/^###$/d" /etc/radvd.conf
}

destroy() {
    rm -rf "$machines/$tmpl"
    rm -f "$machines/ubuntu-focal-core-cloudimg-amd64-root.tar.gz"
}

: "${machines:=/var/lib/machines}" # default location for systemd-nspawn containers
: "${vmnum:=100}" # how many containers to spawn
: "${intf:?specify the physical interface facing the LAN to connect to}"
: "${tmpl:?specify directory basename under $machines to store the containers\' OS template into}"
: "${mybr:=$tmpl-br}" # the temporary bridge to LAN will be named this

install
setup
start
stop
destroy

Когда у вас появятся контейнеры, похожие на docker -, вы можете управлять ими через systemctl. Все они создаются как службы systemd с именем <template-name>-mini-<number>.

Вы можете ввести оболочку в любой из них либо через ssh, либо черезnsenter -at <pid-of-any-process-belonging-to-a-specific-container>


Второй скрипт, опыт "vm -лайк":

#!/bin/bash --
# vim: ts=4 noet

install() {
    [ -e /etc/radvd.conf ] || cat > /etc/radvd.conf <<EOF || return
interface bogus {
    IgnoreIfMissing on;
};
EOF
    apt -y install systemd-container debootstrap radvd || return
}

setup() {
    mkdir -p "$machines/$tmpl" || return
    # Fetch Ubuntu 20.04 base system
    debootstrap focal "$machines/$tmpl" || return

    # Allow apt to function in chroot without complaints
    trap "umount -l $machines/$tmpl/dev/pts" RETURN
    mount -o bind,slave,unbindable /dev/pts "$machines/$tmpl/dev/pts" || return
    # Put our ssh pubkeys
    mkdir -p "$machines/$tmpl/root/.ssh" || return
    (shopt -s failglob; : ~/.ssh/*.pub) 2>/dev/null \
        && { cat ~/.ssh/*.pub > "$machines/$tmpl/root/.ssh/authorized_keys" || return; }
    # Let nspawn use our parameterized hostname
    rm -f "$machines/$tmpl/etc/hostname" || return
    # Enable container's systemd-networkd, it blends automatically with host's systemd-networkd
    chroot "$machines/$tmpl" systemctl enable systemd-networkd || return
    # Make provision for static addresses passed along at start time (see start phase below)
    cat > "$machines/$tmpl/etc/networkd-dispatcher/carrier.d/$tmpl-static-addrs.sh" <<'EOF' || return
#!/bin/bash --
[ -n "$static_ipaddrs" ] && printf 'addr add %s dev host0\n' ${static_ipaddrs//,/ } | ip -b -
EOF
    chmod +x "$machines/$tmpl/etc/networkd-dispatcher/carrier.d/$tmpl-static-addrs.sh" || return
    # Uncomment this to mind about updates and security
#   printf 'deb http://%s.ubuntu.com/ubuntu/ focal-%s main\n' \
#      archive updates security security \
#      >> "$machines/$tmpl/etc/apt/sources.list" || return
    # Uncomment this to consider [uni|multi]verse packages
#   sed -i 's/$/ universe multiverse' "$machines/$tmpl/etc/apt/sources.list" || return

    export DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8
    chroot "$machines/$tmpl" apt-get update || return
    # To upgrade or not to upgrade? that is the question..
    #chroot "$machines/$tmpl" apt-get -y upgrade || return
    # Install additional packages for the use case
    chroot "$machines/$tmpl" apt-get install -y --no-install-recommends \
            bash-completion \
            openssh-server \
        || return
    # Uncomment these to allow root in, with password "let-me-in"
#   echo 'PermitRootLogin yes' > "$machines/$tmpl/etc/ssh/sshd_config.d/allow-root-with-password.conf" || return
#   chroot "$machines/$tmpl" chpasswd <<<'root:let-me-in' || return
}

start() {
    # For full-system modes we need inotify limits greater than default even for just a bunch of containers
    (( (prev_max_inst = $(sysctl -n fs.inotify.max_user_instances)) < 10*vmnum )) \
        && { sysctl fs.inotify.max_user_instances=$((10*vmnum)) || return 1; }
    (( (prev_max_wd = $(sysctl -n fs.inotify.max_user_watches)) < 40*vmnum )) \
        && { sysctl fs.inotify.max_user_watches=$((40*vmnum)) || return 1; }
    [ -s "$machines/prev_inotifys" ] || declare -p ${!prev_max_*} > "$machines/prev_inotifys"

    # Connect to physical LAN by building a temporary bridge over the specified physical interface
    # Of course this is not required if the interface facing the LAN is already a bridge interface, in which case you can just use that as "$mybr" and skip this pipeline
    # TODO: check on possible "$mybr" existence, and/or being already a bridge, and/or enslaving of "$intf" already in place
    # NOTE: be careful how the interface in "$intf" is named, as here it is used in sed's regex
    ip -o -b - <<EOF | awk '{print "route list " $4}' | ip -b - | sed "s/^/route replace /;s/ $intf / $mybr /g" | ip -b -
link add $mybr type bridge
link set $mybr up
link set $intf master $mybr
addr show $intf up
EOF

    # Advertise a temporary private IPv6 network in LAN
    ipv6pfx='fddf:' # this arbitrary pfx is not properly compliant, but very handy for quick use in simple LANs
    cat >> /etc/radvd.conf <<EOF || return
### $tmpl
interface $mybr {
    AdvSendAdvert on;
    prefix $ipv6pfx:/64 {
        AdvValidLifetime 7200;
        AdvPreferredLifetime 3600;
    };
};
###
EOF
    systemctl start radvd

    for i in $(seq "$vmnum"); do
        # Spawn containers that don't persist on disk
        systemd-run --unit="$tmpl-full-$i" --service-type=notify \
            systemd-nspawn --notify-ready=yes -b \
                -M "${tmpl:0:8}$i" \
                -D "$machines/$tmpl" --read-only --link-journal no \
                --overlay +/etc::/etc --overlay +/var::/var \
                --network-bridge="$mybr" \
                --capability=all --drop-capability=CAP_SYS_MODULE \
                "systemd.setenv=static_ipaddrs=$ipv6pfx:$i/64" \
                & # Run in bg and wait later; this way we allow systemd's parallel spawning
                # All capabilities allowed and no users isolation provide an experience which is
                # closer to a true vm (though with less security)
                # The comma separated list of static addresses will be set by our script in networkd-dispatcher
    done
    wait
}

stop() {
    systemctl stop "machine-$tmpl*" "$tmpl-full-*"
    systemctl stop radvd
    ip link del "$mybr" 2>/dev/null
    netplan apply
    sed -i "/^### $tmpl/,/^###$/d" /etc/radvd.conf
    # restore previous inotify limits
    source "$machines/prev_inotifys" || return
    rm -f "$machines/prev_inotifys"
    (( prev_max_wd > 0 )) && sysctl fs.inotify.max_user_watches="$prev_max_wd"
    (( prev_max_inst > 0 )) && sysctl fs.inotify.max_user_instances="$prev_max_inst"
}

destroy() {
    rm -rf "$machines/$tmpl"
}

: "${machines:=/var/lib/machines}" # default location for systemd-nspawn machines
: "${vmnum:=100}" # how many containers to spawn
: "${intf:?specify the physical interface facing the LAN to connect to}"
: "${tmpl:?specify directory basename under $machines to store the containers\' OS template into}"
: "${mybr:=$tmpl-br}" # the temporary bridge will be named this

install || exit
setup || { destroy; exit 1; }
start || { stop; exit 1; }
stop
destroy

После создания контейнеров типа «vm -like» на хосте вы также можете использовать machinectlи systemctlдля их обработки. Примеры:

  • machinectl shell <container-name>предоставляет удобный способ поместить оболочку в конкретный контейнер
  • machinectlотдельно или также systemctl list-machines, предоставить список запущенных контейнеров
  • machinectl poweroff <container-name>,или также systemctl stop machine-<container-name>останавливает контейнер (вы также можете сделать poweroffиз оболочки внутри контейнера)

Для обоих сценариев я выбрал подключение по протоколу IPv6, так как он имеет встроенные функции для автоматической настройки хостов. Если все ваши хосты в локальной сети являются дружественными гражданами IPv6, они самостоятельно -настроят временный адрес сети fddf ::/64, инициированный в -с помощью моих сценариев и объявленный всей локальной сети (и, конечно же, общий для всех контейнеров ).

Такой префикс IPv6 «fddf ::/64» является полностью произвольным и попадает в официальный префикс, выделенный IANA для частных сетей. Я выбрал его очень удобно, так что с любого хоста в вашей локальной сети вы можете просто сделать ssh root@fddf::<vm-number>.

Однако это не совсем соответствует тому, как должны генерироваться эти префиксы, и если вы хотите сгенерировать соответствующий частный префикс, прочтите RFC 4193 , в частности , раздел 3.2.2 .

В любом случае указанное «число vm -» — это число от 1 до любого числа приглашенных вами гостей, и я оставил их десятичными в шестнадцатеричном формате IPv6, чтобы у вас было место для 9999 адресов.

Конечно, вы также можете использовать IPv4-адреса, и здесь у вас есть два варианта:

  • статические адреса :просто добавьте их в командную строку, которая порождает контейнеры (см. там комментарии ); однако вам придется реализовать способ предварительного -вычисления таких адресов в соответствии с вашими потребностями
  • dhcp :Сценарий «docker -like» имеет строку с комментариями для включения dhcp, «vm -like» уже делает это самостоятельно в соответствии с поведением systemd по умолчанию в Ubuntu 20.04
1
18.03.2021, 23:30

Теги

Похожие вопросы