「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
Examples using the Docker Engine SDKs and Docker API
ググっても出てこないくらい触らなそうな作業ではありますが、どこかの誰かのためにサンプルコードを置いておきます。
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)
}
}