Skip to content

Instantly share code, notes, and snippets.

@we4tech
Created June 9, 2019 03:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save we4tech/c0aecd6d45332113d2c719ad4e019a74 to your computer and use it in GitHub Desktop.
Save we4tech/c0aecd6d45332113d2c719ad4e019a74 to your computer and use it in GitHub Desktop.
Use docker client to handle STDIN and STDOUT from a running container
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