* Copyright (c) 2025 Bocloud Technologies Co., Ltd.
* installer is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain n copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
******************************************************************/
package dockerd
import (
"context"
"errors"
"fmt"
"os"
"time"
"github.com/shirou/gopsutil/v3/host"
"gopkg.openfuyao.cn/bkeadm/pkg/executor/docker"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
"gopkg.openfuyao.cn/bkeadm/utils"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
const (
OverrideDockerConfig = `[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
`
)
func waitForDockerConnection(maxRetries int, interval time.Duration) bool {
for i := 0; i < maxRetries; i++ {
time.Sleep(interval)
if ensureDockerConnect() {
return true
}
}
return false
}
func getPackageManager(platform string) string {
switch platform {
case "ubuntu", "debian":
return "apt"
case "centos", "kylin", "redhat", "fedora":
return "yum"
default:
log.Warn("unknown platform, default yum package manager")
return "yum"
}
}
func installDockerPackage(platform, dockerdFile, pkgManager string) error {
if platform == "kylin" && utils.Exists(dockerdFile) {
return utils.UnTar(dockerdFile, "/")
}
result, err := global.Command.ExecuteCommandWithOutput(
"sh", "-c", fmt.Sprintf("%s -y install docker-ce", pkgManager))
if err != nil {
log.Error(result)
return err
}
return nil
}
func createSystemdDockerOverride() error {
configDir := "/etc/systemd/system/docker.service.d"
configFile := configDir + "/docker.conf"
if utils.Exists(configFile) {
return nil
}
if !utils.Exists(configDir) {
if err := os.MkdirAll(configDir, utils.DefaultDirPermission); err != nil {
log.Errorf("Create docker systemd config dir %s failed: %v", configDir, err)
return err
}
}
if err := os.WriteFile(configFile, []byte(OverrideDockerConfig), utils.DefaultFilePermission); err != nil {
log.Errorf("Write docker systemd config %s failed: %v", configFile, err)
return err
}
return nil
}
func startDockerService() error {
result, err := global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl enable docker")
if err != nil {
log.Warnf("systemctl enable docker error %s", result)
}
result, err = global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl daemon-reload")
if err != nil {
log.Warnf("systemctl daemon-reload error %s", result)
}
result, err = global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl start docker")
if err != nil {
log.Error(result)
return err
}
return nil
}
func updateExistingDocker(domain, runtimeStorage, hostIp string) error {
flag, err := initDockerConfig(domain, runtimeStorage)
if err != nil {
return err
}
if err = configDockerTls(hostIp); err != nil {
return err
}
flag2 := ensureRuncVersion()
if flag || flag2 {
result, err := global.Command.ExecuteCommandWithCombinedOutput("systemctl", "restart", "docker")
if err != nil {
log.Error(result)
return err
}
waitForDockerConnection(utils.DockerConnectionMaxRetries, utils.DockerConnectionRetrySeconds*time.Second)
}
return nil
}
func installNewDocker(domain, runtimeStorage, dockerdFile, hostIp string) error {
log.Info("install docker...")
platform, _, _, err := host.PlatformInformation()
if err != nil {
log.Errorf("Get host platform information failed: %v", err)
}
pkgManager := getPackageManager(platform)
if err = installDockerPackage(platform, dockerdFile, pkgManager); err != nil {
return err
}
if err = os.Mkdir("/etc/docker", utils.DefaultDirPermission); err != nil && !os.IsExist(err) {
log.Warnf("Failed to create /etc/docker: %v", err)
}
if _, err = initDockerConfig(domain, runtimeStorage); err != nil {
log.Errorf("Init docker config for domain %s failed: %v", domain, err)
return err
}
ensureRuncVersion()
if err = configDockerTls(hostIp); err != nil {
return err
}
if err = createSystemdDockerOverride(); err != nil {
return err
}
if err = startDockerService(); err != nil {
return err
}
if waitForDockerConnection(utils.DockerConnectionMaxRetries, utils.DockerConnectionRetrySeconds*time.Second) {
return nil
}
return errors.New("docker installation failed")
}
func EnsureDockerServer(domain string, runtimeStorage string, dockerdFile string, hostIp string) error {
if ensureDockerConnect() {
return updateExistingDocker(domain, runtimeStorage, hostIp)
}
return installNewDocker(domain, runtimeStorage, dockerdFile, hostIp)
}
func ensureDockerConnect() bool {
if global.Docker == nil {
global.Docker, _ = docker.NewDockerClient()
}
if global.Docker != nil {
_, err := global.Docker.GetClient().Ping(context.Background())
if err == nil {
return true
}
}
return false
}