[AWS CloudFormation] CloudFormationマクロを作成

### CloudFormationマクロとは
CloudFormationテンプレートの標準的な定義だけでは実現できない処理を、テンプレート内からLambda関数(マクロ)を呼び出すことで実現できるようにするCloudFormation拡張機能のこと

AWSTemplateFormatVersion: "2010-09-09"
Description: 
  CloudFormation Macro Create

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  CFnMacroName:
    Type: String

# ------------------------------------------------------------#
#  LambdaExecutionRole
# ------------------------------------------------------------#        
Resources:
  LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !Sub "${CFnMacroName}-LambdaExecutionRole"
      Policies:
        - PolicyName: !Sub "${CFnMacroName}-LambdaExecutionRole-Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: "arn:aws:logs:*:*:*"

              - Effect: Allow
                Action:
                  - "ssm:PutParameter"
                Resource: "*"

      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Sid: ""
            Effect: Allow
            Principal: 
              Service: "lambda.amazonaws.com"
            Action: "sts:AssumeRole"

# ------------------------------------------------------------#
#  Lambda Function for CloudFormation Macro
#  example : generate random string(10) and register SSM
# ------------------------------------------------------------#  
  LambdaFunction:
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: !Ref CFnMacroName
      Role: !GetAtt LambdaExecutionRole.Arn
      Handler: index.handler

      Code:
        ZipFile: !Sub |
          import boto3
          import string
          import random

          ssm = boto3.client('ssm')

          def handler(event, context):
            key = event['params']['Key']
            description = event['params']['Description']
            randomstr = ''.join(random.choices(string.ascii_letters + string.digits, k=10))

            ssm.put_parameter(
              Name=key,
              Value=randomstr,
              Type='SecureString',
              Description=description
            )
            return {'requestId': event['requestId'], 'status': 'success', 'fragment': randomstr}

      Runtime: "python3.6"
      MemorySize: 128
      Timeout: 5

# ------------------------------------------------------------#
#  CloudFormation Macro
# ------------------------------------------------------------#  
  CFnMacro:
    Type: "AWS::CloudFormation::Macro"
    Properties:
      FunctionName: !Ref LambdaFunction
      Name: !Ref CFnMacroName
      Description: !Ref CFnMacroName 

index.pyが作られる

これは凄いな

[AWS CloudFormation] ELBログ用のS3 Bucket作成

AWSTemplateFormatVersion: "2010-09-09"
Description:
  S3 Bucket for ELB AccessLog Create

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "S3 Bucket for ELB AccessLog Configuration"
        Parameters:
          - ELBLogBucketName

    ParameterLabels:
      ELBLogBucketName:
        default: "ELBLogBucketName"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  ELBLogBucketName:
    Type: String

# ------------------------------------------------------------#
# ELBAccountId Mappings
# ------------------------------------------------------------# 
Mappings:
  ELBAccountID:
    ap-northeast-1:
      "AccountId": ""

Resources:
# ------------------------------------------------------------#
#  S3
# ------------------------------------------------------------#        
# ELBLogBucket
  ELBLogBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Ref ELBLogBucketName

#BucketPolicy
  ELBLogBucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Ref ELBLogBucket
      PolicyDocument:
        Id: "AWSCFn-AccessLogs-Policy-20180920"
        Version: "2012-10-17"
        Statement:
          - Sid: AWSCFn-20180920
            Effect: "Allow"
            Action:
              - "s3:PutObject"
            Resource: !Sub "arn:aws:s3:::${ELBLogBucket}/AWSLogs/${AWS::AccountId}/*"
            Principal:
              AWS: !FindInMap [ ELBAccountId, !Ref "AWS::Region", AccountId ]

# ------------------------------------------------------------#                
# Output Parameters
# ------------------------------------------------------------# 
Outputs:
#ELBLogBucket
  ELBLogBucket:
    Value: !Ref ELBLogBucket
    Export:
      Name: !Ref ELBLogBucketName

ELBの管理画面で、AccessLogをS3に設定できるのね。

[AWS CloudFormation] System Managerのパラメータストアの値を登録

System Managerのパラメータストアとは、Key/Valueのパラメータを集中管理する機能

Stringタイプのパラメータを登録する場合のサンプル

AWSTemplateFormatVersion: "2010-09-09"
Description:
  SSM Parameter Create

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  MasterUserName:
    Type: String
    NoEcho: true
    MinLength: 1
    MaxLength: 16
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
    ConstraintDescription: "must begin with a letter and contain only alphanumeric characters."

# ------------------------------------------------------------#
#  SSM Parameter
# ------------------------------------------------------------# 
Resources:
  Parameter:
    Type: "AWS::SSM::Parameter"
    Properties:
      Name: "MasterUsername"
      Type: "String"
      Value: !Ref MasterUserName
      Description: "MasterUsername for RDS"

うん、これはよーわからんね。

[AWS CloudFormation] cloudwatchによるautorecovery

EC2インスタンスをCloudWatchでモニタリングし、基になるハードウェア障害またはAWSによる復旧を必要とする問題でインスタンスが正常に機能しなくなった事象を検知すると、CloudWatchが自動的にインスタンスを復旧する

cloudwatch-autorecovery.yml

AWSTemplateFormatVersion: "2010-09-09"
Description:
  Auto Recovery for EC2

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  EC2Instance:
    Type: AWS::EC2::Instance::Id

Resources:
# ------------------------------------------------------------#
#  AutoRecoveryAlarm
# ------------------------------------------------------------# 
  AutoRecoveryAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${EC2Instance}-autorecovery"
      Namespace: AWS/EC2
      MetricName: StatusCheckFailed_System
      Statistic: Minimum
      Period: 60
      EvaluationPeriods: 10
      ComparisonOperator: GreaterThanThreshold
      Threshold: 0
      AlarmActions:
        - !Sub "arn:aws:automate:${AWS::Region}:ec2:recover"
      Dimensions:
        - Name: InstanceId
          Value: !Ref EC2Instance

なるほど、これはいけるね

[AWS CloudFormation] ALB + EC2 2台構成

AWSTemplateFormatVersion: "2010-09-09"
Description:
  ALB and EC2 Instance Create

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - PJPrefix
      - Label:
          default: "InternetALB Configuration"
        Parameters:
          - InternetALBName
      - Label:
          default: "EC2Instance Configuration"
        Parameters:
          - KeyPairName
          - EC2InstanceName
          - EC2InstanceAMI
          - EC2InstanceInstanceType
          - EC2InstanceVolumeType
          - EC2InstanceVolumeSize
          - SSHAccessSourceIP

    ParameterLabels:
      IneternetALBName:
        default: "InternetALBName"
      KeyPairName:
        default: "KeyPiarName"
      EC2InstanceName:
        default: "EC2 Name"
      EC2InstanceAMI:
        default: "EC2 AMI"
      EC2InstanceInstanceType:
        default: "EC2 InstanceType"
      EC2InstanceVolumeType:
        default: "EC2 VolumeType"
      EC2InstanceVolumeSize:
        default: "EC2 VolumeSize"
      SSHAccessSourceIP:
        default: "SSH AccessSourceIP"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
#InternetALB
  InternetALBName:
    Type: String
    Default: "web"


#EC2Instance
  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Default: ""
  EC2InstanceName:
    Type: String
    Default: "web"
  EC2InstanceAMI:
    Type: String
    Default: ""
  EC2InstanceInstanceType:
    Type: String
    Default: "t2.micro"
  EC2InstanceVolumeType:
    Type: String
    Default: "gp2"
  EC2InstanceVolumeSize:
    Type: String
    Default: "30"
  SSHAccessSourceIP:
    Type: String

Resources:
# ------------------------------------------------------------#
#  IAM Role for EC2
# ------------------------------------------------------------# 
  EC2IAMRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !Sub "${PJPrefix}-${EC2InstanceName}-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"

      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
        - "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"

  EC2InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      Roles:
        - Ref: EC2IAMRole
      InstanceProfileName: !Sub "${PJPrefix}-${EC2InstanceName}-profile"

# ------------------------------------------------------------#
#  EC2Instance AZ:A
# ------------------------------------------------------------#
  EC2Instance01:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${EC2InstanceName}-01"
      ImageId: !Ref EC2InstanceAMI
      InstanceType: !Ref EC2InstanceInstanceType
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref EC2InstanceProfile
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            VolumeType: !Ref EC2InstanceVolumeType
            VolumeSize: !Ref EC2InstanceVolumeSize
      SecurityGroupIds:
        - !Ref ManagedSecurityGroup
        - !Ref WebSecurityGroup
      SubnetId: {"Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a"}
      UserData: !Base64 | 
        #! /bin/bash
        yum update -y

# ------------------------------------------------------------#
#  EC2Instance AZ:C
# ------------------------------------------------------------#
  EC2Instance02:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${EC2InstanceName}-02"
      ImageId: !Ref EC2InstanceAMI
      InstanceType: !Ref EC2InstanceInstanceType
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref EC2InstanceProfile
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            VolumeType: !Ref EC2InstanceVolumeType
            VolumeSize: !Ref EC2InstanceVolumeSize
      SecurityGroupIds:
        - !Ref ManagedSecurityGroup
        - !Ref WebSecurityGroup
      SubnetId: {"Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c"}
      UserData: !Base64 | 
        #! /bin/bash
        yum update -y

# ------------------------------------------------------------#
#  SecurityGroup for Managed
# ------------------------------------------------------------#
  ManagedSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: {"Fn::ImportValue": !Sub "${PJPrefix}-vpc"}
      GroupName: !Sub "${PJPrefix}-managed-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-managed-sg"

# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHAccessSourceIP

# ------------------------------------------------------------#
#  SecurityGroup for ALB
# ------------------------------------------------------------#
  ALBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      GroupName: !Sub "${PJPrefix}-alb-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-alb-sg"

# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"

        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: "0.0.0.0/0"

# ------------------------------------------------------------#
#  SecurityGroup for Web
# ------------------------------------------------------------#
  WebSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      GroupName: !Sub "${PJPrefix}-web-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-web-sg"

# Rule
  WebSecurityGroupIngress:
    Type: "AWS::EC2::SecurityGroupIngress"
    Properties:
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      SourceSecurityGroupId: !GetAtt [ ALBSecurityGroup, GroupId ]
      GroupId: !GetAtt [ WebSecurityGroup, GroupId ]

# ------------------------------------------------------------#
#  ElasticIP for EC2Instance01
# ------------------------------------------------------------# 
  ElasticIP01:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  ElasticIPAssociate01:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt ElasticIP01.AllocationId
      InstanceId: !Ref EC2Instance01

# ------------------------------------------------------------#
#  ElasticIP for EC2Instance02
# ------------------------------------------------------------# 
  ElasticIP02:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  ElasticIPAssociate02:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt ElasticIP02.AllocationId
      InstanceId: !Ref EC2Instance02

# ------------------------------------------------------------#
#  Target Group
# ------------------------------------------------------------#
  TargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc"}
      Name: !Sub "${PJPrefix}-${InternetALBName}-tg"
      Protocol: HTTP
      Port: 80
      HealthCheckProtocol: HTTP
      HealthCheckPath: "/"
      HealthCheckPort: "traffic-port"
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      HealthCheckTimeoutSeconds: 5
      HealthCheckIntervalSeconds: 10
      Matcher:
        HttpCode: 200
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${InternetALBName}-tg"
      TargetGroupAttributes:
        - Key: "deregistration_delay.timeout_seconds"
          Value: 300
        - Key: "stickiness.enabled"
          Value: false
        - Key: "stickiness.type"
          Value: lb_cookie
        - Key: "stickiness.lb_cookie.duration_seconds"
          Value: 86400
      Targets:
        - Id: !Ref EC2Instance01
        - Id: !Ref EC2Instance02
          Port: 80


# ------------------------------------------------------------#
#  Internet ALB
# ------------------------------------------------------------#
  InternetALB:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties:
      Name: !Sub "${PJPrefix}-${InternetALBName}-alb"
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${InternetALBName}-alb"
      Scheme: "internet-facing"
      LoadBalancerAttributes:
        - Key: "deletion_protection.enabled"
          Value: false
        - Key: "idle_timeout.timeout_seconds"
          Value: 60
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Subnets:
        - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a" }
        - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c" }

  ALBListener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      LoadBalancerArn: !Ref InternetALB
      Port: 80
      Protocol: HTTP

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
#InternetALB
  ALBDNSName:
    Value: !GetAtt InternetALB.DNSName
    Export:
      Name: !Sub "${PJPrefix}-${InternetALBName}-alb-dnsname"

#EC2Instance01
  EC2Instance01ID:
    Value: !Ref EC2Instance01
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-id"

  EC2Instance01PrivateIp:
    Value: !GetAtt EC2Instance01.PrivateIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-private-ip"

  EC2Instance01EIP:
    Value: !GetAtt EC2Instance01.PublicIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-eip"

  EC2Instance01RoleName:
    Value: !Sub "${PJPrefix}-${EC2InstanceName}-01-role"
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-role-name"

#EC2Instance02
  EC2Instance02ID:
    Value: !Ref EC2Instance02
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-id"

  EC2Instance02PrivateIp:
    Value: !GetAtt EC2Instance02.PrivateIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-private-ip"

  EC2Instance02EIP:
    Value: !GetAtt EC2Instance02.PublicIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-eip"

  EC2Instance02RoleName:
    Value: !Sub "${PJPrefix}-${EC2InstanceName}-02-role"
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-role-name"

うん、ここまでは来る。
問題はこれから。

[AWS CloudFormation] ELB + EC2 2台構成を作る

prefix: 0.0.0.0/0
amiID: ami-0ab0bbbd329f565e6

AWSTemplateFormatVersion: "2010-09-09"
Description:
  ELB and EC2 Instance Create

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - PJPrefix
      - Label:
          default: "InternetELB Configuration"
        Parameters:
          - InternetELBName
      - Label:
          default: "EC2Instance Configuration"
        Parameters:
          - KeyPairName
          - EC2InstanceName
          - EC2InstanceAMI
          - EC2InstanceInstanceType
          - EC2InstanceVolumeType
          - EC2InstanceVolumeSize
          - SSHAccessSourceIP

    ParameterLabels:
      IneternetELBName:
        default: "InternetELBName"
      KeyPairName:
        default: "KeyPiarName"
      EC2InstanceName:
        default: "EC2 Name"
      EC2InstanceAMI:
        default: "EC2 AMI"
      EC2InstanceInstanceType:
        default: "EC2 InstanceType"
      EC2InstanceVolumeType:
        default: "EC2 VolumeType"
      EC2InstanceVolumeSize:
        default: "EC2 VolumeSize"
      SSHAccessSourceIP:
        default: "SSH AccessSourceIP"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
#InternetELB
  InternetELBName:
    Type: String
    Default: "web"


#EC2Instance
  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Default: ""
  EC2InstanceName:
    Type: String
    Default: "web"
  EC2InstanceAMI:
    Type: String
    Default: ""
  EC2InstanceInstanceType:
    Type: String
    Default: "t2.micro"
  EC2InstanceVolumeType:
    Type: String
    Default: "gp2"
  EC2InstanceVolumeSize:
    Type: String
    Default: "30"
  SSHAccessSourceIP:
    Type: String

Resources:
# ------------------------------------------------------------#
#  IAM Role for EC2
# ------------------------------------------------------------# 
  EC2IAMRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !Sub "${PJPrefix}-${EC2InstanceName}-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"

      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
        - "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"

  EC2InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      Roles:
        - Ref: EC2IAMRole
      InstanceProfileName: !Sub "${PJPrefix}-${EC2InstanceName}-profile"

# ------------------------------------------------------------#
#  EC2Instance AZ:A
# ------------------------------------------------------------#
  EC2Instance01:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${EC2InstanceName}-01"
      ImageId: !Ref EC2InstanceAMI
      InstanceType: !Ref EC2InstanceInstanceType
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref EC2InstanceProfile
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            VolumeType: !Ref EC2InstanceVolumeType
            VolumeSize: !Ref EC2InstanceVolumeSize
      SecurityGroupIds:
        - !Ref ManagedSecurityGroup
        - !Ref WebSecurityGroup
      SubnetId: {"Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a"}
      UserData: !Base64 | 
        #! /bin/bash
        yum update -y

# ------------------------------------------------------------#
#  EC2Instance AZ:C
# ------------------------------------------------------------#
  EC2Instance02:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-${EC2InstanceName}-02"
      ImageId: !Ref EC2InstanceAMI
      InstanceType: !Ref EC2InstanceInstanceType
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref EC2InstanceProfile
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            VolumeType: !Ref EC2InstanceVolumeType
            VolumeSize: !Ref EC2InstanceVolumeSize
      SecurityGroupIds:
        - !Ref ManagedSecurityGroup
        - !Ref WebSecurityGroup
      SubnetId: {"Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c"}
      UserData: !Base64 | 
        #! /bin/bash
        yum update -y


# ------------------------------------------------------------#
#  SecurityGroup for Managed
# ------------------------------------------------------------#
  ManagedSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: {"Fn::ImportValue": !Sub "${PJPrefix}-vpc"}
      GroupName: !Sub "${PJPrefix}-managed-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-managed-sg"

# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHAccessSourceIP

# ------------------------------------------------------------#
#  SecurityGroup for ELB
# ------------------------------------------------------------#
  ELBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      GroupName: !Sub "${PJPrefix}-elb-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-elb-sg"

# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"

        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: "0.0.0.0/0"

# ------------------------------------------------------------#
#  SecurityGroup for Web
# ------------------------------------------------------------#
  WebSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      GroupName: !Sub "${PJPrefix}-web-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-web-sg"

# Rule
  WebSecurityGroupIngress:
    Type: "AWS::EC2::SecurityGroupIngress"
    Properties:
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      SourceSecurityGroupId: !GetAtt [ ELBSecurityGroup, GroupId ]
      GroupId: !GetAtt [ WebSecurityGroup, GroupId ]

# ------------------------------------------------------------#
#  ElasticIP for EC2Instance01
# ------------------------------------------------------------# 
  ElasticIP01:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  ElasticIPAssociate:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt ElasticIP01.AllocationId
      InstanceId: !Ref EC2Instance01

# ------------------------------------------------------------#
#  ElasticIP for EC2Instance02
# ------------------------------------------------------------# 
  ElasticIP02:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

  ElasticIPAssociate:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt ElasticIP02.AllocationId
      InstanceId: !Ref EC2Instance02

# ------------------------------------------------------------#
#  InternetELB
# ------------------------------------------------------------#
  InternetELB:
    Type: "AWS::ElasticLoadBalancing::LoadBalancer"
    Properties:
      LoadBalancerName: !Sub "${PJPrefix}-${InternetELBName}-elb"
      Scheme: "internet-facing"
      CrossZone: true
      HealthCheck:
        Target: "TCP:80"
        HealthyThreshold: 2
        UnhealthyThreshold: 2
        Interval: 30
        Timeout: 5
      ConnectionDrainingPolicy:
        Enabled: true
        Timeout: 300
      Listeners:
        - LoadBalancerPort: 80
          InstancePort: 80
          Protocol: HTTP
      Instances:
        - !Ref EC2Instance01
        - !Ref EC2Instance02
      SecurityGroups:
        - !Ref ELBSecurityGroup
      Subnets:
        - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a" }
        - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c" }

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
#InternetELB
  ELBDNSName:
    Value: !GetAtt InternetELB.DNSName
    Export:
      Name: !Sub "${PJPrefix}-${InternetELBName}-elb-dnsname"

#EC2Instance01
  EC2InstanceID:
    Value: !Ref EC2Instance01
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-id"

  EC2InstancePrivateIp:
    Value: !GetAtt EC2Instance01.PrivateIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-private-ip"

  EC2Instance01EIP:
    Value: !GetAtt EC2Instance01.PublicIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-eip"

  EC2InstanceRoleName:
    Value: !Sub "${PJPrefix}-${EC2InstanceName}-01-role"
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-01-role-name"

#EC2Instance02
  EC2InstanceID:
    Value: !Ref EC2Instance02
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-id"

  EC2InstancePrivateIp:
    Value: !GetAtt EC2Instance02.PrivateIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-private-ip"

  EC2Instance02EIP:
    Value: !GetAtt EC2Instance02.PublicIp
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-eip"

  EC2InstanceRoleName:
    Value: !Sub "${PJPrefix}-${EC2InstanceName}-02-role"
    Export:
      Name: !Sub "${PJPrefix}-${EC2InstanceName}-02-role-name"

$ ssh ec2-user@* -i ~/.ssh/*.pem

OK, Nice

[Docker] docker-composeでDjangoの開発環境構築

Dockerfile

FROM python:3

ENV PYTHONUNBUFFERED 1

RUN mkdir /code

WORKDIR /code

COPY requirements.txt /code/

RUN pip install -r requirements.txt

COPY . /code/

requirements.txt

Django==2.0
psycopg2

docker-compose.yml

version: '3'
services:
  db:
    image: postgres
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

$ sudo docker-compose run web django-admin.py startproject webpj .
AttributeError: module ‘collections’ has no attribute ‘Iterator’

なんやこれーーーーーーーー

[Docker] docker-composeでRailsの開発環境構築

Dockerfile

FROM ruby:2.3.7

RUN apt-get update -qq && apt-get install -y build-essential nodejs

RUN mkdir /app

WORKDIR /app

COPY Gemfile /app/Gemfile

COPY Gemfile.lock /app/Gemfile.lock

RUN bundle install

COPY . /app

Gemfile

source 'https://rubygems.org'
gem 'rails', '5.0.0.1'

Gemfile.lockの作成
$ touch Gemfile.lock

docker-compose.yml

version: '3'
services:
  web:
    build: .
    command: bundle exec rails server -p 3000 -b 0.0.0.0
    ports:
      - 3000:3000
    volumes:
      - .:/app
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:

ビルドの実行とRailsプロジェクト作成
$ sudo docker-compose run web rails new . –force –database=mysql
$ ls -la
total 84
drwxrwxr-x 12 vagrant vagrant 4096 Mar 19 02:21 .
drwxr-xr-x 16 vagrant vagrant 4096 Mar 19 01:57 ..
-rw-r–r– 1 root root 468 Mar 19 02:21 .gitignore
-rw-rw-r– 1 vagrant vagrant 211 Mar 19 02:00 Dockerfile
-rw-rw-r– 1 vagrant vagrant 1748 Mar 19 02:21 Gemfile
-rw-rw-r– 1 vagrant vagrant 4430 Mar 19 02:22 Gemfile.lock
-rw-r–r– 1 root root 374 Mar 19 02:21 README.md
-rw-r–r– 1 root root 227 Mar 19 02:21 Rakefile
drwxr-xr-x 10 root root 4096 Mar 19 02:21 app
drwxr-xr-x 2 root root 4096 Mar 19 02:22 bin
drwxr-xr-x 5 root root 4096 Mar 19 02:21 config
-rw-r–r– 1 root root 130 Mar 19 02:21 config.ru
drwxr-xr-x 2 root root 4096 Mar 19 02:21 db
-rw-rw-r– 1 vagrant vagrant 366 Mar 19 02:10 docker-compose.yml
drwxr-xr-x 4 root root 4096 Mar 19 02:21 lib
drwxr-xr-x 2 root root 4096 Mar 19 02:21 log
drwxr-xr-x 2 root root 4096 Mar 19 02:21 public
drwxr-xr-x 8 root root 4096 Mar 19 02:21 test
drwxr-xr-x 3 root root 4096 Mar 19 02:21 tmp
drwxr-xr-x 3 root root 4096 Mar 19 02:21 vendor

$ sudo docker run –rm rails_web ls -la /app
total 20
drwxr-xr-x 1 root root 4096 Mar 19 02:21 .
drwxr-xr-x 1 root root 4096 Mar 19 02:26 ..
-rw-rw-r– 1 root root 211 Mar 19 02:00 Dockerfile
-rw-rw-r– 1 root root 52 Mar 19 02:04 Gemfile
-rw-rw-r– 1 root root 0 Mar 19 02:04 Gemfile.lock
-rw-rw-r– 1 root root 366 Mar 19 02:10 docker-compose.yml

$ sudo docker-compose build
$ sudo docker run –rm rails_web ls -la /app

Railsで使用するデータベースの設定と作成
./config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: password
  host: db

$ docker-compose up
$ sudo docker-compose ps
Name Command State Ports
————————————————————-
rails_db_1 docker-entrypoint.sh mysqld Exit 0
rails_web_1 bundle exec rails server – … Exit 1

$ sudo docker-compose up -d
$ sudo docker-compose ps
Name Command State Ports
———————————————————————————————–
rails_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
rails_web_1 bundle exec rails server – … Up 0.0.0.0:3000->3000/tcp,:::3000->3000/tcp

$ sudo docker-compose run web rake db:create

$ sudo docker-compose run web bin/rails g scaffold User name:string
$ sudo docker-compose run web bundle exec rails db:migrate

### コンテナの停止、削除
$ sudo docker-compose stop
$ sudo docker-compose ps
$ sudo docker-compose down
$ sudo docker-compose up -d

なるほどー
Docker compose使うと複雑になるな…

dbのバキュームとは

VACUUM は、不要タプルが使用する領域を回収します。 PostgreSQLの通常動作では、削除されたタプルや更新によって不要となったタプルは、テーブルから物理的には削除されません。 これらのタプルはVACUUMが完了するまで存在し続けます。 そのため、特に更新頻度が多いテーブルでは、VACUUMを定期的に実行する必要があります。

[docker] docker-compose

アプリケーションのコンテナの他に、データベースなどのコンテナが必要な場合などに使用される

$ sudo docker-compose version
docker-compose version 1.16.1, build 6d1ac21
docker-py version: 2.5.1
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.1t 3 May 2016

### docker composeでアプリケーション実行環境を立ち上げる手順
1. コンテナを立ち上げるのに必要なイメージを用意(dockerfile)
2. 各コンテナを起動する際の設定をdocker-compose.ymlに定義
3. docker-compose.ymlに置いてあるディレクトリ上でdocker

– コンテナ間に通信したい場合に、サービス名で通信できる

記述例

version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
  redis:
    image: redis
volumes:
  logvolume01: {}

うおおおおおおおおおお
なんとなくわかってきた