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
}