your programing

웹 애플리케이션없이 Amazon Elastic Beanstalk로 .NET Windows 서비스 배포

lovepro 2020. 12. 31. 23:07
반응형

웹 애플리케이션없이 Amazon Elastic Beanstalk로 .NET Windows 서비스 배포


웹 애플리케이션을 배포하지 않고 .NET Windows 서비스를 배포 할 수있는 Elastic Beanstalk 구성을 생성하려고합니다.

.ebextensions를 사용하여 웹 애플리케이션과 함께 Windows 서비스를 배포하는 방법을 설명하는 이 블로그 게시물방금 읽었 지만 웹 애플리케이션 용 웹 배포 패키지를 배포하지 않고 .ebextensions를 실행할 수있는 시나리오가 있습니까?

.ebextensions 디렉터리가 포함 된 빈 웹 애플리케이션을 생성 한 다음 웹 배포 패키지를 배포하는 유일한 옵션입니까?

Elastic Beanstalk FAQ에는 웹이 아닌 애플리케이션을 배포 할 수있는 기능 ( 여기 )이 언급 되어 있으며 AWS 개발자 포럼 ( 여기 ) 에서 유사한 (답변되지 않은) 질문을 찾았습니다 .

최신 정보

이 질문에 대한 활동이 부족하고 인터넷에서 다른 정보를 찾을 수 없기 때문에이 질문에 대한 대답이 "아니오"라고 가정했습니다 (적어도 지금은).

결국 빈 웹 애플리케이션을 만들고이를 사용하여 .ebextensions YAML 구성을 통해 Windows 서비스를 배포했습니다.

부수적으로 저는 Amazon의 설명서에서이 페이지 를 강조하고 싶습니다. 이 페이지는 이러한 특수 구성 파일을 만드는 데 매우 유용한 가이드입니다.

또 다른 업데이트

위에서 언급 한 접근 방식을 구현 한 후 Elastic Beanstalk가 .ebextensions새 Beanstalk 인스턴스에 대한 스크립트를 실행하지 않는다는 것을 발견했습니다 . 그 결과 새 인스턴스를 만들 때 Windows 서비스를 설치하지 못했습니다. 마침내 확장 가능한 솔루션에 도달하려면 몇 가지 더 많은 단계를 거쳐야했습니다. 최종 솔루션에 대한 자세한 내용을 원하시면 저에게 알려주십시오.

궁극적으로 Elastic Beanstalk는 확장 가능한 Windows 서비스 배포 용이 아닌 것 같습니다.


기본 솔루션

개인 프로젝트가 아니기 때문에 소스 코드를 공개하는 것이 불편하지만 현재 배포 솔루션의 기본 구조는 다음과 같습니다.

  1. 사용자 지정 EC2 AMI에는 시작시 실행되는 '부트 스트랩'프로그램이 포함되어 있습니다. 프로그램은 다음을 수행합니다.
    1.1. (구성 가능한) '배포'S3 버킷 1.2 에서 'zip'아카이브다운로드합니다
    . 다운로드 한 zip 파일을 임시 디렉토리에 추출합니다
    . 1.3. "install.bat"스크립트를 찾아서 실행합니다 (스크립트 이름도 구성 가능). 이 스크립트는 Windows 서비스를 설치하고 시작합니다.
  2. Elastic Beanstalk "인스턴스 AMI"는 부 트랩 프로그램을 사용하여 사용자 지정 AMI로 설정됩니다 ( 이 문서 참조 ).

새 코드를 배포하려면 : 설치 .zip 아카이브 (Windows 서비스 및 install.bat 파일 포함)를 S3 버킷에 업로드하고 Elastic Beanstalk 애플리케이션의 모든 EC2 인스턴스를 종료합니다. 인스턴스가 다시 생성되면 부트 스트랩 프로그램이 새로 업데이트 된 코드를 다운로드 / 설치합니다.

물론 처음부터 다시 시작하는 경우 Elastic Beanstalk 사용을 건너 뛰고 유사한 배포 체계와 함께 표준 AWS 자동 확장을 사용합니다. 결론 은 웹 애플리케이션이없는 경우 Elastic Beanstalk를 사용하지 않는다는 것입니다. 표준 AWS 자동 확장을 사용하는 것이 좋습니다.

새로운 AWS 배포 도구

Amazon은 최근 배포 문제를 해결하는 것으로 보이는 몇 가지 새로운 코드 배포 / 관리 서비스를 발표했습니다. http://aws.amazon.com/blogs/aws/code-management-and-deployment/

나는 아직 이러한 새로운 서비스를 사용하지 않았지만 (아직 출시되었는지는 확실하지 않습니다), 그들은 유망 해 보입니다.


이 질문은 한동안 해결되지 않았지만 여전히 관심을 끌기 때문에 EC2 인스턴스에 Windows 서비스를 설치하는 매우 유사한 문제에 대한 솔루션을 공유하겠습니다. 저는 Beanstalk를 사용하지 않습니다. 그 서비스는 웹 애플리케이션의 빠른 배포를 위해 더 많이 설계 되었기 때문입니다. 대신 Beanstalk가 웹 애플리케이션과 관련된 리소스를 배포하는 데 사용하는 CloudFormation을 직접 사용하고 있습니다.

스택은 기존 VPC (여러 가용 영역에 걸쳐 있음), 모든 서비스 빌드 아티팩트를 저장하는 S3 버킷 및 EC2 키 페어를 예상합니다. 템플릿은 서비스에 필요할 수있는 추가 리소스를 생성하는 방법을 설명하기 위해 Windows AMI 및 액세스 키가있는 IAM 사용자 및 작동하는 S3 버킷과 같은 몇 가지 다른 리소스를 사용하여 EC2 인스턴스를 생성합니다. 템플릿은 또한 빌드 아티팩트 S3 버킷에 업로드 된 모든 서비스 바이너리 및 구성 파일이 포함 된 압축 된 패키지의 이름을 매개 변수로 사용합니다 (우리는이를 생성하는 TeamCity 빌드 서버를 사용하지만 수동으로 패키지를 생성하고 업로드 할 수 있습니다. 강좌). 새 버전의 서비스를 빌드 할 때 새 패키지 (예 : service.v2.zip)를 만들고 새 이름으로 스택을 업데이트하면 서비스가 자동으로 업데이트됩니다. 템플릿에는 4 개 리전의 AMI ID가 포함되어 있지만 원하는 경우 언제든지 다른 리전을 추가 할 수 있습니다. 다음은 스택 템플릿입니다.

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Service stack template.",
    "Parameters": {
        "KeyPair": {
            "Type": "String",
            "Default": "MyDefaultKeys",
            "Description": "Name of EC2 Key Pair."
        },
        "ServicePackageName": {
            "Type": "String",
            "Default": "service.zip",
            "Description": "Name of the zip package of the service files."
        },
        "DeploymentBucketName": {
            "Type": "String",
            "Default": "",
            "Description": "Name of the deployment bucket where all the artifacts are."
        },
        "VPCId": {
            "Type": "String",
            "Default": "",
            "Description": "Identifier of existing VPC."
        },
        "VPCSubnets": {
            "Default": "",
            "Description": "Commaseparated list of existing subnets within the existing VPC. Could be just one.",
            "Type": "CommaDelimitedList"
        },
        "VPCSecurityGroup": {
            "Default": "",
            "Description": "Existing VPC security group. That should be the ID of the VPC's default security group.",
            "Type": "String"
        }
    },
    "Mappings": {
        "Region2WinAMI": {
            "us-east-1": { "64": "ami-40f0d32a" },
            "us-west-1": { "64": "ami-20601740" },
            "us-west-2": { "64": "ami-ff4baf9f" },
            "eu-west-1": { "64": "ami-3367d340" }
        }
    },
    "Resources": {
        "ServiceInstance": {
            "Type": "AWS::EC2::Instance",
            "Metadata": {
                "Comment": "Install Service",
                "AWS::CloudFormation::Init": {
                    "configSets": {
                        "default": [ "ServiceConfig" ]
                    },
                    "ServiceConfig": {
                        "files": {
                            "c:\\service\\settings.config": {
                                "source": { "Fn::Join": [ "/", [ "https://s3.amazonaws.com", { "Ref": "DeploymentBucketName" }, "deployments/stacks", { "Ref": "AWS::StackName" }, "templates/settings.config.mustache" ] ] },
                                "context": {
                                    "region": { "Ref": "AWS::Region" },
                                    "accesskey": { "Ref": "IAMUserAccessKey" },
                                    "secretkey": { "Fn::GetAtt": [ "IAMUserAccessKey", "SecretAccessKey" ] },
                                    "bucket": { "Ref": "BucketName" }
                                }
                            },
                            "c:\\cfn\\cfn-hup.conf": {
                                "content": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "[main]\n",
                                            "stack=",
                                            { "Ref": "AWS::StackId" },
                                            "\n",
                                            "region=",
                                            { "Ref": "AWS::Region" },
                                            "\n",
                                            "interval=1"
                                        ]
                                    ]
                                }
                            },
                            "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf": {
                                "content": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "[cfn-auto-reloader-hook]\n",
                                            "triggers=post.update\n",
                                            "path=Resources.ServiceInstance.Metadata.AWS::CloudFormation::Init\n",
                                            "action=cfn-init.exe -v -s ",
                                            { "Ref": "AWS::StackName" },
                                            " -r ServiceInstance --region ",
                                            { "Ref": "AWS::Region" },
                                            "\n"
                                        ]
                                    ]
                                }
                            }
                        },
                        "sources": {
                            "c:\\tmp\\service": { "Fn::Join": [ "/", [ "https://s3.amazonaws.com", { "Ref": "DeploymentBucketName" }, "deployments/stacks", { "Ref": "AWS::StackName" }, "artifacts/Service", { "Ref": "ServicePackageName" } ] ] }
                        },
                        "commands": {
                            "Install Service": {
                                "command": "call c:\\tmp\\service\\install.bat",
                                "ignoreErrors": "false"
                            }
                        },
                        "services": {
                            "windows": {
                                "cfn-hup": {
                                    "enabled": "true",
                                    "ensureRunning": "true",
                                    "files": [ "c:\\cfn\\cfn-hup.conf", "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf" ]
                                }
                            }
                        }
                    }
                }
            },
            "Properties": {
                "ImageId": { "Fn::FindInMap": [ "Region2WinAMI", { "Ref": "AWS::Region" }, "64" ] },
                "InstanceType": "t2.micro",
                "KeyName": { "Ref": "KeyPair" },
                "SecurityGroupIds" : [{ "Ref": "VPCSecurityGroup" }],
                "SubnetId" : { "Fn::Select": [ "0", { "Ref": "VPCSubnets" } ] },
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "<script>\n",
                                "if not exist \"C:\\logs\" mkdir C:\\logs \n",
                                "cfn-init.exe -v -s ",
                                { "Ref": "AWS::StackName" },
                                " -r ServiceInstance --region ",
                                { "Ref": "AWS::Region" },
                                " -c default \n",
                                "</script>\n"
                            ]
                        ]
                    }
                },
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1",
                        "Ebs": {
                            "DeleteOnTermination": "true",
                            "VolumeSize": "40",
                            "VolumeType": "gp2"
                        }
                    }
                ],
                "Tags": [
                    { "Key": "Name", "Value": { "Fn::Join": [ ".", [ { "Ref": "AWS::StackName" }, "service" ] ] } }
                ]
            }
        },
        "BucketName": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "AccessControl": "PublicRead"
            },
            "DeletionPolicy": "Retain"
        },
        "IAMUser": {
            "Type": "AWS::IAM::User",
            "Properties": {
                "Path": "/",
                "Groups": [ "stack-users" ],
                "Policies": [
                    {
                        "PolicyName": "giveaccesstobuckets",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [ "s3:*" ],
                                    "Resource": [ { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "BucketName" }, "/*" ] ] } ]
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "IAMUserAccessKey": {
            "Type": "AWS::IAM::AccessKey",
            "Properties": {
                "UserName": { "Ref": "IAMUser" }
            }
        }
    }
}

보시다시피 아티팩트를 복사 한 후 install.bat 배치 파일 (zip 파일에 포함됨)을 실행하여 파일을 올바른 위치로 이동하고 서비스를 등록합니다. 다음은 파일의 내용입니다.

@echo off
sc query MyService > NUL
IF ERRORLEVEL 1060 GOTO COPYANDCREATE
sc stop MyService
waitfor /T 20 ServiceStop
echo D | xcopy "c:\tmp\service" "c:\service\" /E /Y /i
GOTO END
:COPYANDCREATE
echo D | xcopy "c:\tmp\service" "c:\service\" /E /Y /i
sc create MyService binpath= "c:\service\MyService.exe" start= "auto"
:END
sc start MyService

템플릿은 또한 서비스에서 사용할 수 있도록 생성 된 다른 리소스에 대한 정보가 포함 된 구성 파일 (아티팩트 버킷에도있는 settings.config.mustache에서)을 생성합니다. 여기있어:

<appSettings>
    <add key="AWSAccessKey" value="{{accesskey}}" />
    <add key="AWSSecretKey" value="{{secretkey}}" />
    <add key="AWSRegion" value="{{region}}" />
    <add key="AWSBucket" value="{{bucket}}" />
</appSettings>

AWS 웹 콘솔 또는 CLI 에서 스택을 생성하고 나중에 업데이트합니다 .

그리고 그것은 거의 다입니다. AWS CloudFormation 웹 사이트방문 하여 서비스 및 템플릿 작업 방법에 대한 자세한 정보를 얻을 수 있습니다 .

추신 : VPC를 생성하는 템플릿도 공유하면 더 좋을 것임을 깨달았습니다. 리 전당 하나의 VPC가 있으므로 별도로 유지합니다. 원하는 경우 서비스 템플릿과 통합 할 수 있지만 이는 새 스택을 생성 할 때마다 새 VPC도 생성됨을 의미합니다. 다음은 VPC 템플릿입니다.

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "VPC stack template.",
    "Mappings": {
        "Region2AZ": {
            "us-east-1": { "AZ": [ "us-east-1a", "us-east-1b", "us-east-1d" ] },
            "us-west-1": { "AZ": [ "us-west-1b", "us-west-1c" ] },
            "us-west-2": { "AZ": [ "us-west-2a", "us-west-2b", "us-west-2c" ] },
            "eu-west-1": { "AZ": [ "eu-west-1a", "eu-west-1b", "eu-west-1c" ] }
        }
    },
    "Conditions": {
        "RegionHas3Zones": { "Fn::Not" : [ { "Fn::Equals" : [ { "Ref": "AWS::Region" }, "us-west-1" ] } ] }
    },
    "Resources": {
        "VPC": {
            "Type": "AWS::EC2::VPC",
            "Properties": {
                "CidrBlock": "10.0.0.0/16",
                "EnableDnsSupport" : "true",
                "EnableDnsHostnames" : "true"
            }
        },
        "VPCSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Security group for VPC.",
                "VpcId": { "Ref": "VPC" }
            }
        },
        "Subnet0": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": { "Ref": "VPC" },
                "CidrBlock": "10.0.0.0/24",
                "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::FindInMap": [ "Region2AZ", { "Ref": "AWS::Region" }, "AZ" ] } ] }
            }
        },
        "Subnet1": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": { "Ref": "VPC" },
                "CidrBlock": "10.0.1.0/24",
                "AvailabilityZone": { "Fn::Select": [ "1", { "Fn::FindInMap": [ "Region2AZ", { "Ref": "AWS::Region" }, "AZ" ] } ] }
            }
        },
        "Subnet2": {
            "Type": "AWS::EC2::Subnet",
            "Condition": "RegionHas3Zones",
            "Properties": {
                "VpcId": { "Ref": "VPC" },
                "CidrBlock": "10.0.2.0/24",
                "AvailabilityZone": { "Fn::Select": [ "2", { "Fn::FindInMap": [ "Region2AZ", { "Ref": "AWS::Region" }, "AZ" ] } ] }
            }
        },
        "InternetGateway": {
            "Type": "AWS::EC2::InternetGateway",
            "Properties": {
            }
        },
        "AttachGateway": {
            "Type": "AWS::EC2::VPCGatewayAttachment",
            "Properties": {
                "VpcId": { "Ref": "VPC" },
                "InternetGatewayId": { "Ref": "InternetGateway" }
            }
        },
        "RouteTable": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": { "Ref": "VPC" }
            }
        },
        "Route": {
            "Type": "AWS::EC2::Route",
            "DependsOn": "AttachGateway",
            "Properties": {
                "RouteTableId": { "Ref": "RouteTable" },
                "DestinationCidrBlock": "0.0.0.0/0",
                "GatewayId": { "Ref": "InternetGateway" }
            }
        },
        "SubnetRouteTableAssociation0": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "SubnetId": { "Ref": "Subnet0" },
                "RouteTableId": { "Ref": "RouteTable" }
            }
        },
        "SubnetRouteTableAssociation1": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "SubnetId": { "Ref": "Subnet1" },
                "RouteTableId": { "Ref": "RouteTable" }
            }
        },
        "SubnetRouteTableAssociation2": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Condition": "RegionHas3Zones",
            "Properties": {
                "SubnetId": { "Ref": "Subnet2" },
                "RouteTableId": { "Ref": "RouteTable" }
            }
        },
        "NetworkAcl": {
            "Type": "AWS::EC2::NetworkAcl",
            "Properties": {
                "VpcId": { "Ref": "VPC" }
            }
        },
        "AllowAllInboundTCPAclEntry": {
            "Type": "AWS::EC2::NetworkAclEntry",
            "Properties": {
                "NetworkAclId": { "Ref": "NetworkAcl" },
                "RuleNumber": "100",
                "Protocol": "6",
                "RuleAction": "allow",
                "Egress": "false",
                "CidrBlock": "0.0.0.0/0",
                "PortRange": { "From": "0", "To": "65535" }
            }
        },
        "AllowAllInboundUDPAclEntry": {
            "Type": "AWS::EC2::NetworkAclEntry",
            "Properties": {
                "NetworkAclId": { "Ref": "NetworkAcl" },
                "RuleNumber": "101",
                "Protocol": "17",
                "RuleAction": "allow",
                "Egress": "false",
                "CidrBlock": "0.0.0.0/0",
                "PortRange": { "From": "0", "To": "65535" }
            }
        },
        "AllowAllOutboundTCPAclEntry": {
            "Type": "AWS::EC2::NetworkAclEntry",
            "Properties": {
                "NetworkAclId": { "Ref": "NetworkAcl" },
                "RuleNumber": "100",
                "Protocol": "6",
                "RuleAction": "allow",
                "Egress": "true",
                "CidrBlock": "0.0.0.0/0",
                "PortRange": { "From": "0", "To": "65535" }
            }
        },
        "AllowAllOutboundUDPAclEntry": {
            "Type": "AWS::EC2::NetworkAclEntry",
            "Properties": {
                "NetworkAclId": { "Ref": "NetworkAcl" },
                "RuleNumber": "101",
                "Protocol": "17",
                "RuleAction": "allow",
                "Egress": "true",
                "CidrBlock": "0.0.0.0/0",
                "PortRange": { "From": "0", "To": "65535" }
            }
        },
        "SubnetNetworkAclAssociation0": {
            "Type": "AWS::EC2::SubnetNetworkAclAssociation",
            "Properties": {
                "SubnetId": { "Ref": "Subnet0" },
                "NetworkAclId": { "Ref": "NetworkAcl" }
            }
        },
        "SubnetNetworkAclAssociation1": {
            "Type": "AWS::EC2::SubnetNetworkAclAssociation",
            "Properties": {
                "SubnetId": { "Ref": "Subnet1" },
                "NetworkAclId": { "Ref": "NetworkAcl" }
            }
        },
        "SubnetNetworkAclAssociation2": {
            "Type": "AWS::EC2::SubnetNetworkAclAssociation",
            "Condition": "RegionHas3Zones",
            "Properties": {
                "SubnetId": { "Ref": "Subnet2" },
                "NetworkAclId": { "Ref": "NetworkAcl" }
            }
        }
    },
    "Outputs": {
        "VPC": {
            "Description": "VPC",
            "Value": { "Ref": "VPC" }
        },
        "VPCSecurityGroup": {
            "Description": "VPC Security Group Id",
            "Value": { "Fn::GetAtt": [ "VPCSecurityGroup", "GroupId" ] }
        },
        "Subnet0": {
            "Description": "Subnet0 Id",
            "Value": { "Ref": "Subnet0" }
        },
        "Subnet1": {
            "Description": "Subnet1 Id",
            "Value": { "Ref": "Subnet1" }
        },
        "Subnet2": {
            "Description": "Subnet2 Id",
            "Condition": "RegionHas3Zones",
            "Value": { "Ref": "Subnet2" }
        }
    }
}

내 경험상 ebextensions를 사용하여 무엇이든 구현하면 배포에 소요되는 시간이 크게 늘어납니다. 자동 확장시 인스턴스가 회전하는 데 최대 15 분이 걸릴 수 있습니다. 목적을 거의 무너 뜨립니다.

In any event, be sure to configure the Auto Scaling Group's "Health Check Grace Period" property to something significant. For example, we use 900 (i.e. 15 minutes). Anything less and the instance never passes the health check and the scale up event fails; which makes for an unending series of attempts to scale up.

ReferenceURL : https://stackoverflow.com/questions/24686305/deploy-a-net-windows-service-with-amazon-elastic-beanstalk-with-no-web-applicat

반응형