Пример #1
0
        static void Main(string[] args)
        {
            var app   = new App(null);
            var stack = new Stack(app, "mystack");
            var rule  = new Rule(stack, "myrule", new RuleProps
            {
                Targets  = new IRuleTarget[] { new MyEventTarget() },
                Schedule = Schedule.Cron(new CronOptions
                {
                    Day = "20"
                })
            });
            var lb = new ApplicationLoadBalancer(stack, "myapplb", new ApplicationLoadBalancerProps
            {
                Vpc = new Vpc(stack, "myvpc")
            });
            var listener = lb.AddListener("Listener", new ApplicationListenerProps
            {
                Port = 80
            });

            listener.AddTargets("mylbtarget", new AddApplicationTargetsProps
            {
                Targets = new IApplicationLoadBalancerTarget[] { new MyLBTarget() },
                Port    = 80
            });
            app.Synth();
        }
Пример #2
0
        internal InternalLoadBalancerStack(Construct scope, string id, IInternalLoadBalancerStackProps props) : base(scope, id, props)
        {
            var loadBalancer = new ApplicationLoadBalancer(this, "LoadBalancer", new ApplicationLoadBalancerProps
            {
                Vpc            = props.Vpc,
                InternetFacing = true
            });

            var defaultTarget = new ApplicationTargetGroup(this, "TargetGroup", new ApplicationTargetGroupProps
            {
                Vpc  = props.Vpc,
                Port = 80
            });

            Listener = loadBalancer.AddListener("Listener", new BaseApplicationListenerProps
            {
                Port = 80,
                DefaultTargetGroups = new ApplicationTargetGroup[] { defaultTarget }
            });

            new CfnOutput(this, "LoadBalancerDNS", new CfnOutputProps
            {
                Value = loadBalancer.LoadBalancerDnsName
            });
        }
        private ApplicationListener AddListener(ApplicationLoadBalancer lb, int port, string certArn = null)
        {
            var certs = (certArn == null) ? null : new ListenerCertificate[] { new ListenerCertificate(certArn) };


            var listener = lb.AddListener($"App2BalancerListener_{port}", new BaseApplicationListenerProps
            {
                Open         = true,
                Certificates = certs,
                Port         = port,
            });


            return(listener);
        }
Пример #4
0
        internal AutoScaledInstances(
            CdkStack stack,
            CfnParameter targetPlatform,
            Vpc vpc,
            bool publicAccess,
            SecurityGroup albSecurityGroup,
            SecurityGroup instanceSecurityGroup,
            Database database = null,
            Policy policy     = null,
            ApplicationLoadBalancer restApiLoadBalancer = null)
        {
            IMachineImage selectedImage;

            bool targetWindows = false;

            if (targetWindows)
            {
                var userData = UserData.ForWindows();
                userData.AddCommands(
                    "New-Item -Path c:\\temp -ItemType Directory -Force",
                    $"Read-S3Object -BucketName aws-codedeploy-{stack.Region}/latest -Key codedeploy-agent.msi -File c:\\temp\\codedeploy-agent.msi",
                    "Start-Process -Wait -FilePath c:\\temp\\codedeploy-agent.msi -WindowStyle Hidden"
                    );
                selectedImage = new WindowsImage(
                    WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_CORE_BASE,
                    new WindowsImageProps
                {
                    UserData = userData
                }
                    );
            }
            else
            {
                var userData = UserData.ForLinux(new LinuxUserDataOptions {
                    Shebang = "#!/bin/bash -xe"
                });
                userData.AddCommands(
                    "exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1",
                    "yum install -y aws-cli ruby jq",
                    "yum -y update",
                    "cd /tmp/",
                    $"curl -O https://aws-codedeploy-{stack.Region}.s3.amazonaws.com/latest/install",
                    "chmod +x ./install",
                    "if ./install auto; then",
                    "    echo \"CodeDeploy Agent installation completed successfully!\"",
                    "    exit 0",
                    "else",
                    "    echo \"CodeDeploy Agent installation failed, please investigate.\"",
                    "    rm -f /tmp/install",
                    "    exit 1",
                    "fi",
                    "rm -rf /tmp/*"
                    );
                selectedImage = new AmazonLinuxImage(new AmazonLinuxImageProps
                {
                    Edition        = AmazonLinuxEdition.STANDARD,
                    Virtualization = AmazonLinuxVirt.HVM,
                    Generation     = AmazonLinuxGeneration.AMAZON_LINUX_2,
                    Storage        = AmazonLinuxStorage.EBS,
                    UserData       = userData
                });
            };

            var alb = new ApplicationLoadBalancer(stack, $"ApplicationLoadBalancer-{(publicAccess ? "public" : "private")}", new ApplicationLoadBalancerProps
            {
                InternetFacing = publicAccess,
                Vpc            = vpc,
                VpcSubnets     = new SubnetSelection {
                    SubnetType = publicAccess ? SubnetType.PUBLIC : SubnetType.PRIVATE
                },
                SecurityGroup = albSecurityGroup,
                IpAddressType = IpAddressType.IPV4,
                Http2Enabled  = true
            });

            var albTargetGroup = new ApplicationTargetGroup(stack, $"ApplicationTargetGroup-{(publicAccess ? "public" : "private")}", new ApplicationTargetGroupProps
            {
                Vpc         = vpc,
                Port        = 80,
                Protocol    = ApplicationProtocol.HTTP,
                TargetType  = TargetType.INSTANCE,
                HealthCheck = new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck
                {
                    Timeout  = Duration.Seconds(5),
                    Interval = Duration.Seconds(10),
                    HealthyThresholdCount = 2
                }
            });
            var albListener = new ApplicationListener(stack, $"ApplicationListener-{(publicAccess ? "public" : "private")}", new ApplicationListenerProps
            {
                Port          = 80,
                Protocol      = ApplicationProtocol.HTTP,
                DefaultAction = ListenerAction.Forward(new[] { albTargetGroup }),
                LoadBalancer  = alb
            });

            var asg = new AutoScalingGroup(stack, $"ASG-{(publicAccess ? "public" : "private")}", new AutoScalingGroupProps
            {
                Vpc          = vpc,
                MinCapacity  = 2,
                InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MEDIUM),
                MachineImage = selectedImage,
                BlockDevices = new[] {
                    new Amazon.CDK.AWS.AutoScaling.BlockDevice()
                    {
                        DeviceName = "/dev/xvda",
                        Volume     = Amazon.CDK.AWS.AutoScaling.BlockDeviceVolume.Ebs(
                            targetWindows ? 30: 8,
                            new Amazon.CDK.AWS.AutoScaling.EbsDeviceOptions {
                            VolumeType          = Amazon.CDK.AWS.AutoScaling.EbsDeviceVolumeType.GP2,
                            DeleteOnTermination = true
                        }
                            )
                    }
                },
                AssociatePublicIpAddress = false,
                VpcSubnets = new SubnetSelection {
                    SubnetType = SubnetType.PRIVATE
                }
            });

            if (policy != null)
            {
                asg.Role.AttachInlinePolicy(policy);
            }
            asg.Role.AddToPrincipalPolicy(
                new PolicyStatement(new PolicyStatementProps
            {
                Effect    = Effect.ALLOW,
                Actions   = new[] { "ec2:DescribeTags" },
                Resources = new[] { "*" }
            })
                );
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"));
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSXRayDaemonWriteAccess"));
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("CloudWatchAgentServerPolicy"));

            Tag.Add(asg, "Application", stack.StackName);
            if (publicAccess)
            {
                Tag.Add(asg, "ApplicationRole", "Front End");
                Tag.Add(asg, "RESTAPIAddress", restApiLoadBalancer.LoadBalancerDnsName);
            }
            else
            {
                Tag.Add(asg, "ApplicationRole", "REST API");
            }
            if (database != null)
            {
                asg.Node.AddDependency(database.DatabaseResource);
                Tag.Add(asg, "DBSecretArn", database.Password.SecretArn);
            }

            // Enable access from the ALB
            asg.AddSecurityGroup(instanceSecurityGroup);
            Result = new LoadBalancedInstancesResult
            {
                AutoScalingGroup = asg,
                TargetGroup      = albTargetGroup,
                LoadBalancer     = alb
            };
        }
        public ApplicationLoadBalancer Create(Construct construct, Amazon.CDK.AWS.EC2.Vpc vpc, Amazon.CDK.AWS.AutoScaling.AutoScalingGroup asg, SecurityGroup sg)
        {
            var lb = new ApplicationLoadBalancer(construct, _config.Alb.Name, new ApplicationLoadBalancerProps
            {
                Vpc              = vpc,
                InternetFacing   = true,
                LoadBalancerName = _config.Alb.Name,
                SecurityGroup    = sg
            });

            Amazon.CDK.Tags.Of(lb).Add("Name", $"{_config.Alb.Name}");

            // add a listener
            var listener = AddListener(lb, 80, null);
            var appPort  = 80;
            var group    = listener.AddTargets($"AppFleet", new AddApplicationTargetsProps
            {
                Port    = appPort,
                Targets = new[] { asg }
            });

            // add specific tags
            Amazon.CDK.Tags.Of(listener).Add("Name", $"{_config.Alb.Name}-listner");
            Amazon.CDK.Tags.Of(group).Add("Name", $"{_config.Alb.Name}-fleet");


            // exmple of a fixed ok message returned by the LB
            listener.AddAction($"FixedOkMessage", new AddApplicationActionProps
            {
                Priority   = 10,
                Conditions = new[] { ListenerCondition.PathPatterns(new[] { "/ok" }) },
                Action     = ListenerAction.FixedResponse(200, new FixedResponseOptions
                {
                    ContentType = "text/html",
                    MessageBody = "OK"
                })
            });

            // example of a fixed health status message returned by LB
            listener.AddAction($"LBHealthInfo", new AddApplicationActionProps
            {
                Priority   = 15,
                Conditions = new[] { ListenerCondition.PathPatterns(new[] { "/lb-status" }) },
                Action     = ListenerAction.FixedResponse(200, new FixedResponseOptions
                {
                    ContentType = "application/json",
                    MessageBody = "{ \"lb\": { \"type\": \"application-load-balancer\", \"launchDateUtc\": \"{" + DateTime.UtcNow + "}\", \"status\": \"ok\" } }"
                })
            });

            //"arn:aws:acm:us-east-1:xxxxxxxxx:certificate/eb2b584c-421d-4134-b679-1746642b5e3f"
            if (_config.Alb.CertArn != null)
            {
                listener = AddListener(lb, 443, _config.Alb.CertArn);

                // forward any ssl requests to the target group
                listener.AddAction("SSLForward", new AddApplicationActionProps
                {
                    Action = ListenerAction.Forward(new[] { group }),
                });
            }


            return(lb);
        }
Пример #6
0
        internal InfraStack(Construct scope, string id, CustomStackProps props = null)
            : base(scope, id, props)
        {
            var vpc = props.Vpc;

            var cluster = new Cluster(this, "Cluster",
                                      new ClusterProps
            {
                Vpc         = vpc,
                ClusterName = Globals.GetDeployEnvironment(this).PutEnvNamePrefixWithDash("Cluster")
            });

            var albSecurityGroup = new SecurityGroup(this, "AlbSecurityGroup",
                                                     new SecurityGroupProps
            {
                Vpc = vpc,
                AllowAllOutbound = true
            });

            albSecurityGroup.AddIngressRule(Peer.AnyIpv4(), Port.Tcp(80));

            var alb = new ApplicationLoadBalancer(this, "ALB",
                                                  new ApplicationLoadBalancerProps
            {
                Vpc            = vpc,
                InternetFacing = true,
                Http2Enabled   = true,
                IdleTimeout    = Duration.Seconds(60),
                IpAddressType  = IpAddressType.IPV4,
                SecurityGroup  = albSecurityGroup
            });

            var webApiServiceSecurityGroup = new SecurityGroup(this, "WebApiServiceSecurityGroup",
                                                               new SecurityGroupProps
            {
                Vpc = vpc,
                AllowAllOutbound = true
            });

            webApiServiceSecurityGroup.AddIngressRule(albSecurityGroup, Port.Tcp(80));

            var appListener = alb.AddListener("AppListener",
                                              new BaseApplicationListenerProps
            {
                Port          = 80,
                Protocol      = ApplicationProtocol.HTTP,
                DefaultAction = ListenerAction.FixedResponse(404,
                                                             new FixedResponseOptions
                {
                    ContentType = "text/plain",
                    MessageBody = "This is not here..."
                })
            });

            new CfnOutput(this, "ClusterName",
                          new CfnOutputProps
            {
                ExportName = Globals.GetDeployEnvironment(this).PutEnvNamePrefixWithDash("ClusterName"),
                Value      = cluster.ClusterName
            });

            new CfnOutput(this, "WebApiServiceSecurityGroupId",
                          new CfnOutputProps
            {
                ExportName = Globals.GetDeployEnvironment(this).PutEnvNamePrefixWithDash("WebApiServiceSecurityGroupId"),
                Value      = albSecurityGroup.SecurityGroupId
            });

            new CfnOutput(this, "AppListenerArn",
                          new CfnOutputProps
            {
                ExportName = Globals.GetDeployEnvironment(this).PutEnvNamePrefixWithDash("AppListenerArn"),
                Value      = appListener.ListenerArn
            });
        }
Пример #7
0
        public CdkExampleStack(Construct parent, string id, IStackProps props) : base(parent, id, props)
        {
            var vpc = new Vpc(this, "MainVPC", new VpcProps
            {
                Cidr = "192.168.0.0/16"
            });

            var loadBalancer = new ApplicationLoadBalancer(this, "PublicALB", new ApplicationLoadBalancerProps
            {
                InternetFacing = true,
                Vpc            = vpc
            });

            var listener = loadBalancer.AddListener("MyListener", new ApplicationListenerProps
            {
                Port = 80
            });

            var userData = UserData.ForLinux(new LinuxUserDataOptions
            {
                Shebang = "#!/bin/bash"
            });

            userData.AddCommands(
                "yum update -y",
                "yum install httpd -y",
                "echo \"Hello World\" >> /var/www/html/index.html",
                "service httpd start",
                "chkconfig httpd on");


            var ec2SG = new SecurityGroup(this, "Ec2SecurityGroup", new SecurityGroupProps
            {
                Vpc = vpc,
                SecurityGroupName = "Ec2SG"
            });

            ec2SG.Connections.AllowFrom(loadBalancer, Port.Tcp(80), "FROM ALB");

            var instanceIds = new List <string>();

            for (var ix = 0; ix < vpc.PrivateSubnets.Length; ix++)
            {
                var instance = new Instance_(this, $"Instance-{ix}", new InstanceProps
                {
                    InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MICRO),
                    VpcSubnets   = new SubnetSelection()
                    {
                        SubnetType = SubnetType.PRIVATE
                    },
                    AvailabilityZone = vpc.PrivateSubnets[ix].AvailabilityZone,
                    Vpc           = vpc,
                    MachineImage  = new AmazonLinuxImage(),
                    UserData      = userData,
                    KeyName       = "test-cdk",
                    SecurityGroup = ec2SG
                });

                instanceIds.Add(instance.InstanceId);
            }

            listener.AddTargets("Targets", new AddApplicationTargetsProps
            {
                Port    = 80,
                Targets = instanceIds.Select(i => new InstanceIdTarget(i, 80)).ToArray()
            });
        }
        internal AppdeploymentStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            #region Application hosting resources

            var vpc = new Vpc(this, "appVpc", new VpcProps
            {
                MaxAzs = 3
            });

            var image = new LookupMachineImage(new LookupMachineImageProps
            {
                // maps to "Amazon Linux 2 with .NET Core 3.0 and Mono 5.18"
                Name   = "amzn2-ami-hvm-2.0.*-x86_64-gp2-mono-*",
                Owners = new [] { "amazon" }
            });

            var userData = UserData.ForLinux();
            userData.AddCommands(new string[]
            {
                "sudo yum install -y httpd",
                "sudo systemctl start httpd",
                "sudo systemctl enable httpd"
            });

            var scalingGroup = new AutoScalingGroup(this, "appASG", new AutoScalingGroupProps
            {
                Vpc              = vpc,
                InstanceType     = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MEDIUM),
                MachineImage     = image,
                MinCapacity      = 1,
                MaxCapacity      = 4,
                AllowAllOutbound = true,
                UserData         = userData
            });

            var alb = new ApplicationLoadBalancer(this, "appLB", new ApplicationLoadBalancerProps
            {
                Vpc            = vpc,
                InternetFacing = true
            });

            var albListener = alb.AddListener("Port80Listener", new BaseApplicationListenerProps
            {
                Port = 80
            });

            albListener.AddTargets("Port80ListenerTargets", new AddApplicationTargetsProps
            {
                Port    = 80,
                Targets = new [] { scalingGroup }
            });

            albListener.Connections.AllowDefaultPortFromAnyIpv4("Open access to port 80");

            scalingGroup.ScaleOnRequestCount("ScaleOnModestLoad", new RequestCountScalingProps
            {
                TargetRequestsPerSecond = 1
            });

            #endregion

            #region CI/CD resources

            var _sourceOutput = new Artifact_("Source");
            var _buildOutput  = new Artifact_("Build");

            var build = new PipelineProject(this, "CodeBuild", new PipelineProjectProps
            {
                // relative path to sample app's file (single html page for now)
                BuildSpec   = BuildSpec.FromSourceFilename("talk-demos/appdeployment/SimplePage/buildspec.yml"),
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_2
                },
            });

            var appDeployment = new ServerApplication(this, "appDeployment");
            // we will use CodeDeploy's default one-at-a-time deployment mode as we are
            // not specifying a deployment config
            var deploymentGroup = new ServerDeploymentGroup(this, "appDeploymentGroup", new ServerDeploymentGroupProps
            {
                Application  = appDeployment,
                InstallAgent = true,
                AutoRollback = new AutoRollbackConfig
                {
                    FailedDeployment = true
                },
                AutoScalingGroups = new [] { scalingGroup }
            });

            // SecretValue.SsmSecure is not currently supported for setting OauthToken,
            // and haven't gotten the SecretsManager approach to work either so
            // resorting to keeping my token in an environment var for now!
            var oauthToken = SecretValue.PlainText(System.Environment.GetEnvironmentVariable("GitHubPersonalToken"));

            var pipeline = new Pipeline(this, "sampleappPipeline", new PipelineProps
            {
                Stages = new StageProps[]
                {
                    new StageProps
                    {
                        StageName = "Source",
                        Actions   = new IAction[]
                        {
                            new GitHubSourceAction(new GitHubSourceActionProps
                            {
                                ActionName = "GitHubSource",
                                Branch     = "master",
                                Repo       = this.Node.TryGetContext("repo-name").ToString(),
                                Owner      = this.Node.TryGetContext("repo-owner").ToString(),
                                OauthToken = oauthToken,
                                Output     = _sourceOutput
                            })
                        }
                    },

                    new StageProps
                    {
                        StageName = "Build",
                        Actions   = new IAction[]
                        {
                            new CodeBuildAction(new CodeBuildActionProps
                            {
                                ActionName = "Build-app",
                                Project    = build,
                                Input      = _sourceOutput,
                                Outputs    = new Artifact_[] { _buildOutput },
                                RunOrder   = 1
                            })
                        }
                    },

                    new StageProps
                    {
                        StageName = "Deploy",
                        Actions   = new IAction[]
                        {
                            new CodeDeployServerDeployAction(new CodeDeployServerDeployActionProps
                            {
                                ActionName      = "Deploy-app",
                                Input           = _buildOutput,
                                RunOrder        = 2,
                                DeploymentGroup = deploymentGroup
                            })
                        }
                    }
                }
            });

            #endregion
        }
Пример #9
0
        private void ConfigureLoadBalancer(Configuration settings)
        {
            if (AppVpc == null)
            {
                throw new InvalidOperationException($"{nameof(AppVpc)} has not been set. The {nameof(ConfigureVpc)} method should be called before {nameof(ConfigureLoadBalancer)}");
            }
            if (EcsCluster == null)
            {
                throw new InvalidOperationException($"{nameof(EcsCluster)} has not been set. The {nameof(ConfigureECSClusterAndService)} method should be called before {nameof(ConfigureLoadBalancer)}");
            }
            if (AppFargateService == null)
            {
                throw new InvalidOperationException($"{nameof(AppFargateService)} has not been set. The {nameof(ConfigureECSClusterAndService)} method should be called before {nameof(ConfigureLoadBalancer)}");
            }

            if (settings.LoadBalancer.CreateNew)
            {
                ServiceLoadBalancer = new ApplicationLoadBalancer(this, nameof(ServiceLoadBalancer), InvokeCustomizeCDKPropsEvent(nameof(ServiceLoadBalancer), this, new ApplicationLoadBalancerProps
                {
                    Vpc            = AppVpc,
                    InternetFacing = true
                }));

                LoadBalancerListener = ServiceLoadBalancer.AddListener(nameof(LoadBalancerListener), InvokeCustomizeCDKPropsEvent(nameof(LoadBalancerListener), this, new ApplicationListenerProps
                {
                    Protocol = ApplicationProtocol.HTTP,
                    Port     = 80,
                    Open     = true
                }));

                ServiceTargetGroup = LoadBalancerListener.AddTargets(nameof(ServiceTargetGroup), InvokeCustomizeCDKPropsEvent(nameof(ServiceTargetGroup), this, new AddApplicationTargetsProps
                {
                    Protocol            = ApplicationProtocol.HTTP,
                    DeregistrationDelay = Duration.Seconds(settings.LoadBalancer.DeregistrationDelayInSeconds)
                }));
            }
            else
            {
                ServiceLoadBalancer = ApplicationLoadBalancer.FromLookup(this, nameof(ServiceLoadBalancer), InvokeCustomizeCDKPropsEvent(nameof(ServiceLoadBalancer), this, new ApplicationLoadBalancerLookupOptions
                {
                    LoadBalancerArn = settings.LoadBalancer.ExistingLoadBalancerArn
                }));

                LoadBalancerListener = ApplicationListener.FromLookup(this, nameof(LoadBalancerListener), InvokeCustomizeCDKPropsEvent(nameof(LoadBalancerListener), this, new ApplicationListenerLookupOptions
                {
                    LoadBalancerArn = settings.LoadBalancer.ExistingLoadBalancerArn,
                    ListenerPort    = 80
                }));

                ServiceTargetGroup = new ApplicationTargetGroup(this, nameof(ServiceTargetGroup), InvokeCustomizeCDKPropsEvent(nameof(ServiceTargetGroup), this, new ApplicationTargetGroupProps
                {
                    Port = 80,
                    Vpc  = EcsCluster.Vpc,
                }));


                var addApplicationTargetGroupsProps = new AddApplicationTargetGroupsProps
                {
                    TargetGroups = new[] { ServiceTargetGroup }
                };

                if (settings.LoadBalancer.ListenerConditionType != LoadBalancerConfiguration.ListenerConditionTypeEnum.None)
                {
                    addApplicationTargetGroupsProps.Priority = settings.LoadBalancer.ListenerConditionPriority;
                }

                if (settings.LoadBalancer.ListenerConditionType == LoadBalancerConfiguration.ListenerConditionTypeEnum.Path)
                {
                    if (settings.LoadBalancer.ListenerConditionPathPattern == null)
                    {
                        throw new ArgumentNullException("Listener condition type was set to \"Path\" but no value was set for the \"TargetPathPattern\"");
                    }
                    addApplicationTargetGroupsProps.Conditions = new ListenerCondition[]
                    {
                        ListenerCondition.PathPatterns(new [] { settings.LoadBalancer.ListenerConditionPathPattern })
                    };
                }

                LoadBalancerListener.AddTargetGroups("AddTargetGroup", InvokeCustomizeCDKPropsEvent("AddTargetGroup", this, addApplicationTargetGroupsProps));
            }

            // Configure health check for ALB Target Group
            var healthCheck = new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck();

            if (settings.LoadBalancer.HealthCheckPath != null)
            {
                var path = settings.LoadBalancer.HealthCheckPath;
                if (!path.StartsWith("/"))
                {
                    path = "/" + path;
                }
                healthCheck.Path = path;
            }
            if (settings.LoadBalancer.HealthCheckInternval.HasValue)
            {
                healthCheck.Interval = Duration.Seconds(settings.LoadBalancer.HealthCheckInternval.Value);
            }
            if (settings.LoadBalancer.HealthyThresholdCount.HasValue)
            {
                healthCheck.HealthyThresholdCount = settings.LoadBalancer.HealthyThresholdCount.Value;
            }
            if (settings.LoadBalancer.UnhealthyThresholdCount.HasValue)
            {
                healthCheck.UnhealthyThresholdCount = settings.LoadBalancer.UnhealthyThresholdCount.Value;
            }

            ServiceTargetGroup.ConfigureHealthCheck(healthCheck);

            ServiceTargetGroup.AddTarget(AppFargateService);
        }
Пример #10
0
        private IApplicationTargetGroup AddGrpcTargetGroup(BenchNetwork benchNetwork, Vpc vpc, DnsValidatedCertificate certificate, ApplicationLoadBalancer lb)
        {
            var grpcTargetGroupResource = CreateGrpcTargetGroup(vpc, new Dictionary <string, object>()
            {
                { "Name", "MagicOnionBench-grpc-target" },
                { "Port", benchNetwork.AlbGrpcPort.targetgroupPort },
                { "Protocol", ApplicationProtocol.HTTP.ToString() },
                { "ProtocolVersion", "GRPC" },
                { "VpcId", vpc.VpcId },
                { "TargetType", "instance" },
                { "HealthCheckEnabled", true },
                { "HealthCheckProtocol", Amazon.CDK.AWS.ElasticLoadBalancingV2.Protocol.HTTP.ToString() },
                { "HealthyThresholdCount", 2 },
                { "HealthCheckIntervalSeconds", 15 },
                { "HealthCheckTimeoutSeconds", 10 },
                { "HealthCheckPath", "/grpc.health.v1.Health/Check" },
                { "Matcher", new Dictionary <string, string> {
                      { "GrpcCode", "0-99" }
                  } },
            });
            var targetGroup = ApplicationTargetGroup.FromTargetGroupAttributes(this, "grpc-target-group", new TargetGroupAttributes
            {
                TargetGroupArn = grpcTargetGroupResource.Ref,
            });
            var listener = lb.AddListener("GrpcListener", new BaseApplicationListenerProps
            {
                Port         = benchNetwork.AlbGrpcPort.listenerPort,
                Protocol     = ApplicationProtocol.HTTPS,
                Certificates = new[] { new ListenerCertificate(certificate.CertificateArn) },
            });

            listener.AddTargetGroups("GrpcTargetGroupAttachment", new AddApplicationTargetGroupsProps
            {
                TargetGroups = new[] { targetGroup },
            });
            listener.Node.AddDependency(grpcTargetGroupResource);

            return(targetGroup);
        }
Пример #11
0
        private IApplicationTargetGroup AddHttpsTargetGroup(BenchNetwork benchNetwork, Vpc vpc, DnsValidatedCertificate certificate, ApplicationLoadBalancer lb)
        {
            var targetGroup = new ApplicationTargetGroup(this, $"{StackName}-https-target-group", new ApplicationTargetGroupProps
            {
                Port        = benchNetwork.AlbHttpsPort.targetgroupPort,
                Protocol    = ApplicationProtocol.HTTP,
                Vpc         = vpc,
                TargetType  = TargetType.INSTANCE,
                HealthCheck = new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck
                {
                    Enabled  = true,
                    Protocol = Amazon.CDK.AWS.ElasticLoadBalancingV2.Protocol.HTTP,
                    HealthyThresholdCount = 2,
                    Interval = Duration.Seconds(15),
                    Timeout  = Duration.Seconds(10),
                    Path     = "/health",
                },
                DeregistrationDelay = Duration.Seconds(30),
            });
            var listener = lb.AddListener("HttpsListener", new BaseApplicationListenerProps
            {
                Port         = benchNetwork.AlbHttpsPort.listenerPort,
                Protocol     = ApplicationProtocol.HTTPS,
                Certificates = new[] { new ListenerCertificate(certificate.CertificateArn) },
            });

            listener.AddTargetGroups("HttpsTargetGroupAttachment", new AddApplicationTargetGroupsProps
            {
                TargetGroups = new[] { targetGroup },
            });
            return(targetGroup);
        }
Пример #12
0
        internal CdkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var stackProps                = ReportStackProps.ParseOrDefault(props);
            var dframeWorkerLogGroup      = "MagicOnionBenchWorkerLogGroup";
            var dframeMasterLogGroup      = "MagicOnionBenchMasterLogGroup";
            var benchNetwork              = stackProps.GetBenchNetwork();
            var recreateMagicOnionTrigger = stackProps.GetBenchmarkServerBinariesHash();

            // s3
            var s3 = new Bucket(this, "Bucket", new BucketProps
            {
                AutoDeleteObjects = true,
                RemovalPolicy     = RemovalPolicy.DESTROY,
                AccessControl     = BucketAccessControl.PRIVATE,
            });
            var lifecycleRule = new LifecycleRule
            {
                Enabled    = true,
                Prefix     = "reports/",
                Expiration = Duration.Days(stackProps.DaysKeepReports),
                AbortIncompleteMultipartUploadAfter = Duration.Days(1),
            };

            s3.AddLifecycleRule(lifecycleRule);
            s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps
            {
                Sid        = "AllowPublicRead",
                Effect     = Effect.ALLOW,
                Principals = new[] { new AnyPrincipal() },
                Actions    = new[] { "s3:GetObject*" },
                Resources  = new[] { $"{s3.BucketArn}/html/*" },
            }));
            s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps
            {
                Sid        = "AllowAwsAccountAccess",
                Effect     = Effect.ALLOW,
                Principals = new[] { new AccountRootPrincipal() },
                Actions    = new[] { "s3:*" },
                Resources  = new[] { $"{s3.BucketArn}/*" },
            }));

            // s3 deploy
            var masterDllDeployment = new BucketDeployment(this, "DeployMasterDll", new BucketDeploymentProps
            {
                DestinationBucket    = s3,
                Sources              = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), $"out/linux/server")) },
                DestinationKeyPrefix = $"assembly/linux/server"
            });
            var userdataDeployment = new BucketDeployment(this, "UserData", new BucketDeploymentProps
            {
                DestinationBucket    = s3,
                Sources              = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), "userdata/")) },
                DestinationKeyPrefix = "userdata/"
            });

            // docker deploy
            var dockerImage = new DockerImageAsset(this, "dframeWorkerImage", new DockerImageAssetProps
            {
                Directory = Path.Combine(Directory.GetCurrentDirectory(), "app"),
                File      = "ConsoleAppEcs/Dockerfile.Ecs",
            });
            var dframeImage = ContainerImage.FromDockerImageAsset(dockerImage);

            // network
            var vpc = new Vpc(this, "Vpc", new VpcProps
            {
                MaxAzs              = 2,
                NatGateways         = 0,
                SubnetConfiguration = new[] { new SubnetConfiguration {
                                                  Name = "public", SubnetType = SubnetType.PUBLIC
                                              } },
            });
            var allsubnets = new SubnetSelection {
                Subnets = vpc.PublicSubnets
            };
            var singleSubnets = new SubnetSelection {
                Subnets = new[] { vpc.PublicSubnets.First() }
            };
            var sg = new SecurityGroup(this, "MasterSg", new SecurityGroupProps
            {
                AllowAllOutbound = true,
                Vpc = vpc,
            });

            foreach (var subnet in vpc.PublicSubnets)
            {
                sg.AddIngressRule(Peer.Ipv4(vpc.VpcCidrBlock), Port.AllTcp(), "VPC", true);
            }

            // service discovery
            var serviceDiscoveryDomain = "local";
            var serverMapName          = "server";
            var dframeMapName          = "dframe-master";
            var ns = new PrivateDnsNamespace(this, "Namespace", new PrivateDnsNamespaceProps
            {
                Vpc  = vpc,
                Name = serviceDiscoveryDomain,
            });
            var serviceDiscoveryServer = ns.CreateService("server", new DnsServiceProps
            {
                Name          = serverMapName,
                DnsRecordType = DnsRecordType.A,
                RoutingPolicy = RoutingPolicy.MULTIVALUE,
            });

            // alb
            var albDnsName = "benchmark-alb";
            var benchToMagicOnionDnsName = benchNetwork.RequireAlb
                ? $"{benchNetwork.EndpointScheme}://{albDnsName}.{stackProps.AlbDomain.domain}"
                : $"{benchNetwork.EndpointScheme}://{serverMapName}.{serviceDiscoveryDomain}";
            IApplicationTargetGroup grpcTargetGroup  = null;
            IApplicationTargetGroup httpsTargetGroup = null;

            if (benchNetwork.RequireAlb)
            {
                // route53
                var hostedZone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes
                {
                    HostedZoneId = stackProps.AlbDomain.zoneId,
                    ZoneName     = stackProps.AlbDomain.domain,
                });

                // acm
                var certificate = new DnsValidatedCertificate(this, "certificate", new DnsValidatedCertificateProps
                {
                    DomainName = $"{albDnsName}.{hostedZone.ZoneName}",
                    HostedZone = hostedZone,
                });
                // alb
                var lb = new ApplicationLoadBalancer(this, "LB", new ApplicationLoadBalancerProps
                {
                    Vpc           = vpc,
                    VpcSubnets    = allsubnets,
                    SecurityGroup = new SecurityGroup(this, "AlbSg", new SecurityGroupProps
                    {
                        AllowAllOutbound = true,
                        Vpc = vpc,
                    }),
                    InternetFacing = false,
                    Http2Enabled   = true,
                });
                grpcTargetGroup  = AddGrpcTargetGroup(benchNetwork, vpc, certificate, lb);
                httpsTargetGroup = AddHttpsTargetGroup(benchNetwork, vpc, certificate, lb);

                // Dns Record
                _ = new CnameRecord(this, "alb-alias-record", new CnameRecordProps
                {
                    RecordName = $"{albDnsName}.{stackProps.AlbDomain.domain}",
                    Ttl        = Duration.Seconds(60),
                    Zone       = hostedZone,
                    DomainName = lb.LoadBalancerDnsName,
                });
            }

            // iam
            var iamEc2MagicOnionRole  = GetIamEc2MagicOnionRole(s3, serviceDiscoveryServer);
            var iamEcsTaskExecuteRole = GetIamEcsTaskExecuteRole(new[] { dframeWorkerLogGroup, dframeMasterLogGroup });
            var iamDFrameTaskDefRole  = GetIamEcsDframeTaskDefRole(s3);
            var iamWorkerTaskDefRole  = GetIamEcsWorkerTaskDefRole(s3);

            // secrets
            var ddToken = stackProps.UseEc2DatadogAgentProfiler || stackProps.UseFargateDatadogAgentProfiler
                ? Amazon.CDK.AWS.SecretsManager.Secret.FromSecretNameV2(this, "dd-token", "magiconion-benchmark-datadog-token")
                : null;

            // MagicOnion
            var asg = new AutoScalingGroup(this, "MagicOnionAsg", new AutoScalingGroupProps
            {
                // Monitoring is default DETAILED.
                SpotPrice                = "1.0", // 0.0096 for spot price average for m3.medium
                Vpc                      = vpc,
                SecurityGroup            = sg,
                VpcSubnets               = singleSubnets,
                InstanceType             = stackProps.MagicOnionInstanceType,
                DesiredCapacity          = 1,
                MaxCapacity              = 1,
                MinCapacity              = 0,
                AssociatePublicIpAddress = true,
                MachineImage             = new AmazonLinuxImage(new AmazonLinuxImageProps
                {
                    CpuType        = AmazonLinuxCpuType.X86_64,
                    Generation     = AmazonLinuxGeneration.AMAZON_LINUX_2,
                    Storage        = AmazonLinuxStorage.GENERAL_PURPOSE,
                    Virtualization = AmazonLinuxVirt.HVM,
                }),
                AllowAllOutbound = true,
                GroupMetrics     = new[] { GroupMetrics.All() },
                Role             = iamEc2MagicOnionRole,
                UpdatePolicy     = UpdatePolicy.ReplacingUpdate(),
                Signals          = Signals.WaitForCount(1, new SignalsOptions
                {
                    Timeout = Duration.Minutes(10),
                }),
            });

            asg.AddSecretsReadGrant(ddToken, () => stackProps.UseEc2DatadogAgentProfiler);
            var userdata = GetUserData(recreateMagicOnionTrigger, s3.BucketName, stackProps.BenchmarkBinaryNames, serviceDiscoveryServer.ServiceId, stackProps.UseEc2CloudWatchAgentProfiler, stackProps.UseEc2DatadogAgentProfiler);

            asg.AddUserData(userdata);
            asg.UserData.AddSignalOnExitCommand(asg);
            asg.Node.AddDependency(masterDllDeployment);
            asg.Node.AddDependency(userdataDeployment);
            if (stackProps.EnableMagicOnionScaleInCron)
            {
                asg.ScaleOnSchedule("ScheduleOut", new BasicScheduledActionProps
                {
                    DesiredCapacity = 1,
                    MaxCapacity     = 1,
                    // AM9:00 (JST+9) on Monday to Wednesday
                    Schedule = Schedule.Expression("0 0 * 1-3 *"),
                });
                asg.ScaleOnSchedule("ScheduleIn", new BasicScheduledActionProps
                {
                    DesiredCapacity = 0,
                    MaxCapacity     = 0,
                    // PM9:00 (JST+9) on Everyday
                    Schedule = Schedule.Expression("0 12 * 1-7 *"),
                });
            }
            if (benchNetwork.RequireAlb)
            {
                asg.AttachToApplicationTargetGroup(grpcTargetGroup);
                asg.AttachToApplicationTargetGroup(httpsTargetGroup);
            }

            // ECS
            var cluster = new Cluster(this, "WorkerCluster", new ClusterProps
            {
                Vpc = vpc,
            });

            cluster.Node.AddDependency(asg); // wait until asg is up

            // dframe-worker
            var dframeWorkerContainerName = "worker";
            var dframeWorkerTaskDef       = new FargateTaskDefinition(this, "DFrameWorkerTaskDef", new FargateTaskDefinitionProps
            {
                ExecutionRole  = iamEcsTaskExecuteRole,
                TaskRole       = iamWorkerTaskDefRole,
                Cpu            = stackProps.WorkerFargate.CpuSize,
                MemoryLimitMiB = stackProps.WorkerFargate.MemorySize,
            });

            dframeWorkerTaskDef.AddContainer(dframeWorkerContainerName, new ContainerDefinitionOptions
            {
                Image       = dframeImage,
                Command     = new[] { "--worker-flag" },
                Environment = new Dictionary <string, string>
                {
                    { "DFRAME_MASTER_CONNECT_TO_HOST", $"{dframeMapName}.{serviceDiscoveryDomain}" },
                    { "DFRAME_MASTER_CONNECT_TO_PORT", "12345" },
                    { "BENCH_SERVER_HOST", benchToMagicOnionDnsName },
                    { "BENCH_REPORTID", stackProps.ReportId },
                    { "BENCH_S3BUCKET", s3.BucketName },
                },
                Logging = LogDriver.AwsLogs(new AwsLogDriverProps
                {
                    LogGroup = new LogGroup(this, "WorkerLogGroup", new LogGroupProps
                    {
                        LogGroupName  = dframeWorkerLogGroup,
                        RemovalPolicy = RemovalPolicy.DESTROY,
                        Retention     = RetentionDays.TWO_WEEKS,
                    }),
                    StreamPrefix = dframeWorkerLogGroup,
                }),
            });
            dframeWorkerTaskDef.AddDatadogContainer($"{dframeWorkerContainerName}-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler);
            var dframeWorkerService = new FargateService(this, "DFrameWorkerService", new FargateServiceProps
            {
                ServiceName       = "DFrameWorkerService",
                DesiredCount      = 0,
                Cluster           = cluster,
                TaskDefinition    = dframeWorkerTaskDef,
                VpcSubnets        = singleSubnets,
                SecurityGroups    = new[] { sg },
                PlatformVersion   = FargatePlatformVersion.VERSION1_4,
                MinHealthyPercent = 0,
                AssignPublicIp    = true,
            });

            // dframe-master
            var dframeMasterTaskDef = new FargateTaskDefinition(this, "DFrameMasterTaskDef", new FargateTaskDefinitionProps
            {
                ExecutionRole  = iamEcsTaskExecuteRole,
                TaskRole       = iamDFrameTaskDefRole,
                Cpu            = stackProps.MasterFargate.CpuSize,
                MemoryLimitMiB = stackProps.MasterFargate.MemorySize,
            });

            dframeMasterTaskDef.AddContainer("dframe", new ContainerDefinitionOptions
            {
                Image       = dframeImage,
                Environment = new Dictionary <string, string>
                {
                    { "DFRAME_CLUSTER_NAME", cluster.ClusterName },
                    { "DFRAME_MASTER_SERVICE_NAME", "DFrameMasterService" },
                    { "DFRAME_WORKER_CONTAINER_NAME", dframeWorkerContainerName },
                    { "DFRAME_WORKER_SERVICE_NAME", dframeWorkerService.ServiceName },
                    { "DFRAME_WORKER_TASK_NAME", Fn.Select(1, Fn.Split("/", dframeWorkerTaskDef.TaskDefinitionArn)) },
                    { "DFRAME_WORKER_IMAGE", dockerImage.ImageUri },
                    { "BENCH_REPORTID", stackProps.ReportId },
                    { "BENCH_S3BUCKET", s3.BucketName },
                },
                Logging = LogDriver.AwsLogs(new AwsLogDriverProps
                {
                    LogGroup = new LogGroup(this, "MasterLogGroup", new LogGroupProps
                    {
                        LogGroupName  = dframeMasterLogGroup,
                        RemovalPolicy = RemovalPolicy.DESTROY,
                        Retention     = RetentionDays.TWO_WEEKS,
                    }),
                    StreamPrefix = dframeMasterLogGroup,
                }),
            });
            dframeMasterTaskDef.AddDatadogContainer($"dframe-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler);
            var dframeMasterService = new FargateService(this, "DFrameMasterService", new FargateServiceProps
            {
                ServiceName       = "DFrameMasterService",
                DesiredCount      = 1,
                Cluster           = cluster,
                TaskDefinition    = dframeMasterTaskDef,
                VpcSubnets        = singleSubnets,
                SecurityGroups    = new[] { sg },
                PlatformVersion   = FargatePlatformVersion.VERSION1_4,
                MinHealthyPercent = 0,
                AssignPublicIp    = true,
            });

            dframeMasterService.EnableCloudMap(new CloudMapOptions
            {
                CloudMapNamespace = ns,
                Name          = dframeMapName,
                DnsRecordType = DnsRecordType.A,
                DnsTtl        = Duration.Seconds(300),
            });

            // output
            new CfnOutput(this, "ReportUrl", new CfnOutputProps {
                Value = $"https://{s3.BucketRegionalDomainName}/html/{stackProps.ReportId}/index.html"
            });
            new CfnOutput(this, "EndPointStyle", new CfnOutputProps {
                Value = stackProps.BenchmarkEndpoint.ToString()
            });
            new CfnOutput(this, "AsgName", new CfnOutputProps {
                Value = asg.AutoScalingGroupName
            });
            new CfnOutput(this, "EcsClusterName", new CfnOutputProps {
                Value = cluster.ClusterName
            });
            new CfnOutput(this, "DFrameWorkerEcsTaskdefImage", new CfnOutputProps {
                Value = dockerImage.ImageUri
            });
        }
Пример #13
0
        public ApiStack(Construct parent, string id, IApiStackProps props) : base(parent, id, props)
        {
            var cluster = new Cluster(
                this,
                "Example",
                new ClusterProps
            {
                Vpc = props.Vpc,
            });

            var logging = new AwsLogDriver(new AwsLogDriverProps
            {
                StreamPrefix = "Example",
            });

            var taskDef = new FargateTaskDefinition(
                this,
                "Task",
                new FargateTaskDefinitionProps
            {
                MemoryLimitMiB = 512,
                Cpu            = 256,
            });

            var repo = Repository.FromRepositoryName(
                this,
                "EcrRepository",
                props.Repository.RepositoryName);

            var imageTag = new CfnParameter(
                this,
                props.ApiImageTag,
                new CfnParameterProps
            {
                Default = "latest",
            });

            var container = new ContainerDefinition(
                this,
                "ApiContainer",
                new ContainerDefinitionProps
            {
                TaskDefinition = taskDef,
                Image          = ContainerImage.FromEcrRepository(repo, imageTag.ValueAsString),
                Logging        = logging,
            });

            container.AddPortMappings(new PortMapping
            {
                ContainerPort = 80,
                HostPort      = 80,
                Protocol      = Amazon.CDK.AWS.ECS.Protocol.TCP,
            });

            var loadBalancer = new ApplicationLoadBalancer(
                this,
                "LoadBalancer",
                new ApplicationLoadBalancerProps
            {
                Vpc            = props.Vpc,
                Http2Enabled   = false,
                IdleTimeout    = Duration.Seconds(5),
                InternetFacing = true,
                IpAddressType  = IpAddressType.IPV4,
                VpcSubnets     = new SubnetSelection
                {
                    Subnets = props.Vpc.PublicSubnets,
                },
            });

            var ecsService = new ApplicationLoadBalancedFargateService(
                this,
                "Service",
                new ApplicationLoadBalancedFargateServiceProps
            {
                Cluster            = cluster,
                TaskDefinition     = taskDef,
                AssignPublicIp     = false,
                PublicLoadBalancer = true,
                LoadBalancer       = loadBalancer,
            });

            PrintLoadBalancerDnsName(ecsService);
        }