CasaOS/service/docker.go

959 lines
26 KiB
Go
Raw Normal View History

2021-09-26 02:35:02 +00:00
package service
import (
"bytes"
"context"
"encoding/base64"
"encoding/binary"
json2 "encoding/json"
"fmt"
"github.com/IceWhaleTech/CasaOS/model/notify"
2022-05-05 05:46:55 +00:00
"github.com/pkg/errors"
"go.uber.org/zap"
2021-09-26 02:35:02 +00:00
2021-09-27 06:17:36 +00:00
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
2021-09-27 06:17:36 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
2021-09-26 02:35:02 +00:00
//"github.com/containerd/containerd/oci"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
client2 "github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
2021-09-26 02:35:02 +00:00
)
type DockerService interface {
DockerPullImage(imageName string, icon, name string) error
2021-09-26 02:35:02 +00:00
IsExistImage(imageName string) bool
DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error)
2022-05-05 05:46:55 +00:00
DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error)
2021-09-26 02:35:02 +00:00
DockerContainerStart(name string) error
DockerContainerStats(name string) (string, error)
DockerListByName(name string) (*types.Container, error)
DockerListByImage(image, version string) (*types.Container, error)
DockerContainerInfo(name string) (*types.ContainerJSON, error)
DockerImageRemove(name string) error
2021-12-06 09:08:36 +00:00
DockerContainerRemove(name string, update bool) error
2021-09-26 02:35:02 +00:00
DockerContainerStop(id string) error
DockerContainerUpdateName(name, id string) (err error)
2021-09-26 02:35:02 +00:00
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
DockerContainerLog(name string) (string, error)
DockerContainerCommit(name string)
2022-05-05 05:46:55 +00:00
DockerContainerList() []types.Container
2021-09-26 02:35:02 +00:00
DockerNetworkModelList() []types.NetworkResource
2022-05-05 05:46:55 +00:00
DockerImageInfo(image string) (types.ImageInspect, error)
GetNetWorkNameByNetWorkID(id string) (string, error)
ContainerExecShell(container_id string) string
2022-09-15 07:13:07 +00:00
GetDockerInfo() (types.Info, error)
2021-09-26 02:35:02 +00:00
}
type dockerService struct {
rootDir string
}
2022-05-05 05:46:55 +00:00
func (ds *dockerService) DockerContainerList() []types.Container {
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil {
return nil
}
defer cli.Close()
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return containers
}
return containers
}
func (ds *dockerService) ContainerExecShell(container_id string) string {
2021-09-26 02:35:02 +00:00
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{
User: "1000:1000",
Cmd: []string{"echo -e \"hellow\nworld\" >> /a.txt"},
})
2021-09-26 02:35:02 +00:00
if err != nil {
os.Exit(5)
}
err = cli.ContainerExecStart(context.Background(), exec.ID, types.ExecStartCheck{})
if err != nil {
fmt.Println("exec script error ", err)
2021-09-26 02:35:02 +00:00
}
return exec.ID
2021-09-26 02:35:02 +00:00
}
2022-09-15 07:13:07 +00:00
// 创建默认网络
2021-09-26 02:35:02 +00:00
func DockerNetwork() {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
d, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
2021-09-26 02:35:02 +00:00
for _, resource := range d {
if resource.Name == docker.NETWORKNAME {
return
}
}
cli.NetworkCreate(context.Background(), docker.NETWORKNAME, types.NetworkCreate{})
}
2022-09-15 07:13:07 +00:00
// 根据网络id获取网络名
func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
filter := filters.NewArgs()
filter.Add("id", id)
2021-12-03 08:48:07 +00:00
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter})
if err == nil && len(d) > 0 {
return d[0].Name, nil
}
return "", err
}
2022-09-15 07:13:07 +00:00
// 拉取镜像
2021-09-26 02:35:02 +00:00
func DockerPull() {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
✨ New Feature - [Apps] This is a feature that has been highly requested by the community. Import the original Docker application into CasaOS. Now it's easy to import with just a few clicks! - [Apps] App list supports a custom sorting function! You can arrange apps in different orders by dragging the icons. - [Apps] App custom installation supports Docker Compose configuration import in YAML format. - [Files] Added thumbnail preview function for image files. - [Connect] Multiple CasaConenct devices in the LAN will be transmitted through the LAN network. - [System] Added a switch for auto-mounting USB disk devices. 🎈 Enhancement - [System] Optimized the system update alert, you will see the new version update log from the next version. - [Apps] Added live preview for icons in custom installed apps. - [Apps] Optimized the input of WebUI. - [Files] Completely updated the image preview, now it supports switching all images in the same folder, as well as dragging, zooming, rotating and resetting. - [Widgets] Added color levels for CPU and RAM charts. - [Conenct] Optimized the display of the right-click menu of the Connect friends list. 🎈 Changed - [Files] Change the initial display directory to /DATA 🐞 Fixed - [System] Fixed an issue with Raspberry Pi devices failing to boot using USB disks. (Achieved by disabling USB disk auto-mount) - [Apps] Fixed the issue that some Docker CLI commands failed to import. - [Apps] Fixed the issue that the app is not easily recognized in /DATA/AppData directory and docker command line after installation, it will be shown as the app name. (Newly installed apps only) - [Apps] Fixed the issue that Pi-hole cannot be launched after installation in the app store. - [Apps] Fixed the issue that apps cannot be updated with WatchTower. - [Files] Fixed the issue that when there is an upload task, the task status is lost after closing Files.
2022-05-13 10:12:26 +00:00
authConfig := types.AuthConfig{}
2021-09-26 02:35:02 +00:00
encodedJSON, err := json2.Marshal(authConfig)
fmt.Println(err)
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
reader, err := cli.ImagePull(context.Background(), "swr.cn-north-4.myhuaweicloud.com/root/swr-demo-2048:latest", types.ImagePullOptions{RegistryAuth: authStr})
buf := new(bytes.Buffer)
buf.ReadFrom(reader)
fmt.Println(buf.String())
}
2022-09-15 07:13:07 +00:00
// 拉取镜像
2021-09-26 02:35:02 +00:00
func DockerEx() {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
importResponse, err := cli.ImageImport(context.Background(), types.ImageImportSource{
Source: strings.NewReader("source"),
SourceName: "image_source",
}, "repository_name:imported", types.ImageImportOptions{
Tag: "imported",
Message: "A message",
Changes: []string{"change1", "change2"},
})
response, err := ioutil.ReadAll(importResponse)
if err != nil {
fmt.Println(err)
}
importResponse.Close()
println(string(response))
if string(response) != "response" {
2021-12-03 08:48:07 +00:00
fmt.Printf("expected response to contain 'response', got %s", string(response))
2021-09-26 02:35:02 +00:00
}
}
//func DockerContainerSize() {
// cli, err := client2.NewClientWithOpts(client2.FromEnv)
// //but := bytes.Buffer{}
// d, err := cli.ContainerExecCreate(context.Background(), "c3adcef92bae648890941ac00e6c4024d7f2959c2e629f0b581d6a19d77b5eda")
// fmt.Println(d)
// st, _ := ioutil.ReadAll(d.Body)
// fmt.Println(string(st))
// if err != nil {
// fmt.Print(err)
// }
//
//}
2022-05-05 05:46:55 +00:00
func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) {
2021-09-26 02:35:02 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
2022-05-05 05:46:55 +00:00
return types.ImageInspect{}, err
2021-09-26 02:35:02 +00:00
}
2022-05-05 05:46:55 +00:00
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image)
if err != nil {
return inspect, err
}
return inspect, nil
2021-09-26 02:35:02 +00:00
}
func MsqlExec(container string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
ctx := context.Background()
// 执行/bin/bash命令
ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{
AttachStdin: false,
AttachStdout: true,
AttachStderr: true,
Cmd: []string{"date"},
Tty: true,
Env: []string{"aaa=ddd"},
})
err = cli.ContainerExecStart(ctx, ir.ID, types.ExecStartCheck{})
fmt.Println(err)
return err
}
func Exec(container, row, col string) (hr types.HijackedResponse, err error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
ctx := context.Background()
// 执行/bin/bash命令
ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Env: []string{"COLUMNS=" + col, "LINES=" + row},
Cmd: []string{"/bin/bash"},
Tty: true,
})
if err != nil {
return
}
// 附加到上面创建的/bin/bash进程中
hr, err = cli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true})
if err != nil {
return
}
return
}
func DockerLog() {
//cli, err := client2.NewClientWithOpts(client2.FromEnv)
//ctx := context.Background()
//ir, err := cli.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{})
//str, err := ioutil.ReadAll(ir)
//fmt.Println(string(str))
//fmt.Println(err)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
client, _ := client2.NewClientWithOpts(client2.FromEnv)
reader, err := client.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{})
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(os.Stdout, reader)
if err != nil && err != io.EOF {
log.Fatal(err)
}
}
func DockerLogs() {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
i, err := cli.ContainerLogs(context.Background(), "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{
ShowStderr: true,
ShowStdout: true,
Timestamps: false,
Follow: true,
Tail: "40",
})
if err != nil {
log.Fatal(err)
}
2021-12-03 08:48:07 +00:00
defer i.Close()
2021-09-26 02:35:02 +00:00
hdr := make([]byte, 8)
for {
_, err := i.Read(hdr)
if err != nil {
log.Fatal(err)
}
var w io.Writer
switch hdr[0] {
case 1:
w = os.Stdout
default:
w = os.Stderr
}
count := binary.BigEndian.Uint32(hdr[4:])
dat := make([]byte, count)
_, err = i.Read(dat)
fmt.Fprint(w, string(dat))
}
}
//正式内容
2022-09-15 07:13:07 +00:00
// 检查镜像是否存在
2021-09-26 02:35:02 +00:00
func (ds *dockerService) IsExistImage(imageName string) bool {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return false
}
defer cli.Close()
filter := filters.NewArgs()
filter.Add("reference", imageName)
list, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
if err == nil && len(list) > 0 {
return true
}
return false
}
2022-09-15 07:13:07 +00:00
// 安装镜像
func (ds *dockerService) DockerPullImage(imageName string, icon, name string) error {
2021-09-26 02:35:02 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
out, err := cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{})
if err != nil {
return err
}
defer out.Close()
if err != nil {
return err
}
//io.Copy()
buf := make([]byte, 2048*4)
2021-09-26 02:35:02 +00:00
for {
n, err := out.Read(buf)
if err != nil {
if err != io.EOF {
fmt.Println("read error:", err)
}
break
}
if len(icon) > 0 && len(name) > 0 {
notify := notify.Application{}
notify.Icon = icon
notify.Name = name
notify.State = "PULLING"
notify.Type = "INSTALL"
notify.Finished = false
notify.Success = true
notify.Message = string(buf[:n])
MyService.Notify().SendInstallAppBySocket(notify)
}
2021-09-26 02:35:02 +00:00
}
return err
}
2022-05-05 05:46:55 +00:00
func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return "", err
}
defer cli.Close()
container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
if err != nil {
return "", err
}
return container.ID, err
}
2021-09-26 02:35:02 +00:00
2022-09-15 07:13:07 +00:00
// param imageName 镜像名称
// param containerDbId 数据库的id
// param port 容器内部主端口
// param mapPort 容器主端口映射到外部的端口
// param tcp 容器其他tcp端口
// param udp 容器其他udp端口
func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) {
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
if len(m.NetworkModel) == 0 {
m.NetworkModel = "bridge"
2021-09-26 02:35:02 +00:00
}
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return "", err
}
2021-09-26 02:35:02 +00:00
defer cli.Close()
ports := make(nat.PortSet)
portMaps := make(nat.PortMap)
// ports[nat.Port(fmt.Sprint(m.PortMap)+"/tcp")] = struct{}{}
// if net != "host" {
// portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
// }
2021-12-29 08:42:20 +00:00
//port := ""
2021-09-26 02:35:02 +00:00
for _, portMap := range m.Ports {
2021-12-29 08:42:20 +00:00
// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
// port = portMap.ContainerPort
// }
2021-09-26 02:35:02 +00:00
if portMap.Protocol == "tcp" {
2021-09-26 02:35:02 +00:00
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
if tContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
if m.NetworkModel != "host" {
2022-03-18 03:30:06 +00:00
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
2021-09-26 02:35:02 +00:00
}
}
} else if portMap.Protocol == "both" {
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
if tContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
if m.NetworkModel != "host" {
2022-03-18 03:30:06 +00:00
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
2021-09-26 02:35:02 +00:00
}
}
uContainer, _ := strconv.Atoi(portMap.ContainerPort)
if uContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
if m.NetworkModel != "host" {
2022-03-18 03:30:06 +00:00
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
2021-09-26 02:35:02 +00:00
}
}
} else {
uContainer, _ := strconv.Atoi(portMap.ContainerPort)
if uContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
if m.NetworkModel != "host" {
2022-03-18 03:30:06 +00:00
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
2021-09-26 02:35:02 +00:00
}
}
}
}
var envArr []string
var showENV []string
2022-06-13 12:43:19 +00:00
showENV = append(showENV, "casaos")
2021-09-26 02:35:02 +00:00
for _, e := range m.Envs {
2022-06-13 12:43:19 +00:00
showENV = append(showENV, e.Name)
if strings.HasPrefix(e.Value, "$") {
2021-12-29 08:42:20 +00:00
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
continue
}
2021-09-26 02:35:02 +00:00
if len(e.Value) > 0 {
if e.Value == "port_map" {
envArr = append(envArr, e.Name+"="+m.PortMap)
continue
}
envArr = append(envArr, e.Name+"="+e.Value)
}
}
res := container.Resources{}
if m.CpuShares > 0 {
res.CPUShares = m.CpuShares
}
if m.Memory > 0 {
res.Memory = m.Memory << 20
}
for _, p := range m.Devices {
if len(p.Path) > 0 {
2022-02-17 10:43:25 +00:00
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
2021-09-26 02:35:02 +00:00
}
}
hostConfingBind := []string{}
2021-09-26 02:35:02 +00:00
// volumes bind
volumes := []mount.Mount{}
for _, v := range m.Volumes {
path := v.Path
if len(path) == 0 {
2022-05-05 05:46:55 +00:00
path = docker.GetDir(m.Label, v.Path)
2021-09-26 02:35:02 +00:00
if len(path) == 0 {
continue
}
}
2022-05-05 05:46:55 +00:00
path = strings.ReplaceAll(path, "$AppID", m.Label)
2021-12-29 08:42:20 +00:00
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
//result1 := reg1.FindAllStringSubmatch(path, -1)
//if len(result1) == 0 {
err = file.IsNotExistMkDir(path)
if err != nil {
loger.Error("Failed to create a folder", zap.Any("err", err))
2021-12-29 08:42:20 +00:00
continue
2021-09-26 02:35:02 +00:00
}
2021-12-29 08:42:20 +00:00
//}
// else {
// err = file.IsNotExistCreateFile(path)
// if err != nil {
// ds.log.Error("mkdir error", err)
// continue
// }
// }
2021-09-26 02:35:02 +00:00
volumes = append(volumes, mount.Mount{
Type: mount.TypeBind,
Source: path,
Target: v.ContainerPath,
})
hostConfingBind = append(hostConfingBind, v.Path+":"+v.ContainerPath)
2021-09-26 02:35:02 +00:00
}
rp := container.RestartPolicy{}
if len(m.Restart) > 0 {
rp.Name = m.Restart
}
2021-12-29 08:42:20 +00:00
// healthTest := []string{}
// if len(port) > 0 {
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
// }
// health := &container.HealthConfig{
// Test: healthTest,
// StartPeriod: 0,
// Retries: 1000,
// }
// fmt.Print(health)
2022-02-17 10:43:25 +00:00
if len(m.HostName) == 0 {
m.HostName = m.Label
}
info, err := cli.ContainerInspect(context.Background(), id)
hostConfig := &container.HostConfig{}
config := &container.Config{}
config.Labels = map[string]string{}
if err == nil {
// info.HostConfig = &container.HostConfig{}
// info.Config = &container.Config{}
// info.NetworkSettings = &types.NetworkSettings{}
hostConfig = info.HostConfig
config = info.Config
if config.Labels["casaos"] == "casaos" {
config.Cmd = m.Cmd
config.Image = m.Image
config.Env = envArr
config.Hostname = m.HostName
config.ExposedPorts = ports
}
} else {
config.Cmd = m.Cmd
config.Image = m.Image
config.Env = envArr
config.Hostname = m.HostName
config.ExposedPorts = ports
2021-09-26 02:35:02 +00:00
}
2022-05-05 05:46:55 +00:00
config.Labels["origin"] = m.Origin
config.Labels["casaos"] = "casaos"
2022-05-05 05:46:55 +00:00
config.Labels["web"] = m.PortMap
config.Labels["icon"] = m.Icon
config.Labels["desc"] = m.Description
✨ New Feature - [Apps] This is a feature that has been highly requested by the community. Import the original Docker application into CasaOS. Now it's easy to import with just a few clicks! - [Apps] App list supports a custom sorting function! You can arrange apps in different orders by dragging the icons. - [Apps] App custom installation supports Docker Compose configuration import in YAML format. - [Files] Added thumbnail preview function for image files. - [Connect] Multiple CasaConenct devices in the LAN will be transmitted through the LAN network. - [System] Added a switch for auto-mounting USB disk devices. 🎈 Enhancement - [System] Optimized the system update alert, you will see the new version update log from the next version. - [Apps] Added live preview for icons in custom installed apps. - [Apps] Optimized the input of WebUI. - [Files] Completely updated the image preview, now it supports switching all images in the same folder, as well as dragging, zooming, rotating and resetting. - [Widgets] Added color levels for CPU and RAM charts. - [Conenct] Optimized the display of the right-click menu of the Connect friends list. 🎈 Changed - [Files] Change the initial display directory to /DATA 🐞 Fixed - [System] Fixed an issue with Raspberry Pi devices failing to boot using USB disks. (Achieved by disabling USB disk auto-mount) - [Apps] Fixed the issue that some Docker CLI commands failed to import. - [Apps] Fixed the issue that the app is not easily recognized in /DATA/AppData directory and docker command line after installation, it will be shown as the app name. (Newly installed apps only) - [Apps] Fixed the issue that Pi-hole cannot be launched after installation in the app store. - [Apps] Fixed the issue that apps cannot be updated with WatchTower. - [Files] Fixed the issue that when there is an upload task, the task status is lost after closing Files.
2022-05-13 10:12:26 +00:00
config.Labels["index"] = m.Index
config.Labels["custom_id"] = m.CustomId
config.Labels["show_env"] = strings.Join(showENV, ",")
config.Labels["protocol"] = m.Protocol
config.Labels["host"] = m.Host
config.Labels["name"] = m.Label
//container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
hostConfig.Mounts = volumes
hostConfig.Privileged = m.Privileged
hostConfig.CapAdd = m.CapAdd
hostConfig.NetworkMode = container.NetworkMode(m.NetworkModel)
hostConfig.RestartPolicy = rp
hostConfig.Resources = res
//hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: , Privileged: m.Privileged, CapAdd: m.CapAdd}
2021-09-26 02:35:02 +00:00
//if net != "host" {
2021-09-26 02:35:02 +00:00
hostConfig.PortBindings = portMaps
//}
containerDb, err := cli.ContainerCreate(context.Background(),
config,
hostConfig,
Dev (#298) * fix bug * updata UI * 0.3.2 ### Added - [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc. - [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204)) ### Changed - [Apps] Hide the display of non-essential environment variables in the application. - [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket. - [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214)) ### Fixed - [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68)) - [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210)) - [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240)) - [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224)) * Modify log help class * Fix some bugs in 0.3.2 * Solve the operation file queue problem * Exclude web folders * update UI * add cancel file operate * Update UI * Merge sockets to transfer data * Conflict Resolution * Update send data interval * Update UI * fixed bug - Fix the problem of application opening failure on non-80 ports - Modify port failure problem - Modify environment variables disappearing problem * update version function * Fix version update issues * fixed bug - [System] Fixed the issue of widgets displaying wrongly on mobile devices. - [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280)) - [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282)) - [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284)) - [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278)) - [System] Fixed some bugs of application cpu usage and memory staging([#272]https://github.com/IceWhaleTech/CasaOS/issues/272) * update UI * Update CHANGELOG.md * update app service * update ui * Fix application installation host mode error * update ui * Update UI
2022-06-15 11:01:26 +00:00
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{m.NetworkModel: {NetworkID: "", Aliases: []string{}}}},
2021-09-26 02:35:02 +00:00
nil,
m.ContainerName)
2021-09-26 02:35:02 +00:00
if err != nil {
return "", err
}
return containerDb.ID, err
}
2022-09-15 07:13:07 +00:00
// 删除容器
2021-12-06 09:08:36 +00:00
func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
2021-09-26 02:35:02 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
//路径处理
2021-12-06 09:08:36 +00:00
if !update {
path := docker.GetDir(name, "/config")
if !file.CheckNotExist(path) {
file.RMDir(path)
}
2021-09-26 02:35:02 +00:00
}
if err != nil {
return err
}
return err
}
2022-09-15 07:13:07 +00:00
// 删除镜像
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerImageRemove(name string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{})
imageId := ""
Loop:
for _, ig := range imageList {
for _, i := range ig.RepoTags {
if i == name {
imageId = ig.ID
break Loop
}
}
}
_, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{})
return err
}
func DockerImageRemove(name string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{})
imageId := ""
Loop:
for _, ig := range imageList {
fmt.Println(ig.RepoDigests)
fmt.Println(ig.Containers)
for _, i := range ig.RepoTags {
if i == name {
imageId = ig.ID
break Loop
}
}
}
_, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{})
return err
}
2022-09-15 07:13:07 +00:00
// 停止镜像
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerStop(id string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
err = cli.ContainerStop(context.Background(), id, nil)
return err
}
2022-09-15 07:13:07 +00:00
// 启动容器
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerStart(name string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
return err
}
2022-09-15 07:13:07 +00:00
// 查看日志
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerLog(name string) (string, error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return "", err
}
defer cli.Close()
body, err := cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{ShowStderr: true, ShowStdout: true})
if err != nil {
return "", err
}
defer body.Close()
content, err := ioutil.ReadAll(body)
if err != nil {
return "", err
}
return string(content), nil
}
func DockerContainerStats1() error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
dss, err := cli.ContainerStats(context.Background(), "dockermysql", false)
if err != nil {
return err
}
defer dss.Body.Close()
sts, err := ioutil.ReadAll(dss.Body)
if err != nil {
return err
}
fmt.Println(string(sts))
return nil
}
2022-09-15 07:13:07 +00:00
// 获取容器状态
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerStats(name string) (string, error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return "", err
}
defer cli.Close()
dss, err := cli.ContainerStats(context.Background(), name, false)
if err != nil {
return "", err
}
defer dss.Body.Close()
sts, err := ioutil.ReadAll(dss.Body)
if err != nil {
return "", err
}
return string(sts), nil
}
2022-09-15 07:13:07 +00:00
// 备份容器
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerCommit(name string) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
fmt.Println(err)
}
defer cli.Close()
d, err := cli.ContainerInspect(context.Background(), name)
dss, err := cli.ContainerCommit(context.Background(), name, types.ContainerCommitOptions{Reference: "test", Config: d.Config})
if err != nil {
fmt.Println(err)
}
fmt.Println(dss)
}
func (ds *dockerService) DockerListByName(name string) (*types.Container, error) {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
filter := filters.NewArgs()
filter.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
if err != nil {
return &types.Container{}, err
}
2022-05-05 05:46:55 +00:00
if len(containers) == 0 {
return &types.Container{}, errors.New("not found")
}
2021-09-26 02:35:02 +00:00
return &containers[0], nil
}
func (ds *dockerService) DockerListByImage(image, version string) (*types.Container, error) {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
filter := filters.NewArgs()
filter.Add("ancestor", image+":"+version)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
if err != nil {
return nil, err
}
if len(containers) == 0 {
return nil, nil
}
return &containers[0], nil
}
2022-09-15 07:13:07 +00:00
// 获取容器详情
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerInfo(name string) (*types.ContainerJSON, error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return &types.ContainerJSON{}, err
}
defer cli.Close()
d, err := cli.ContainerInspect(context.Background(), name)
if err != nil {
return &types.ContainerJSON{}, err
}
return &d, nil
}
2022-09-15 07:13:07 +00:00
// 更新容器
// param shares cpu优先级
// param containerDbId 数据库的id
// param port 容器内部主端口
// param mapPort 容器主端口映射到外部的端口
// param tcp 容器其他tcp端口
// param udp 容器其他udp端口
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
//重启策略
rp := container.RestartPolicy{
Name: "",
MaximumRetryCount: 0,
}
if len(m.Restart) > 0 {
rp.Name = m.Restart
}
res := container.Resources{}
if m.Memory > 0 {
res.Memory = m.Memory * 1024 * 1024
res.MemorySwap = -1
}
if m.CpuShares > 0 {
res.CPUShares = m.CpuShares
}
for _, p := range m.Devices {
2022-02-17 10:43:25 +00:00
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
2021-09-26 02:35:02 +00:00
}
_, err = cli.ContainerUpdate(context.Background(), id, container.UpdateConfig{RestartPolicy: rp, Resources: res})
if err != nil {
return err
}
return
}
2022-09-15 07:13:07 +00:00
// 更新容器名称
// param name 容器名称
// param id 老的容器名称
func (ds *dockerService) DockerContainerUpdateName(name, id string) (err error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
}
defer cli.Close()
err = cli.ContainerRename(context.Background(), id, name)
if err != nil {
return err
}
return
}
2022-09-15 07:13:07 +00:00
// 获取网络列表
2021-09-26 02:35:02 +00:00
func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close()
networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
return networks
}
func NewDockerService() DockerService {
return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`)}
2021-09-26 02:35:02 +00:00
}
2022-09-15 07:13:07 +00:00
func (ds *dockerService) GetDockerInfo() (types.Info, error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return types.Info{}, err
}
defer cli.Close()
return cli.Info(context.Background())
}
2021-09-26 02:35:02 +00:00
// ---------------------------------------test------------------------------------
//func ServiceCreate() {
// cli, err := client2.NewClientWithOpts(client2.FromEnv)
// r, err := cli.ServiceCreate(context.Background(), swarm.ServiceSpec{}, types.ServiceCreateOptions{})
// if err != nil {
// fmt.Println("error", err)
// }
//
//
//}
// func Containerd() {
// // create a new client connected to the default socket path for containerd
// cli, err := containerd.New("/run/containerd/containerd.sock")
// if err != nil {
// fmt.Println("111")
// fmt.Println(err)
// }
// defer cli.Close()
// // create a new context with an "example" namespace
// ctx := namespaces.WithNamespace(context.Background(), "default")
// // pull the redis image from DockerHub
// image, err := cli.Pull(ctx, "docker.io/library/busybox:latest", containerd.WithPullUnpack)
// if err != nil {
// fmt.Println("222")
// fmt.Println(err)
// }
// // create a container
// container, err := cli.NewContainer(
// ctx,
// "test1",
// containerd.WithImage(image),
// containerd.WithNewSnapshot("redis-server-snapshot1", image),
// containerd.WithNewSpec(oci.WithImageConfig(image)),
// )
// if err != nil {
// fmt.Println(err)
// }
// defer container.Delete(ctx, containerd.WithSnapshotCleanup)
// // create a task from the container
// task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
// if err != nil {
// fmt.Println(err)
// }
// defer task.Delete(ctx)
// // make sure we wait before calling start
// exitStatusC, err := task.Wait(ctx)
// if err != nil {
// fmt.Println(err)
// }
// // call start on the task to execute the redis server
// if err = task.Start(ctx); err != nil {
// fmt.Println(err)
// }
// fmt.Println("执行完成等待")
// // sleep for a lil bit to see the logs
// time.Sleep(3 * time.Second)
// // kill the process and get the exit status
// if err = task.Kill(ctx, syscall.SIGTERM); err != nil {
// fmt.Println(err)
// }
// // wait for the process to fully exit and print out the exit status
// status := <-exitStatusC
// code, _, err := status.Result()
// if err != nil {
// fmt.Println(err)
// }
// fmt.Printf("redis-server exited with status: %d\n", code)
// }