I'm setting up Docker containers.
On the server side, files are uploaded to S3.
It succeeded to upload under my local environment.
However, it fails to upload under Docker environment.
article
├ client
├ api
└ docker-compose.yml
Here is the docker-compose.yml:
version: '3'
services:
api:
build:
dockerfile: Dockerfile.dev
context: ./api
volumes:
- ./api:/app
ports:
- 2345:2345
depends_on:
- db
tty: true
volumes:
- $HOME/.aws/credentials.properties:/home/api/.aws/credentials.properties
Here is the server side code to access to S3.
api := router.Group("/api")
{
api.POST("/post/image", func(c *gin.Context) {
var creds *credentials.Credentials
var err error
creds = credentials.NewSharedCredentials("", "default")
_, err = creds.Get()
if err != nil {
creds = credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{})
_, err = creds.Get()
}
cfg := aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds)
svc := s3.New(session.New(), cfg)
form, _ := c.MultipartForm()
files := form.File["images[]"]
var imageNames []ImageName
imageName := ImageName{}
for _, file := range files {
f, err := file.Open()
if err != nil {
log.Println(err)
}
defer f.Close()
size := file.Size
buffer := make([]byte, size)
f.Read(buffer)
fileBytes := bytes.NewReader(buffer)
fileType := http.DetectContentType(buffer)
path := "/media/" + file.Filename
params := &s3.PutObjectInput{
Bucket: aws.String("article-s3-jpskgc"),
Key: aws.String(path),
Body: fileBytes,
ContentLength: aws.Int64(size),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
fmt.Printf("response %s", awsutil.StringValue(resp))
imageName.NAME = file.Filename
imageNames = append(imageNames, imageName)
}
c.JSON(http.StatusOK, imageNames)
})
}
I expect images are uploaded in server side to S3.
But in actuality they're not.
Here are some logs:
api_1 | 2019/07/31 14:58:53 [Recovery] 2019/07/31 - 14:58:53 panic recovered:
api_1 | POST /api/post/image HTTP/1.1
api_1 | Host: localhost:2345
api_1 | Accept: application/json, text/plain, */*
api_1 | Accept-Encoding: gzip, deflate, br
api_1 | Accept-Language: en-US,en;q=0.9
api_1 | Connection: keep-alive
api_1 | Content-Length: 92267
api_1 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryYx6aOI06AYceIHnU
api_1 | Origin: http://localhost:3000
api_1 | Referer: http://localhost:3000/post/finish
api_1 | User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
api_1 |
api_1 |
api_1 | runtime error: invalid memory address or nil pointer dereference
api_1 | /usr/local/go/src/runtime/panic.go:82 (0x4427f0)
api_1 | panicmem: panic(memoryError)
api_1 | /usr/local/go/src/runtime/signal_unix.go:390 (0x44261f)
api_1 | sigpanic: panicmem()
api_1 | /go/src/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go:26 (0xa01a35)
api_1 | (*EC2Metadata).GetMetadata: req := c.NewRequest(op, nil, output)
api_1 | /go/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go:134 (0xa05607)
api_1 | requestCredList: resp, err := client.GetMetadata(iamSecurityCredsPath)
api_1 | /go/src/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go:90 (0xa05159)
api_1 | (*EC2RoleProvider).Retrieve: credsList, err := requestCredList(m.Client)
api_1 | /go/src/github.com/aws/aws-sdk-go/aws/credentials/credentials.go:241 (0x945246)
api_1 | (*Credentials).Get: creds, err := c.provider.Retrieve()
api_1 | /app/main.go:172 (0xb1dde1)
api_1 | main.func5: _, err = creds.Get()
api_1 | /go/src/github.com/gin-gonic/gin/context.go:147 (0x8f97c9)
api_1 | (*Context).Next: c.handlers[c.index](c)
api_1 | /go/src/github.com/gin-gonic/gin/recovery.go:83 (0x90d259)
api_1 | RecoveryWithWriter.func1: c.Next()
api_1 | /go/src/github.com/gin-gonic/gin/context.go:147 (0x8f97c9)
api_1 | (*Context).Next: c.handlers[c.index](c)
api_1 | /go/src/github.com/gin-gonic/gin/logger.go:240 (0x90c300)
api_1 | LoggerWithConfig.func1: c.Next()
api_1 | /go/src/github.com/gin-gonic/gin/context.go:147 (0x8f97c9)
api_1 | (*Context).Next: c.handlers[c.index](c)
api_1 | /go/src/github.com/gin-gonic/gin/gin.go:391 (0x9036c9)
api_1 | (*Engine).handleHTTPRequest: c.Next()
api_1 | /go/src/github.com/gin-gonic/gin/gin.go:352 (0x902dbd)
api_1 | (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
api_1 | /usr/local/go/src/net/http/server.go:2774 (0x6dcc77)
api_1 | serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
api_1 | /usr/local/go/src/net/http/server.go:1878 (0x6d8860)
api_1 | (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
api_1 | /usr/local/go/src/runtime/asm_amd64.s:1337 (0x45a090)
api_1 | goexit: BYTE $0x90 // NOP
api_1 |
api_1 | [GIN] 2019/07/31 - 14:58:53 | 500 | 695.0698ms | 172.18.0.1 | POST /api/post/image
I set environment variable in docker-compose.yml
and set value in console.
environment:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
$ export AWS_ACCESS_KEY_ID=$(aws --profile default configure get aws_access_key_id)
$ export AWS_SECRET_ACCESS_KEY=$(aws --profile default configure get aws_secret_access_key)
creds := credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY"), "")
You can pass your credentials using environment variables like this:
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=yyy
So your docker-compose will look like:
version: '3'
services:
api:
build:
dockerfile: Dockerfile.dev
context: ./api
volumes:
- ./api:/app
environment:
AWS_ACCESS_KEY_ID: YOUR-ACCESS-KEY-ID
AWS_SECRET_ACCESS_KEY: YOUR-SECRET-KEY
ports:
- 2345:2345
depends_on:
- db
tty: true
You shouldn't do this in production and use IAM profiles instead both for the simplicity of not having a ton of keys everywhere, and for security to avoid leaking you keys in logs or anywhere, but it works well for development purpose.
Is you use this method, you can remove the credentials part of your code, more informations here: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
Hope it helps.
I made AWS SDK for Go V2 happy by mounting the host .aws directory to the docker container docker-compose.yml:
volumes:
- $HOME/.aws/credentials:/.aws/credentials:ro
The SDK looks for .aws
directory under $HOME
directory so you may need to find out what HOME
env is in the docker container and then update accordingly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.