├── .github ├── auto_assign.yml ├── pull_request_template.md └── workflows │ ├── assign-reviewers.yml │ ├── deploy.yml │ ├── review.yaml │ └── test-deploy.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── blog ├── 2022-08-03-jekyll-cloudwatch-rum │ ├── app-monitor-01.png │ ├── app-monitor-02.png │ ├── app-monitor-03.png │ ├── app-monitor-04.png │ ├── app-monitor-05.png │ └── index.md ├── 2022-08-04-cdk-static-website │ └── index.md ├── 2022-08-10-simple-nft-marketplace │ ├── index.md │ ├── web01.png │ ├── web02.png │ ├── web03.png │ ├── web04.png │ ├── web05.png │ ├── web06.png │ ├── web07.png │ ├── web08.png │ ├── web09.png │ └── web10.png ├── 2022-09-16-cloudwatch-rum-stats │ ├── index.md │ ├── insights.png │ └── overview.png ├── 2022-10-03-closed-serverless-app │ ├── arch.png │ ├── background.png │ └── index.md ├── 2022-10-20-cdk-notices │ └── index.md ├── 2022-12-02-react-3dmol │ ├── 3dmol.png │ └── index.md ├── 2022-12-05-codebuild-concurrency │ └── index.md ├── 2022-12-05-jenkins-ec2 │ └── index.md ├── 2022-12-21-rails-lambda │ ├── alb_architecture.png │ ├── apigw_architecture.png │ ├── index.md │ ├── rails_lambda.png │ └── rails_puma.png ├── 2023-01-05-fluentd-kds │ ├── arch.png │ ├── buf.png │ └── index.md ├── 2023-01-20-identity-pool-unauth │ └── index.md ├── 2023-01-23-cdk-deploy-cloudshell-cloud9 │ └── index.md ├── 2023-02-01-ec2-mac-instances │ ├── ard.jpg │ ├── dedicated-hosts.png │ ├── index.md │ └── quota.png ├── 2023-02-08-lex-kendra-dev │ └── index.md ├── 2023-02-20-primary-eni-with-cdk │ └── index.md ├── 2023-03-02-lambda-web-adapter-with-prisma │ ├── architecture.png │ └── index.md ├── 2023-03-06-openai-discord-bot │ ├── architecture.png │ ├── bot-demo.png │ ├── bot-profile.png │ ├── cloudwatch-log.png │ └── index.md ├── 2023-03-22-eks-gpu-time-slicing │ └── index.md ├── 2023-03-23-clean-cdk-resources │ └── index.md ├── 2023-03-24-amazon-eks-gpu-ami │ └── index.md ├── 2023-03-28-redshift-to-dynamo-glue │ └── index.md ├── 2023-04-18-lambda-cr-trigger-update │ └── index.md ├── 2023-04-27-vue3-typescript │ ├── application.png │ └── index.md ├── 2023-05-16-kendra-s3-access-control │ └── index.md ├── 2023-06-01-transcribe-in-react │ └── index.md ├── 2023-06-20-ec2-cloudwatchlogs-al2023 │ └── index.md ├── 2023-06-21-preview-service-apiloader │ └── index.md ├── 2023-07-10-ec2-proto-env │ └── index.md ├── 2023-07-13-snapstart-any-langs │ └── index.md ├── 2023-08-17-cdk-aurora-migration │ └── index.md ├── 2023-09-20-aws-healthomics-analysis-app │ ├── analysis_outputs.png │ ├── analysis_tasks.png │ ├── architecture.png │ ├── index.md │ ├── new_analysis_confirmation.png │ ├── new_analysis_parameters.png │ ├── new_analysis_settings.png │ └── stepfunctions.png ├── 2023-10-25-aws-healthomics-analysis-app-alphafold │ ├── analysis_3dmol.png │ ├── index.md │ ├── new_analysis_confirmation.png │ ├── new_analysis_parameters.png │ ├── new_analysis_settings.png │ └── stepfunctions.png ├── 2023-11-15-claude-prompt-engineering-put-on-her-mouth │ └── index.md ├── 2023-11-27-amplify-v6-migration │ └── index.md ├── 2023-12-22-amazon-cognito-with-x-for-web3auth │ ├── Architecture.png │ ├── flow.png │ └── index.md └── authors.yml ├── docs └── dummy.md ├── docusaurus.config.js ├── package-lock.json ├── package.json ├── plugins └── get-recent-posts │ └── index.js ├── sidebars.js ├── src ├── components │ ├── Recommends │ │ ├── index.js │ │ └── styles.module.css │ ├── Search │ │ ├── cloud.jpg │ │ ├── index.js │ │ └── styles.module.css │ └── ShareButtons │ │ ├── index.js │ │ └── index.module.css ├── css │ └── custom.css ├── pages │ ├── about-team │ │ ├── index.mdx │ │ ├── proto-career.png │ │ └── proto-teams.png │ ├── index.js │ ├── index.module.css │ └── program │ │ ├── analytics.png │ │ ├── cloud-native.png │ │ ├── container.png │ │ ├── devops.png │ │ ├── index.js │ │ ├── logo.png │ │ └── styles.module.css └── theme │ └── BlogPostItem │ ├── Footer │ └── index.js │ └── Header │ └── Info │ └── index.js └── static ├── .nojekyll ├── img ├── docusaurus.png ├── favicon.ico ├── logo.png ├── logo.svg ├── undraw_docusaurus_mountain.svg ├── undraw_docusaurus_react.svg └── undraw_docusaurus_tree.svg ├── js ├── rum-dev.js └── rum-prod.js └── robots.txt /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # Set to true to add reviewers to pull requests 2 | addReviewers: true 3 | 4 | # Set to true to add assignees to pull requests 5 | addAssignees: author 6 | 7 | # A list of reviewers to be added to pull requests (GitHub user name) 8 | reviewers: 9 | - tbrand 10 | - kudtomoy 11 | - Yukinobu-Mine 12 | 13 | # A number of reviewers added to the pull request 14 | # Set 0 to add all the reviewers (default: 0) 15 | numberOfReviewers: 1 16 | # A list of assignees, overrides reviewers if set 17 | # assignees: 18 | # - assigneeA 19 | 20 | # A number of assignees to add to the pull request 21 | # Set to 0 to add all of the assignees. 22 | # Uses numberOfReviewers if unset. 23 | # numberOfAssignees: 2 24 | 25 | # A list of keywords to be skipped the process that add reviewers if pull requests include it 26 | # dna = Do NOT Assign 27 | skipKeywords: 28 | - wip 29 | - dna 30 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request 2 | 3 | - デフォルトではランダムで reviewer がアサインされます。手動でアサインする場合は Pull Request のタイトルに "DNA" = Do Not Assign を付与してください。(#30) 4 | - **Merge は reviewer が LGTM を出したタイミングで行ってください!** 5 | 6 | ## 新規記事のチェックリスト 7 | 8 | 新規記事の Pull Request でない場合はスキップして問題ありません。 9 | 10 | - [ ] カスタマーの情報を含んでいないかチェック 11 | - [ ] 記事に Header の追加 (title, slug, tags, authors) 12 | - [ ] 記事に `` の挿入 13 | - [ ] 手元で動作確認 14 | -------------------------------------------------------------------------------- /.github/workflows/assign-reviewers.yml: -------------------------------------------------------------------------------- 1 | name: 'Auto Assign' 2 | on: 3 | pull_request: 4 | types: [opened, ready_for_review] 5 | 6 | jobs: 7 | add-reviews: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: kentaro-m/auto-assign-action@v1.2.4 11 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | name: Deploy to GitHub Pages 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 18 17 | 18 | - name: Install dependencies 19 | run: npm ci 20 | - name: Build website 21 | run: npm run build 22 | - name: Deploy to GitHub Pages 23 | uses: peaceiris/actions-gh-pages@v3 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: ./build 27 | cname: prototyping-blog.com 28 | -------------------------------------------------------------------------------- /.github/workflows/review.yaml: -------------------------------------------------------------------------------- 1 | name: Automated review 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | id-token: write # This is required for requesting the JWT 7 | 8 | on: 9 | pull_request_target: 10 | types: [opened, reopened] 11 | pull_request_review_comment: 12 | types: [created] 13 | 14 | 15 | concurrency: 16 | group: 17 | ${{ github.repository }}-${{ github.event.number || github.head_ref || 18 | github.sha }}-${{ github.workflow }}-${{ github.event_name == 19 | 'pull_request_review_comment' && 'pr_comment' || 'pr' }} 20 | cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }} 21 | 22 | 23 | env: 24 | TARGET_AWS_REGION: us-east-1 25 | jobs: 26 | Run-Bedrock-review: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: configure aws credentials 30 | uses: aws-actions/configure-aws-credentials@v4 31 | with: 32 | role-to-assume: ${{ secrets.AWS_ROLE_ARN }} 33 | role-session-name: gha-session 34 | aws-region: ${{ env.TARGET_AWS_REGION }} 35 | - name: PR review 36 | uses: tmokmss/bedrock-pr-reviewer@main 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | with: 40 | debug: true 41 | language: ja-JP 42 | review_simple_changes: true 43 | review_comment_lgtm: true 44 | only_allow_collaborator: true 45 | path_filters: | 46 | **/*.md 47 | summarize_release_notes: | 48 | 提出されたブログ記事を読んで、100文字程度に内容を要約してください。要約はソフトウェアエンジニアが読んで分かりやすいものにしてください。 49 | 入力された内容にブログ記事が含まれていない場合は、簡単に入力された内容をまとめてください。 50 | review_file_diff: | 51 | あなたはエンジニア向けブログ記事の編集者です。記事の原稿が入力されるので、以下の観点でレビューをしてください。 52 | - 分かりやすい日本語か 53 | - 誤解の余地がある表現がないか 54 | - 技術的な誤りを含んでいないか 55 | - より良くできるポイントはないか 56 | どんな些細な点でも構わないので、気になる点があれば指摘してください。 57 | -------------------------------------------------------------------------------- /.github/workflows/test-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test deployment 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test-deploy: 10 | name: Test deployment 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 18 17 | 18 | - name: Install dependencies 19 | run: npm ci 20 | - name: Test build website 21 | run: npm run build 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS JP Prototyping Blog 2 | 3 | [![Website](https://img.shields.io/badge/AWS%20Prototyping%20Blog-Website-blue)](https://aws-samples.github.io/jp-prototyping-blog/) 4 | [![Deploy to GitHub Pages](https://github.com/aws-samples/jp-prototyping-blog/actions/workflows/deploy.yml/badge.svg)](https://github.com/aws-samples/jp-prototyping-blog/actions/workflows/deploy.yml) 5 | 6 | AWS JP Prototyping チームが日々の知見を蓄積するブログです。 7 | 8 | ## ご指摘・ご質問 9 | 10 | 記事の内容に関するご指摘・ご質問は大歓迎です。[Issue](https://github.com/aws-samples/jp-prototyping-blog/issues) にてお待ちしております。 11 | 12 | ## 記事の書き方 (Prototyping チーム用) 13 | 14 | 1. `/blog` ディレクトリに、`YYYY-MM-DD-` の命名規則でディレクトリを作成してください。`` は各記事の Identifier に置き換えてください。 15 | 1. 作成したディレクトリ内に index.md を作成してください。記事本体を表すファイルです。 16 | 1. 記事の先頭には `title` `slug` `tags` `authors` を含んだ Header を追加しください。Header の書き方は既存の記事を参考にしてください。`/blog/authors.yml` に自分の id がない場合は追加してください。 17 | 1. 冒頭には概要を記述し、本文との間に `` を追加してください。本文のボリュームが極端に少ない場合は省略しても構いません。`` 以前の内容がリストで並べた際に表示されます。 18 | 1. 画像はディレクトリ内に適当な命名で配置し、index.md から参照してください。 19 | 1. 書き終わったら Pull Request を作成し、チームにレビューを依頼してください。 20 | 21 | ## 手元で確認する方法 22 | 23 | ```bash 24 | npm install 25 | npm start 26 | ``` 27 | 28 | ## レビューの依頼 29 | 30 | デフォルトではランダムで reviewer がアサインされます。手動でアサインする場合は Pull Request のタイトルに "DNA" (= Do Not Assign) を含めて、手動でアサインしてください。 31 | 32 | ## Security 33 | 34 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 35 | 36 | ## License 37 | 38 | This library is licensed under the MIT-0 License. See the LICENSE file. 39 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-01.png -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-02.png -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-03.png -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-04.png -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-03-jekyll-cloudwatch-rum/app-monitor-05.png -------------------------------------------------------------------------------- /blog/2022-08-03-jekyll-cloudwatch-rum/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Amazon CloudWatch RUM で Jekyll の静的サイトのアクセス解析を行う" 3 | slug: jekyll-cloudwatch-rum 4 | tags: [cloudwatch, rum, jekyll] 5 | authors: [tbrand] 6 | --- 7 | 8 | # 概要 9 | 10 | 本記事では、GitHub Pages で広く利用されている静的サイト作成ツール Jekyll と AWS の Web アプリケーションモニタリングツールである Amazon CloudWatch RUM を組み合わせたアクセス解析可能な静的サイトの構築方法をご紹介いたします。なお、ホスティング方法については触れません。 11 | 12 | 13 | 14 | # Jekyll の準備 15 | 16 | 基本的には [Jekyll](http://jekyllrb-ja.github.io/) の公式サイトの手順をなぞる形になります。Jekyll のコマンドラインツールは gem (Ruby のライブラリ形式) で公開されていますので、手元の環境に Ruby が必要だということに注意してください。以下のコマンドを実行して、`jekyll` コマンドをインストールし、`hello-rum` というサイトを作成します。 17 | ```bash 18 | gem install bundler jekyll 19 | jekyll new hello-rum 20 | cd hello-rum 21 | ``` 22 | 23 | 公式の手順では次に `bundle exec jekyll serve` を実行していますが、筆者の手元の環境では `webrick` という gem が必要だというエラーが出ました。同様のエラーに遭遇した場合、Gemfile に以下の一文を追加してください。 24 | ```ruby 25 | source "https://rubygems.org" 26 | 27 | ...省略... 28 | 29 | # 末尾にこれを追加 30 | gem "webrick" 31 | ``` 32 | 33 | 最後に、以下のコマンドを実行して serve を開始します。 34 | ```bash 35 | bundle install 36 | bundle exec jekyll serve 37 | ``` 38 | 39 | [http://localhost:4000](http://localhost:4000) にアクセスし、正常に表示されていることを確認してください。 40 | 41 | # Amazon CloudWatch RUM による App monitor の作成 42 | 43 | [Amazon CloudWatch RUM](https://console.aws.amazon.com/cloudwatch/home#rum:dashboard?tab=overview) にアクセスし、右上の「Add app monitor」をクリックして App monitor の作成を開始します。 44 | 45 | App monitor 名は「hello-rum」にします。Application domain は検証目的のため「localhost」にします。 46 | 47 | ![App monitor 01](./app-monitor-01.png) 48 | 49 | 集めるデータには全てチェックを入れます。不必要なものがある場合はチェックを外しても問題ありません。 50 | 51 | ![App monitor 02](./app-monitor-02.png) 52 | 53 | 「Allow cookies」のチェックは外しました。チェックを入れた場合は、cookie を設定してユーザーの動向を追跡できます。「Session samples」は 100% にします。「Data Storage」は有効にしました。これにより、CloudWatch Logs でデータを集計できるようになります。 54 | 55 | ![App monitor 03](./app-monitor-03.png) 56 | 57 | 作成が完了すると、組み込み用の Snippet が表示されます。TypeScript、JavaScript、HTML が選択できますが、Jekyll 用に「HTML」を選択します。右上から Snippet をコピーしてください。 58 | 59 | ![App monitor 04](./app-monitor-04.png) 60 | 61 | # Jekyll に App monitor を組み込む 62 | 63 | jekyll (バージョン 4.2.2) ではデフォルトで [minima](https://github.com/jekyll/minima) というテーマが適応されています。Snippet を組み込む `` タグを上書きするため、`hello-rum` ディレクトリに `_includes` ディレクトリを作成し、その中に `head.html` を作成します。`head.html` の内容は以下にします。`` は Snippet に置き換えてください。 64 | ```html 65 | 66 | 67 | 68 | 69 | {%- seo -%} 70 | 71 | {%- feed_meta -%} 72 | 73 | 74 | 75 | ``` 76 | 77 | 上のコードはほとんど [minima の `_includes/head.html`](https://github.com/jekyll/minima/blob/master/_includes/head.html) の内容ですが、下部に App monitor のスニペットを組み込みます。また、minima のバージョンによっては [`_includes/custom-head.html`](https://github.com/jekyll/minima/blob/master/_includes/custom-head.html) も利用可能なようなので、そちらにスニペットを貼り付けても良いかもしれません。 78 | 79 | [http://localhost:4000](http://localhost:4000) を何度かリロードしたり記事を閲覧したりして App monitor のダッシュボードにデータが表示されることを確認してください。成功していると以下のようにデータが表示されます。 80 | 81 | ![App monitor 05](./app-monitor-05.png) 82 | 83 | # Production 環境への組み込み 84 | 85 | 前述した App monitor は localhost に設定した開発用のものでした。本番用の App monitor も組み込んでみます。前述した手順と同様に App monitor を作成してください。App monitor 名は「hello-rum-prod」にして、Application domain は本番環境で使うドメインに設定します。GitHub Pages の場合「`.github.io`」になります。他の設定は同じで問題ありません。Snippet はコピーしておいてください。 86 | 87 | 続いて、`head.html` を以下のように編集します。本番環境か否かを `{% if jekyll.environment == "development" %}` で判断しています。 88 | ```html 89 | 90 | 91 | 92 | 93 | {%- seo -%} 94 | 95 | {%- feed_meta -%} 96 | 97 | {% if jekyll.environment == "development" %} 98 | 99 | {% else %} 100 | 101 | {% endif %} 102 | 103 | ``` 104 | 105 | 本番環境にデプロイしたあと、正常にデータが受信できることを確認してください。以上で全ての設定が完了です! 106 | 107 | # おわりに 108 | 109 | 本記事では Jekyll で作成した静的サイトに Amazon CloudWatch RUM を組み込む手順を紹介しました。Amazon CloudWatch RUM ではページごとのアクセス状況やデバイス種別などのデータが解析可能ですし、CloudWatch Logs と連携させることにより、柔軟な集計を行うことも可能です。また、今回は Jekyll への組み込みを行いましたが、React や Vue.js などの SPA にも組み込むことは可能ですので、ぜひ一度お試しください。 110 | -------------------------------------------------------------------------------- /blog/2022-08-04-cdk-static-website/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "AWS CDK で静的サイトをデプロイする (CloudFront + S3 + CF2)" 3 | slug: cdk-static-website 4 | tags: [cdk, cloudfront, s3] 5 | authors: [kudtomoy] 6 | --- 7 | 8 | ## はじめに 9 | 静的 Web サイトを AWS CDK を使い、CloudFront + S3 の構成でデプロイ方法について説明します。この組み合わせは定番なのでいろいろな所で紹介されていますが、 10 | 情報が古くなってしまっているものもあるため2022年8月の時点で良さそうだと思った作り方を紹介します。 11 | 12 | CDK アプリのソースコード全体は [GitHub](https://github.com/kudtomoy/aws-cdk-samples/tree/main/static-website) で公開しています。この記事では、今回の CDK アプリの書き方のポイントや理由について説明していきます。 13 | 14 | 15 | 16 | 使用した Node.js と CDK のバージョンは以下になります: 17 | ```bash 18 | $ node --version 19 | v16.14.0 20 | 21 | $ cdk --version 22 | 2.28.1 (build d035432) 23 | ``` 24 | 25 | ## ホストゾーンと証明書の情報を Parameter Store から取得する 26 | ```typescript 27 | const recordName = ssm.StringParameter.valueFromLookup( 28 | this, 29 | '/static-website/record-name' 30 | ) 31 | const domainName = ssm.StringParameter.valueFromLookup( 32 | this, 33 | '/static-website/domain-name' 34 | ) 35 | const certificateArn = ssm.StringParameter.valueFromLookup( 36 | this, 37 | '/static-website/certificate-arn' 38 | ) 39 | ``` 40 | 41 | AWS マネジメントコンソール上で Amazon Route53 のホストゾーンと AWS Certificate Manager (ACM) の証明書をあらかじめ作成しておき、それらの情報を AWS Systems Manager の Parameter Store に保存して、テンプレート生成時に読み込んでいます。 42 | 43 | 今回 CDK でホストゾーンや証明書を管理しなかった理由は以下です: 44 | - ドメインの取得や移管には手作業が発生するし、何度も繰り返す作業ではない 45 | - Amazon CloudFront で ACM の証明書を使用するには証明書が `us-east-1` リージョンで発行されている必要があり、クロススタック参照になって手間が増える 46 | 47 | ACM も CDK で管理したい場合は [AWS CDK(cdk-remote-stack)でACMとCloudFrontのクロスリージョン参照を実装する](https://dev.classmethod.jp/articles/cdk-remote-stack-for-acm-and-cloudfront/) の記事が参考になると思います。 48 | 49 | また ARN 等をソースコードに書きたくなかったので Parameter Store を利用しましたが、ここはお好みでベタ書きしたり、CDK の Context を利用するなどしても良いと思います。Parameter Store を利用する場合は AWS CLI で以下のように値を保存します。 50 | 51 | ```bash 52 | aws ssm put-parameter --type 'String' --name '/static-website/record-name' --value 'sample.com' 53 | aws ssm put-parameter --type 'String' --name '/static-website/domain-name' --value 'sample.com' 54 | aws ssm put-parameter --type 'String' --name '/static-website/certificate-arn' --value 'arn:aws:acm:us-east-1:xxxx:certificate/xxxx' 55 | ``` 56 | 57 | 58 | ## S3 Origin + Origin Access Identity を使用する 59 | ```typescript 60 | const bucket = new s3.Bucket(this, 'Bucket', { 61 | autoDeleteObjects: true, 62 | removalPolicy: RemovalPolicy.DESTROY, 63 | }) 64 | 65 | const originAccessIdentity = new cloudfront.OriginAccessIdentity( 66 | this, 67 | 'OriginAccessIdentity' 68 | ) 69 | 70 | const bucketPolicyStatement = new iam.PolicyStatement({ 71 | actions: ['s3:GetObject'], 72 | effect: iam.Effect.ALLOW, 73 | principals: [ 74 | new iam.CanonicalUserPrincipal( 75 | originAccessIdentity.cloudFrontOriginAccessIdentityS3CanonicalUserId 76 | ), 77 | ], 78 | resources: [`${bucket.bucketArn}/*`], 79 | }) 80 | 81 | bucket.addToResourcePolicy(bucketPolicyStatement) 82 | ``` 83 | CloudFront 経由 で Amazon S3 のデータを配信する方法は2種類あります: 84 | 85 | 1. CloudFront のオリジンに S3 バケットそのものを指定する 86 | 2. CloudFront のオリジンに S3 バケットの Static website hosting のエンドポイントを指定する 87 | 88 | 今回は S3 に直接アクセスされたくなかったので Static website hosting を有効にせず、Origin Access Identity(OAI) を作成して CloudFront からのみアクセスできる1の構成にしました。 89 | 90 | この場合、デフォルトルートオブジェクトのファイル名 (`index.html`) をディストリビューションで指定しているオリジンのルートにしか設定できません。たとえば `https://sample.com/posts/` にアクセスすると `https://sample.com/posts/index.html` は表示されずに403エラーになります。この問題は次の CloudFront Functions で解決します。 91 | 92 | ## CloudFront Functions でファイル名を含まない URL に対応する 93 | ```typescript 94 | const rewriteUrlFunction = new cloudfront.Function( 95 | this, 96 | 'RewriteUrlFunction', 97 | { 98 | functionName: 'rewrite-url', 99 | code: cloudfront.FunctionCode.fromFile({ 100 | filePath: 'functions/rewrite-url/index.js', 101 | }), 102 | } 103 | ) 104 | ``` 105 | 106 | `functions/rewrite-url/index.js` は [公式ドキュメント](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example-function-add-index.html) のコードをそのまま使用しています: 107 | ```js 108 | function handler(event) { 109 | var request = event.request; 110 | var uri = request.uri; 111 | 112 | // Check whether the URI is missing a file name. 113 | if (uri.endsWith('/')) { 114 | request.uri += 'index.html'; 115 | } 116 | // Check whether the URI is missing a file extension. 117 | else if (!uri.includes('.')) { 118 | request.uri += '/index.html'; 119 | } 120 | 121 | return request; 122 | } 123 | 124 | ``` 125 | 126 | ファイル名を含まない URL でアクセスされた時に `index.html` を返せるように CloudFront Functions (CF2) を設定します。CF2 は GA が比較的最近 (2021年5月) だったこともあり、同じことを Lambda@Edge でやっている例がよく紹介されています。 1回あたりの呼び出しは CF2 の方が安くレイテンシも小さいですが、Lambda@Edge は CloudFront のキャッシュにヒットしなかった場合のみ実行できるという利点があり、このあたりの選択はお好みだと思います。 127 | 128 | Lambda@Edge を利用する場合は Lambda を `us-east-1` にデプロイする必要があり、CDK でやろうとするとクロススタック参照をする必要があります。この場合は Experimental ではありますが [EdgeFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.experimental.EdgeFunction.html) を使うとかんたんに書くことができます。 129 | 130 | ## CloudFrontWebDistribution ではなく Distribution API を使用する 131 | ```typescript 132 | const distribution = new cloudfront.Distribution(this, 'Distribution', { 133 | defaultRootObject: 'index.html', 134 | defaultBehavior: { 135 | allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, 136 | cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD, 137 | cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, 138 | viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, 139 | origin: new cloudfrontOrigins.S3Origin(bucket, { 140 | originAccessIdentity, 141 | }), 142 | functionAssociations: [ 143 | { 144 | eventType: cloudfront.FunctionEventType.VIEWER_REQUEST, 145 | function: rewriteUrlFunction, 146 | }, 147 | ], 148 | }, 149 | priceClass: cloudfront.PriceClass.PRICE_CLASS_200, 150 | certificate: acm.Certificate.fromCertificateArn( 151 | this, 152 | 'Certificate', 153 | Lazy.string({ produce: () => certificateArn }) 154 | ), 155 | domainNames: [recordName], 156 | minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021, 157 | }) 158 | ``` 159 | 160 | CDK で CloudFront の Distribution を作成する高レベル Constructs は `CloudFrontWebDistribution` と `Distribution` の2つが用意されていますが、`Distribution` の方が新しく、[ドキュメント](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html)でもこちらの使用が推奨されています。 161 | 162 | > The CloudFrontWebDistribution construct is the original construct written for working with CloudFront distributions. Users are encouraged to use the newer Distribution instead, as it has a simpler interface and receives new features faster. 163 | 164 | 他に、`priceClass` は日本のエッジロケーションを使用したいので `PRICE_CLASS_200` としています。また `certificateArn` を渡すのに `Lazy` を使用しているのは [Issue#8699](https://github.com/aws/aws-cdk/issues/8699) に対応するためです。 165 | 166 | ## BucketDeployment を使ってファイルを S3 にアップロードする 167 | ```typescript 168 | new s3Deployment.BucketDeployment(this, 'BucketDeployment', { 169 | sources: [ 170 | s3Deployment.Source.asset(path.resolve(__dirname, '../web/public')), 171 | ], 172 | destinationBucket: bucket, 173 | distribution: distribution, 174 | distributionPaths: ['/*'], 175 | }) 176 | ``` 177 | [BucketDeployment](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3_deployment.BucketDeployment.html) はローカルのファイルをS3バケットにデプロイします。また、先ほど作成した `Distribution` がこのバケットを Origin とするように設定しています。`../web/public` はデプロイしたいファイルがある場所に合わせて修正して下さい。 178 | 179 | ## IPv4 と IPv6 両方に対応する 180 | ```typescript 181 | const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', { 182 | domainName, 183 | }) 184 | 185 | const propsForRoute53Records = { 186 | zone: hostedZone, 187 | recordName, 188 | target: route53.RecordTarget.fromAlias( 189 | new route53Targets.CloudFrontTarget(destribution) 190 | ), 191 | } 192 | 193 | new route53.ARecord(this, 'ARecord', propsForRoute53Records) 194 | new route53.AaaaRecord(this, 'AaaaRecord', propsForRoute53Records) 195 | ``` 196 | A と AAAA の2つのレコードを追加することで、IPv4 と IPv6 両方に対応しています。 197 | 198 | ## おわりに 199 | 本記事では CDK で 静的ウェブサイトをデプロイする方法についてご紹介しました。CloudFront + S3 の組み合わせでファイル名を含まない URL に対応するためには少し工夫が必要になりますが、CDK であれば管理も簡単なのでおすすめです。 200 | 201 | ## あわせて読みたい 202 | - [CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/) 203 | - [CloudFront FunctionsはLambda@Edgeより安い。それ本当?!](https://dev.classmethod.jp/articles/sometimes-cf2-price-is-higher-than-lae/) 204 | -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "AWS Samples の Simple NFT Marketplace を触ってみた" 3 | slug: simple-nft-marketplace 4 | tags: [nft, blockchain, ethereum] 5 | authors: [tbrand] 6 | --- 7 | 8 | ## 概要 9 | 10 | 本記事では、[github.com/aws-samples/simple-nft-marketplace](https://github.com/aws-samples/simple-nft-marketplace) というサンプルプロジェクトの動作をざっと確認してみたいと思います。Simple NFT Marketplace はその名の通り、シンプルな NFT のマーケットプレイスです。ただし、[OpenSea](https://opensea.io/) のように [MataMask](https://metamask.io/) と連携させた完全な非中央集権的なマーケットプレイスではなく、アカウント登録が必要で、かつ、ウォレットをシステム側で管理するマーケットプレイスです。ただ、ERC-721 の規格に則っていますので、Simple NFT Marketplace で作成した NFT を OpenSea に陳列するといったことも可能です。 11 | 12 | 13 | 14 | ## Simple NFT Marketplace の環境構築について 15 | 16 | 構築方法については [ドキュメント](https://github.com/aws-samples/simple-nft-marketplace/tree/main/docs/ja) をご参照ください。方法は 2 通り存在していて、1 つは deploy.js というスクリプトを利用した簡単な手順、もう一つは Step-by-Step で構築する手順です。**いずれの場合も Ethereum Ropsten の Ethereum が必要です。インターネット上のサービスを活用して、事前にトークンを取得しておいてください。「Ropsten Ethereum Faucet」などで検索すると見つかります。** (Ethereum Ropsten は Ethereum のテストネットです。Simple NFT Marketplace の Contract はデフォルトで Ropsten にデプロイされます。) 17 | 18 | ## 動作確認 19 | 20 | では構築が完了した Simple NFT Marketplace にアクセスしてみます。まず、最初にサインイン/アカウント登録画面が表示されます。 21 | 22 | ![web01](./web01.png) 23 | 24 | 初回なので、アカウントを作成しましょう。 25 | 26 | ![web02](./web02.png) 27 | 28 | アカウント登録が完了 or サインインが完了すると、トップページに遷移します。とてもシンプルな UI ですが、大きく 2 つの機能があることがわかります。1 つは NFT を作成する機能、もう 1 つは NFT を表示する機能です。後者の画面で NFT の売買も可能です。また、右上の Account ページでアカウント情報を確認できます。 29 | 30 | ![web03](./web03.png) 31 | 32 | こちらがアカウントページで表示されている情報です。ユーザー名 (taichirs)、ウォレットの Public Address、Balance (残高) が表示されています。Private Key は下部の Retrieve ボタンを押下すると表示されます。この Private Key は MetaMask などの外部ウォレットに Export することも可能です。また、サインアウトもここから行います。Private Key をユーザーに渡さない用に実装を変更すれば、サービス側で完全にウォレットを管理するということになります。 33 | 34 | ![web04](./web04.png) 35 | 36 | では Create NFT から最初の NFT を作成してみようと思います。Simple NFT Marketplace では、画像を NFT として登録する機能を提供しています。適当な画像をアップロードし、タイトルと説明を記入します。Royalty Percentage は、NFT の発行者に支払われるロイヤリティの設定です。例えばデフォルトの 5 %を設定した場合、NFT が売買されるたびに売買代金の 5 %が発行者に支払われます。ここで言う発行者は、売買する度に変わるオーナーとは別で、最初に NFT を作成したアカウントになります。発行者は NFT 作成後に変更できない仕様です。(変更できるように実装することも可能です。) 一通り入力したら CREATE ボタンを押下してください。暫く待つと、NFT の詳細ページに遷移します。 37 | 38 | ![web05](./web05.png) 39 | 40 | こちらが NFT の詳細ページです。Metadata として Token ID が払い出されています。Token ID は 1 から始まり、NFT が発行されるたびにインクリメントされる仕様です。Owner は今ログイン中のアカウントの Public Address になります。続いて Marketplace の情報です。Listing が false なので、現在この NFT は陳列されてません。(= 売買することができません。) Publisher (発行者) は Owner と同じアカウントで、Royalty は 5 %で設定されています。 41 | 42 | ![web06](./web06.png) 43 | 44 | 下部にスクロールすると、Marketplace と Transfer の機能が使えます。前者は、値段を設定した上で Marketplace に NFT を陳列する機能です。後者は、売買とは別に、NFT を転送する (= Owner を変更する) 機能です。では、Marketplace の機能で、発行した NFT を陳列してみます。適当な Price を入力し、Set price ボタンを押下してください。 45 | 46 | ![web07](./web07.png) 47 | 48 | 陳列が完了すると、Listing が true になり、Price が設定されていることが確認できます。この状態であれば、売買が可能です。 49 | 50 | ![web08](./web08.png) 51 | 52 | この状態で下部にスクロールすると、先程は値段を設定する UI だったところが、今度は陳列を取り下げる機能に変わっています。Remove を押下すると陳列を取り下げます。 53 | 54 | ![web09](./web09.png) 55 | 56 | では、NFT を購入してみます。別のアカウントでログインし、先程発行した NFT の詳細ページを開きます。下部にスクロールすると、Purchase という機能が表示されていると思います。Price を確認して、Purchase ボタンを押下してください。購入が完了すると、自動でページがリロードされます。なお、購入するアカウントの Balance が NFT の値段よりも多いことを事前に確認してください。 57 | 58 | ![web10](./web10.png) 59 | 60 | こちらが購入後の NFT の詳細ページの情報です。ご覧の通り、Owner のアドレスが変更されました。購入直後は陳列から外されるため、Marketplace の Listing は false になります。また前述したとおり、Publisher は変わっていないことを確認してください。 61 | 62 | 以上で売買を含む Simple NFT Marketplace の機能の紹介は終了です! 63 | 64 | ## おわりに 65 | 66 | Simple NFT Marketplace では秘密鍵を DynamoDB で管理しています。AWS KMS を利用すると、システムの運用者ですら秘密鍵を取り出すことができなくなり、よりセキュアです。方法は以下をご参照ください。 67 | 68 | - [How to sign Ethereum EIP-1559 transactions using AWS KMS](https://aws.amazon.com/jp/blogs/database/how-to-sign-ethereum-eip-1559-transactions-using-aws-kms/) 69 | -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web01.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web02.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web03.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web04.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web05.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web06.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web07.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web08.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web09.png -------------------------------------------------------------------------------- /blog/2022-08-10-simple-nft-marketplace/web10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-08-10-simple-nft-marketplace/web10.png -------------------------------------------------------------------------------- /blog/2022-09-16-cloudwatch-rum-stats/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Amazon CloudWatch RUM で月次アクセス数を集計してみた" 3 | slug: cloudwatch-rum-stats 4 | tags: [cloudwatch, rum, stats] 5 | authors: [tbrand] 6 | --- 7 | 8 | ## 概要 9 | 10 | 本記事では、[Amazon CloudWatch RUM](https://console.aws.amazon.com/cloudwatch/home#rum:dashboard?tab=overview) を利用した月次アクセス数の集計方法を実際のコードと合わせて紹介します。 11 | 12 | 13 | 14 | ## Amazon CloudWatch RUM とは 15 | 16 | ![overview](./overview.png) 17 | 18 | Amazon CloudWatch RUM は、Web アプリケーションのモニタリングサービスです。簡単な JavaScript のスニペットをサイトに追加するだけで、ユーザーが使っているブラウザ、アクセス元の地域、パフォーマンスなどを取得し、可視化してくれます。利用方法は極めて簡単で、[Amazon CloudWatch RUM](https://console.aws.amazon.com/cloudwatch/home#rum:dashboard?tab=overview) のページを開き、右上の「Add app monitor」をクリックしてサイト名とドメイン名を入力すれば基本的な設定は完了です。**後述する集計を行う場合は「Data storage」を有効にしてログを出力するようにしてください。**テスト用のローカル環境であれば、ドメインは localhost で構いません。 19 | 20 | 作成するとスニペットが出力されるので、それをサイトに追加しましょう。追加された状態でサイトにアクセスし、Amazon CloudWatch RUM の Overview をご覧ください。「Page loads」などでアクセスが確認できれば正常に設定できています。 21 | 22 | Jekyll で構成されたサイトの場合、次のように設定すれば本番環境と開発環境でスニペットを分けることができます。 23 | 24 | ```html 25 | {% if jekyll.environment == "development" %} 26 | 33 | {% else %} 34 | 41 | {% endif %} 42 | ``` 43 | 44 | ## マネージメントコンソールでの集計テスト 45 | 46 | Amazon CloudWatch RUM にはさまざまな機能があるのですが、ここではログの集計にフォーカスします。月次にそれぞれのページにどれくらいアクセスがあったか投稿する Bot を作成しましょう。まずは [Amazon CloudWatch Logs](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups) を開いて、該当の Log group を探します。Log group は `/aws/vendedlogs/RUMService_<サイト名><ランダム文字列>` の形式になっていますので、検索ボックスから探してみてください。さまざまな Event が記録されていると思います。以下に一例を示します。(一部の項目は無効な値に置き換えています。) 47 | 48 | ```json 49 | { 50 | "event_timestamp": 1663290527000, 51 | "event_type": "com.amazon.rum.page_view_event", 52 | "event_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", 53 | "event_version": "1.0.0", 54 | "log_stream": "2022-09-15T18", 55 | "application_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", 56 | "application_version": "1.0.0", 57 | "metadata": { 58 | "version": "1.0.0", 59 | "browserLanguage": "en", 60 | "browserName": "Chrome", 61 | "browserVersion": "0.0.0.0", 62 | "osName": "Mac OS", 63 | "osVersion": "0.0.0", 64 | "deviceType": "desktop", 65 | "platformType": "web", 66 | "domain": "aws-samples.github.io", 67 | "title": "Home | AWS Prototyping ブログ", 68 | "pageId": "/jp-prototyping-blog/", 69 | "countryCode": "JP", 70 | "subdivisionCode": "13" 71 | }, 72 | "user_details": { 73 | "sessionId": "00000000-0000-0000-0000-000000000000", 74 | "userId": "00000000-0000-0000-0000-000000000000" 75 | }, 76 | "event_details": { 77 | "version": "1.0.0", 78 | "pageId": "/jp-prototyping-blog/" 79 | } 80 | } 81 | ``` 82 | 83 | 大事な項目をピックアップします。まず、event_timestamp にはイベントを受信した Unixtime が記録されています。次に、event_type が com.amazon.rum.page_view_event なので、ページを開いたというイベントであることがわかります。集計する際には event_type が com.amazon.rum.page_view_event のものをページごとに集計すれば良いことがわかります。metadata 以下にはユーザーのさまざまな情報が記録されています。 84 | 85 | では、[Amazon CloudWatch の Logs Insights](https://console.aws.amazon.com/cloudwatch/home#logsV2:logs-insights) で集計してみようと思います。Log group に該当のものを選択し、Query を以下のように入力します。右上の集計期間内にログが存在しないと結果が正しく表示されない可能性があるため、注意してください。(不明な場合は、とりあえず最大の 4 weeks を選択してみてください。) 86 | 87 | ``` 88 | filter event_type = "com.amazon.rum.page_view_event" 89 | | stats count(*) as pageCount by metadata.title as pageTitle 90 | | sort pageCount desc 91 | ``` 92 | 93 | 以下のような結果が出力されましたでしょうか。Home や About、404 などの結果も入ってしまっていますが、ここでは一旦アプリケーションレベルでフィルタリングすることにします。 94 | 95 | ![insights](./insights.png) 96 | 97 | では、この実行の流れをコードに落とし込みたいと思います。 98 | 99 | ## Python による集計 100 | 101 | boto3 を利用して Query を実行します。まず、クエリ探索範囲の指定に Unixtime が必要です。ここでは約 1 ヶ月ということにします。 102 | 103 | ```python 104 | import datetime 105 | 106 | today = datetime.date.today() 107 | month = today - datetime.timedelta(30) 108 | ``` 109 | 110 | これで今日と 1 ヶ月前の datetime が取得できました。あとは `strftime("%s")` によって Unixtime に変換できます。では boto3 の logs クライアントを初期化して、`start_query` を実行してみます。`` となっているところは置き換えが必要です。 111 | 112 | ```python 113 | import boto3 114 | 115 | client = boto3.client('logs') 116 | 117 | query = client.start_query( 118 | logGroupName='', 119 | startTime=int(month.strftime("%s")), 120 | endTime=int(today.strftime("%s")), 121 | queryString="""filter event_type = "com.amazon.rum.page_view_event" 122 | | stats count(*) as pageCount by metadata.title as pageTitle 123 | | sort pageCount desc""") 124 | 125 | print(query) 126 | ``` 127 | 128 | 正常に実行完了すると以下のように出力されます。 129 | 130 | ``` 131 | {'queryId': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'ResponseMetadata': ... 省略 ...} 132 | ``` 133 | 134 | クエリの実行は非同期ですので、この queryId をポーリングすることにより実行結果を得ます。 135 | 136 | ```python 137 | import time 138 | 139 | while True: 140 | res = client.get_query_results(queryId=query['queryId']) 141 | 142 | if res['status'] != 'Running' and res['status'] != 'Scheduled': 143 | break 144 | 145 | time.sleep(1) 146 | 147 | if res['status'] != 'Complete': 148 | print('status for the query was not Complete', res) 149 | exit(1) 150 | 151 | print(res) 152 | ``` 153 | 154 | 結果は以下のようになっていると思います。 155 | 156 | ``` 157 | {'results': [[{'field': 'pageTitle', 'value': 'ページタイトル'}, {'field': 'pageCount', 'value': '104'}],... 省略 ...]], 'statistics': {'recordsMatched': 193.0, 'recordsScanned': 2034.0, 'bytesScanned': 2139385.0}, 'status': 'Complete', 'ResponseMetadata': ... 省略 ...} 158 | ``` 159 | 160 | 一つ一つの項目が `[{'field': 'field名', 'value': '値'}]` となっているのが少し扱いづらいので、これを `{ 'field名': '値' }` となるように変換します。 161 | 162 | ```python 163 | def formatFields(fields): 164 | pageTitle = next(filter(lambda x: x['field'] == 'pageTitle', fields), None) 165 | pageCount = next(filter(lambda x: x['field'] == 'pageCount', fields), None) 166 | 167 | return { 168 | 'title': pageTitle['value'], 169 | 'count': pageCount['value'], 170 | } 171 | 172 | print(list(map(formatFields, res['results']))) 173 | ``` 174 | 175 | これで出力が `[{ 'title': 'ページタイトル', 'count': '閲覧数' }...]` のようになりました。また、Home や About などのページを対象外にします。ここでは Python レベルでフィルタリングしていますが、Amazon CloudWatch RUM の設定でページを排除することも可能ですし、Amazon CloudWatch Logs Insigts のクエリで排除することもできます。 176 | 177 | ```python 178 | # ページタイトルが Home, About, Archive, 404 で始まる物を対象外とする 179 | def filterPosts(post): 180 | return (not post['title'].startswith('Home | ')) and \ 181 | (not post['title'].startswith('About | ')) and \ 182 | (not post['title'].startswith('Archive | ')) and \ 183 | (not post['title'].startswith('404: ')) 184 | 185 | print(list(filter(filterPosts, map(formatFields, res['results'])))) 186 | ``` 187 | 188 | 以上で各ページの 1 ヶ月の閲覧数が取得できました! 189 | 190 | ## おわりに 191 | 192 | あとはこれを Lambda 関数にして Slack に定期的に投稿するなどすれば、立派な集計 Bot の完成です!Lambda 化する場合は、十分な実行時間を確保できるタイムアウトに設定するのと、権限に注意してください。Lambda 関数から対象の CloudWatch Log Group に `logs:StartQuery` と `logs:GetQueryResults` が許可されている必要があります。 193 | -------------------------------------------------------------------------------- /blog/2022-09-16-cloudwatch-rum-stats/insights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-09-16-cloudwatch-rum-stats/insights.png -------------------------------------------------------------------------------- /blog/2022-09-16-cloudwatch-rum-stats/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-09-16-cloudwatch-rum-stats/overview.png -------------------------------------------------------------------------------- /blog/2022-10-03-closed-serverless-app/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-10-03-closed-serverless-app/arch.png -------------------------------------------------------------------------------- /blog/2022-10-03-closed-serverless-app/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-10-03-closed-serverless-app/background.png -------------------------------------------------------------------------------- /blog/2022-10-03-closed-serverless-app/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "閉域網でサーバレスなアプリケーションを開発する" 3 | slug: closed-serverless-app 4 | tags: [dx, closed, serverless] 5 | authors: [statefb] 6 | --- 7 | 8 | ## はじめに 9 | 10 | 昨今、DX (Digital Transformation)に代表されるように、あらゆる業界・企業において IT 技術を駆使した業務変革のニーズが高まっています。その中で社内の変化を促すにあたり、既存の社内システムと連携が必要になるケースがあるかと思います。しかしこのような変革を担う部署では、PoC を実施し素早い成果創出を求められることが多い一方で、予算確保や保守・運用に関する社内調整が煩雑になり、スピード感を持って進めることが難しいと感じたご経験を持つ方もいらっしゃると思います。本記事は上記のような悩みを持っている方の助けになることを目指して執筆致しました。 11 | 12 | 13 | 14 | ## 背景 15 | 16 | ゼロトラストによるセキュリティ対策が登場し久しいですが、多くのエンタープライズ企業ではまだ境界型セキュリティが主流であり、社内ネットワークと外部ネットワーク(例えばインターネットなど)の境界に、ファイアウォール等を設置しネットワークレイヤーでアクセス制限をかけているケースが多いと思います。特にプロキシを経由した社内ネットワークからインターネットへ出る outbound の通信は許可されている一方で、インターネットから社内イントラへの inboud は厳禁など、クライアントからインターネット経由でのサーバへのアクセスは許可されていないこともあるかと思います。このような制約があるため、既存の社内システム(ERP、Active Directory などの何らかの管理システム)と連携が必要なシステムを AWS 上に構築する場合、[AWS Direct Connect](https://aws.amazon.com/jp/directconnect/)による閉域環境を構成した上で、EC2 や RDS などを使い開発していくケースが多いかと思います。 17 | 18 | ![background](background.png) 19 | 20 | 一方 EC2 や RDS を使った PoC では、下記のような課題が発生することがあります。 21 | 22 | - 料金:基本的に使用時間に基づいた課金のため、社内システムのようにアクセス量の比較的少ないシステムの場合、リクエスト数と実行時間で課金される[AWS Lambda](https://aws.amazon.com/jp/lambda/)などと比較し高くつくことがあります。PoC 予算は限られている傾向にあるため、これは PJ を進める上で障害となる可能性があります。 23 | - 運用・保守:EC2 は各社社内ルールの規定上、従来の物理サーバやプライベートクラウドと同様の保守・運用プロセスが求められることがあります(参考:[責任共有モデル](https://aws.amazon.com/jp/compliance/shared-responsibility-model/))。これは運用・保守人材確保のための社内調整や、人件費予算が必要となることを意味します。 24 | 25 | 上記のような課題は、サーバレス構成を採用することで解決が見込める一方、閉域網でのサーバレス構成に関する情報は散逸的であり、いざ開発に取り掛かると時間がかかったり、苦労することもあるかと思います。このため、参考となるようなサンプル:[serverless-application-on-closed-network](https://github.com/aws-samples/serverless-application-on-closed-network)を公開しました。下記にそのアーキテクチャを示します。 26 | 27 | ## アーキテクチャ 28 | 29 | ![arch](arch.png) 30 | 31 | フロントエンド・バックエンド・RDB からなる典型的な3層構成を想定したアーキテクチャであり、フロントエンド (html/css/js)は S3 から配信、バックエンドは API Gateway + AWS Lambda の組み合わせを想定しています。フロントエンドは静的ファイルであり、SPA (e.g. React、Vue)を想定しています。 S3 および API Gateway は VPC Endpoint によりインターネットを経由せずにアクセスが可能です。なおバックエンドを Fargate 上で稼働するサンプルも併せて公開しているため、既存のアプリケーションがコンテナで稼働している場合はそのままお使いいただけます(※Fargate は稼働時間による課金である点はご留意ください)。なお簡便のため RDB は今回のサンプルの中に含めていません。 32 | 33 | 図中左側の VPC は Transit Gateway や VPC Peering によって接続された他 VPC のほか、Direct Connect によって接続された社内のイントラネットを想定した検証用環境です。アプリケーション稼働確認用の Windows Server を立ち上げるためだけに存在していますので、他環境にて確認できる場合は不要となります。デプロイおよび確認の詳細な手順については [Github のリポジトリ](https://github.com/aws-samples/serverless-application-on-closed-network)をご参照ください。 34 | 35 | ## おわりに 36 | 37 | サーバレスコンピューティングは、従来かかっていた運用負荷を下げるための良い解法の一つです。人的資源の限られる中で変革を遂げるにあたり、ぜひ閉域ネットワーク内においても AWS のサーバレスな仕組みを積極的にご活用いただければ幸いです。 38 | -------------------------------------------------------------------------------- /blog/2022-10-20-cdk-notices/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "CDK の NOTICES についてざっと調べてみた" 3 | slug: cdk-notices 4 | tags: [cdk] 5 | authors: [tbrand] 6 | --- 7 | 8 | ## CDK NOTICES とは? 9 | 10 | [ここ](https://github.com/aws/aws-cdk/tree/main/packages/aws-cdk#notices) に説明がありました。 11 | 12 | > CDK Notices are important messages regarding security vulnerabilities, regressions, and usage of unsupported versions. Relevant notices appear on every command by default. 13 | 14 | 15 | 16 | `cdk deploy` などのコマンドを実行すると、このようなメッセージがでます。 17 | 18 | ``` 19 | NOTICES 20 | 21 | 21902 apigateway: Unable to serialize value as aws-cdk-lib.aws_apigateway.IModel 22 | 23 | Overview: Users of CDK in any language other than TS/JS cannot use 24 | values that return an instance of a deprecated class. 25 | 26 | Affected versions: framework: >=2.41.0 <=2.43.0 27 | 28 | More information at: https://github.com/aws/aws-cdk/issues/21902 29 | 30 | 31 | If you don’t want to see a notice anymore, use "cdk acknowledge ". For example, "cdk acknowledge 21902". 32 | ``` 33 | 34 | ## CDK の NOTICES はいつから出るようになった? 35 | 36 | [v2.14.0](https://github.com/aws/aws-cdk/releases/tag/v2.14.0) に入っている[こちらの対応](https://github.com/aws/aws-cdk/pull/18936) で導入されたようです。 37 | 38 | ## CDK の NOTICES を消すには? 39 | 40 | - Affected versions に書かれている通り、CDK のバージョンをアップデートするのが正攻法です。 41 | - CDK のバージョンを都合によってアップデートできない場合、`cdk acknowledge ` で消すこともできます。 42 | - CI で実行していて不要な場合などは `--no-notices` で非表示にすることも可能です。 43 | - プロジェクト単位で NOTICES 対応が不要な場合は、cdk.json に `notices: false` を追加することで消すこともできます。 44 | 45 | :::tip 46 | 47 | ちなみに NOTICES を明示的に表示する `cdk notices` というコマンドがあるのですが、`cdk notices --no-notices` を実行したところ、NOTICES は表示されませんでした。 48 | 49 | ::: 50 | 51 | ## 一度消した NOTICES をもう一度出すためには? 52 | 53 | CDK の NOTICES は `$HOME/.cdk/cache/notices.json` に状態が保存されているようです。 54 | よって、これまで acknowledge した NOTICES は全てこちらで管理されています。 55 | 該当する項目を消すことで、筆者の手元で NOTICES がもう一度表示されることが確認できました。 56 | 57 | ## 複数のプロジェクトを運用している場合は注意が必要 58 | 59 | CDK の NOTICES がユーザー単位で注目されていることに注意が必要です。 60 | 61 | 例えば、とあるプロジェクトには不要で、とあるプロジェクトには必要な NOTICES があった場合、不用意に `cdk acknowledge` をしてしまうと、必要なプロジェクトでも見えなくなります。 62 | そのようなケースでは、根本原因である CDK のバージョンアップ、`--no-notices` フラグ、cdk.json の `notices: false` で対応するのが良いでしょう。 63 | 64 | また、CDK のバージョンアップを行うと NOTICES が見えなくなりますが、実態としては自動的に `cdk acknowledge` されているようです。 65 | つまり複数のプロジェクトに NOTICES がでていても、1 つのプロジェクトで対応すると見えなくなり、対応していないプロジェクトが放置される原因になります。 66 | よって、CDK をアップデートする際は、同時に行うのが良いでしょう。 67 | -------------------------------------------------------------------------------- /blog/2022-12-02-react-3dmol/3dmol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-12-02-react-3dmol/3dmol.png -------------------------------------------------------------------------------- /blog/2022-12-02-react-3dmol/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'React 環境で 3Dmol.js を使う' 3 | slug: react-3dmol 4 | tags: [react] 5 | authors: [kuridaik] 6 | --- 7 | 8 | 3dmol.js は分子を立体表示する JavaScript ライブラリです。React 環境で動作させる場合、少しコツが必要でしたので紹介します。 9 | https://3dmol.csb.pitt.edu/doc/index.html 10 | 11 | ![3dmol.png](3dmol.png) 12 | 13 | 14 | 15 | ## React 環境で 3Dmol.js を読み込み分子データを可視化する手順 16 | 17 | jQuery への依存を解決するために `3Dmol-min.js` を読み込みます。jQuery を読み込んだりバンドル時に解決する方法でも構いません。 18 | 19 | ```html 20 | 21 | 26 | ``` 27 | 28 | 構造データ (pdb) のリンクを state にして、リンク取得時にレンダリングする hook を作成します。3Dmol viewer は構造データをテキストで渡すこともできますが、URL からダウンロードして表示する機能も備わっていますので、そちらを利用しています。 29 | 30 | ```tsx 31 | // npm install 3dmol@^1.8.0 32 | // @ts-ignore 33 | import * as $3Dmol from '3dmol/build/3Dmol-nojquery.js' 34 | 35 | export function Page() { 36 | const pdbViewer = useRef(null) 37 | const [pdbUrl, setPdbUrl] = useState('') 38 | 39 | useEffect(() => { 40 | const render = async () => { 41 | const viewer = $3Dmol.createViewer(pdbViewer.current) 42 | await $3Dmol.download(`url:${pdbUrl}`, viewer, {}) 43 | viewer.setStyle({ cartoon: { color: 'spectrum' } }) 44 | viewer.render() 45 | } 46 | if (pdbUrl) render() 47 | }, [pdbUrl]) 48 | 49 | return
50 | } 51 | ``` 52 | 53 | ## Vite (Rollup) を利用している場合 54 | 55 | 3Dmol.js の内部で require を上書きしている箇所があり、その部分が `Illegal reassignment to import 'commonjsRequire'` と怒られてビルドに失敗します。利用していない箇所のため、下記のように rollup replace plugin でコードを書き換えてビルドすると回避できます。 56 | 57 | ```ts 58 | import { defineConfig } from 'vite' 59 | import react from '@vitejs/plugin-react' 60 | // npm install @rollup/plugin-replace@^5.0.0 61 | import replace from '@rollup/plugin-replace' 62 | 63 | export default defineConfig({ 64 | plugins: [ 65 | replace({ 66 | preventAssignment: true, 67 | include: 'node_modules/3dmol/build/3Dmol-nojquery.js', 68 | values: { 69 | 'require = _3dmol_saved_require': '', 70 | }, 71 | }), 72 | react(), 73 | ], 74 | }) 75 | ``` 76 | -------------------------------------------------------------------------------- /blog/2022-12-05-codebuild-concurrency/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '新規 AWS アカウントで CodeBuild を利用する際の注意点' 3 | slug: codebuild-concurrency 4 | tags: [codebuild] 5 | authors: [yukimine] 6 | --- 7 | 8 | AWS のサービスには、新規作成したばかりのアカウントにはデフォルトよりも低い上限を設けているものがあります。今回は、AWS CodeBuild に適用される事がある制限をご紹介します。 9 | 10 | 11 | 12 | ## AWS CodeBuild とは 13 | 14 | [AWS CodeBuild](https://aws.amazon.com/codebuild/) は、フルマネージドなソフトウェア開発環境を提供する Code シリーズのサービスの1つで、ソフトウェアのビルドやテストのフェーズを担当しています。CodeBuild を使う事で、ビルドやテストを実行するためのサーバーの構築や運用から解放され、必要な時に必要なだけのリソースを持つインフラで自動的に実行できるようになります。CodeBuild の詳しい使い方について知りたい方は、[Black Belt Online Seminar](https://youtu.be/Zzv1_ztf-B0) の動画を見て頂ければと思います。 15 | 16 | ## AWS CodeBuild のビルド同時実行数 17 | 18 | AWS CodeBuild では、複数のビルドを並列で実行する事ができます。例えば、依存関係のないビルドを並列で実行する事でビルドにかかる時間を大きく短縮する事ができますが、同時実行できるビルドの数にはアカウント毎に上限が設けられています。 19 | 20 | [AWS CodeBuild のクォータ](https://docs.aws.amazon.com/codebuild/latest/userguide/limits.html)のページを見ると、「ビルドの同時実行」のデフォルトの上限は「60」となっていますが、下の方に以下のような注釈が書かれています。(2022年12月現在) 21 | 22 | > 同時実行ビルドの最大数のクォータは、コンピューティングタイプによって異なります。 23 | > 一部のプラットフォームとコンピューティングタイプでは、デフォルトは 20 です。 24 | > 新しいアカウントの場合、クォータは最低 5 になります。 25 | 26 | コンピューティングタイプについては、[ビルド環境のコンピューティングタイプ](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-compute-types.html)のページをご確認ください。詳細は非公表となっていますが、一部のコンピューティングタイプには異なる上限が設けられています。現在の上限がいくつであるかは、実際に実行してみて「`Cannot have more than X builds in queue for the account`」といったエラーが出る事でしか確認できません。 27 | 28 | そして、今回の本題である「新規 AWS アカウントに適用される制限」についても記載されており、「新しいアカウントの場合、クォータは最低 5 になります」とありますが、本当に新規作成したばかりのアカウントの場合、制限が 5 ではなく 1 になっている場合があります。そのため、その状態では並列ビルドの機能を使う事ができず、逐次実行させる必要があるという事になります。 29 | 30 | 無料枠の範囲内でも構いませんので、AWS サービスの利用実態をある程度積む事でこの制限は解除されるようですが、新規作成した AWS アカウントで CodeBuild の並列実行を行いたい場合はご注意ください。 31 | 32 | ## まとめ 33 | 34 | - AWS CodeBuild のビルド同時実行数の上限は一律ではなく、条件によって異なる 35 | - 新規作成したばかりの AWS アカウントでは、同時実行数の上限が 1 で並列ビルドができない場合がある 36 | -------------------------------------------------------------------------------- /blog/2022-12-05-jenkins-ec2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'JenkinsのEC2プラグインは2つある' 3 | slug: jenkins-ec2 4 | tags: [jenkins, ec2] 5 | authors: [tmokmss] 6 | --- 7 | 8 | Jenkins、便利ですよね!ワンストップなCI/CDツールで、オンプレ時代からの愛好家も多いのではないかと思います。 9 | AWSはJenkinsととても相性が良く、最近も[JenkinsのHA構成を実現するブログ](https://aws.amazon.com/blogs/devops/jenkins-high-availability-and-disaster-recovery-on-aws/)が書かれていたり、[AWS関連のプラグインも多数公開](https://plugins.jenkins.io/ui/search?query=aws)されていたりします。 10 | 11 | 今日はその中でも特に、JenkinsのエージェントノードとしてEC2インスタンスを利用するためのプラグインを紹介します。実はほぼ同じ用途のものが2つあるので、比べてみましょう。 12 | 13 | 14 | 15 | ## 1. [Amazon EC2 プラグイン](https://plugins.jenkins.io/ec2/) 16 | [Documentation](https://plugins.jenkins.io/ec2/) / [GitHub](https://github.com/jenkinsci/ec2-plugin) 17 | 18 | JenkinsのMasterノードからEC2 APIを叩き、必要に応じてエージェントノードのEC2インスタンスを起動・維持・終了するプラグインです。 19 | Jenkinsエージェントのセットアップ自体はSSH経由で自動的に行われるので、事前のAMI構築が楽になって良いですね。 20 | 21 | より昔からあるプラグインのためユーザー数は多く、また今もしっかりとメンテナンスされているようです。こちらしか知らなかったという方もいるんではないでしょうか。 22 | 23 | 内部実装としては、ec2:RunInstance APIを直接叩いてインスタンスを起動するなど、プラグインが自身でインスタンスの管理を行う形になります。 24 | このため、EC2の起動に必要な情報をすべてJenkinsに登録する必要があります。このために、設定項目が多めでやや煩雑な印象も受けました。 25 | 26 | とはいえ枯れていてユーザー数も多いという点で無難な選択肢ではないかと思います。 27 | 28 | ## 2. [EC2 Fleet プラグイン](https://plugins.jenkins.io/ec2-fleet/) 29 | [Documentation](https://plugins.jenkins.io/ec2-fleet/) / [GitHub](https://github.com/jenkinsci/ec2-fleet-plugin) 30 | 31 | 機能的には1と大きな違いはありません。EC2インスタンスの起動・終了やSSHによる自動設定も同様に利用可能です。 32 | 33 | 大きな違いは、ノードを管理する仕組みとしてAWSマネージドのAuto Scaling Groupを利用していることです。 34 | これにより、プラグイン自体の実装は単純になり、またASGに慣れている人にはより理解しやすい挙動を得られるでしょう。 35 | Allocation strategyなどASGの豊富な機能をそのまま使えるのも魅力です。 36 | [EC2プラグインとのより詳細な比較はこちらにある](https://plugins.jenkins.io/ec2-fleet/#plugin-content-comparison-to-ec2-plugin)ので、ぜひご確認ください。 37 | 38 | 元々は `github.com/awslabs` 配下の [ec2-spot-jenkins-plugin](https://github.com/awslabs/ec2-spot-jenkins-plugin) というプロジェクトだったようで、AWS公式に提供されていたようです。 39 | コミットログを見る限り、今もAWSやAmazonの開発者が関わっている様子が窺えます。 40 | 41 | また、個人的にはEC2の起動設定 (どのAMIやインスタンスタイプを使うかなど) を、ASGやLaunch templateの設定としてAWS側で持つことができるのも良いと思いました。 42 | これにより、AWS CDKやTerraformなど慣れたIaCツールでそれらの設定を記述することができます。 43 | 一方すべてJenkins側で管理したい方もいると思うので、ここは好みの問題かもしれません。 44 | 45 | 注意点として、まだ枯れていないせいか、ドキュメントが一部そのまま動かない点がありました。例えばGroovyスクリプトはそのままではエラーになります。 46 | この辺りをカバーするために後ほど動作するサンプルを公開する予定ですので、そちらもぜひ合わせてご確認ください。 47 | 48 | ## 私見 49 | 2つの大きな違いは、ノードの管理にAWSマネージドなAuto Scaling Groupを使うか、プラグイン自身が管理するかという点です。 50 | 51 | 個人的には、そのような低レベルな処理はできるだけAWSに寄せたほうがプラグイン自体の開発・メンテナンスは楽になるのではと思います。 52 | 楽なものは維持されやすいので、サステイナビリティの面ではEC2 Fleetの方が良いかもしれません。(とはいえユーザー数の差は大きいので今は判断が難しいですが) 53 | 54 | 一方で、ノードの起動時間などパフォーマンスの面ではEC2プラグインが優れているかもしれません。自前で実装している分、最適化の余地がより大きいためです。 55 | ノード起動時間にシビアな要求がある場合は、こちらに軍配が上がるかもしれません。 56 | 57 | この比較をしていて、似たような話を思い出しました。Amazon EKSのノードのスケーリングの仕組みとして、Cluster Autoscaler(CAS) と Karpenter の2つがあるという話です。 58 | 前者はASGを利用し、後者は自前実装でEC2インスタンスを管理します。Karpenterの方が性能が良いなどの理由で、最近は[CASより推奨される](https://aws.github.io/aws-eks-best-practices/karpenter/)こともあるようです。 59 | EKSのような汎用基盤ではパフォーマンスが最重要視されるため、ノードをいち早く起動できる後者の選択肢が生まれたのでしょう。 60 | 61 | Jenkinsプラグインの場合はCI/CD用のノードを管理することに特化しているため、ノードの起動時間は最優先ではないとも考えられます。 62 | コミュニティが主導するOSSである都合上、プラグイン自体のメンテナンス性や開発容易性にも優先度が置かれることもあるでしょう。 63 | このため、EC2 Fleetプラグインが後発で登場したのではないでしょうか。 64 | 65 | JenkinsとEKSのノード管理、似たような話でありながら逆の方向に進化しているのが面白いですね。 66 | 67 | ## まとめ 68 | JenkinsのEC2プラグインを2つ紹介しました。 69 | 特にまだEC2 Fleetプラグインの知名度はやや低いようなので、ぜひこの機会にお試しください! 70 | -------------------------------------------------------------------------------- /blog/2022-12-21-rails-lambda/alb_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-12-21-rails-lambda/alb_architecture.png -------------------------------------------------------------------------------- /blog/2022-12-21-rails-lambda/apigw_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-12-21-rails-lambda/apigw_architecture.png -------------------------------------------------------------------------------- /blog/2022-12-21-rails-lambda/rails_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-12-21-rails-lambda/rails_lambda.png -------------------------------------------------------------------------------- /blog/2022-12-21-rails-lambda/rails_puma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2022-12-21-rails-lambda/rails_puma.png -------------------------------------------------------------------------------- /blog/2023-01-05-fluentd-kds/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2023-01-05-fluentd-kds/arch.png -------------------------------------------------------------------------------- /blog/2023-01-05-fluentd-kds/buf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/jp-prototyping-blog/84683665cf29a215a2d3ef25d10fa9c4495c34f3/blog/2023-01-05-fluentd-kds/buf.png -------------------------------------------------------------------------------- /blog/2023-01-05-fluentd-kds/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fluentd から Kinesis Data Streams へサイズが大きいデータを転送する" 3 | slug: fluentd-kds 4 | tags: [fluentd, kinesis data streams, kinesis] 5 | authors: [statefb] 6 | --- 7 | 8 | [Kinesis Data Streams](https://aws.amazon.com/jp/kinesis/data-streams/) には、1 レコードのサイズは 1MB 以下でなければならない制約があり、サイズの大きいデータを転送するには工夫が必要となります。また利用料金はストリームに読み書きされるデータ量に基づいて決定されるため、サイズが大きいと課金額も増えてしまいます。本記事では Publisher が Fluentd の場合において、上記課題を解決する方法についてご紹介します。メッセージをメタデータと本体に分割し、本体は S3 経由で Consumer に渡し、メタデータのみを Kinesis Data Streams へ送ることで実現します。 9 | 10 | ![](./arch.png) 11 | 12 | 13 | 14 | ## Kinesis Data Streams について 15 | 16 | Kinesis Data Streams (以降 KDS と呼称) は、フルマネージドのサーバレスストリーミングサービスです。シンプルな従量制課金を採用しており、シャードの稼働時間に応じて料金は計算されます。シャードは基本的なスループットの単位であり、スループット要件に応じて必要なシャード数を決定します。なおオンデマンドモードを利用した場合、読み書きのデータ量に応じて自動的にシャード数のスケールが行われます。詳細は[Amazon Kinesis Data Streams の料金](https://aws.amazon.com/jp/kinesis/data-streams/pricing/)をご覧ください。 17 | また KDS では 1 レコードのサイズが 1MB 以下である必要があります。詳細は[Quotas and Limits](https://docs.aws.amazon.com/streams/latest/dev/service-sizes-and-limits.html)をご確認ください。 18 | 19 | ## 方針 20 | 21 | 各レコードにユニークな ID を割り当て、KDS では ID のみを、S3 バケットへはレコードの本体をそれぞれ送信します。バケットのオブジェクトキーに ID を含ませておけば、Consumer 側で ID を元にバケットから本体のデータを取得し処理することができます。これにより KDS で取り扱うレコードのサイズを削減することが可能です。本記事では、Fluentd を用いた場合について具体的に解説します。 22 | 23 | ## 想定するレコード例 24 | 25 | サイズの大きなレコードの例を示します。 26 | 27 | ```record.json 28 | [ 29 | { 30 | "metrics_name": "metrics1", 31 | "metrics_value": 24.1, 32 | ... 33 | }, 34 | { 35 | "metrics_name": "metrics2", 36 | "metrics_value": 312.56, 37 | ... 38 | }, 39 | ...以降続く 40 | ] 41 | 42 | ``` 43 | 44 | 上記の配列を「1 レコード」として取り扱うことを想定しています。この例の場合、各`metrics`を別々のレコードとして取り扱えばサイズを 1MB に抑えることも可能でしょう。しかし Fluentd の入力側の都合や (技術的な課題や組織的な事情)、個々の`metrics`間に依存関係があるため Consumer 側ではまとめて処理した方が見通しが良い等の事情により、分割することが困難または妥当でないケースがあります。また上記の配列単位で順序性が担保されれば良い場合、KDS にすべて送信すると前述のコスト体系により予算面で厳しいケースも考えれます。このような課題を前述の方針により解決を図ります。 45 | 46 | ## Fluentd のバッファリング 47 | 48 | Fluentd ではレコードをバッファリングし、まとめて送信する機能があります。これによりログの欠損防止や流量の制御が可能です。本記事ではバッファリングの利用を前提とします。 49 | 50 | Fluentd のバッファの仕組みを下記に示します。 51 | ![](buf.png) 52 | [引用先](https://docs.fluentd.org/buffer) 53 | 54 | バッファリングには stage と queue の 2 ステップが存在します。stage の段階でイベントの塊であるチャンク (chunk) を作成し、時間経過とともにエンキューされ、Output Plugin の指定する宛先へ送信されます。なおイベントはレコード (送信したいデータ本体)、タグ、タイムスタンプの 3 つの要素から構成されます。タグは Fluentd の備える主要な要素であり、Fluentd の内部でのルーティングに利用されます。Fluentd へデータを投入する Input Plugin はレコードにタグをつけ、Fluentd はそのタグにマッチする`match`ディレクティブを検索し、対応する Output Plugin へルーティングします。 55 | たとえば下記のような 2 つのダミーのデータソースがあるとします。それぞれタグは`example.hello`, `example.hoge`です。 56 | 57 | ``` 58 | 59 | @type dummy 60 | dummy {"hello": "world"} 61 | tag example.hello 62 | 63 | 64 | 65 | @type dummy 66 | dummy {"hoge": "hoge"} 67 | tag example.hoge 68 | 69 | ``` 70 | 71 | 上記両方ともに`example_bucket`という名前の S3 バケットへ転送したい場合、対応する match ディレクティブは下記のようになります。 72 | 73 | ``` 74 | 75 | @type s3 76 | s3_bucket example_bucket 77 | 78 | ``` 79 | 80 | それぞれ別のバケット (`hello_bucket`, `hoge_bucket`)へ転送したい場合は下記のように記述します。 81 | 82 | ``` 83 | 84 | @type s3 85 | s3_bucket hello_bucket 86 | 87 | 88 | @type s3 89 | s3_bucket hoge_bucket 90 | 91 | ``` 92 | 93 | 詳細は[Config File Syntax](https://docs.fluentd.org/configuration/config-file)をご覧ください。 94 | 95 | ### チャンク 96 | 97 | チャンクを作成するとき、[Chunk key](https://docs.fluentd.org/configuration/buffer-section#chunk-keys)と呼ばれるキーを指定しグルーピングすることができます。キーにはタグの他、タイムキーなどを含めることができます。 98 | 例えば下記のように記述した場合、イベントは 60 秒ごと、かつタグごとにグルーピングされチャンクが作られます。 99 | 100 | ```fluent.conf 101 | 102 | timekey 60 103 | 104 | ``` 105 | 106 | チャンクを S3 へ転送する際、上記のチャンクに付与されたユニークな ID を KDS へ転送すれば Consumer 側で S3 のオブジェクトを取得できます。ユニークな ID は Output Plugin の[chunk.unique_id](https://docs.fluentd.org/plugin-development/api-plugin-output#chunk.unique_id)、Chunk key で利用したタグやタイムキーは[chunk.metadata](https://docs.fluentd.org/plugin-development/api-plugin-output#chunk.metadata)から取得することが可能です。 107 | 108 | ## Fluentd 自身のログをキャプチャする 109 | 110 | チャンクのユニークな ID を KDS へ転送するには、Fluentd への入力として`chunk.unique_id`および`chunk.metadata`を与える必要があります。ここでは [Fluentd 自身のログをキャプチャする](https://docs.fluentd.org/deployment/logging#capture-fluentd-logs)方法を利用します。 111 | Fluentd は Fluentd 自身のログを`fluent`タグをつけて管理しています。このログは`