Created
June 9, 2019 03:51
-
-
Save we4tech/c0aecd6d45332113d2c719ad4e019a74 to your computer and use it in GitHub Desktop.
Use docker client to handle STDIN and STDOUT from a running container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"context" | |
"fmt" | |
"github.com/docker/docker/api/types" | |
"github.com/docker/docker/api/types/container" | |
"github.com/docker/docker/client" | |
"io" | |
"log" | |
"math/rand" | |
"os" | |
"os/signal" | |
"syscall" | |
"time" | |
) | |
var ( | |
ctx = context.Background() | |
dockerCli = buildDockerClient() | |
imageRef = "we4tech/echo:latest" | |
signalsCh = make(chan os.Signal, 1) | |
controlCh = make(chan string) | |
) | |
func buildDockerClient() *client.Client { | |
cli, err := client.NewClientWithOpts(client.WithVersion("1.39")) | |
if err != nil { | |
panic(err) | |
} | |
return cli | |
} | |
func main() { | |
handleSignals() | |
printContainerList() | |
pullImage() | |
containerId := createContainer() | |
defer cleanup(containerId) | |
startContainer(containerId) | |
//captureLogs(containerId) | |
interact(containerId) | |
} | |
func handleSignals() { | |
signal.Notify(signalsCh, syscall.SIGTERM, syscall.SIGINT) | |
go func() { | |
select { | |
case sig := <-signalsCh: | |
log.Println("Received signal:", sig) | |
switch sig { | |
case syscall.SIGTERM: | |
log.Println("Handling graceful stop") | |
controlCh <- "done" | |
case syscall.SIGINT: | |
log.Println("Handling graceful stop for ^C") | |
controlCh <- "done" | |
} | |
} | |
}() | |
} | |
func cleanup(containerId string) { | |
if r := recover(); r != nil { | |
log.Printf("Recovered: %s", r) | |
} | |
defer removeContainer(containerId) | |
defer stopContainer(containerId) | |
} | |
func removeContainer(containerId string) { | |
log.Println("Removing container...") | |
if err := dockerCli.ContainerRemove(ctx, containerId, types.ContainerRemoveOptions{Force: true}); err != nil { | |
panic(err) | |
} | |
} | |
func stopContainer(containerId string) { | |
log.Println("Stopping container...") | |
duration := time.Duration(1000) | |
if err := dockerCli.ContainerStop(ctx, containerId, &duration); err != nil { | |
panic(err) | |
} | |
} | |
func interact(containerId string) { | |
log.Println("Start interacting") | |
resp, err := dockerCli.ContainerAttach(ctx, containerId, types.ContainerAttachOptions{ | |
Stdin: true, | |
Stdout: true, | |
Stderr: false, | |
Stream: true, | |
}) | |
if err != nil { | |
panic(err) | |
} | |
defer resp.Close() | |
go func() { | |
scanner := bufio.NewScanner(resp.Reader) | |
for scanner.Scan() { | |
fmt.Println("> ", scanner.Text()) | |
} | |
}() | |
go func() { | |
for i := 1; true; i++ { | |
if _, err := resp.Conn.Write([]byte(fmt.Sprintf("Count - %d\n", i))); err != nil { | |
if i == 1 { | |
panic(err) | |
} else { | |
break | |
} | |
} | |
time.Sleep(1000 * time.Millisecond) | |
} | |
}() | |
for msg := range controlCh { | |
if msg == "done" { | |
log.Println("Exiting...") | |
break | |
} | |
} | |
} | |
func createContainer() string { | |
log.Println("Creating container") | |
imageName := fmt.Sprintf("echo.test.%d", rand.Int()) | |
newContainer, err := dockerCli.ContainerCreate(ctx, &container.Config{ | |
Image: imageRef, | |
Tty: true, | |
AttachStdout: true, | |
AttachStdin: true, | |
OpenStdin: true, | |
}, nil, nil, imageName) | |
if err != nil { | |
panic(err) | |
} | |
log.Printf("Created container ID: %s", newContainer.ID) | |
return newContainer.ID | |
} | |
func pullImage() { | |
log.Println("Pull container image") | |
out, err := dockerCli.ImagePull(ctx, imageRef, types.ImagePullOptions{}) | |
if err != nil { | |
panic(err) | |
} | |
_, err = io.Copy(os.Stdout, out) | |
if err != nil { | |
panic(err) | |
} | |
} | |
func startContainer(containerId string) { | |
log.Println("Start container") | |
if err := dockerCli.ContainerStart( | |
context.Background(), | |
containerId, | |
types.ContainerStartOptions{}); err != nil { | |
panic(err) | |
} | |
log.Println("Waiting for the right state") | |
go func() { | |
statusCh, errCh := dockerCli.ContainerWait( | |
context.Background(), | |
containerId, | |
container.WaitConditionNotRunning) | |
log.Println("Verify the status") | |
select { | |
case err := <-errCh: | |
if err != nil { | |
panic(err) | |
} | |
case status := <-statusCh: | |
log.Printf("Status - %v", status) | |
} | |
}() | |
} | |
func printContainerList() { | |
log.Println("Print containers list") | |
containers, err := dockerCli.ContainerList(context.Background(), types.ContainerListOptions{}) | |
if err != nil { | |
panic(err) | |
} | |
for _, cont := range containers { | |
log.Printf("Container: %s Image: %s", cont.ID, cont.Image) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment