- 投稿日:2020-08-08T23:39:08+09:00
[AWS] AWS上に、安価で簡単にRedmineの環境を作成・管理できるよ!そうLightsailならね
Redmine
今更説明する必要もありませんが、Webベースのプロジェクト管理ツールです。
AWSには、DB(PostgreSQL、MySQL)や全文検索(Elasticsearch)、あるいはコンテナ管理(Kubernetes)など、様々なOSSをマネージドサービスとして提供されていますが、残念ながらプロジェクト管理や課題管理をしてくれるサービスがありません(2020年8月現在)。これらのサービスを利用しようと思ったら、
- EC2インスタンス上で起動
- ECSでRedmineのコンテナを起動
少なくともAWS上で、ということを考えると、この辺がすぐに思い浮かぶと思います。
などが考えられると思います。
が、しかし、もっと簡単な方法があるのです。それも定額で。Amazon Lightsail
AWSでの仮装サーバといえば、すぐに思い浮かぶのは、やはりEC2だと思います。
EC2は、多種多様なインスタンスやOSの選択ができる一方、課金がインスタンスの稼働時間に依存するため、気がつくと高額になっている、なんてことも実はない話ではありません。
しかし、Lightsailは、なんと定額利用できる、仮装サーバなのです。
EC2でもリザーブドインスタンスなどを利用すれば、かなりコストを抑えることができますが、それも及ばないほど、しかも定額で利用することができるのです。価格
いくつか、インスタンスタイプが用意されています。
これはEC2と同様で、メモリ、CPUコア数、ディスク容量、データ転送量の組み合わせです。
あと、OSは、LinuxとWindowsが選択できますが、価格面ではWindowsの方がやや高い設定になっています。
- Linux (Amazon Linux / Ubuntu / Debian / FreeBSD / OpenSUSE)
- 3.5$/月 〜 160$/月
- Windows Server
- 8$/月 〜 240$/月
※USドル
なお、データ転送量のみ、それぞれのプランの上限を超過した場合に、超過分のみの追加料金が発生します。
用意されているOSS
もう一つ特徴的なのが、いくつかのOSSが自動設定可能になっています。
そう、自分でインストールして初期設定して、といった作業が不要になるのです。
提供されているOSSは、以下の通りです。
- WordPress
- WordPress Multisite
- LAMP
- Node.js
- Joomla!
- Magento
- MEAN
- Drupal
- GitLab CE
- Remine
- Nginx
- Ghost
- Django
- Plesk
- cPanel & WHM
Redmineを使えるようにするまで
Lightsailでのインスタンス作成
まず、サービス一覧より、Lightsailを選択します。
ここで「インスタンスの作成」を押します。
次の画面で、
- リージョン(アベイラビリティゾーン)
- OS
- OSS
- インスタンスプラン
などを選択します。
今回は、東京リージョン上に、Lunux+Redmineで、月額3.5$のインスタンス作成してます。
すると、下記のように「保留中」という状態になり、1分もしないうちに「実行中」に変わります。これだけで、RedmineがセットアップされたLinux環境ができあがりました。
Redmineユーザの確認
まず、インスタンスに接続してみます。
インスタンスの枠の右上にあるメニューをクリックします。その中から「接続」を選択してください。
ステータスが「実行中」になった直後だと、まだインスタンスに接続できないことがあります。
その場合は、1、2分経ってから接続してみてください。接続できると、ブラウザで別のウィンドウが開き、コンソールが表示されます。
どんなファイルがあるか、見てみましょう。
bitnami@ip-172-26-4-233:~$ ls -la total 40 drwxr-xr-x 4 bitnami bitnami 4096 Aug 8 12:35 . drwxr-xr-x 3 root root 4096 Feb 6 2020 .. lrwxrwxrwx 1 bitnami bitnami 17 Feb 6 2020 apps -> /opt/bitnami/apps -rw-r--r-- 1 bitnami bitnami 220 Aug 31 2015 .bash_logout -rw-r--r-- 1 bitnami bitnami 4139 Feb 6 2020 .bashrc -rw------- 1 bitnami bitnami 13 Aug 8 12:35 bitnami_application_password -r-------- 1 bitnami bitnami 422 Aug 8 12:35 bitnami_credentials drwx------ 2 bitnami bitnami 4096 Feb 6 2020 .cache lrwxrwxrwx 1 bitnami bitnami 27 Feb 6 2020 htdocs -> /opt/bitnami/apache2/htdocs -rw-r--r-- 1 bitnami bitnami 655 Jul 12 2019 .profile drwx------ 2 bitnami bitnami 4096 Aug 8 12:33 .ssh lrwxrwxrwx 1 bitnami bitnami 12 Feb 6 2020 stack -> /opt/bitnamiはい、この中の
bitnami_credentials
に、Redmineの管理用ログインIDとパスワードが記載されているのです。このファイルにある赤枠部分がログインID、青枠部分がパスワードになります。
Redmineに接続してみる
インスタンスに対してパブリックIPアドレスが割り当てられています。
上記例ですと
http://54.92.33.40
にアクセスしてみましょう。Redmineの画面が出てきました!
管理者でログインする
では、
bitnami_credentials
に記載されていた情報でログインしてみましょう。
画面右上にある「ログイン」をクリックします。そして、ログインIDとパスワードを入力し、ログインします。
ログインできました!
あとは、「Administration」から、各種設定を行ってください。
初期状態は英語表示ですが、日本語表示も問題なく動作します。ネットワークの設定を変更したい
実はLightsailのネットワークはVPCで構成されていません。
ある意味、これが管理を簡略化できる要因の一つだったりもしますが、例えば、IPアドレスはインスタンス起動ごとに変更になってしまうので固定したい、だとか、IPアドレスではなくホスト名(ドメイン名)でアクセスしたい、などといったことが、実は可能です。
その場合は、最初の画面にある「ネットワーキング」をクリックしてみましょう。バックアップをとる
スナップショット
インスタンスに接続して所定の方法でバックアップを取得する方法もありますが、最も簡単なのはスナップショットをとってしまうことです。
インスタンスのメニューから「管理」を選択します。管理画面が表示されるので、この中から「スナップショット」を選択します。
今回は手動スナップショットを作成してみましょう。
スナップショットの名称を入力します。
今回はデフォルト設定のまま作成してみます。間も無く「スナップショット作成中」の状態になります。
しばらくたつと、完成します。
今回は手動でスナップショットを取得しましたが、自動スナップショットの場合、定期的に取得してくれるようになります。
スナップショットの使い道
作成済みのスナップショットは、ホーム画面で確認することができます。
ホーム画面の「スナップショット」をクリックしてみましょう。先ほど取得したスナップショットが確認できました。
では、スナップショットをどう使うかというと、スナップショットの右側にあるメニューを開いてみましょう。スナップショットを使ってできることは
- 新しくインスタンスを作成して、そこに復元する
- 別のリージョンにスナップショットをコピーする
- EC2にエクスポートする
- スナップショットを削除する
です。RDSのスナップショットなどとできることはほぼ同じようなものですが、EC2にエクスポートできるのが特徴的です。
EC2にエクスポートしてみた
せっかくここまでやってみたので、EC2にエクスポートするとどうなるか見てみたいと思います。
メニューから選択すると、確認画面が表示されます。
ここで「はい、続行します」を選択します。セキュリティの案内が出るので「承諾」。
なんか、歯車がクルクル回り出した!!
しばらく経つと、完了します。
EC2
EC2側での確認
では、どのような状態でエクスポートされているか、ですが、インスタンスとしてエクスポートされるわけではなく、EC2のスナップショットとして復元されます。
EC2の管理画面より、EBSのスナップショットを確認してみましょう。あったー!!
では、せっかくなんで、ここからインスタンスとして復元してみましょう。
「アクション」から「ボリュームの作成」を選択します。
そのままの状態で「ボリュームの作成」ボタンを押します。
少し経つと、ボリュームが出来上がります。
EC2インスタンスに復元
ちょっと長くなったので、省略しますが、手順はオーソドックスです。
- EC2インスタンスを作成
- Redmineに接続したいので、Public Subnetを割り当ててください
- EBSの設定は適当でよいです(サイズもあってなくてよいです)
- インスタンスが起動したら停止(終了ではないですよ!)
- この時、インスタンスのルートデバイス(/dev/xvdaなど)を確認しておいてください
- インスタンスのステータスが「stopping」から「stopped」になったら、ボリューム一覧の画面で、インスタンスからデタッチする。
- LightsailからエクスポートしたボリュームをEC2インスタンスにアタッチする
- ルートデバイスをちゃんと指定しましょう
- インスタンスのアベイラリティゾーンとあっていないとアタッチできないので、あっていない場合はボリューム作成時のアベイラリティゾーンをEC2インスタンスにあわせて作り直しましょう
- 停止中だったEC2インスタンスを開始する
ここまできたら、インスタンスのパブリックIPアドレスにブラウザでアクセスするだけです。
きたー!!!!
もちろん、Lightsailでアクセスした、管理者のログインIDとパスワードでログインもできます。
もしアクセスできない場合は、EC2インスタンスにアタッチされているセキュリティグループにHTTP(80)のポートをインバウンドルールに追加してみてください。まとめ
ご覧のように、AWS上でOSSを安価にさくっと立ち上げる方法として、Lightsailという選択肢が有効であることがおわかりいただけたかと思います。
また、スケーリングの必要性などが出てきた場合は、EC2インスタンスとして移行することも、非常に簡単に行えることがわかったかと思います。
これまで、EC2やECSの影に隠れがちで、あまりメジャーな感じがしなかったLightsailですが、こんな簡単に導入できるのです。
結構おすすめです!
- 投稿日:2020-08-08T23:39:08+09:00
[AWS] 安価で簡単にRedmineの環境を作成・管理できるよ!そうLightsailならね
Redmine
今更説明する必要もありませんが、Webベースのプロジェクト管理ツールです。
AWSでは、DB(PostgreSQL、MySQL)や全文検索(Elasticsearch)、あるいはコンテナ管理(Kubernetes)など、様々なOSSがマネージドサービスとして提供されていますが、残念ながらプロジェクト管理や課題管理をしてくれるサービスがありません(2020年8月現在)。これらのサービスを利用しようと思ったら、
- EC2インスタンス上で起動
- ECSでRedmineのコンテナを起動
少なくともAWS上で、ということを考えると、この辺がすぐに思い浮かぶと思います。
などが考えられると思います。
が、しかし、もっと簡単な方法があるのです。それも定額で。Amazon Lightsail
AWSでの仮想サーバといえば、すぐに思い浮かぶのは、やはりEC2だと思います。
EC2は、多種多様なインスタンスやOSの選択ができる一方、課金がインスタンスの稼働時間に依存するため、気がつくと高額になっている、なんてことも実はない話ではありません。
しかし、Lightsailは、なんと定額利用できる、仮想サーバなのです。
EC2でもリザーブドインスタンスなどを利用すれば、かなりコストを抑えることができますが、それも及ばないほど、しかも定額で利用することができるのです。価格
いくつか、インスタンスタイプが用意されています。
これはEC2と同様で、メモリ、CPUコア数、ディスク容量、データ転送量の組み合わせです。
あと、OSは、LinuxとWindowsが選択できますが、価格面ではWindowsの方がやや高い設定になっています。
- Linux (Amazon Linux / Ubuntu / Debian / FreeBSD / OpenSUSE)
- 3.5 USドル/月 - 160.0 USドル/月
- Windows Server
- 8.0 USドル/月 - 240.0 USドル/月
なお、データ転送量のみ、それぞれのプランの上限を超過した場合に、超過分のみの追加料金が発生します。
用意されているOSS
もう一つ特徴的なのが、いくつかのOSSが自動設定可能になっています。
そう、自分でインストールして初期設定して、といった作業が不要になるのです。
提供されているOSSは、以下の通りです。
- WordPress
- WordPress Multisite
- LAMP
- Node.js
- Joomla!
- Magento
- MEAN
- Drupal
- GitLab CE
- Remine
- Nginx
- Ghost
- Django
- Plesk
- cPanel & WHM
Redmineを使えるようにするまで
Lightsailでのインスタンス作成
まず、サービス一覧より、Lightsailを選択します。
ここで「インスタンスの作成」を押します。
次の画面で、
- リージョン(アベイラビリティゾーン)
- OS
- OSS
- インスタンスプラン
などを選択します。
今回は、東京リージョン上に、Linux+Redmineで、月額3.5$のインスタンス作成してます。
すると、下記のように「保留中」という状態になり、1分もしないうちに「実行中」に変わります。これだけで、RedmineがセットアップされたLinux環境ができあがりました。
Redmineユーザの確認
まず、インスタンスに接続してみます。
インスタンスの枠の右上にあるメニューをクリックします。その中から「接続」を選択してください。
ステータスが「実行中」になった直後だと、まだインスタンスに接続できないことがあります。
その場合は、1、2分経ってから接続してみてください。接続できると、ブラウザで別のウィンドウが開き、コンソールが表示されます。
どんなファイルがあるか、見てみましょう。
bitnami@ip-172-26-4-233:~$ ls -la total 40 drwxr-xr-x 4 bitnami bitnami 4096 Aug 8 12:35 . drwxr-xr-x 3 root root 4096 Feb 6 2020 .. lrwxrwxrwx 1 bitnami bitnami 17 Feb 6 2020 apps -> /opt/bitnami/apps -rw-r--r-- 1 bitnami bitnami 220 Aug 31 2015 .bash_logout -rw-r--r-- 1 bitnami bitnami 4139 Feb 6 2020 .bashrc -rw------- 1 bitnami bitnami 13 Aug 8 12:35 bitnami_application_password -r-------- 1 bitnami bitnami 422 Aug 8 12:35 bitnami_credentials drwx------ 2 bitnami bitnami 4096 Feb 6 2020 .cache lrwxrwxrwx 1 bitnami bitnami 27 Feb 6 2020 htdocs -> /opt/bitnami/apache2/htdocs -rw-r--r-- 1 bitnami bitnami 655 Jul 12 2019 .profile drwx------ 2 bitnami bitnami 4096 Aug 8 12:33 .ssh lrwxrwxrwx 1 bitnami bitnami 12 Feb 6 2020 stack -> /opt/bitnamiはい、この中の
bitnami_credentials
に、Redmineの管理用ログインIDとパスワードが記載されているのです。このファイルにある赤枠部分がログインID、青枠部分がパスワードになります。
Redmineに接続してみる
インスタンスに対してパブリックIPアドレスが割り当てられています。
上記例ですと
http://54.92.33.40
にアクセスしてみましょう。Redmineの画面が出てきました!
管理者でログインする
では、
bitnami_credentials
に記載されていた情報でログインしてみましょう。
画面右上にある「ログイン」をクリックします。そして、ログインIDとパスワードを入力し、ログインします。
ログインできました!
あとは、「Administration」から、各種設定を行ってください。
初期状態は英語表示ですが、日本語表示も問題なく動作します。ネットワークの設定を変更したい
実はLightsailのネットワークはVPCで構成されていません。
ある意味、これが管理を簡略化できる要因の一つだったりもしますが、例えば、IPアドレスはインスタンス起動ごとに変更になってしまうので固定したい、だとか、IPアドレスではなくホスト名(ドメイン名)でアクセスしたい、などといったことが、実は可能です。
その場合は、最初の画面にある「ネットワーキング」をクリックしてみましょう。バックアップをとる
スナップショット
インスタンスに接続して所定の方法でバックアップを取得する方法もありますが、最も簡単なのはスナップショットをとってしまうことです。
インスタンスのメニューから「管理」を選択します。管理画面が表示されるので、この中から「スナップショット」を選択します。
今回は手動スナップショットを作成してみましょう。
スナップショットの名称を入力します。
今回はデフォルト設定のまま作成してみます。間も無く「スナップショット作成中」の状態になります。
しばらくたつと、完成します。
今回は手動でスナップショットを取得しましたが、自動スナップショットの場合、定期的に取得してくれるようになります。
スナップショットの使い道
作成済みのスナップショットは、ホーム画面で確認することができます。
ホーム画面の「スナップショット」をクリックしてみましょう。先ほど取得したスナップショットが確認できました。
では、スナップショットをどう使うかというと、スナップショットの右側にあるメニューを開いてみましょう。スナップショットを使ってできることは
- 新しくインスタンスを作成して、そこに復元する
- 別のリージョンにスナップショットをコピーする
- EC2にエクスポートする
- スナップショットを削除する
です。RDSのスナップショットなどとできることはほぼ同じようなものですが、EC2にエクスポートできるのが特徴的です。
EC2にエクスポートしてみた
せっかくここまでやってみたので、EC2にエクスポートするとどうなるか見てみたいと思います。
メニューから選択すると、確認画面が表示されます。
ここで「はい、続行します」を選択します。セキュリティの案内が出るので「承諾」。
なんか、歯車がクルクル回り出した!!
しばらく経つと、完了します。
EC2
EC2側での確認
では、どのような状態でエクスポートされているか、ですが、インスタンスとしてエクスポートされるわけではなく、EC2のスナップショットとして復元されます。
あと、カスタムAMIとしても作成されますが、今回は、スナップショットから復元する方法で進めてみようと思います。まずは、EC2の管理画面より、EBSのスナップショットを確認してみましょう。
あったー!!
では、せっかくなんで、ここからインスタンスとして復元してみましょう。
「アクション」から「ボリュームの作成」を選択します。
そのままの状態で「ボリュームの作成」ボタンを押します。
少し経つと、ボリュームが出来上がります。
EC2インスタンスに復元
ちょっと長くなったので、省略しますが、手順はオーソドックスです。
- EC2インスタンスを作成
- Redmineに接続したいので、Public Subnetを割り当ててください
- EBSの設定は適当でよいです(サイズもあってなくてよいです)
- インスタンスが起動したら停止(終了ではないですよ!)
- この時、インスタンスのルートデバイス(/dev/xvdaなど)を確認しておいてください
- インスタンスのステータスが「stopping」から「stopped」になったら、ボリューム一覧の画面で、インスタンスからデタッチする。
- LightsailからエクスポートしたボリュームをEC2インスタンスにアタッチする
- ルートデバイスをちゃんと指定しましょう
- インスタンスのアベイラリティゾーンとあっていないとアタッチできないので、あっていない場合はボリューム作成時のアベイラリティゾーンをEC2インスタンスにあわせて作り直しましょう
- 停止中だったEC2インスタンスを開始する
ここまできたら、インスタンスのパブリックIPアドレスにブラウザでアクセスするだけです。
きたー!!!!
もちろん、Lightsailでアクセスした、管理者のログインIDとパスワードでログインもできます。
もしアクセスできない場合は、EC2インスタンスにアタッチされているセキュリティグループにHTTP(80)のポートをインバウンドルールに追加してみてください。まとめ
ご覧のように、AWS上でOSSを安価にさくっと立ち上げる方法として、Lightsailという選択肢が有効であることがおわかりいただけたかと思います。
また、スケーリングの必要性などが出てきた場合は、EC2インスタンスとして移行することも、非常に簡単に行えることがわかったかと思います。
これまで、EC2やECSの影に隠れがちで、あまりメジャーな感じがしなかったLightsailですが、こんな簡単に導入できるのです。
結構おすすめです!
- 投稿日:2020-08-08T23:11:59+09:00
メモ:Elastic IPアドレスの一覧を取得する
- 投稿日:2020-08-08T22:06:58+09:00
AWS AmplifyのAuthで取得した認証情報をAWS SDKのCredentialProviderChainを利用して埋め込む
前回からの続き
AWS Amplify Libraryで取得した認証をAWS SDKで利用する
CredentialProviderChainから認証が通ってAWS SDKの処理が動いた時点で書き込んでおり、肝心の認証情報が失効したあとの自動更新はまだ確認していません。確認できたら追記します。
とりあえず、調べてもほとんど情報が出てこない、
CredentialProviderChain
の使い方メモ的にでも残しておく。やること
Amplifyの
Auth.currentUserCredentials()
で取得した認証情報は1時間で失効する。この方法で取得した認証情報をAWS SDKに引き継いで利用する場合などにおいて、1時間以上時間が空いたあとに処理を再開すると使えなくなる。( SPAなどでアプリケーションを提供していて、1時間以上画面を放置した場合とか)
それを回避するために、自前で認証情報が失効するタイムスタンプを見て、切れていたら認証情報を取得し直すというコードを書いていると煩雑になるので、AWS SDKの
CredentialProviderChain
を利用して、認証情報の再発行を任せる。仕組みについて
前回の記事から続いてS3を例とする。前回は初期化時の引数について、
credential
フィールドに認証情報(アクセスキーなど)を直接渡していたが、今回はcredentialProvider
を使う。const s3 = new AWS.S3({ credentialProvider: provider, region: '任意のリージョン', });この
credentialProvider
はAWS SDK側で下記のように定義されている。aws-sdk/lib/credentials/credential_provider_chain.d.tsimport {Credentials} from '../credentials'; import {AWSError} from '../error'; export class CredentialProviderChain { /** * Creates a new CredentialProviderChain with a default set of providers specified by defaultProviders. */ constructor(providers?: provider[]) /** * Resolves the provider chain by searching for the first set of credentials in providers. */ resolve(callback:(err: AWSError, credentials: Credentials) => void): CredentialProviderChain; /** * Return a Promise on resolve() function */ resolvePromise(): Promise<Credentials>; /** * Returns a list of credentials objects or functions that return credentials objects. If the provider is a function, the function will be executed lazily when the provider needs to be checked for valid credentials. By default, this object will be set to the defaultProviders. */ providers: Credentials[]|provider[]; static defaultProviders: provider[] } type provider = () => Credentials;コンストラクタにproviderの定義を満たす実装を渡しておくと、渡した順番に認証情報を評価し、利用可能なものがあればそれを使う動きをするらしい。providerはCredentialsを返す関数型となっている。そのため、Credentialsの定義を満たしたクラスを渡せばいいらしい。
Credentialsの定義が長いので省略するが、この定義を満たす実装がAWS SDKからいくつか提供されているのでそれを使っても良さそうだが、今回の記事のテーマのようなものは用意されていないので自作することとなった。事前に用意されているものは、JSONファイルから認証情報をパースしたりするものなどで、例としては下記。
import {Credentials} from '../credentials'; export class FileSystemCredentials extends Credentials { /** * Creates a new FileSystemCredentials object from a filename. * @param {string} filename - The path on disk to the JSON file to load. */ constructor(filename: string); /** * The path to the JSON file on disk containing the credentials. */ filename: string }↑はTypeScriptの定義だけなので、JavaScript側の実装まで追いかけると、Credentialクラスのメソッドをオーバーライドして、必要箇所の実装を満たすようになっている。実装をしておくと、各種AWS SDK側のコードから、認証情報を読み取って利用してくれる仕組みになっている。
AmplifyのAuthをproviderとして渡すクラスを自作する
実装がまだ荒削りかもしれないが(コンストラクタの中身とか)、↓を実装した。必要最低限のメソッドをオーバーライドしている。認証情報が失効しているかをチェックするメソッドなどもあり、最初はそれをオーバーライドして中身でDateの比較を実装していたが、
this.expireTime
に渡すと、スーパークラス側(Credentialsクラス)で判定してくれるようなので、値のセットだけにした。Promiseで取り扱うためのメソッドと、そうではないメソッドで2つ別れていて、それがどういう条件で使い分けされるかわわからないが(refreshとrefreshPromise)、両方に対応できるようにしておいた。また、片言のコメントに書いてあるように、
Auth.currentUserCredentials()
の返却値の定義にはexpiration
は定義されていないが、実態には含まれる。import { Auth } from '@aws-amplify/auth'; import * as AWS from 'aws-sdk'; export class AmplifyAuthCredentials extends AWS.Credentials { constructor() { super('', '', ''); } refresh(callback: (err?: AWS.AWSError) => void) { this.setCredentials().then(() => callback()).catch(callback); } async refreshPromise() { return this.setCredentials(); } private async setCredentials() { try { const credentials = await Auth.currentUserCredentials(); this.accessKeyId = credentials.accessKeyId; this.secretAccessKey = credentials.secretAccessKey; this.sessionToken = credentials.sessionToken; this.expired = false; // Amplify's Auth.currentUserCredentials contains expiration date time with string object. this.expireTime = new Date((credentials as any).expiration); } catch (error) { return Promise.reject(error); } } }このクラスを下記のように使う。ログにS3のファイル一覧が出るはず。
import * as AWS from 'aws-sdk'; const provider = new AWS.CredentialProviderChain([ () => new AmplifyAuthCredentials(), ]); const s3 = new AWS.S3({ credentialProvider: provider, region: region, }); s3.listObjectsV2({ Bucket: '任意のバケット名'}) .promise() .then(console.log) .catch(console.error);まとめ
CredentialProviderChain
に 自作のクラスを渡す方法はかなり探しても見つからなかったが、上記のような方法で実現は可能。
- 投稿日:2020-08-08T20:34:40+09:00
FlutterとAWSで始めるサービス開発 (8)Cognitoの認証情報を使ってAPIを呼び出す
はじめに
「(5)AWS Cognitoでログイン」や、「(7)AWS Cognito Googleでログイン」で、Cognitoを使ったログイン処理を一通り実装完了しました。今回はそれら認証情報がないと呼び出せないAPIを実装していきたいと思います。前回まででCognito ユーザープールからID Tokenを取得するところまではできています。APIを呼び出すために、ID Tokenを要求し、それを検証してから実行するAPIを作っていきます。つまり、ログインした場合だけサービスのAPIを呼び出せるというモデルを実現するための構成です。認証した上でさらに特定の権限を持っているユーザーだけが利用できるといったAPIも考えられますが、今回はそこまでは踏みこみません。
参考文献
- 公式サイト
APIの作成
早速APIを作成していきます。AWSマネージメントコンソールからLambdaを開き、関数の作成を押下します。
まず、設計図の使用を選択し、httpでフィルタします。microservice-http-endpoint-pythonを選択します。python版の選択理由は単に筆者の職場では、Lambdaのアプリをpythonで書いていて慣れているからです。
関数名には任意の名前を入れてください。実行ロールは、基本的なLambdaアクセス権限で新しいロールを作成を選択します。
API Gaeway トリガー
ではAPIにCreate an API、API TypeにREST、セキュリティにオープンを選択します。API名は任意に決めてください。入力が終わったら追加ボタンを押下します。
以下が、変更後のコードです。一部元のソースを流用していますが、ほぼ書き換えてしまっています。本実装では、呼び出し時に渡されたeventの一部(
event['requestContext']['authorizer']['claims']
)を返却することだけをしています。event['requestContext']['authorizer']['claims']
に関しては後ほど解説したいとおもいます。import boto3 import json print('Loading function') def respond(err, res=None): return { 'statusCode': '400' if err else '200', 'body': err.message if err else json.dumps(res), 'headers': { 'Content-Type': 'application/json', }, } def lambda_handler(event, context): response = { "claims" : event['requestContext']['authorizer']['claims'] } return respond(None, response)以上で、APIの骨格が完成しましたが、次に、APIにCognitoとの認証連携を設定していきます。マネージメントコンソールでAPI Gatewayを開くと、先ほど作成したAPIが表示されるので選択します。
オーソライザーを選択し、新しいオーソライザーの作成を押下します。名前には任意の名前を入力し、タイプはCognitoを選択します。Cognitoユーザープールでは、作成してあるプールを選択し、トークンのソースにAuthorizationを入力し、作成ボタンを押下します。
リソースを選択し、作成したAPIのANYを選択し、メソッドリクエストを選択します。
認可で
Cognitoユーザープールオーソライザー
で先ほど作成したオーソライザーを選択します。
アクションからAPIのデプロイを選択し、デプロイされるステージでdefaultを選択しデプロイボタンを押下します。
以上でサーバー側の設定が完了です。
APIの呼び出し
ここまでで作ったAPIをFlutterのアプリケーションから呼び出します。
(5)AWS Cognitoでログインで作成したトップ画面を修正します。
まず、画面にAPIの呼び出し結果をテキストで表示する機能を追加します。非同期処理になるので、FutureBuilder<>
を利用します。Future
にAPIを呼び出し、レスポンスを文字列で返却する関数である_invokeApi()
を設定します。builder
ではデータを受け取ったら、API呼び出し結果をTextで返却、データを受け取らない間は、CircularProgressIndicator()
で処理中を表示するようにしています。
引き続き、_invokeApi()
の中身を確認します。先ほど作成したAPIの呼び出しコードです。Autorizationヘッダに、(5)AWS Cognitoでログインや(7)AWS Cognito Googleでログインで取得した、CognitoUserSessionインスタンスの、JWT形式IDトークンを設定しGET呼び出しを行っています。また、APIの呼び出し結果のResponse.bodyを戻り値としています。@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('トップページ'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('ログイン成功'), Divider(color: Colors.black), FutureBuilder<String>( future: _invokeApi(session), builder: (context, AsyncSnapshot<String> snapshot) { if (snapshot.hasData) { return Text(snapshot.data); } else { return CircularProgressIndicator(); } }) ], ), ), ); } Future<String> _invokeApi(CognitoUserSession session) async { String url = "https://2wmzck1189.execute-api.ap-northeast-1.amazonaws.com/default/testCognito"; final response = await http.get(url, headers: {'Authorization': session.getIdToken().getJwtToken()}); if (response.statusCode != 200) { throw Exception("Received bad status code from API:" + response.statusCode.toString() + "; body: " + response.body); } return response.body; } } `` 実際に本アプリを実行すると以下のように画面にレスポンスが表示されます。 ![app1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273926/5bae9119-23dc-8c2f-e282-6d89cbb36ef3.jpeg) 以上で、最低限のアプリケーションは完成です。 # API側での処理 API GatewayのオーソライザーでCognitoのID Tokenが検証できた場合、Lambda側には検証結果の情報として、Cognitoユーザーの情報がわたってきます。 前述した``event['requestContext']['authorizer']['claims']``にID Tokenの検証結果としてログインしているユーザーの情報が入ります。以下が具体的な、cliamsの中身になります。__sub__にCognitoのユーザープール内でユーザーを一意に識別するIDがわたってくるので、アプリケーションはそのキーを使って、ユーザーごとの処理を実装していくことが可能です。 ``` json "claims": { "at_hash": "jC8Q3e2kh1LmzloesriHHw", "sub": "bdec0872-9384-453f-99f9-c8c50dee23db", "aud": "***********************", "cognito:groups": "ap-northeast-1_*********_Google", "identities": "{"dateCreated":"1594465378058","userId":"100299533705733233603","providerName":"Google","providerType":"Google","issuer":null,"primary":"true"}", "token_use": "id", "auth_time": "1595514490", "iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_*********", "cognito:username": "google_100299533705733233603", "exp": "Thu Jul 23 15:28:10 UTC 2020", "iat": "Thu Jul 23 14:28:10 UTC 2020" }まとめ
Cognitoでログインして取得したIDトークンを利用してAPIの呼び出しを実施するところまでできました。これでサービス開発の最低限の流れはできたと思います。本シリーズはいったんここまでで終わりたいと思います。ここまで実装したコードを一通りリファクタリングしたり、エラー処理を拡充して、もう少し人に見せられそうなレベルに持っていけたらソースコードを公開しようかなと思います。また、あまり技術的なことは深く突っ込まず、どう設定すれば動くのかに比重をおいて進めてきましたが、もう少し技術面を整理してその辺の情報も公開できれば名智考えています。
- 投稿日:2020-08-08T20:10:41+09:00
EC2にPostgreSQLをインストールする方法(動作確認用)
インストール
sudo yum update # 省略していい sudo yum install postgresql postgresql-libs postgresql-server # 何をインストールしているのか未調査 sudo service postgresql initdb # これをしないと起動できないらしい sudo service postgresql start sudo service postgresql status sudo chkconfig postgresql on # EC2起動時にPostgreSQLを起動してくれるらしいpsqlを使う
postgresqlインストール時に作られるpostgresユーザに切り替える。
このユーザじゃないとpsqlを使えない。sudo su - postgres psql create database testdb; \l \c testdbメモ
postgresユーザに切り替えるのが不便で分かりにくい。
安全のための設定と思われる。参考
AmazonLinuxにPostgreSQL9.6をインストールする
https://qiita.com/shinsaka/items/cf45cd87c2c75e35ce12PostgreSQLの基本的なコマンド
https://qiita.com/H-A-L/items/fe8cb0e0ee0041ff3ceb
- 投稿日:2020-08-08T19:37:53+09:00
【今日から始めるAWS】LambdaでLINEのbotをつくる
はじめに
30代未経験からエンジニア転職をめざすコーディング初学者のYNと申します。お読みいただきありがとうございます。
コーディング初学者にとってのAWS入門といえばLambda
!、サーバレスアプリを作ろう!、ということでメッセージをオウム返ししてくるLINEのbotをつくりました。
下記参考記事をそのままコピーした内容になってしまったのですが、学習ログとして投稿させていただきました。今回やったこと
下記のように、こちらが送ったテキストメッセージをそのまま返答してくれる、オウム返しbotを作ります。
下記のサーバレス構造を構築します。(こちらの記事から図を拝借させていただきました。)
手順
- 事前準備
Lambda
の設定- API-gatewayの設定
- LINEチャンネルの設定
事前準備
- LINEデベロッパー登録
Lambdaの設定
- 1. ローカルPCでlambda関数のフォルダを作成
$ cd ~ $ mkdir line-bot $ cd line-bot
- 2. index.jsを作成
$ npm install @line/bot-sdkline-bot/index.js"use strict"; const line = require("@line/bot-sdk"); const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN }); // ①SDKをインポート const crypto = require("crypto"); exports.handler = function (event, context) { let body = JSON.parse(event.body); let signature = crypto .createHmac("sha256", process.env.CHANNELSECRET) .update(event.body) .digest("base64"); let checkHeader = (event.headers || {})["X-Line-Signature"]; if (signature === checkHeader) { // ②cryptoを使ってユーザーからのメッセージの署名を検証する if (body.events[0].replyToken === "00000000000000000000000000000000") { let lambdaResponse = { statusCode: 200, headers: { "X-Line-Status": "OK" }, body: '{"result":"connect check"}', }; context.succeed(lambdaResponse); // ③接続確認エラーを確認する。 } else { let text = body.events[0].message.text; const message = { type: "text", text, }; client .replyMessage(body.events[0].replyToken, message) .then((response) => { let lambdaResponse = { statusCode: 200, headers: { "X-Line-Status": "OK" }, body: '{"result":"completed"}', }; context.succeed(lambdaResponse); }) .catch((err) => console.log(err)); // ④リクエストとして受け取ったテキストをそのまま返す } } else { console.log("署名認証エラー"); } };下記、index.jsにおける処理を解説します。
①SDKをインポートする
const line = require("@line/bot-sdk"); const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });githubのexampleでSDKの使い方が参照できます。
②cryptoを使ってユーザーからのメッセージの署名を検証する
const crypto = require("crypto"); exports.handler = function (event, context) { let body = JSON.parse(event.body); let signature = crypto .createHmac("sha256", process.env.CHANNELSECRET) .update(event.body) .digest("base64"); let checkHeader = (event.headers || {})["X-Line-Signature"]; if (signature === checkHeader) { // ここでlambdaの処理を記載 }cryptoはnode.jsに標準で組み込まれている暗号化に関するライブラリで、botにおける実装の詳細についてはLINE公式ドキュメントに書いてあります。
(暗号化についてはこちらの記事が分かりやすかったです)ここでは、下記2点が一致するかを検証しています。
signature
: ユーザーから送られてきたリクエスト(event.body
)を、秘密鍵(CHANNELSECRET
)を使って暗号化したもの
event.headers["X-Line-Signature"]
:リクエストヘッダーに含まれる署名
③接続確認の場合の処理を実装する
botが接続確認を行う場合、
replyToken="000..."
のリクエストが来ます。let body = JSON.parse(event.body); if (body.events[0].replyToken === "00000000000000000000000000000000"){ let lambdaResponse = { statusCode: 200, headers: { "X-Line-Status": "OK" }, body: '{"result":"connect check"}', }; context.succeed(lambdaResponse); }
④リクエストとして受け取ったテキストをそのまま返す
ユーザーから送られてきたリクエストの中身(イベントオブジェクト)はLINE公式ドキュメントにまとめられています。
リクエストに含まれるメッセージがテキストの場合、body.events[0].message.text
に含まれます。
また、client.replyMessage(replyToken, message)
のメソッドを使うことで、ユーザーにメッセージを返信することが出来ます。let text = body.events[0].message.text; const message = { type: "text", text, }; client .replyMessage(body.events[0].replyToken, message) .then((response) => { let lambdaResponse = { statusCode: 200, headers: { "X-Line-Status": "OK" }, body: '{"result":"completed"}', }; context.succeed(lambdaResponse); })
- 3. index.jsとnode_modulesを圧縮しLambdaにアップロードする
- 4. アクセストークン(ACCESSTOKEN)とChannelSecret(CHANNELSECRET)を環境変数に登録する
API-gatewayの設定
LINEチャンネルの設定
LINE Official Account Manager
からユーザーからのメッセージに対するあいさつや応答の設定をすることができます。
最後に
Lambda
を使うことで、簡単にLINEのbotを作ることができます。
初学者でも1時間弱でつくることができました。
機械学習や外部のAPIを組み合わせれば、面白いことができそうです。
ご覧いただきありがとうございました。
- 投稿日:2020-08-08T17:44:02+09:00
【AWS】 押さえておくべきポイント <IAM, Security Group, AMI>
はじめに
以下のリンクがシンプルでわかりやすい説明のため、とても参考になりました。
【AWS初心者がインフラ設計/構築を理解するために、まず最初におさえるべきキーワード15選】
対象範囲
上記記事内で実践した内容には以下が含まれています。
使用した機能
- リージョン (Region)
- アベイラビリティーゾーン (AZ:Availability Zone)
- サブネット(Subnet)
- セキュリティグループ (Security Group)
- IAM (Identity and Access Management)
- ACL (Access Control List)
押さえておくべきポイント
- IAM
- セキュリティグループ(EC2)
- AMI
上記の説明に対してはもう少し踏み込んで理解したいと思ったので、下記をまとめました。
IAM
【AWS】IAMまとめ:IAMとは?
【AWS】IAMまとめ:IAMにできること以下のリンクは写真付きなので、作業工程もイメージしやすいです。
新人プログラマの為のAWS入門 ~導入編~:IAMロール・ユーザ作成
セキュリティグループ(EC2)
AMI
- 投稿日:2020-08-08T16:51:04+09:00
AWS Dynamo DBへのcsvインポートを手軽に実装(Windows・無料)
はじめに
Tech Dive様の記事 を大変参考にさせて頂きました。この場を借りて御礼申し上げます。
この記事は上記内容をWindows環境で実施した際の備忘録になります。
筆者の環境
・Windows 10
・Git Bash手順
Python3 のインストール
Pandasのインストール
pip install pandas
aws cliのインストール
インストールしてもGit Bash でaws
コマンドが使えなかったので、GitBashで
cmd \\C aws --version
を叩いてから再起動したら使えるようになりましたアクセスキーの確認
AWS ユーザーメニューの「マイセキュリティ資格情報」から、インポート用のアクセスキーを新規作成アクセスキーとシークレットアクセスキーの登録
aws configure
を叩き、先ほど作ったアクセスキーを登録aws configure AWS Access Key ID [None]: [アクセスキー] AWS Secret Access Key [None]: [シークレットアクセスキー] Default region name [None]: us-east-2 ※テーブルがあるリージョン Default output format [None]: jsonCSVのヘッダーを変更
先頭行をデータベースのkeyと合わせて、型を()でくくって指定
例) キーが「UserName」(String)なら UserName (S)import_to_dynamodb をclone
git clone https://github.com/hidesan-xyz/import_to_dynamodb.git
cloneしたディレクトリのルートにインポートするcsvファイルを置く
import用shellコマンドの作成
python create_insert_command.py importdata testtable
※第一引数にcsv名(拡張子は記載しない) 第二引数にテーブル名作成されたシェルコマンドの実行
sh ./testtable_import_20200808164839.sh
上記手順で完了です。
- 投稿日:2020-08-08T12:47:08+09:00
AWSとAzureの比較(リージョン・AZ)
※個人の調査によるものです。誤りがあればご指摘ください
※2020/8/8現在の情報をもとにまとめました。AWSとAzureのリージョンなどの考え方を比較しました。
AWS
分類レベル 名称 定義 レベル小 データセンター 1つの物理的なデータセンター レベル中 アベイラビリティゾーン (AZ) 1 つの AWS リージョン内でそれぞれ切り離され、冗長的な電力源、ネットワーク、そして接続機能を備えている 1 つ以上のデータセンターのことです。各 AZ はそれぞれ他の AZ から物理的に意味のある距離、つまり数キロメートル離れていますが、すべて 100 km 以内 (互いに 60 マイル) に配置されています。 レベル大 リージョン 1 つの地理的エリアにある、複数の、それぞれが隔離され物理的にも分離された AZ によって構成されています。1 つのデータセンターを 1 つのリージョンとして定義することが多い他のクラウドプロバイダーとは違い、全 AWS リージョンが採用するこのマルチ AZ デザインは、お客様にいくつかのメリットをご提供するものです。 大阪ローカルリージョンは特殊で、
- 分離された耐障害性の高いインフラストラクチャデザインが 1 つのデータセンター内で構成されます。
- アジアパシフィック (大阪) ローカルリージョンは 1 つのアベイラビリティーゾーンで構成されており、アジアパシフィック (東京) リージョンと組み合わせて使用することが意図されています。
- このリージョンには、お客様のセールス担当者からのリクエストが必要です。
とのこと。
他にはLocal Zonesというものがあるようです。現在はロサンゼルスのみで提供されています。
https://aws.amazon.com/jp/about-aws/global-infrastructure/
https://aws.amazon.com/jp/about-aws/global-infrastructure/regional-product-services/
https://aws.amazon.com/jp/about-aws/global-infrastructure/regional-product-services/Azure
分類レベル 名称 定義 小 Azure データセンター ネットワークに接続されたコンピューター サーバーのグループを収容する、世界中に存在する一意の物理的な建物です。 中 Azure Availability Zones Azure リージョン内の一意の物理的な場所であり、データセンターの障害からアプリケーションとデータを保護する高可用性を提供しています。それぞれのゾーンは、独立した電源、冷却手段、ネットワークを備えた 1 つまたは複数のデータセンターで構成されています。 大 Azure リージョン Azure リージョンは、待機時間で定義された境界内でデプロイされ、低遅延の専用リージョン ネットワークを使用して接続された一連のデータセンターです。 特大 Azure 地域 通常、1 つ以上のリージョンを含み、データ所在地とコンプライアンスの境界を保持します。 AWSにはない、「地域」というものが出てきました。リージョンも地域のような気もしますが、英語名はAzure リージョンがAzure regionで、Azure 地域がAzure geographyです。
東日本リージョンと西日本リージョンはペアに指定されているようで、このAzure 地域に該当するようです。ペアになっているリージョンのメリットとしては、以下が上げらててました
* 物理的な分離
* プラットフォームに備わっているレプリケーション
* リージョン復旧順序
* 順次更新
* データ所在地https://azure.microsoft.com/ja-jp/global-infrastructure/
https://azure.microsoft.com/ja-jp/global-infrastructure/geographies/#geographies
https://docs.microsoft.com/ja-jp/azure/best-practices-availability-paired-regions日本国内リージョンの比較
比較項目 AWS東京リージョン AWS大阪ローカルリージョン Azure東日本リージョン Azure西日本リージョン 開設時期 2011年 2018年 2014年 2014年 AZ数 4 1 3 1 調べていると、AWS東京リージョンに4つ目のリージョンが開設されたのが、2018年、Azure東日本リージョンがAZに対応したのが2019年のようです。この間はAWS東京リージョンが4AZ、Azure東日本リージョンが1AZとかなりの差があったような形ですね。
また、AWS大阪ローカルリージョンは2021年初頭までに3つのAZをもつフルリージョンになるようです。https://aws.amazon.com/jp/blogs/news/the-fourth-new-availability-zone-tokyo-region/
https://azure.microsoft.com/ja-jp/updates/general-availability-azure-availability-zones-in-japan-east/
https://aws.amazon.com/jp/blogs/news/in-the-works-aws-osaka-local-region-expansion-to-full-region/まとめ
AWS側のほうが知識があるので、AWS押しのような内容となりましたが、Azure側の押しポイントがあれば教えて下さい。
- 投稿日:2020-08-08T10:37:24+09:00
AWSサーバレス環境でSPARQLエンドポイントを作ろうとしたが上手くいかなかった話
個人的にSPARQLエンドポイントを作るときに、運用やメンテナンスが楽になればということでサーバレスでSPARQLエンドポイント作れないかと思い、AWSのサーバレス環境での構築に挑戦してみました。
結論から言うと、ちゃんと動きましたが、期待してたよりもうまくいきませんでした。
一応今回使ったコードは以下で公開していますが、利用される場合は以下を最後まで読まれることをお勧めします。
https://github.com/uedayou/quadstore-server-on-aws-serverless
環境
Lambda と API Gateway はAWS SAMでデプロイするようにしました。
サーバレス環境の設定をあらかじめ指定しておけるのでデプロイが楽ですし、ある程度の設定もコード上で細かく変更できていいですね。SPARQLエンドポイントサーバ自体のコードは、node-quadstore と levelDB を使いました。
あらかじめRDFファイルを使ってlevelDBファイルを生成しておき、それを利用してSPARQLクエリで検索結果を得るような形です。
cd quadstore-server-on-aws-serverless/quadstore-server-lambda npm install npm run build:db -- ../sample/isillod.ttlパフォーマンス
この環境でどれくらい使えるか、トリプル数と以下の3つのクエリ毎の検索時間を計ってみました。
Lambdaのメモリは1024MB、タイムアウトは30秒(API Gatewayが30秒でタイムアウトするため)で設定しています。
データセットは「図書館及び関連組織のための国際標準識別子(ISIL)」試行版LODを使いました。
上記サイトでは Turtleファイルを分割して公開しています。これらを1つずつ追加して作成したDBファイル毎に計測しています。(1) トリプルを100件取得
select * where {?s ?p ?o} limit 100(2) 全トリプル数を取得
select (count(*) as ?count) where {?s ?p ?o}(3)
filter
を使って文字列の絞り込みprefix schema: <http://schema.org/> prefix org: <http://www.w3.org/ns/org#> prefix dbpedia: <http://dbpedia.org/ontology/> select * where { ?uri dbpedia:originalName ?name; org:hasSite/org:siteAddress/schema:addressRegion ?pref. filter( regex(?pref, "東京") ) } limit 10
トリプル数 (1) (2) (3) 21,788 0.192 秒 2.85 秒 5.20 秒 42,585 0.186 秒 4.35 秒 7.53 秒 63,448 0.193 秒 5.58 秒 11.08 秒 84,587 0.181 秒 9.74 秒 14.02 秒 104,826 0.163 秒 11.47 秒 16.19 秒 124,718 0.225 秒 14.19 秒 21.83 秒 144,669 0.244 秒 12.64 秒 12.11 秒 160,491 0.220 秒 12.91 秒 12.91 秒 若干ゆれがありますが、概ねトリプル数の増加とともに検索時間が増えてますが、(2)、(3) はその増え方がかなり大きく、トリプル数取得するだけで10秒もかかるのはどうかと思いました。API Gatewayの仕様で30秒でタイムアウトするので、これ以上のトリプル数だと結果が得られずタイムアウトする可能性が高いです。
どうやら全スキャンがかかるようなクエリの実行のより多くの時間がかかっているっぽい感じがします。例えば、(1) に
order by
追加するだけで極端に時間がかかるようになりました。ちなみに、Lambdaはメモリサイズを増やすとCPUの性能もアップするらしいですが、最大の3008MBにしても大きな差はなかったです。個人的な用途でいろいろ目をつぶるにしても、10万トリプルぐらいが限界かなと思います。
実際にその遅さを体感したい人がいれば、
鉄道駅LODのSPARQLエンドポイントを実験的に公開しました
https://qiita.com/uedayou/items/3ba823c5d3bede12af9cこちらを使ってみてください。
30万トリプル登録していますが、複雑なクエリはタイムアウトしてしまいます。まとめ
- (個人的には)SPARQLエンドポイント構築は簡単になった
- ちゃんとSPARQLで検索ができる
- トリプル数とクエリによっては実行が遅い、最悪タイムアウトする
- トリプル数が少ないデータセットなら一応運用は可能
今回使っているRDFストアnode-quadstoreの開発中のブランチを見てみるとSPARQLクエリ実行の高速化も現在対応しているっぽい?ので、将来的に結構使えるものになるかもしれません。ちょっとこの方法を試すには時期が早かったのかも...
今後この方法とは違う方法でも、AWSサーバレスでSPARQLエンドポイント構築挑戦してみたいと思います。
- 投稿日:2020-08-08T02:58:51+09:00
【AWS】Cross-Account CICD
要件(ソースアカウント)
IAM
CodePipeline用IAM RoleはターゲットアカウントのCodeBuildとCodeDeployのIAM RoleをAssumeできる必要がある。
S3
Bucket PolicyはターゲットアカウントのRootを許可する。
KMS
ソースアカウントでCMKを作成し、ターゲットアカウントのRootを許可する。
CodeCommit
通常通りに作成する。
EventBridge
CodeCommitのRepositoryの特定のBranchが作成または更新した際に、CodePipelineを起動する。
Events: Type: AWS::Events::Rule Properties: EventBusName: default EventPattern: source: - aws.codecommit detail-type: - CodeCommit Repository State Change resources: - !Sub arn:aws:codecommit:ap-northeast-1:${AWS::AccountId}:${CodeCommitRepositoryName} detail: event: - referenceCreated - referenceUpdated referenceType: - branch referenceName: - !Ref RepositoryBranch repositoryName: - !Ref CodeCommitRepositoryName State: ENABLED Targets: - Arn: !Sub arn:aws:codepipeline:ap-northeast-1:${AWS::AccountId}:${CodePipeline} RoleArn: !ImportValue EventsInvokePipelineRole Id: "Pipeline"CodePipeline
CodeCommit、CodeBuild、CodeDeployのActionを設定する。
注意点として以下2つがある。
- 使用するKMS KeyはソースアカウントのCMKとする
- CodeBuildとCodeDeployにはIAMを設定し、ターゲットアカウントのCodeBuildとCodeDeployのIAM Roleを指定する
CodePipeline: Type: AWS::CodePipeline::Pipeline Properties: ArtifactStore: Type: S3 Location: !Ref S3Bucket EncryptionKey: Id: !Sub arn:aws:kms:ap-northeast-1:${AWS::AccountId}:key/${KmsId} Type: KMS RestartExecutionOnUpdate: False RoleArn: !ImportValue CodePipelineRole Stages: - Name: Source Actions: - Name: Source ActionTypeId: Category: Source Owner: AWS Version: "1" Provider: CodeCommit OutputArtifacts: - Name: PreBuild_SourceCode Configuration: RepositoryName: !Ref CodeCommitRepositoryName BranchName: !Ref RepositoryBranch PollForSourceChanges: "false" RunOrder: 1 - Name: Build Actions: - Name: Build ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" RunOrder: 1 RoleArn: !Sub arn:aws:iam::${ProdAccount}:role/CrossAccountPipelineRole Configuration: ProjectName: !Ref CodeBuildProjectName PrimarySource: PreBuild_SourceCode InputArtifacts: - Name: PreBuild_SourceCode OutputArtifacts: - Name: PostCodeBuild_Artifact - Name: Deploy Actions: - Name: Deploy ActionTypeId: Category: Deploy Owner: AWS Provider: CodeDeployToECS Version: "1" Configuration: TaskDefinitionTemplateArtifact: PostCodeBuild_Artifact AppSpecTemplateArtifact: PostCodeBuild_Artifact AppSpecTemplatePath: "appspec.yaml" ApplicationName: !Ref CodeDeployApplicationName DeploymentGroupName: DeploymentGroup Image1ArtifactName: PostCodeBuild_Artifact Image1ContainerName: "IMAGE1_NAME" RunOrder: 1 RoleArn: !Sub arn:aws:iam::${ProdAccount}:role/CrossAccountPipelineRole InputArtifacts: - Name: PostCodeBuild_Artifact要件(ターゲットアカウント)
IAM
CodeBuildとCodeDeploy用のIAMはソースアカウントのRootからのAssumeを許可する必要がある。
CodeBuildとCodeDeploy用のIAM RoleにソースアカウントのCMKとS3の関連権限を設定する。CodeBuild
通常通りに作成する。
TaskDefinitionのIamgeを更新の都度バージョン番号を記載しないよう、buildspec.ymlとtaskdef.jsonを以下のように記載する。buildspec.ymlversion: 0.2 phases: pre_build: commands: - echo Logging in to Amazon ECR... - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) build: commands: - echo build - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG . - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on `date` - echo Pushing the Docker image... - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG - printf '{"Version":"1.0","ImageURI":"%s"}' $AWS_ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json artifacts: files: - imageDetail.json - appspec.yaml - taskdef.jsontaskdef.json{ "family": "JavaHelloWorld", "networkMode": "awsvpc", "containerDefinitions": [{ "name": "ecs-test-codecommit-repository", "image": "<IMAGE1_NAME>", "portMappings": [{ "containerPort": 8080, "hostPort": 8080, "protocol": "tcp" }], "essential": true }], "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "executionRoleArn": "arn:aws:iam::<AccountId>:role/ecsTaskExecutionRole" }CodeDeploy
CloudFormationはECSのBlue/GreenのDeploymentGroupを作成できないため、Custom Resourceで作成する。
LambdaCodeDeploy: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import json import boto3 import cfnresponse def lambda_handler(event, context): print(event) if event['RequestType'] == 'Delete' or event['RequestType'] == 'Update' : responseData = {} responseData['Data'] = 'test' cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID") client = boto3.client('codedeploy') applicationName = event['ResourceProperties']['applicationName'] deploymentGroupName = event['ResourceProperties']['deploymentGroupName'] serviceRoleArn = event['ResourceProperties']['serviceRoleArn'] targetGroups1 = event['ResourceProperties']['targetGroups1'] targetGroups2 = event['ResourceProperties']['targetGroups2'] listenerArns = event['ResourceProperties']['listenerArns'] serviceName = event['ResourceProperties']['serviceName'] clusterName = event['ResourceProperties']['clusterName'] response = client.create_deployment_group( applicationName=applicationName, deploymentGroupName=deploymentGroupName, serviceRoleArn=serviceRoleArn, autoRollbackConfiguration={ 'enabled': True, 'events': ['DEPLOYMENT_FAILURE'] }, deploymentStyle={ 'deploymentType': 'BLUE_GREEN', 'deploymentOption': 'WITH_TRAFFIC_CONTROL' }, blueGreenDeploymentConfiguration={ 'terminateBlueInstancesOnDeploymentSuccess': { 'action': 'TERMINATE', 'terminationWaitTimeInMinutes': 5 }, 'deploymentReadyOption': { 'actionOnTimeout': 'CONTINUE_DEPLOYMENT', 'waitTimeInMinutes': 0 } }, loadBalancerInfo={ 'targetGroupPairInfoList': [ { 'targetGroups': [ { 'name': targetGroups1 }, { 'name': targetGroups2 } ], 'prodTrafficRoute': { 'listenerArns': [ listenerArns, ] } }, ] }, ecsServices=[ { 'serviceName': serviceName, 'clusterName': clusterName }, ] ) cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "CustomResourcePhysicalID") Handler: index.lambda_handler Runtime: python3.7 Timeout: 30 Role: !ImportValue LambdaExecutionRole CreateCodeDeployGroup: Type: Custom::LambdaCallout Properties: ServiceToken: !GetAtt LambdaCodeDeploy.Arn applicationName: !Ref CodeDeploy deploymentGroupName: DeploymentGroup serviceRoleArn: !ImportValue CodeDeployRole targetGroups1: !ImportValue targetgroup1-name targetGroups2: !ImportValue targetgroup2-name listenerArns: !ImportValue listener1-arn serviceName: !ImportValue ecs-servicename clusterName: !ImportValue ecs-clusternameappspec.yamlのTaskDefinitionは以下のように記載する。
appspec.yamlversion: 0.0 Resources: - TargetService: Type: AWS::ECS::Service Properties: TaskDefinition: "<TASK_DEFINITION>" LoadBalancerInfo: ContainerName: "ecs-test-codecommit-repository" ContainerPort: 8080 PlatformVersion: "LATEST"ECS + ELB
通常通りに作成する。
- 投稿日:2020-08-08T00:07:07+09:00
EC2 Amazon Linux 2 + nginx で Laravel の環境構築の際によく使うコマンド
yumアップデート
sudo yum update -ynginxのインストール
sudo amazon-linux-extras install nginx1.12 -y // nginxの起動 sudo systemctl start nginx // 自動起動設定(これをやっておくとEC2再起動などの際に自動で起動してくれる) sudo systemctl enable nginx // nginxのステータス確認(起動失敗時などに調査で使用する) systemctl status nginx.servicePHPのインストール
sudo amazon-linux-extras install php7.3 // Laravelを動かすためには php-xmlとphp-mbstringが必要 sudo yum install php-xml php-mbstringComposerのインストール
sudo curl -sS https://getcomposer.org/installer | php // パスを通す sudo mv composer.phar /usr/local/bin/composerLaravelのインストール
// インストール先のディレクトリに権限を付与する sudo chmod -R 777 /usr/share/nginx/html cd /usr.share/nginx/html composer create-project --prefer-dist laravel/laravel app_nameLaravelのセットアップ
cd app_name cp .env.example .envphp artisan コマンドを使えるようにする
composer install