- 投稿日:2019-10-09T22:38:25+09:00
開発環境から始めるdocker環境の浸透
dockerによるCIと、コンテナクラスタリング構築の記録を残していきます。
スマートフォンベースのECサイトのプロジェクトへ配属になりました。
プロジェクトはオーソドックスなLAMP構成+jQueryによるインタラクションが付与されたものですが、中〜大規模のPVを持っており、決済機能も存在する事から
品質管理やリリース手順などは整備されていました。ライフサイクルとしては成熟期を過ぎた印象があり、プロダクトとしては一定の完成度に達していたので
バックエンドより、ユーザが直接関わるUI部分の改修に比重が置かれ
インフラ部分については、現状動いているのだから、コストを掛けて改修するほど優先度は高くない、といった状況でした。そんな中で、合間を見てdocker環境を構築し、現場に浸透させて行った記録です。
docker環境の構築の助けになれば幸いです。
(記録になるので、ベストプラクティスから外れている部分も多いかと思いますが、ご容赦下さい)当時の開発環境
開発環境は、VirtualBox(Vagrant)でCentOSベースのイメージを一つ起動し
一つのOSの内に
・サービス内で展開している、三種類の2層webアプリケーション(VirtuaHostによる統合)
・上記3アプリケーションから参照するmysql
・DB負荷軽減の為のRedisサーバ
が同居しています。その他、CDNとしてAWS S3を採用している為、擬似S3となるminoサーバを
ホストマシン上で起動しています。
ホストマシン上のGitHubのリポジトリを、Vagrantのイメージにマウントし、エディタで開発を行なっていました。開発環境の問題点
前述の通りインフラ構築は逆風の雰囲気でしたが
開発チームからは、開発環境の問題の指摘が挙げられていました。1.Virtualboxの起動速度
Virtualboxは、仮想環境内でOSを起動する為起動にリソースを消費しますが
dockerはホストOSの機能を共有して、docker仮想環境内で
アプリケーションが格納されたコンテナを起動する為、
「OSを起動する」部分のオーバーヘッドが無く、起動が高速になります。
docker導入のメリットとして訴求しました。2.サービス環境と開発環境で、構成が異なり、健全ではない
■開発環境は、3つの2層webアプリケーションを1つのEC2インスタンスに集約していましたが
商用環境は、AWS EC2を3台に分け(別途、multi-AZも実施している)
それぞれのアプリケーションを分けて配置していました。
■開発環境はCentOS6(何故かOSのメッセージ全般がドイツ語)でしたが、
商用はAmazonLinuxでした。dockerでコンテナ毎にサーバを構築する事で、商用と同じ3サーバ構成にする事で、解決を試みました。
OS差分の問題は、AmazonLinuxのDockerイメージを使うことも考えましたが
開発陣からの、「商用と同じ環境」をより納得させる為に、
商用で稼働しているAmazonLinuxを、Dockerイメージとして使うことで、心理的安全性を担保する事にしました。将来的にAWS ECSによる、コンテナクラスタのデプロイを想定し
その際は、alpineで再構築する予定だったので、この対応は繋ぎという形でした。
(正直、そのままalpineで構築しておけばよかった)3.Githubリポジトリが2つ存在し、連携しにくい
配属以前は、SASS/JS/HTMLが別リポジトリで管理されていました。
フロントのリポジトリで、gulpを使用したhtml+SASS+JSのモックを作成し
バックエンドのリポジトリに(ZIPか何かで)移植、viewファイルへ反映を行なっていましたが
・2つのリポジトリとのバージョン整合が大変
・移植コストが大きい。大規模なフロントエンド開発がもう無さそう
という事を考慮し、リポジトリをバックエンドに統合する事にしました。
統合により
・バックエンドのJSやSASSの変更をgulpで検知しコンパイル、ブラウザに即時(又はリロード)で反映
・PHPソースとJS/CSSが正しくバージョン管理されているので、将来的には継続的デプロイとして、GitHubへのPUSH時、JS・SASSを自動でコンパイルし、dockerimageの自動デプロイと、JSやCSS,画像ファイルのS3への自動反映
(AWS codebuildを想定)
が可能だと見積りました。プロトタイプ作成
プロトタイプを見せる事が説得力に繋がると感じたので、業務の合間にdockerの構築を進めていくことになりました。
- 投稿日:2019-10-09T22:05:33+09:00
Amazon SES + mailx で「Error in certificate: Peer's certificate issuer is not recognized.」が出た時の対処法
1.前書き
Amazon SESとmailxでメール送信できる仕組みを作ったのですが、
メール送信のたびに「Error in certificate: Peer's certificate issuer is not recognized.」が出力していました。
メール送信自体は成功しているので問題は無いのかもしれませんが、エラーが出たままなのは精神衛生上よろしくないので、四苦八苦しながら対処しました。これは、その時の対処法を記載しています。
2.環境
- Centos7.6
- mailx-12.5-19
前提
- Amazon SES には送信元メールアドレス登録&承認済み
- mailx はインストール済み
- ~/.mailrc には以下のように設定
~/.mailrcset smtp-use-starttls set smtp=smtp://email-smtp.us-east-1.amazonaws.com:587 set smtp-auth=login set smtp-auth-user=<Access key ID> set smtp-auth-password=<Secret access key> set ssl-verify=ignore set nss-config-dir=/etc/pki/nssdb/ set from=<From Mail Address>3.調査
エラーが出るタイミング
mail -v
で確認したところ、Amazon SESのメールサーバへTLS通信を開始した際に出力されているようです。>>> STARTTLS 220 Ready to start TLS Error in certificate: Peer's certificate issuer is not recognized. --★ Comparing DNS name: "email-smtp.us-east-1.amazonaws.com" SSL parameters: cipher=AES-256-GCM, keysize=256, secretkeysize=256, issuer=CN=Amazon,OU=Server CA 1B,O=Amazon,C=US subject=CN=email-smtp.us-east-1.amazonaws.comGoogle翻訳にかけると、「Error in certificate: Peer's certificate issuer is not recognized.(証明書のエラー:ピアの証明書発行者が認識されません。)」って言っているので、怪しいのは証明書のよう。
~/.mailrc
でも指定した、証明書のデータベース/etc/pki/nssdb/
を確認してみます。$ sudo certutil -L -d /etc/pki/nssdb/ Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI何も入っていませんでした。
指定した証明書のデータベースに証明書が無いために起こったエラーだったことが判ります。4.対処
Amazonの証明書をインポートして対処します。
4-1 Firefox の証明書データベースを流用する場合
Firefoxから取得済みの証明書をインポートする方法が一番手軽だったので、その方法で対処していきます。
※別途Firefoxのインストールと、GUI環境が必要となります。1. Firefox の現在の証明書を確認
Firefox が所持している証明書を確認します。
$ certutil -L -d ~/.mozilla/firefox/<xxxxxxxx>.default/ Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI※Firefoxにも証明書が無い場合、一度FirefoxでAmazonのサイトを閲覧しましょう。
閲覧後に再度確認すると、「Amazon」の証明書が追加されるはずです。$ certutil -L -d ~/.mozilla/firefox/<xxxxxxxx>.default/ Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI Amazon ,,2. Firefox の証明書データベースを流用
新たに証明書データベース用のディレクトリを作成し、そこにFirefoxの証明書データベースをコピーします。
$ mkdir -m700 ~/.certs $ cp -p ~/.mozilla/firefox/<xxxxxxxx>.default/{cert8.db,key3.db,secmod.db} ~/.certs3. Amazonの証明書に信頼性を指定する
Firefoxから流用した証明書は信頼性が何も指定されていません。
そのため、証明書をエクスポート→インポートし、インポート時に信頼性の指定を行います。$ certutil -L -n 'Amazon' -d ~/.certs -a > amazon.cert.asc # 証明書エクスポート $ certutil -A -t "C,," -n 'Amazon' -d ~/.certs -i amazon.cert.asc # 信頼性を指定して証明書インポートこうすることで、「Trust Attributes」の項目が
C,,
1に変更されます。$ certutil -L -d ~/.certs/ Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI Amazon C,,4-2 直接ルート証明書をインポートする場合
えー、FirefoxもGUI環境も用意しなきゃならないの? という場合は、直接証明書をインポートする方法があります。
1. 新規の証明書データベース格納ディレクトリを作成する
$ mkdir -m700 ~/.certs $ certutil -N -d ~/.certs Enter a password which will be used to encrypt your keys. The password should be at least 8 characters long, and should contain at least one non-alphabetic character. Enter new password: <空エンター> Re-enter password: <空エンター>2. Amazonからルート証明書をダウンロードする
こちらからルート証明書を入手します。
$ wget https://www.amazontrust.com/repository/AmazonRootCA1.pem $ mv AmazonRootCA1.pem ~/.certs/3. 入手したルート証明書をインポートする
「Trust Attributes」の項目を
C,,
1の形でインポートします。$ certutil -A -n "Amazon" -t "C,," -d ~/.certs -i ~/.certs/AmazonRootCA1.pem -a $ certutil -L -d ~/.certs/ Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI Amazon C,,5.確認
上記の対処が完了したら
.mailrc
の設定を変更して、メールを送信してみましょう。~/.mailrcset nss-config-dir=/etc/pki/nssdb/ ↓ set nss-config-dir=~/.certs/$ echo -e "test mail" | mail -v -s "test mail title" -r "<From Mail Address>" "<To Mail Address>" ~~ >>> STARTTLS 220 Ready to start TLS Comparing DNS name: "email-smtp.us-east-1.amazonaws.com" SSL parameters: cipher=AES-256-GCM, keysize=256, secretkeysize=256, issuer=CN=Amazon,OU=Server CA 1B,O=Amazon,C=US subject=CN=email-smtp.us-east-1.amazonaws.com ~~「Error in certificate: Peer's certificate issuer is not recognized.」が出力されなければ対処完了です。
6.まとめ
以上、対処法でした。
TLS通信における証明書の役割など、まだぼんやりとしか理解してないので、今後の課題になりそうです。
ですが、エラーが解決できると気持ちいいですね。以下、参考にさせて頂いたサイト
Linuxからプロセスの動作状況をスマホに通知する
certutilによる証明書管理 [Fedora14]
C
は「サーバ証明書発行元として信頼しているCAの証明書」を示す。 ↩
- 投稿日:2019-10-09T22:01:54+09:00
LambdaでRedshiftのスナップショット取得&クラスター削除
やりたいこと
Redshiftのランニングコストをできるだけ抑えたい。
AWSのビッグデータ基盤であるRedshiftは、手軽に使えてしかも他のDWHサービスと比べて安価という非常に優良なサービスです。
とはいえ、一番小さいdc2.largeのインスタンスでも一時間あたり最低0.314$、一ヶ月ずっと起動しっぱなしの場合だとおよそ25000円程度なので、個人が学習目的で常用するには少し躊躇われるお値段。
少なくとも、使わない時間は停止しておきたいのですが、このRedshift、RDSとは違って停止という概念がありません。
インスタンスを削除して、必要なときにスナップショット(要するにバックアップですね)から復元するという手段を取るしかない。まぁこの作業もAWSのコンソール上から数クリックでできてしまうものなので、さほど手間というわけでもないんですが、削除し忘れてそこそこの金額を取られてしまうのもアレなので、できることならこのスナップショットの取得→削除の流れをLambdaで自動でやってしまいたいよね、というのが今回のお題です。
結論
というわけで今回も結論から。言語はPython3.7。
import boto3 import time from botocore.client import ClientError from datetime import datetime, timedelta, tzinfo redshift = boto3.client('redshift') snapshot_prefix = "testinstance" clusterid = "testinstance" generation = 2 def delete_snapshot(): # 手動スナップショットの情報を取得 snapshots = redshift.describe_cluster_snapshots( ClusterIdentifier=clusterid, SnapshotType='manual' ) # Snapshotが管理世代より少ない場合はスキップ if len(snapshots['Snapshots']) <= generation: return # SnapshotCreateTime の降順にソート snapshot_sorted = sorted(snapshots['Snapshots'], key=lambda x:x['SnapshotCreateTime'], reverse=True) # 管理世代(generation)以前のスナップショットを削除 for snapshot in snapshot_sorted[generation:]: try: response = redshift.delete_cluster_snapshot( SnapshotIdentifier=snapshot['SnapshotIdentifier'], SnapshotClusterIdentifier=clusterid ) return except ClientError as e: pass def delete_cluster(): snapshotid = "-".join([snapshot_prefix, datetime.now().strftime("%Y%m%d-%H%M%S")]) # スナップショットを取得してクラスターを for i in range(0, 5): try: response = redshift.delete_cluster( ClusterIdentifier=clusterid, SkipFinalClusterSnapshot=False, FinalClusterSnapshotIdentifier=snapshotid ) return True except ClientError as e: print(str(e)) time.sleep(1) def lambda_handler(event, context): try: # クラスターの存在確認 response = redshift.describe_clusters(ClusterIdentifier=clusterid) except ClientError as e: print(str(e)) else: # スナップショット削除 delete_snapshot() # クラスター削除 delete_cluster()詳細
やっていることは簡単で、
・特定のプレフィックスがついたスナップショットを、指定した世代数だけ残して削除
・指定したインスタンス名のRedshiftインスタンスを、スナップショットを取得してから削除
だけです。あとはLambdaのトリガーで、日次で起動してやれば良いだけ。
これで、うっかり削除し忘れても安心ですね!
- 投稿日:2019-10-09T19:00:46+09:00
RailsのmigrateをAWS Fargateに移行した時の話
前提
- ECSでRailsアプリが起動されていること
- migrateはfargateでやってなかった
- テスト環境でやること
作業内容
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/ecs_run_task_fargate.html
これ見ながら作業する。実際は、コマンドでやると何をしているのかよくわからないので、まずはGUIでやる。把握した後にコード化するというのが良い。そうすることで、全てのオプションやらパラメータの世界が見えてくる。念の為、新規DBを作成
t2.microなどで良い
何らかのエラーが出たときの切り分けにしたい。
インスタンスが作れたら、アプリケーションデプロイ用のタスクにDBの環境変数を設定する(System Managerが使えるなら ECS containerからvalueFrom
で呼び出せるのでjson自体をgit管理できる。AWSでマネージドされているのが良い)taskを定義する
実際は、コマンドなどを付与したりするのでENTRYPOINTで設定している。
これは、Initial,Migrate,Seedそれぞれリビジョンで分けるだけで良い。Initial,Seed,Migrateの順で作る。
※なお、実際の運用ではInitialやらSeedは使わない。これは、今回新規でRDSを立ち上げたので必要になっただけ。LATESTリビジョンだけがあれば良い。
key value ネットワークモード awsvpc 互換性が必要 FARGATE タスクメモリ(GB) 0.5GB タスクCPU(vCPU) 0.25 vCPU containerの環境設定(Initial)
key value エントリポイント bundle,exec,rails,db:create
作業ディレクトリ /app
(アプリがある場所)"containerDefinitions": [ { "entryPoint": [ "bundle", "exec", "rails", "db:create" ], "workingDirectory": "/app" } ]containerの環境設定(Migrate)
key value エントリポイント bundle,exec,rails,db:migrate
作業ディレクトリ /app
(アプリがある場所)"containerDefinitions": [ { "entryPoint": [ "bundle", "exec", "rails", "db:migrate" ], "workingDirectory": "/app" } ]containerの環境設定(Seed)
key value エントリポイント bundle,exec,rails,db:seed,a=b
作業ディレクトリ /app
(アプリがある場所)"containerDefinitions": [ { "entryPoint": [ "bundle", "exec", "rails", "db:seed", "a=b" ], "workingDirectory": "/app" } ]taskを実行する
- VPCを設定、subnetを設定
- ネットに繋がるものを設定しておく
2つエラーが発生した
- メモリ不足エラー → メトリクスをチェックして、スペックの問題ならスペックを上げる
- コンテナインスタンスのリソースから、メモリ使用量を見る
- ECRからイメージをpullしてこれず、エラー → インターネットにつながるネットワークを設定する
結果を見る
- PROVISIONING→PENDING→RUNNING→STOPのようなフローだったような気がする
- タスクのStoppedの中でログを確認する。
- Migrateタスクならば、以下のようなログが吐かれているだろう。
2019-10-09 18:16:45D, [2019-10-09T09:16:45.290941 #1] DEBUG -- : [1m[35m (572.8ms)[0m [1m[35mCREATE DATABASE "test_database" ENCODING = 'unicode'[0m 2019-10-09 18:16:45Created database 'test_database'
- 実際にアプリケーション側でも確認する。
- 問題がなければCodeDeployやCIなどで連携する。
- 投稿日:2019-10-09T17:19:32+09:00
CloudFormationでCodeBuildのBuildSpecのファイル名指定方法
はじめに
BuildSpecの初期値のファイル名「buildspec.yml」を変更する方法がわからず、サポートに問い合わせしたため備忘録として記録。
開発/本番環境でファイル名を変えたかった。方法
SourceプロパティのBuildSpecに指定する。
下記は「my-buildspec.yml」を指定した例Resources: MyProject: Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/standard:2.0-1.10.0 ImagePullCredentialsType: CODEBUILD Type: LINUX_CONTAINER ServiceRole: <サービスロールの ARN> Source: BuildSpec: my-buildspec.yml Type: CODEPIPELINE参考
ひとこと
ドキュメントを見て理解できずにサポートにお世話になってしまう。
- 投稿日:2019-10-09T15:53:14+09:00
【また】AWS認定プラクティショナー試験を受けた結果…不合格でした
こんにちは。
本日(2019/10/9)、またまたとある事情(業務命令)でAWS認定プラクティショナー試験を受けてきましたので、その感想をば書かせて頂ければと思います。前の記事
https://qiita.com/Watachan/items/d72a2d409c5c00db8603タイトル通り、試験結果はまたまた不合格でした。
この…バカがッ(自分が)!!前回の反省点
もちろん前の状態のまま受けるわけもなく、ちゃんと反省点を考えてみました。
・業務で使った知識を過信
・ホワイトペーパーの流し読み
・模擬試験の結果が良かったので、あまり問題を追求していなかった
・完全に舐めていた対策
ということで、今回は「AWS認定資格試験テキスト AWS認定 クラウドプラクティショナー」という本を(会社の経費で)買い、徹底的に読んで挑みました。
模擬試験…は前回の結果があるからもう信用しないことにしました。出題された問題について
覚えている限り書きます。
・AWSの利点
・AWSの請け負う責任はどんなものがあるか
・DDoS攻撃を防ぐ時はどうするか
・AWS SnowballとAWS Snowmobileの違いと内容
・コンピューティングリソースにはどんなものがあるか
・AWS内の通信サービスはどんなものがあるか
・ハイブリッド構成の概要と利点
・ダイレクトコネクトの説明
・サードパーティシステムの利点(なぜAWSマーケットプレイスで選んだほうが良いのか?)
・AWS X-Rayの説明をせよ
・AWS Rekognitionの説明をせよ…おい待て!何だX-RayとかRekognitionって…知らんぞ!そんなサービスは!!
結果
よし終わった…と思って終了をクリックすると「不合格」の文字が…
最初はちょっと信じられなくて固まっていましたが、ため息とともに試験会場を後にしました。まとめ
・参考書は流し読みしないほうが良い
・似通ったサービス名を同時に出されて「どっちが正しいか」と聞いてくる印象が強かったので、サービス概要は性格に覚えるべきかもしれない…例えば、AWS SnowballとAWS Snowmobileはどちらもデータ転送を行うサービスだけれど、違いはペタバイト単位かテラバイト単位で送る…など
・出題範囲外の問題も結構出ていた印象…問題のガチャガチャ要素がでかいかもしれないが、少しは試験外のサービスにも目を通しておいても良いかも
・やっぱり模擬問題の問題は全く出ないので、正直受けるだけ無駄…お祭りのくじびきみたいな一見さんをひっかけるための汚い仕掛けのようにも思える遠吠え
今回、ちゃんと勉強(?)したつもりで挑んだのに何でたった700点の上限を超えられない…?こんなバカな!
勉強方法がおかしかったと言われても、どの項目の何が間違っていたなんて点数しか明かされないから文句のつけようがないし…正直、もう受けたくないってのが本音です
いずれ滅び去るシステム専用の試験問題を高いお金を払ってやるなんてどう考えても馬鹿げてるし
AWSに限らず、資格試験全般を受けたくないです…まぁ、全部会社のお金なんですけどね…
- 投稿日:2019-10-09T15:49:50+09:00
AWS WorkSpacesでmacからのキーボード操作ができない
突然リーダーから「ちょっと本番環境見てくれや〜」って言われて、
いつも通りWorkSpacesにログインしたもののキーボードが反応せず大変困ったので備忘録を。環境
MacBook Pro (Retina, 15-inch, Mid 2015)
macOS Catalina バージョン 10.15 Beta
Amazon WorkSpaces Version 2.5.9.1186これのおかげ
https://forums.aws.amazon.com/thread.jspa?threadID=278583
対処法
WorkSpaceを起動してログイン。
キーボードで入力できるようになっていた!!突然キーボードが反応しなくなるのは辛い
同僚のPCから確認し、なんとか依頼は完了させました。参考
- 投稿日:2019-10-09T15:44:29+09:00
【AWS】EC2へのデプロイの手順<備忘録>
はじめに
プログラミング初心者です。自分のための備忘録として記録を残します。
環境
- macOS10
- Rails 5.2.3
- Nginx
- Unicorn
- Postgresql
- Sidekiq
- Redis
EC2インスタンス作成
- Amazon Linux AMI 2018.03.0(HVM,SSD Volume Typeを選択
- t2.microを選択(無料枠を利用の場合)
- キーペアの作成
↓
パブリックDNSが生成される。
*https://qiita.com/Quikky/items/2897573a42fd71cfc47fを参考にしました。rbenvインストールの準備
$ sudo yum install git $ sudo yum -y install gcc $ sudo yum -y install gcc-c++ $ sudo yum -y install zlib-devel $ sudo yum -y install openssl-devel $ sudo yum -y install readline-develrbenvのインストール
$ mkdir ~/.rbenv $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv $ mkdir ~/.rbenv/plugins ~/.rbenv/plugins/ruby-build $ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build $ cd ~/.rbenv/plugins/ruby-build $ sudo ./install.sh $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profileRubyのインストール
$ rbenv install 2.4.6 $ rbenv rehash $ rbenv global 2.4.6 $ ruby -vBundlerのインストール
$ rbenv exec gem install bundler -v 2.0.1 $ rbenv rehashGitHubでプロジェクトを作成
GitHubにPush
Mac上で $ git remote add origin <URLアドレス> $ git add . $ git commit -m "1st push" $ git push -u origin masterGitHubからEC2にPull
git clone <URLアドレス> cd <プロジェクトのディレクトリ>Railsのインストール
gem i -v 5.2.3 rails gem list rails$ bundle install上記でエラーが出たので以下のコマンド実施
$ gem install pg -v '1.1.4' --source 'https://rubygems.org/'postgreSQLのインストール
$ yum install postgresql $ sudo yum install postgresql-develSQLite3のエラー回避
sudo yum install sqlite-develインスタンスのセキュリティグループのインバウンド設定
- カスタムTCP/IP port 3000 0.0.0.0/0 を設定追加。
EC2インスタンス内でPostgres起動
sudo yum install -y postgresql-server sudo /sbin/service postgresql initdb sudo /sbin/service postgresql startEC2のインスタンス内でのPostgresの設定
マスターユーザー名:<プロジェクト名> マスターパスワード:<パスワード> postgres=# create role <username> with createdb login password '<password>'; postgres=# create database [database_name] owner [user_name]; $ sudo -u postgres psql postgres=# create role <プロジェクト名> with createdb login password '<パスワード>'; postgres=# create database <プロジェクト名>_production owner <プロジェクト名>; postgres=# create database <プロジェクト名>_development owner <プロジェクト名>; postgres=# create database <プロジェクト名>_test owner <プロジェクト名>; postgres=# \qDB(Postgres)の作成
.bash_profile export POSTGRES_USERNAME="<プロジェクト名>" export POSTGRES_PASSWORD="<パスワード>" プロジェクトのディレクトリ rails db:create/var/lib/pgsql9/data/pg_hba.conf local all all peer ↓ local all all md5 に変更。rails db:create rails db:migrateSMTPの設定
環境変数を.bash_profileに設定します。
EMAIL_ADDRESS EMAIL_PASSWORD設定おわったら、それを反映させるため以下のコマンドを実行
source .bash_profile
- RedisサーバをEC2に立ち上げる。
- ElasticCache選択
- 作成
primary endpointが生成。
VPCの設定で、Redisのインバウンド設定をセキュリティーグループにする
- sg-694f3715のインバウンドルールの編集で追加
- カスタムTCP:TCP
- port:6379
- source 0.0.0.0/0
以下のファイル設定
config/initializers/sidekiq.rb config/redis.ymlプロジェクトを再起動してSidekiqを起動
bundle exec sidekiqNginxをインストール
$ sudo yum install nginxMac上の/usr/local/etc/nginx/nginx.confをEC2環境にコピーする。
scp -i ~/.ssh/<プロジェクト名> nginx.conf ec2-user@XXXXXXXXXXXXXXXXXXXXX.amazonaws.com:~/nginx.conf sudo cp ~/nginx.conf /etc/nginx/ポート番号や、rootディレクトリを修正する。
Unicornの起動
unicorn -c config/unicorn.rb -E production -DNginx起動
$ sudo service nginx startVPCの設定で、port80(HTTP)を追加
ホームディレクトリの権限を744(drwxr--r--)に変更する。
chmod 755 ~/Nginxのリスタート
$ sudo service nginx restartproduction 環境のDBを構築する。
$ rails db:migrate RAILS_ENV=productionUnicornの再起動
$ kill [pid] $ unicorn -c config/unicorn.rb -E production -Dアセットパイプラインでエラーが発生。
config/environments/production.rb内の config.assets.compileをfalseからtrueに変更*https://kakuyon.hatenablog.com/entry/2018/07/15/033059を参考にしました。
- 投稿日:2019-10-09T11:48:17+09:00
[AWS CDK]thisがエラーになる
new s3.Bucket
使用としたらthis
がエラー(TS2345)になった。cdk-stack.tsimport * as cdk from '@aws-cdk/core'; import * as s3 from '@aws-cdk/aws-s3'; export class CdkStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // this ok const serviceName: string = this.node.tryGetContext("serviceName"); // this error const originBucket = new s3.Bucket(this, `${serviceName}BucketId`, { bucketName: `${serviceName}-bucket` }); }; }解決策
package.json内でaws-cdkのバージョンが混合していると発生するエラーらしいのでバージョンを揃える
package.json"devDependencies": { "@aws-cdk/core": "^1.11.0", "@aws-cdk/aws-s3": "^1.12.0", "aws-cdk": "^1.11.0", "@types/node": "^12.7.11" }↓
package.json"devDependencies": { "@aws-cdk/core": "^1.12.0", "@aws-cdk/aws-s3": "^1.12.0", "aws-cdk": "^1.12.0", "@types/node": "^12.7.11" }参考
- 投稿日:2019-10-09T09:00:15+09:00
Amazon Web Services (AWS)サービスの正式名称・略称・読み方まとめ #9 (移行と転送)
Amazon Web Services (AWS)のサービスで正式名称や略称はともかく、読み方がわからずに困ることがよくあるのでまとめてみました。
Amazon Web Services (AWS) - Cloud Computing Services
https://aws.amazon.com/まとめルールについては下記を参考ください。
Amazon Web Services (AWS)サービスの正式名称・略称・読み方まとめ #1 (コンピューティング) - Qiita
https://qiita.com/kai_kou/items/a6795dbab7e707b0d1a6間違いや、こんな呼び方あるよーなどありましたらコメントお願いします!
Migration & Transfer - 移行と転送
AWS Application Discovery Service
- 正式名称: AWS Application Discovery Service
- https://docs.aws.amazon.com/application-discovery/?id=docs_gateway
- 読み方: アプリケーション ディスカバリ サービス
- 略称: なし
- 俗称: ADS
AWS Database Migration Service (AWS DMS)
- 正式名称: AWS Database Migration Service
- https://docs.aws.amazon.com/dms/?id=docs_gateway
- 読み方: データベース マイグレション サービス
- 略称: AWS DMS
- 俗称: なし
AWS DataSync
- 正式名称: AWS DataSync
- https://docs.aws.amazon.com/datasync/?id=docs_gateway
- 読み方: データシンク
- 略称: なし
- 俗称: なし
AWS Migration Hub
- 正式名称: AWS Migration Hub
- https://docs.aws.amazon.com/migrationhub/?id=docs_gateway
- 読み方: マイグレーション ハブ
- 略称: なし
- 俗称: なし
AWS Server Migration Service (SMS)
- 正式名称: AWS Server Migration Service
- https://docs.aws.amazon.com/server-migration-service/?id=docs_gateway
- 読み方: サーバ マイグレーション サービス
- 略称: SMS
- 俗称: なし
AWS Snowball
- 正式名称: AWS Snowball
- https://docs.aws.amazon.com/snowball/?id=docs_gateway
- 読み方: スノーボール
- 略称: なし
- 俗称: なし
AWS Transfer for SFTP (AWS SFTP)
- 正式名称: AWS Transfer for SFTP
- https://docs.aws.amazon.com/transfer/?id=docs_gateway
- 読み方: トランスファー フォー エスエフティーピー
- 略称: AWS SFTP
- 俗称: なし
- 投稿日:2019-10-09T02:41:11+09:00
CloudFront で IPv6対応の APIを作る際の罠
IPv6なAPIをつくりたいぞ!
APIGateway x Lambda で APIをつくるのは定石だが、IPv6対応させようとした瞬間に悩む。
そう、APIGatewayが、IPv6対応していないのである!
仕方がないので、手前にCloudFrontを置いてやるのが、これまた定石。APIGatewayの手前のCloudFrontって、エラー時とかタイムアウト時のキャッシュ周りで癖が強いから、ちゃんと設定しないと、ユーザが無限エラーにハマったりで大変だよね、、とかあるけど、それはまた別の話
独自ドメインを振りたいが?
さて、CloudFront => APIGateway => Lambda したところで、当然ドメインを振りたいわけだ。
AWSあるある、マネージドサービスにドメイン振る場合はRoute53必須問題。だが、そんなことは百も承知。
しかも私は賢いので、CNAMEではなく、ALIASレコードで華麗にマネージドサービスに別名をつけるのさ、ふふん。と思っていたんですけどね、補完候補にCloudFrontのDistが出てこねーんだわ。。
仕方なく、手動で入れるとちゃんと認識する、なんでやねん。
(あと地味にCloudFront側のCNAMEリストにALIASレコードと同じ名前の定義を入れないとダメって初見だと気づかんよね...)あとはHTTPS対応かな?
独自ドメインにする場合、ACMに証明書を登録しておかないとCloudFront側の設定が進めなくなって詰む、ガッテム!
しかし、私は賢いので、ACMにちゃんとGeoTrustの証明書をインポートしてあるのさ、ふふん。と思ってたんですけどね、補完候補にACMで登録したはずの証明書がでてこねーんだわ。。
調べていくと、CloudFrontが参照するACMはバージニアリージョンのACMなんだってさ!へぇ!
ファック!!と殺意を覚えつつも、バージニアのACMに証明書を入れたら、無事認識してめでたしめでたし。にしても、CloudFront遅すぎない?
ここまでCloudFrontの設定を変えて更新を繰り返しているのだが、どうにも遅い。
設定をミリ弄って更新を押すと、都度10分〜30分は帰ってこない。
こんな状態でトライ&エラーとかやってられるかという感じだ。
(CNAME/ACMに依存する設定をかえると、30分かかる感じだった)ちなみに、deploy now みたいなステータスでアクセスすると、変な挙動したり、レスポンスが先祖返りすることがあるが、そういうものみたいなので、この状態での動作を気にしてはいけない。
IPアドレス問題
もう疲れたので終わりにしたいけど、なんかね、APIGatewayで $context.identity.sourceIp を使ってたんですよ。
なんとこいつが、CloudFrontのIPアドレスで入ってきて、クライアントのIPが取れねぇw
ELB挟んだりするのと同じと言われると、なるほど、と思うが...いやいやいや。で、どうすりゃえーねんというと、 X-Forwarded-For ヘッダーを信用して、APIGateway側のマッピングテンプレートでこいつをLambdaに渡してやれということだ。(カンマ区切りで中継IPが全てはいるので、Lambda側でパースが必要。)
ちなみに、$context.identity.sourceIp は IPv6を受け取れないが、X-Forwarded-For にはIPv6が入る。なるほどね。IPv6 Only のエッジを分けておきたい
普通はDual StackのAPIでおわり、、なんだが、用途として特殊で、IPv4とIPv6のエッジを明示的に指定できるようにしておきたかったのだ。
Route53のALIASレコードでAとAAAAを違う名前でつけておけば実現できる、そう思っていた時期が私にもありました。
これやるとね、Aしか振ってない名前でIPv4/IPv6両方いけるんですよねww(逆も然り)
色々やったけど、ダメだったので、多分AWSのバグ仕様なんだと思います。苦肉の策として、CloudFrontのDistributeを二系統つくって、AのALIASとAAAAのALIASをそれぞれ別に指定してやった。そしたら、期待通りの動き、パーフェクトゲームだ。
おわりに
こうして、期待するAPI構築が終わり(実際にはCORS問題もあったが、
Serverless Frameworkが優秀すぎて、数分で解決した)、私は帰宅するのであった。そうそう、「クラウドはIPv6対応万全だ、アプリケーション開発者が怠けてるだけだ」と口を大にしてゆう人を、非開発系のIPv6推進者(笑)の方でよく見かける。
君らは自分でクラウドのIPv6使って開発してから、そういうこと言おうな?
とマジで思う。IPv6は普及してきたといっても、実際にコンテンツを開発/運用する上で足りてないものが、まだまだたくさんある。みんな、色んな罠や沼で精神汚染されて、苦しむといい。
その苦しみが、IPv6で自在にコンテンツを開発・運用するための糧になる。
というか、今失敗しないと、永久にIPv4の呪縛からは解かれないからな。
- 投稿日:2019-10-09T01:10:57+09:00
【AWS】CloudFormationでIAM RoleのPolicy定義に変数を用いる【小ネタ】
はじめに
CloudFormationのResourceのPropertyの指定において、Typeが「Json」のものがいくつかあります。
IAM Roleの「AssumeRolePolicyDocument」や「Policies」などがこれに該当します。しかしながら、IAM Entityに対して指定するPolicyドキュメントでCFnの関数を使いたいことが多く(PolicyドキュメントのResourceに、他のCFn Stackで作成したリソースを指定する、など)、JSONでは指定が難しいことも多々あります。
Typeが「Json」となっているProperyには、同等の内容をyamlとして定義して渡すことも可能です。
この仕様を利用して、PolicyドキュメントでCFn関数を指定することが可能です。AWS::IAM::Role - AWS CloudFormation
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-assumerolepolicydocument
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-policiesAWS::IAM::Role Policy - AWS CloudFormation
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-policy.html#cfn-iam-policies-policydocumentIAM Role定義サンプル
以下の2つのCloudFormationテンプレート定義は等価です。
JSON形式でPolicyドキュメントを指定する
Resources: # AWS::IAM::Role - AWS CloudFormation # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html SampleAdminRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "sts:AssumeRole" } ] } Description: Describe what you want Policies: - PolicyName: AllowAllActions PolicyDocument: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ] }yaml形式でPolicyドキュメントを指定する
AWSTemplateFormatVersion: '2010-09-09' Description: Describe what you want. Parameters: # Define what you want. Resources: # AWS::IAM::Role - AWS CloudFormation # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html SampleAdminRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: AWS: "arn:aws:iam::123456789012:root" Action: "sts:AssumeRole" Description: Describe what you want Policies: - PolicyName: AllowAllActions PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "*" Resource: "*"AssumeRolePolicyDocumentのPrincipalでCFn関数を使う
上記のように、TypeとしてJsonが指定されているPropertyをyamlに変換したことで、CFn関数を利用しやすくなります。
先ほどの例ですと、AssumeRoleする主体となるPrincipalのAWSアカウントIDを、Parameterとして渡したくなると思います。
この場合、以下のように!Sub関数を利用することが可能です。cfn-iam-role-policy-with-function.ymlAWSTemplateFormatVersion: '2010-09-09' Description: Describe what you want. Parameters: # Define what you want. PrincipalAwsAccountId: Description: An AWS account id will be a principal to invoke the AssumeRole API. Type: Number Default: 123456789012 Resources: # AWS::IAM::Role - AWS CloudFormation # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html SampleAdminRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: AWS: !Sub arn:aws:iam::${PrincipalAwsAccountId}:root Action: "sts:AssumeRole" Description: Describe what you want Policies: - PolicyName: AllowAllActions PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "*" Resource: "*"Fn::Sub - AWS CloudFormation
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.htmlCFnスタック作成時に、下記のようにPrincipalAwsAccountIdパラメータを指定することで、任意のAWSアカウントIDに対応することができるようになります。
$ aws cloudformation create-stack \ --stack-name iam-role-policy-with-function \ --template-body file://cfn-iam-role-policy-with-function.yml \ --capabilities CAPABILITY_NAMED_IAM \ --parameters ParameterKey=PrincipalAwsAccountId,ParameterValue=987654321098,UsePreviousValue=trueおわりに
CDKが出たので、今後はCDKを使うことでこのような用途はProgrammaticに解決できるようになると思います。
しかしながら、いきなり全て移行することは難しいため、このようなテクニックはまだ暫く必要になるでしょう。