PVE/LXC

Материал из ALT Linux Wiki
< PVE
Stub.png
Данная страница находится в разработке.
Эта страница ещё не закончена. Информация, представленная здесь, может оказаться неполной или неверной.

В данной статье описано развёртывание LXC-контейнера c ALT (из готового шаблона) на оригинальном Proxmox VE (который на данный момент на Debian).

Если у вас установлен любой из дистрибутивов ALT и собственно сам PVE (pve-manager) или стартовый набор server-pve, данная статья вам не нужна, так как проблем с развёртыванием контейнера не будет.

Создание шаблона

Для этого можно воспользоваться набором инструментов - m-p. Вся информация тут.

Основным требованием для шаблона является наличие в нём systemd. Исходя из статьи Шаблоны для развёртывания CT в PVE, нам подойдет только шаблон ve/systemd-bare.tar.gz. Для его сборки после первоначальной настройки окружения необходимо выполнить следующие команды (предварительно настроив нужный репозиторий с помощью утилиты apt-repo):

$ git clone git://git.altlinux.org/people/mike/packages/mkimage-profiles.git
$ cd mkimage-profiles
$ make ve/systemd-bare.tar.gz

После этого готовый шаблон нужно загрузить в локальное хранилище PVE.

Подготовка Proxmox

Для установки рутового пароля при развёртывании шаблона потребуется установить perl-библиотеку Crypt::Eksblowfish::Bcrypt:

apt-get install libcrypt-eksblowfish-perl

Затем необходимо внести изменения в скрипты работы с LXC-контейнерами и добавить новый скрипт для разворачивания шаблона с ALT Linux. За основу взят патч для пакета pve-container.

Proxmox VE 5.1

Проверено на версиях 5.1-35 и 5.1-36.

Следует внести изменения в следующие файлы (изменения под спойлером):

  • /usr/share/perl5/PVE/LXC/Config.pm
diff --git a/Config.pm b/Config.pm
index 8d71f4a..a73a6be 100644
--- a/Config.pm
+++ b/Config.pm
@@ -302,7 +302,7 @@ my $confdesc = {
     ostype => {
 	optional => 1,
 	type => 'string',
-	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo unmanaged)],
+	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo altlinux unmanaged)],
 	description => "OS type. This is used to setup configuration inside the container, and corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf. Value 'unmanaged' can be used to skip and OS specific setup.",
     },
     console => {
  • /usr/share/perl5/PVE/LXC/Setup.pm
diff --git a/Setup.pm b/Setup.pm
index 9b91539..672ed02 100644
--- a/Setup.pm
+++ b/Setup.pm
@@ -13,6 +13,7 @@ use PVE::LXC::Setup::SUSE;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::Alpine;
 use PVE::LXC::Setup::Gentoo;
+use PVE::LXC::Setup::ALTLinux;
 
 my $plugins = {
     debian    => 'PVE::LXC::Setup::Debian',
@@ -23,6 +24,7 @@ my $plugins = {
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     alpine    => 'PVE::LXC::Setup::Alpine',
     gentoo    => 'PVE::LXC::Setup::Gentoo',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
 };
 
 # a map to allow supporting related distro flavours
@@ -53,6 +55,8 @@ my $autodetect_type = sub {
 	return "debian";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
 	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+        return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
 	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -229,7 +233,12 @@ sub rewrite_ssh_host_keys {
     my $plugin = $self->{plugin};
     my $rootdir = $self->{rootdir};
 
-    return if ! -d "$rootdir/etc/ssh";
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$rootdir$sshdir" ) {
+	if ( ! -d "$rootdir/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
 
     my $keynames = {
 	rsa => 'ssh_host_rsa_key',
@@ -246,8 +255,7 @@ sub rewrite_ssh_host_keys {
 	my $line = shift;
 
 	print "done: $line\n"
-	    if $line =~ m/^(?:[0-9a-f]{2}:)+[0-9a-f]{2}\s+\Q$ssh_comment\E$/i ||
-	       $line =~ m/^SHA256:[0-9a-z+\/]{43}\s+\Q$ssh_comment\E$/i;
+	    if ($line =~ m/^([0-9a-f]{2}:)+[0-9a-f]{2}\s+\Q$ssh_comment\E$/i);
     };
 
     # Create temporary keys in /tmp on the host
@@ -257,10 +265,10 @@ sub rewrite_ssh_host_keys {
 	my $file = "/tmp/$$.$basename";
 	print "Creating SSH host key '$basename' - this may take some time ...\n";
 	my $cmd = ['ssh-keygen', '-f', $file, '-t', $keytype,
-		   '-N', '', '-E', 'sha256', '-C', $ssh_comment];
+		   '-N', '', '-C', $ssh_comment];
 	PVE::Tools::run_command($cmd, outfunc => $keygen_outfunc);
-	$keyfiles->{"/etc/ssh/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
-	$keyfiles->{"/etc/ssh/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
+	$keyfiles->{"$sshdir/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
+	$keyfiles->{"$sshdir/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
 	unlink $file;
 	unlink "$file.pub";
     }

И добавить новый файл с описанием инструкций для ALT:

  • /usr/share/perl5/PVE/LXC/Setup/ALTLinux.pm
package PVE::LXC::Setup::ALTLinux;

use strict;
use warnings;
use Digest::SHA;
use Crypt::Eksblowfish::Bcrypt;
use PVE::LXC::Setup::Base;
use base qw(PVE::LXC::Setup::Base);

sub new {
	my ($class, $conf, $rootdir) = @_;
	my $ostype = "altlinux";
	my $version = PVE::Tools::file_read_firstline("$rootdir/etc/$ostype-release");
	my $self = { conf => $conf, rootdir => $rootdir, version => $version };
	$conf->{ostype} = $ostype;
	return bless $self, $class;
}

sub setup_init {
    my ($self, $conf) = @_;
    $self->setup_systemd_console($conf);
}

sub setup_network {
    my ($self, $conf) = @_;
    $self->setup_systemd_networkd($conf);
}

sub template_fixup {
    my ($self, $conf) = @_;
    $self->setup_securetty($conf, qw(pts/0 lxc/console));
}

sub set_user_password {
    my ($self, $conf, $user, $opt_password) = @_;

    my $shadowfile = "/etc/tcb/$user/shadow";
    return if !$self->ct_file_exists($shadowfile);

    if (defined($opt_password)) {
	if ($opt_password !~ m/^\$/) {
	    my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(substr(Digest::SHA::sha1_base64(time), 0, 16));
	    $opt_password = Crypt::Eksblowfish::Bcrypt::bcrypt($opt_password, '$2a$08$'.$salt);
	};
    } else {
	$opt_password = '*';
    }

    my $data = $user . ":" . $opt_password . ":" . (int(time()/86400)) . "::::::\n";

    my $st = $self->ct_stat($shadowfile) || die "unable to stat file - $!";
    $self->ct_file_set_contents($shadowfile, $data);
    chmod $st->mode, $shadowfile;
    chown $st->uid, $st->gid, $shadowfile;
}

1;
  • Модификация, пригодная для работы и с systemd, и с systemv — полезно при модернизации старых контейнеров и не требует обязательного наличия systemd в шаблоне

(NB: в патч входит только вышеприведённый вариант!)

package PVE::LXC::Setup::ALTLinux;

use strict;
use warnings;
use Digest::SHA;
use Crypt::Eksblowfish::Bcrypt;
use PVE::LXC::Setup::Base;
use base qw(PVE::LXC::Setup::Base);

sub new {
    my $ostype = "altlinux";
    my ($class, $conf, $rootdir) = @_;
    my $version = PVE::Tools::file_read_firstline("$rootdir/etc/$ostype-release");
    my $self = { conf => $conf, rootdir => $rootdir, version => $version };
    $conf->{ostype} = $ostype;
    return bless $self, $class;
}

sub setup_init {
    my ($self, $conf) = @_;
    my $systemd = $self->ct_readlink('/sbin/init');
    if (defined($systemd) && $systemd =~ m@/systemd$@){
        $self->setup_systemd_console($conf);
    } else {
        my $filename = "/etc/inittab";
        return if !$self->ct_file_exists($filename);
        my $ttycount = PVE::LXC::Config->get_tty_count($conf);
        my $inittab = $self->ct_file_get_contents($filename);
        my @lines = grep {
            # remove getty lines
            !/^\s*\d+:\d+:[^:]*:.*getty/ &&
            # remove power lines
            !/^\s*p[fno0]:/
        } split(/\n/, $inittab);
        $inittab = join("\n", @lines) . "\n";
        $inittab .= "p0::powerfail:/sbin/shutdown -f -h +2 \"Power failure, system shutting down...\"\n";
        for (my $id = 1; $id <= $ttycount; $id++){
            next if $id == 7; # reserved for X11
            my $levels = ($id == 1) ? '234' : '2345';
            $inittab .= "$id:$levels:respawn:/sbin/mingetty tty$id\n";
        }
        $self->ct_file_set_contents($filename, $inittab);
    }
}

sub setup_network {
    my ($self, $conf) = @_;
    my $systemd = $self->ct_readlink('/sbin/init');
    if (defined($systemd) && $systemd =~ m@/systemd$@){
        $self->setup_systemd_networkd($conf);
    } else {
        foreach my $k (keys %$conf) {
            next if $k !~ m/^net(\d+)$/;
            my $d = PVE::LXC::Config->parse_lxc_network($conf->{$k});
            next if !$d->{name};
            my $ifpath = "/etc/net/ifaces/$d->{name}";
            $self->ct_make_path($ifpath);
            my $optfile = "$ifpath/options";
            my $addrfile = "$ifpath/ipv4address";
            my $routefile = "$ifpath/ipv4route";
            my $options = "TYPE=eth\n";
            my $address = '';
            my $routes = '';
            if ($d->{ip} && $d->{ip} ne 'manual'){
                if ($d->{ip} eq 'dhcp'){
                    $options .= "BOOTPROTO=dhcp\n";
                } else {
                    $options .= "BOOTPROTO=static\n";
                    $address = "$d->{ip}\n";
                    if (defined($d->{gw})){
                        $routes .= "default via $d->{gw}\n";
                        $self->ct_modify_file($routefile, $routes, delete => 1, prepend => 1);
                    }
                    $self->ct_file_set_contents($addrfile, $address);
                }
                $self->ct_file_set_contents($optfile, $options);
            }
        }
    }
}

sub template_fixup {
    my ($self, $conf) = @_;
    $self->setup_securetty($conf, qw(pts/0 lxc/console));
}

sub set_user_password {
    my ($self, $conf, $user, $opt_password) = @_;
    my $shadowfile = "/etc/tcb/$user/shadow";
    return if !$self->ct_file_exists($shadowfile);
    if (defined($opt_password)){
        if ($opt_password !~ m/^\$/){
            my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(substr(Digest::SHA::sha1_base64(time), 0, 16));
            $opt_password = Crypt::Eksblowfish::Bcrypt::bcrypt($opt_password, '$2a$08$'.$salt);
        };
    } else {
        $opt_password = '*';
    }
    my $data = $user . ":" . $opt_password . ":" . (int(time()/86400)) . "::::::\n";
    my $st = $self->ct_stat($shadowfile) || die "unable to stat file - $!";
    $self->ct_file_set_contents($shadowfile, $data);
    chmod $st->mode, $shadowfile;
    chown $st->uid, $st->gid, $shadowfile;
}

1;

Указанные файлы можно поправить как вручную, так и посредством патча, создав файл со следующим содержимым (TODO: добавить ссылку на ftp):

pve5-alt-lxc.patch

diff --git a/Config.pm b/Config.pm
index 8d71f4a..a73a6be 100644
--- a/Config.pm
+++ b/Config.pm
@@ -302,7 +302,7 @@ my $confdesc = {
     ostype => {
 	optional => 1,
 	type => 'string',
-	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo unmanaged)],
+	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo altlinux unmanaged)],
 	description => "OS type. This is used to setup configuration inside the container, and corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf. Value 'unmanaged' can be used to skip and OS specific setup.",
     },
     console => {
diff --git a/Setup.pm b/Setup.pm
index 9b91539..672ed02 100644
--- a/Setup.pm
+++ b/Setup.pm
@@ -13,6 +13,7 @@ use PVE::LXC::Setup::SUSE;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::Alpine;
 use PVE::LXC::Setup::Gentoo;
+use PVE::LXC::Setup::ALTLinux;
 
 my $plugins = {
     debian    => 'PVE::LXC::Setup::Debian',
@@ -23,6 +24,7 @@ my $plugins = {
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     alpine    => 'PVE::LXC::Setup::Alpine',
     gentoo    => 'PVE::LXC::Setup::Gentoo',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
 };
 
 # a map to allow supporting related distro flavours
@@ -53,6 +55,8 @@ my $autodetect_type = sub {
 	return "debian";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
 	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+        return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
 	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -229,7 +233,12 @@ sub rewrite_ssh_host_keys {
     my $plugin = $self->{plugin};
     my $rootdir = $self->{rootdir};
 
-    return if ! -d "$rootdir/etc/ssh";
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$rootdir$sshdir" ) {
+	if ( ! -d "$rootdir/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
 
     my $keynames = {
 	rsa => 'ssh_host_rsa_key',
@@ -246,8 +255,7 @@ sub rewrite_ssh_host_keys {
 	my $line = shift;
 
 	print "done: $line\n"
-	    if $line =~ m/^(?:[0-9a-f]{2}:)+[0-9a-f]{2}\s+\Q$ssh_comment\E$/i ||
-	       $line =~ m/^SHA256:[0-9a-z+\/]{43}\s+\Q$ssh_comment\E$/i;
+	    if ($line =~ m/^([0-9a-f]{2}:)+[0-9a-f]{2}\s+\Q$ssh_comment\E$/i);
     };
 
     # Create temporary keys in /tmp on the host
@@ -257,10 +265,10 @@ sub rewrite_ssh_host_keys {
 	my $file = "/tmp/$$.$basename";
 	print "Creating SSH host key '$basename' - this may take some time ...\n";
 	my $cmd = ['ssh-keygen', '-f', $file, '-t', $keytype,
-		   '-N', '', '-E', 'sha256', '-C', $ssh_comment];
+		   '-N', '', '-C', $ssh_comment];
 	PVE::Tools::run_command($cmd, outfunc => $keygen_outfunc);
-	$keyfiles->{"/etc/ssh/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
-	$keyfiles->{"/etc/ssh/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
+	$keyfiles->{"$sshdir/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
+	$keyfiles->{"$sshdir/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
 	unlink $file;
 	unlink "$file.pub";
     }
diff --git a/Setup/ALTLinux.pm b/Setup/ALTLinux.pm
new file mode 100644
index 0000000..177b617
--- /dev/null
+++ b/Setup/ALTLinux.pm
@@ -0,0 +1,57 @@
+package PVE::LXC::Setup::ALTLinux;
+
+use strict;
+use warnings;
+use Digest::SHA;
+use Crypt::Eksblowfish::Bcrypt;
+use PVE::LXC::Setup::Base;
+use base qw(PVE::LXC::Setup::Base);
+
+sub new {
+	my ($class, $conf, $rootdir) = @_;
+	my $ostype = "altlinux";
+	my $version = PVE::Tools::file_read_firstline("$rootdir/etc/$ostype-release");
+	my $self = { conf => $conf, rootdir => $rootdir, version => $version };
+	$conf->{ostype} = $ostype;
+	return bless $self, $class;
+}
+
+sub setup_init {
+    my ($self, $conf) = @_;
+    $self->setup_systemd_console($conf);
+}
+
+sub setup_network {
+    my ($self, $conf) = @_;
+    $self->setup_systemd_networkd($conf);
+}
+
+sub template_fixup {
+    my ($self, $conf) = @_;
+    $self->setup_securetty($conf, qw(pts/0 lxc/console));
+}
+
+sub set_user_password {
+    my ($self, $conf, $user, $opt_password) = @_;
+
+    my $shadowfile = "/etc/tcb/$user/shadow";
+    return if !$self->ct_file_exists($shadowfile);
+
+    if (defined($opt_password)) {
+	if ($opt_password !~ m/^\$/) {
+	    my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(substr(Digest::SHA::sha1_base64(time), 0, 16));
+	    $opt_password = Crypt::Eksblowfish::Bcrypt::bcrypt($opt_password, '$2a$08$'.$salt);
+	};
+    } else {
+	$opt_password = '*';
+    }
+
+    my $data = $user . ":" . $opt_password . ":" . (int(time()/86400)) . "::::::\n";
+
+    my $st = $self->ct_stat($shadowfile) || die "unable to stat file - $!";
+    $self->ct_file_set_contents($shadowfile, $data);
+    chmod $st->mode, $shadowfile;
+    chown $st->uid, $st->gid, $shadowfile;
+}
+
+1;

Затем выполнить следующие команды:

cd /usr/share/perl5/PVE/LXC
patch -p1 -i <path_to>/pve5-alt-lxc.patch

После изменения скриптов (вручную или патчем) необходимо перезапустить PVE API Daemon:

service pvedaemon restart

Теперь можно спокойно разворачивать контейнер из шаблона с ALT Linux.

Proxmox VE 8.х

Патч, применимый к версиям PVE с 8.1 по 8.3 (этот ощутимо меньше отличается от оригинала):

pve8.1-alt-lxc.patch

--- /usr/share/perl5/PVE/LXC/Config.pm	2024-03-15 17:24:22.000000000 +0800
+++ /usr/share/perl5/PVE/LXC/Config.pm	2024-12-28 11:35:19.255815727 +0800
@@ -480,7 +480,7 @@
     ostype => {
	optional => 1,
	type => 'string',
-	enum => [qw(debian devuan ubuntu centos fedora opensuse archlinux alpine gentoo nixos unmanaged)],
+	enum => [qw(debian devuan ubuntu centos fedora opensuse archlinux alpine altlinux gentoo nixos unmanaged)],
	description => "OS type. This is used to setup configuration inside the container, and corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf. Value 'unmanaged' can be used to skip and OS specific setup.",
     },
     console => {
--- /usr/share/perl5/PVE/LXC/Setup.pm	2024-03-15 17:24:22.000000000 +0800
+++ /usr/share/perl5/PVE/LXC/Setup.pm	2024-04-04 10:41:30.975163060 +0800
@@ -9,6 +9,7 @@
 use PVE::Tools;

 use PVE::LXC::Setup::Alpine;
+use PVE::LXC::Setup::ALTLinux;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::CentOS;
 use PVE::LXC::Setup::Debian;
@@ -22,6 +23,7 @@

 my $plugins = {
     alpine    => 'PVE::LXC::Setup::Alpine',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     centos    => 'PVE::LXC::Setup::CentOS',
     debian    => 'PVE::LXC::Setup::Debian',
@@ -67,6 +69,8 @@
	return "devuan";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+	return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -257,7 +261,13 @@

     my $keynames = $plugin->ssh_host_key_types_to_generate();

-    return if ! -d "$self->{rootdir}/etc/ssh" || !$keynames || !scalar(keys $keynames->%*);
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$self->{rootdir}$sshdir" ) {
+	if ( ! -d "$self->{rootdir}/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
+    return if ! -d "$self->{rootdir}/$sshdir" || !$keynames || !scalar(keys $keynames->%*);

     my $hostname = $self->{conf}->{hostname} || 'localhost';
     $hostname =~ s/\..*$//;
@@ -269,7 +279,7 @@
	my ($id, $private, $public) = generate_ssh_key($keytype, "root\@$hostname");
	print "done: $id\n";

-	push $keyfiles->@*, ["/etc/ssh/$basename", $private, 0600], ["/etc/ssh/$basename.pub", $public, 0644];
+	push $keyfiles->@*, ["$sshdir/$basename", $private, 0600], ["$sshdir/$basename.pub", $public, 0644];
     }

     $self->protected_call(sub { # write them now all to the CTs rootfs at once

Для PVE-8.0 не подходит: хотя правки те же, но номера строк иные — как для версий 7.х, которые здесь не рассматриваются.


В PVE-8.4+ номера строк снова поменялись, вот патч:

pve8.4-alt-lxc.patch

--- /usr/share/perl5/PVE/LXC/Config.pl  2025-04-08 05:27:00.000000000 +0800
+++ /usr/share/perl5/PVE/LXC/Config.pm  2025-06-06 09:36:44.645549046 +0800
@@ -486,7 +486,7 @@
     ostype => {
	optional => 1,
	type => 'string',
-	enum => [qw(debian devuan ubuntu centos fedora opensuse archlinux alpine gentoo nixos unmanaged)],
+	enum => [qw(debian devuan ubuntu centos fedora opensuse archlinux alpine altlinux gentoo nixos unmanaged)],
	description => "OS type. This is used to setup configuration inside the container, and corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf. Value 'unmanaged' can be used to skip and OS specific setup.",
     },
     console => {
--- /usr/share/perl5/PVE/LXC/Setup.pl   2025-04-08 05:27:00.000000000 +0800
+++ /usr/share/perl5/PVE/LXC/Setup.pm   2025-06-06 09:43:34.463539899 +0800
@@ -9,6 +9,7 @@
 use PVE::Tools;

 use PVE::LXC::Setup::Alpine;
+use PVE::LXC::Setup::ALTLinux;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::CentOS;
 use PVE::LXC::Setup::Debian;
@@ -23,6 +24,7 @@

 my $plugins = {
     alpine    => 'PVE::LXC::Setup::Alpine',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     centos    => 'PVE::LXC::Setup::CentOS',
     debian    => 'PVE::LXC::Setup::Debian',
@@ -71,6 +73,8 @@
	return "devuan";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+	return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -263,7 +267,13 @@

     my $keynames = $plugin->ssh_host_key_types_to_generate();

-    return if ! -d "$self->{rootdir}/etc/ssh" || !$keynames || !scalar(keys $keynames->%*);
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$self->{rootdir}$sshdir" ) {
+	if ( ! -d "$self->{rootdir}/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
+    return if ! -d "$self->{rootdir}/$sshdir" || !$keynames || !scalar(keys $keynames->%*);

     my $hostname = $self->{conf}->{hostname} || 'localhost';
     $hostname =~ s/\..*$//;
@@ -275,7 +285,7 @@
	my ($id, $private, $public) = generate_ssh_key($keytype, "root\@$hostname");
	print "done: $id\n";

-	push $keyfiles->@*, ["/etc/ssh/$basename", $private, 0600], ["/etc/ssh/$basename.pub", $public, 0644];
+	push $keyfiles->@*, ["$sshdir/$basename", $private, 0600], ["$sshdir/$basename.pub", $public, 0644];
     }

     $self->protected_call(sub { # write them now all to the CTs rootfs at once


Порядок действий тот же.

  1. Применить патч в зависимости от версии PVE:
    • patch -p1 -i <path_to>/pve8.1-alt-lxc.patch
    или:
    • patch -p1 -i <path_to>/pve8.4-alt-lxc.patch
  2. Поместить в /usr/share/perl5/PVE/LXC/Setup/ALTLinux.pm подходящий вариант скрипта из примера PVE-5.1 выше по тексту.
  3. И: service pvedaemon restart

После чего можно добавлять альт-контейнеры.

Proxmox VE 4.4

Проверено на версиях 4.4-18 и 4.4-20.

Потребуется внести изменения в следующие файлы:

  • /usr/share/perl5/PVE/LXC/Config.pm - аналогично 5 версии (см. выше);
  • /usr/share/perl5/PVE/LXC/Setup.pm - есть немного отличий;
diff --git a/LXC/Setup.pm b/LXC/Setup.pm
index 1baeaa2..04fc082 100644
--- a/LXC/Setup.pm
+++ b/LXC/Setup.pm
@@ -13,6 +13,7 @@ use PVE::LXC::Setup::SUSE;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::Alpine;
 use PVE::LXC::Setup::Gentoo;
+use PVE::LXC::Setup::ALTLinux;
 
 my $plugins = {
     debian    => 'PVE::LXC::Setup::Debian',
@@ -23,6 +24,7 @@ my $plugins = {
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     alpine    => 'PVE::LXC::Setup::Alpine',
     gentoo    => 'PVE::LXC::Setup::Gentoo',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
 };
 
 my $autodetect_type = sub {
@@ -40,6 +42,8 @@ my $autodetect_type = sub {
 	return "debian";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
 	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+        return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
 	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -206,7 +210,12 @@ sub rewrite_ssh_host_keys {
     my $plugin = $self->{plugin};
     my $rootdir = $self->{rootdir};
 
-    return if ! -d "$rootdir/etc/ssh";
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$rootdir$sshdir" ) {
+	if ( ! -d "$rootdir/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
 
     my $keynames = {
 	rsa1 => 'ssh_host_key',
@@ -236,8 +245,8 @@ sub rewrite_ssh_host_keys {
 	my $cmd = ['ssh-keygen', '-f', $file, '-t', $keytype,
 		   '-N', '', '-C', $ssh_comment];
 	PVE::Tools::run_command($cmd, outfunc => $keygen_outfunc);
-	$keyfiles->{"/etc/ssh/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
-	$keyfiles->{"/etc/ssh/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
+	$keyfiles->{"$sshdir/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
+	$keyfiles->{"$sshdir/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
 	unlink $file;
 	unlink "$file.pub";
     }
  • /usr/share/perl5/PVE/LXC/Setup/ALTLinux.pm - аналогично 5 версии (см. выше).

Для 4 версии Proxmox VE следует также изменить LXC.pm:

  • /usr/share/perl5/PVE/LXC.pm
diff --git a/LXC.pm b/LXC.pm
index 9413308..947786b 100644
--- a/LXC.pm
+++ b/LXC.pm
@@ -366,7 +366,7 @@ sub update_lxc_config {
     my $custom_idmap = grep { $_->[0] eq 'lxc.id_map' } @{$conf->{lxc}};
 
     my $ostype = $conf->{ostype} || die "missing 'ostype' - internal error";
-    if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | opensuse | archlinux | alpine | gentoo | unmanaged)$/x) {
+    if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | opensuse | archlinux | alpine | gentoo | altlinux | unmanaged)$/x) {
 	my $inc ="/usr/share/lxc/config/$ostype.common.conf";
 	$inc ="/usr/share/lxc/config/common.conf" if !-f $inc;
 	$raw .= "lxc.include = $inc\n";

Как и с 5 версией, файлы можно поправить и вручную, и таким патчем:

pve4-alt-lxc.patch

diff --git a/LXC.pm b/LXC.pm
index 9413308..947786b 100644
--- a/LXC.pm
+++ b/LXC.pm
@@ -366,7 +366,7 @@ sub update_lxc_config {
     my $custom_idmap = grep { $_->[0] eq 'lxc.id_map' } @{$conf->{lxc}};
 
     my $ostype = $conf->{ostype} || die "missing 'ostype' - internal error";
-    if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | opensuse | archlinux | alpine | gentoo | unmanaged)$/x) {
+    if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | opensuse | archlinux | alpine | gentoo | altlinux | unmanaged)$/x) {
 	my $inc ="/usr/share/lxc/config/$ostype.common.conf";
 	$inc ="/usr/share/lxc/config/common.conf" if !-f $inc;
 	$raw .= "lxc.include = $inc\n";
diff --git a/LXC/Config.pm b/LXC/Config.pm
index 05cd970..397f72a 100644
--- a/LXC/Config.pm
+++ b/LXC/Config.pm
@@ -296,7 +296,7 @@ my $confdesc = {
     ostype => {
 	optional => 1,
 	type => 'string',
-	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo unmanaged)],
+	enum => [qw(debian ubuntu centos fedora opensuse archlinux alpine gentoo altlinux unmanaged)],
 	description => "OS type. This is used to setup configuration inside the container, and corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf. Value 'unmanaged' can be used to skip and OS specific setup.",
     },
     console => {
diff --git a/LXC/Setup.pm b/LXC/Setup.pm
index 1baeaa2..04fc082 100644
--- a/LXC/Setup.pm
+++ b/LXC/Setup.pm
@@ -13,6 +13,7 @@ use PVE::LXC::Setup::SUSE;
 use PVE::LXC::Setup::ArchLinux;
 use PVE::LXC::Setup::Alpine;
 use PVE::LXC::Setup::Gentoo;
+use PVE::LXC::Setup::ALTLinux;
 
 my $plugins = {
     debian    => 'PVE::LXC::Setup::Debian',
@@ -23,6 +24,7 @@ my $plugins = {
     archlinux => 'PVE::LXC::Setup::ArchLinux',
     alpine    => 'PVE::LXC::Setup::Alpine',
     gentoo    => 'PVE::LXC::Setup::Gentoo',
+    altlinux  => 'PVE::LXC::Setup::ALTLinux',
 };
 
 my $autodetect_type = sub {
@@ -40,6 +42,8 @@ my $autodetect_type = sub {
 	return "debian";
     } elsif (-f  "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
 	return "opensuse";
+    } elsif (-f  "$rootdir/etc/altlinux-release") {
+        return "altlinux";
     } elsif (-f  "$rootdir/etc/fedora-release") {
 	return "fedora";
     } elsif (-f  "$rootdir/etc/centos-release" || -f "$rootdir/etc/redhat-release") {
@@ -206,7 +210,12 @@ sub rewrite_ssh_host_keys {
     my $plugin = $self->{plugin};
     my $rootdir = $self->{rootdir};
 
-    return if ! -d "$rootdir/etc/ssh";
+    my $sshdir = "/etc/ssh";
+    if ( ! -d "$rootdir$sshdir" ) {
+	if ( ! -d "$rootdir/etc/openssh" ) {
+	    return;
+	} $sshdir = "/etc/openssh";
+    }
 
     my $keynames = {
 	rsa1 => 'ssh_host_key',
@@ -236,8 +245,8 @@ sub rewrite_ssh_host_keys {
 	my $cmd = ['ssh-keygen', '-f', $file, '-t', $keytype,
 		   '-N', '', '-C', $ssh_comment];
 	PVE::Tools::run_command($cmd, outfunc => $keygen_outfunc);
-	$keyfiles->{"/etc/ssh/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
-	$keyfiles->{"/etc/ssh/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
+	$keyfiles->{"$sshdir/$basename"} = [PVE::Tools::file_get_contents($file), 0600];
+	$keyfiles->{"$sshdir/$basename.pub"} = [PVE::Tools::file_get_contents("$file.pub"), 0644];
 	unlink $file;
 	unlink "$file.pub";
     }
diff --git a/LXC/Setup/ALTLinux.pm b/LXC/Setup/ALTLinux.pm
new file mode 100644
index 0000000..177b617
--- /dev/null
+++ b/LXC/Setup/ALTLinux.pm
@@ -0,0 +1,57 @@
+package PVE::LXC::Setup::ALTLinux;
+
+use strict;
+use warnings;
+use Digest::SHA;
+use Crypt::Eksblowfish::Bcrypt;
+use PVE::LXC::Setup::Base;
+use base qw(PVE::LXC::Setup::Base);
+
+sub new {
+	my ($class, $conf, $rootdir) = @_;
+	my $ostype = "altlinux";
+	my $version = PVE::Tools::file_read_firstline("$rootdir/etc/$ostype-release");
+	my $self = { conf => $conf, rootdir => $rootdir, version => $version };
+	$conf->{ostype} = $ostype;
+	return bless $self, $class;
+}
+
+sub setup_init {
+    my ($self, $conf) = @_;
+    $self->setup_systemd_console($conf);
+}
+
+sub setup_network {
+    my ($self, $conf) = @_;
+    $self->setup_systemd_networkd($conf);
+}
+
+sub template_fixup {
+    my ($self, $conf) = @_;
+    $self->setup_securetty($conf, qw(pts/0 lxc/console));
+}
+
+sub set_user_password {
+    my ($self, $conf, $user, $opt_password) = @_;
+
+    my $shadowfile = "/etc/tcb/$user/shadow";
+    return if !$self->ct_file_exists($shadowfile);
+
+    if (defined($opt_password)) {
+	if ($opt_password !~ m/^\$/) {
+	    my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(substr(Digest::SHA::sha1_base64(time), 0, 16));
+	    $opt_password = Crypt::Eksblowfish::Bcrypt::bcrypt($opt_password, '$2a$08$'.$salt);
+	};
+    } else {
+	$opt_password = '*';
+    }
+
+    my $data = $user . ":" . $opt_password . ":" . (int(time()/86400)) . "::::::\n";
+
+    my $st = $self->ct_stat($shadowfile) || die "unable to stat file - $!";
+    $self->ct_file_set_contents($shadowfile, $data);
+    chmod $st->mode, $shadowfile;
+    chown $st->uid, $st->gid, $shadowfile;
+}
+
+1;

Порядок тот же (обратите внимание — запуск патча происходит из каталога, отличного от 5 версии):

cd /usr/share/perl5/PVE
patch -p1 -i <path_to>/pve4-alt-lxc.patch
service pvedaemon restart

Можно разворачивать контейнер из шаблона с ALT.

Создание CT

Подробнее об этом читайте тут. Отличий нет.

Ссылки