こんにちは、広野です。
社内研修開催のため、研修期間の数日だけ受講者とのコミュニケーションに使用する使い捨てチャットサーバを Rocket.Chat を使って構築しました。AWS CloudFormation テンプレート化してあるので、前日にサクッと作って、終わったらサクッと捨てる、そんな用途に最適です。
Rocket.Chat 公式インストール手順
Rocket.Chat インストール手順は Ubuntu であれば簡単すぎて衝撃でした。EC2 の userdata に仕込んでいます。
前提とか
- VPC や マルチ AZ のパブリックサブネット、プライベートサブネット、インターネットゲートウェイは構築済み
- 独自ドメインが Route 53 ホストゾーンに登録済み
- SSL 証明書は構築するリージョンの AWS Certificate Manager で作成済み
- OS は Ubuntu 22.04 とする( Rocket.Chat は snap install でインストールする)
- EC2 への SSH アクセスは SSM とするため、セキュリティグループには 22 ポートを開けていない。が、一応キーペアも関連付けておく(キーペア作成済みであること)
- SSM セッションマネージャでの操作ログを Amazon S3 バケットに吐き出す場合、EC2 の IAM ロールに吐き出し先バケットへの put 権限を追加すること
- 完成すると、AWS CloudFormation テンプレートのパラメータで指定したドメイン名の URL で、Rocket.Chat サーバが起動した状態で立ち上がる(初期画面で、管理者ユーザの登録画面が表示されている状態)
- IPv6 非対応
アーキテクチャ
- EC2 インスタンスはプライベートサブネットに配置。シングル構成。
- ALB は SSL アクセラレータとしての意味しかない。
- Rocket.Chat は HTTP 3000 番ポートでリッスンしているので、ALB からはそこにアクセスするよう設定する。
- 図には書いていないが、Route 53 で ALB をエイリアスレコードに紐づける。
- 図には書いていないが、ALB に AWS Certificate Manager の SSL 証明書を紐づける。
AWS CloudFormation テンプレート
適宜、IAM ロールやセキュリティーグループなどは要件に応じて変更してください。ドメイン関連も不要であれば削除で。
東京リージョン Ubuntu 22.04 AMI の Image ID をベタにパラメータのデフォルト値に書いているので、適宜変更してください。
AWSTemplateFormatVersion: "2010-09-09" Description: The CloudFormation template that creates an EC2 instance, an ALB and a DNS record in Route 53 for Rocket.Chat. # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: SystemName: Type: String Description: System name. (e.g. EXAMPLE) Default: EXAMPLE MaxLength: 10 MinLength: 1 GroupName: Type: String Description: Group name. (e.g. RocketChat) Default: RocketChat MaxLength: 30 MinLength: 1 HostName: Type: String Description: Host name. (e.g. ROCKETCHAT) Default: ROCKETCHAT MaxLength: 30 MinLength: 1 VpcId: Type: AWS::EC2::VPC::Id Description: Choose a existing VPC ID you deploy the EC2 instance in. InstanceSubnet: Type: AWS::EC2::Subnet::Id Description: Choose an existing Private Subnet ID you deploy the EC2 instance in. AlbSubnet1: Type: AWS::EC2::Subnet::Id Description: Choose an existing Public Subnet ID you deploy the Application Load Balancer in. AlbSubnet2: Type: AWS::EC2::Subnet::Id Description: Choose an existing Public Subnet ID you deploy the Application Load Balancer in. ImageID: Type: String Description: OS AMI Image ID (Ubuntu) Default: ami-03f4fa076d2981b45 MaxLength: 100 MinLength: 1 InstanceType: Type: String Default: t3.small KeyPairName: Type: AWS::EC2::KeyPair::KeyName Description: Choose a existing key pair you associate with the EC2. DomainName: Type: String Description: Domain name for URL. xxxxx.xxx (e.g. example.com) Default: example.com MaxLength: 40 MinLength: 5 SubDomainName: Type: String Description: Sub domain name for URL. xxxxx.example.com Default: chat MaxLength: 20 MinLength: 1 CertificateArn: Type: String Description: ACM certificate ARN. Default: "arn:aws:acm:ap-northeast-1:xxxxxxxxxx:certificate/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" MaxLength: 128 MinLength: 10 Resources: # ------------------------------------------------------------# # EC2 # ------------------------------------------------------------# Ec2Instance: Type: AWS::EC2::Instance Properties: IamInstanceProfile: !Ref Ec2InstanceProfile ImageId: !Ref ImageID KeyName: !Ref KeyPairName InstanceType: !Ref InstanceType BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeType: gp2 VolumeSize: 40 SecurityGroupIds: - !Ref Ec2SecurityGroup SourceDestCheck: false SubnetId: !Ref InstanceSubnet Tags: - Key: Cost Value: !Ref SystemName - Key: Name Value: !Sub ${SystemName}-${HostName} UserData: Fn::Base64: !Sub | #!/bin/bash snap install rocketchat-server systemctl status snap.rocketchat-server.rocketchat-server.service systemctl status snap.rocketchat-server.rocketchat-mongo.service DependsOn: - Ec2SecurityGroup - Ec2InstanceProfile # ------------------------------------------------------------# # EC2 Security Group # ------------------------------------------------------------# Ec2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VpcId GroupDescription: Allow web access via port TCP 3000. SecurityGroupIngress: - SourceSecurityGroupId: !GetAtt AlbSecurityGroup.GroupId FromPort: 3000 IpProtocol: tcp ToPort: 3000 Tags: - Key: Cost Value: !Ref SystemName - Key: Name Value: !Sub SG-${SystemName}-${GroupName} DependsOn: - AlbSecurityGroup # ------------------------------------------------------------# # EC2 Role / Instance Profile (IAM) # ------------------------------------------------------------# Ec2Role: Type: AWS::IAM::Role Properties: RoleName: !Sub Ec2Role-${SystemName}-${GroupName} Description: This role allows EC2 instance to invoke SSM. AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore Policies: - PolicyName: !Sub Ec2S3Policy-${SystemName}-${GroupName} PolicyDocument: Version: "2012-10-17" Statement: - Action: - "s3:GetEncryptionConfiguration" - "kms:Decrypt" - "kms:GenerateDataKey" - "logs:CreateLogStream" - "logs:PutLogEvents" - "logs:DescribeLogGroups" - "logs:DescribeLogStreams" Resource: "*" Effect: Allow Ec2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: !Ref Ec2Role Path: / Roles: - !Ref Ec2Role DependsOn: - Ec2Role # ------------------------------------------------------------# # ALB # ------------------------------------------------------------# ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${SystemName}-${GroupName} Type: application IpAddressType: ipv4 LoadBalancerAttributes: - Key: deletion_protection.enabled Value: false - Key: access_logs.s3.enabled Value: false - Key: idle_timeout.timeout_seconds Value: 60 - Key: routing.http.desync_mitigation_mode Value: defensive - Key: routing.http.drop_invalid_header_fields.enabled Value: true - Key: routing.http.preserve_host_header.enabled Value: false - Key: routing.http.x_amzn_tls_version_and_cipher_suite.enabled Value: false - Key: routing.http.xff_client_port.enabled Value: false - Key: routing.http.xff_header_processing.mode Value: append - Key: routing.http2.enabled Value: true - Key: waf.fail_open.enabled Value: false Scheme: internet-facing SecurityGroups: - !GetAtt AlbSecurityGroup.GroupId Subnets: - !Ref AlbSubnet1 - !Ref AlbSubnet2 Tags: - Key: Cost Value: !Ref SystemName - Key: Name Value: !Sub ${SystemName}-${GroupName} DependsOn: - AlbSecurityGroup AlbListenerHttps: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !Ref CertificateArn DefaultActions: - TargetGroupArn: !Ref AlbListenerHttpsTargetgroup Type: forward LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 443 Protocol: HTTPS SslPolicy: ELBSecurityPolicy-2016-08 DependsOn: - ApplicationLoadBalancer AlbListenerHttpsTargetgroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub TG-${SystemName}-${GroupName} TargetType: instance HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckPort: traffic-port HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 5 IpAddressType: ipv4 Matcher: HttpCode: 200 Port: 3000 Protocol: HTTP ProtocolVersion: HTTP1 TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 300 - Key: stickiness.enabled Value: false - Key: load_balancing.algorithm.type Value: round_robin - Key: slow_start.duration_seconds Value: 0 - Key: stickiness.app_cookie.cookie_name Value: APPCOOKIE - Key: stickiness.app_cookie.duration_seconds Value: 86400 - Key: stickiness.lb_cookie.duration_seconds Value: 86400 Targets: - Id: !Ref Ec2Instance Port: 3000 UnhealthyThresholdCount: 2 VpcId: !Ref VpcId Tags: - Key: Cost Value: !Ref SystemName DependsOn: - Ec2Instance # ------------------------------------------------------------# # ALB Security Group # ------------------------------------------------------------# AlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VpcId GroupDescription: Allow access via HTTPS. SecurityGroupIngress: - CidrIp: 0.0.0.0/0 FromPort: 443 IpProtocol: tcp ToPort: 443 Tags: - Key: Cost Value: !Ref SystemName - Key: Name Value: !Sub SG-${SystemName}-${GroupName}-ALB # ------------------------------------------------------------# # Route 53 # ------------------------------------------------------------# Route53RecordA: Type: AWS::Route53::RecordSet Properties: HostedZoneName: !Sub ${DomainName}. Name: !Sub ${SubDomainName}.${DomainName}. Type: A AliasTarget: HostedZoneId: !GetAtt ApplicationLoadBalancer.CanonicalHostedZoneID DNSName: !GetAtt ApplicationLoadBalancer.DNSName DependsOn: ApplicationLoadBalancer # ------------------------------------------------------------# # Output Parameters # ------------------------------------------------------------# Outputs: # Server URL RocketChatUrl: Value: !Sub https://${SubDomainName}.${DomainName}
Rocket.Chat バージョン 4 をインストールするには
上記テンプレート内、UserData の部分を修正します。
UserData: Fn::Base64: !Sub | #!/bin/bash snap install rocketchat-server --channel=4.x/stable systemctl status snap.rocketchat-server.rocketchat-server.service systemctl status snap.rocketchat-server.rocketchat-mongo.service
snap install のコマンドに、メジャーバージョンを指定してインストールします。
まとめ
いかがでしたでしょうか?
研修用途、一時利用の環境なので構成がかなりテキトーですが、起動した状態にまでサクっと作れるのが売りです。CloudFormation での ALB の記述方法の参考にもなるかもです。
本記事が皆様のお役に立てれば幸いです。