- 投稿日:2021-03-14T23:50:48+09:00
【学習メモ】AWS Lambda
Lambda
サーバーレス。
FaaS(Functions as a Service)
AWS Lambdaはサーバーがなくても、コードを実行することで効率的なアーキテクチャを実現できるサービス。特徴
・実行基盤は全てAWSが管理
・AWSサービスと連携させることで簡単にイベントドリブンなアプリケーションを実装可能
・100ミリ秒単位でコード実行時間に対しての課金でありコスト効率が非常に高い
・オートスケール
・Python/Java/Node.js/C#/Go/Rubyで書かれたコードを実行仕組み
イベントの発生がトリガーとして、Lambdaコートが実行される。
利用モデル
Pushモデル
・AWSサービスとカスタムイベントが直接実行することによって、Lambdaへイベント通知して、コードを実行する。
※コード実行の順序は保証されないPullモデル
・LambdaはDynamoDBとKinesisなどのデータ処理へポーリングを行い、コードを実行する。
※一度ストリームに入れることによって、イベントの順序を保つことができるパーミッション
Pullモデルの場合、ストリーム側 (invocation role) と、実行側 (excution role) の両方のパーミッションが必要。
◯Execution:
・LambdaファンクションがAWSリソースにどういったアクションを実施させるかを決定する。
・指定されたIAMロールに沿ってAWSのリソースへのアクセスが許可される。
◯Invocation:
・Lambdaファンクションをどのリソースが実行できるかを決定する。
- 投稿日:2021-03-14T23:48:49+09:00
django+docker+AWS EC2+AWS S3でポートフォリオサイトをデプロイ
- 投稿日:2021-03-14T23:07:06+09:00
【初心者】Amazon VPC フローログを使ってみる
1. 目的
- AWSのセキュリティ関連サービスの復習をしている。VPCフローログについて、今さらやってみるのも…と思ったが、定期的に新機能も追加されているようなので、改めて動作確認してみる。
- ちょうど2021/3/3に、VPCフローログで取得できるフィールドが追加されたとのこと。せっかくなのでそれらを含めた確認を行う。
2. やったこと
- 検証用のVPCとインスタンスを作成する。
- VPC全体に対して、VPCフローログの取得設定を行う。
- 試験トラフィックを発生させ、VPCフローログにどのように記録されるか確認する。
3. 構成図
4. 設定手順
4.1 事前準備
- 検証用のVPCなどを作成する。(上記構成図の通り)
- VPC、パブリックサブネット、パブリックサブネット上のインスタンス(EIP付与)
- インスタンスタイプはt3.micro (Nitro世代インスタンスの場合のみ詳細に出力できるフィールドがあり、それを確認したいため)
4.2 フローログの設定
- VPC全体のフローログを取得する設定を行う。
- VPCを選択 -> アクション -> 「フローログを作成」
- 今回はAthenaでログを検索したいため、「送信先」はS3を選択する。
- ログレコード形式で「AWSのデフォルト形式」を選択すると、2021/3/3に追加されたフィールドが含まれない。そのため、「カスタム形式」を選択し、「AWSのデフォルト形式」に含まれるフィールドを全て手動で選択した上で、新しいフィールド(赤枠の4つ)を追加する。
4.3 Athena検索の設定
- S3に保存されるVPCフローログを、Athenaで検索できるようにする。
- 公式ドキュメント「Amazon VPC フローログのクエリ」に従い設定する。
- 基本的に手順通り行えばよいが、テーブル作成時に新しく追加したフィールド(4つ)を含める。
# テーブルの作成 CREATE EXTERNAL TABLE IF NOT EXISTS vpc_flow_logs ( version int, account string, interfaceid string, sourceaddress string, destinationaddress string, sourceport int, destinationport int, protocol int, numpackets int, numbytes bigint, starttime int, endtime int, action string, logstatus string, pkt_src_aws_service string, pkt_dst_aws_service string, flow_direction string, traffic_path int ) PARTITIONED BY (`date` date) ROW FORMAT DELIMITED FIELDS TERMINATED BY ' ' LOCATION 's3://[BUCKETNAME]/AWSLogs/[ACCOUNTID]/vpcflowlogs/ap-northeast-1/' TBLPROPERTIES ("skip.header.line.count"="1"); # パーティションの作成 ALTER TABLE vpc_flow_logs ADD PARTITION (`date`='2021-03-10') LOCATION 's3://[BUCKETNAME]/AWSLogs/[ACCOUNTID]/vpcflowlogs/ap-northeast-1/2021/03/10';
- フィールド名にハイフンがある(例えばtraffic-pathなど)と以下のエラーになるため、「traffic_path」などのように修正した。
# エラーメッセージ(ハイフンがある場合) line 1:8: no viable alternative at input 'create external' (service: amazonathena; status code: 400; error code: invalidrequestexception; request id: 757d9049-a6a7-4753-b554-38df81adbecb; proxy: null)5. 試験トラフィックの生成及びフローログの確認
- トラフィックを発生させ、それらのトラフィックがどのように記録されるかを確認する。
5.1 外部(インターネット)からのsshアクセス
- 手元の作業用PCから、VPCフローログが有効化されているVPCのインスタンスへsshアクセスする。
- インスタンス(10.0.0.188)へのssh(22/tcp)のacceptが記録されている。
5.2 インスタンスからのhttps/pingアクセス
- 検証用のインスタンスから、インターネット(例:www.yahoo.co.jp)へのhttps(curl)/pingのアクセスを行う。
- 2行目にhttpsアクセス(443/tcp)、3行目にpingアクセス(protocol 1 = icmp)が記録されている。
- その他、1行目は作業用PCからのsshアクセスへの応答、4~6行目は外部へのNTPアクセスが記録されている。
5.3 インスタンスからのS3アクセス
- 検証用のインスタンスから、VPCエンドポイントがない状態で、インターネットGW経由でS3アクセスを行う。その後、S3 VPCエンドポイント(Gatewayタイプ)を作成し、エンドポイント経由でS3アクセスを行う。通信経路の違いでログがどのように変わるかを確認する。
- 一番下の行(startime 1615437144 = 2021-03-11 13:32:24(JST)) は、VPCエンドポイントがない状態で、インスタンスで"aws s3 ls"コマンドを実行した際のログ。「traffic-path」の値が「8」(Internet Gateway経由) になっている。
- 上から3行目(starttime 1615445753 = 2021-03-11 15:55:53(JST))は、S3 VPCエンドポイントを作成した後、インスタンスで"aws s3 ls"コマンドを実行した際のログ。「traffic-path」の値が「7」(VPC Endpoint経由) になっており、経路が変わったことが確認できる。
- 上記の7と8が区別できるのは2021/3時点ではNitroインスタンスのENIのみ。
6. 所感
- 今回、やっと使い方が分かったので、トラフィックが想定通りに通らない時とかの調査に活用するようにしたい。
- 投稿日:2021-03-14T21:43:48+09:00
AWS_Cloudformationで環境構築してみた②
前回の記事
https://qiita.com/shinichi_yoshioka/items/487662c0749fe7b1ca8c前回の続きで、Networkレイヤは作成済。
以下のシンプルな構成で、今回はEC2インスタンスとセキュリティグループをCloudFormationで作成します。
テンプレートの作成
①CloudFormationのymlを作成するにあたって、CloudFormationのRain(CLI実行ツール)を使ってテンプレート(EC2用ymlとセキュリティグループ用yml)を出力する。
Rainの使い方の詳細は以下のURLを参照。
https://dev.classmethod.jp/articles/aws-cloudformation-rain/②出力されたymlそれぞれをクロススタック参照するようにパラメータを入れる。
Application.yml (EC2インスタンス作成)AWSTemplateFormatVersion: "2010-09-09" Description: Template generated by rain Resources: MyInstance: Type: AWS::EC2::Instance Properties: KeyName: Secret-key AvailabilityZone: ap-northeast-1a ImageId: ami-0f27d081df46f326c InstanceType: t2.micro NetworkInterfaces: - AssociatePublicIpAddress: true #DeleteOnTermination: false # Optional #Description: CHANGEME # Optional DeviceIndex: "0" GroupSet: - !ImportValue TEST-SGfromCF SubnetId: subnet-068305cddc05d01bd #SecurityGroupIds: #- !ImportValue TEST-SGfromCF #SecurityGroups: #- !ImportValue TEST-SGfromCF #SubnetId: subnet-068305cddc05d01bd Tags: - Key: Name Value: TEST-EC2_fromCF #UserData: CHANGEME # Optional #Volumes: #- Device: CHANGEME #VolumeId: CHANGEMEパラメータメモ
KeyName:秘密鍵の名前(.pemは不要)
ImageId: ami-0f27d081df46f326c ←AmazonLinux
AssociatePublicIpAddress: true ←パブリックIPアドレスを自動で割り当てる
DeviceIndex: "0" ←自動でパブリックIPアドレスを割り当てる際は"0"にする
GroupSet: Import関数でセキュリティグループを参照Secutiry.yml
AWSTemplateFormatVersion: "2010-09-09" Description: Template generated by rain Resources: MySecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow SSH from ALL SecurityGroupEgress: - Description: Outbound CidrIp: 0.0.0.0/0 IpProtocol: tcp FromPort: 22 ToPort: 22 #CidrIpv6: CHANGEME # Optional #DestinationPrefixListId: CHANGEME # Optional #DestinationSecurityGroupId: CHANGEME # Optional SecurityGroupIngress: - Description: Inbound CidrIp: 0.0.0.0/0 IpProtocol: tcp FromPort: 22 ToPort: 22 #CidrIpv6: CHANGEME # Optional #SourcePrefixListId: CHANGEME # Optional #SourceSecurityGroupId: CHANGEME # Optional #SourceSecurityGroupName: CHANGEME # Optional #SourceSecurityGroupOwnerId: CHANGEME # Optional Tags: - Key: Name Value: TEST-SG VpcId: vpc-0af10c6c61fb430cc Outputs: MySecurityGroupGroupId: Value: !GetAtt MySecurityGroup.GroupId Export: Name: TEST-SGfromCFパラメータメモ
SecurityGroupEgress: セキュリティグループのアウトバウンド
SecurityGroupIngress: セキュリティグループのインバウンド
Outputs: GetAtt関数を用いてMySecurityGroupのGroupIdを「TEST-SGfromCF」の名前タグをつけてエクスポートするスタックを作成
マネージメントコンソール- [CloudFormation]から[スタックの作成]をクリックし、
Application.ymlとSecutiry.ymlをアップロードして、スタックを作成する。
イベントタブのステータスがCREATE_COMPLETEになっていれば、正常に作成されたことを確認できる。
作成したEC2にセキュリティグループが適用され、EC2に秘密鍵を使ってSSH接続できることを確認した。最後に
EC2のセキュリティグループに関して紛わしい部分があるので、以下にメモを残しておきます。
①NetworkInterfaces配下のGroupSet・・・EC2インスタンス起動時に新しくネットワークインターフェースを作成する場合にセキュリティグループのIDを参照する際に使用
②SecurityGroups・・・デフォルトVPCのセキュリティグループを作成する際に使用
③SecurityGroupIds・・・推奨。参照するセキュリティグループ(AWS::EC2::SecurityGroup)を作成して、それを参照する際に使用
- 投稿日:2021-03-14T21:17:26+09:00
AWS DynamoDB テーブル一覧取得 メモ
テーブル一覧取得
resource
import boto3 dynamodb = boto3.resource('dynamodb') response = dynamodb.tables.all() print(type(response)) print(response) print('------------') for x in response: print(x, x._name, type(x))<class 'boto3.resources.collection.dynamodb.tablesCollection'> dynamodb.tablesCollection(dynamodb.ServiceResource(), dynamodb.Table) ------------ dynamodb.Table(name='TestTable1') TestTable1 <class 'boto3.resources.factory.dynamodb.Table'> dynamodb.Table(name='TestTable2') TestTable2 <class 'boto3.resources.factory.dynamodb.Table'>client
import boto3 dynamodb = boto3.client('dynamodb') response = dynamodb.list_tables() print(type(response)) print(response['TableNames'])<class 'dict'> ['TestTable1', 'TestTable2']参考記事
- 投稿日:2021-03-14T21:11:43+09:00
AWSでIPフローティングを試してみた!
AWSでIPフローティングを試してみた!
以前、IPフローティングについて調べてみたという記事を書いたときに、機会があったら試してみようと思っていたので、今回実際にやってみようと思います!
簡単なおさらいですが、IPフローティングというのはEC2インスタンスにアタッチしているEIPを別のEC2インスタンスに付け替えることです。
早速やっていきましょう!※今回はEC2インスタンスの構築手順から紹介していますが、「そんなの知ってるよ!」という方はEIPを手動で付け替えてみるまでスキップして頂いても構いません。
構成図
今回はシンプルに以下のような構成で試してみようと思います。
EIPの付け替えはAPIを使えば自動化できますが、今回は手っ取り早くやりたいので手動で付け替えます。
CDP:Floating IPパターン - AWS-CloudDesignPatternより前提
Route 53にドメインを登録している前提で進めますので、ドメインがない方はRoute 53で登録するか(有料)、サードパーティの無料ドメインや低価格ドメインを取得してRoute 53に登録してください。
登録方法についてはググるといっぱい出てきますので、ネットの記事を参考にしてください。
検索例:Route53 ドメイン お名前.com
EC2インスタンスを構築する
まずは適当なEC2インスタンスをWebサーバーとして起動します。
インスタンスの詳細は以下のように設定しました。
購入のオプション:スポットインスタンスのリクエスト
VPC:作成済みのVPC
サブネット:作成済みのパブリックサブネット
キャパシティーの予約:なし
ユーザーデータでは以下のようにApacheをインストールしてWebサーバーにするよう設定しています。
#!/bin/bash yum update -y yum -y install httpd chkconfig httpd on service httpd startその他のIAMロールやモニタリングの設定はデフォルトのままです。
セキュリティグループは作成済みのグループを使用します。
とりあえずHTTPとSSHのマイIPを許可していればいいと思います。
インスタンス一覧からパブリックIPをコピペしてアクセスしてみます。
無事Apacheのデフォルトページが表示されました。
接続がうまくいかない場合はセキュリティグループでHTTPを許可しているか、サブネットがパブリックか、EC2インスタンスにパブリックIPが付与されているかなどをご確認ください。
中身をちょっと編集
後ほど作成するセカンダリーのEC2インスタンスと区別がつくように、表示を変えておこうと思います。
僕はTera Termでインスタンスに入りますがお好きなソフトをお使いください。ユーザー名はデフォルトでは
ec2-user
となっているのでそれを入力し、ダウンロードしたキーペアを指定して接続します。
入れました。
接続がうまくいかない場合はセキュリティグループでSSH接続を許可しているかなどをご確認ください。
以下のコマンドで管理者権限でindex.htmlを作成していきます。
sudo su cd /var/www/html nano index.html適当に
<h1>This is Primary</h1>
とか入力しておきます。
あとはCtrl + X → Y →Enterで保存すると元の画面に戻ります。
一応ファイルができてるか
ls
コマンドで確認しておきます。
うん、ちゃんとできてる。
セカンダリーのEC2インスタンスを構築
同じ手順でセカンダリーのEC2インスタンスも構築しますが、同じ手順なので変更点だけ書いておきます。
・サブネット:セカンダリーはap-northeast-1c
にしました。
・タグ:Secondary
・htmlファイル:<h1>This is Secondary</h1>
プライマリーにEIPをアタッチ
プライマリーのEC2インスタンスに固定IPであるEIPをアタッチしていきます。
EC2ダッシュボードから
Elastic IP
をクリックします。
タグに
Floating-Test
と付けて、あとはデフォルトのまま割り当てをクリックします。
プライマリー用のEC2インスタンスとプライベートIPアドレス(自動入力)を設定し、再関連付けにチェックを付けておきます。
関連付けされたら試しにEIPでのアクセスもしておきます。
プライマリー側が表示されればOKです。
Route 53でドメインとEIPの紐づけ
続いてRoute 53での設定を行います。
ひとまずRoute 53のコンソールに移動しましょう!
レコード名をに
floating
と入力し、値にEIPを入力します。
TTLは試しに0秒にしてみました。
floating.<ドメイン名>
でアクセスしてみます。
プライマリー側の表示が確認できました!
EIPを手動で付け替えてみる
ようやくやりたいことにたどり着きました!
今回はプライマリーにアタッチしているEIPをセカンダリーに手動で切り替えてみたいと思います。ドメイン名でアクセスしてみました。
2~3秒でプライマリーからセカンダリーに切り替わりました。はやっ!!
試しにTTLを変えてみる
先ほどはRoute 53でTTLを0秒に設定していましたが、今度は60秒に変更してみます。
EIPの付け替えだけならTTLの影響は受けないはずなので、切り替わりもすぐ行われるはずです。
セカンダリーのEIPをプライマリーに付け替えてっと。
さて、どうかな?
おお!さっきと一緒ですぐ切り替わった!
って、そりゃそうですよね。ドメイン名とIPの紐づけをキャッシュしている時間がTTLだと思っているので、関連付けられているIPが変わらない限りTTLは関係ないですね。今回はIPの先にあるインスタンスを変えているだけです。
Route 53のヘルスチェックを用いたフェイルオーバーもやったことありますが、あちらは切り替えに1分~2分ほどかかり、なおかつブラウザのキャッシュにも影響されていたので、切り替え時間だけならIPフローティングの方が速そうです。
まとめ
今回は、以前調べたIPフローティングを実際に試してみました。切り替え時間がすごく速くてびっくりしました!ただ今回は手動での付け替えだったので、実務で使う場合はAPIを使って自動化するのが良いと思います。その際、EC2インスタンスの監視に何を使うのが良いのかは要件などにもよりそうですが、AWSのサービスや監視ソフトといったところでしょうか。
今度はそのあたりの組み合わせも試せたらと思っています。
それでは今回はこのへんで!課金に関する注意点
構築したEC2インスタンスは不要な場合削除しましょう。また、EIPは関連付けを外して解放しましょう。EIPはアタッチされていない時間や停止したインスタンスに関連付けられていると課金されてしまいます。EC2インスタンスも停止だけだとEBSの料金がかかりますので、不要な場合は削除しておきましょう!
- 投稿日:2021-03-14T20:36:56+09:00
AWS Signature v4の署名をJavaで作る「完全な署名バージョン4」for Java
AWS Sig V4とは
AWSのAPIを利用するときに、クライアント側からI AMユーザであることを示す為に送付する署名のことです。前はバージョン2とかいろいろあったみたいですが、今はV4がメインで使われているようです。
SigV4はAWS公式のルールにしたがって作り、HTTPリクエストのAuthorizationヘッダーの値に載せて送ります。それを受け取ったAWS側では、同じロジックに従って署名を作り、送られてきた署名と一致するかを確かめることで認証を行います。API GatewayのI AMユーザを使ったアクセス制限を例に、今回は自前で実装してみます。
SigV4の使い方
POSTであればリクエストヘッダーにAuthorization、X-Amz-Dateの二つを載せて送ります。GETであればクエリパラメータ文字列でもいけるようです。その2つの文字列を作るのにはルールがあり、特にAuthorizationのほうは面倒なルールに従って文字列を生成する必要があります。
本来であれば、SDKを使えば簡単にできるところですが、どんなことをしているのか中身が気になったので自前で書いてみました。自前で署名するプログラム
https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-4.html
公式ドキュメントを参考にして署名をします。
手順は4つです。
- タスク 1: 正規リクエストを作成する
- タスク 2: 署名文字列を作成する
- タスク 3: 署名を計算する
- タスク 4: HTTP リクエストに署名を追加する
どの文字列を作るのにも改行の場所とか、暗号化する対象とか、色々気を使いながらルールに従って署名をします。簡単そうに見えていましたが、1文字でも違うと認証はじかれるので、結構ハマりました。
実際に書いてみたプログラムは以下です。
以下の関数doShomei()
はパラメータは全部べた書きなので適宜パラメータ化したりなんなりしたほうが良いですね。package sample.XXXX; import java.net.InetSocketAddress; import java.net.Proxy; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; public class Shomei { private static final Log LOG = LogFactory.getLog(Shomei.class); public void doShomei() { /* * タスク1. 署名バージョン4の正規リクエストを作成する. * https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-create-canonical-request.html * CanonicalRequest = * HTTPRequestMethod + '\n' + * CanonicalURI + '\n' + * CanonicalQueryString + '\n' + * CanonicalHeaders + '\n' + * SignedHeaders + '\n' + * HexEncode(Hash(RequestPayload)) */ SimpleDateFormat xAmzDateFormatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); xAmzDateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); String xAmzDate = xAmzDateFormatter.format(new Date()).trim(); String host = "XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com"; String httpRequestMethod = "POST"; String canonicalUri = "/hoge/fuga"; String signedHeaders = "content-type;host;x-amz-date"; String canonicalQueryString = ""; String contentType = "application/json"; String canonicalHeaders = "content-type:" + contentType + "\nhost:" + host + "\nx-amz-date:" + xAmzDate; String requestPayload = ""; String canonicalRequest = httpRequestMethod + '\n' + canonicalUri + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + '\n' + signedHeaders + '\n' + DigestUtils.sha256Hex(requestPayload); LOG.debug(canonicalRequest); String hashedCanonicalRequest = DigestUtils.sha256Hex(canonicalRequest); /* * タスク2. 署名バージョン4の署名文字列を作成する. * https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-create-string-to-sign.html * StringToSign = * Algorithm + \n + * RequestDateTime + \n + * CredentialScope + \n + * HashedCanonicalRequest */ String date = "20210314"; String region = "ap-northeast-1"; String service = "execute-api"; String endStr = "aws4_request"; String algorithm = "AWS4-HMAC-SHA256"; String credentialScope = date + "/" + region + "/" + service + "/" + endStr; String stringToSign = algorithm + "\n" + xAmzDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest; /* * タスク3. 署名バージョン4の署名を計算する. * https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-calculate-signature.html * * kSecret = your secret access key * kDate = HMAC("AWS4" + kSecret, Date) * kRegion = HMAC(kDate, Region) * kService = HMAC(kRegion, Service) * kSigning = HMAC(kService, "aws4_request") */ String accessKey = "API Gatewayに実行権限を持つIAMユーザーのアクセスキー"; String secretKey = "API Gatewayに実行権限を持つIAMユーザーシークレットキー"; try { /* * Javaを使用して署名キーを取得 * https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java */ byte[] key = getSignatureKey(secretKey, date, region, service); String signature = String.valueOf(Hex.encodeHex(hmacSHA256(stringToSign, key))); LOG.debug(signature); /* * タスク4. HTTPリクエストに署名を追加する * https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-add-signature-to-request.html * * Authorization: algorithm Credential=access key ID/credential scope, SignedHeaders=SignedHeaders, Signature=signature */ String authorization = algorithm + " Credential=" + accessKey + "/" + credentialScope + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature; LOG.debug(authorization); LOG.debug(xAmzDate); } catch (Exception e) { e.printStackTrace(); } } public static byte[] hmacSHA256(String data, byte[] key) throws Exception { String algorithm = "HmacSHA256"; Mac mac = Mac.getInstance(algorithm); mac.init(new SecretKeySpec(key, algorithm)); return mac.doFinal(data.getBytes("UTF-8")); } public static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception { byte[] kSecret = ("AWS4" + key).getBytes("UTF-8"); byte[] kDate = hmacSHA256(dateStamp, kSecret); byte[] kRegion = hmacSHA256(regionName, kDate); byte[] kService = hmacSHA256(serviceName, kRegion); byte[] kSigning = hmacSHA256("aws4_request", kService); return kSigning; } }結論
AWSのSDK使える人は使ったほうが早いと思いますし、公式もそれを推奨しています。メンテを考えるとSDK使ったほうが絶対によいです。ただ自前で書いても(ハマらなければ)大した時間かからないので、何らかの理由で自前でやる方はご参考にどうぞ。
- 投稿日:2021-03-14T20:35:24+09:00
【学習メモ】AWS SNS
SNS
Simple Notification Service。
フルマネージド型のプッシュ型通知サービス。SNSはどう言うもの?
TOPICを作成して、どういう受信側に送るのかというpolicyを指定することによって、
特定の通信内容を受信側に送る。特徴
AWSの他のサービスと連携して、疎結合化が可能。
Ref:https://aws.amazon.com/cn/sns/features/標準トピック
1回以上受信され順番付けされていないメッセージをアプリケーションが処理できるのであれば、 多くのシナリオで使用することができます。FIFO トピック
オペレーションやイベントの順番が重要であったり、 重複を許容しないようなアプリケーション間で行うメッセージングを、 強化するために設計されています。SQS Vs. SNS
Ref:https://medium.com/awesome-cloud/aws-difference-between-sqs-and-sns-61a397bf76c5
◯エンティティタイプ
SQS:キュー
SNS:トピック◯Message consumption
SQS :プル型(受信側はSQSにてメッセージを引っ張る)
SNS :プッシュ型( SNSはメッセージを受信側に送る)◯ユーケース
SQS :二つのアプリを疎結合。非同期処理を許す。
SNS :同じメッセージを複数の方法で処理できる。◯永続性
SQS:永続性あり。
SNS:永続性なし。
メッセージの到着時にどちらのコンシューマーが存在していたとしても、メッセージを取得すると、メッセージは削除される。利用可能なコンシューマーがない場合、メッセージは失う。※SQSではメッセージ配信は保証されるが、SNSでは保証されていない。
◯消費者タイプ
SQS:すべてのコンシューマーは同一であると想定されているため、メッセージをまったく同じ方法で処理する。
SNS:すべての消費者は(想定される)さまざまな方法でメッセージを処理する。
- 投稿日:2021-03-14T18:40:45+09:00
AWS 入門者が EC2 で Linux 仮想サーバーを構築してみた
概要
本項では、クラウドコンピューティングサービスである Amazon Web Service (AWS) を用いて Linux 仮想サーバーを構築する手順を紹介する。
環境
- MacBook Air (Retina, 13-inch, 2018)
- macOS Big Sur (Version 11.2.3)
- メモリ 16 GB
AWS とは
- クラウドコンピューティングサービスのひとつである
- 200 以上のサービスがあり、組み合わせによって様々なアプリケーションやインフラを構築できる
- 社内 LAN など、外部のシステムやネットワークと連結することができる
- 料金体系がサービスの使用量に従う
- 学生は AWS Educate でクラウドスキルを無料で学習できる
AWS アカウントの作成
AWS を利用するには AWS アカウントを作成する 必要である。登録時にクレジット/デビットカード番号が求められるが、サポートプランでベーシックプランを選択すれば無料でも使用できる。
AWS をはじめてみよう
AWS は、マネージメントコンソールを用いることで Web ブラウザの GUI で利用・操作することができる。マネージメントコンソールを開くと、利用可能なサービスの一覧を確認できる。
今回は、サーバーに必要なもの(OS やソフトウェアなど)を一式でレンタルすることができる Amazon Elastic Compute Cloud (Amazon EC2) を上記の一覧から選択して、仮想サーバーを構築してみよう。
EC2 を用いた仮想サーバー構築
マネージメントコンソールからEC2 を選択すると、EC2 ダッシュボードが表示される。EC2 では、AWS クラウドに作る仮想サーバーをインスタンスという。インスタンスには「設計図をもとに作成されたもの」という意味があり、EC2 にも仮想サーバーの設計図(仮想イメージ)が用意されている。ここでは仮想イメージからインスタンスを作成する手順を紹介する。
STEP1: Amazon マシンイメージ(AMI)を選択する
EC2 ダッシュボードで「インスタンスを起動」を選択すると、仮想イメージの一覧を確認できる。
EC2 では仮想イメージのことを Amazon マシンイメージ(AMI) という。同じ AMI から作成されたインスタンスは、設定が全て同じの仮想サーバーである。今回は linux 仮想サーバーを構築するために Amazon Linux 2 AMI (HVM), SSD Volume Type を選択してみよう。
STEP2: インスタンスタイプを選択する
次の画面ではインスタンスの性能が一覧で表示される。ここではインスタンスの CPU やメモリなどを選択できる。性能によって料金体系も異なるが、今回は無料で使用できる t2.micro を選択して、「確認と作成」ボタンをクリックしよう。
STEP7: インスタンスタイプを作成する
次の画面で「起動」ボタンを押すとインスタンスが作成される。なお STEP3~STEP6 の各種設定は、インスタンス作成後でも可能である。
キーペアの作成
インスタンス作成時にキーペアに関するポップアップが表示される。キーペアはインスタンス接続時の認証に必要な鍵である。ローカルサーバーからの接続にも必要なため、ここで新しいキーペアを作成してくおくとよい。キーペアに適当な名前をつけてダウンロードしておこう。
キーペアとはログイン認証時の公開鍵と秘密鍵のペアであり、ここでダウンロードされるのは秘密鍵である。RSA によって暗号化されており、拡張子は
pem
である。Demo2021.pem-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAhiJeziiC9SC6TiWQfjOjp6vouPD7QwCdHzOLB/+FMD2/8U52 +F8JDcXHYulMTjyXhADy1WF+TKCgohh07GRPNrGU6LxnWLrTKnLkIPzFV/jnU6k1 GILmXI7yvtfWSC5tA5OUSWNUCeFYq8bh2RXKHVmrJxLYaIO/LoeFUFJou2qOgEA6 (中略) Y+I9qQKBgBUsxReCPgvdRJ2Ba88muNgxWZnr437m9nESo0MMlDH6lNtd5UVOsNbJ VDqg55p0Gy3Jepk8XZbpAybLmglyJY0cYU1GaCFQdw/NFtCnX8e7oYUGB20uMe40 Muyp+udJCx0MHP+y5hm80FabKziYF/5dQl2LMSZLgGMLO1gt/1YE -----END RSA PRIVATE KEY-----インスタンス作成中
インスタンス作成中は次の画面が表示される。右下の「インスタンスの表示」ボタンを押すとインスタンスの状態を確認できる。
次の画面で、ステータスチェックが「初期化しています」から「2/2 のチェックに合格しました」に変わるとインスタンスが作成される。
SSH 接続
SSH(Secure Shell) とは、ネットワークに接続された機器(今回はインスタンス)を遠隔操作し、管理するための手段をさす。ここでは MacBook から Amazon EC2 に SSH 接続する方法を紹介する。
まずは、接続先の EC2 インスタンスにチェックを入れて接続ボタンを押してみよう。
次の画面で「SSH クライアント」タブを開くと、SSH 接続手順が説明されている。
STEP1: SSH クライアントを開く
Mac に標準搭載されているターミナルを SSH クライアントソフトとして使用する。Windows の場合はこちらの動画で詳しく解説されている。
STEP2: プライベートキーファイルを見つける
プライベートキーファイルとはキーペアのうちの秘密鍵をさす。今回は先ほどダウンロードした
Demo2021.pem
を使用する。ユーザーのホームディレクトリに.ssh
フォルダを作成し、新規フォルダにpem
ファイルを移動してもよい。ターミナルmkdir ~/.ssh mv Demo2021.pem ~/.ssh cd ~/.sshSTEP3: 必要に応じてキーが公開されていないことを確認する
chmod コマンドでキーファイルの権限を設定する。
ターミナルchmod 400 Demo2021.pemSTEP4: プライベートキーファイルを見つける
次のコマンドを実行すると SSH 接続が完了する。
ターミナルssh -i "Demo2021.pem" ec2-user@ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com次のように表示されれば SSH 接続は成功している。
ターミナルThe authenticity of host 'ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com (18.183.11.87)' can't be established. ECDSA key fingerprint is SHA256:gyQ0V6rZ8KDgET/yROzqJvUy59Elo9wvkuWoNcqniWI. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com,18.183.11.87' (ECDSA) to the list of known hosts. __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-172-31-0-200 ~]$パッケージのアップデート
デフォルトでインストールされているパッケージが最新でない場合があるため、次のコマンドでアップデートしておくとよい。(すべて最新版の場合は
No packages marked for update
と表示される。)
AWS 利用者は一般ユーザーであるためyum
を実行できないが、sudo
コマンドによってルートユーザーの権限をもつことで実行できる。
yum
は Red Hat 系の Linux ディストリビューションで使われているパッケージ管理ソフトである。ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo yum updatePython 3 のダウンロード
次のコマンドで Python3 をダウンロードする。(参考)
ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo yum install python3 -yDocker のダウンロード
次のコマンドで Docker をダウンロードする。(参考)
ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo amazon-linux-extras install dockerSSH 接続の終了
ターミナルで
logout
と実行する。参考図書
- 投稿日:2021-03-14T18:40:45+09:00
【AWS】EC2 による Linux 仮想サーバーの構築
概要
本項では、クラウドコンピューティングサービスである Amazon Web Service (AWS) を用いて Linux 仮想サーバーを構築する手順を紹介する。
環境
- MacBook Air (Retina, 13-inch, 2018)
- macOS Big Sur (Version 11.2.3)
- メモリ 16 GB
AWS とは
- クラウドコンピューティングサービスのひとつである
- 200 以上のサービスがあり、組み合わせによって様々なアプリケーションやインフラを構築できる
- 社内 LAN など、外部のシステムやネットワークと連結することができる
- 料金体系がサービスの使用量に従う
- 学生は AWS Educate でクラウドスキルを無料で学習できる
AWS アカウントの作成
AWS を利用するには AWS アカウントを作成する 必要である。登録時にクレジット/デビットカード番号が求められるが、サポートプランでベーシックプランを選択すれば無料でも使用できる。
AWS をはじめてみよう
AWS は、マネージメントコンソールを用いることで Web ブラウザの GUI で利用・操作することができる。マネージメントコンソールを開くと、利用可能なサービスの一覧を確認できる。
今回は、サーバーに必要なもの(OS やソフトウェアなど)を一式でレンタルすることができる Amazon Elastic Compute Cloud (Amazon EC2) を上記の一覧から選択して、仮想サーバーを構築してみよう。
EC2 を用いた仮想サーバー構築
マネージメントコンソールからEC2 を選択すると、EC2 ダッシュボードが表示される。EC2 では、AWS クラウドに作る仮想サーバーをインスタンスという。インスタンスには「設計図をもとに作成されたもの」という意味があり、EC2 にも仮想サーバーの設計図(仮想イメージ)が用意されている。ここでは仮想イメージからインスタンスを作成する手順を紹介する。
STEP1: Amazon マシンイメージ(AMI)を選択する
EC2 ダッシュボードで「インスタンスを起動」を選択すると、仮想イメージの一覧を確認できる。
EC2 では仮想イメージのことを Amazon マシンイメージ(AMI) という。同じ AMI から作成されたインスタンスは、設定が全て同じの仮想サーバーである。今回は linux 仮想サーバーを構築するために Amazon Linux 2 AMI (HVM), SSD Volume Type を選択してみよう。
STEP2: インスタンスタイプを選択する
次の画面ではインスタンスの性能が一覧で表示される。ここではインスタンスの CPU やメモリなどを選択できる。性能によって料金体系も異なるが、今回は無料で使用できる t2.micro を選択して、「確認と作成」ボタンをクリックしよう。
STEP7: インスタンスタイプを作成する
次の画面で「起動」ボタンを押すとインスタンスが作成される。なお STEP3~STEP6 の各種設定は、インスタンス作成後でも可能である。
キーペアの作成
インスタンス作成時にキーペアに関するポップアップが表示される。キーペアはインスタンス接続時の認証に必要な鍵である。ローカルサーバーからの接続にも必要なため、ここで新しいキーペアを作成してくおくとよい。キーペアに適当な名前をつけてダウンロードしておこう。
キーペアとはログイン認証時の公開鍵と秘密鍵のペアであり、ここでダウンロードされるのは秘密鍵である。RSA によって暗号化されており、拡張子は
pem
である。Demo2021.pem-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAhiJeziiC9SC6TiWQfjOjp6vouPD7QwCdHzOLB/+FMD2/8U52 +F8JDcXHYulMTjyXhADy1WF+TKCgohh07GRPNrGU6LxnWLrTKnLkIPzFV/jnU6k1 GILmXI7yvtfWSC5tA5OUSWNUCeFYq8bh2RXKHVmrJxLYaIO/LoeFUFJou2qOgEA6 (中略) Y+I9qQKBgBUsxReCPgvdRJ2Ba88muNgxWZnr437m9nESo0MMlDH6lNtd5UVOsNbJ VDqg55p0Gy3Jepk8XZbpAybLmglyJY0cYU1GaCFQdw/NFtCnX8e7oYUGB20uMe40 Muyp+udJCx0MHP+y5hm80FabKziYF/5dQl2LMSZLgGMLO1gt/1YE -----END RSA PRIVATE KEY-----インスタンス作成中
インスタンス作成中は次の画面が表示される。右下の「インスタンスの表示」ボタンを押すとインスタンスの状態を確認できる。
次の画面で、ステータスチェックが「初期化しています」から「2/2 のチェックに合格しました」に変わるとインスタンスが作成される。
SSH 接続
SSH(Secure Shell) とは、ネットワークに接続された機器(今回はインスタンス)を遠隔操作し、管理するための手段をさす。ここでは MacBook から Amazon EC2 に SSH 接続する方法を紹介する。
まずは、接続先の EC2 インスタンスにチェックを入れて接続ボタンを押してみよう。
次の画面で「SSH クライアント」タブを開くと、SSH 接続手順が説明されている。
STEP1: SSH クライアントを開く
Mac に標準搭載されているターミナルを SSH クライアントソフトとして使用する。Windows の場合はこちらの動画で詳しく解説されている。
STEP2: プライベートキーファイルを見つける
プライベートキーファイルとはキーペアのうちの秘密鍵をさす。今回は先ほどダウンロードした
Demo2021.pem
を使用する。ユーザーのホームディレクトリに.ssh
フォルダを作成し、新規フォルダにpem
ファイルを移動してもよい。ターミナルmkdir ~/.ssh mv Demo2021.pem ~/.ssh cd ~/.sshSTEP3: 必要に応じてキーが公開されていないことを確認する
chmod コマンドでキーファイルの権限を設定する。
ターミナルchmod 400 Demo2021.pemSTEP4: プライベートキーファイルを見つける
次のコマンドを実行すると SSH 接続が完了する。
ターミナルssh -i "Demo2021.pem" ec2-user@ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com次のように表示されれば SSH 接続は成功している。
ターミナルThe authenticity of host 'ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com (18.183.11.87)' can't be established. ECDSA key fingerprint is SHA256:gyQ0V6rZ8KDgET/yROzqJvUy59Elo9wvkuWoNcqniWI. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'ec2-18-183-11-87.ap-northeast-1.compute.amazonaws.com,18.183.11.87' (ECDSA) to the list of known hosts. __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-172-31-0-200 ~]$パッケージのアップデート
デフォルトでインストールされているパッケージが最新でない場合があるため、次のコマンドでアップデートしておくとよい。(すべて最新版の場合は
No packages marked for update
と表示される。)
AWS 利用者は一般ユーザーであるためyum
を実行できないが、sudo
コマンドによってルートユーザーの権限をもつことで実行できる。
yum
は Red Hat 系の Linux ディストリビューションで使われているパッケージ管理ソフトである。ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo yum updatePython 3 のダウンロード
次のコマンドで Python3 をダウンロードする。(参考)
ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo yum install python3 -yDocker のダウンロード
次のコマンドで Docker をダウンロードする。(参考)
ターミナル[ec2-user@ip-172-31-0-200 ~]$ sudo amazon-linux-extras install dockerSSH 接続の終了
ターミナルで
logout
と実行する。参考図書
- 投稿日:2021-03-14T18:31:19+09:00
LambdaでAWS利用料のグラフをS3に保存し、Slackに通知する
はじめに
AWSアカウントの管理者になってから、ほぼ毎日Cost Explorerで利用料を確認し、料金の急増がないかをチェックしています。ただ、
- 手動での確認はやはり手間がかかり、もっと手軽な方法でやりたい
- 利用料の状況をチームメンバーにも共有し、コストの管理意識を芽生えてもらいたい
というニーズがあり、日々の利用料をSlackに通知するためのLambda関数を実装しました。
参考記事
まず、アーキテクチャとソースコードはこちらの記事を参考し、一部カスタマイズして作りました。(@hayao_kさん、ありがとうございました!)
日々のAWS請求額をグラフ付きでSlackに通知するただ、弊社のSlackワークスペースにおいては、ファイルアップロードのための
files:write
スコープが規則上認められていないため、アーキテクチャを一部変更し、Slackへの直接アップロードではなく、一度S3に保存したうえ、グラフのオブジェクトURLをリンクとしてSlackメッセージに貼り付けるという形にしました。実際のアーキテクチャは以下となります。
- CloudWatch Eventsによって指定の時間にLambda関数を呼び出す
- CloudWatchから
EstimatedCharges
のメトリクス情報(データポイント)を取得- 取得したデータポイントに基づき、Lambda関数で利用料のグラフを生成
- 生成したグラフをS3バケットに保存 ? ここは参考記事からの変更点
- 利用料に関するメッセージを作成してSlackに送る(メッセージにグラフのURLも含める)
成果物のイメージ
また、メッセージにあるリンクをクリックすると、ブラウザ上でS3に保存されているグラフが表示されます。
実装の事前準備
Slack Incoming Webhooksを用意
S3バケットを用意
任意の端末からS3に保存されているグラフにアクセスしたい場合は、バケットのパブリックアクセスを有効化する必要がありますが、社外からのアクセスを回避したいので、バケットポリシーに弊社事業所のグローバルIPのみ許可します。
Lambda関数を作成
ランタイムは
Python 3.8
実行ロールは基本的な権限(CloudWatchにログ出力するための権限)で新規作成したうえ、再度IAMから当該ロールを編集し、下記2つのポリシーを追加します。
- CloudWatchReadOnlyAccess(手順2でCloudWatchからメトリクス情報を取得するため)
- 上記S3バケットへの操作権限(手順4でグラフをバケットに保存するため)
Lambda関数の中身(ソースコード)
バケットやWebhooksなどの情報は適宜書き換えるように。
lambda_function.pyimport base64 import boto3 import datetime import json import logging import os import requests from botocore.exceptions import ClientError logger = logging.getLogger() logger.setLevel(logging.INFO) client = None def get_cloudwatch_client(): global client client = boto3.client('cloudwatch', region_name='us-east-1') return client def get_metrics(start_time, end_time, client=None): if client is None: client = get_cloudwatch_client() try: response = client.get_metric_statistics( Namespace='AWS/Billing', MetricName='EstimatedCharges', Dimensions=[ { 'Name': 'Currency', 'Value': 'USD' } ], StartTime=start_time, EndTime=end_time, Period=21600, Statistics=['Maximum'] ) except ClientError as e: logger.error("Request failed: %s", e.response['Error']['Message']) else: return response def get_image(today, yesterday, diff, metrics, s3ObjKey, client=None): if client is None: client = get_cloudwatch_client() if diff > 0: title = ('Current Charges: $' + str(today) + ' / Increased $' + str(diff) + ' from Yesterday') min = yesterday * 0.7 max = today * 1.05 else: title = ('Current Charges: $' + str(today)) min = today * 0.7 max = yesterday * 1.05 widget_definition = json.dumps( { "width": 1280, "height": 800, "start": "-PT144H", "end": "PT0H", "timezone": "+0900", "view": "timeSeries", "stacked": True, "stat": "Maximum", "title": title, "metrics": [ ["AWS/Billing", "EstimatedCharges", "Currency", "USD"] ], "period": 43200, "annotations": { "horizontal": [ { "label": "Today", "value": today }, { "label": "Yesterday", "value": yesterday } ] }, "yAxis": { "left": { "label": "$", "min": (min), "max": (max) } }, } ) try: response = client.get_metric_widget_image( MetricWidget=widget_definition ) except ClientError as e: logger.error("Request failed: %s", e.response['Error']['Message']) else: s3 = boto3.resource('s3') bucket = s3.Bucket('xxxxxxxxxx') res = bucket.put_object(Body=( response["MetricWidgetImage"]), Key=s3ObjKey, ContentType='image/png') logger.info("Upload Image succeeded.") def build_payload(today_charge, diff, s3ObjUrl): payload = { "attachments": [ { "color": "good", "title": "AWS料金(クリックしてグラフを確認)", "title_link": s3ObjUrl, "fields": [ { "title": "対象AWSアカウント", "value": "`xxxxxxxxxxxx`", "short": False }, { "title": "本日まで利用した金額", "value": ":heavy_dollar_sign:" + str(today_charge), "short": True }, { "title": "昨日よりの増加量", "value": ":heavy_dollar_sign:" + str(diff), "short": True } ] } ] } return payload def lambda_handler(event, context): start_time = datetime.datetime.now() - datetime.timedelta(hours=30) end_time = datetime.datetime.now() logger.info('Metric Start Time: ' + str(start_time)) logger.info('Metric End Time: ' + str(end_time)) metrics = get_metrics(start_time, end_time) sorted_data = sorted(metrics['Datapoints'], key=lambda x: x['Timestamp']) logger.info("Sorted Data: %s", sorted_data) today_charge = sorted_data[-1]['Maximum'] yesterday_charge = sorted_data[0]['Maximum'] diff = round(today_charge - yesterday_charge, 2) targetAccount = 'xxxxxxxxxxxx' s3ObjKey = targetAccount + '/charge-graph-' + \ str((end_time + datetime.timedelta(hours=9)).date()) s3ObjUrl = 'https://xxxxxxxx.s3-ap-northeast-1.amazonaws.com/' + s3ObjKey get_image(today_charge, yesterday_charge, diff, metrics, s3ObjKey) payload = build_payload(today_charge, diff, s3ObjUrl) req = requests.post( 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxx', data=json.dumps(payload)) try: req.raise_for_status() logger.info("Message posted.") return req.text except requests.RequestException as e: logger.error("Request failed: %s", e) return req最後に
Lambdaを実装し、データポイントの取得やグラフ(ウイジェット)生成のためのパラメータをチューニングして簡単なテストを済ませ、CloudWatchのイベントルールを設定したら終わりです。これで毎日Slackで料金のチェックや推移グラフを見ることができるようになりました。かなり便利です!
後日に余裕あったら
get_metric_statistics
とget_metric_widget_image
の仕様をまとめてみます。
- 投稿日:2021-03-14T17:32:34+09:00
[EKS] Cronjob経由でpodからAWSリソースへのアクセスとkubectlを実行したい
はじめに
Kubernetesの Cronjob経由のPodでkubectlコマンドを実行したり、AWSリソースへアクセスする方法についてのメモです。
やりたいことは以下の通りです。
- 定期的にkubectlコマンドを実行し、結果をAWSのcloudwatchのカスタムメトリクスへ送信する
ポイントは以下の5点です
- aws cliとkubectlを実行できるコンテナイメージの作成
- awsリソースを操作する権限
- kubectlリソースを操作する権限
- cloud watchへカスタムメトリクスの送信
- cron jobの実行
aws cliとkubectlを実行できるコンテナイメージの作成
aws cliはamazonに公式のイメージがあります。
https://hub.docker.com/r/amazon/aws-cli
これにkubectlを追加するのが良さそうです。FROM amazon/aws-cli:latest RUN yum update -y \ && curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" \ && chmod +x kubectl \ && mv kubectl /usr/local/bin/ ENTRYPOINT [""]kubectlだけ実行したい人はalpineにkubectlを追加した方がイメージが軽くなると思います。
※最初にこの方法で進めてたら、aws cliはalpineをサポート対象に含まれていないのと、
動かすにはpythonやらglibcやらと結局イメージ膨れそうなので、amazonの公式イメージにしました。FROM alpine RUN apk add --no-cache --virtual=build wget \ && wget https://storage.googleapis.com/kubernetes-release/release/v1.20.0/bin/linux/amd64/kubectl \ && mv kubectl /usr/local/bin/ \ && chmod +x /usr/local/bin/ \ && apk del build各イメージサイズはこんな感じです。
# docker images | sort master REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest 28f6e2705743 2 weeks ago 5.61MB alpine-with-kubectl latest 0f52e434f905 6 minutes ago 45.9MB amazon/aws-cli latest 19790bab4269 4 days ago 298MB aws-cli-with-kubectl latest f7b960da07f6 3 hours ago 534MBECRへpushしておく
# aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded # docker build -t xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-check:latest . # docker push xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-checkawsリソースを操作する権限
これはNodeに付与するIAMRoleで制御できました。
kubectl/EKSリソースを操作する権限
そのまま試したらNGでした。
defaultのservice accountが使われるようで、そのアカウントに権限がないみたいです。kubectl run -it aws-cli-test --image=amazon/aws-cli:latest --command '/bin/bash' bash-4.2# bash-4.2# curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" \ > && chmod +x kubectl \ > && mv kubectl /usr/local/bin/ bash-4.2# kubectl get node Error from server (Forbidden): nodes is forbidden: User "system:serviceaccount:default:default" cannot list resource "nodes" in API group "" at the cluster scope新たにservice accountを作成して、rbacのcluster role bindingに追加してあげる
# kubectl create sa aws-cli serviceaccount/aws-cli created # kubectl edit clusterrolebinding -n kube-system cluster-admin apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: ~~ - kind: ServiceAccount name: aws-cli namespace: defaultそうすると見えるようになる。
ただ、 軽く調べたらOpenID Connect (OIDC) ID を使うのが正攻法みたいです。# kubectl run -it aws-cli-test --image=amazon/aws-cli:latest --command '/bin/bash' --serviceaccount=aws-cli If you don't see a command prompt, try pressing enter. bash-4.2# bash-4.2# kubectl get node NAME STATUS ROLES AGE VERSION ip-10-0-2-99.ap-northeast-1.compute.internal Ready <none> 18d v1.17.12-eks-7684af ip-10-0-3-144.ap-northeast-1.compute.internal Ready <none> 18d v1.17.12-eks-7684af bash-4.2# kubectl get pod | grep aws-cli aws-cli-test 1/1 Running 0 2m25scloud watchへカスタムメトリクスの送信
aws cliが使えれば送れます。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudwatch-custom-metrics/因みにやりたかったことは、NodeのステータスがたまにNotReadyになってて、何か気づく術が欲しかったのが発端です。
AWSへ問い合わせたら、prometheus入れて kube-state-metrics 入れたらメトリクス取れるよ。と言われましたが、途中で断念しました。nodestatus=$(kubectl get node | grep Ready | wc -l) aws cloudwatch put-metric-data --metric-name notready_count --dimensions ClusterName=eks-cluster --namespace "ContainerInsights" --value $nodestatuscron jobの実行
config mapで実行したいscriptを書いて、cronjob側で読み込みます。
--- apiVersion: batch/v1beta1 kind: CronJob metadata: name: nodecheck spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: serviceAccountName: aws-cli containers: - name: nodecheck image: xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-check:latest imagePullPolicy: IfNotPresent command: ["/bin/sh"] args: ["/root/entrypoint.sh"] volumeMounts: - name: entrypoint mountPath: /root restartPolicy: OnFailure volumes: - name: entrypoint configMap: name: node-status-check --- apiVersion: v1 kind: ConfigMap metadata: name: node-status-check data: entrypoint.sh: |- #!/bin/sh nodestatus=$(kubectl get node | grep Ready | wc -l) aws cloudwatch put-metric-data --metric-name Eks_node_notready_count --dimensions ClusterName=eks-cluster --namespace "ContainerInsights" --value $nodestatus ---
- 投稿日:2021-03-14T17:27:43+09:00
生のPHPとLaravelの、二通りの類似ポートフォリオを作った話
はじめに
こんにちは、おーもとと申します。エンジニアに転職をするため学習している初学者です。
私は車が好きで、「近年の若者の車離れ」という問題にフォーカスしたアプリを制作しようと思いました。制作背景
若者が車を持たない理由には様々な理由があると思いますが、
「欲しいと思えるほど魅力を感じる車に出会っていないからなのでは?」
と思い、
・かわいいやかっこいいというスタイル
・大きさ
・国産か外車か
・アウトドアや街乗りという用途
これらの項目に当てはまる車を、結果として表示するアプリを制作することにしました。
(これらの特徴は全て私が定めているため、投票などにより特徴を決める機能をつけたいです)11月 PHPでアプリ開発
10月からPHPの学習を始めていたので、そのアプリはPHPで制作しました。
カーセンサーAPIを使用して、車の情報を取得します。
解説動画:https://www.youtube.com/watch?v=ZXbgUtjxKM8
機能
ユーザー登録関連
⚪︎ ログイン
⚪︎ ログアウト
⚪︎ 新規登録
⚪︎ ユーザー件数を表示車の検索機能
⚪︎ 車の見た目→「かわいい」「かっこいい」「シンプル」「おしゃれ」「レトロ」
⚪︎ 車のサイズ→「ふつう」「すごくおおきい」「おおきい」「ちいさい」
⚪︎ 車の製造国→「国産車」「外車」
⚪︎ 車の用途 →「街乗り」「アウトドア」「スポーツ」カーセンサーAPI連携
⚪︎ DBにある車情報と合致した車情報を取得
⚪︎ cronでキャッシュファイル自動生成苦労した点
検索結果の画像表示高速化
検索の度にAPIからデータを取得していたので、電波の悪い場所では結果の表示に1分以上かかっていました。
毎日APIからデータを自動取得しキャッシュ化することで、ユーザーにストレスのない速度で結果を表示させることができました。EC2へデプロイ
公式ドキュメントを参考にしデプロイしました。
その際、インフラの知識が不足していたため、デプロイに一週間以上かかりました。APIのサービス終了!!
転職活動を始めようとした際、一週間後にカーセンサーAPIサービスが終了すると知りました。
急いで提供元へ問い合わせたところ、
「完全に提供が終了すること」「24時間以上のキャッシュデータの保有も禁止」、ということを告げられました。
その後、他の車データAPIの提供元を調べましたが他にありませんでした。
画像だけでもどうにかならないかと思い、ト◯タや◯産などの画像利用規約を確認しましたが、
営利目的ではない&提供元のURLなどの情報を記載する
としても、利用は禁止でした。
そのためLaravelの勉強も兼ねて、画像問題を解決できるアプリの制作に取り掛かりました。1月 Laravelでアプリ開発
12月末からLaravelの学習を始め、1月からアプリの制作に取り掛かりました。
前回のPHPで制作したポートフォリオとの違い
画像の取得にAPIを用いていましたが、ユーザーから愛車の画像を提供してもらう方針に変更し、機能の追加などを行いました。
完成
アプリのURL:https://pf-kurushira.com
(スマホサイズにも対応しています)
使用技術
使用言語
⚪︎ HTML
⚪︎ CSS
⚪︎ SCSS
⚪︎ PHP 7.4.14
⚪︎ Laravel 6.20.11インフラ
⚪︎ Github Actions 自動デプロイ
⚪︎ Docker 20.10.2 / docker-compose 1.27.4
⚪︎ nginx 1.18
⚪︎ mysql 5.7.31 / PHPMyAdmin
⚪︎ AWS ( EC2, ALB, ACM, S3, RDS, Route53, VPC, EIP, IAM)インフラ構成図
機能一覧
機能 概要 ユーザー管理機能 新規登録・ログイン・ログアウトができます 簡単ログイン機能 ログイン画面のゲストログインをクリックすることで、ゲストユーザーとしてログインできます おすすめ車種検索機能 条件を選択すると、それにあった車種一覧を表示します 検索履歴機能 直近の検索履歴・結果を表示します 画像提供機能 ユーザーの所有している車の画像を提供できます 提供した画像の削除機能 提供した画像を削除できます 提供画像一覧表示機能 自身が提供した画像一覧を表示します。 ユーザー情報編集機能 ご登録いただいたユーザー名・メールアドレスを変更できます Twitterシェア機能 車の検索結果をツイートすることができます レスポンシブ機能 スマホサイズ(320~540px)にも対応しています DB設計
各テーブルについて
テーブル名 説明 users 登録ユーザー情報 cars 登録車情報 histories 直近の検索結果の情報 car_images 提供画像の情報 苦労した点
ユーザー情報編集ページのバリデーション
LaravelのAuth機能のバリデーションを使いまわそうとしましたが、ブラックボックスになっていて苦労しました。
→新しくバリデーションを作成。S3からオブジェクト削除
画像の削除機能でDBからだけでなく、S3からもオブジェクトを削除する必要があり苦労しました。
→解決方法を記事にしました
laravel6でS3に画像アップロード&削除今後の課題
機能
機能 概要 英訳機能 Google Cloud Translation APIを利用して翻訳 通報機能 ユーザーの投票で不適切な画像を削除 技術
⚪︎ テスト
⚪︎ Dockerを用いた本番環境の構築
⚪︎ ECSへデプロイ参考にした学習教材など
PHP/Laravel
・【Udemy】PHP+MySQL(MariaDB) Webサーバーサイドプログラミング入門
・【書籍】詳細!PHP 7+MySQL 入門ノート
・【書籍】PHPフレームワークLaravel入門 第2版
・【書籍】PHPフレームワーク Laravel実践開発
・Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作るAWS
・【Udemy】AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
Docker
・【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン
さいごに
生のPHPでひとつPFを制作したのは、基礎力が身についたので良かったと思います。
今回ポートフォリオ完成を優先したため、ECSではなくEC2へデプロイしました。
まだ課題も多いですが、ブラッシュアップしていきたく思っています。
長くなりましたが、ここまで読んでくださりありがとうございました!!
- 投稿日:2021-03-14T16:55:42+09:00
AWS CLIからEC2インスタンスを起動/停止してみた。超ざっくりまとめてみた。
EC2オンデマンドインスタンスの場合、利用しない時間は停止し、利用するときだけ起動するように制御をしたいものです。
このため、AWS CLIからEC2インスタンスの起動/停止を行うためのやり方を調べ、自分の備忘録としてまとまました。これを見れば、一目で思い出せるはず!
- 作図には AWS 公式アイコンセットを利用してます
- 全般的に概念的な説明のみとしています。
- 以下サイトを参考としました。不明点がある場合は、補足で参照ください。画面キャプチャ付きで細かく説明されてました!
前提
- 説明を極力シンプルにするために、CLI用IAMユーザーの登録、AWS CLIのインストール(+設定:aws configure)は完了している状態から始めます。
- IAMユーザーの作り方は公式サイトを参照してください。
- 登録したユーザには、アクセス権限のポリシー「AmazonEC2FullAccess」を付けておきます。(今回だけならフルには不要なのですが)
起動
実行コマンドaws ec2 start-instances --instance-ids "i-xxxxxxxxxxxxxxxxx"処理結果{ "StartingInstances": [ { "InstanceId": "i-xxxxxxxxxxxxxxxxx", "CurrentState": { "Code": 0, "Name": "pending" }, "PreviousState": { "Code": 80, "Name": "stopped" } } ] }起動完了待ち
実行コマンドaws ec2 wait instance-running --instance-ids "i-xxxxxxxxxxxxxxxxx"停止
実行コマンドaws ec2 stop-instances --instance-ids "i-xxxxxxxxxxxxxxxxx"処理結果{ "StoppingInstances": [ { "InstanceId": "i-xxxxxxxxxxxxxxxxx", "CurrentState": { "Code": 64, "Name": "stopping" }, "PreviousState": { "Code": 16, "Name": "running" } } ] }状態表示(停止中)
停止状態で
describe-instance-status
すると、結果のjsonが空値で返ってきます。実行コマンドaws ec2 describe-instance-status --instance-ids "i-xxxxxxxxxxxxxxxxx"処理結果{ "InstanceStatuses": [] }さいごに
この記事はAWS初学者を導く体系的な動画学習サービス「AWS CloudTech」の課題カリキュラムで作成しました。
このサービスは、テンポの良い/わかりやすい動画説明をもとに、気軽に実践を積み、自分の血肉とできるオンラインスクールです。
コミュニティも存在し、Slackで会員通しの情報交換/質問も気楽にできます。
書籍を購入するような値段で学習ができ、とてもお得です。(個人的な感想です)
では、また次回お会いしましょう!
- 投稿日:2021-03-14T16:42:54+09:00
【AWS】 S3簡単まとめ
S3 (Simple Storage Serviceの略)
AWSのサービスの1つで、クラウド型の
オブジェクトサービス
です。
容量は無制限で、破格の安さと高い耐久性もあり、高可用性を兼ね備えています。(補足)
※1オブジェクトサービス
オブジェクト(ファイル、テキスト、データなど)単位で出し入れが可能なストレージ
です。※2
ストレージ
パソコンのデータを保管しておくための補助記憶装置のことです。
メリット
● ストレージ機能
ストレージの容量により自動的に拡張・縮小されます。
大量のデータを取り扱う際にも最適です。
● 耐久性と可用性の高さ
全てのオブジェクトに対して99.999999999%の耐久性と、可用性においても、1年間で99.99%になるように設計されています。
可用性の99.99%というのは、1年間でアクセスできない時間が52〜53分程度なので、高可用性であると言えます。障害などにも強いため、データを安全に利用することが可能です。
● 低コスト
1GBあたり0.025ドル(日本円で2.72円、3/14時点)と大変安く、ストレージにおいの容量、リクエスト数、データの転送数などで料金が決まるシステムです。
つまり、最低料金や一定額の料金のお支払いがありませんので、使用量に応じた金額になります。
● 静的ファイルの配信
静的なコンテンツを配信する場合には、S3から直接公開することができます。
アクセスによる負荷の軽減に繋がります。
S3のイメージ
※
バケット
S3に保存されるあらゆるオブジェクトを入れておく箱のことです。※
キー
ファイルなどが持つ固有の識別子(名前)のことです。=> 画像やテキストデータがそれぞれURLを持ち、公開閲覧することができます。
終わり
最後までご覧いただきまして、ありがとうございます。
また、もし内容に誤りなどがございましたら、ご指摘いただけますと幸いです。
- 投稿日:2021-03-14T16:26:37+09:00
サーバーの構築からソースコードのデプロイまで(Amazon Linux 2, Nginx + Puma, Rails 6.1, Ruby2.7.2)
この記事での注意
この作業はローカル環境からの作業とサーバーでの作業が複雑に入り交じっています。その為、ターミナルで実行するコマンドの説明に「ローカル」「サーバー」と記載しています。お間違えないように気をつけてください。
アプリケーション名を「sample611」 としています。ご自身のアプリケーション名に読み替えてご参考ください。
サーバーにインストールする環境
- Amazon Linux 2
- Ruby 2.7.2 (rbenv)
- Rails 6.1
- MySQL or PostgreSQL
- Nginx + Puma 5
- Node.js 12
- Yarn
本番サーバーの構築
本番サーバーのEC2のOSがAmazon Linux2の場合の設定手順を紹介します。
1. システムライブラリアップデート
まずはAmazon Linux 2のシステムライブラリを更新します。
サーバー$ sudo yum update -y2. タイムゾーン、ロケール
日本での運用する場合はタイムゾーンと言語の設定を日本にした方がわかりやすいと思います。
サーバー$ sudo timedatectl set-timezone Asia/Tokyo $ sudo localectl set-locale LANG=ja_JP.UTF-83. NTP
サーバーの時刻のずれを自動で補正するタイムサーバーの設定を行います。
サーバー$ yum info chrony $ chronyc sources -v4. 標準パッケージインストール
Rubyのインストールなどで必要になるライブラリをインストールします。
サーバー$ sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel git5. データベースモジュールのインストール
Railsからデータベースにアクセスするためのアダプタをインストールする必要がありますが、そのインストールに必要なライブラリをデータベース別にインストールします。
- PostgreSQLの場合
サーバー$ sudo yum -y install postgresql-devel
- MySQLの場合
サーバー$ sudo yum -y install mysql-devel6. Rubyのインストール
Railsを動かすためにはRubyのインストールが必要です。いろんなインストール方法がありますが、Rubyのバージョンを切り替えることができるrbenvを使った方法を説明します。
6.1 rbenvのインストール
サーバー$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ rbenv -v6.2 ruby-buildのインストール
サーバー$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ cd ~/.rbenv/plugins/ruby-build $ sudo ./install.sh $ rbenv install -l6.3 Rubyのインストール
rbenvとruby-buildをインストールが終わったので、Rubyのインストールを行います。
サーバー$ rbenv install 2.7.2 $ rbenv global 2.7.2rubyのインストールにはすこし時間がかかります。
rbenv globalでシステム全体で使用するRubyのバージョンを指定しています。7. Rails 6で必要なモジュールのインストール
7.1 Node.jsのインストール
Rails 6からは Node.js や Yarn が必要になりました。Node.jsはサーバーサイドでのJavaScript実行環境で、Yarnはfacebook製のJavaScriptのパッケージマネージャーです。
サーバー$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash - $ sudo yum install -y nodejs $ sudo npm install -g n $ sudo n stable $ sudo ln -snf /usr/local/bin/node /usr/bin/node7.2 Yarnのインストール
サーバー$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo $ sudo yum install yarn -y8. Railsのインストール
Rails 6のインストールを行います。gem install railsでもインストールできますが、ここではパッケージ管理ソフトbundlerからインストールする方法を紹介します。
サーバー$ cd ~ $ mkdir rails $ cd rails $ bundle init $ vim Gemfile (gem "rails"をコメントアウト解除) $ bundle install $ bundle exec rails -v (インストールされたことを確認) $ cd .. $ rm -rf railsデータベースの設定
9. 本番データベースの作成
ここではRDSの設定については詳しく説明しません。すでにRDSにデータベースが設定されていることを前提に進めていきますが、下記をご確認ください。
- RDSにて作成したデータベースのユーザー名、パスワード、データベースエンドポイントをご確認ください。
- RDSのセキュリティグループでウェブサーバーとなるEC2のセキュリティグループのアクセス許可を設定してください。
10. Railsアプリと本番データベースの接続設定
Railsとデータベースの接続設定を行います。データベースの設定にはデータベースにアクセスするためのパスワードが含まれますが、これを直接database.ymlに記載すると、github上でパスワードを知ることができてしまい危険です。
こういった機密情報は config/credentials.yml.enc にセットします。(Rails5.2以降で可能)
このファイルはエディタで表示すると暗号化された文字列になっていますが、 master.key を使うことで閲覧、編集することができます。この credentials.yml.enc と master.key の関係を理解しておいてください。
次のコマンドでcredentials.yml.encを編集します。ここではエディタをvimに指定しています。
ローカル$ EDITOR=vim bin/rails credentials:edit下記のようにdbの項目を追記し、RDS作成時に設定したユーザー名、パスワード、データベースエンドポイントを記述します。
credential.yml.enc(ローカル)# aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx db: username: (username) password: (password) host: (database endpoint)終わったら、:wqでエディタを終えます。
次に本番環境において、データベースの設定が適用されるようconfig/database.ymlを編集します。database.ymlの最後の方にproductionの項があります。そこを下記のように修正します。
database.yml(ローカル)production: <<: *default database: sample611_production username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> host: <%= Rails.application.credentials.db[:host] %> port: 5432Rails.application.credentials.dbとすることでcredentials.yml.encのdbの項を読みにいきます。
portはデータベースで使用するポートを指定します。一般的にはPostgreSQLの場合は 5432、MySQLの場合は 3306 になります。ここで、改修したコードをいったんコミットし、githubへプッシュしましょう。
ローカル$ git add . $ git commit -m "Setup database" $ git push origin masterデプロイ設定
デプロイツールCapistranoを使ったデプロイの設定を行います。
11. Capistranoのインストール
Capistranoをインストールします。下記のようにGemfileのdevelopmentグループにcapistrano, capistrano-rails, capistrano-rbenvを追加し、bundle installします。
Gemfile(ローカル)group :development do gem "capistrano", "~> 3.14", require: false gem "capistrano-rails", "~> 1.6", require: false gem 'capistrano-rbenv', '~> 2.2' endローカル$ bundle install $ bundle exec cap install12. Capfileの設定
下記のようにCapfileに追記します。
Capfile(ローカル): # require "capistrano/rails/migrations" # require "capistrano/passenger" require 'capistrano/rails' require 'capistrano/rbenv' :13. デプロイの設定
Capistranoのデプロイ設定を行います。全体的なデプロイの設定を「config/deploy.rb」、本番環境用の設定を「config/deploy/production.rb」に記述します。
config/deploy.rb(ローカル)lock "~> 3.15.0" set :application, "sample611" # 自分のリポジトリを設定 set :repo_url, "git@github.com:yukeippi/sample611.git" # rbenvの設定 set :rbenv_type, :user set :rbenv_ruby, '2.7.2' # Railsアプリの設置先 set :deploy_to, "/var/rails/sample611" # 共有ファイルの設定 append :linked_files, "config/master.key" # 共有ディレクトリの設定 append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system" # リリース保存数 set :keep_releases, 5linked_filesはデフォルトではconfig/database.ymlとなっていますが、config/master.keyに変更してください。
次にconfig/deploy/production.rbを編集します。下記の (server ip) にはデプロイ先EC2のIPをセットしてください。
githubへのキー登録については下記をご参照ください。config/deploy/production.rb(ローカル)set :rails_env, 'production' set :branch, 'master' # githubへの設定 set :ssh_options, { auth_methods: [ 'publickey' ], keys: [ '~/.ssh/aws.pem' ], } server '(server IP)', user: 'ec2-user', roles: %w{app db web}区切りが良いので、ここでいったんコミット、プッシュしましょう。(プッシュは任意です)
ローカル$ git add . $ git commit -m "Setup capistrano" $ git push oririn master14. Githubへのキー登録
デプロイ時にデプロイ先サーバーがgithubからソースコードを取得するための設定を行います。
この設定は下記の記事をご参照ください。
15. デプロイ先ディレクトリの作成
Railsアプリのプログラムの設置(デプロイ)を行います。アプリケーションの設置場所を「/var/rails」、実行者を「ec2-user」とした場合、下記のコマンドを実行し、ディレクトリを作ります。
サーバー$ cd /var/ $ sudo mkdir rails $ sudo chown ec2-user:ec2-user railsここで「cap deploy:check」を実行しますが、下記のように失敗します。この処理の目的は、Capistranoにデプロイに必要なディレクトリを作らせることです。
ローカル$ bundle exec cap production deploy:check 00:02 deploy:check:make_linked_dirs 01 mkdir -p /var/rails/sample611/shared/config ✔ 01 ec2-user@(server IP) 0.078s 00:02 deploy:check:linked_files ERROR linked file /var/rails/sample611/shared/config/master.key does not exist on (server IP)エラーメッセージにあるように「master.key」がないことが原因です。サーバーに入って下記のようにmaster.keyを作成してください。
サーバー$ cd /var/rails/sample611/shared/config/ $ vim master.key (ローカルにあるmaster.keyを貼り付け)これで問題は解決しましたので、再度、デプロイチェックを行います。
ローカル$ bundle exec cap production deploy:check成功するはずです。これでデプロイ先ディレクトリができました。
16. Databaseのcreate
しかし、まだこの時点でもデプロイ途中で失敗します。それはデータベースがcreateされていないからです。deployでデータベースのmigrateは実行しますが、createしていないため、migrateできずに失敗してしまいます。
そこで、失敗前提でデプロイを実行し、そのときにデプロイされたソースコードを使ってcreateします。
ローカル$ bundle exec cap production deploy最初はgemをインストールするため、時間がかかります。
しばらく待つとデプロイは終わり、途中で失敗していることが確認できます。その後、本番サーバーに入り、下記のようにデプロイされたソースコードのルートに移動し、データベースを作成します。サーバー$ cd /var/rails/sample611/releases/(最新リリース)/ $ bundle exec rails db:create RAILS_ENV=production(最新リリース)は「20210216104333」といったディレクトリ作成日時を意味するディレクトリを指します。ソースコードがデプロイされると、Capistranoがこのようなディレクトリを作成し、そこにプログラムを保存します。
これでデータベースが作成されたら、デプロイが可能になります。
再度デプロイします。ローカル$ bundle exec cap production deployこれで成功するはずです。
WebサーバーとRailsアプリの連携
17. Pumaの設定
本番環境のPumaの設定を行います。
config/puma/production.rb(ローカル)# Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } threads min_threads_count, max_threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } # Specifies the `environment` that Puma will run in. # environment ENV.fetch("RAILS_ENV") { "production" } # Specifies the `pidfile` that Puma will use. # pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). # # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart bind "unix:///var/rails/sample611/shared/tmp/sockets/puma.sock"RAILS_ENVをproductionに指定しているところと、最下行でsocketを指定しているのがポイントです。
ここでいったんコミット、プッシュしてください。
ローカル$ git add . $ git commit -m "Setup puma for production" $ git push origin master18. Nginxのインストール
ここからはサーバーでの作業になります。
サーバーにNginxをインストールします。サーバー$ sudo amazon-linux-extras install nginx1 -y19. NginxとPumaの紐付け
次にNginxとPumaを紐付けるための設定ファイルを作成します。ポイントはuptreamの設定、rootの指定、proxy_passの指定です。
サーバー$ sudo vim /etc/nginx/conf.d/sample611.conf/etc/nginx/conf.d/sample611.conf(サーバー)upstream puma { server unix:///var/rails/sample611/shared/tmp/sockets/puma.sock fail_timeout=0; } server { listen 80; server_name example.com; root /var/rails/sample611/current/public; try_files $uri/index.html $uri @railsapp; location @railsapp { proxy_pass http://puma; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; }upstream puma内にあるpuma.sockのパスに気をつけてください。これは15のbindで設定したパスにあわせなければなりません。
20. Pumaのサービス設定
次にpumaをsystemctlで起動や再起動ができるように設定を行います。
サーバー$ sudo vim /etc/systemd/system/puma.service/etc/systemd/system/puma.service(サーバー)[Unit] Description=Puma HTTP Server After=network.target [Service] Type=simple Environment="RAILS_ENV=production" WorkingDirectory=/var/rails/sample611/current ExecStart=/home/ec2-user/.rbenv/shims/bundle exec /var/rails/sample611/shared/bundle/ruby/2.7.0/bin/puma -C /var/rails/sample611/current/config/puma/production.rb Restart=always [Install] WantedBy=multi-user.targetここでpumaの実行パスや実行時の設定ファイルを指定しています。
あと、このままでは実行権限がないため、下記のコマンドでpuma.serviceに実行権限を付与してください。サーバー$ sudo chmod +x /etc/systemd/system/puma.serviceこれでサーバー側の設定は終わりです。
21. Puma, Nginxの起動
いよいよウェブサーバー、アプリケーションサーバーの起動です。まず、Pumaを起動します。
サーバー$ sudo systemctl daemon-reload $ sudo systemctl start puma下記のコマンドで起動を確認します。
サーバー$ sudo systemctl status puma ● puma.service - Puma HTTP Server for sample611 (production_mysql) Loaded: loaded (/etc/systemd/system/puma.service; enabled; vendor preset: disabled) Active: active (running) since 土 2021-02-20 15:47:30 JST; 27min ago Main PID: 2876 (bundle) CGroup: /system.slice/puma.service └─2876 puma 5.1.1 (tcp://0.0.0.0:3000,unix:///var/rails/sample611/shared/tmp/sockets/puma.sock) [20210216072308]上記のようになければ「Active: active」になっていれば、起動成功です。
もし「Active: inactive」になっていれば、何かしらの設定に間違いがある可能性があります。
journalctl -xe等を使って原因を調べてください。次にnginxの起動します。
サーバー$ sudo systemctl start nginx.serviceこれでブラウザを使って下記のようにサイトにアクセスすれば画面に表示されるはずです。
http://(サイトのIP)/
21. デプロイ時のリスタート設定
プログラムをデプロイしたときはアプリケーションサーバーをリスタートする必要があります。capistranoのrestartタスクを追加しておくと、それも自動で実行してくれます。
config/deploy.rb(ローカル)namespace :deploy do task :restart do on roles(:web), in: :sequence, wait: 5 do within release_path do execute "sudo systemctl daemon-reload" execute "sudo systemctl restart puma" end end end after :finishing, :restart endこれでローカル側のコード改修が終わりです。
最後にここまでをコミットしましょう。ローカル$ git add . $ git commit -m "Setup restart puma"再起動することを確認するため、デプロイします。
ローカル$ bundle exec cap production deploy : 00:34 deploy:cleanup Keeping 5 of 6 deployed releases on (server IP) 01 rm -rf /var/rails/sample611/releases/20210314010936 ✔ 01 ec2-user@(server IP) 0.797s 00:35 deploy:restart 01 sudo systemctl daemon-reload ✔ 01 ec2-user@(server IP) 0.199s 02 sudo systemctl restart puma ✔ 02 ec2-user@(server IP) 0.094s 00:35 deploy:log_revision 01 echo "Branch master (at 0e3b185044e3a56f20a3bf37d7c6ce31f5a92b54) deployed as release 20210314015609 b… ✔ 01 ec2-user@(server IP) 0.119sデプロイログからrestartが実行されていることがわかると思います。
これでデプロイは成功です!お疲れ様でした。puma, nginxの自動起動設定
最後にpuma,nginxの自動起動設定を行っておくとよいでしょう。これを行うことでサーバーを再起動しても自動でWebアプリケーションを起動してくれます。
サーバー$ sudo systemctl enable puma.service $ sudo systemctl enable nginx.service以上です。
- 投稿日:2021-03-14T16:26:37+09:00
Rails 6アプリをAWSへのデプロイする手順
この記事での注意
この作業はローカル環境からの作業とサーバーでの作業が複雑に入り交じっています。その為、ターミナルで実行するコマンドの説明に「ローカル」「サーバー」と記載しています。お間違えないように気をつけてください。
アプリケーション名を「sample611」 としています。ご自身のアプリケーション名に読み替えてご参考ください。
サーバーにインストールする環境
- Amazon Linux 2
- Ruby 2.7.2 (rbenv)
- Rails 6.1
- MySQL or PostgreSQL
- Nginx + Puma 5
- Node.js 12
- Yarn
本番サーバーの構築
本番サーバーのEC2のOSがAmazon Linux2の場合の設定手順を紹介します。
1. システムライブラリアップデート
まずはAmazon Linux 2のシステムライブラリを更新します。
サーバー$ sudo yum update -y2. タイムゾーン、ロケール
日本での運用する場合はタイムゾーンと言語の設定を日本にした方がわかりやすいと思います。
サーバー$ sudo timedatectl set-timezone Asia/Tokyo $ sudo localectl set-locale LANG=ja_JP.UTF-83. NTP
サーバーの時刻のずれを自動で補正するタイムサーバーの設定を行います。
サーバー$ yum info chrony $ chronyc sources -v4. 標準パッケージインストール
Rubyのインストールなどで必要になるライブラリをインストールします。
サーバー$ sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel git5. データベースモジュールのインストール
Railsからデータベースにアクセスするためのアダプタをインストールする必要がありますが、そのインストールに必要なライブラリをデータベース別にインストールします。
- PostgreSQLの場合
サーバー$ sudo yum -y install postgresql-devel
- MySQLの場合
サーバー$ sudo yum -y install mysql-devel6. Rubyのインストール
Railsを動かすためにはRubyのインストールが必要です。いろんなインストール方法がありますが、Rubyのバージョンを切り替えることができるrbenvを使った方法を説明します。
6.1 rbenvのインストール
サーバー$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ rbenv -v6.2 ruby-buildのインストール
サーバー$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ cd ~/.rbenv/plugins/ruby-build $ sudo ./install.sh $ rbenv install -l6.3 Rubyのインストール
rbenvとruby-buildをインストールが終わったので、Rubyのインストールを行います。
サーバー$ rbenv install 2.7.2 $ rbenv global 2.7.2rubyのインストールにはすこし時間がかかります。
rbenv globalでシステム全体で使用するRubyのバージョンを指定しています。7. Rails 6で必要なモジュールのインストール
7.1 Node.jsのインストール
Rails 6からは Node.js や Yarn が必要になりました。Node.jsはサーバーサイドでのJavaScript実行環境で、Yarnはfacebook製のJavaScriptのパッケージマネージャーです。
サーバー$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash - $ sudo yum install -y nodejs $ sudo npm install -g n $ sudo n stable $ sudo ln -snf /usr/local/bin/node /usr/bin/node7.2 Yarnのインストール
サーバー$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo $ sudo yum install yarn -y8. Railsのインストール
Rails 6のインストールを行います。gem install railsでもインストールできますが、ここではパッケージ管理ソフトbundlerからインストールする方法を紹介します。
サーバー$ cd ~ $ mkdir rails $ cd rails $ bundle init $ vim Gemfile (gem "rails"をコメントアウト解除) $ bundle install $ bundle exec rails -v (インストールされたことを確認) $ cd .. $ rm -rf railsデータベースの設定
9. 本番データベースの作成
ここではRDSの設定については詳しく説明しません。すでにRDSにデータベースが設定されていることを前提に進めていきますが、下記をご確認ください。
- RDSにて作成したデータベースのユーザー名、パスワード、データベースエンドポイントをご確認ください。
- RDSのセキュリティグループでウェブサーバーとなるEC2のセキュリティグループのアクセス許可を設定してください。
10. Railsアプリと本番データベースの接続設定
Railsとデータベースの接続設定を行います。データベースの設定にはデータベースにアクセスするためのパスワードが含まれますが、これを直接database.ymlに記載すると、github上でパスワードを知ることができてしまい危険です。
こういった機密情報は config/credentials.yml.enc にセットします。(Rails5.2以降で可能)
このファイルはエディタで表示すると暗号化された文字列になっていますが、 master.key を使うことで閲覧、編集することができます。この credentials.yml.enc と master.key の関係を理解しておいてください。
次のコマンドでcredentials.yml.encを編集します。ここではエディタをvimに指定しています。
ローカル$ EDITOR=vim bin/rails credentials:edit下記のようにdbの項目を追記し、RDS作成時に設定したユーザー名、パスワード、データベースエンドポイントを記述します。
credential.yml.enc(ローカル)# aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx db: username: (username) password: (password) host: (database endpoint)終わったら、:wqでエディタを終えます。
次に本番環境において、データベースの設定が適用されるようconfig/database.ymlを編集します。database.ymlの最後の方にproductionの項があります。そこを下記のように修正します。
database.yml(ローカル)production: <<: *default database: sample611_production username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> host: <%= Rails.application.credentials.db[:host] %> port: 5432Rails.application.credentials.dbとすることでcredentials.yml.encのdbの項を読みにいきます。
portはデータベースで使用するポートを指定します。一般的にはPostgreSQLの場合は 5432、MySQLの場合は 3306 になります。ここで、改修したコードをいったんコミットし、githubへプッシュしましょう。
ローカル$ git add . $ git commit -m "Setup database" $ git push origin masterデプロイ設定
デプロイツールCapistranoを使ったデプロイの設定を行います。
11. Capistranoのインストール
Capistranoをインストールします。下記のようにGemfileのdevelopmentグループにcapistrano, capistrano-rails, capistrano-rbenvを追加し、bundle installします。
Gemfile(ローカル)group :development do gem "capistrano", "~> 3.14", require: false gem "capistrano-rails", "~> 1.6", require: false gem 'capistrano-rbenv', '~> 2.2' endローカル$ bundle install $ bundle exec cap install12. Capfileの設定
下記のようにCapfileに追記します。
Capfile(ローカル): # require "capistrano/rails/migrations" # require "capistrano/passenger" require 'capistrano/rails' require 'capistrano/rbenv' :13. デプロイの設定
Capistranoのデプロイ設定を行います。全体的なデプロイの設定を「config/deploy.rb」、本番環境用の設定を「config/deploy/production.rb」に記述します。
config/deploy.rb(ローカル)lock "~> 3.15.0" set :application, "sample611" # 自分のリポジトリを設定 set :repo_url, "git@github.com:yukeippi/sample611.git" # rbenvの設定 set :rbenv_type, :user set :rbenv_ruby, '2.7.2' # Railsアプリの設置先 set :deploy_to, "/var/rails/sample611" # 共有ファイルの設定 append :linked_files, "config/master.key" # 共有ディレクトリの設定 append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system" # リリース保存数 set :keep_releases, 5linked_filesはデフォルトではconfig/database.ymlとなっていますが、config/master.keyに変更してください。
次にconfig/deploy/production.rbを編集します。下記の (server ip) にはデプロイ先EC2のIPをセットしてください。
githubへのキー登録については下記をご参照ください。config/deploy/production.rb(ローカル)set :rails_env, 'production' set :branch, 'master' # githubへの設定 set :ssh_options, { auth_methods: [ 'publickey' ], keys: [ '~/.ssh/aws.pem' ], } server '(server IP)', user: 'ec2-user', roles: %w{app db web}区切りが良いので、ここでいったんコミット、プッシュしましょう。(プッシュは任意です)
ローカル$ git add . $ git commit -m "Setup capistrano" $ git push oririn master14. Githubへのキー登録
デプロイ時にデプロイ先サーバーがgithubからソースコードを取得するための設定を行います。
この設定は下記の記事をご参照ください。
15. デプロイ先ディレクトリの作成
Railsアプリのプログラムの設置(デプロイ)を行います。アプリケーションの設置場所を「/var/rails」、実行者を「ec2-user」とした場合、下記のコマンドを実行し、ディレクトリを作ります。
サーバー$ cd /var/ $ sudo mkdir rails $ sudo chown ec2-user:ec2-user railsここで「cap deploy:check」を実行しますが、下記のように失敗します。この処理の目的は、Capistranoにデプロイに必要なディレクトリを作らせることです。
ローカル$ bundle exec cap production deploy:check 00:02 deploy:check:make_linked_dirs 01 mkdir -p /var/rails/sample611/shared/config ✔ 01 ec2-user@(server IP) 0.078s 00:02 deploy:check:linked_files ERROR linked file /var/rails/sample611/shared/config/master.key does not exist on (server IP)エラーメッセージにあるように「master.key」がないことが原因です。サーバーに入って下記のようにmaster.keyを作成してください。
サーバー$ cd /var/rails/sample611/shared/config/ $ vim master.key (ローカルにあるmaster.keyを貼り付け)これで問題は解決しましたので、再度、デプロイチェックを行います。
ローカル$ bundle exec cap production deploy:check成功するはずです。これでデプロイ先ディレクトリができました。
16. Databaseのcreate
しかし、まだこの時点でもデプロイ途中で失敗します。それはデータベースがcreateされていないからです。deployでデータベースのmigrateは実行しますが、createしていないため、migrateできずに失敗してしまいます。
そこで、失敗前提でデプロイを実行し、そのときにデプロイされたソースコードを使ってcreateします。
ローカル$ bundle exec cap production deploy最初はgemをインストールするため、時間がかかります。
しばらく待つとデプロイは終わり、途中で失敗していることが確認できます。その後、本番サーバーに入り、下記のようにデプロイされたソースコードのルートに移動し、データベースを作成します。サーバー$ cd /var/rails/sample611/releases/(最新リリース)/ $ bundle exec rails db:create RAILS_ENV=production(最新リリース)は「20210216104333」といったディレクトリ作成日時を意味するディレクトリを指します。ソースコードがデプロイされると、Capistranoがこのようなディレクトリを作成し、そこにプログラムを保存します。
これでデータベースが作成されたら、デプロイが可能になります。
再度デプロイします。ローカル$ bundle exec cap production deployこれで成功するはずです。
WebサーバーとRailsアプリの連携
17. Pumaの設定
本番環境のPumaの設定を行います。
config/puma/production.rb(ローカル)# Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } threads min_threads_count, max_threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } # Specifies the `environment` that Puma will run in. # environment ENV.fetch("RAILS_ENV") { "production" } # Specifies the `pidfile` that Puma will use. # pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). # # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart bind "unix:///var/rails/sample611/shared/tmp/sockets/puma.sock"RAILS_ENVをproductionに指定しているところと、最下行でsocketを指定しているのがポイントです。
ここでいったんコミット、プッシュしてください。
ローカル$ git add . $ git commit -m "Setup puma for production" $ git push origin master18. Nginxのインストール
ここからはサーバーでの作業になります。
サーバーにNginxをインストールします。サーバー$ sudo amazon-linux-extras install nginx1 -y19. NginxとPumaの紐付け
次にNginxとPumaを紐付けるための設定ファイルを作成します。ポイントはuptreamの設定、rootの指定、proxy_passの指定です。
サーバー$ sudo vim /etc/nginx/conf.d/sample611.conf/etc/nginx/conf.d/sample611.conf(サーバー)upstream puma { server unix:///var/rails/sample611/shared/tmp/sockets/puma.sock fail_timeout=0; } server { listen 80; server_name example.com; root /var/rails/sample611/current/public; try_files $uri/index.html $uri @railsapp; location @railsapp { proxy_pass http://puma; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; }upstream puma内にあるpuma.sockのパスに気をつけてください。これは15のbindで設定したパスにあわせなければなりません。
20. Pumaのサービス設定
次にpumaをsystemctlで起動や再起動ができるように設定を行います。
サーバー$ sudo vim /etc/systemd/system/puma.service/etc/systemd/system/puma.service(サーバー)[Unit] Description=Puma HTTP Server After=network.target [Service] Type=simple Environment="RAILS_ENV=production" WorkingDirectory=/var/rails/sample611/current ExecStart=/home/ec2-user/.rbenv/shims/bundle exec /var/rails/sample611/shared/bundle/ruby/2.7.0/bin/puma -C /var/rails/sample611/current/config/puma/production.rb Restart=always [Install] WantedBy=multi-user.targetここでpumaの実行パスや実行時の設定ファイルを指定しています。
あと、このままでは実行権限がないため、下記のコマンドでpuma.serviceに実行権限を付与してください。サーバー$ sudo chmod +x /etc/systemd/system/puma.serviceこれでサーバー側の設定は終わりです。
21. Puma, Nginxの起動
いよいよウェブサーバー、アプリケーションサーバーの起動です。まず、Pumaを起動します。
サーバー$ sudo systemctl daemon-reload $ sudo systemctl start puma下記のコマンドで起動を確認します。
サーバー$ sudo systemctl status puma ● puma.service - Puma HTTP Server for sample611 (production_mysql) Loaded: loaded (/etc/systemd/system/puma.service; enabled; vendor preset: disabled) Active: active (running) since 土 2021-02-20 15:47:30 JST; 27min ago Main PID: 2876 (bundle) CGroup: /system.slice/puma.service └─2876 puma 5.1.1 (tcp://0.0.0.0:3000,unix:///var/rails/sample611/shared/tmp/sockets/puma.sock) [20210216072308]上記のようになければ「Active: active」になっていれば、起動成功です。
もし「Active: inactive」になっていれば、何かしらの設定に間違いがある可能性があります。
journalctl -xe等を使って原因を調べてください。次にnginxの起動します。
サーバー$ sudo systemctl start nginx.serviceこれでブラウザを使って下記のようにサイトにアクセスすれば画面に表示されるはずです。
http://(サイトのIP)/
21. デプロイ時のリスタート設定
プログラムをデプロイしたときはアプリケーションサーバーをリスタートする必要があります。capistranoのrestartタスクを追加しておくと、それも自動で実行してくれます。
config/deploy.rb(ローカル)namespace :deploy do task :restart do on roles(:web), in: :sequence, wait: 5 do within release_path do execute "sudo systemctl daemon-reload" execute "sudo systemctl restart puma" end end end after :finishing, :restart endこれでローカル側のコード改修が終わりです。
最後にここまでをコミットしましょう。ローカル$ git add . $ git commit -m "Setup restart puma"再起動することを確認するため、デプロイします。
ローカル$ bundle exec cap production deploy : 00:34 deploy:cleanup Keeping 5 of 6 deployed releases on (server IP) 01 rm -rf /var/rails/sample611/releases/20210314010936 ✔ 01 ec2-user@(server IP) 0.797s 00:35 deploy:restart 01 sudo systemctl daemon-reload ✔ 01 ec2-user@(server IP) 0.199s 02 sudo systemctl restart puma ✔ 02 ec2-user@(server IP) 0.094s 00:35 deploy:log_revision 01 echo "Branch master (at 0e3b185044e3a56f20a3bf37d7c6ce31f5a92b54) deployed as release 20210314015609 b… ✔ 01 ec2-user@(server IP) 0.119sデプロイログからrestartが実行されていることがわかると思います。
これでデプロイは成功です!お疲れ様でした。puma, nginxの自動起動設定
最後にpuma,nginxの自動起動設定を行っておくとよいでしょう。これを行うことでサーバーを再起動しても自動でWebアプリケーションを起動してくれます。
サーバー$ sudo systemctl enable puma.service $ sudo systemctl enable nginx.service以上です。
- 投稿日:2021-03-14T15:24:40+09:00
AWS EC-2 docker + wordpress インストール
AWSにEC2作る
ec2でdockerとwordpressをインストール
sshでログイン
__| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-x-x-x-x ~]$yumをアップデート
[ec2-user@ip-x-x-x-x ~]$ sudo yum update -y Loaded plugins: extras_suggestions, langpacks, priorities, update-motd amzn2-core | 3.7 kB 00:00:00 No packages marked for updatedocker準備
dockerをインストール
sudo amazon-linux-extras install docker -y [ec2-user@ip-172-31-20-108 ~]$ sudo amazon-linux-extras install docker -y Installing docker Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Cleaning repos: amzn2-core amzn2extra-docker 10 metadata files removed 4 sqlite files removed 0 metadata files removed Loaded plugins: extras_suggestions, langpacks, priorities, update-motd amzn2-core | 3.7 kB 00:00:00 amzn2extra-docker | 3.0 kB 00:00:00 (1/5): amzn2-core/2/x86_64/group_gz | 2.5 kB 00:00:00 (2/5): amzn2extra-docker/2/x86_64/updateinfo | 76 B 00:00:00 (3/5): amzn2extra-docker/2/x86_64/primary_db | 75 kB 00:00:00 (4/5): amzn2-core/2/x86_64/updateinfo | 350 kB 00:00:00 (5/5): amzn2-core/2/x86_64/primary_db | 50 MB 00:00:00 Resolving Dependencies --> Running transaction check ---> Package docker.x86_64 0:19.03.13ce-1.amzn2 will be installed --> Processing Dependency: runc >= 1.0.0 for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: containerd >= 1.3.2 for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: pigz for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: libcgroup for package: docker-19.03.13ce-1.amzn2.x86_64 --> Running transaction check ---> Package containerd.x86_64 0:1.4.1-2.amzn2 will be installed ---> Package libcgroup.x86_64 0:0.41-21.amzn2 will be installed ---> Package pigz.x86_64 0:2.3.4-1.amzn2.0.1 will be installed ---> Package runc.x86_64 0:1.0.0-0.1.20200826.gitff819c7.amzn2 will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================================================================================================================ Package Arch Version Repository Size ============================================================================================================================================================================ Installing: docker x86_64 19.03.13ce-1.amzn2 amzn2extra-docker 37 M Installing for dependencies: containerd x86_64 1.4.1-2.amzn2 amzn2extra-docker 24 M libcgroup x86_64 0.41-21.amzn2 amzn2-core 66 k pigz x86_64 2.3.4-1.amzn2.0.1 amzn2-core 81 k runc x86_64 1.0.0-0.1.20200826.gitff819c7.amzn2 amzn2extra-docker 3.7 M Transaction Summary ============================================================================================================================================================================ Install 1 Package (+4 Dependent packages) Total download size: 65 M Installed size: 270 M Downloading packages: (1/5): libcgroup-0.41-21.amzn2.x86_64.rpm | 66 kB 00:00:00 (2/5): pigz-2.3.4-1.amzn2.0.1.x86_64.rpm | 81 kB 00:00:00 (省略)dockerサービス起動
[ec2-user@ip-x-x-x-x ~]$ sudo systemctl start dockerdockerサービス状態確認
[ec2-user@ip-x-x-x-x ~]$ sudo systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) Active: active (running) since Sun 2021-03-14 05:59:36 UTC; 25s ago Docs: https://docs.docker.com Process: 3722 ExecStartPre=/usr/libexec/docker/docker-setup-runtimes.sh (code=exited, status=0/SUCCESS) Process: 3709 ExecStartPre=/bin/mkdir -p /run/docker (code=exited, status=0/SUCCESS) Main PID: 3731 (dockerd) Tasks: 8 Memory: 36.6M CGroup: /system.slice/docker.service mq3731 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit nofile=1024:4096 Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354394783Z" level=info msg="scheme \"unix\" not registered, f...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354629298Z" level=info msg="ccResolverWrapper: sending update...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354858217Z" level=info msg="ClientConn switching balancer to ...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.394039324Z" level=info msg="Loading containers: start." Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.858998545Z" level=info msg="Default bridge (docker0) is assig...ddress" Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.915341056Z" level=info msg="Loading containers: done." Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.942822332Z" level=info msg="Docker daemon" commit=4484c46 gra...3.13-ce Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.943274164Z" level=info msg="Daemon has completed initialization" Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal systemd[1]: Started Docker Application Container Engine. Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.967245548Z" level=info msg="API listen on /var/run/docker.sock" Hint: Some lines were ellipsized, use -l to show in full.dockerをec2-userで実行可能にする
[ec2-user@ip-x-x-x-x ~]$ sudo usermod -a -G docker ec2-user [ec2-user@ip-x-x-x-x ~]$ exit※ここで一度ログアウトして再度ログインすることで権限が反映される
docker-compose
docker-composeインストール
[ec2-user@ip-x-x-x-x ~]$ sudo curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 633 100 633 0 0 9447 0 --:--:-- --:--:-- --:--:-- 9447 100 11.6M 100 11.6M 0 0 22.2M 0 --:--:-- --:--:-- --:--:-- 44.5M [ec2-user@ip-x-x-x-x ~]$ sudo chmod +x /usr/local/bin/docker-composecurlのURLは↓ここでdocker-composeのバージョンを確認して適宜書き換える。(2021/03/14時点は1.28.5)
https://docs.docker.com/compose/install/#install-compose-on-linux-systemsバージョン確認
[ec2-user@ip-x-x-x-x ~]$ docker-compose --version docker-compose version 1.28.5, build c4eb3a1fwordpress
docker-compose.ymlファイルを用意
[ec2-user@ip-x-x-x-x ~]$ pwd /home/ec2-user [ec2-user@ip-x-x-x-x ~]$ mkdir wordpress [ec2-user@ip-x-x-x-x ~]$ vi ~/wordpress/docker-compose.ymldocker-compose.ymlversion: '3.1' services: wordpress: container_name: wp-trial image: wordpress restart: always ports: - 55555:80 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: exampleuser WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_NAME: exampledb volumes: - wordpress:/var/www/html db: container_name: wp-db image: mysql:5.7 restart: always environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - db:/var/lib/mysql volumes: wordpress: db:
wordpressをビルドして起動
docker-compose.ymlが入っているディレクトリに移動して
docker-compose up
する。[ec2-user@ip-x-x-x-x ~]$ cd wordpress/ [ec2-user@ip-x-x-x-x wordpress]$ pwd /home/ec2-user/wordpress [ec2-user@ip-x-x-x-x wordpress]$ ls -la total 4 drwxrwxr-x 2 ec2-user ec2-user 32 Mar 14 06:12 . drwx------ 5 ec2-user ec2-user 142 Mar 14 06:12 .. -rw-rw-r-- 1 ec2-user ec2-user 638 Mar 14 06:12 docker-compose.yml[ec2-user@ip-x-x-x-x wordpress]$ docker-compose up --build -d Creating network "wordpress_default" with the default driver Creating volume "wordpress_wordpress" with default driver Creating volume "wordpress_db" with default driver Pulling wordpress (wordpress:)... latest: Pulling from library/wordpress 6f28985ad184: Pull complete db883aae18bc: Pull complete ffae70ea03a9: Pull complete 1e8027612378: Pull complete 3ec32e53dce5: Pull complete 3bb74037bf77: Pull complete feda0fbd85b1: Pull complete b2244185b327: Pull complete 8852ae668073: Pull complete 985e21deb66e: Pull complete f262da4e7afa: Pull complete 157f3d683e13: Pull complete 990684a56233: Pull complete c80999e49328: Pull complete 02585da80b89: Pull complete d68ab7635a0a: Pull complete 5a577fb48682: Pull complete d27e8a2c96b8: Pull complete f94fa08d2764: Pull complete 6db2ebd4cef9: Pull complete 9c4c1399bbb1: Pull complete Digest: sha256:92fb18e472ce46f289b475457289075c20387374d79bc41724689aa88112eab1 Status: Downloaded newer image for wordpress:latest Pulling db (mysql:5.7)... 5.7: Pulling from library/mysql 6f28985ad184: Already exists e7cd18945cf6: Pull complete ee91068b9313: Pull complete b4efa1a4f93b: Pull complete f220edfa5893: Pull complete 74a27d3460f8: Pull complete 2e11e23b7542: Pull complete 39ac93d44c47: Pull complete dfd9db50d4ea: Pull complete 4e97f54f11a3: Pull complete ebfb95795c5f: Pull complete Digest: sha256:5f649e87093a5b6b863f5c5277b2d2aa797b04d68657494e0f28ffabfa25e781 Status: Downloaded newer image for mysql:5.7 Creating wp-trial ... done Creating wp-db ... done[ec2-user@ip-172-31-20-108 wordpress]$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d0296aeb5318 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp, 33060/tcp wp-db c01446d87997 wordpress "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:55555->80/tcp wp-trialWordpressにアクセスしてみる
参考
AWS公式 Dockerインストール手順
AWS EC2インスタンスにdockerとdocker-composeをインストールして簡単なWEBサービスを立ち上げる方法
- 投稿日:2021-03-14T15:24:40+09:00
AWS EC2 docker + wordpress インストール
AWSにEC2作る
AMIの選択
インスタンスタイプの選択
インスタンスの詳細の設定
自動割り当てパブリックIPを「有効」にした以外はデフォルト設定。
ストレージの追加
タグの追加
タグはなにも設定していない。
セキュリティグループの設定
セキュリティグループは事前に作成してあったものを利用した。
- 22番ポート: SSH接続
- 55555番ポート: WordPress接続
インスタンス作成の確認
内容に問題なければ「起動」。
キーペアの確認
事前に作ったあったキーペアを使った。
ec2でdockerとwordpressをインストール
sshでログイン
__| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-x-x-x-x ~]$yumをアップデート
[ec2-user@ip-x-x-x-x ~]$ sudo yum update -y Loaded plugins: extras_suggestions, langpacks, priorities, update-motd amzn2-core | 3.7 kB 00:00:00 No packages marked for updatedocker準備
dockerをインストール
[ec2-user@ip-x-x-x-x ~]$ sudo amazon-linux-extras install docker -y Installing docker Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Cleaning repos: amzn2-core amzn2extra-docker 10 metadata files removed 4 sqlite files removed 0 metadata files removed Loaded plugins: extras_suggestions, langpacks, priorities, update-motd amzn2-core | 3.7 kB 00:00:00 amzn2extra-docker | 3.0 kB 00:00:00 (1/5): amzn2-core/2/x86_64/group_gz | 2.5 kB 00:00:00 (2/5): amzn2extra-docker/2/x86_64/updateinfo | 76 B 00:00:00 (3/5): amzn2extra-docker/2/x86_64/primary_db | 75 kB 00:00:00 (4/5): amzn2-core/2/x86_64/updateinfo | 350 kB 00:00:00 (5/5): amzn2-core/2/x86_64/primary_db | 50 MB 00:00:00 Resolving Dependencies --> Running transaction check ---> Package docker.x86_64 0:19.03.13ce-1.amzn2 will be installed --> Processing Dependency: runc >= 1.0.0 for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: containerd >= 1.3.2 for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: pigz for package: docker-19.03.13ce-1.amzn2.x86_64 --> Processing Dependency: libcgroup for package: docker-19.03.13ce-1.amzn2.x86_64 --> Running transaction check ---> Package containerd.x86_64 0:1.4.1-2.amzn2 will be installed ---> Package libcgroup.x86_64 0:0.41-21.amzn2 will be installed ---> Package pigz.x86_64 0:2.3.4-1.amzn2.0.1 will be installed ---> Package runc.x86_64 0:1.0.0-0.1.20200826.gitff819c7.amzn2 will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================================================================================================================ Package Arch Version Repository Size ============================================================================================================================================================================ Installing: docker x86_64 19.03.13ce-1.amzn2 amzn2extra-docker 37 M Installing for dependencies: containerd x86_64 1.4.1-2.amzn2 amzn2extra-docker 24 M libcgroup x86_64 0.41-21.amzn2 amzn2-core 66 k pigz x86_64 2.3.4-1.amzn2.0.1 amzn2-core 81 k runc x86_64 1.0.0-0.1.20200826.gitff819c7.amzn2 amzn2extra-docker 3.7 M Transaction Summary ============================================================================================================================================================================ Install 1 Package (+4 Dependent packages) Total download size: 65 M Installed size: 270 M Downloading packages: (1/5): libcgroup-0.41-21.amzn2.x86_64.rpm | 66 kB 00:00:00 (2/5): pigz-2.3.4-1.amzn2.0.1.x86_64.rpm | 81 kB 00:00:00 (省略)dockerサービス起動
[ec2-user@ip-x-x-x-x ~]$ sudo systemctl start dockerdockerサービス状態確認
[ec2-user@ip-x-x-x-x ~]$ sudo systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) Active: active (running) since Sun 2021-03-14 05:59:36 UTC; 25s ago Docs: https://docs.docker.com Process: 3722 ExecStartPre=/usr/libexec/docker/docker-setup-runtimes.sh (code=exited, status=0/SUCCESS) Process: 3709 ExecStartPre=/bin/mkdir -p /run/docker (code=exited, status=0/SUCCESS) Main PID: 3731 (dockerd) Tasks: 8 Memory: 36.6M CGroup: /system.slice/docker.service mq3731 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit nofile=1024:4096 Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354394783Z" level=info msg="scheme \"unix\" not registered, f...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354629298Z" level=info msg="ccResolverWrapper: sending update...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.354858217Z" level=info msg="ClientConn switching balancer to ...le=grpc Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.394039324Z" level=info msg="Loading containers: start." Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.858998545Z" level=info msg="Default bridge (docker0) is assig...ddress" Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.915341056Z" level=info msg="Loading containers: done." Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.942822332Z" level=info msg="Docker daemon" commit=4484c46 gra...3.13-ce Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.943274164Z" level=info msg="Daemon has completed initialization" Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal systemd[1]: Started Docker Application Container Engine. Mar 14 05:59:36 ip-172-31-20-108.us-east-2.compute.internal dockerd[3731]: time="2021-03-14T05:59:36.967245548Z" level=info msg="API listen on /var/run/docker.sock" Hint: Some lines were ellipsized, use -l to show in full.dockerをec2-userで実行可能にする
[ec2-user@ip-x-x-x-x ~]$ sudo usermod -a -G docker ec2-user [ec2-user@ip-x-x-x-x ~]$ exit※ここで一度ログアウトして再度ログインすることで権限が反映される
docker-compose
docker-composeインストール
[ec2-user@ip-x-x-x-x ~]$ sudo curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 633 100 633 0 0 9447 0 --:--:-- --:--:-- --:--:-- 9447 100 11.6M 100 11.6M 0 0 22.2M 0 --:--:-- --:--:-- --:--:-- 44.5McurlのURLは↓ここでdocker-composeのバージョンを確認して適宜書き換える。(2021/03/14時点は1.28.5)
https://docs.docker.com/compose/install/#install-compose-on-linux-systemsdocker-compose実行権限設定
[ec2-user@ip-x-x-x-x ~]$ sudo chmod +x /usr/local/bin/docker-composeバージョン確認
[ec2-user@ip-x-x-x-x ~]$ docker-compose --version docker-compose version 1.28.5, build c4eb3a1fwordpress
docker-compose.ymlファイルを用意
[ec2-user@ip-x-x-x-x ~]$ pwd /home/ec2-user [ec2-user@ip-x-x-x-x ~]$ mkdir wordpress [ec2-user@ip-x-x-x-x ~]$ vi ~/wordpress/docker-compose.ymldocker-compose.ymlversion: '3.1' services: wordpress: container_name: wp-trial image: wordpress restart: always ports: - 55555:80 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: exampleuser WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_NAME: exampledb volumes: - wordpress:/var/www/html db: container_name: wp-db image: mysql:5.7 restart: always environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - db:/var/lib/mysql volumes: wordpress: db:wordpress用のdocker-compose.ymlファイルは↓を参考に作成。
https://hub.docker.com/_/wordpresswordpressをビルドして起動
docker-compose.ymlが入っているディレクトリに移動して
docker-compose up
する。[ec2-user@ip-x-x-x-x ~]$ cd ~/wordpress/ [ec2-user@ip-x-x-x-x wordpress]$ pwd /home/ec2-user/wordpress [ec2-user@ip-x-x-x-x wordpress]$ ls -la total 4 drwxrwxr-x 2 ec2-user ec2-user 32 Mar 14 06:12 . drwx------ 5 ec2-user ec2-user 142 Mar 14 06:12 .. -rw-rw-r-- 1 ec2-user ec2-user 638 Mar 14 06:12 docker-compose.yml[ec2-user@ip-x-x-x-x wordpress]$ docker-compose up --build -d Creating network "wordpress_default" with the default driver Creating volume "wordpress_wordpress" with default driver Creating volume "wordpress_db" with default driver Pulling wordpress (wordpress:)... latest: Pulling from library/wordpress 6f28985ad184: Pull complete db883aae18bc: Pull complete ffae70ea03a9: Pull complete 1e8027612378: Pull complete 3ec32e53dce5: Pull complete 3bb74037bf77: Pull complete feda0fbd85b1: Pull complete b2244185b327: Pull complete 8852ae668073: Pull complete 985e21deb66e: Pull complete f262da4e7afa: Pull complete 157f3d683e13: Pull complete 990684a56233: Pull complete c80999e49328: Pull complete 02585da80b89: Pull complete d68ab7635a0a: Pull complete 5a577fb48682: Pull complete d27e8a2c96b8: Pull complete f94fa08d2764: Pull complete 6db2ebd4cef9: Pull complete 9c4c1399bbb1: Pull complete Digest: sha256:92fb18e472ce46f289b475457289075c20387374d79bc41724689aa88112eab1 Status: Downloaded newer image for wordpress:latest Pulling db (mysql:5.7)... 5.7: Pulling from library/mysql 6f28985ad184: Already exists e7cd18945cf6: Pull complete ee91068b9313: Pull complete b4efa1a4f93b: Pull complete f220edfa5893: Pull complete 74a27d3460f8: Pull complete 2e11e23b7542: Pull complete 39ac93d44c47: Pull complete dfd9db50d4ea: Pull complete 4e97f54f11a3: Pull complete ebfb95795c5f: Pull complete Digest: sha256:5f649e87093a5b6b863f5c5277b2d2aa797b04d68657494e0f28ffabfa25e781 Status: Downloaded newer image for mysql:5.7 Creating wp-trial ... done Creating wp-db ... done[ec2-user@ip-172-31-20-108 wordpress]$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d0296aeb5318 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp, 33060/tcp wp-db c01446d87997 wordpress "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:55555->80/tcp wp-trialWordpressにアクセスしてみる
参考
AWS公式 Dockerインストール手順
AWS EC2インスタンスにdockerとdocker-composeをインストールして簡単なWEBサービスを立ち上げる方法
- 投稿日:2021-03-14T15:13:34+09:00
【学習メモ】AWS SQS Loose Coupling
Loose Coupling
疎結合の意味。密結合の反対。
システム上で、各要素が独立し、互いの関連性が弱い。
疎結合の設計によって、一部のシステム要素は故障が起きても、影響が他の要素に及びにくいというメリットがある。また、一つの要素を修正しても、他の要素への影響を考えなくても良いメリットもある。SQSとは
SQS(Simple Queue Service)
二つのプログラムが通信する際にポーリング処理を実施するサービス。本来ならば、直接通信だと、受信側の処理がいっぱい溜まってて、送信側のキューがうまく届かないかもしれない。
SQSは中継所みたいな役割を果たして、送信側が送ってきたキューを溜め込んで、受信側が通信内容を問合せして、SQSの中にキューがあれば送信。・SQSの中身は Request QueueとResponse Queueがある。
特徴
・フルマネージド型
・高可用性:複数のサーバー/データセンターにメッセージを保持する。
・高スケーラビリティ:多数の送信者と受信者に対応可能。
・高スループット:メッセージが増加しても高スループットを維持できる。
・低コスト:無料枠あり、従量課金。◯メッセージサイズ:最大256KB
※Extended Client Libraryを利用すると、2GBまでのメッセージの送受信が可能。◯保持期限:
デフォルト:4日間保持
※60秒から14日の間で変更可能。※30日以上、キューに以下のリクエストがない場合、SQSはそのキューを削除する可能性がある。
SendMessage、ReceiveMessage、DeleteMessage、GetQueueAttributes、SetQueueAttributes。処理形式
二つの処理形式がある。
◯標準キュー
◯FIFO(First in First out)標準キュー
なるべく順番通りに処理するが、順番が前後する場合もある。
少なくとも 1 回のメッセージ配信をサポートする。FIFO
順番通りに処理。最初に入ったキューを優先的に処理。
SQSの追加機能
Short Poling
キューが空の場合でも即時にリターンする。
Long Poling
キューが空の場合はタイムアウトまで待つ。
※Long polingとShort PolingはReceive Message Wait Timeで設定する。
0=Short Poling。最大は20まで。Visibility Timeout
コンシューマーがキューからメッセージを受信して処理しても、そのメッセージはキューに残ったままです。 Amazon SQS では、メッセージが自動的に削除されません。 Amazon SQS は分散システムであり、接続の問題やコンシューマーアプリケーションの問題などが原因で、 コンシューマーが実際にメッセージを受信するという保証がないためです。 そのため、コンシューマーはメッセージを受信して処理した後、キューからメッセージを削除する必要があります。 メッセージが受信された直後は、メッセージはキューに残ったままです。 他のコンシューマーが同じメッセージを再処理しないように、Amazon SQS は可視性タイムアウトを設定しています。 Amazon SQS では、この時間内に他のコンシューマーが同じメッセージを受信したり処理したりすることはできません。 メッセージのデフォルトの可視性タイムアウトは 30 秒です。 最小値は 0 秒、最大スケールは 12 時間です。
- 投稿日:2021-03-14T13:17:43+09:00
AWS認定ソリューションアーキテクトアソシエイト 合格体験記
【AWS認定ソリューションアーキテクトアソシエイト 合格体験記】
3/13に合格しました。700点台でした。800点に乗せたかった。
(2/26に1度目の受験をしましたが不合格でした。。)1度落ちてしまった反省も踏まえて、簡単にまとめてみました。
自分の備忘録のような記事になってしまっているかもしれないです。はじめに
クラウドプラクティショナーとはレベルが違いました。
私は今回のSAAも同じような感覚で受験したため1度不合格になってしまいました。
通勤電車内でのUdemyの模擬問題のみで受験しました。ITパスポートと同じような難易度と書かれているサイトなどがありますが、ITパスポートよりも確実に難しいです。
AWSの一つ一つの用語をきっちり理解する必要があります。不合格後にUdemyの短期突破講座を利用して、効率的に学び直しました。
AWS認定ソリューションアーキテクトアソシエイトの概要
720/1000 点 なので、7.2割解けたら合格です。65問です。
分野 1: レジリエントアーキテクチャの設計 (試験出題比率:30%)
1.1 多層アーキテクチャソリューションの設計
1.2 可用性の高いアーキテクチャやフォールトトレラントなアーキテクチャの設計
1.3 AWS のサービスを使用したデカップリングメカニズムの設計
1.4 適切な回復力のあるストレージの選択分野 2: 高パフォーマンスアーキテクチャの設計 (試験出題比率:28%)
2.1 ワークロードに対する伸縮自在でスケーラブルなコンピューティングソリューションの識別
2.2 ワークロードに対するパフォーマンスとスケーラブルなストレージソリューションの選択
2.3 ワークロードに対するパフォーマンスが高いネットワーキングソリューションの選択
2.4 ワークロードに対するパフォーマンスの高いデータベース ソリューションの選択分野 3: セキュアなアプリケーションとアーキテクチャの設計 (試験出題比率:24%)
3.1 AWS リソースへのセキュアなアクセスの設計
3.2 セキュアなアプリケーション階層の設計
3.3 適切なデータセキュリティオプションの選択分野 4: コスト最適化アーキテクチャの設計 (試験出題比率:18%)
4.1 コスト効率が高いストレージソリューションの識別
4.2 コスト効率が高いコンピューティングおよびデータベース サービスの識別
4.3 コスト最適化ネットワークアーキテクチャの設計(AWS認定公式サイトから引用)
詳しい内容は、こちらからご確認頂くと良いと思います。
→AWS認定 ソリューションアーキテクトアソシエイト学習教材
使用した学習教材は3つです。
・一夜漬け AWS認定ソリューションアーキテクト アソシエイト[C02対応]直前対策テキスト
・AWS認定ソリューションアーキテクト アソシエイト試験:短期突破講座(300問の演習問題)
・【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問)
私が不合格から反省して実践した学習手順
1、テキストを1周を読む。わかりやすく説明されています。
2、テキストに確認問題があるのでそちらも解いてみる。
(実際の試験にも似たような問題が出ました。)3、Udemy ハンズオンなしの短期突破講座を使う。
(12時間のオンデマンドビデオですが、空き時間に2倍速で聞けばすぐです。)4、Udemy ハンズオンなしの短期突破講座の総復習問題①を解く。
(出題の可能性の高い問題が厳選されています。)5、Udemy ハンズオンなしの短期突破講座の総復習問題①の不正解問題の復習
6、Udemy 模擬試験を解く。
(全6つありますが、番号が若い順に優先的に勉強するといいと思います。)7、Udemy 模擬試験の不正解問題の復習
8、試験の直前に、テキストを利用して最終仕上げ。
※Udemyの講座はセール時に購入すると出費を抑えられます。
模擬問題の正解、不正解などと絞り込みが出来るので活用するといいと思います。今後の反省
ここまで読んでいただきまして、ありがとうございます。
私の学習手順が参考になれば幸いですが、ここは非効率ではないか。など
反面教師にでもなることができたら記事を書いて良かったと思えます。もし良い学習方法などありました、コメントいただけますととても嬉しいです。
今回は正直なところ運が良かったから合格しただけかもしれません。
力不足であることを真摯に受け止めて、これからもAWSに触れていって、
ポートフォリオにも組み込んで、より実践的な知識を身につけていこうと思います。通勤電車や業務の休憩時間の空き時間が長くてもったいないので、
これまでと同様にUdemyの模擬試験を解いて、AWS DVA,SOAの取得を目指します。・おわりに Udemyの模擬試験の点数推移を参考に。
このような感じでした。
1度目は、全問回答しないで問題文と解答を照らし合わせました。短期突破講座
総復習問題① 0%正解→32%正解→53%正解
【SAA-C02版】
基本① 0%正解→53%正解→52%正解→66%正解→83%正解→91%正解
高難易度② 0%正解→24%正解→41%正解→60%正解→72%正解→85%正解
高難易度③ 0%正解→35%正解→46%正解→50%正解→61%正解→76%正解
高難易度④ 0%正解→35%正解→40%正解→61%正解→70%正解→79%正解
高難易度⑤ 0%正解→35%正解→63%正解→76%正解→85%正解
高難易度⑤ 0%正解→43%正解→50%正解→56%正解→76%正解※締め切りを設定していたので上記のような点数でも受験しました。
時間に余裕のある方は、これ以上を目指すと合格に近づくと思われます。
- 投稿日:2021-03-14T12:54:19+09:00
ポートフォリオのAWSネットワーク構成を整理した【Rails + Nginx + Unicorn + MySQL】
Railsアプリポートフォリオのネットワーク構成を頭の整理と備忘を兼ねて整理してみました。
俯瞰的に整理するものなので各リソースやネットワークの細かい設定等には触れません。
初学者なりに自分の言葉で整理したものになっていますので、おかいし点などありましたらご指摘いただけると幸いです。はじめに:参考書籍
AWSのネットワーク構築において以下の本を参考にさせていただきました。
初学者でも大変分かりやすく、かつ内容に従って操作することで本格的でセキュアなネットワークを構築できるハンズオン形式にもなっており、これ無くしてこのネットワーク環境は作れなかったと思います。
まだ発刊されて日も浅い(2021年3月時点)ため、ネット上の記事や古い書籍でありがちな、解説のUIと現在のUIが違って迷う、ということもほぼ無かったのも良かったです。おすすめです!
ネットワーク構成図
開発環境・デプロイ
開発・テストはDockerリモートコンテナ上で実施
ソースコードはGitHubで管理、デプロイはCapistranoで行うIAM
IAM(Identity and Access Management)はAWSへのアクセスを安全に管理するための仕組み
AWSアカウントのデフォルトユーザであるルートユーザは権限が強く、通常の開発等で使うにはリスクが大きい
そのため別途権限を抑えたユーザを作成し、こちらでネットワークの構築を行う
また仮想デバイスを用いたMFA(多要素認証)を導入し、更にセキュアな接続を実現するVPC
ここは私の領域ですよ、と宣言する領域。Virtual Private Cloud
この中にAWSのネットワークを構築していくアベイラビリティゾーン
耐障害性を上げるために、同じ東京リージョンの中でも異なるアベイラビリティゾーンにそれぞれサブネットを構成する
サブネット
VPCのIPアドレスの範囲を分割する範囲。分割する理由は主に以下2点
- 役割の分離:外部に公開するリソースかどうかを区別するため
- 機器の分離:AWS内での物理的な冗長化を行うため
今回は、2つのアベイラビリティゾーンにそれぞれパブリック・プライベートサブネットを用意する
インターネットゲートウェイ
VPCで作成したネットワークとインターネット間の通信を可能にするためのもの
NATゲートウェイ
インターネットゲートウェイを使った通信ではVPCのリソースは外部のネットワークと直接通信を行うため、VPCリソースはパブリックIPを持っている必要がある
しかしパブリックIPを持つ=インターネットに直接公開されている状態になり、サブネットをパブリックとプライベートに分けた意味が無くなる
プライベートサブネットのリソースは、インターネットに出ていく必要はあってもインターネットから直接アクセスはされたくない
→このような要求を実現するための仕組みがNAT(ネットワークアドレス変換)AWSではこの役割を果たすのがNATゲートウェイになる
ルートテーブル
サブネット同士、あるいはサブネットと各ゲートとの間には、通信をするための経路がまだ無い
そのため、サブネットが別のサブネット内のリソースを見たり、サブネット外のリソースにアクセスができない
サブネット間の通信経路を設定するために、AWSにはルートテーブルという機能がある
今回はサブネットが4つある すべてのサブネットにルートテーブルを作成する必要がある(ただし複数のサブネットで同じルートテーブルを共有することは可能これを踏まえ今回作成するのは以下3つ
- パブリックルートテーブル:パブリックサブネット1,2共有
- 外部とはIGW経由、プライベートサブネットとはLocalターゲットとしてアクセス
- プライベートルートテーブル1:プライベートサブネット1用
- プライベートルートテーブル2:プライベートサブネット2用
- 外部とはNATGW経由、パブリックサブネットとはLocalターゲットとしてアクセス
セキュリティグループ
今のままだとインターネットを通じてどんなアクセスもできてしまう
VPC内のリソースを守るため、外部からのアクセス制限をつける必要がある
→セキュリティグループという機能を用いて実現するセキュリティグループでは、外部からのアクセスを次の2つの概念で制御できる
- ポート番号
- サービスのアクセスで使われる80番(HTTP)、443番(HTTPS)、
- 管理者としてサーバ接続時に使われる22番(SSHなど)
- IPアドレス
今回は以下2つのセキュリティグループが必要
- 全てのリソースに接続するための入り口となる「踏み台サーバ」
- インバウンドルール:SSH接続(22番)のみ
- リクエストや処理を分散する「ロードバランサー」
- インバウンドルール:HTTP(80番)とHTTPS(443番)接続のみ
EC2(踏み台サーバ)
今回は機器の冗長化、負荷分散のために2つのアベイラビリティゾーンにサブネットを構築した
しかしリソースを増やすということはそれだけ侵入の経路が増えセキュリティ上のリスクが高まることになる
そこで全てのリソースに接続するための入り口となる踏み台(bastion)サーバを用意し、
このサーバ経由でないと各リソースに接続できないようにする踏み台サーバは目的のリソースへの通り道となる以外の用途がないため、低スペックでもOK
EC2インスタンス上に構築する
踏み台サーバはパブリックサブネット1に設置し、先程作成した踏み台サーバ用のセキュリティグループを適用する(=SSH接続のみ許可する。秘密鍵はローカルマシンで保持)EC2(Webサーバ・アプリケーションサーバ)
実際のアプリケーションを稼働させるEC2インスタンス
この中にWebサーバとしての役割を果たすNginx、Rackアプリケーション用サーバとしての役割を果たすUnicorn、アプリ本体であるRailsをインストールする
プライベートサブネット1,2にそれぞれ設置こちらもssh認証の秘密鍵はローカルで持ち、ssh-agentを利用してセキュアに多段接続する(踏み台サーバには秘密鍵をアップしない)
ここで踏み台サーバとWebサーバの違いを整理する
項目 踏み台 Webサーバ 設置サブネット パブリック プライベート パブリックIP 必要 不要 セキュリティグループ デフォルト+SSH接続 デフォルト+HTTP, HTTPS接続 誰がいつ接続する? 管理者が必要に応じて Webサービスのユーザが常時 接続形態 直接接続 間接接続(ロードバランサ経由) ロードバランサー
ユーザが増えてくると1台のWebサーバではリクエストを捌き切れなくなる可能性がある
スケールアウトの方法として用いられるのがロードバランサーで、リクエストの分散を実現できる設定項目は以下
- アベイラビリティゾーン:インターネットゲートウェイへの経路があるサブネット(今回はパブリックサブネット1,2)があるゾーンを指定する必要がある
- セキュリティグループ:デフォルト+HTTP, HTTPS接続(内部向けと外部向け)
- ターゲットグループ:Webサーバ1, 2、プロトコルはHTTP
データベース
AWSのサービスの一つであるRDSを用いて実現
RDSは以下の4点で構成される
データベースエンジン
→ 今回はMySQLを使用)パラメータグループ
→ 主にデータベースエンジン固有の設定を行うためのものオプショングループ
→ 主にRDS固有の設定を行うためのものサブネットグループ
→ データベースサーバーを複数のアベイラビリティーゾーンに分散させて配置させる時に使われる設定
RDSはサブネットグループを指定することで自動的に複数のアベイラビリティーゾーンにデータベースを作成し、
耐障害性を上げてくれる(マルチAZ)S3
今回のアプリではユーザのアイコンや投稿機能で画像をアップロードすることが可能
その画像を保管する場所として、AWSのストレージサービスであるS3を利用する
S3はVPCの外に配置するものである
そのためIAMでS3にアクセスするためのロールを作成し、EC2に適用することでアプリからS3へのアクセスを実現するAmazon Route 53
Webアプリを公開するためには分かりやすくて覚えやすいドメインが必要
AWSではドメインを取得することができるRoute 53というサービスがある
こちらで希望のドメインを取得することで公開用のURLを発行することができる
(費用は$10~15/年 前後)また、Route 53では他に以下の設定を行う
SSLサーバー証明書の発行(Certificate Manager)
→ ドメインの正しさを保証する証明書の発行を行う。
今回はドメイン検証済み(DV)証明書を使う
発行した証明書を使い、HTTPSのリスナーをロードバランサーに追加するパブリックDNSの設定
→ 踏み台サーバとロードバランサーに対し設定するプライベートDNSの設定
→ 踏み台サーバ、Webサーバ1,2、DBサーバに対し設定するAmazon SES
SES(Simple Email Service)はメールの送受信行う機能を提供するAWSのサービス
今回のアプリではパスワードを忘れた際に再発行するためにメールの送信を行うため用意する
受信に関する設定は不要のため行わない通常のメール送受信においては、以下プロトコルが利用される
SMTP(Simple Mail Transfer Protocol)
→ 送信用のプロトコルPOP3(Post Office Protocol Version 3)
→ 受信用のプロトコル。メールは受信者のローカルに取り込まれるIMAP4(Internet Message Access Protocol Version 4)
→ 受信用のプロトコル。メールはサーバ上に保管されるためインターネットアクセスが必要アプリからメールを送るには、メール送信用のIAMユーザを作成し、Amazon SES API または Amazon SES SMTPインターフェイスで認証する必要がある
今回は通常のメールサーバと同じ方法で実装ができるAmazon SES SMTPインターフェイスを利用しているCloudWatch
AWSで提供されている、各種サーバ等の運用状況を監視するツール
今回はWebサーバ・アプリサーバを包含するEC2インスタンスの死活監視、CPU使用率監視を行っているおわりに
CircleCI/CDを使った自動テスト・自動デプロイも導入したいと考えています。
導入できたらこちらも更新しようと思います。
- 投稿日:2021-03-14T12:07:47+09:00
AWS SDK for Javaで "JAXB is unavailable" と言われたら
環境
- AWS SDK for Java S3 1.11.327
- Zulu 11.0.9.1
- M1版 macOS Big Sur 11.2.3
現象
AmazonS3#putObject()
でS3にファイルをアップロードすると、JAXB is unavailable. Will fallback to SDK implementation which may be less performant
という警告ログが出ます。原因
JDK 11にはJAXB実装が含まれないからです。JDK 8とかだと、この現象は起こらないはずです。
解決方法
JAXBを明示的に追加すればOKです。
pom.xml<dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <version>1.11.327</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-s3</artifactId> </dependency> <!-- この2つ! --> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.3</version> <scope>runtime</scope> </dependency> </dependencies>注意点
jakarta.xml.bind-apiやjaxb-implのバージョンは必ず
2.3.3
にしてください。最新の3.0.0
だと問題は解決しません。おそらくAWS SDK側が
jakarta.*
ネームスペースに対応していないからだと思われます。参考URL
Issue立てました
「いいね」などよろしくお願いします。
- 投稿日:2021-03-14T10:53:41+09:00
Cronが動かないとは何ごとぞ!
背景
先日、Amazon EC2 (Amazon Linux 2) インスタンス(※1)起動時に自動でスクリプトを実行したく、cron を設定していたのですが、スクリプトが実行されない現象にぶつかりました。その際の対処をここにメモとして残しておきます。
(※1)インスタンスタイプ:g4dn.xlarge ...機械学習などに用いるGPUを利用できるインスタンスタイプです
先人たちの知恵をお借りするなどして解決できたことを、この場をお借りして感謝するとともに、大変恐縮ですが自分のメモとして、こちらへまとめておきます。
環境
(本番)
- AWS EC2 (Amazon Linux 2)
- Python 3.7.9 ※2021/02/21時点のAmazon Linux2でのデフォルト
- Putty 0.74- AWS EC2 (Amazon Linux 2)0. Cron とは
IT用語辞典 e-Words ―cronの項目 より引用:
cronとは、多くのUNIX系OSで標準的に利用される常駐プログラム(デーモン)の一種で、利用者の設定したスケジュールに従って指定されたプログラムを定期的に起動してくれるもの。
利用者はcrontab(“cron table”の略)コマンドで実行したいプログラムやコマンド、シェルスクリプトなどと実行日時を指定すると、同名のテキストファイル(crontabファイル)に設定が保存される。システムに常駐するデーモンの一つであるcrond(“cron daemon”の略)がcrontabファイルに書かれたスケジュールに従って、決まった日時に指定されたプログラムを実行する。1. 現象
cron で設定したスクリプトが、EC2 インスタンス起動時に起動しない。
2. 原因
まず考えられたのは、cron コマンドの設定ミス。
コマンドは、単純にリブート時にとあるスクリプトを実行するというもの。
しかしながら、何度見直してもコマンドの記述に間違いは見当たりません。crontab@reboot /home/(username)/app/on_start.sh
実行されるスクリプトの内容も、1つのpythonファイルを実行するだけの簡単なものです。
こちらもディレクトリの設定や処理内容に間違いはありませんでした。on_start.sh#!/bin/bash cd `dirname $0` SHELL=/bin/bash # パスを通す source /home/(username)/.bashrc # 好きなPython環境を設定 source activate tensorflow2_latest_serving # 起動から45分後にインスタンスを停止する sudo shutdown +45 cd /home/(username)/app python3 app.py3. 対処
いろいろと調べていた中で末尾に記載した参考記事(特に @nagimaruxxx 様の記事)を見付け、それに沿って以下を実行しました。
a) crond ステータス確認
service crond status # ステータス確認 service crond start # 起動⇒ crond は稼働していました。
※以降 b)~d) はルート権限で実行が必要。「sudo su -」コマンドでルート権限に移行する。
ユーザー権限に戻る際は、「exit」を入力して[enter]キー押下。b) run level 確認
chkconfig --list crond crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off
⇒ 私の環境では、何故か上記コマンドを受け付けずに確認ができなかったため、確認なしで、直接に下記コマンドを実行しました。chkconfig --level 2345 crond on # run level 2,3,4,5 を on とするc) ファイルの実行権限
ls -l on_start.sh -rw-r--r-- 1 dev dev 1 2月 25 10:51 2021 on_start.sh chmod +x on_start.sh # 権限を付与 ls -l on_start.sh -rwxr-xr-x 1 dev dev 1 2月 25 10:52 2021 on_start.sh⇒ 変更前は「644」でしたが、これに
+x
して「755」へ。
一番の原因は、この実行権限だった模様。d) noanacron の導入
デフォルトで anacron という cron がインストールされていましたが、使いづらい点があり、私も @nagimaruxxx 様の記事を参考に noanacron をインストールしました。
yum -y install cronie-noanacron yum remove cronie-anacron
4. 結果
cronにより、EC2 インスタンス起動時(再起動時)に指定したスクリプト(上述の on_start.sh)が起動されるようになりました!
また、インスタンス起動から指定通り45分後にインスタンスが停止されることも確認できました。めでたしめでたし。
参考
(編集後記)
まさか cron が動かないとは思わず(まさしくタイトル通り「Cronが動かないとは何ごとぞ!」と思っていたため)、参考記事に辿り着くまで、さらには、ファイルの実行権限が原因であることを突き止めるまでに、多くの時間を費やしてしまいました。
私自身は通常、スクリプトファイルやPythonファイルを、Puttyからのコマンドや、WinSCPでローカルからEC2へコピーするなどしているのですが、その際に実行権限を確認することをあまり行なっておりませんでした。
今後は、追加・変更したファイルやディレクトリの実行権限を必ず確認するよう、手元のチェック項目へ追記しました。皆様はこれを反面教師として考えていただけたら幸いです。
最後までお付き合いいただきまして、ありがとうございました。
- 投稿日:2021-03-14T01:59:56+09:00
【AWS】Lambdaの初回起動を早くする方法
はじめに
個人請負でとあるサイトをサーバーレスで構築しています。
よくあるAmazon API Gatewayでリクエストを受けてAWS Lambdaで処理を行って結果を返却する簡単な構造なのですが・・・Lambdaからのリクエストが初回だけとにかく遅い!
原因は関数実行前の準備に時間がかかるからです。
Lambdaというサービスの内部では、初回実行時に実行する関数のパッケージのロードや展開、ランタイムの起動など色々な「実行前準備」をやってくれています。
しかし、一定時間関数が呼び出されないと「実行前準備」がアンロードされてしまうのです。そのため実行頻度の低いLambdaの場合は毎回遅い初回実行になってしまいます。今回は色々と試してみてなんとか解決した方法を載せておきます。
前提
この方法が有効なケースは以下の場合です。
- Lambdaの実行頻度が低い。※30分に1度程度しか実行されないなど
デプロイパッケージのサイズをランタイムに必要な最小限のサイズにしていることやJavaよりPythonを選択している等も速度に影響してきますが今回は実行頻度が低い場合のみを対象としています。
解決した方法
なんと「Lambdaを定期的に実行する」だけです。
邪道のような気もしますがこれが一番効果がありました。
一定時間関数が呼び出されないと「実行前準備」がアンロードされてしまうのでアンロードされる前に再度実行だけしておく。そりゃ効果ありますよね。今回は5分毎に実行するようにLambdaのトリガーを追加しました。
始めは1分毎で設定してみたのですが5分でも大丈夫そうなので5分毎に変更しています。
AWS Lambdaは関数に対するリクエストの数とコードの実行時間に基づいて課金されるので「コストあがっちゃうよ!」ってお考えの方もいらっしゃるかもしれませんが安心してください。1日288回プラスになるだけです。誤差です。では早速設定してみます。
トリガーの種類を選択できるので、「EventBridge(CloudWatch Events)」を選択します。
「新規ルールの作成」を選択し、ルール名を入力します。
今回は「scheduled-execution」としました。
次にルールタイプを選択します。「スケジュール式」を選択します。
スケジュール式に「rate(5 minutes)」と入力します。
※5分毎に実行しますよの設定です。
あとは追加ボタンを押下すれば完了です。
定期実行されてもエラーにならないよう関数側を必要に応じて修正してください。パラメータなしで実行されるのでそれを判定に使っても良いかと思います。これできっと何かが数秒早くなって世界のどこかで誰かが喜びます。
- 投稿日:2021-03-14T00:16:34+09:00
【学習メモ】AWS CloudFront
CloudFront:
AWSが提供するCDN(Content Delivery Network)サービスCDSとは
CDNはWEBコンテンツ配信処理を高速化するためのサービス。
スタバを例としてあげると、
例)A市にスタバのお店が設置されていない、A市市民がスタバコーヒーを飲みたい時、
スタバのあるB市に行かないと飲めない。B市への往復時間は3時間。
もしA市にスタバを設置したら、そのB市への往復時間を省ける。CDNの話に戻ると、CDNはbranch officeみたいな役割で、CDNがあれば、
ユーザーがウェブにアクセスする際に、距離が一番近いノードにアクセスして、そのアクセスの時間を短縮可能。CDSのメリット:
・異なる地域にアクセスする際、遅延時間が短くなる。
・requestはCDNノードで完了。オリジンサーバーの負荷軽減。CloudFront
大規模なアクセスも世界中にあるエッジのキャパシティを活用して効率的かつ高速にコンテツ配信が可能なサービス。
・210以上のエッジロケーションがあるため、多数のエッジサーバーが用意される。それによって、全世界に高性能、高いパフォーマンスで配信可能。
・AWSWAF/AWS Certificate Managerとの連携やDDoS対策によるセキュリティ機能。
・オリジンに対してHeader/Cookie/QueryStringsによるフォワード指定で、静的なページだけでなく、動的なページ配信が可能。現在のアーキテクチャはリージョナルエッジキャッシュが追加されより効率的な配信処理が可能になった。
Distribution設定
CloudFrontの設定において、まずはDistribution設定。
・各配信先となるドメインに割り当てるCloudFrontを設定する。
・WEB DistributionとRTMP Distribution、この二つの形式を選べる。
・使用量が最大40Gbps/10万RPS超は上限緩和申請を実施する。
・独自ドメインを指定可能。各種設定:
・コンテンツオリジン設定:CloudFrontの配信ファイルの取得先の設定
・アクセス設定:ファイルアクセスの許可設定
・セキュリティ設定:アクセスにHTTPSを利用するかどうかの設定
・Cookie またはクエリ文字列転送の設定:オリジンへのCookie/クエリ文字列転送の要否を設定
・地域制限:特定の国のユーザーからのアクセス拒否設定
・アクセスログ設定:アクセスログを作成するかどうかの設定※通常はWEBディストリビューションを利用するが、
Adobeメディアの場合:RTMPディストリビューションを利用する。セキュリティー機能
CloudFrontは様々なセキュリティー設定によって、セキュアなコンテンツ配信が可能になる。
・SSL証明書の設定:コンテンツ配信のHTTPSに対応してり、配信時の暗号化通信が可能。
・オリジンカスタムヘッダーによる通信制御。
(リクエストユーザーを識別可能。)・AWS WAFによるファイアーウォールと連携し、
ディストリビューションに対するウェブリクエストを許可、ブロックが可能。・AWS ShieldによるDDoS対応。
CLoudFrontを利用すると、DDoS対応のスタンダード版が自動で設定される。・署名付きURL/Cookieによる有効期間指定。
・GEOリストリクションによる地域情報でアクセス判定。
- 投稿日:2021-03-14T00:04:27+09:00
リザーブドインスタンスの種類について(スタンダード・コンバーティブル)
勉強前イメージ
リザーブドインスタンスはわかるけど、
種類があるのん・・?調査
まずリザーブドインスタンスとは?
リザーブドインスタンスとは
1年・3年単位で購入するインスタンスのことで、時間単価の割引が行われます。
ものによっては前払いが必要なこともあります。詳細は こちら をご確認ください。
種類について
種類がどこで見れるかというと、
リザーブドインスタンスの購入の画面で以下のようにどのようなインスタンスを購入するか選ぶ画面で確認することが出来ます。画像にある通り、種類には
スタンダード
とコンバーティブル
の2種類あります。種類を詳細に
スタンダード
- 平均割引率 : 1年(40%) 3年(60%)
- 交換 : 交換は出来ません
- マーケットプレイスでの販売・購入 : 販売・購入できます
コンバーティブル
- 平均割引率 : 1年(31%) 3年(54%)
- 交換 : 期間内であれば、インスタンスファミリー・インスタンスタイプ・プラットフォームなど違う属性の別のリザーブドインスタンスに交換することができます
- マーケットプレイスでの販売 : 販売・購入できません
まとめ
スタンダード
とコンバーティブル
の違いとしては、
- スタンダード : 割引率は高いが、インスタンスタイプなど違ったときに交換してもらえない。ただし、マーケットプレイスで販売・購入出来る
- コンバーティブル : 割引率は低いが、インスタンスタイプなど違ったときに交換してもらえる。
必ずこのインスタンスタイプ・インスタンスファミリー使うんだ!ってときはスタンダード使えばより安くなるが、
もしかしたら変更あり得るかも・・・ってときはコンバーティブルを使えば万が一のときは交換してもらえる。
スタンダードは、マーケットプレイスで販売・購入出来るらしいけど、めんどくさそうな気がする。勉強後イメージ
リザーブドインスタンスにもいろいろ種類があるのね・・・・
選択肢がどんどん広がって便利になる分、選ぶの大変そうだなぁ参考