优化了机器创建流程

This commit is contained in:
MengMengCode
2026-07-18 20:45:23 +08:00
parent ebba97f1d6
commit 2324494dd7
3 changed files with 45 additions and 6 deletions
+27 -6
View File
@@ -545,9 +545,11 @@ func (m *Manager) CreateContainer(cfg ContainerConfig) error {
fmt.Printf("Warning: failed to install IPv6 init in %s: %v\n", lxcName, err) fmt.Printf("Warning: failed to install IPv6 init in %s: %v\n", lxcName, err)
} }
} }
cfg.ReportProgress("ssh", "安装并配置 SSH 服务") cfg.ReportProgress("ssh", "检测并预配置 SSH 服务")
if err := m.preconfigureSSH(rootfsPath, cfg.TemplateID, sshAccess.Mode); err != nil { if configured, err := m.preconfigureSSHIfInstalled(rootfsPath, cfg.TemplateID, sshAccess.Mode); err != nil {
fmt.Printf("Warning: failed to pre-configure SSH in %s: %v\n", lxcName, err) fmt.Printf("Warning: failed to pre-configure SSH in %s: %v\n", lxcName, err)
} else if !configured {
fmt.Printf("SSH server is not bundled in %s; installation deferred until after first boot\n", lxcName)
} }
if sshAccess.PublicKey != "" { if sshAccess.PublicKey != "" {
if err := m.installRootAuthorizedKey(rootfsPath, sshAccess.PublicKey); err != nil { if err := m.installRootAuthorizedKey(rootfsPath, sshAccess.PublicKey); err != nil {
@@ -898,6 +900,25 @@ func (m *Manager) preconfigureSSH(rootfsPath, templateID string, sshAuthMode str
return nil return nil
} }
// preconfigureSSHIfInstalled keeps image creation independent from external
// package mirrors. Minimal images install SSH asynchronously after first boot.
func (m *Manager) preconfigureSSHIfInstalled(rootfsPath, templateID, sshAuthMode string) (bool, error) {
if !rootfsHasSSHD(rootfsPath) {
return false, nil
}
return true, m.preconfigureSSH(rootfsPath, templateID, sshAuthMode)
}
func rootfsHasSSHD(rootfsPath string) bool {
for _, relativePath := range []string{"usr/sbin/sshd", "sbin/sshd", "usr/bin/sshd"} {
info, err := os.Stat(filepath.Join(rootfsPath, relativePath))
if err == nil && !info.IsDir() {
return true
}
}
return false
}
// applyResourceLimits applies cgroup v2 limits and mandatory security hardening to container config. // applyResourceLimits applies cgroup v2 limits and mandatory security hardening to container config.
func (m *Manager) applyResourceLimits(lxcName string, cfg ContainerConfig) error { func (m *Manager) applyResourceLimits(lxcName string, cfg ContainerConfig) error {
cfg.NormalizeResourceAliases() cfg.NormalizeResourceAliases()
@@ -1877,9 +1898,7 @@ func (m *Manager) StartContainer(id int) error {
if err := m.ensureLANHostAccess(c); err != nil { if err := m.ensureLANHostAccess(c); err != nil {
fmt.Printf("Warning: failed to prepare LAN IPv4 host access for %s: %v\n", lxcName, err) fmt.Printf("Warning: failed to prepare LAN IPv4 host access for %s: %v\n", lxcName, err)
} }
if err := m.EnsureSSH(id); err != nil { m.WarmSSHAsync(id, "container start")
return err
}
} }
if current := config.FindContainer(id); current != nil { if current := config.FindContainer(id); current != nil {
@@ -3336,8 +3355,10 @@ func (m *Manager) ReinstallContainer(id int, templateID string, authConfig ...Co
} }
} }
c.SSHPassword = sshAccess.Password c.SSHPassword = sshAccess.Password
if err := m.preconfigureSSH(rootfsPath, templateID, sshAccess.Mode); err != nil { if configured, err := m.preconfigureSSHIfInstalled(rootfsPath, templateID, sshAccess.Mode); err != nil {
fmt.Printf("Warning: failed to pre-configure SSH in %s after reinstall: %v\n", lxcName, err) fmt.Printf("Warning: failed to pre-configure SSH in %s after reinstall: %v\n", lxcName, err)
} else if !configured {
fmt.Printf("SSH server is not bundled in %s; installation deferred until after reinstall boot\n", lxcName)
} }
if sshAccess.PublicKey != "" { if sshAccess.PublicKey != "" {
if err := m.installRootAuthorizedKey(rootfsPath, sshAccess.PublicKey); err != nil { if err := m.installRootAuthorizedKey(rootfsPath, sshAccess.PublicKey); err != nil {
+17
View File
@@ -121,6 +121,23 @@ func TestManagedPrlimitLinesDoNotSetNproc(t *testing.T) {
} }
} }
func TestRootfsHasSSHD(t *testing.T) {
rootfs := t.TempDir()
if rootfsHasSSHD(rootfs) {
t.Fatal("empty rootfs unexpectedly reports sshd")
}
sshd := filepath.Join(rootfs, "usr", "sbin", "sshd")
if err := os.MkdirAll(filepath.Dir(sshd), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(sshd, []byte("#!/bin/sh\n"), 0755); err != nil {
t.Fatal(err)
}
if !rootfsHasSSHD(rootfs) {
t.Fatal("executable sshd was not detected")
}
}
func TestSameFilesystemPathResolvesContainerStorageSymlink(t *testing.T) { func TestSameFilesystemPathResolvesContainerStorageSymlink(t *testing.T) {
base := t.TempDir() base := t.TempDir()
storageContainer := filepath.Join(base, "storage", "ct-1") storageContainer := filepath.Join(base, "storage", "ct-1")
+1
View File
@@ -795,6 +795,7 @@ const exact: Record<string, string> = {
'保存容器配置': 'Saving container configuration', '保存容器配置': 'Saving container configuration',
'写入容器网络配置': 'Writing container network configuration', '写入容器网络配置': 'Writing container network configuration',
'安装并配置 SSH 服务': 'Installing and configuring SSH', '安装并配置 SSH 服务': 'Installing and configuring SSH',
'检测并预配置 SSH 服务': 'Detecting and preconfiguring SSH',
'转换非特权容器文件权限': 'Converting unprivileged container permissions', '转换非特权容器文件权限': 'Converting unprivileged container permissions',
'设置容器登录凭据': 'Setting container login credentials', '设置容器登录凭据': 'Setting container login credentials',
'启动容器并等待网络就绪': 'Starting container and waiting for network', '启动容器并等待网络就绪': 'Starting container and waiting for network',