You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-08-08 22:36:41 +02:00
updated devops which removed use of placeholders in taskdef
This commit is contained in:
@ -5,7 +5,8 @@ services:
|
||||
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
GIT_DEPTH: "1"
|
||||
GIT_DEPTH: "10"
|
||||
|
||||
stages:
|
||||
- setup:dev
|
||||
- build:dev
|
||||
@ -90,6 +91,8 @@ webapp:build:prod:
|
||||
- master
|
||||
- prod
|
||||
- prod-web-app
|
||||
dependencies:
|
||||
- 'infra:setup:prod'
|
||||
variables:
|
||||
TARGET_ENV: 'prod'
|
||||
TARGET_TYPE: 'service'
|
||||
@ -124,6 +127,8 @@ webapi:build:prod:
|
||||
- master
|
||||
- prod
|
||||
- prod-web-api
|
||||
dependencies:
|
||||
- 'infra:setup:prod'
|
||||
variables:
|
||||
TARGET_ENV: 'prod'
|
||||
TARGET_TYPE: 'service'
|
||||
@ -158,6 +163,8 @@ ddlogscollector:build:prod:
|
||||
- master
|
||||
- prod
|
||||
- prod-ddlogs
|
||||
dependencies:
|
||||
- 'infra:setup:prod'
|
||||
variables:
|
||||
TARGET_ENV: 'prod'
|
||||
TARGET_TYPE: 'function'
|
||||
|
@ -358,6 +358,21 @@ Access/Secret Keys are required
|
||||
--no-push disable pushing release image to remote repository
|
||||
```
|
||||
|
||||
* `build image` - Executes a build for a single image
|
||||
|
||||
```bash
|
||||
$ cicd -env [dev|stage|prod] build image -name NNNNN [command options]
|
||||
```
|
||||
|
||||
Options:
|
||||
```bash
|
||||
--name value, -n value target image, required
|
||||
--release-tag value, --tag value optional tag to override default CI_COMMIT_SHORT_SHA
|
||||
--dry-run print out the build details
|
||||
--no-cache skip caching for the docker build
|
||||
--no-push disable pushing release image to remote repository
|
||||
```
|
||||
|
||||
* `deploy infrastructure` - Executes a deploy to setup the infrastructure for the deployment environment.
|
||||
|
||||
```bash
|
||||
|
@ -538,7 +538,7 @@ func getDatadogApiKey(cfg *devdeploy.Config) (string, error) {
|
||||
|
||||
// 3. Check AWS Secrets Manager for Datadog entry.
|
||||
if apiKey == "" {
|
||||
secretId := "DATADOG"
|
||||
secretId := "datadog"
|
||||
var err error
|
||||
apiKey, err = devdeploy.GetAwsSecretValue(cfg.AwsCredentials, secretId)
|
||||
if err != nil {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
type Function = string
|
||||
|
||||
var (
|
||||
Function_Ddlogscollector = "ddlogscollector"
|
||||
Function_Ddlogscollector Function = "ddlogscollector"
|
||||
)
|
||||
|
||||
// List of function names used by main.go for help.
|
||||
|
103
build/cicd/internal/config/image.go
Normal file
103
build/cicd/internal/config/image.go
Normal file
@ -0,0 +1,103 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/geeks-accelerator/oss/devops/pkg/devdeploy"
|
||||
)
|
||||
|
||||
// Image define the name of an image.
|
||||
type Image = string
|
||||
|
||||
var (
|
||||
ImageYourBaseImage Image = "your-base-image"
|
||||
)
|
||||
|
||||
// List of images names used by main.go for help and append the functions to config.
|
||||
var ImageNames = []Image{
|
||||
ImageYourBaseImage,
|
||||
}
|
||||
|
||||
// NewImage returns the *devdeploy.ProjectImage.
|
||||
func NewImage(imageName string, cfg *devdeploy.Config) (*devdeploy.ProjectImage, error) {
|
||||
|
||||
ctx := &devdeploy.ProjectImage{
|
||||
Name: fmt.Sprintf("%s-%s-%s", cfg.Env, cfg.ProjectName, imageName),
|
||||
CodeDir: filepath.Join(cfg.ProjectRoot, "build/docker", imageName),
|
||||
DockerBuildDir: cfg.ProjectRoot,
|
||||
DockerBuildContext: ".",
|
||||
|
||||
// Set the release tag for the image to use include env + function name + commit hash/tag.
|
||||
ReleaseTag: devdeploy.GitLabCiReleaseTag(cfg.Env, imageName),
|
||||
}
|
||||
|
||||
switch imageName {
|
||||
case ImageYourBaseImage:
|
||||
// No specific settings.
|
||||
|
||||
default:
|
||||
return nil, errors.Wrapf(devdeploy.ErrInvalidFunction,
|
||||
"No context defined for image '%s'",
|
||||
imageName)
|
||||
}
|
||||
|
||||
// Set the docker file if no custom one has been defined for the service.
|
||||
if ctx.Dockerfile == "" {
|
||||
ctx.Dockerfile = filepath.Join(ctx.CodeDir, "Dockerfile")
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// BuildImageForTargetEnv executes the build commands for a target image.
|
||||
func BuildImageForTargetEnv(log *log.Logger, awsCredentials devdeploy.AwsCredentials, targetEnv Env, imageName, releaseTag string, dryRun, noCache, noPush bool) error {
|
||||
|
||||
cfg, err := NewConfig(log, targetEnv, awsCredentials)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetImage, err := NewImage(imageName, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override the release tag if set.
|
||||
if releaseTag != "" {
|
||||
targetImage.ReleaseTag = releaseTag
|
||||
}
|
||||
|
||||
// Append build args to be used for all functions.
|
||||
if targetImage.DockerBuildArgs == nil {
|
||||
targetImage.DockerBuildArgs = make(map[string]string)
|
||||
}
|
||||
|
||||
// funcPath is used to copy the service specific code in the Dockerfile.
|
||||
codePath, err := filepath.Rel(cfg.ProjectRoot, targetImage.CodeDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
targetImage.DockerBuildArgs["code_path"] = codePath
|
||||
|
||||
if dryRun {
|
||||
cfgJSON, err := json.MarshalIndent(cfg, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("BuildFunctionForTargetEnv : Marshalling config to JSON : %+v", err)
|
||||
}
|
||||
log.Printf("BuildFunctionForTargetEnv : config : %v\n", string(cfgJSON))
|
||||
|
||||
detailsJSON, err := json.MarshalIndent(targetImage, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("BuildFunctionForTargetEnv : Marshalling details to JSON : %+v", err)
|
||||
}
|
||||
log.Printf("BuildFunctionForTargetEnv : details : %v\n", string(detailsJSON))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return devdeploy.BuildImageForTargetEnv(log, cfg, targetImage, noCache, noPush)
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@ -41,8 +42,8 @@ const (
|
||||
type Service = string
|
||||
|
||||
var (
|
||||
ServiceWebApi = "web-api"
|
||||
ServiceWebApp = "web-app"
|
||||
ServiceWebApi Service = "web-api"
|
||||
ServiceWebApp Service = "web-app"
|
||||
)
|
||||
|
||||
// List of service names used by main.go for help.
|
||||
@ -185,7 +186,6 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
srv.StaticFilesS3Prefix = filepath.Join(cfg.AwsS3BucketPublicKeyPrefix, ctx.ReleaseTag, "static")
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Service settings based on target env.
|
||||
var enableElb bool
|
||||
@ -293,7 +293,7 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
srv.AwsElbLoadBalancer.TargetGroups[0].Name)
|
||||
|
||||
// Set ECS configs based on specified env.
|
||||
if cfg.Env == "prod" {
|
||||
if cfg.Env == EnvProd {
|
||||
srv.AwsElbLoadBalancer.EcsTaskDeregistrationDelay = 300
|
||||
} else {
|
||||
// Force staging to deploy immediately without waiting for connections to drain
|
||||
@ -311,12 +311,12 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
}
|
||||
|
||||
// Set ECS configs based on specified env.
|
||||
if cfg.Env == "prod" {
|
||||
if cfg.Env == EnvProd {
|
||||
srv.AwsEcsService.DeploymentMinimumHealthyPercent = 100
|
||||
srv.AwsEcsService.DeploymentMaximumPercent = 200
|
||||
} else {
|
||||
srv.AwsEcsService.DeploymentMinimumHealthyPercent = 100
|
||||
srv.AwsEcsService.DeploymentMaximumPercent = 200
|
||||
srv.AwsEcsService.DeploymentMinimumHealthyPercent = 0
|
||||
srv.AwsEcsService.DeploymentMaximumPercent = 100
|
||||
}
|
||||
|
||||
if EnableServiceAutoscaling {
|
||||
@ -415,6 +415,55 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Try to find the Datadog API key, this value is optional.
|
||||
// If Datadog API key is not specified, then integration with Datadog for observability will not be active.
|
||||
datadogApiKey, err := getDatadogApiKey(cfg)
|
||||
if err != nil {
|
||||
return srv, err
|
||||
}
|
||||
|
||||
// Add the Datadog container to the task definition if an API Key is set.
|
||||
var ddContainer *ecs.ContainerDefinition
|
||||
if datadogApiKey != "" {
|
||||
ddTags := []string{
|
||||
"source:docker",
|
||||
"service:" + srv.AwsEcsService.ServiceName,
|
||||
"service_name:" + ctx.Name,
|
||||
"cluster:" + srv.AwsEcsCluster.ClusterName,
|
||||
"env:" + cfg.Env,
|
||||
}
|
||||
|
||||
// Defined a container definition for the specific service.
|
||||
ddContainer = &ecs.ContainerDefinition{
|
||||
Name: aws.String("datadog-agent"),
|
||||
Image: aws.String(srv.ReleaseImage),
|
||||
Essential: aws.Bool(true),
|
||||
PortMappings: []*ecs.PortMapping{
|
||||
&ecs.PortMapping{
|
||||
ContainerPort: aws.Int64(8125),
|
||||
},
|
||||
&ecs.PortMapping{
|
||||
ContainerPort: aws.Int64(8126),
|
||||
},
|
||||
},
|
||||
Cpu: aws.Int64(128),
|
||||
MemoryReservation: aws.Int64(256),
|
||||
Environment: []*ecs.KeyValuePair{
|
||||
ecsKeyValuePair("DD_API_KEY", datadogApiKey),
|
||||
ecsKeyValuePair("DD_LOGS_ENABLED", "true"),
|
||||
ecsKeyValuePair("DD_APM_ENABLED", "true"),
|
||||
ecsKeyValuePair("DD_RECEIVER_PORT", "8126"),
|
||||
ecsKeyValuePair("DD_APM_NON_LOCAL_TRAFFIC", "true"),
|
||||
ecsKeyValuePair("DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL", "true"),
|
||||
ecsKeyValuePair("DD_TAGS", strings.Join(ddTags, " ")),
|
||||
ecsKeyValuePair("DD_DOGSTATSD_ORIGIN_DETECTION", "true"),
|
||||
ecsKeyValuePair("DD_DOGSTATSD_NON_LOCAL_TRAFFIC", "true"),
|
||||
ecsKeyValuePair("ECS_FARGATE", "true"),
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Define a base set of environment variables that can be assigned to individual container definitions.
|
||||
baseEnvVals := func() []*ecs.KeyValuePair {
|
||||
|
||||
@ -428,7 +477,7 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
ciPipelineURL = strings.TrimRight(GitLabProjectBaseUrl, "/") + "/pipelines/" + os.Getenv("CI_PIPELINE_ID")
|
||||
}
|
||||
|
||||
return []*ecs.KeyValuePair{
|
||||
envVars := []*ecs.KeyValuePair{
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ECS_CLUSTER, srv.AwsEcsCluster.ClusterName),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ECS_SERVICE, srv.AwsEcsService.ServiceName),
|
||||
ecsKeyValuePair("AWS_DEFAULT_REGION", cfg.AwsCredentials.Region),
|
||||
@ -447,6 +496,16 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
ecsKeyValuePair("WEB_API_BASE_URL", webApiCtx.BaseUrl()),
|
||||
ecsKeyValuePair("EMAIL_SENDER", "lee+saas-starter-kit@geeksinthewoods.com"),
|
||||
}
|
||||
|
||||
if datadogApiKey != "" {
|
||||
envVars = append(envVars, ecsKeyValuePair("DATADOG_ADDR", "127.0.0.1:8125"),
|
||||
ecsKeyValuePair("DD_API_KEY", datadogApiKey),
|
||||
ecsKeyValuePair("DD_TRACE_AGENT_PORT", "8126"),
|
||||
ecsKeyValuePair("DD_SERVICE_NAME", srv.AwsEcsService.ServiceName),
|
||||
ecsKeyValuePair("DD_ENV", cfg.Env))
|
||||
}
|
||||
|
||||
return envVars
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
@ -508,33 +567,6 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
})
|
||||
}
|
||||
|
||||
// Append env vars for the service task.
|
||||
container1.Environment = append(container1.Environment,
|
||||
ecsKeyValuePair("SERVICE_NAME", ctx.Name),
|
||||
ecsKeyValuePair("PROJECT_NAME", cfg.ProjectName),
|
||||
|
||||
// Use placeholders for these environment variables that will be replaced with devdeploy.DeployServiceToTargetEnv
|
||||
ecsKeyValuePair("WEB_APP_HTTP_HOST", "{HTTP_HOST}"),
|
||||
ecsKeyValuePair("WEB_APP_HTTPS_HOST", "{HTTPS_HOST}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_ENABLE_HTTPS", "{HTTPS_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_BASE_URL", "{APP_BASE_URL}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_HOST_NAMES", "{HOST_NAMES}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_S3_ENABLED", "{STATIC_FILES_S3_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_S3_PREFIX", "{STATIC_FILES_S3_PREFIX}"),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_CLOUDFRONT_ENABLED", "{STATIC_FILES_CLOUDFRONT_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_APP_REDIS_HOST", "{CACHE_HOST}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_HOST", "{DB_HOST}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_USERNAME", "{DB_USER}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_PASSWORD", "{DB_PASS}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_DATABASE", "{DB_DATABASE}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_DRIVER", "{DB_DRIVER}"),
|
||||
ecsKeyValuePair("WEB_APP_DB_DISABLE_TLS", "{DB_DISABLE_TLS}"),
|
||||
ecsKeyValuePair("WEB_APP_AWS_S3_BUCKET_PRIVATE", "{AWS_S3_BUCKET_PRIVATE}"),
|
||||
ecsKeyValuePair("WEB_APP_AWS_S3_BUCKET_PUBLIC", "{AWS_S3_BUCKET_PUBLIC}"),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_UPDATE_TASK_IPS, "{ROUTE53_UPDATE_TASK_IPS}"),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_ZONES, "{ROUTE53_ZONES}"),
|
||||
)
|
||||
|
||||
// Define the full task definition for the service.
|
||||
taskDef := &ecs.RegisterTaskDefinitionInput{
|
||||
Family: aws.String(fmt.Sprintf("%s-%s-%s", cfg.Env, srv.AwsEcsCluster.ClusterName, ctx.Name)),
|
||||
@ -547,32 +579,44 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
RequiresCompatibilities: aws.StringSlice([]string{"FARGATE"}),
|
||||
}
|
||||
|
||||
// Append the datadog container if defined.
|
||||
if ddContainer != nil {
|
||||
taskDef.ContainerDefinitions = append(taskDef.ContainerDefinitions, ddContainer)
|
||||
}
|
||||
|
||||
srv.AwsEcsTaskDefinition = &devdeploy.AwsEcsTaskDefinition{
|
||||
RegisterInput: taskDef,
|
||||
UpdatePlaceholders: func(placeholders map[string]string) error {
|
||||
PreRegister: func(input *ecs.RegisterTaskDefinitionInput, vars devdeploy.AwsEcsServiceDeployVariables) error {
|
||||
// Append env vars for the service task.
|
||||
input.ContainerDefinitions[0].Environment = append(input.ContainerDefinitions[0].Environment,
|
||||
ecsKeyValuePair("SERVICE_NAME", ctx.Name),
|
||||
ecsKeyValuePair("PROJECT_NAME", cfg.ProjectName),
|
||||
|
||||
// Try to find the Datadog API key, this value is optional.
|
||||
// If Datadog API key is not specified, then integration with Datadog for observability will not be active.
|
||||
{
|
||||
datadogApiKey, err := getDatadogApiKey(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Use placeholders for these environment variables that will be replaced with devdeploy.DeployServiceToTargetEnv
|
||||
ecsKeyValuePair("WEB_APP_HTTP_HOST", vars.HTTPHost),
|
||||
ecsKeyValuePair("WEB_APP_HTTPS_HOST", vars.HTTPSHost),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_ENABLE_HTTPS", strconv.FormatBool(vars.HTTPSEnabled)),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_BASE_URL", vars.ServiceBaseUrl),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_HOST_NAMES", strings.Join(vars.AlternativeHostnames, ",")),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_S3_ENABLED", strconv.FormatBool(vars.StaticFilesS3Enabled)),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_S3_PREFIX", vars.StaticFilesS3Prefix),
|
||||
ecsKeyValuePair("WEB_APP_SERVICE_STATICFILES_CLOUDFRONT_ENABLED", strconv.FormatBool(vars.StaticFilesCloudfrontEnabled)),
|
||||
ecsKeyValuePair("WEB_APP_REDIS_HOST", vars.CacheHost),
|
||||
ecsKeyValuePair("WEB_APP_DB_HOST", vars.DbHost),
|
||||
ecsKeyValuePair("WEB_APP_DB_USERNAME", vars.DbUser),
|
||||
ecsKeyValuePair("WEB_APP_DB_PASSWORD", vars.DbPass),
|
||||
ecsKeyValuePair("WEB_APP_DB_DATABASE", vars.DbName),
|
||||
ecsKeyValuePair("WEB_APP_DB_DRIVER", vars.DbDriver),
|
||||
ecsKeyValuePair("WEB_APP_DB_DISABLE_TLS", strconv.FormatBool(vars.DbDisableTLS)),
|
||||
ecsKeyValuePair("WEB_APP_AWS_S3_BUCKET_PRIVATE", vars.AwsS3BucketNamePrivate),
|
||||
ecsKeyValuePair("WEB_APP_AWS_S3_BUCKET_PUBLIC", vars.AwsS3BucketNamePublic),
|
||||
)
|
||||
|
||||
if datadogApiKey != "" {
|
||||
log.Println("DATADOG API Key set.")
|
||||
} else {
|
||||
log.Printf("DATADOG API Key NOT set.")
|
||||
}
|
||||
|
||||
placeholders["{DATADOG_APIKEY}"] = datadogApiKey
|
||||
|
||||
// When the datadog API key is empty, don't force the container to be essential have have the whole task fail.
|
||||
if datadogApiKey != "" {
|
||||
placeholders["{DATADOG_ESSENTIAL}"] = "true"
|
||||
} else {
|
||||
placeholders["{DATADOG_ESSENTIAL}"] = "false"
|
||||
}
|
||||
// When no Elastic Load Balance is used, tasks need to be able to directly update the Route 53 records.
|
||||
if vars.AwsElbLoadBalancer == nil {
|
||||
input.ContainerDefinitions[0].Environment = append(input.ContainerDefinitions[0].Environment,
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_ZONES, vars.EncodeRoute53Zones()),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_UPDATE_TASK_IPS, "true"))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -634,33 +678,6 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
})
|
||||
}
|
||||
|
||||
// Append env vars for the service task.
|
||||
container1.Environment = append(container1.Environment,
|
||||
ecsKeyValuePair("SERVICE_NAME", ctx.Name),
|
||||
ecsKeyValuePair("PROJECT_NAME", cfg.ProjectName),
|
||||
|
||||
// Use placeholders for these environment variables that will be replaced with devdeploy.DeployServiceToTargetEnv
|
||||
ecsKeyValuePair("WEB_API_HTTP_HOST", "{HTTP_HOST}"),
|
||||
ecsKeyValuePair("WEB_API_HTTPS_HOST", "{HTTPS_HOST}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_ENABLE_HTTPS", "{HTTPS_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_BASE_URL", "{APP_BASE_URL}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_HOST_NAMES", "{HOST_NAMES}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_S3_ENABLED", "{STATIC_FILES_S3_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_S3_PREFIX", "{STATIC_FILES_S3_PREFIX}"),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_CLOUDFRONT_ENABLED", "{STATIC_FILES_CLOUDFRONT_ENABLED}"),
|
||||
ecsKeyValuePair("WEB_API_REDIS_HOST", "{CACHE_HOST}"),
|
||||
ecsKeyValuePair("WEB_API_DB_HOST", "{DB_HOST}"),
|
||||
ecsKeyValuePair("WEB_API_DB_USERNAME", "{DB_USER}"),
|
||||
ecsKeyValuePair("WEB_API_DB_PASSWORD", "{DB_PASS}"),
|
||||
ecsKeyValuePair("WEB_API_DB_DATABASE", "{DB_DATABASE}"),
|
||||
ecsKeyValuePair("WEB_API_DB_DRIVER", "{DB_DRIVER}"),
|
||||
ecsKeyValuePair("WEB_API_DB_DISABLE_TLS", "{DB_DISABLE_TLS}"),
|
||||
ecsKeyValuePair("WEB_API_AWS_S3_BUCKET_PRIVATE", "{AWS_S3_BUCKET_PRIVATE}"),
|
||||
ecsKeyValuePair("WEB_API_AWS_S3_BUCKET_PUBLIC", "{AWS_S3_BUCKET_PUBLIC}"),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_UPDATE_TASK_IPS, "{ROUTE53_UPDATE_TASK_IPS}"),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_ZONES, "{ROUTE53_ZONES}"),
|
||||
)
|
||||
|
||||
// Define the full task definition for the service.
|
||||
taskDef := &ecs.RegisterTaskDefinitionInput{
|
||||
Family: aws.String(fmt.Sprintf("%s-%s-%s", cfg.Env, srv.AwsEcsCluster.ClusterName, ctx.Name)),
|
||||
@ -673,32 +690,44 @@ func NewService(serviceName string, cfg *devdeploy.Config) (*devdeploy.ProjectSe
|
||||
RequiresCompatibilities: aws.StringSlice([]string{"FARGATE"}),
|
||||
}
|
||||
|
||||
// Append the datadog container if defined.
|
||||
if ddContainer != nil {
|
||||
taskDef.ContainerDefinitions = append(taskDef.ContainerDefinitions, ddContainer)
|
||||
}
|
||||
|
||||
srv.AwsEcsTaskDefinition = &devdeploy.AwsEcsTaskDefinition{
|
||||
RegisterInput: taskDef,
|
||||
UpdatePlaceholders: func(placeholders map[string]string) error {
|
||||
PreRegister: func(input *ecs.RegisterTaskDefinitionInput, vars devdeploy.AwsEcsServiceDeployVariables) error {
|
||||
// Append env vars for the service task.
|
||||
input.ContainerDefinitions[0].Environment = append(input.ContainerDefinitions[0].Environment,
|
||||
ecsKeyValuePair("SERVICE_NAME", ctx.Name),
|
||||
ecsKeyValuePair("PROJECT_NAME", cfg.ProjectName),
|
||||
|
||||
// Try to find the Datadog API key, this value is optional.
|
||||
// If Datadog API key is not specified, then integration with Datadog for observability will not be active.
|
||||
{
|
||||
datadogApiKey, err := getDatadogApiKey(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Use placeholders for these environment variables that will be replaced with devdeploy.DeployServiceToTargetEnv
|
||||
ecsKeyValuePair("WEB_API_HTTP_HOST", vars.HTTPHost),
|
||||
ecsKeyValuePair("WEB_API_HTTPS_HOST", vars.HTTPSHost),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_ENABLE_HTTPS", strconv.FormatBool(vars.HTTPSEnabled)),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_BASE_URL", vars.ServiceBaseUrl),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_HOST_NAMES", strings.Join(vars.AlternativeHostnames, ",")),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_S3_ENABLED", strconv.FormatBool(vars.StaticFilesS3Enabled)),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_S3_PREFIX", vars.StaticFilesS3Prefix),
|
||||
ecsKeyValuePair("WEB_API_SERVICE_STATICFILES_CLOUDFRONT_ENABLED", strconv.FormatBool(vars.StaticFilesCloudfrontEnabled)),
|
||||
ecsKeyValuePair("WEB_API_REDIS_HOST", vars.CacheHost),
|
||||
ecsKeyValuePair("WEB_API_DB_HOST", vars.DbHost),
|
||||
ecsKeyValuePair("WEB_API_DB_USERNAME", vars.DbUser),
|
||||
ecsKeyValuePair("WEB_API_DB_PASSWORD", vars.DbPass),
|
||||
ecsKeyValuePair("WEB_API_DB_DATABASE", vars.DbName),
|
||||
ecsKeyValuePair("WEB_API_DB_DRIVER", vars.DbDriver),
|
||||
ecsKeyValuePair("WEB_API_DB_DISABLE_TLS", strconv.FormatBool(vars.DbDisableTLS)),
|
||||
ecsKeyValuePair("WEB_API_AWS_S3_BUCKET_PRIVATE", vars.AwsS3BucketNamePrivate),
|
||||
ecsKeyValuePair("WEB_API_AWS_S3_BUCKET_PUBLIC", vars.AwsS3BucketNamePublic),
|
||||
)
|
||||
|
||||
if datadogApiKey != "" {
|
||||
log.Println("DATADOG API Key set.")
|
||||
} else {
|
||||
log.Printf("DATADOG API Key NOT set.")
|
||||
}
|
||||
|
||||
placeholders["{DATADOG_APIKEY}"] = datadogApiKey
|
||||
|
||||
// When the datadog API key is empty, don't force the container to be essential have have the whole task fail.
|
||||
if datadogApiKey != "" {
|
||||
placeholders["{DATADOG_ESSENTIAL}"] = "true"
|
||||
} else {
|
||||
placeholders["{DATADOG_ESSENTIAL}"] = "false"
|
||||
}
|
||||
// When no Elastic Load Balance is used, tasks need to be able to directly update the Route 53 records.
|
||||
if vars.AwsElbLoadBalancer == nil {
|
||||
input.ContainerDefinitions[0].Environment = append(input.ContainerDefinitions[0].Environment,
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_ZONES, vars.EncodeRoute53Zones()),
|
||||
ecsKeyValuePair(devdeploy.ENV_KEY_ROUTE53_UPDATE_TASK_IPS, "true"))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -149,6 +149,44 @@ func main() {
|
||||
return config.BuildFunctionForTargetEnv(log, awsCredentials, targetEnv, funcName, releaseTag, dryRun, noCache, noPush)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "image",
|
||||
Usage: "build an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name, n",
|
||||
Usage: fmt.Sprintf("target image, one of [%s]",
|
||||
strings.Join(config.ImageNames, ", ")),
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "release-tag, tag",
|
||||
Usage: "optional tag to override default CI_COMMIT_SHORT_SHA",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "print out the build details",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-cache",
|
||||
Usage: "skip caching for the docker build",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-push",
|
||||
Usage: "disable pushing release image to remote repository",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
targetEnv := c.GlobalString("env")
|
||||
funcName := c.String("name")
|
||||
releaseTag := c.String("release-tag")
|
||||
dryRun := c.Bool("dry-run")
|
||||
noCache := c.Bool("no-cache")
|
||||
noPush := c.Bool("no-push")
|
||||
|
||||
return config.BuildImageForTargetEnv(log, awsCredentials, targetEnv, funcName, releaseTag, dryRun, noCache, noPush)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -41,7 +41,7 @@ require (
|
||||
github.com/tinylib/msgp v1.1.0 // indirect
|
||||
github.com/urfave/cli v1.21.0
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.18
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.19
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
|
||||
golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de // indirect
|
||||
|
4
go.sum
4
go.sum
@ -215,8 +215,8 @@ github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVU
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.18 h1:Vkk7WrTIvGd+Nnb6ru3o4r1yw4h7lJBdcnGLG71d390=
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.18/go.mod h1:xr+rhNSDXrEh0A6bkBPnfMiRIou3OiPZK0oD5h9GAAM=
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.19 h1:x/PknYjZFZNfrm9TW4wWXlI73Jd56HYrQt3a1IUbpK8=
|
||||
gitlab.com/geeks-accelerator/oss/devops v1.0.19/go.mod h1:xr+rhNSDXrEh0A6bkBPnfMiRIou3OiPZK0oD5h9GAAM=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
Reference in New Issue
Block a user