Docker (Engine) SDK  & Go言語 を使ってAWS ECRのimageをpull  & run する 

「AWS ECRにログインして docker imageを pullし、docker runする」

このような作業はあまりプロダクションで手動でやることはありませんが、やるとすれば普通に ``` aws-cli ```を使ってECRにLogin, 後は ``` docker ```コマンドでの作業となるかと思います。


ところで、Go製であるDockerには公式SDKがあります。
今回とある事情があり、 ``` github.com/aws/aws-sdk-go ``` と ```github.com/docker/docker ``` を使って**上記の作業をGoのコードのみでやる**機会がありました。


[Develop with Docker Engine SDKs](https://docs.docker.com/engine/api/sdk/)
[Examples using the Docker Engine SDKs and Docker API](https://docs.docker.com/engine/api/sdk/examples/)


ググっても出てこないくらい触らなそうな作業ではありますが、どこかの誰かのためにサンプルコードを置いておきます。


```golang

package main

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecr"
	"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/labstack/gommon/log"
	"io"
	"os"
	"strings"
	"time"
)

func main() {

	auth := getEcrRegistryAuth()
	pullAndRunContainer(auth)

}

func getEcrRegistryAuth() string {

	/*  ECR Login  */
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))

	ecrSdk := ecr.New(sess)
	authOutput, err := ecrSdk.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
	if err != nil {
		log.Panic(err)
	}

	token := authOutput.AuthorizationData[0].AuthorizationToken

	authStr := aws.StringValue(token)
	decoded, err := base64.StdEncoding.DecodeString(authStr) // Decode the Base64 encoded token
	if err != nil {
		log.Panic(err)
	}
	password := strings.ReplaceAll(string(decoded), "AWS:", "")

	jsonBytes, _ := json.Marshal(map[string]string{
		"username": "AWS",
		"password": password,
	})

	return base64.StdEncoding.EncodeToString(jsonBytes)

}

func pullAndRunContainer(auth string) {

	imageUri := `xxxxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr:latest`
	containerName := fmt.Sprintf(`test-container-%v`, time.Now().UnixNano())

	ctx := context.Background()

	cli, err := client.NewEnvClient()
	if err != nil {
		log.Fatal(err)
	}

	reader, err := cli.ImagePull(ctx, imageUri, types.ImagePullOptions{
		RegistryAuth: auth,
	})
	if err != nil {
		log.Panic(err)
	}
	io.Copy(os.Stdout, reader)

	cont, err := cli.ContainerCreate(
		ctx,
		&container.Config{
			Image: imageUri,
			Cmd: []string{
				`sh`,
				`-c`,
				`echo "Run App !!!!!"`,
			},
			Env: []string{
				"PASS=xxxxxxxxxxxxxx", // いいのか?
			},
			//Cmd:   command,
		}, &container.HostConfig{
			Mounts: []mount.Mount{
				{
					Type:   mount.TypeBind,
					Source: "<HostのMount Dir>",
					Target: "/mnt", // gyao_yvpub_wrapper内のmount dir
				},
			},
		}, nil, containerName)
	if err := cli.ContainerStart(ctx, cont.ID, types.ContainerStartOptions{}); err != nil {
		log.Panic(err)
	}

	go func() {
		out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
		if logErr != nil {
			log.Error(logErr)
		}
		containerLog := streamToString(out)
		fmt.Println(containerLog)
	}()

	exitCode, err := cli.ContainerWait(ctx, cont.ID)
	if err != nil {
		log.Fatal(err)
	}

	if exitCode != 0 {
		log.Error(err)

		out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
		if logErr != nil {
			log.Error(err)
		}

		containerLog := streamToString(out)
		fmt.Println(containerLog)
	}

}


```