20220115のAWSに関する記事は15件です。

Mircosoft Teamsで勤怠管理bot

はじめに 会社の上司は部下の生存確認をしたいお年頃になったようです。 在宅勤務も増え、上司は目隠しでサッカーやってる感覚でしょう。 さすがに「ピッチに出てるか否か」ぐらいは知りたい、ということだったので ビジネスチャットツールであるMicrosoft Teamsで勤怠管理botをつくってみました。 構成 部下は何かとAPIを使いたいお年頃になってきましたので、ご多分に漏れずAWSでサクッとつくります。 1.TeamsのOutgoing Webhook設定 2.Lambdaで情報を受け取って処理 3.出退勤時刻と名前をDynamoDBに保存 4.FlaskをバックエンドにDynamoDBのデータを読みこんで表示 5.上司はWeb上で勤怠管理ができるようになって楽ちん こんな感じです.1のWebhook設定をよしなにすれば、SlackでもLINEでも好きなプラットフォームで実現できます。 end2endはこんなミテクレになります。 手順詳細 上記の各手順を詳しく掘ります。 0.下準備 API Gatewayの、エンドポイントURL取得およびLambdaとのつなぎ込みに関しては、こちらの素晴らしい記事を参考にさせて頂きました。このあたりの下準備は息を吐くようにデキるようになると楽ちんです。 DynamoDBはattendance-recordという名前で、下記のキー仕様で作成しておきます。 プライマリーキー:date(string) ソートキー:name(string) 1. TeamsのOutgoing Webhook設定 Teams上での操作になります。 Teamsのチーム画面で、↑いちにのさんよんで「送信Webhookを作成」します。 そうすると、送信webhook作成画面になります。 ここで、名前はメンションするときの名前です。上記の例では「@kintai」でメンションします。 で、このコールバックURLにはAPI GatewayのエンドポイントURLを指定します。 この設定により@kintai で送信すると、API Gatewayにリーチできます。 2&3. Lambdaで情報を受け取ってDynamoDBに保存 Teamsで送信した内容が、API Gatewayを通ってLambdaに送られます。 今回はメッセージに「in」が含まれていたら「出勤」とし、「out」が含まれていたら「退勤」としました。 lambda_function.py import json import datetime import boto3 from boto3.dynamodb.conditions import Key, Attr #-- get dynamodb object dynamodb = boto3.resource('dynamodb') table_name = "attendance-record" def lambda_handler(event, context): #-- 0. check event(for debug) print(json.dumps(event)) #-- 1. extract information timestamp=event['localTimestamp'] #2022-01-13T14:13:42.108816 date_today=timestamp.split('T')[0] #2022-01-13 time=timestamp.split('T')[-1].split('.')[0] #14:13:42 name=event['from']['name'] in_out=in_out.replace('kintai','') #[ハマった場所] #-- 2. attendance / leaving if 'in' in in_out: status='出勤' msg=msg_name+'今日も楽しんでいきましょう!' elif 'out' in in_out: status='退勤' msg=msg_name+'今日もおつかれさまでした。飲みすぎ注意!' else: return { 'type': 'message', 'text': 'ERROR! put [in] or [out] !' } #-- 3. item store to dynamodb dynamotable = dynamodb.Table(table_name) keydata={ 'date':date_today, 'name':name } try: option = { 'Key': keydata, 'UpdateExpression': 'set #in_out=:in_out', 'ExpressionAttributeNames': { '#in_out': status, }, 'ExpressionAttributeValues': { ':in_out': time, }, } res=dynamotable.update_item(**option) print('Successed!') except Exception as e: print("Failed.") print(e) #-- 4. return return { 'type': 'message', 'text': msg } 受け取った情報から,下記の手順でLambda処理します。 1. 時間と名前,メッセージ内容を受け取る 2. メッセージ内容に基づき加工 3.DynamoDBに格納 1のハマッた場所について 「@kintai」の文字列に'in'が入っており、2の条件分岐で出勤ステータスにしか入りませんでした。このままだと一生出勤社畜地獄奴なので、kintaiの文字を消すようにしました。 3のupdate_itemについて DynamoDBのプライマリーキーにdate、ソートキーにnameを指定しており、出退勤はPキーとSキーに合致したアイテムに対してupdate_itemで打刻するようにしてます。 絶対もっと美しく書く方法がありそう... Lambdaおわり。 4.DynamoDBのデータをWeb表示(Flask) DynamoDBのデータをweb表示させます。バックエンドはFlaskで。 上司が分かれば良いので、テーブル表示させるだけの超シンプル構成です。 せめてもの見やすさのために「本日」と「今月全体」を分けて表示させるようにしてます。 app.py from flask import Flask, render_template import datetime import boto3 import pandas as pd import pytz app = Flask(__name__) jst = pytz.timezone('Asia/Tokyo') table_name='attendance-record' @app.route('/',methods=["GET","POST"]) def index(): df_today, df_month=get_table_from_dynamodb(table_name) return render_template("/index.html", date=df_today['date'].iat[0], tables_today=df_today.to_html(classes='data', header="true",index=False), tables_month=df_month.to_html(classes='data', header="true",index=False), ) def get_table_from_dynamodb(table_name): today=jst.localize(datetime.datetime.today()).strftime('%Y-%m-%d') #-- dynamodb設定 & 全データ取り出し dynamodb = boto3.resource('dynamodb',region_name='ap-northeast-1') table = dynamodb.Table(table_name) response = table.scan() #-- db to df df = pd.json_normalize(response['Items']).fillna('-') df_today=df[df['date']==today] df_month=df[df['date'].str.contains(today[:7])] #2022-01 #-- reindex column(today:出勤時間順, month:日付順にソート) df_today=df_today.reindex(columns=['date','name','出勤','退勤']).sort_values('出勤') df_month=df_month.reindex(columns=['date','name','出勤','退勤']).sort_values('date') return df_today,df_month if __name__ == '__main__': app.run(debug=True) DynamoDB->PandasDataFrameにできるpd.json_normalize() PandasDataFrame->HTML Tableにできるdf.to_html() なんて便利なのでしょうか。ふんだんに使わせていただきました。 そしてHTMLのトップ画面はこんな感じ。説明不要なシンプルさです。 index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>attendance record</title> </head> <body> <h2>今日の日付 {{date}}</h2> {% for table in tables_today %} {{ table|safe }} {% endfor %} <h3>-- ↓今月の勤務実績↓ --</h3> {% for table in tables_month %} {{ table|safe }} {% endfor %} </body> </html> あとはFlaskのページを上司が確認するだけですね! いつでもどこでも見られるようにWebサーバーにデプロイしてます。 まとめ 今回はMicrosoft Teamsで勤怠情報を送信し、Web上で表示する「勤怠管理bot」を作りました。 API-Lambda-DBという割とよくある(?)構成でやってみました。 botという割には応答が定型文 なのは、要改善ということで。 上司の疲労軽減になりますように。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ROSA検証用のVPCを作る(CFnで)

「2回以上やることは、なんでも自動化されるべきだ」 本当にそう思います。 ROSAの検証の度、AWS CLIで作っているもの Deployment models for AWS Network Firewall より。これのALBが無いやつ。 作っているROSAはSTS有効化、Multi-AZ、自前のVPC... 全部CFnにしてやるー(^q^) AWSTemplateFormatVersion: "2010-09-09" Description: VPC, Subnet Metadata: "AWS::CloudFormation::Interface": ParameterGroups: - Label: default: "Project Name Prefix" Parameters: - ClusterPrefix - Label: default: "Network Configuration" Parameters: - VPCCIDR - FirewallSubnetACIDR - FirewallSubnetCCIDR - FirewallSubnetDCIDR - ProtectedSubnetACIDR - ProtectedSubnetCCIDR - ProtectedSubnetDCIDR - PrivateSubnetACIDR - PrivateSubnetCCIDR - PrivateSubnetDCIDR ParameterLabels: VPCCIDR: default: "VPC CIDR" FirewallSubnetACIDR: default: "FirewallSubnetA CIDR" FirewallSubnetCCIDR: default: "FirewallSubnetC CIDR" FirewallSubnetCCIDR: default: "FirewallSubnetD CIDR" ProtectedSubnetACIDR: default: "ProtectedSubnetA CIDR" ProtectedSubnetCCIDR: default: "ProtectedSubnetC CIDR" ProtectedSubnetCCIDR: default: "ProtectedSubnetD CIDR" PrivateSubnetACIDR: default: "PrivateSubnetA CIDR" PrivateSubnetCCIDR: default: "PrivateSubnetC CIDR" PrivateSubnetCCIDR: default: "PrivateSubnetD CIDR" # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: ClusterPrefix: Type: String Default: "ROSA" VPCCIDR: Type: String Default: "10.0.0.0/16" FirewallSubnetACIDR: Type: String Default: "10.0.10.0/24" FirewallSubnetCCIDR: Type: String Default: "10.0.11.0/24" FirewallSubnetDCIDR: Type: String Default: "10.0.12.0/24" ProtectedSubnetACIDR: Type: String Default: "10.0.20.0/24" ProtectedSubnetCCIDR: Type: String Default: "10.0.21.0/24" ProtectedSubnetDCIDR: Type: String Default: "10.0.22.0/24" PrivateSubnetACIDR: Type: String Default: "10.0.30.0/24" PrivateSubnetCCIDR: Type: String Default: "10.0.31.0/24" PrivateSubnetDCIDR: Type: String Default: "10.0.32.0/24" Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# # VPC VPC: Type: "AWS::EC2::VPC" Properties: CidrBlock: !Ref VPCCIDR EnableDnsSupport: "true" EnableDnsHostnames: "true" InstanceTenancy: default Tags: - Key: Name Value: !Sub "${ClusterPrefix}-vpc" # InternetGateway InternetGateway: Type: "AWS::EC2::InternetGateway" Properties: Tags: - Key: Name Value: !Sub "${ClusterPrefix}-igw" # IGW Attach InternetGatewayAttachment: Type: "AWS::EC2::VPCGatewayAttachment" Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC # DHCPOptions DHCPOptions: Type: AWS::EC2::DHCPOptions Properties: DomainName: ap-northeast-1.compute.internal DomainNameServers: - AmazonProvidedDNS Tags: - Key: Name Value: !Sub "${ClusterPrefix}-dhcp-options" DHCPOptionsAssociation: Type: AWS::EC2::VPCDHCPOptionsAssociation Properties: VpcId: !Ref VPC DhcpOptionsId: !Ref DHCPOptions # ------------------------------------------------------------# # Subnet # ------------------------------------------------------------# # FirewallSubnetA FirewallSubnetA: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1a" CidrBlock: !Ref FirewallSubnetACIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-subnet-a" # FirewallSubnetC FirewallSubnetC: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1c" CidrBlock: !Ref FirewallSubnetCCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-subnet-c" # FirewallSubnetD FirewallSubnetD: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1d" CidrBlock: !Ref FirewallSubnetDCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-subnet-d" # ProtectedSubnetA ProtectedSubnetA: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1a" CidrBlock: !Ref ProtectedSubnetACIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-subnet-a" # ProtectedSubnetC ProtectedSubnetC: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1c" CidrBlock: !Ref ProtectedSubnetCCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-subnet-c" # ProtectedSubnetD ProtectedSubnetD: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1d" CidrBlock: !Ref ProtectedSubnetDCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-subnet-d" # PrivateSubnetA PrivateSubnetA: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1a" CidrBlock: !Ref PrivateSubnetACIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-subnet-a" # PrivateSubnetC PrivateSubnetC: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1c" CidrBlock: !Ref PrivateSubnetCCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-subnet-c" # PrivateSubnetD PrivateSubnetD: Type: "AWS::EC2::Subnet" Properties: AvailabilityZone: "ap-northeast-1d" CidrBlock: !Ref PrivateSubnetDCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-subnet-d" # ------------------------------------------------------------# # RouteTable # ------------------------------------------------------------# # IGWRouteTable IGWRouteTable: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-igw-route" # FirewallRouteTableA FirewallRouteTableA: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-route-a" # FirewallRouteTableC FirewallRouteTableC: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-route-c" # FirewallRouteTableD FirewallRouteTableD: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-route-d" # ProtectedRouteTableA ProtectedRouteTableA: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-route-a" # ProtectedRouteTableC ProtectedRouteTableC: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-route-c" # ProtectedRouteTableD ProtectedRouteTableD: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-protected-route-d" # PrivateRouteTableA PrivateRouteTableA: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-route-a" # PrivateRouteTableC PrivateRouteTableC: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-route-c" # PrivateRouteTableD PrivateRouteTableD: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-private-route-d" # ------------------------------------------------------------# # NAT Gateway # ------------------------------------------------------------# # EIP for NATGatewayA NATGatewayAEIP: Type: "AWS::EC2::EIP" Properties: Domain: vpc # NATGatewayA NATGatewayA: Type: "AWS::EC2::NatGateway" DependsOn: - NATGatewayAEIP - ProtectedSubnetA Properties: AllocationId: !GetAtt NATGatewayAEIP.AllocationId SubnetId: !Ref ProtectedSubnetA Tags: - Key: Name Value: !Sub "${ClusterPrefix}-natgw-a" # EIP for NATGatewayC NATGatewayCEIP: Type: "AWS::EC2::EIP" Properties: Domain: vpc # NATGatewayC NATGatewayC: Type: "AWS::EC2::NatGateway" DependsOn: - NATGatewayCEIP - ProtectedSubnetC Properties: AllocationId: !GetAtt NATGatewayCEIP.AllocationId SubnetId: !Ref ProtectedSubnetC Tags: - Key: Name Value: !Sub "${ClusterPrefix}-natgw-c" # EIP for NATGatewayD NATGatewayDEIP: Type: "AWS::EC2::EIP" Properties: Domain: vpc # NATGatewayD NATGatewayD: Type: "AWS::EC2::NatGateway" DependsOn: - NATGatewayDEIP - ProtectedSubnetD Properties: AllocationId: !GetAtt NATGatewayDEIP.AllocationId SubnetId: !Ref ProtectedSubnetD Tags: - Key: Name Value: !Sub "${ClusterPrefix}-natgw-d" # ------------------------------------------------------------# # Network Firewall # ------------------------------------------------------------# # AWS Network Firewall: NetworkFirewall: Type: AWS::NetworkFirewall::Firewall Properties: FirewallName: !Sub "${ClusterPrefix}-firewall" FirewallPolicyArn: !Ref EgressFirewallPolicy VpcId: !Ref VPC SubnetMappings: - SubnetId: !Ref FirewallSubnetA - SubnetId: !Ref FirewallSubnetC - SubnetId: !Ref FirewallSubnetD Tags: - Key: Name Value: !Sub "${ClusterPrefix}-network-firewall" ICMPAlertStatefulRuleGroup: Type: 'AWS::NetworkFirewall::RuleGroup' Properties: RuleGroupName: !Sub "${ClusterPrefix}-icmp-alert" Type: STATEFUL Capacity: 100 RuleGroup: RulesSource: StatefulRules: - Action: ALERT Header: Direction: ANY Protocol: ICMP Destination: ANY Source: ANY DestinationPort: ANY SourcePort: ANY RuleOptions: - Keyword: "sid:1" Tags: - Key: Name Value: !Sub "${ClusterPrefix}-icmp-alert" DomainAllowStatefulRuleGroup: Type: 'AWS::NetworkFirewall::RuleGroup' Properties: RuleGroupName: !Sub "${ClusterPrefix}-domain-allow" Type: STATEFUL Capacity: 100 RuleGroup: RuleVariables: IPSets: HOME_NET: Definition: - !Ref VPCCIDR RulesSource: RulesSourceList: TargetTypes: - HTTP_HOST - TLS_SNI # TODO : I'll fix them later... Targets: - ".nosnch.in" - ".osdsecuritylogs.splunkcloud.com" - ".quay.io" - ".quay.rhcloud.com" - ".rhel.pool.ntp.org" - ".amazonaws.com" - "cluster-id-shard.ap-northeast-1.amazonaws.com" - "api.access.redhat.com" - "api.deadmanssnitch.com" - "api.openshift.com" - "api.pagerduty.com" - "art-rhcos-ci.s3.amazonaws.com" - "cert-api.access.redhat.com" - "cloud.redhat.com" - "cm-quay-production-s3.s3.amazonaws.com" - "console.redhat.com" - "ec2.amazonaws.com" - "ec2.ap-northeast-1.amazonaws.com" - "elasticloadbalancing.ap-northeast-1.amazonaws.com" - "events.amazonaws.com" - "events.pagerduty.com" - "http-inputs-osdsecuritylogs.splunkcloud.com" - "iam.amazonaws.com" - "infogw.api.openshift.com" - "mirror.openshift.com" - "observatorium.api.openshift.com" - "openshift.org" - "quay-registry.s3.amazonaws.com" - "quayio-production-s3.s3.amazonaws.com" - "registry.access.redhat.com" - "registry.redhat.io" - "route53.amazonaws.com" - "sftp.access.redhat.com" - "sso.redhat.com" - "storage.googleapis.com" - "sts.amazonaws.com" GeneratedRulesType: "ALLOWLIST" Tags: - Key: Name Value: !Sub "${ClusterPrefix}-domain-allow" EgressFirewallPolicy: Type: AWS::NetworkFirewall::FirewallPolicy Properties: FirewallPolicyName: !Sub "${ClusterPrefix}-firewall-policy" FirewallPolicy: StatelessDefaultActions: - 'aws:forward_to_sfe' StatelessFragmentDefaultActions: - 'aws:forward_to_sfe' StatefulRuleGroupReferences: - ResourceArn: !Ref DomainAllowStatefulRuleGroup - ResourceArn: !Ref ICMPAlertStatefulRuleGroup Tags: - Key: Name Value: !Sub "${ClusterPrefix}-firewall-policy" FirewallLogFlowGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/${ClusterPrefix}/anfw/flow" FirewallLogAlertGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/${ClusterPrefix}/anfw/alert" FirewallLog: Type: AWS::NetworkFirewall::LoggingConfiguration Properties: FirewallArn: !Ref NetworkFirewall LoggingConfiguration: LogDestinationConfigs: - LogType: FLOW LogDestinationType: CloudWatchLogs LogDestination: logGroup: !Sub "/${ClusterPrefix}/anfw/flow" - LogType: ALERT LogDestinationType: CloudWatchLogs LogDestination: logGroup: !Sub "/${ClusterPrefix}/anfw/alert" # ------------------------------------------------------------# # Route # ------------------------------------------------------------# # IGWRouteA IGWRouteA: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref IGWRouteTable DestinationCidrBlock: !Ref ProtectedSubnetACIDR VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 0, !GetAtt NetworkFirewall.EndpointIds ] ] ] # IGWRouteC IGWRouteC: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref IGWRouteTable DestinationCidrBlock: !Ref ProtectedSubnetCCIDR VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 1, !GetAtt NetworkFirewall.EndpointIds ] ] ] # IGWRouteD IGWRouteD: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref IGWRouteTable DestinationCidrBlock: !Ref ProtectedSubnetDCIDR VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 2, !GetAtt NetworkFirewall.EndpointIds ] ] ] # FirewallRouteA FirewallRouteA: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref FirewallRouteTableA DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway # FirewallRouteC FirewallRouteC: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref FirewallRouteTableC DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway # FirewallRouteD FirewallRouteD: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref FirewallRouteTableD DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway # ProtectedRouteA ProtectedRouteA: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref ProtectedRouteTableA DestinationCidrBlock: "0.0.0.0/0" VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 0, !GetAtt NetworkFirewall.EndpointIds ] ] ] # ProtectedRouteC ProtectedRouteC: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref ProtectedRouteTableC DestinationCidrBlock: "0.0.0.0/0" VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 1, !GetAtt NetworkFirewall.EndpointIds ] ] ] # ProtectedRouteD ProtectedRouteD: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref ProtectedRouteTableD DestinationCidrBlock: "0.0.0.0/0" VpcEndpointId: !Select [ 1, Fn::Split: [ ":", !Select [ 2, !GetAtt NetworkFirewall.EndpointIds ] ] ] # PrivateRouteA PrivateRouteA: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref PrivateRouteTableA DestinationCidrBlock: "0.0.0.0/0" NatGatewayId: !Ref NATGatewayA # PrivateRouteC PrivateRouteC: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref PrivateRouteTableC DestinationCidrBlock: "0.0.0.0/0" NatGatewayId: !Ref NATGatewayC # PrivateRouteD PrivateRouteD: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref PrivateRouteTableD DestinationCidrBlock: "0.0.0.0/0" NatGatewayId: !Ref NATGatewayD # ------------------------------------------------------------# # RouteTable Associate # ------------------------------------------------------------# # IGWRouteTableAssociation IGWRouteTableAssociation: Type: "AWS::EC2::GatewayRouteTableAssociation" Properties: GatewayId: !Ref InternetGateway RouteTableId: !Ref IGWRouteTable # FirewallSubnetARouteTableAssociation FirewallSubnetARouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref FirewallSubnetA RouteTableId: !Ref FirewallRouteTableA # FirewallSubnetCRouteTableAssociation FirewallSubnetCRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref FirewallSubnetC RouteTableId: !Ref FirewallRouteTableC # FirewallSubnetDRouteTableAssociation FirewallSubnetDRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref FirewallSubnetD RouteTableId: !Ref FirewallRouteTableD # ProtectedSubnetARouteTableAssociation ProtectedSubnetARouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref ProtectedSubnetA RouteTableId: !Ref ProtectedRouteTableA # ProtectedSubnetCRouteTableAssociation ProtectedSubnetCRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref ProtectedSubnetC RouteTableId: !Ref ProtectedRouteTableC # ProtectedSubnetDRouteTableAssociation ProtectedSubnetDRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref ProtectedSubnetD RouteTableId: !Ref ProtectedRouteTableD # PrivateSubnetARouteTableAssociation PrivateSubnetARouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref PrivateSubnetA RouteTableId: !Ref PrivateRouteTableA # PrivateSubnetCRouteTableAssociation PrivateSubnetCRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref PrivateSubnetC RouteTableId: !Ref PrivateRouteTableC # PrivateSubnetDRouteTableAssociation PrivateSubnetDRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: SubnetId: !Ref PrivateSubnetD RouteTableId: !Ref PrivateRouteTableD # ------------------------------------------------------------# # Output Parameters # ------------------------------------------------------------# Outputs: # VPC VPC: Value: !Ref VPC Export: Name: !Sub "${ClusterPrefix}-vpc" VPCCIDR: Value: !Ref VPCCIDR Export: Name: !Sub "${ClusterPrefix}-vpc-cidr" # Subnet FirewallSubnetA: Value: !Ref FirewallSubnetA Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-a" FirewallSubnetACIDR: Value: !Ref FirewallSubnetACIDR Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-a-cidr" FirewallSubnetC: Value: !Ref FirewallSubnetC Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-c" FirewallSubnetCCIDR: Value: !Ref FirewallSubnetCCIDR Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-c-cidr" FirewallSubnetD: Value: !Ref FirewallSubnetD Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-d" FirewallSubnetDCIDR: Value: !Ref FirewallSubnetDCIDR Export: Name: !Sub "${ClusterPrefix}-firewall-subnet-d-cidr" ProtectedSubnetA: Value: !Ref ProtectedSubnetA Export: Name: !Sub "${ClusterPrefix}-protected-subnet-a" ProtectedSubnetACIDR: Value: !Ref ProtectedSubnetACIDR Export: Name: !Sub "${ClusterPrefix}-protected-subnet-a-cidr" ProtectedSubnetC: Value: !Ref ProtectedSubnetC Export: Name: !Sub "${ClusterPrefix}-protected-subnet-c" ProtectedSubnetCCIDR: Value: !Ref ProtectedSubnetCCIDR Export: Name: !Sub "${ClusterPrefix}-protected-subnet-c-cidr" ProtectedSubnetD: Value: !Ref ProtectedSubnetD Export: Name: !Sub "${ClusterPrefix}-protected-subnet-d" ProtectedSubnetDCIDR: Value: !Ref ProtectedSubnetDCIDR Export: Name: !Sub "${ClusterPrefix}-protected-subnet-d-cidr" PrivateSubnetA: Value: !Ref PrivateSubnetA Export: Name: !Sub "${ClusterPrefix}-private-subnet-a" PrivateSubnetACIDR: Value: !Ref PrivateSubnetACIDR Export: Name: !Sub "${ClusterPrefix}-private-subnet-a-cidr" PrivateSubnetC: Value: !Ref PrivateSubnetC Export: Name: !Sub "${ClusterPrefix}-private-subnet-c" PrivateSubnetCCIDR: Value: !Ref PrivateSubnetCCIDR Export: Name: !Sub "${ClusterPrefix}-private-subnet-c-cidr" PrivateSubnetD: Value: !Ref PrivateSubnetD Export: Name: !Sub "${ClusterPrefix}-private-subnet-d" PrivateSubnetDCIDR: Value: !Ref PrivateSubnetDCIDR Export: Name: !Sub "${ClusterPrefix}-private-subnet-d-cidr" # Route FirewallRouteTableA: Value: !Ref FirewallRouteTableA Export: Name: !Sub "${ClusterPrefix}-firewall-route-a" FirewallRouteTableC: Value: !Ref FirewallRouteTableC Export: Name: !Sub "${ClusterPrefix}-firewall-route-c" FirewallRouteTableD: Value: !Ref FirewallRouteTableD Export: Name: !Sub "${ClusterPrefix}-firewall-route-d" ProtectedRouteTableA: Value: !Ref ProtectedRouteTableA Export: Name: !Sub "${ClusterPrefix}-protected-route-a" ProtectedRouteTableC: Value: !Ref ProtectedRouteTableC Export: Name: !Sub "${ClusterPrefix}-protected-route-c" ProtectedRouteTableD: Value: !Ref ProtectedRouteTableD Export: Name: !Sub "${ClusterPrefix}-protected-route-d" PrivateRouteTableA: Value: !Ref PrivateRouteTableA Export: Name: !Sub "${ClusterPrefix}-private-route-a" PrivateRouteTableC: Value: !Ref PrivateRouteTableC Export: Name: !Sub "${ClusterPrefix}-private-route-c" PrivateRouteTableD: Value: !Ref PrivateRouteTableD Export: Name: !Sub "${ClusterPrefix}-private-route-d" # VPCe NetworkFirewallVPCeA: Value: !Select [ 1, Fn::Split: [ ":", !Select [ 0, !GetAtt NetworkFirewall.EndpointIds ] ] ] Export: Name: !Sub "${ClusterPrefix}-network-firewall-a" NetworkFirewallVPCeC: Value: !Select [ 1, Fn::Split: [ ":", !Select [ 1, !GetAtt NetworkFirewall.EndpointIds ] ] ] Export: Name: !Sub "${ClusterPrefix}-network-firewall-c" NetworkFirewallVPCeD: Value: !Select [ 1, Fn::Split: [ ":", !Select [ 2, !GetAtt NetworkFirewall.EndpointIds ] ] ] Export: Name: !Sub "${ClusterPrefix}-network-firewall-d" 愚痴:NetworkFirewallをCFnから作ったとき、VPCeのIdが取れない 以下の通り、リストで返しやがるので、ちょっと不格好だけど組み込み関数を駆使した。 AWS::NetworkFirewall::FirewallのReturn valuesの仕様 EndpointIds The unique IDs of the firewall endpoints for all of the subnets that you attached to the firewall. The subnets are not listed in any particular order. For example: ["us-west-2c:vpce-111122223333", "us-west-2a:vpce-987654321098", "us-west-2b:vpce-012345678901"]. 同じように困っている人 AWS CloudFormation deployment of AWS Network Firewall Custom ResourceでLambdaをcallする手順に案内されていて笑った やったこと Value: !Select [ 1, Fn::Split: [ ":", !Select [ 0, !GetAtt NetworkFirewall.EndpointIds ] ] ] 注意事項 Productionで使わないこと インストールにコケても泣かないこと 私がこの記事をROSA側の変更に合わせてメンテすることはない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws lambda + python3.9 + selenium (python 旧バージョンで止まった人向け)

対象者 aws lambda + python3.9 で Layers に headlesschrome + selenium を使って動かなかった渋い経験がある人(127 エラーに泣いた日々) 現在 python3.7 で動かしているけど、いつ AWS から見限られるかでおびえている人 ※ python の書き方や、aws lambda の使い方云々については取り上げてません(参考記事だけは残してます) 前置き(どうでもいい人はスキップ) ふとしたきっかけはこちらの記事 この記事を見た時、Docker のことはよくわかっていないけれど、Docker イメージ(OS+必要なアプリケーションや実行ファイルをまとめたもの)を作って ECR に配置すると、Lambda で使えるようになったよ!ということらしい その時は、いまいちピンと来てなかったが、、、 ある日ネットサーフィンしていると以下に出会う 脳内再生(docker を使うと chrome + chromedriver あと必要なライブラリも docker イメージにぶち込んで動かしたら動くようになったんだZE!) 頭の片隅にはあったけど、先人の方が実績を作ってくれたというならば、試すしかないということで試した結果をこちらにまとめました これを読んで実践すると、、、あなたはこうなるだろう それ解決できるようになったよ Docker ならね 説明下手の説明より参考記事をくれ! 人の記事を読むうえで、必要な情報の取捨選択はとても重要になると思っている 特にこういう記事を書くときお酒飲みながら書いている以上、参考になるかは怪しい部分があったりする そうなると記事を参考にするより元ネタを追ったほうが手っ取り早いと思ったので、参考になった記事を真っ先に乗せておきます Docker で試すきっかけをくれた git serverless.yml は残念ながら取り組んでない Dockerfile をコピペするだけで大体うまくいくような気がする不思議 とはいえ、使いたい python のバージョンはあると思うので、使いたいものを選ぶと良い 費用対効果であれば、arm64 だけど chrome が提供されていないので、 chromium + chromedriver でエキサイティングしたい人には向いているのかもしれない(※試してないので適当書いてます) Docker でプロセス停止ってどうすりゃいいの?で検索した記事 読もうとしたけど、Docker Desktop の ごみ箱アイコンで停止できたのでパソコンを電源ボタン長押しで停止する外道になりました Dockerfile を作って、ローカル環境で作るようにしたけどその後どうすりゃええねん ってなった時にフローを理解できた記事、「Amazon ECRにpush」が困りどころを救ってくれました lambda python 3.7 -> 3.9 移行やってくよ! ではでは本題はこちらから始めます(ごめんなさい結構飲んだ上で、飲みながら書いてます) 開発環境 windows10 インストールしているOfficeが古すぎて移行できない aws-cli ver 2 以降 ver1 だとコマンドが動かないので注意、流し見した記事にバージョンのこと書いて無くてコマンドなくて困った Docker 4.2.x だと最近結構ヤバめの不具合でたのでアップデートしてね とりあえず今の最新バージョンで良いと思う VSCode Power Shell とか必須 結論 今まで、レイヤーにヘッダーレスchrome置いて、aws コンソールからファイル修正みたいなことはできなくなる ローカルファイルでファイルを編集、Docker イメージを作成、ECR に登録 ECR に登録した Docker イメージを Lambda でキックするような形になる とはいえ、Amazon Linux 2 だとどうにもこうにもできないから仕方がないのかな、、、(いい方法があれば教えてほしい) Dockerfile の準備 ベースはこちらを参考にしながら以下のようなファイルにしました FROM public.ecr.aws/lambda/python@sha256:b8fb2628d7622a94b53c041d4c0cd14e001fbf97452c528fe9421fe7dae35aba as build RUN yum install -y unzip && \ curl -Lo "/tmp/chromedriver.zip" "https://chromedriver.storage.googleapis.com/97.0.4692.71/chromedriver_linux64.zip" && \ curl -Lo "/tmp/chrome-linux.zip" "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F938549%2Fchrome-linux.zip?alt=media" && \ unzip /tmp/chromedriver.zip -d /opt/ && \ unzip /tmp/chrome-linux.zip -d /opt/ FROM public.ecr.aws/lambda/python@sha256:b8fb2628d7622a94b53c041d4c0cd14e001fbf97452c528fe9421fe7dae35aba RUN yum install atk cups-libs gtk3 libXcomposite alsa-lib \ libXcursor libXdamage libXext libXi libXrandr libXScrnSaver \ libXtst pango at-spi2-atk libXt xorg-x11-server-Xvfb \ xorg-x11-xauth dbus-glib dbus-glib-devel -y COPY app.py requirements.txt hogefuga.json ${LAMBDA_TASK_ROOT}/ RUN pip install --requirement requirements.txt ENV HOGE=fuga COPY --from=build /opt/chrome-linux /opt/chrome COPY --from=build /opt/chromedriver /opt/ CMD [ "app.lambda_handler" ] 違いは requirements.txt を使って環境を構築したかったので、その前に LAMBDA_TASK_ROOT に必要なファイルをコピーしたこと 過去に実装した lambda でディレクトリ直下にファイルを置いているケースだと、LAMBDA_TASK_ROOT にファイルをコピーしないと実行できなくなるので注意してね! AWS で環境変数を設定している場合、うまく読み込まなくなるので、とりあえず動かす程度で良いならば ENV で指定すると回避できる。 ただ、 docker-compose とかもっと良い手段があるらしい が、どうすればいいかいまいちピンとこない(ご教授いただけるととてもうれしいです) ソースファイルの修正 ヘッドレス chrome の時に指定していたオプションと、chrome 用のオプションに若干の違いがあるので、その誤差を埋める必要がある ※ 上記を参考にDockerfileを作った場合は、chrome や chromedriver のパスも直さないと動かないので注意 Dockerfile を使ってローカル環境で動作確認 docker build -t ${PJ名} . docker run -p 9000:8080 ${PJ名} 起動した後はコマンドプロンプトとかで以下の URL にアクセスすれば ローカル環境でLambda の動作確認ができる(-d 以降のパラメータは実装依存なので単純にキックしたときの例を残してます) curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d "{}" 成果物を ECR に登録する ローカル環境で動作確認ができた後、Docker イメージを ECR に登録する必要がある aws cli の最初の準備方法は忘れてしまったので割愛(ぐぐれば多分色々情報は出てくると思います) ECR のリポジトリを作るのは以下のコマンドを実行します aws ecr create-repository --repository-name ${PJ名} 実行が完了したときの、registryId、repositoryUri はこの後の操作で重要になるので、コピーして残しておいてください ECR で Push するには Docker にログインする必要がある(らしいです) ログイン方法は以下のコマンドを、PowerShell で用います aws --region ap-northeast-1 ecr get-login-password | docker login --password-stdin --username AWS ${registryId}.dkr.ecr.ap-northeast-1.amazonaws.com やっていることは単純でパイプ前のコマンドでパスワードを取得して、「--password-stdin」でパイプの内容をパスワードとして扱っているだけ、考えずに実行でも大体何とかなりそう 次にどのイメージを push するかの選択は以下のコマンドで Docker イメージの一覧を表示します docker images で見てもわかんねーよ!ってなるのであれば Doker で実行中に以下の画像のように Docker Desktop で稼働中の IMAGE ID を見るのも手段としてはありだと思います docker tag ${↑のID} ${repositoryUri} docker push ${repositoryUri} あとはタグを切って、push するだけで良いみたい(Git みたいな感じですね) Lambda の指定方法 文章を書こうとしたけど、画像ありで以下の記事が存在していたので割愛(車輪の再発明はやりたくない) むしろこちらを参考すると Selenium 以外はだいたい解決できると思います 最後に さて、、、書いてみましたが参考になりましたでしょうか? 今北産業だと aws-cli は ver2 をインストールする Docker イメージを ECR に push する Docker イメージを利用して Lambda 作ってキックする 上記でおしまい これであなたも「それ解決できるようになったよ Docker ならね」ってドヤれますね( ・´ー・`)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Cloud Practitioner Essential まとめ2

AWS Cloud Practitiner Essential 殴りがき AWSグローバルインフラストラクチャ 世界中でリージョンを構築 リージョンとは、データセンターがある地域のこと 各リージョンには複数のデータセンターがある 1つのリージョン内のデータセンターのグループをAZ(アベイラビリティーゾーン)と呼ぶ リージョン 地理的に分離された場所 リージョンを選択する上での要素 コンプライアンス -> どうしてもこのリージョンでないとコンプライアンスが守れない。。 近接性 -> 遠くのリージョンにアクセスしようとするとかかる時間は増える 利用可能な機能 -> AWSの新サービスは、それぞれのリージョンに適用するのに時間がかかるため、まずは1つのリージョンでサービスを開始している可能性がある。将来的には、全てのリージョンで使えるようになると考えられるが、今すぐに使いたいサービスがそのリージョンにあるとは限らない。(基本的には大丈夫) 料金 -> リージョンによっては、同じことを実現するのにかかるお金が異なることがある アベイラビリティゾーン アベイラビリティゾーンでデータセンターを分けることにより、EC2などを物理的に1つのサーバーに置かないようにする。 これにより、災害時にEC2のサーバーの一つが不能になっても、同じリージョンの異なるアベイラビリティーゾーンのサーバー上のEC2を起動し続けることができる。 2つのリージョンを選択した際は、インスタンスは同期的に実行される。 ELBはリージョンレベルで設置される = 異なるAZに対してリクエストを振り分けることが可能。 インスタンスは同期されており、同じ環境として使えるため、どのAZのインスタンスにリクエストが割り振られても処理は変わらない。 ベストプラクティス 一つのリージョンを選択した際に2つ以上のアベイラビリティゾーンでインスタンスを実行する エッジロケーション コンテンツのコピーをキャッシュして、任意の場所のユーザーに素早く配信するための場所 各国のユーザーのリクエストを低レイテンシーかつ高速でレスポンスする。 顧客の近くにリージョンが存在しない場合、わざわざ選択したリージョンにリクエストを送る訳ではなく、キャッシュやコピーをその地域におく。 Amazon Cloud Front 世界中のさまざまなリージョンからCloud Frontにコンテンツをプッシュしている。 キャッシュをここで保持できるため、リージョン外のユーザーに素早くレスポンスできる。 Amazon Route53 DNS(ドメインネームサービス) 低レイテンシーでサービスを提供するために、リクエストを適切にルーティングする AWS Outposts 十分に機能するミニリージョンがインストールしてあり、会社オリジナルの物理サーバーに配置できる。 AWSが100%所有・運用するが、会社独自の物理サーバーに置くことができる。 自分の建物内でAWSサービスを使用したい場合に使う。 この体制をハイブリットクラウドアプローチと言う。  AWSサービスを操作する方法 基本的には各サービスで提供されているAPIを叩く。APIを叩く方法は以下の方法がある。 AWSマネジメントコンソール -> ブラウザベースでAWSサービスを操作できる サービスの利用開始・サービスについての知見を増やすのに適する テスト環境 AWS請求書の表示 モニタリングの表示 非技術リソースで作業する AWS CLI(コマンドラインインターフェース) -> コマンドラインを使ってAPIを叩く 手動での操作ミスがなくなる  & 繰り返し実行できる Windows, Mac, Linuxが使える AWS SDK(ソフトウェア開発キット) -> プログラミング言語を使用して、ソースコード単位でリソースを操作できる サービスに埋め込むことができる。 ※ マネジメントコンソール・CLI,SDKは操作と管理を自分で行う方法。 AWS Elastic Beanstalk アプリケーションコードと必要な設定をAWS Elastic Beanstalkに提供すると、環境が自動で構築される。 全ての要素を個別で操作・管理する必要はない これによって、インフラ構築などに注力せず、オリジナルサービスの開発に集中できる。 以下のタスクを実行に必要なリソースが自動デプロイされる キャパシティーの調査 負荷分散 自動スケーリング アプリケーションの状態のモニタリング AWS Cloud Formation IaCのツール Json or Yamlベースの記述により、様々なインフラを定義できる 複数のリージョンに複数の全く同じ環境を構築できる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon Lexで受け答えした情報を、Lambdaを用いてDynamoDBに書き込む

はじめに Lexで答えた情報をLambdaを用いて、DynamoDBに書き込むことをやります。 流れ DynamoDBのテーブル作成 Lex作成 Lambda作成 LexにLambdaを設定 DynamoDBのテーブル作成 以下の設定で作成します。 テストですので、オンデマンドモードにして、安く済ませます。 テーブル名:Lex-Write-Lambda パーティションキー:telephoneNumber:文字列 ソートキー:date:文字列 項目:age:数値 (テーブル作成後) 項目:timeStamp:数値 (テーブル作成後) テーブルクラス:DynamoDB 標準 – IA キャパシティーモード:オンデマンド ageとtimeStampを含めた項目を作成します。 Lexの作成 bot作成 botを作成します。 名前は適当に作成し、言語は日本語に設定します。それ以外はデフォルトのままです。 インテント作成 インテント名は、bookとします。 lexとの会話の流れは以下の通りです。 予約したい日付と電話番号と年齢の情報をlexに渡します。 user「予約したいです。」  lex「あなたの電話番号を教えて下さい」 user「09011111111」  lex「予約したい日付を教えて下さい」 user「明日」  lex「年齢を教えて下さい?」 user「22歳です」  lex「2022-01-16に、電話番号09011111111の年齢22歳で予約します。よろしいでしょうか?よろしければ、はい、予約をキャンセルしたい場合、いいえとお伝え下さい」 user「はい」  lex「予約を完了しました」 発話 サンプル発話は、bookインテントが発動するトリガーとなる言葉を設定します。 スロット まず、telephoneNumberを以下の設定で作成します。 ここでポイントですが、 スロットタイプ:AMAZON.PhoneNumberは、番号のみを聞き取ります。 userが数値のみを言うと、Lexは聞き取ってくれますが、userが「09011111111です。」と文字列も含めて答えると、Lexは聞き取れなくなります。 そのため、telephoneNumberスロットの詳細オプション→サンプル発話 -オプションで、{telephoneNumber}です。」と設定することで、文字列のです`を省いた数値を聞き取ってくれるようになります。 注意 スロットを更新を押した後、スロットのプロンプト等を修正すると、先程設定したサンプル発話 -オプションが削除される場合がありますので、再度入力して更新してください。 同様に、dateとageのスロットを作成します。 必要に応じて、詳細オプション→サンプル発話 -オプションで設定しましょう。 ちなみに、AMAZON.Dateで聞き取れるのは、下記の通りです。 反応 言葉 ○ 2日後 ○ 明日 ○ 明後日 ○ 17日(未来の直近の月の17日になる) ○ 来週の月曜日 ✕ 明々後日 確認プロンプトと応答拒否 以下のように設定します。 テスト インテントを保存し、構築をクリック後、テストしてみましょう。 テスト時の検査のJSON 入力と出力の最下部の応答にjsonデータがあります。 これは、Lambdaを使用する際に、Lambdaが受け取るデータになります。 後でLambdaを作成するにあたり、Lambdaのテストで、このjsonデータを貼り付けて、Lambdaのコードを書くとスムーズにLambdaが作成できるためコピーしておきましょう。 応答 { "messages": [ { "content": "予約を完了しました。", "contentType": "PlainText" } ], "sessionState": { "dialogAction": { "type": "Close" }, "intent": { "name": "book", "slots": { "age": { "value": { "originalValue": "22", "interpretedValue": "22", "resolvedValues": [ "22" ] } }, "date": { "value": { "originalValue": "明日", "interpretedValue": "2022-01-16", "resolvedValues": [ "2022-01-16" ] } }, "telephoneNumber": { "value": { "originalValue": "09011111111", "interpretedValue": "09011111111", "resolvedValues": [ "09011111111" ] } } }, "state": "Fulfilled", "confirmationState": "Confirmed" }, "originatingRequestId": "c840623f-ac13-4290-9283-10dc9c891df7" }, 省略 } Lambdaを作成 以下の通りに作成します。 IAMロールは、シンプルなマイクロサービスを指定してください。 設定のタイムアウト時間は、3秒から1分に変更します。 Lambdaのテストイベントは、先程のlexのjsonを貼り付けておきます。 lambda 'use strict'; // 時間 // 現在時刻の取得 var dt = new Date(); // 日本の時間に修正 dt.setTime(dt.getTime() + 32400000); // 1000 * 60 * 60 * 9(hour) // 日付を数字として取り出す var year = dt.getFullYear(); var month = dt.getMonth()+1; var day = dt.getDate(); var hour = dt.getHours(); var min = dt.getMinutes(); // 値が1桁であれば '0'を追加 if (month < 10) { month = '0' + month; } if (day < 10) { day = '0' + day; } if (hour < 10) { hour = '0' + hour; } if (min < 10) { min = '0' + min; } // 出力 var dateTime = year + month + day + hour + min; console.log("現在の日付" + dateTime); exports.handler = (event, context, callback) => { try { dispatch(event, (response) => { callback(null, response); }); } catch (err) { callback(err); } }; function dispatch(intentRequest, callback) { const AWS = require("aws-sdk"); const dynamo = new AWS.DynamoDB.DocumentClient({ region: "ap-northeast-1" // DynamoDBのリージョン }); console.log('Received event:', JSON.stringify(intentRequest, null, 2)); // DynamoDBの名前 var tableName = "Lex-Write-Lambda"; const slotsLex = intentRequest.sessionState.intent.slots; // 各スロットの値 const dateLex = slotsLex.date?.value?.interpretedValue; const telephoneNumberLex = slotsLex.telephoneNumber?.value?.interpretedValue; const ageLex = slotsLex.age?.value?.interpretedValue; var item = { age: ageLex, date: dateLex, telephoneNumber: telephoneNumberLex, timeStamp: dateTime }; var params = { TableName: tableName, Item: item }; // 20歳以上か確認 if (ageLex < 20 ) { console.log("20歳未満と判定"); return callback(close([{contentType: 'PlainText', content: `ご利用は20歳以上とさせていただいております。`}], slotsLex)); } // DynamoDBに書き込み処理 dynamo.put(params).promise().then((data) => { console.log("書き込み完了"); return callback(close([{contentType: 'PlainText', content: '予約完了しました'}], slotsLex)); }).catch((err) => { console.log(err); callback(err); }); } function close(messages, slots) { return { sessionState: { dialogAction: { type: 'Close' }, intent: { name: 'book', slots, state: 'Fulfilled', }, }, messages }; } 下記の記事を参考にしました。 dispach関数は、インテントが複数あるときに、振り分ける役割があります。 LexにLambdaを設定 作成したLambdaをボットに設定します。 Lambdaの設定場所がわかりにくいですね。 Lex > ボット > ボット:Lex-Write-Lambda-bot > エイリアス > エイリアス: TestBotAlias > 日本語 (JP) インテントのフルフィルメントの詳細オプションフルフィルメントにLambda関数を使用にチェックし更新する。 テストしてみましょう。 予約完了し、DynamoDBにも保存されており、成功ですね。 20歳未満の場合、予約できず、DBに書き込まれないようになっています。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS FargateとECSの違い

AWS FargateとECSの違いについて。 AWS Fargate ECSをサーバレスで動かすための仕組み。 自分でEC2を立ててコンテナを作成するか、Fargate上にコンテナを作成するかの違いと理解した。 ちなみにAWS Fargateというサービスはなく、AWS ECSを構築する際にEC2で構築するか、Fargateで構築するか、自身で選択することになる。 料金 https://aws.amazon.com/jp/ecs/pricing/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Cloud Practitioner Essential まとめ

AWS Cloud Practitiner Essential 殴りがき クラウドコンピューティング メリット 他の人と1台のOSのリソースをシェアすることによって、必要コストを下げて提供することができる 使いたい時にすぐに使える 使わなくなったらすぐに削除できるため、オーバーコストが発生しない EC2 EC2とは サーバーをクラウドとして提供する つまり、物理サーバーを保有することなく、自分のサービスを提供できる メリット 使いたい時にすぐに使える(設定を選択するだけ) 用事が済めば、使用を停止することで、それ以上の料金が掛からなくなる(使っていた時間に対してのみの支払いとなる) コストを節約できる。 (物理サーバー)は、保有コストがかかる上、使用する前に大きく投資することとなるため、実際の使用量を越したコストが必要となる EC2は使いたい時だけ。 EC2の仕組み 作成 基本設定を含むテンプレートの選択 基本設定 = OS,アプリケーション、インスタンスタイプ(スペック) ネットワークの設定 = 通信制御・セキュリティ設定 接続 プログラム・アプリケーションから直接接続(SDKやAPIかな?) EC2インスタンスにログインしてアクセス 使用 普通のPCと同じように使いたいように使える 使いたいソフトウェアのインストール ストレージの追加 ファイルのコピーや整理 など。。  EC2インスタンスタイプ CPU,メモリ、ストレージ、ネットワーク の性能の組み合わせ 作業負荷(=ワークロード)やアプリケーション固有のニーズを考慮して選択する インスタンスファミリー 汎用 コンピューティング、メモリ、ネットワークそれぞれのリソースが同じくらい必要な時に使う それぞれどのリソース領域でも最適化を必要としないため ウェブサーバー・アプリケーションサーバー・コードリポジトリとして使われる。 多様なワークロードに適したバランス型 コンピューティング最適化 ゲームサーバー(※ ゲームをプレイする側ではなく提供する側)・ハイパフォーマンスコンピューティング(HPC)・化学モデリングなどに使われる - コンピューティング負荷(CPU負荷)の高いタスク - バッチ処理 メモリ最適化 大量のメモリを必要とするワークロードに向いている メモリはCPUがアクションするために必要な全てのデータと全ての命令を持っている。 アプリケーションは、ストレージからメモリにロードされたのちに実行可能となる。 メモリ内にロードした大規模なデータを処理するのに向いている メモリ負荷の高いタスク 高パフォーマンスデータベースに最適 DBのデータはアプリから読み込まれるために使われる。つまり、メモリから読み込まれる。 高速コンピューティング グラフィック処理・データパターンマッチング・浮動小数点の計算・ハードウェアアクセラレータ等 高パフォーマンスプロセッサの提供 ストレージ最適化 ローカルに保存されたデータをハイパフォーマンスで処理する IOPS(input/output operation per second) = 1秒間に実行できる入出力操作の回数はストレージ最適化に依存する。 分散ファイルシステム・データウェアハウジングアプリケーション 、オンライントランザクション処理などに向いている デーファウェアハウジングアプリケーションに最適 データウェアハウスとは、データを業務で使用するだけではなく、その開発者チームの知識として、意思決定などに役立てるようにして使われること。データは基本的にストレージにあるものなので、ストレージにあるデータをうまく使う(データウェアハウスを使いこなす)にはストレージ最適化が適切 EC2 料金体制 オンデマンド = 起動時間単位の支払い契約となる。 一年以上継続して実行し続ける場合は向いていない。⇨ リザーブどインスタンスなどを使うことでコスト削減できる Savings Plans = 1時間あたりの使用量を契約することで固定料金として支払うことができる。 一時間あたりの使用量上限が指定されている? 1年 or 3年の期間で契約することでコスト削減できる。 契約した使用量を超えなければ(一時間単位など)、割引が適用された料金で使用できる 契約した使用量を超えた場合、超えた分だけオンデマンド料金で支払う 契約期間を超えて実行することはできない? リザーブド インスタンス = 使用量が一定 or 予想可能な際に適している。 全額前払い。一部前払い。前払いなし オンデマンドインスタンスの割引体系。 1年 or 3年の契約。 契約期間が終了しても、EC2インスタンスは停止されず実行できる。 契約期間終了後も使用する場合、オンデマンド料金で支払う. (インスタンスを削除 or 新しいリザーブドインスタンスを購入 をしない限りオンデマンド料金が継続される) スポット インスタンス = 予備として確保されているEC2を利用できる。 AWSがEC2要領を必要とした場合、すぐに(2分前)に連絡がくる。 実行するワークが中断可能でないと使えない リクエストを行い、HOSTのキャパがない場合はリクエスト失敗。 ⇨ EC2を利用できない。 リクエストを行い、HOSTのキャパがある場合はリクエスト成功。 Dedicated Hosts = 自分のEC2インスタンスのために物理ホストを占領する。 Dedicated Hosts 以外では、一台の物理Hostsを仮想的に分割して、いろいろな人が使うEC2を確保する EC2で一番高い料金体制。 EC2 Auto Scaling ※ Auto Scaling自体は無料。ただし、実行インスタンスがスケーリングされるため、その数に応じてEC2料金が変わる。 スケールアップ インスタンスの能力を強化する。 スケールアウト ニーズに合わせて台数を増やすこと スケールイン ニーズに合わせて台数を減らすこと 2つの方法 動的スケーリング 変化する需要に対応。後手で対応する。 予測スケーリング 予測された需要に基づいて対応。 先手で対応する。 ※ どちらも同時に使える スケーリングの設定 最小キャパシティー スケールインによって減らせる最小の数(設定できる最小は1) Auto Scaling適用後すぐに作成されるインスタンスの数 必要キャパシティー 通常はこの数で運用されることを想定してる? スケールイン・スケールアウトされていない状態の設定数 何も設定していない時は最小キャパシティーと同じ数になる 最大キャパシティー スケールアウトによって増やせる最大の数 ELB (Elastic Load Balancing) リクエストを受け付け、リクエストを処理するインスタンスにルーティングする。 ELBはリージョンごとに稼働する。 ELBが一貫してリクエストを受け取る それぞれのインスタンスに割り振る ELBはEC2インスタンスがスケールアウト(auto scaling)された際、新しく作られたインスタンスから通知を受け取る 作成されたインスタンスにリクエストを割り振れるようになる スケールアップされた際は、インスタンスが終了するまでにリクエストを送らなくなる。 ただし、EC2は既に送られてきたリクエストを処理し終わるまでは終了しない。 インスタンスのurlは一つ。ELBがリクエストを仲介することになるため、リクエストを送る側は、インスタンスの数を気にすることはない。 ### メッセージングとキューイング メッセージング(= キューイング) とは、サービス間でデータをやり取りする際、一方のサービスが機能不能となっても、その間のリクエストが失われないように、バッファ(メッセージキューと呼ばれる)を間に挟み、そこでデータを一時的に保存しておくこと。 配列のキューと同じイメージ。送信側のサービスは、送信先のサービスの状態に依存せず、各サービスの状態に依存することなくリクエストができる。 SQSとSNSの使うことで、各サービスを疎結合することが可能。 サービス間(A2A) or サービスtoユーザーでメッセージを送ることができる Amazon SQS(Simple Queue Service) 二つのサービス間に設置する。いくらでもメッセージ(リクエスト)の送信、保存、受信ができる。 ※ メッセージを喪失することはない。 = 処理されるまでデータは保存される。 メッセージを送信する メッセージを保存する メッセージを受信する ソフトウェアコンポーネント間 任意のボリューム Amazon SNS(Simple Notification Service) SQSの各機能 + サービスへ通知を送信する or エンドユーザへの通知が可能。 pubsubモデル。 サーバーレス EC2は、新しいソフトウェアパッケージがリリースされるたびに、それを適用することが必要。 サーバーを管理しながら使わないといけない。 そこで、サーバーレスを使う。 サーバーレスとは、基盤・サーバー管理を意識しない。プロビジョニング・スケーリング(Auto Scaling)、高可用性の確保(マイクロサービス, メッセージングキュー)などを設計しないで使える。 サーバーレスでは、サーバーの維持を考慮することなく、サービス開発に集中できる AWS Lambda 開発したコードをLamdaにアップロードして、Lamda関数として使用する。 トリガーを用意して、トリガーが呼び出されるまではLambda関数は待機してる トリガーが呼び出されると、開発したコードがLambda環境上で実行される ただし、1つのリクエストに対しての処理 = コードの実行時間が15分未満である必要がある。 ディープラーニングは不適切。 Webサービスのバックエンドは適切。 支払いはコンピューティングに使用した時間に対してのみ発生する コンテナオーケストレーションツール Dockerコンテナの構築・運用などの自動化ツール コンテナとは、アプリケーションの実行に必要な構成・設定(実行バージョンなど)をパッケージ化している コンテナが構築されるホストはEC2インスタンス ECS 各コンテナの実行・停止などをする コンテナ内には、複数のアプリケーションがある。アプリのバージョンはコンテナによって維持されている。 clusterと呼ばれる、コンテナの名前?(実行アプリケーションの集合体)があり、それを実行・停止する 複数のEC2をまとめて実行できる。 クラスター設定をして、クラスターを起動すると、複数のEC2インスタンスが生成されるイメージ EC2はアプリケーション1つずつ。 自分達でEC2の管理をしないといけない。 EKS よくわからん。詳細は今度。 自分達でEC2の管理をしないといけない。 AWS Fargate ECS,EKS用のサーバーレスコンピューティングプラットフォーム。 ECS,EKS実行時には、EC2インスタンスが生成され、自分でサーバーの管理をしないといけないが、基盤・サーバー管理を意識したくない場合は AWS Fargateを使う。 ECS,EKSのコンテナのインスタンスにEC2を使いたくない場合に使う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ECS/FargateでBlue/Greenデプロイをしてみた

はじめに チュートリアルをなぞりながらECS/FargateでBlue/Greenデプロイをしてみたときのメモです。 デプロイ 手順 1. 事前構築手順 1-1. ネットワークの構築 Terraformで作成 VPCの作成 DNSホスト名有効化(エンドポイントのため) サブネットの作成 インターネットゲートウェイの作成 -> ルートテーブルへ追加する エンドポイント(Interface)の作成 -> エンドポイント用のSGを作成する ecr.dkr ecr.api logs エンドポイント(Gateway)の作成 -> ルーティングテーブルへ追加する s3 1-2. ALBの構築 Terraformで作成 ALB用のSG作成 ALBの作成 ターゲットグループの作成 2つ作成する(blue用とgreen用) このターゲットグループは、サービスで設定されている元のタスクにトラフィックをルーティングする 後続で作成するECSサービスで、このターゲットグループを指定する リスナーの作成 ターゲットグループにリクエストを転送するデフォルトルールが関連付けられた、ロードバランサーのリスナーを作成する 1-3. ECRの構築 Terraformで作成 リポジトリの作成 タグのイミュータビリティを有効化 同じタグでpushしても更新されない プッシュ時にスキャン 補足 ecs cliの場合push時の作成もできるが、管理上+リポジトリ設定のため、Terraformで構築する 1-4. ECSクラスターの構築 Terraformで作成 Clusterの作成 Fargateの場合 -> 「ネットワーキングのみ」 補足 Cluster: TaskとServiceをグルーピングする概念。アプリケーションごと、環境ごとに用意する。 1-5. ECSサービスの構築 Terraformで作成 ECSサービス用のSG(ALBのSGからのインバウンド) ECSサービスの作成 初回は先にタスク定義ファイルの登録が必要?(「タスク定義ファイルの更新と登録」) タスク定義バージョンの指定 タスクの数の指定( desired-count ) ex. CLIで作成する場合 ecs-service.json { "cluster": "ecs-example-cluster", "serviceName": "ecs-example-service", "taskDefinition": "ecs-task-def", "loadBalancers": [ { "targetGroupArn": "arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/ecs-example-tg1/XXXXXXXX", "containerName": "ecs-example", "containerPort": 80 } ], "launchType": "FARGATE", "schedulingStrategy": "REPLICA", "deploymentController": { "type": "CODE_DEPLOY" }, "platformVersion": "LATEST", "networkConfiguration": { "awsvpcConfiguration": { "assignPublicIp": "ENABLED", "securityGroups": [ "sg-abcd1234" ], "subnets": [ "subnet-abcd1234", "subnet-abcd5678" ] } }, "desiredCount": 2 } # 保留中でサービスが作成される $ aws ecs create-service --cli-input-json file://ecs-service.json 補足 Serviceを作成せずTaskを実行することも可能(バッチ処理など) Service: 指定したtaskDefinitionからtaskを生成する Serviceで定義するもの: ネットワーク、VPC、タスク定義 ネットワークモードで awsvpc を使う場合はプライベートサブネットを使う ECS Serviceを作成する際に「deployment_controller」の設定で「type = "CODE_DEPLOY"」を指定する 1-6. CodeDeploy Applicationの構築 Terraformで作成 ex. CLIで作成する場合 aws deploy create-application \ --application-name ecs-example-deploy-application \ --compute-platform ECS 1-7. CodeDeploy Deployment Groupの構築 Terraformで作成 Deployment Groupを作成する Blue/Greenを指定 ターゲットグループ(Blue/Green)とリスナーを指定 その他、切り替え方式などを指定 ex. CLIで作成する場合 CLIを実行するIAMの権限に注意(code deploy, pass roleが必要) deployment-group.json { "applicationName": "ecs-example-deploy-application", "autoRollbackConfiguration": { "enabled": true, "events": [ "DEPLOYMENT_FAILURE" ] }, "blueGreenDeploymentConfiguration": { "deploymentReadyOption": { "actionOnTimeout": "CONTINUE_DEPLOYMENT", "waitTimeInMinutes": 0 }, "terminateBlueInstancesOnDeploymentSuccess": { "action": "TERMINATE", "terminationWaitTimeInMinutes": 5 } }, "deploymentGroupName": "ecs-example-deploy-group", "deploymentStyle": { "deploymentOption": "WITH_TRAFFIC_CONTROL", "deploymentType": "BLUE_GREEN" }, "loadBalancerInfo": { "targetGroupPairInfoList": [ { "targetGroups": [ { "name": "ecs-example-tg1" }, { "name": "ecs-example-tg2" } ], "prodTrafficRoute": { "listenerArns": [ "arn:aws:elasticloadbalancing:region:aws_account_id:listener/app/ecs-example-alb/e5ba62739c16e642/665750bec1b03bd4" ] } } ] }, "serviceRoleArn": "arn:aws:iam::aws_account_id:role/ecsCodeDeployRole", "ecsServices": [ { "serviceName": "ecs-example-service", "clusterName": "ecs-example-cluster" } ] } $ aws deploy create-deployment-group --cli-input-json file://deployment-group.json 2. CI/CD手順 2-1. ビルド実行 GitLabRunnerなどで、コードのマージをトリガーに、①コンテナのビルドとECRへのpush+②タスク定義ファイルの更新と登録を実施する 2-1-1. コンテナのビルドとECRへのpush # 手動の場合 # イメージビルド # もしもどうしても環境ごとに変数を変えたい場合は、ARGインストラクションを使う(参考: [Use argument in Dockerfile](https://blog.lorentzca.me/use-argument-in-dockerfile/) ) $ docker build ./ -t ecs-example # (参考)ローカルで確認 $ docker run --name hogehoge ecs-example -p 8080:80 # ECRにログイン $ aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin XXX.dkr.ecr.us-east-2.amazonaws.com # タグ付け(ローカルで) # commit hash値を使う $ docker tag ecs-example:latest XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1 # ECRにプッシュ $ docker push XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1 2-2-2. タスク定義ファイルの更新と登録 タスク定義ファイルの更新 基本的には image のtagを更新していく ecs-task-def.json { "family": "ecs-task-def", "executionRoleArn": "arn:aws:iam::123456789012:role/ecs-exec-role", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "containerDefinitions": [ { "name": "ecs-example", "image": "XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1", "essential": true, "memory": 384, "memoryReservation": 128, "portMappings": [ { "containerPort": 80 } ] } ] } タスク定義ファイルの登録 file:// を忘れない aws ecs register-task-definition --cli-input-json file://ecs-task-def.json 2-2-3. appspec.yamlファイルの更新とS3アップロード appspec.yamlの更新 タスク定義のバージョン情報を更新する appspec.yaml version: 0.0 Resources: - TargetService: Type: AWS::ECS::Service Properties: TaskDefinition: "arn:aws:ecs:region:aws_account_id:task-definition/ecs-task-definition:7" LoadBalancerInfo: ContainerName: "ecs-example" ContainerPort: 80 PlatformVersion: "LATEST" appspec.yamlのアップロード $ aws s3 cp ./appspec.yaml s3://deploy-bucket/appspec.yaml 補足 Task: コンテナの集合体 TaskDefinition: docker-compose的なもの TaskDefinitionで定義するもの: タスクメモリ、CPU、コンテナ1のイメージURI・ポートマッピング・ログ設定 タスク定義パラメータはこちらを参照 2-2. デプロイ実行 事前にcreate-deployment.jsonを作成しておく(更新不要) { "applicationName": "ecs-example-deploy-application", "deploymentGroupName": "ecs-example-deploy-group", "revision": { "revisionType": "S3", "s3Location": { "bucket": "deploy-bucket", "key": "appspec.yaml", "bundleType": "YAML" } } } CodeDeployのデプロイを作成する(デプロイ実行) $ aws deploy create-deployment \ --cli-input-json file://create-deployment.json 2-3. 動作確認 テストポートで動作確認する 2-4. Blue/Green切り替え 確認が完了したらCodeDeploy画面で『トラフィックの再ルーティング』を実行する。→ロールバックの必要がないと判断したら『元のタスクセットの終了』を選択する。 参考 AWSコンテナ設計・構築[本格]入門 チュートリアル: Blue/Green デプロイを使用するサービスの作成 CodeDeployを利用したECSのデプロイをCLIから試す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS - S3の種類

クラウドプラクティショナーの勉強をしていて、S3に種類がたくさんあって覚えられないので、自身のアウトプット学習のために内容を纏める。 上が一番コストが高く、下が一番コストが低い。 S3 標準 ・頻繁にアクセスするデータ用 ・最低3つのAZにデータを保存 ・ウェブサイト、コンテンツ配信等、データ分析など、様々なユースケースに適している ・他のストレージクラスよりコストが高い。 S3 標準 - 低頻度アクセス(S3 標準 - IA) Infrequent Access = まれなアクセス ・アクセス頻度の低いデータに最適 ・最低3つのAZにデータを保存 ・S3標準と同じレベルの可用性 ・S3標準よりもストレージ料金が低いが、取り出し料金が高い S3 1ゾーン - 低頻度アクセス(S3 1ゾーン - IA) ・1つのAZにデータを保存(だから1ゾーン) ・コストを節約する必要があり、AZに障害が起きても構わない場合はこれを使う ・最悪はデータが消失するので、ローカルデータなどから復元できるようにしておく必要がある S3 Intelligent-Tiering Intelligent = 頭がいい ・アクセスする頻度が不明たったり、変化するデータに最適 ・オブジェクトごとに月単位のモニタリング料金と、オートメーション料金が発生する ・30日間連続してアクセスのなかったオブジェクトは、S3 標準 - IAに自動で移動される ・IAに移動したオブジェクトにアクセスがあると、S3 標準に自動で移動される S3 Glacier Glacier = 氷河 ・データアーカイブ用に設計された低コストストレージ ・データを取り出す(開く)のに3~5時間くらい掛かる ・迅速取り出し機能というものがあるらしく、これを使えば2~5分で取り出せる アーカイブ=ここでは古いデータの塊とかって解釈でOK S3 Glacier Deep Archive ・データを取り出す(開く)のに12時間くらい掛かる 以上がS3の種類。 学生とかでクラウドプラクティショナーの勉強している人は、Glacierとかどういう場面で使うか、想像つかないんじゃないかな。 会社のパソコンって、全従業員のパソコン操作ログや送受信したメールなどを数年~無期限で保管していたりして、内部不正や警察沙汰、訴訟等が起きた場合に、証拠として提示する義務があるんだよね。こういったデータってデータ量は莫大で且つ普段はアクセスする事がないので、S3 標準とかに置いとくとめちゃくちゃ無駄なコストになっちゃうのさ。 なのでGlacierとかに保管してコストを低く抑える必要があるわけ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Azure】Amazon EKS をジャンプスタートを使って Azure Arc に追加してみた

はじめに  こんにちは@sk_130と申します。  本記事は、クラウドサービスのAzureにおけるAzureArcを触っていきます。 執筆に際して以下の記事を参考にしています。感謝です。 Amazon EKS クラスターを Azure Arc に追加してみた Azure Arc とは オンプレミスやパブリッククラウド(GCPやAWSなど)とのハイブリッドクラウドを実現するサービスで AzureArc上で管理されたKubernetes環境(EKS, GKEなど)へAzureの一部サービスをデプロイすることが可能です。 つまり別クラウドサービスやオンプレのリソース管理やOS定期更新などのコマンド実行など 統合管理できるのがメリットです。AWSでこの手のサービスがないので、Azureが差別化できるサービスでもあります。 ちなみに、GCPだと似たようなサービスでAnthosというものがあります 簡単な操作方法、ハンズオンもここに載っています。気になる方は触ってみてください。 ただし、ブログとかではないので躓く可能性も高いです。 Azure Arc とAWS EKSの連携 EKSとはAWSのKubernetesサービスになります AWSのEKSで作ったクラスタをAzure Arcで管理します。 うまくいくとこんな感じになります。 正攻法でコンソールからポチポチ構築する場合は以下の記事が参考になると思います。 Amazon EKS クラスターを Azure Arc に追加してみた 今回はAzureが提供しているジャンプスタートを使って構築してみます Azure Arc ジャンプスタートとは Azure Arc Jumpstartプロジェクトは、「ゼロからヒーロー」のエクスペリエンスを提供するように設計されているため、AzureArcの操作をすぐに開始できます。 ジャンプスタートは、可能な限り多くの自動化、詳細なスクリーンショットとコードサンプル、およびAzure Arcプラットフォームの使用を開始する際の豊富で包括的なエクスペリエンスを組み込んだ、独立したAzureArcシナリオのステップバイステップガイドを提供します。 私たちの目標は、稼働中のAzure Arc環境をすぐにスピンアップして、インフラストラクチャがオンプレミスまたはクラウドのどこにあるかに関係なく、プラットフォームのコアバリューに集中できるようにすることです。 (以下英語ページをGoogle先生で翻訳したので若干読みずらいです) ざっくりいうと、Terraformの資材を使って、EKSの構築から簡単にできるものになっています。 Terraformの概要は以下参照 早速やってみる 以下の公式サイトに従って、作業開始 今回はAzureにVMサーバ(Ubuntu)を用意して、そこに環境を構築する流れとしています。 まず、事前準備から 公式サイトに従って、以下の準備を実施 ざっくり以下の作業を実施しました。 上記HPにリンクが貼ってあるのでそれに従うか、ググればインストール方法が出てきます。 Azureサービスプリンシパル(SP)を作成のところは、本来用意した方がいいものの なぜかアカウントの都合かうまくいかず、az loginして実行しました。 ・Azure ArcJumpstartリポジトリのクローンを作成(git clone https://github.com/microsoft/azure_arc.git) ・AWSCLIをインストールして設定 ・wgetパッケージをインストール(eksモジュールに必要) ・AWS IAMAuthenticatorをインストール ・AzureCLIをインストールするかバージョン2.25.0以降に更新(Azureって推奨AMIにCLIはいってないんだな。。) ・無料のアマゾンウェブサービスのアカウントを作成します(実際には有償アカウントを使った) ・Helm3をインストール ・Terraformをインストール 続いて、以下のコマンド入力を実施して、下準備 AzureArc対応のKubernetesの2つのリソースプロバイダーでサブスクリプションを有効にします 登録は非同期プロセスであり、登録には約10分かかる場合があります az provider register --namespace Microsoft.Kubernetes az provider register --namespace Microsoft.KubernetesConfiguration az provider register --namespace Microsoft.ExtendedLocation Azure Arc for KubernetesCLI拡張接続k8sおよびk8sをインストールします az extension add --name connectedk8s az extension add --name k8s-configuration AWSユーザーIAMキーを作成する 詳細は上記公式サイトに記載。払い出したあとVMサーバにaws configureすると後で詰まらなくて済む(認証情報の登録) 初めて実行する際は空になっているので、作成したIAMキーをもとに手打ちする aws configure AWS Access Key ID [****************73PJ]: AWS Secret Access Key [****************IuRh]: Default region name [ap-northeast-1]: Default output format [json]: AWSアクセスキーとAWSシークレットキーを表す環境変数であるAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを介してクレデンシャルを設定します。 後述するTerraformで使われる環境変数になります。以下の""を適宜変更して実行 ここで入力しなくてもTerraform実行時に聞かれるので、入れなくても動作するみたいです。 (リージョンは適宜変更のこと) export TF_VAR_AWS_ACCESS_KEY_ID="an access key" export TF_VAR_AWS_SECRET_ACCESS_KEY="a secret key" export TF_VAR_AWS_DEFAULT_REGION="us-west-2" Terraformの実行 Terraformとは?という点はこの記事では記述しませんが、.tfファイルに構築したいEKSの設計パラメータを入れておくことで コマンド実行でサーバやクラスタが立ち上がるものです。今回はデフォルトで入っているものを使いますが 適宜構築したいサーバスペックに変えたり、持っているTerraformのファイルに置き換えればよしなに動いてくれると思います。 EKSテラフォームバイナリがあるフォルダに移動します。 cd azure_arc/azure_arc_k8s_jumpstart/eks/terraform #公式にはcd azure_arc_k8s_jumpstart/eks/terraformと記載 Terraformを初期化するコマンドを実行し、作業を追跡するための状態ファイルを作成し、その後実行 terraform init terraform apply --auto-approve この作業でAWS側にクラスタが構築されます。 上記でも記載しましたが、EKSの構成(サーバ台数や設定、リージョンやサーバの名前)を変えたい場合はTerraformのファイルをいじればいいです。 各種設定を実施 公式に記載通りに実行 mkdir ~/.kube/ terraform output -raw kubeconfig > ~/.kube/config terraform output -raw config_map_aws_auth > configmap.yml kubectl apply -f configmap.yml kubectl get nodes -o wide 詳細割愛しますが、これでEKSのNodeの用意が完了です。 AWSのコンソールでNodeが立ち上がっていることを確認しました。 AzureArcに接続する 最後の作業になります。 実行中のEKSクラスターができたので、次の方法でEKSクラスターをAzureArcに接続します。 この時サービスプリンシパルのログインは割愛しています。az loginを実行しました。 Azure側にリソースグループの用意 必要に応じて以下を実行する。--name以下は任意の名前やリージョンに変えていいです az group create --name arceksdemo -l EastUS -o table AzureCLIを使用してArcバイナリをデプロイします 任意のリソースグループ名、名前を付けて構いません。 az connectedk8s connect --name arceksdemo --resource-group arceksdemo --location 'eastus' --tags 'Project=jumpstart_azure_arc_k8s' 完了すると、EKSクラスターが新しいリソースグループ内の新しいAzureArc対応のKubernetesリソースとして接続され 最初に示した接続ができます。 はまったところ kubectlが通らない AWS側の認証の問題なようでした。aws conffigureでごり押しました。 azureuser@test-eks-arc:~$ kubectl apply -f configmap.yml error: error loading config file "/home/azureuser/.kube/config": yaml: control characters azureuser@test-eks-arc:~$ sudo kubectl apply -f configmap.yml The connection to the server localhost:8080 was refused - did you specify the right host ちゃんと理解するなら、以下を読むのがいいかなと思いました Kubernetesにて複数人開発する際にぶつかったRBACの壁 終わりに これでAzureArcにEKSを登録できたものの、各種機能が使えるようになるかというとそういうわけでじゃなく ここから拡張機能の設定などをうることで、kubernetes構成情報やリソース使量料をAzure側から見れるようになります。 その作業の投稿はまたいつか・・
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

re:Invent 2021 ストレージ関連の新サービス、アップデートまとめ

re:Invent2021で発表されたストレージ関連サービスのアップデートをまとめてみました。 1/15 20:00 から JAWS-UG横浜 #41 AWS re:Invent 2021 Recap Storage でこのあたりをキャッチアップしますので是非ご参加ください Amazon EBS Snapshots Archive ビジネスコンプライアンスや規制のニーズから、EBS スナップショットを長期間 (数か月または数年) 保持する人向けの機能 Amazon Glacier などの低コストのストレージ階層に EBS スナップショットを転送 ストレージコストを最大 75% 削減 リカバリの流れ アーカイブされたスナップショットを取得し、復元(24~72 時間以内) スナップショットを使用して EBS ボリュームをリカバリ 料金 保存したデータ 1 か月 1 GB あたり 0.0125 USD 取得した GB あたり 0.03 USD 最低 90 日間の料金を請求 Recycle Bin for EBS Snapshots EBS スナップショットの「ゴミ箱」機能 保持期間(1日から1年)を指定 ゴミ箱内のスナップショットは自動的に削除 Amazon FSx for OpenZFS OpenZFSのメリット(透過的な圧縮、継続的な整合性の検証、スナップショット、copy-on-write など) 100~200 マイクロ秒のレイテンシーで最大 100 万 IOPS を、最大 4 GB/秒の非圧縮スループット、12 GB/秒の圧縮スループット、キャッシュされたデータに対する最大 12.5 GB/秒のスループットで実現 NFS プロトコル (v3、v4、v4.1、および v4.2) を介して接続 要求の非常に厳しい機械学習、EDA (Electronic Design Automation)、メディア処理、財務分析、コードリポジトリ、DevOps、およびウェブコンテンツ管理のワークロードに対処 多数の小さなファイルを操作して順次アクセスする、レイテンシーの影響を受けやすいワークロードに最適 AWS Backup の新機能 – VMware および VMware Cloud on AWS のサポート VMware オンプレミスおよび VMware CloudTM on AWS で実行される仮想マシン (VM) のデータ保護を一元化および自動化できる機能 オンプレミスおよび VMware Cloud on AWS で NFS、VMFS、および VSAN データストア上で実行される VMware ESXi 6.7.x および 7.0.x 仮想マシンをサポート 最初の完全バックアップと、永久増分バックアップがサポート バックアップが増分として保存されている場合でも、常に完全復元を行うため、復元を簡単に実行しながら、ストレージ効率コスト削減のメリットを享受 AWS Backupに Amazon S3 のサポートを追加 S3 を含めたアプリケーションのバックアップを一元的に管理できることです S3 バケットとオブジェクトを新規または既存の S3 バケットにポイントインタイム復元可能 バックアップコンプライアンスが向上 Amazon S3 が S3 ライフサイクル、S3 Intelligent-Tiering、オブジェクトタグ、オブジェクトアクセスコントロールリストの新しい S3 イベント通知を追加 オブジェクトが S3 ライフサイクルで移行または期限切れ(削除)になったとき、または S3 Intelligent-Tiering ストレージクラス内でアーカイブアクセス層またはディープアーカイブアクセス層に移動したときにトリガーされる オブジェクトタグやアクセスコントロールリスト (ACLs) への変更に対して S3 イベント通知をトリガー 適用例 Amazon DynamoDB テーブル、 AWS Glue データカタログ、またはメディアアセットマネージャーを自動的に更新して、S3 ライフサイクル設定に従って、データが、取得時間が数分または数時間のストレージクラスに移行したか、期限切れになっているかを追跡する オブジェクトタグの変更に S3 イベント通知を使用して、 AWS Lambda 関数を呼び出してイメージのサイズを変更したり、Amazon Rekognition で機械学習サービスを実行したりするアプリケーションを構築する Amazon S3 に保存されているデータのアクセス管理を簡素化 Amazon S3 に保存されているデータのアクセス管理を簡素化するために、アクセスコントロールリスト (ACL) を無効 s3 ポリシーを作成するときに、Amazon S3 コンソールポリシーエディタが IAM Access Analyzer によって強化されたセキュリティ警告、エラー、および提案を報告 Amazon S3 Glacier ストレージクラスが刷新され、Amazon S3 Glacier Flexible Retrieval になりました。ストレージ料金は 10% 引き下げられ、一括取り出しは無料です Amazon S3 Glacier ストレージクラスは Amazon S3 Glacier Flexible Retrieval という名前に変更 10% の料金値下げに加えて無料の一括検索が含まれる 大規模なデータセットを年に 1〜2 回取得する必要があり、取得コストを気にしたくない場合に最適 Amazon S3 が 3 つのストレージクラスにおける最大 31% の値下げを発表 S3 標準 – 低頻度アクセスおよび S3 ワンゾーン-低頻度アクセスのストレージ料金を最大 31% 引き下げ 2021 年 12 月 1 日に有効になり、AWS の請求書に自動的に反映 対象リージョン アジアパシフィック (東京) アジアパシフィック (大阪) アジアパシフィック (香港) アジアパシフィック (ムンバイ) アジアパシフィック (ソウル) アジアパシフィック (シンガポール) アジアパシフィック (シドニー) 米国西部 (北カリフォルニア) 南米 (サンパウロ) Amazon FSx for Lustre – Amazon S3 統合の強化 ファイルシステムとAmazon Simple Storage Service(Amazon S3)との完全な双方向同期(削除されたファイルやオブジェクトを含む) ファイルシステムを複数の S3 バケットまたはプレフィックスと同期 AWS Snow ファミリーがオフラインテープデータ移行機能の提供を開始 既存のテープベースのバックアップワークフローを変更することなく、物理テープに保存されているペタバイトのデータを AWS に移行 ネットワーク接続の制限、帯域幅の制約、および高いネットワーク接続コストがある環境から AWS にテープデータを移行
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS認定】SysOps アドミニストレーター(SOA-C02)試験受験記

はじめに 私はAWSを仕事で扱うようになって1年程度経ちます。 自分がどの程度AWSが扱えるのか、どの程度理解できているかを客観的に示してみたいと思い、2021年12月からAWSの試験を受験しています。 この記事の執筆時点では、CLFとSAAを取得しています。(どちらも2021年12月に取得) SAPに行くよりはまずはアソシエイト3冠を目指そうと思い、AWS SysOps アドミニストレーター試験を2022年の1月10日に受験しました。 この記事はSOA試験の備忘録となります。 受験対策 受験するにあたり、以下のサイトを利用し勉強しました。 AWS Certifited SysOps Administrator - Associate (SOA-C02) 試験問題サンプル AWS公式のサンプル問題です。10問しかありませんが、どのような問題が出るかを確認する程度には役に立ちます。 kws-cloud-tech ユーザー登録すれば50問まで無料で学習可能です。 受験後の感想となりますが、無料枠で出る問題は実際のSOA-C02試験で類似した問題は出ませんでした。 有料で使用できる問題には本番に似た問題があるかもしれません。 benchprep AWS公式の模擬試験です。ユーザー登録すれば20問まで無料で模擬問題が学習可能です。 これまで模擬試験はお金がかかっていたのでこれはありがたいサービスです。 SOAに限らず、他の試験の模擬問題もありますので、記載している中では一番お勧めです。 詳細は以下のページを参照してください。 ななななんと!AWS認定の模擬試験が無料になりました!! Qiitaで受験している方を見た感じでは、Udemyを使用されている方が圧倒的に多かったですが、AWS試験は受験料が若干高いので私はなるべく出費を抑えたいと思い、基本的に無料で勉強できるサイトを使用しています。 ※SOA-C02に限らずAWS試験対策としてUdemyを使用されている方が多いので、どの資料で勉強するか迷われている方は選んでみても良いと思います。 模擬問題を解いて足りない知識があれば、必要に応じて検索して調べたり、Black Belt見て確認するといった感じで勉強しました。 試験ラボ対策は普段仕事でAWSコンソール触ってるので、よほど変な問題が出なければ大丈夫だろうとタカをくくっていました。 試験結果 678点で不合格でした。おそらく4問程度足りなかったと思われます。 試験中に問題を解いてて今まで見たような問題がなく、あまり手応えがない中で進めていたので、正直微妙だろうなと思っていました。 VPCトラフィックログの見方を問われる問題も出て、VPCトラフィックログ見たことなかったので全然わからなかった。。。 VPCトラフィックログの見方 試験結果の内訳では1~5の分野でまだまだ知識が足りないことが伺えます。 足りないところは試験ガイドをもとに再度勉強する必要がありますね。 AWS Certified SysOps Administrator – Associate (SOA-C02) 試験ガイド 試験ラボでは2問それぞれ20分程度で回答できてよかったですが、出る問題によってはまったく触ったことのないサービスだったり、処理時間がかかるものがあると思われるため、1問あたり30分は見といた方が良いと思います。 終わりに 不合格の結果を受けて、やはり課金して対策するしかないか、、、と思っていたところ、本番の問題とかなり似ている問題があるサイトを発見しました。 ぶっちゃけ、このサイトで勉強していれば本番も受かっていたと思うほどの内容でしたが、若干日本語が怪しかったり、同じ問題が何回か出たりしてて色々怪しいですw 無料Amazon認定試験問題集 不合格だったので2週間ほど再受験ができませんが、さらに勉強して1月中にはリベンジを果たしたいと思います! Qiitaで参考になるページ AWS SysOps アドミニストレーター試験に合格したぞ!(SOA-C02) AWS Certified SysOps Administrator の試験勉強して「へぇ〜」って思ったものを列挙してる記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール5~

はじめに 「AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール4~」の続きです。 過去投稿分 「AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール1~」 「AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール2~」 「AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール3~」 「AWS Cloud Practitioner について勉強してわからないことをまとめた ~モジュール4~」 参考:AWS Cloud Practitioner Essentials(Japanese) インスタンスストアとAmazon Elastic Block Store(Amazon EBS) インスタンスストア ブロックレベルのストレージボリュームは、物理ハードドライブのように動作する。 EC2インスタンスのホストコンピュータに物理的にアタッチされているディスクストレージであるため、存続期間がそのインスタンスと同じ。インスタンスが削除されると、インスタンスストアのデータは失われる。 Amazon Elastic Block Store(Amazon EBS) Amazon EC2インスタンスで使用できるブロックレベルのストレージボリュームを提供するサービス。 Amazon EC2インスタンスが停止または削除されても、アタッチされたEBSボリュームのすべてのデータは使用できる。 Amazon EBS スナップショット 増分バックアップ。つまり、1回目のボリュームバックアップでは、すべてのデータがコピーされる。それ移行のバックアップでは最新のスナップショット以降に変更されたデータのブロックのみが保存されている。 増分バックアップは、バックアップを実行するたびにストレージボリューム内のすべてのデータをコピーする完全バックアップとは異なります。完全バックアップには、最新のバックアップ以降に変更されていないデータも含まれています。 Amazon Simple Storage Service(Amazon S3) オブジェクトストレージの各オブジェクトは、データ、メタデータ、キーで構成される。 データは、画像、動画、テキスト文書、またはその他の種類のファイル。 メタデータは、データの種類、使用方法、オブジェクトサイズなどの情報。 オブジェクトのキーは一意の識別子。 Amazon S3はオブジェクトレベルのストレージを提供するサービス。 データをオブジェクトとしてバケットに保存する。 画像、動画、テキストファイルなど、あらゆるタイプのファイルを Amazon S3 にアップロードできます。例えば、Amazon S3 を使用して、バックアップファイル、ウェブサイトのメディアファイル、アーカイブされたドキュメントを保存できます。Amazon S3 は、無制限のストレージ容量を提供します。Amazon S3 内のオブジェクトの最大ファイルサイズは 5 TB です。 Amazon S3 にファイルをアップロードするときに、そのファイルの可視性とアクセスを制御するアクセス許可を設定できます。Amazon S3 のバージョニング機能を使用して、オブジェクトの経時的な変更を追跡することもできます。 Amazon S3ストレージクラス 使用した分のみ料金が発生する。 ストレージクラスを選択するときは、 データの取得の頻度 データの可用性の要件 の2つの要素を考慮する S3標準 頻繁にアクセスされるデータ用の設計 最低3つのアベイラビリティーゾーンにデータを保存 S3標準 - 低頻度アクセス(S3標準 - IA) アクセス頻度の低いデータに最適 S3標準に似ているが、ストレージ料金が低く、取り出し料金が高い S3 1ゾーン - 低頻度アクセス(S3 1ゾーン - IA) 1つのアベイラビリティーゾーンにデータを保存 S3標準 - IAよりも低いストレージ料金  S3 Intelligent-Tiering アクセスパターンが不明または変化するデータに最適 オブジェクトごとに月単位の少額のモニタリング及びオートメーション料金が必要 S3 Intelligent-Tiering ストレージクラスでは、Amazon S3 によってオブジェクトのアクセスパターンがモニタリングされます。30 日間連続してアクセスがないオブジェクトは、Amazon S3 によって低頻度アクセス階層である S3 標準 – IA に自動的に移動されます。低頻度アクセス階層のオブジェクトにアクセスがあると、オブジェクトは Amazon S3 によって自動的に高頻度アクセス階層である S3 標準に移動されます。 S3 Glacier データアーカイブ用に設計された低コストのストレージ 数分から数時間以内にオブジェクトを取得可能 S3 Glacier Deep Archive 最も低コストのオブジェクトストレージクラスで、アーカイブに最適 12時間以内にオブジェクトを取得可能 Amazon Elastic File System(Amazon EFS) リージョナルサービス。 複数のアベイラビリティーゾーンにデータを保存。 ファイルストレージ 複数のクライアントが、共有ファイルフォルダに保存されているデータにアクセスできます。 AWSクラウドサービスとオンプレミスのリソースで使用できるスケーラブルなファイルシステム。 Amazon Relational Database Service(Amazon RDS) AWS クラウドでリレーショナルデータベースを実行するサービスです。 ハードウェアのプロビジョニング、データベースのセットアップ、パッチ適用、バックアップなどのタスクを自動化するマネージドサービス。 リレーショナルデータベース SQLを使用してデータの保存及びクエリを実行する。 データを簡単に把握し、一貫性を保ち、スケーラブルな方法で保存ができる。 Amazon RDS データベースエンジン Amazon Aurora PostgreSQL MySQL MariaDB Oracleデータベース Microsoft SQL Server Amazon Aurora エンタープライズ規模のリレーショナルデータベース。 MySQL及びPostgreSQLのリレーショナルデータベースと互換性がある。 標準のMySQLデータベースよりも最大5倍、標準のPostgreSQLデータベースよりも最大3倍高速です。 高可用性が求められるワークロードでは、Amazon Aurora を検討してください。このデータベースでは、3 つのアベイラビリティーゾーン間にデータのコピーを 6 つ作成してレプリケートし、データを Amazon S3 に継続的にバックアップします。 Amazon DynamoDB キーバリューデータベースサービスです。あらゆる規模で 1 桁ミリ秒のパフォーマンスを提供。 非リレーショナルデータベース 非リレーショナルデータベースは、行と列以外の構造を使用してデータを整理するため、「NoSQL データベース」と呼ばれることがあります。非リレーショナルデータベースの構造的アプローチの 1 つとして、キーバリューペアがあります。キーバリューペアでは、データは項目 (キー) で分類され、項目は属性 (バリュー) を持ちます。属性は、データの異なる特徴であると考えることができます。 Amazon Redshift ビッグデータ分析に使用できるデータウェアハウジングサービス。 多くのソースからデータを収集し、データ全体の関係性や傾向を理解するのに役立つ機能を提供する。 AWS Database Migration Service(AWS DMS) リレーショナルデータベース、非リレーショナルデータベース、及びその他のタイプのデータストアを移行できる。 ソースとターゲットのデータベース間でデータを移動します。ソースとターゲットのデータベースは、同じタイプでも異なるタイプでも使用できます。ソースデータベースは移行中でも利用可能な状態に保たれるため、データベースを利用するアプリケーションのダウンタイムを低減できます。 参考:AWS Database Migration Service のリソース その他のデータベースサービス Amazon DocumentDB MongoDBワークロードをサポートするドキュメントデータベースサービス。 Amazon Neptune グラフデータベースサービス。 レコメンデーションエンジン、不正検出、ナレッジグラフなど、高度に接続されたデータセットを使うアプリケーションを構築して実行できる。 Amazon Quantum Ledger Database (Amazon QLDB) 台帳データベースサービス。 アプリケーションデータに対して行われた全ての変更履歴を確認できる。 Amazon Managed Blockchain オープンソースフレームワークのブロックチェーンネットワークを作成および管理するために使用できるサービス。 ブロックチェーン 中央機関を使用せずに複数の当事者がトランザクションを実行し、データを共有できるようにする分散台帳システム。 Amazon ElastiCache 一般的なリクエストの読み込み時間を短縮するために、データベースの上にキャッシュレイヤーを追加するサービス。 Amazon DynamoDB Accelerator DynamoDB のインメモリキャッシュ。 応答時間を 1 桁ミリ秒からマイクロ秒に向上させるのに役立つ。 注意 自己学習のために割愛している部分があるので 公式も合わせてご確認ください。 AWS Cloud Practitioner Essentials(Japanese) 参考書籍: 図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jenkinsの罠 !? 知っておくべきJenkinsの知識

はじめに EC2にJekinsをインストールし、jenkinsのジョブを作成して実行するぞ! と意気込んでいたときのことです。 jenkinsのジョブの実行に失敗してしまいました。 私自身、jenkinsについてとても勉強になった出来事だったので、知っておくべきjenkinsの知識として残します。 事前準備 Jenkins用のEC2インスタンスを作成します。今回は、Amazon Linux 2で作成します。 EC2(Amazon Linux2)にJekinsをインストールする方法については以下記事を参考にしました。 今回、jenkinsで定型化するものは以下のようなジョブです。 ・ EC2インスタンス起動・停止 ・ 検証環境、staging、本番環境でのEC2インスタンスへのデプロイ ・ elasticsearchの全文検索インポート など そのため、jenkinsからEC2への操作を可能にするためのポリシーをアタッチします。 EC2FullAccessのポリシーをつけたIAMユーザーを作成し、認証情報のタブからアクセスキーの作成を行い、アクセスキーIDとシークレットパスワードをメモしておいてください (※作成画面以降2度と表示されないのでCSVをダウンロードしておくことをオススメします) その後、aws configureコマンドで、jenkinsインスタンスにアクセスキーの配置を行います。 (※ここに罠があるので注意) jenkinsインスタンス # 認証情報を設定 $ aws configure # 4つ聞かれるのでそれぞれ入力 1. アクセスキー 2. シークレットキー 3. region 4. output形式 => json # この配下にAWS認証情報(アクセスキー等)がある $ cd ~/.aws $ ls -la => config, credentials Jenkinsのジョブが失敗する アクセスキーの設置が終わり、jenkinsのジョブを作成し実行したところ、エラーになりました。 jenkinsのコンソール出力を見ると以下のようなエラーメッセージが・・・ unable to locate credentials. you can configure credentials by running "aws configure". AWSの認証情報が設定されていないので、aws configureを実行してください だと!! おいおい、アクセスキーはさっきちゃんと配置したはずだぞ? 設定を確認してもきちんと登録されているはず、、、と思い見てみると、、やはり設定されている。。。 jenkinsインスタンス # アクセスキー設定情報を確認 $ aws configure list => aws_access_key_id = ***************** => aws_secret_access_key = ***************** ここに罠があった 以下、私が知らなかった事実です。。。 まず、前提として、、、、 Jenkinsをインストールすると、jenkinsユーザーが作成され、EC2内の/var/lib/jenkinsがjenkinsユーザーのホームディレクトリに設定されます。 そうなんです!jenkinsのジョブを実行しているのは、EC2の中のec2-userでもなければ、rootユーザーでもありません。jenkinsユーザーだったのです。 だからEC2内のjenkinsユーザーにAWSの認証情報(アクセスキー)を設定してあげる必要があったのです。 (お気づきだと思いますが、これまでは、ec2ユーザーとrootユーザーに設定していました) 一連の流れを確認すると・・・ jenkinsインスタンス # EC2内にjenkinsディレクトリが存在することを確認 $ cd /var/lib/jenkins $ ls -a => ~~~ , jenkins, ~~ # jenkinsユーザーになる $ sudo su - jenkins # -bash-4.2$になると成功している -bash-4.2$ pwd => /var/lib/jenkins # ここで認証情報を確認すると・・・やはりなにも設定されていなかった? $ aws configure list => aws_access_key_id => aws_secret_access_key # jenkinsユーザーに対して、認証情報を設定 $ aws configure 無事、ジョブが成功しました! ジョブを実行しているのはjenkinsユーザーである どうかこれだけは忘れずに。 余談 画面上で作成したJenkinsのジョブはサーバ内jenkinsユーザーの以下に格納されているので、確認できます。 jenkinsインスタンス # jenkinstユーザーになる $ sudo su - jenkins $ ls -la => ~~, jobs, users, logs, ~~ $ cd jobs $ ls -la => 作成したジョブ一覧 # usersにはjekins上のuser一覧、logsにはジョブの実行ログが入っている こうしてサーバ内に入り、いろいろ見てみると改めて、ソフトウェアがサーバ上で実行されているんだという実感が持ててとても勉強になりました。 以上、jenkins導入後知っておきたい初期知識でした。 憎いおじさんに数時間捕まってしまいました、、、 参考 Jenkins Jenkinsをインストールしたにもかかわらず、sudo su - jenkins でjenkinsユーザーになれない場合の対処 AWS Configure AWS 設定ファイルと認証情報ファイルの設定
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CNAMEレコードとTXTレコードは共存できないので、ALIAS レコードを使う

はじめに DNS の CNAME レコードは、他のレコードと同じ値を使った共存が出来ません。RFC で定義されている、DNS の中のルールになっています。 A CNAME record is not allowed to coexist with any other data. TXT レコードやAレコードなど、種類問わずすべてのレコードと共存することが出来ません。 ELB を使って Web サービスをインターネットに公開する際に、CNAME レコードを使って公開する方法がありますが、上記の制限が問題になる場合があります。具体例を挙げましょう orenoservice.co.jp という名前でとあるWebサービスを公開している この名前は CNAME レコードとして、ELB を指している なんらかの事情で、orenoservice.co.jp の値を使って TXT レコードを作りたい (Google Search Console などのサービスを利用する際に、TXT レコードを使ったドメインの所有状況を証明する場合がある) しかし、orenoservice.co.jp は CNAMEレコードなので、TXT レコードを作成できないため、利用したいサービスが使えない こういった問題を解決するために、Route 53 では Alias レコードという機能を提供しています。Alias レコードとは、AWS 上のリソースをルーティングするための Route 53 の拡張機能となっており、これを使うことで、Alias レコードと TXT レコードが共存できます。CNAME を使った制限を回避する点を初め、さまざまなメリットがあります。詳細は次の Document に記載されています。 念のため動作確認を行ったので、備忘録として残しておきます。 CNAME と他レコードは共存できない まず、RFC で定義されている通り、CNAME と他レコードが共存できないことを確認していきましょう。 Route 53 上で、CNAME レコードを Create します。 thisistest.sugiaws.tokyo という CNAME レコードを作成します。 CNAME が作成されました。 この状態で、同じく thisistest.sugiaws.tokyo という TXT レコードを Create を試みてみます。 Error になりました。CNAME と同じ値を指定しているので、エラーになっています。 ALIAS レコードでやる では次に、ALIAS レコードでやってみましょう。Create を押して作成を進めます。 右上の Alias を ON にするのがポイントです。 Alias Record が作成されています。 この状態で TXT レコードを Create してみます。 はい、CNAME レコード違い、ALIAS レコードでは、TXT レコードと共存できていますね。 もちろん、ALIAS レコードを使って、実際にブラウザからアクセス可能です。 この検証を通じてわかったこと ALIAS レコードを使えば、他レコードと共存できる 既存の DNS サービスからの移行の手間はあるかもしれないが、移行を検討するのが良い
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む