我的最后一招是在这里问。我是Golang的新手,我已经编写了简单的程序。
我正在尝试执行以下操作: 使用golang: 1-运行一个容器 2-接受输入标准输入到容器
我要使用的示例是hashicorp / terraform docker映像,我想做一个简单的terraform apply
,但是我需要等待用户输入
下面是我到目前为止正在使用的代码...尝试以下确切代码的任何人都需要更新AWS环境变量或将terraform测试文件更改为另一个提供程序...或仅使用其他docker镜像;-)
package main
import (
"fmt"
"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/docker/pkg/stdcopy"
"golang.org/x/net/context"
"io"
"os"
)
const workingDir = "/home"
func main() {
ctx := context.Background()
cli,err := client.NewClientWithOpts(client.FromEnv,client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
reader,err := cli.ImagePull(ctx,"hashicorp/terraform",types.ImagePullOptions{})
if err != nil {
panic(err)
}
io.Copy(os.Stdout,reader)
fmt.Println(os.Args)
cwd,_ := os.Getwd()
resp,err := cli.ContainerCreate(ctx,&container.Config{
AttachStdin: true,Tty: false,StdinOnce: true,AttachStdout:true,Cmd: os.Args[1:],Image: "hashicorp/terraform",WorkingDir: workingDir,Env: []string{"AWS_accESS_KEY_ID=XXX","AWS_SECRET_accESS_KEY=XXX","AWS_SESSION_TOKEN=XXX"},},&container.HostConfig{
Mounts: []mount.Mount{
mount.Mount{
Type: mount.TypeBind,Source: cwd,Target: workingDir,nil,"")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx,resp.ID,types.ContainerStartOptions{}); err != nil {
panic(err)
}
statusCh,errCh := cli.ContainerWait(ctx,container.WaitConditionNotRunning)
select {
case err := <-errCh:
if err != nil {
panic(err)
}
case <-statusCh:
}
out,err := cli.ContainerLogs(ctx,types.ContainerLogsOptions{ShowStdout: true})
if err != nil {
panic(err)
}
stdcopy.StdCopy(os.Stdout,os.Stderr,out)
}
我的示例Terraform文件test.tf
provider "aws" {
region = "eu-west-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "dedicated"
tags = {
Name = "test-main-vpc"
}
}
因此,如果我构建该go文件并运行
./build apply
和test.tf在同一目录中
我得到以下输出:
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ arn = (known after apply)
+ assign_generated_ipv6_cidr_block = false
+ cidr_block = "10.0.0.0/16"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_classiclink = (known after apply)
+ enable_classiclink_dns_support = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = true
+ id = (known after apply)
+ instance_tenancy = "dedicated"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "test-main-vpc"
}
}
Plan: 1 to add,0 to change,0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
Apply cancelled.
Process finished with exit code 0
我一直想弄清楚的是如何等待用户输入。
运行容器并退出后,日志正在打印,我认为..所以我认为我需要混合使用以下这些容器:
https://godoc.org/github.com/docker/docker/container/stream
https://godoc.org/github.com/docker/docker/client#Client.ContainerAttach
我只是不知道如何实现这些,因此没有示例。
任何想法都会有所帮助。我不想要完整的答案,我只想了解如何使用容器/流和/或Client.ContainerAttach等待用户输入的一般指导
非常感谢!
编辑:
我设法使其正常运行。下面是工作代码
package main
import (
"bufio"
"fmt"
"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"
"golang.org/x/net/context"
"io"
"os"
)
const workingDir = "/home"
var inout chan []byte
func main() {
inout = make(chan []byte)
ctx := context.Background()
cli,types.ImagePullOptions{})
if err != nil {
panic(err)
}
go io.Copy(os.Stdout,reader)
//fmt.Println(os.Args)
cwd,&container.Config{
AttachStderr:true,AttachStdin: true,Tty: true,OpenStdin: true,Env: []string{"AWS_accESS_KEY_ID=","AWS_SECRET_accESS_KEY=","AWS_SESSION_TOKEN=","")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx,types.ContainerStartOptions{}); err != nil {
panic(err)
}
waiter,err := cli.ContainerAttach(ctx,types.ContainerAttachOptions{
Stderr: true,Stdout: true,Stdin: true,Stream: true,})
go io.Copy(os.Stdout,waiter.Reader)
go io.Copy(os.Stderr,waiter.Reader)
if err != nil {
panic(err)
}
go func() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
inout <- []byte(scanner.Text())
}
}()
// Write to docker container
go func(w io.Writecloser) {
for {
data,ok := <-inout
//log.Println("Received to send to docker",string(data))
if !ok {
fmt.Println("!ok")
w.Close()
return
}
w.Write(append(data,'\n'))
}
}(waiter.Conn)
statusCh,container.WaitConditionNotRunning)
select {
case err := <-errCh:
if err != nil {
panic(err)
}
case <-statusCh:
}
}