mirror of https://github.com/docker/docs.git
[awslogs] Auto-detect region on EC2 instances
Signed-off-by: Samuel Karp <skarp@amazon.com>
This commit is contained in:
parent
480c9c0178
commit
8a6dfb26f3
|
@ -2,6 +2,7 @@
|
||||||
package awslogs
|
package awslogs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -14,6 +15,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
|
@ -58,6 +60,10 @@ type api interface {
|
||||||
PutLogEvents(*cloudwatchlogs.PutLogEventsInput) (*cloudwatchlogs.PutLogEventsOutput, error)
|
PutLogEvents(*cloudwatchlogs.PutLogEventsInput) (*cloudwatchlogs.PutLogEventsOutput, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type regionFinder interface {
|
||||||
|
Region() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
type byTimestamp []*cloudwatchlogs.InputLogEvent
|
type byTimestamp []*cloudwatchlogs.InputLogEvent
|
||||||
|
|
||||||
// init registers the awslogs driver and sets the default region, if provided
|
// init registers the awslogs driver and sets the default region, if provided
|
||||||
|
@ -85,13 +91,17 @@ func New(ctx logger.Context) (logger.Logger, error) {
|
||||||
if ctx.Config[logStreamKey] != "" {
|
if ctx.Config[logStreamKey] != "" {
|
||||||
logStreamName = ctx.Config[logStreamKey]
|
logStreamName = ctx.Config[logStreamKey]
|
||||||
}
|
}
|
||||||
|
client, err := newAWSLogsClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
containerStream := &logStream{
|
containerStream := &logStream{
|
||||||
logStreamName: logStreamName,
|
logStreamName: logStreamName,
|
||||||
logGroupName: logGroupName,
|
logGroupName: logGroupName,
|
||||||
client: newAWSLogsClient(ctx),
|
client: client,
|
||||||
messages: make(chan *logger.Message, 4096),
|
messages: make(chan *logger.Message, 4096),
|
||||||
}
|
}
|
||||||
err := containerStream.create()
|
err = containerStream.create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -100,13 +110,38 @@ func New(ctx logger.Context) (logger.Logger, error) {
|
||||||
return containerStream, nil
|
return containerStream, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAWSLogsClient(ctx logger.Context) api {
|
// newRegionFinder is a variable such that the implementation
|
||||||
|
// can be swapped out for unit tests.
|
||||||
|
var newRegionFinder = func() regionFinder {
|
||||||
|
return ec2metadata.New(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newAWSLogsClient creates the service client for Amazon CloudWatch Logs.
|
||||||
|
// Customizations to the default client from the SDK include a Docker-specific
|
||||||
|
// User-Agent string and automatic region detection using the EC2 Instance
|
||||||
|
// Metadata Service when region is otherwise unspecified.
|
||||||
|
func newAWSLogsClient(ctx logger.Context) (api, error) {
|
||||||
config := defaults.DefaultConfig
|
config := defaults.DefaultConfig
|
||||||
if ctx.Config[regionKey] != "" {
|
if ctx.Config[regionKey] != "" {
|
||||||
config = defaults.DefaultConfig.Merge(&aws.Config{
|
config = defaults.DefaultConfig.Merge(&aws.Config{
|
||||||
Region: aws.String(ctx.Config[regionKey]),
|
Region: aws.String(ctx.Config[regionKey]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if config.Region == nil || *config.Region == "" {
|
||||||
|
logrus.Info("Trying to get region from EC2 Metadata")
|
||||||
|
ec2MetadataClient := newRegionFinder()
|
||||||
|
region, err := ec2MetadataClient.Region()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Could not get region from EC2 metadata, environment, or log option")
|
||||||
|
return nil, errors.New("Cannot determine region for awslogs driver")
|
||||||
|
}
|
||||||
|
config.Region = ®ion
|
||||||
|
}
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"region": *config.Region,
|
||||||
|
}).Debug("Created awslogs client")
|
||||||
client := cloudwatchlogs.New(config)
|
client := cloudwatchlogs.New(config)
|
||||||
|
|
||||||
client.Handlers.Build.PushBackNamed(request.NamedHandler{
|
client.Handlers.Build.PushBackNamed(request.NamedHandler{
|
||||||
|
@ -118,7 +153,7 @@ func newAWSLogsClient(ctx logger.Context) api {
|
||||||
version.VERSION, runtime.GOOS, currentAgent))
|
version.VERSION, runtime.GOOS, currentAgent))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return client
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the awslogs logging driver
|
// Name returns the name of the awslogs logging driver
|
||||||
|
@ -312,12 +347,6 @@ func ValidateLogOpt(cfg map[string]string) error {
|
||||||
if cfg[logGroupKey] == "" {
|
if cfg[logGroupKey] == "" {
|
||||||
return fmt.Errorf("must specify a value for log opt '%s'", logGroupKey)
|
return fmt.Errorf("must specify a value for log opt '%s'", logGroupKey)
|
||||||
}
|
}
|
||||||
if cfg[regionKey] == "" && os.Getenv(regionEnvKey) == "" {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"must specify a value for environment variable '%s' or log opt '%s'",
|
|
||||||
regionEnvKey,
|
|
||||||
regionKey)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,10 @@ func TestNewAWSLogsClientUserAgentHandler(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
client := newAWSLogsClient(ctx)
|
client, err := newAWSLogsClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
realClient, ok := client.(*cloudwatchlogs.CloudWatchLogs)
|
realClient, ok := client.(*cloudwatchlogs.CloudWatchLogs)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("Could not cast client to cloudwatchlogs.CloudWatchLogs")
|
t.Fatal("Could not cast client to cloudwatchlogs.CloudWatchLogs")
|
||||||
|
@ -53,6 +56,25 @@ func TestNewAWSLogsClientUserAgentHandler(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewAWSLogsClientRegionDetect(t *testing.T) {
|
||||||
|
ctx := logger.Context{
|
||||||
|
Config: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockMetadata := newMockMetadataClient()
|
||||||
|
newRegionFinder = func() regionFinder {
|
||||||
|
return mockMetadata
|
||||||
|
}
|
||||||
|
mockMetadata.regionResult <- ®ionResult{
|
||||||
|
successResult: "us-east-1",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := newAWSLogsClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateSuccess(t *testing.T) {
|
func TestCreateSuccess(t *testing.T) {
|
||||||
mockClient := newMockClient()
|
mockClient := newMockClient()
|
||||||
stream := &logStream{
|
stream := &logStream{
|
||||||
|
|
|
@ -49,6 +49,26 @@ func (m *mockcwlogsclient) PutLogEvents(input *cloudwatchlogs.PutLogEventsInput)
|
||||||
return output.successResult, output.errorResult
|
return output.successResult, output.errorResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockmetadataclient struct {
|
||||||
|
regionResult chan *regionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type regionResult struct {
|
||||||
|
successResult string
|
||||||
|
errorResult error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockMetadataClient() *mockmetadataclient {
|
||||||
|
return &mockmetadataclient{
|
||||||
|
regionResult: make(chan *regionResult, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockmetadataclient) Region() (string, error) {
|
||||||
|
output := <-m.regionResult
|
||||||
|
return output.successResult, output.errorResult
|
||||||
|
}
|
||||||
|
|
||||||
func test() {
|
func test() {
|
||||||
_ = &logStream{
|
_ = &logStream{
|
||||||
client: newMockClient(),
|
client: newMockClient(),
|
||||||
|
|
|
@ -34,9 +34,10 @@ You can use the `--log-opt NAME=VALUE` flag to specify Amazon CloudWatch Logs lo
|
||||||
|
|
||||||
### awslogs-region
|
### awslogs-region
|
||||||
|
|
||||||
You must specify a region for the `awslogs` logging driver. You can specify the
|
The `awslogs` logging driver sends your Docker logs to a specific region. Use
|
||||||
region with either the `awslogs-region` log option or `AWS_REGION` environment
|
the `awslogs-region` log option or the `AWS_REGION` environment variable to set
|
||||||
variable:
|
the region. By default, if your Docker daemon is running on an EC2 instance
|
||||||
|
and no region is set, the driver uses the instance's region.
|
||||||
|
|
||||||
docker run --log-driver=awslogs --log-opt awslogs-region=us-east-1 ...
|
docker run --log-driver=awslogs --log-opt awslogs-region=us-east-1 ...
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue