package main import ( "io" "log" "os" "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" "golang.org/x/net/context" ) const ( imageName string = "my-gin:latest" //鏡像名稱 containerName string = "mygin-latest" //容器名稱 indexName string = "/" + containerName //容器索引名稱,用於檢查該容器是否存在是使用 cmd string = "./ginDocker2" //運行的cmd命令,用於啟動container中的程序 workDir string = "/go/src/ginDocker2" //container工作目錄 openPort nat.Port = "7070" //container開放端口 hostPort string = "7070" //container映射到宿主機的端口 containerDir string = "/go/src/ginDocker2" //容器掛在目錄 hostDir string = "/home/youngblood/Go/src/ginDocker2" //容器掛在到宿主機的目錄 n int = 5 //每5s檢查一個容器是否在運行 ) func main() { ctx := context.Background() cli, err := client.NewEnvClient() defer cli.Close() if err != nil { panic(err) } checkAndStartContainer(ctx, cli) } //創建容器 func createContainer(ctx context.Context, cli *client.Client) { //創建容器 cont, err := cli.ContainerCreate(ctx, &container.Config{ Image: imageName, //鏡像名稱 Tty: true, //docker run命令中的-t選項 OpenStdin: true, //docker run命令中的-i選項 Cmd: []string{cmd}, //docker 容器中執行的命令 WorkingDir: workDir, //docker容器中的工作目錄 ExposedPorts: nat.PortSet{ openPort: struct{}{}, //docker容器對外開放的端口 }, }, &container.HostConfig{ PortBindings: nat.PortMap{ openPort: []nat.PortBinding{nat.PortBinding{ HostIP: "0.0.0.0", //docker容器映射的宿主機的ip HostPort: hostPort, //docker 容器映射到宿主機的端口 }}, }, Mounts: []mount.Mount{ //docker 容器目錄掛在到宿主機目錄 mount.Mount{ Type: mount.TypeBind, Source: hostDir, Target: containerDir, }, }, }, nil, containerName) if err == nil { log.Printf("success create container:%s\n", cont.ID) } else { log.Println("failed to create container!!!!!!!!!!!!!") } } //啟動容器 func startContainer(ctx context.Context, containerID string, cli *client.Client) error { err := cli.ContainerStart(ctx, containerID, types.ContainerStartOptions{}) if err == nil { log.Printf("success start container:%s\n", containerID) } else { log.Printf("failed to start container:%s!!!!!!!!!!!!!\n", containerID) } return err } //將容器的標准輸出輸出到控制台中 func printConsole(ctx context.Context, cli *client.Client, id string) { //將容器的標准輸出顯示出來 out, err := cli.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true}) if err != nil { panic(err) } io.Copy(os.Stdout, out) //容器內部的運行狀態 status, err := cli.ContainerStats(ctx, id, true) if err != nil { panic(err) } io.Copy(os.Stdout, status.Body) } //檢查容器是否存在並啟動容器 func checkAndStartContainer(ctx context.Context, cli *client.Client) { for { select { case <-isRuning(ctx, cli): //該container沒有在運行 //獲取所有的container查看該container是否存在 contTemp := getContainer(ctx, cli, true) if contTemp.ID == "" { //該容器不存在,創建該容器 log.Printf("the container name[%s] is not exists!!!!!!!!!!!!!\n", containerName) createContainer(ctx, cli) } else { //該容器存在,啟動該容器 log.Printf("the container name[%s] is exists\n", containerName) startContainer(ctx, contTemp.ID, cli) } } } } //獲取container func getContainer(ctx context.Context, cli *client.Client, all bool) types.Container { containerList, err := cli.ContainerList(ctx, types.ContainerListOptions{All: all}) if err != nil { panic(err) } var contTemp types.Container //找出名為“mygin-latest”的container並將其存入contTemp中 for _, v1 := range containerList { for _, v2 := range v1.Names { if v2 == indexName { contTemp = v1 break } } } return contTemp } //容器是否正在運行 func isRuning(ctx context.Context, cli *client.Client) <-chan bool { isRun := make(chan bool) var timer *time.Ticker go func(ctx context.Context, cli *client.Client) { for { //每n s檢查一次容器是否運行 timer = time.NewTicker(time.Duration(n) * time.Second) select { case <-timer.C: //獲取正在運行的container list log.Printf("%s is checking the container[%s]is Runing??", os.Args[0], containerName) contTemp := getContainer(ctx, cli, false) if contTemp.ID == "" { log.Print(":NO") //說明container沒有運行 isRun <- true } else { log.Print(":YES") //說明該container正在運行 go printConsole(ctx, cli, contTemp.ID) } } } }(ctx, cli) return isRun }