package service
|
|
import (
|
"aps_crm/conf"
|
"aps_crm/pkg/logx"
|
"aps_crm/utils"
|
"context"
|
"encoding/json"
|
"errors"
|
"os"
|
"os/exec"
|
"time"
|
)
|
|
// DockerImpl 平台下的用户容器管理
|
type DockerImpl struct{}
|
|
func (slf *DockerImpl) Image() string {
|
return "/var/data/aps/docker/image"
|
}
|
|
func (slf *DockerImpl) GetContainerRoot() string {
|
return "/var/data/aps/docker"
|
}
|
|
// Init 初始化(创建容器,并启动)
|
func (slf *DockerImpl) Init(cid string) error {
|
uDir := slf.GetContainerRoot() + "/" + cid
|
//if !utils.DirExists(uDir + "/db") {
|
if !utils.DirExists(uDir) {
|
err := os.MkdirAll(uDir, os.ModePerm)
|
if err != nil {
|
logx.Errorf("MkdirAll err:", err)
|
return err
|
}
|
}
|
var err error
|
defer func() {
|
if err != nil {
|
logx.Errorf("docker init defer err:", err)
|
os.RemoveAll(uDir)
|
}
|
}()
|
|
//启动容器
|
err = slf.Start(cid)
|
if err != nil {
|
logx.Errorf("start container err:", err, " id:", cid)
|
return err
|
}
|
return nil
|
}
|
|
type ContainerDockerInfo struct {
|
Name string `json:"Name"`
|
Image string `json:"Image"`
|
State struct {
|
Status string `json:"SalesReturnStatus"`
|
Running bool `json:"Running"`
|
} `json:"State"`
|
}
|
|
// Exist 判断容器是否存在
|
func (slf *DockerImpl) Exist(cid string) (*ContainerDockerInfo, error) {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return nil, errors.New("sudoPassword 配置有误")
|
}
|
sh := "echo " + sudoPwd + "|sudo -S docker inspect " + cid
|
cmd := exec.Command("sh", "-c", sh)
|
ret, _ := cmd.Output()
|
//当前cid容器不存在时,会报exit status 1错误并且 ret是空数组。所以不再判断Output的输出Error
|
var cdi []ContainerDockerInfo
|
e := json.Unmarshal(ret, &cdi)
|
if e != nil {
|
logx.Errorf("unmarshal e:", e)
|
return nil, e
|
}
|
if len(cdi) == 1 {
|
return &cdi[0], nil
|
}
|
|
return nil, ContainerNotFound
|
}
|
|
// Start 启动容器
|
func (slf *DockerImpl) Start(cid string) error {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return errors.New("sudoPassword 配置有误")
|
}
|
|
// 判断容器是否存在
|
cdi, ce := slf.Exist(cid)
|
logx.Infof("slf.Exist containerInfo:", cdi, " ce:", ce)
|
if ce != nil { // 容器不存在
|
uhome := slf.GetContainerRoot() + "/" + cid
|
//if !utils.DirExists(uhome + "/db")
|
if !utils.DirExists(uhome) {
|
//err := os.MkdirAll(uhome+"/db", os.ModePerm)
|
err := os.MkdirAll(uhome, os.ModePerm)
|
if err != nil {
|
logx.Errorf("docker Init err:", err)
|
return err
|
}
|
}
|
//sh := "echo " + sudoPwd + "|sudo -S docker run -d --restart=always --net host --name " + cid + " -v " + uhome + "/db:/saas/db saasuser:latest start.sh " + cid
|
sh := "echo " + sudoPwd + "|sudo -S docker run -d --restart=always --net host --name " + cid + " aps-admin:latest /bin/bash /aps/start.sh " + cid
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker start container:", cid, " ret:", ret)
|
return nil
|
}
|
|
if cdi.State.Running { // 容器存在,运行状态
|
return nil
|
}
|
|
// 容器存在,停止状态
|
{
|
sh := "echo " + sudoPwd + "|sudo -S docker start " + cid
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker start container:", cid, " ret:", ret)
|
return nil
|
}
|
}
|
|
// Stop 停止容器
|
func (slf *DockerImpl) Stop(cid string) error {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return errors.New("sudoPassword 配置有误")
|
}
|
sh := "echo " + sudoPwd + "|sudo -S docker stop " + cid + ""
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker stop container:", cid, " ret:", ret)
|
return nil
|
}
|
|
// Restart 重启容器
|
func (slf *DockerImpl) Restart(cid string) error {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return errors.New("sudoPassword 配置有误")
|
}
|
sh := "echo " + sudoPwd + "|sudo -S docker restart " + cid + ""
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker restart container:", cid, " ret:", ret)
|
return nil
|
}
|
|
// BakData 备份数据
|
func (slf *DockerImpl) BakData(cid string) error {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return errors.New("sudoPassword 配置有误")
|
}
|
bdir := slf.GetContainerRoot() + "/bak"
|
if !utils.DirExists(bdir) {
|
err := os.MkdirAll(bdir, os.ModePerm)
|
if err != nil {
|
return err
|
}
|
}
|
sh := "echo " + sudoPwd + "|sudo -S cp -r " + slf.GetContainerRoot() + "/" + cid + " " + bdir
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker Bake container:", cid, " ret:", ret)
|
return nil
|
}
|
|
// Destroy 销毁容器包括数据(销毁前先备份)
|
func (slf *DockerImpl) Destroy(cid string) error {
|
sudoPwd := conf.Conf.System.SudoPassword
|
if sudoPwd == "" {
|
return errors.New("sudoPassword 配置有误")
|
}
|
//删除前先备份数据
|
if err := slf.BakData(cid); err != nil {
|
return err
|
}
|
sh := "echo " + sudoPwd + "|sudo -S docker rm -f " + cid + ""
|
cmd := exec.Command("sh", "-c", sh)
|
ret, e := cmd.Output()
|
if e != nil {
|
return e
|
}
|
logx.Infof("docker rm container:", cid, " ret:", ret)
|
|
dsh := "echo " + sudoPwd + "|sudo -S rm -rf " + slf.GetContainerRoot() + "/" + cid
|
dmd := exec.Command("sh", "-c", dsh)
|
dr, de := dmd.Output()
|
if de != nil {
|
return de
|
}
|
logx.Infof("rm -rf volume: ", slf.GetContainerRoot()+"/"+cid, " dret:", string(dr))
|
|
return nil
|
}
|
|
// 监控是否有未启动的用户容器
|
func (slf *DockerImpl) watch() {
|
ctx := context.Background()
|
for {
|
select {
|
case <-ctx.Done():
|
return
|
default:
|
time.Sleep(60 * time.Second)
|
//slf.initContainerNotFound()
|
}
|
}
|
}
|
|
func (slf *DockerImpl) initContainerNotFound() {
|
//users, _ := model.NewUserSearch(nil).FindNotTotal()
|
//for _, u := range users {
|
// if u.ParentId == "" { //是主账号
|
// //判断容器是否存在时是否需要加锁?用户注册主账号时是异步请求,创建docker容器没有冲突,因为容器的id不同。
|
// //拉起容器和用户主动启动容器也没有时间冲突
|
// _, e := slf.Exist(u.UUID)
|
// if e != ContainerNotFound {
|
// continue
|
// }
|
// if err := slf.Init(u.UUID); err != nil {
|
// logx.Errorf("init ContainerNotFound err:", err)
|
// }
|
// }
|
//}
|
}
|