3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS Developer Associate を受かったのでメモ公開

Posted at

はじめに

先日、「AWS Developer Associate」 を受験して合格しました。
勉強にするにあたり備忘録を書いたので公開します。
個人的メモですのでご参考になればと思います。
随時updateはしていきたいと思います。

過去の記事のリンクも貼っておきます

この受験について

  • ご存知の方も多いと思いますが、720/1000以上で合格となります
  • 試験問題は、全部で65問あります
  • SAAより開発者向けの試験、サービスの設定とか特徴について深堀されます
  • 勉強していて重要となるサービスは、Cognito / DynamoDB / Lambda が問われることが多いと思います
  • 今回の試験勉強に使用した教材

CI/CDパイプライン

CI(継続的インテグレーション / Continuous Integration)

  • ソースコードを開発し、リポジトリに新規に登録すること、変更して更新することなどを一般的に「チェックインする」という
  • ソースコードを継続的にチェックインし、ビルドとテストを自動化しコードを検証する手法

CD(継続的デプロイメント, 継続的デリバリー / Continuous Deployment, Continuous Delivery)

  • 開発 / 更新したソースコードが、本番環境でお客様が安全に使える状態に反映

デプロイパターン

名前 説明
(1)In-Place ・稼働中の環境を新しいアプリケーションで更新する。
・直接アプリを配置して再起動
(2)Linear ・トラフィックを毎回、同じ増分、同じ間隔で移行する
(3)Canary ・トラフィックを2回の増分で移行(2回目で残り全てを移行)・最初は10%のみで、数分後に全てなど、割合によって段階的にリリース。
・一部だけ新しいアプリケーションをデプロイ/リリース。特定のユーザーだけ新しいApp
(4)Blue / Green ・現バージョンとは別に新バージョン環境を構築し、リクエスト送信先を切り替える
・新しい環境ができるのでDNS名が変わる
(5)Rolling ・サーバーをいくつかのグループに分けて、グループごとにIn-Placeする
・アプリケーションの古いバージョンでリクエストを処理するインスタンスもあり、新しいバージョンでリクエストを処理するインスタンスもある
(6) Rolling with additional batch ・バッチサイズ分の新しいインスタンスを追加してデプロイを実行
・キャパシティーを100%に維持できる(メリット)
・本番でよく使われる
(6)Immuitable ・同じ環境にASGだけ追加する、それで同じASGが同じDNS名を持つ
・Blue/GreenはDNS名が変わるがこの方法は変わらない
・リリース後は旧環境を削除
・部分的に完了したローリングデプロイにより発生する問題を防ぐ
・古いバージョンと新しいバージョンが混在している時間はある
(7)All at once ・全てのサーバで同時にIn-Place更新をする
  • 単一インスタンス >> All at Once, Immutabel
  • LB, ASG >> All at Once, Immutable, Rolling, Rolling with additional batch, Immutable
  • Rolling, Rolling with additional batch, Immutable ->>> 古いバージョンと新しいバージョンが混在している時間が存在->>> Blue/Greenで改善

CodeCommit

  • プライベートなプライベートなGitリポ

  • SSH or HTTPSを使って安全に接続できる

  • SSH / HTTPSで使用する認証情報はIAMユーザー毎に生成

  • IAMと統合されている(IMAポリシーによって、リポジトリのアクセス権限を設定できる : AWSCodeCommitPowerUser)

  • ソースコードが更新されたなどのタイミングで、通知やLambda関数を実行するイベントを設定できる

  • 通知先:SNSとAWS Chatbot

  • codecommitからEC2にデプロイ→CodeDeploy AgentをEC2にインストール

◆ CodeCommitへのアクセスを許可する方法

  • HTTPS Git認証情報を設定する
  • 新しいSSHキーを生成し、公開SSHキーを開発者の各IAMユーザーに関連付ける

CodeBuild

  • ソースコードをコンパイルし、ユニットテストを実行して、すぐにデプロイできるArtifactsを生成
  • コンパイル、テスト、パッケージなどビルドプロセスの提供
  • コードのビルドおよびテストを実行するために必要なシステムやツールを備えている
  • ex) ビルドに必要なOS, プログラミング言語ランタイム。npmなどのビルドツール
  • Jenkinsジョブ相当のものを「Build Project」と呼び、任意のDockerイメージを起動してコンテナ内で任意のコマンドを起動できるサービス
  • CloudTrailを有効化することでAWS CodeBuildのログを取得できる
  • CloudTrailは、CodeBuildコンソールからのコールや、CodeBuild APIへのコード呼び出しを含む、CodeBuildの全てのAPIコールをイベントとしてキャプチャ
  • CloudWatchによるモニタリング可能
  • 一貫したimmutableな環境なので個々にビルドを新規Dockerコンテナで実行
  • 通知先 : SNS or chatbot
  • CodeBuildタイムアウトを有効することにより、構成されたタイムアウトの期限が切れるとビルドプロセスが自動的に終了
  • デフォは、60min, aws cli で queuedTimeoutInMinutesOverride (min 5m, max 8h)

ビルド対象

  • S3バケット
  • CodeCommit
  • GitHub
  • GiHub Enterprise
  • Bitbucket

◆ buildspec.yaml

  • ソースのルートレベルにbuildspec.ymlというファイルを配置
  • buildspec.yml
    • ビルドの仕様であり、ビルドプロセスのコマンド(環境変数)を記述
    • アーティファクトを作成しS3に保存
    • 各フェーズで実行するコマンドの指定
      - install : パッケージのインストールやコマンド実行
      - pre-build : 構文チェックやコマンド実行
      - build : ビルドツールやコマンドの実行
      - post-build : テスト実行やレポジトリへのコンテナイメージの配布

ex) CodeBuildでテストしてテストに成功したらS3にアーカイブをupload

buildspec.yml
version : X.X

phases:
    install:
        commands:
            - pip install -r requirements.txt
    build:
        commands:
            - python main.py test
artifacts:
    files:
        - app/*
        - project/*
        - manage.py
        - requirements.txt 

◆ CodeBuild Local

  • AWSが提供するCodeBuildのビルド用イメージのDockerファイルと、それを動かすためのAgent Dockerイメージとヘルパースクリプト
  • ローカルでbuildspec.ymlを走らせて実行できる
  • ローカルでもセットアップして実行することができる
  • buildspecの整合性と内容をローカルでテストできる
  • コミットする前に、アプリケーションをローカルでテストしてビルドできる
  • ローカル開発環境からエラーを素早く特定して修正

AWS CodeDeploy

  • ソフトウェアのデプロイを自動化するフルマネージド型のサービス
  • EC2、Lambda, オンプレミス、コンテナへの自動的なデプロイメント
  • アプリのデプロイ中のダウンタイムを回避
  • エラーを検知すると、自動的にロールバック
  • Pull型を推奨 : 各インスタンスが必要な変更をPull→どんなサーバーが立っているか意識しなくて良い
  • 以前にデプロイされたアプリケーションのリビジョンを新しいデプロイとして再デプロイすることでロールバックする
  • ロールバックされたデプロイは、前のデプロイバージョンでなく新しいデプロイIDを使用

◆ サービスロール

  • Code Deployに付与するIAMロール
  • Code DeployからAWSリソースを操作するために必要

appspec.yml

  • アプリケーションや設定ファイルをディレクトリへコピー
  • 特定のディレクトリとファイルアクセスを許可を設定
  • Hook用のスクリプト指定
  • CodeDeployで実行するデプロイ方式
  • ルートディレクトリに定義
  • Code Commit と Code Deployの設定に対して、アプリケーションのデプロイ時にファイルへのアクセス許可を変更することができる
    リビジョンに含まれるアプリケーション仕様ファイル
用語 説明
BeforeAllowTraffic トラフィックがデプロイされたLambda関数バージョンに移行する前にタスクを実行するために使用
ValidateService デプロイが正常に完了したことを確認するために使用される
BeforeInstall インストール前にタスクを実行するために使用
AfterAllowTraffic トラフィックがデプロイされたLambda関数バージョンに移行する後にタスクを実行するために使用
appspec.yml
version: 0.0
os: linux
files:
   - source: /index.html
     destination: /var/www/html
hooks:
   BeforeInstall:
      - location: scripts/install_dependencies
        timeout: 300
        runas: root
      - location: scripts/start_server
        timeout: 300
        runas: root
   ApplicationStop:
      - location: scripts/stop_server
        timeout: 300
        runas: root

★CodeDeployの主要な3つの機能

用語 説明
アプリケーション デプロイするアプリケーションの名前とコンピューティングPFを設定する
デプロイグループ EC2インスタンスのグループを設定する。タググループ、オートスケーリンググループが指定できる
リビジョン ・ソースコンテンツを保存している。AppSpecファイルを含む
・アプリケーションのリリース単位
・リビジョンは環境(デプロイグループ)毎にデプロイ単位を作成
  • リビジョンは、アプリケーションでデプロイするソースファイル・バイナリファイル・設定ファイル、さらにデプロイ時に実行するフックスクリプトなどで構成
  • これらはパッケージされ、S3に登録するかGithubに登録

CodePipeline

  • 迅速かつ信頼性の高いアプリケーション更新を実現

  • コードが変更されるたびにコードをビルド、テスト、デプロイする

  • SNSと連携することで、パイプラインのステージに対して承認アクションを追加することができる

ソースプロバイダ

  • CodeCommit
  • ECR
  • S3
  • Bitbucket
  • GitHub

ビルドプロバイダ

  • CodeBuild
  • Jenkins

デプロイプロバイダ

  • CodeDeploy
  • AppConfig
  • CloudFormation
  • Elastic Beanstalk
  • OpsWorks
  • Service Catalog
  • Skills Kit
  • ECS
  • S3

CodeStar

  • プロジェクトテンプレートを選択して、プロジェクト名を決めるだけで、各AWS Codeサービスを構成したCI/CDパイプラインを自動的に作成
  • 迅速にプロジェクトを開始できるサービス

Code Artifact

  • ソフトウェアパッケージを保存して配信できるサービス
  • 一般的に使用されるパッケージマネージャ及びビルドツールと連携して動作

CodeGuru

(1)CodeGuru Profiler (コードのパフォーマンス可視化)

  • EC2,EKS,ECS, Fargate, Lambda, またはオンプレのJava、JVM言語で開発されたアプリケーションのパフォーマンスを可視化
  • アプリケーションのパフォーマンスの問題の原因を診断できることできる

(2)CodeGuru Reviewer (コードの自動レビュー)

  • GitHub, CodeCommit, Bitbucketと連携し、Javaのコードの自動レビューを実行
  • ソースコードの品質向上に役立つ

CloudFormation

  • スタックというAWSリソースの集合体を自動構築
用語 説明
Resources(必須) ・TypeでAWSのリソースを指定する
・条件付きで作成するリソースまたは出力と条件を関連づける
Mappings 複数のリージョンで使用する場合に、リージョンごとにテンプレートを作ると管理が煩雑で整合性が失われてしまう可能性もあるのを解決
Parameters ・条件において評価する入力を定義
・実行時にテンプレートに渡す値(スタック作成時・更新時)
Conditions 組み込み関数を使用して条件を定義
Outputs ・実際に割り当てられたEIPなどを返す

★Mappingの使い方

.yml
Mappings: 
    Map01: 
        Key01: 
            Name01: Value01

呼び出し

.yml
!FindInMap [Map01, Key01, Name01]
組み込み関数 2
Fn::Ref ・指定したパラメータやリソースの取得に使う
・パラメータでは設定された値が、リソースではリソース宣言の戻り値を返す(大体はリソースの物理ID)
Fn::FindInMap ・Mappingsで定義された内容を取得
Fn::GetAtt ・GetAttはリソースごとに決められている物理IDを引っ張ってくる感じ
・リソースのみを対象とするほか、Refは大抵が物理IDだが、こちらの関数で何かが返ってくるかは各リソースで違う
Fn::Sub ・内部に変数を仕込んだ文字列をスタック生成時に変数の値を解決
・複雑な文字列を組むときに使用する
Fn::ImportValue ・組み込み関数は、別のスタックによってエクスポートされた出力の値を返す

◆ ヘルパースクリプト

  • EC2インスタンスのプロビジョニング&構成管理ツール
  • CFnテンプレートファイルのEC2のメタ情報に設定情報を記述
用語 説明
cfn-init ・入力した値の整合性チェックできるCLI
・パッケージのインストール
・ファイルの作成
cfn-single ・設定完了をAWSに通知
cfn-get-metadata ・設定情報を読み取る
・特定のキーへのリソースまたはパスのメタデータを取得するために使用
cfn-hup ・定期的に設定情報を読み取る。設定情報に変更があれば、指定の操作を実行
・メタデータへの更新を確認し、変更が検出されたときにカスタムフックを実行する

⭐️メリット

  • インスタンスを作り直すことはなく設定を更新できる
  • 失敗への検知が楽

Elastic Beanstalk

  • 使い慣れたサーバーでデプロイおよびスケーリングするためのサービス
  • ネットワーク設定・保守が不要
  • 利用料金は不要で、デプロイしたAWSリソースに対する使用料金が課金
  • ウェブサーバー環境(ELB + Auto Scaling)とワーカー環境(SQS + Auto Scaling)の2パターンの構成可能
  • 開発者がアプリケーションの構築に集中するために、アプリケーションコード以外の環境をAWSが構築するサービス
  • ワーカー環境のキューに対して定期ジョブを自動的に追加するためには、cron.yamlファイルをソースバンドルに追加することが必要
  • cron.yamlファイルを設定およびアップロードして、2つの定期的なタスクを作成できる
  • env.yaml : EB環境を作成する時に利用
  • アプリケーションをZIPファイルにパッケージ化し、eb deployコマンドを使用してデプロイすることで新しいバージョンをEB上で実行

◆ ワーカー環境

  • 完了するまでに長い時間がかかる処理は、SQSを用いたワーカー処理が望ましい
  • バッチアプリケーション
  • ワーカー環境では、SQSキューを管理しタスクを実行するSQSデーモンが実行
  • SQSデーモン : SQSからキューを読み取り、ローカルのポート80にHTTP POSTをリクエストを送ってくれるデーモンプロセスが各インスタンス内に常在
  • メッセージ -> SQS -> sqsd -> App
  • cron.yamlにタスクを記述することでタスクの定期実行可能

◆ アプリケーションの管理

  • ソースコードをアップロードするたびに、新たなバージョンラベルを付与し、アプリケーションバージョンを作成する

  • 古いバージョンは削除もできる

  • アプリケーションバージョンライフサイクルポリシーを設定することで、過去のバージョンを自動的に削除することが可能

◆ デプロイメントポリシー

  • デプロイポリシー
    • All at once, Rolling (In Place)
    • Rolling with additional batch (In Place & Blue/Green)
    • Immutable
  • URL Swap
  • Route 53を利用した既存環境と新環境の入れ替え(Blue/Green)

*In Place Deployment(Rolling Deploy):インスタンスは現行環境のものをそのまま利用し、新しいリビジョンのコードをその場で反映
*Blue/Green Deployment : 新しいリビジョンのコードを、新しいインスタンスに反映させ、インスタンスごとに入れ替える

⭐️EBのアプリケーション作成により以下のリソースができる

  • CloudFormationスタック
  • 起動設定
  • オートスケーリンググループ
  • スケーリングポリシーと紐づくCloudWatchアラーム
  • セキュリティグループ
  • ALB

EB CLI

  • EBアプリ環境を構築できる
  • 代表的なコマンド (eb init, eb create, eb deploy)
$ eb init -p python-3.6 flask-tutorial --region us-east-1
.elasticbeanstalk/config.yaml
branch-defaults:
   default:
      environment: null
      group_suffix: null
   global:
      application_name: flask-tutorial
      branch: null
      default_ec2_keyname: null
      default_platform: Python 3.6
      default_region: us-east-1
      include_git_submodules: true
      instance_profile: null
      platform_name : null
      platform_version: null
      profile: null
      repository : null
      sc : null
      workspace_type : Application
$ eb create flask-env
$ eb deploy -l v2

AWS SAM (Serverless Application Model)

  • CloudFormationの拡張機能で、lambda, API GW, DynamoDB, S3, step functionsなどを組みあわせた、サーバレスアプリケーションの構築、自動化
  • SAMは専用のCLIを使用
  • 普通のCFnより圧倒的に人に優しい
  • 最もシンプルなデプロイは、(1)sam init → (2)sam build → (3)sam deployの3ステップで完了
用語 説明
sam init サーバーレスアプリケーションの初期処理、テンプレートが作成される
sam build APIとLambda関数をデプロイするための準備をする. ビルドが完了すると、後述するローカルでのテストも実行できるようになる
sam deploy AWSアカウントにAWSリソースを構築できる
sam publish samで作成したアプリケーションをAWS Serverless Application Repositryに公開できる
sam package samで作成したアプリをパッケージ化できる
sam validate samテンプレートがSAMの仕様に沿った記述になっているか検証
sam local start-api ・開発環境でサーバーレスアプリケーションのテストができる
・ローカルでAPIの実行可能になる
$ pip install aws-sam-cli
$ sam --version
$ sam init --runtime XXXX
template.yml
AWSTemplateFormationVersion : XXXX
Transform : AWS::Serverless-2016-10-31
Description: XXX
Resources:
    TranslateLambda :
        Type : AWS::Serverless::Function
        Properties:
            FunctionName: XXXX
            CodeUri: ./XXXXXX
            Handler: XXXXXXXX
            Runtime : python3.7
            Architectures : [ arm64 ]
            Timeout: X
            MemorySize : 256

移行(オンプレ→AWS)

(1)リホスト(REHOST)

  • そのままの構成でAWSへ
  • オンプレの仮想マシンから移行する時は、Server Migration Serviceを使う
  • DBは、export / import

(2)リプラットフォーム

  • プログラムは変更せずに最適化を検討
  • 2つのAZを利用
  • 高可用性・DBの運用管理の負担を軽減。ただし、AWSの知識必要

(3)再購入(REPURCHASE)

  • 製品やサービスの再検討
  • アカウント利用コストに置き換えて運用コストをなくす

(4)リファクタリング/再設計

  • (2)(3)に加えて、プログラムのカスタマイズ、または作り直しをする
  • クラウドの最適化されて、そのメリットをフルに活用した設計ができる
  • ただし、開発コスト、時間の追加が必要

(5)廃止(RETIRE)

(6)保持(RETAIN)

  • 移行せずにオンプレミスで運用継続

モニタリングサービス

デバッグやパフォーマンス測定に役立つAWSサービス

  • ⭐️Amazon CloudWatch
  • ⭐️VPC フローログ
  • ⭐️AWS CloudTrail
  • ⭐️AWS X-Ray

CloudWatch (モニタリング①)

  • AWSでモニタリングと言えば、CloudWatch
  • 非常に多機能なモニタリングサービス

◆ CloudWatch Logs

  • EC2にデプロイしたアプリケーションのログをCloudWatchに書き出す
    • (1)IAMロールの作成
    • (2)System Managerを使用してCloudWatchエージェントをインストール
    • (3)cloudwatch agent設定ファイルの作成
    • (4)cloudwatch agentの開始

メトリクス

  • 数値情報をモニタリングできる
  • 標準メトリクスとして、各サービスが自動で取得されているものに加え、カスタムメトリクスとして独自の数値情報を送信することが可能
  • カスタムメトリクスの送信にはPutMetricData APIアクションを実行可能

⭐️ 代表的な標準メトリクス

EC2 説明
CPUUtilization EC2で使用されている比率
NetworkIn インスタンスが受信したバイト数
NetworkOut インスタンスから送信したバイト数
StatusCheckFailed インスタンスのステータスチェックとシステムステータスチェックのいずれかに失敗した場合は1、それ以外は0
EBS 説明
VolumeReadOps ディスク読み取り回数
VolumeWriteOps ディスク書き込み回数
S3 説明
BucketSizeBytes 保存されているオブジェクトのデータの量
NumberOfObjects オブジェクトの合計数
RDS 説明
DatabaseConnections データベースの接続数
ReadIOPS ディスク読み取り回数
WriteIOPS ディスク書き込み回数
FreeableMemory 使用可能なメモリ容量

VPCフローログ (モニタリング②)

  • VPC内のENIを通過するIPトラフィックに関する情報をキャプチャできる機能
  • 送信元IPアドレスとポートおよび送信先IPアドレスとポート、プロトコル、転送パケット数、バイト数、許可されたか拒否されたかを、S3バケットまたはCloudWatch Logsに出力できる
  • SGやNACLが正しいか調べるのにも使える
  • CloudWatch Logsへの発行する場合は、IAMロールが必要

X-Ray (モニタリング③)

  • 連携可能サービス: EC2, ECS, Lambda, EB (EC2/ECSは手動でインストール必要)
  • X-Ray SDK : 単純なX-Ray APIへの操作
  • X-Ray デーモン : UDP(Port 2000)でX-Ray SDkからトラフィックを受信し、未加工のセブメントデータを収集。アプリケーションに設定して、エラーとバグの特定に役立つ
  • xray-daemon.config : ディレクトリにこのファイルを置けば、X-Rayデーモン有効
  • X-Ray agent : データをログファイルから収集し、X-Rayサービスに送信するためのエージェント
  • X-Rayではフィルタ式を利用して検索したいトレース情報の結果を絞り込むことできる
  • そして、X-RayコンソールまたはGetTraceSummaries APIを使用して特定の情報に関連付けられたセグメントを検索できる
  • Fargate起動モードを使用したDockerコンテナに対してX-Rayデーモンを実行したい場合は、X-Rayデーモンエージェントをサイドカーコンテナとしてデプロイする必要あり
  • x-rayデーモンを実行するDockerイメージの作成は、EBではなくECSクラスタでX-rayを有効にした場合に必要
  • EBにおけるX-rayトレースオプションを有効化することで、自動でトレースが実施されることはない、X-rayデーモンを有効化することが必要
  • X-rayが取得するトレースデータはセグメントドキュメントの形式でX-rayに送信
  • セグメントドキュメントは最大64kbでサブセグメントを含むセグメント全体、リクエストが進行中であることを示すセグメントのフラグメント、または個別に送信される単一のサブセグメントを含むことできる
  • PutTraceSegments APIを使用して、セグメントドキュメントをX-Rayに直接送信できる
  • セグメントとサブセグメントをX-rayデーモンに送信し、それらをバッファリングしてバッチでX-ray apiにアップロード
  • X-ray Daemonの仕事はSegmentsを送信すること

★lambda⇒X-rayアクセス

  • 最低限xray:PutTraceSegmentsxray:PutTelemetryRecordsがあれば動作する
  • これらを含んでいる最小権限のAWS管理ポリシーはAWSXrayWriteOnlyAccess
用語 説明
セグメント 動作に関するデータ。リソース名、リクエストの詳細、行った作業の詳細が含まれる
サブセグメント 呼び出しに関する追加の詳細なデータ
トレース 1つのリクエストで生成されたセグメントのすべてを収集
トレースID トレースが含むセグメント管理
セグメントID セグメントのつながり順序
トレースヘッダー トレースIDセグメントIDをどのように伝搬
注釈、メタデータ セグメントに情報付与
サービスマップ トレースデータの可視化

◆ LambdaでX-rayトレースを有効化する

  • ①アクティブトレースを有効化する

    • Lambda関数の設定で[アクティブトレース]を有効にして保存
    • X-Rayにトレースデータを送信するためのアクション許可がIAMロールに不足知っている場合は自動的に追加
    • 以下の2つのAPI必要
      • xray : PutTraceSegments
      • xray : PutTelemetryRecords
  • ②X-Ray SDKをコードに含める

    • Lambda関数内の様々なリクエストを分析したい場合は、X-ray SDKをコードに含める
  • ③コードを追加する

シンプルなコード

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all
pathc_all()

*patch_all()によって、関数内の各リクエストが自動トレースされる

◆ X-Ray API

用語 説明
★ PutTraceSegments ・X-Rayにトレースデータを送信する
・アプリケーションからX-Rayにトレースデータを送信するにはこのアクションをIAMポリシーで許可
GetServiceGraph ・サービスマップのようなJSONサービスグラフの情報を取得
★ GetTraceSummaries ・フィルタ式を使用して、指定された時間枠で使用可能なトレースIDと注釈を取得できる
BatchGetTraces ・完全なトレースを取得
・トレースIDによるトレースリストの取得

CloudTrail (モニタリング④)

  • AWSアカウント上で行われたAPIアクションのほとんど記録
  • CloudTrailはログをS3バケットに保存
  • ⭐️ 問題の解析をしたり、セキュリティ脅威が発生した際に何が行われたかを明確に調査できる

トラブルシューティング

大まかには、5xxサーバー側エラーに対しては再試行、4xxクライアント側エラーに対してはソースコードの修正

◆ スロットリングエラー

  • リクエスト拒否や遅延が発生する原因にスロットリングエラー
  • これはサービスAPIの制限リクエスト回数に達したために発生
  • 以下で例としてLambdaの同時実行数、KMSのキーへのリクエストクォータ

①Lambdaの同時実行数

  • Lambda関数はイベントトリガーやリクエストによって実行される
  • 関数ごとに同時実行数をユーザーが制限しておくこと
  • 同時実行数の制限に達してさらにリクエストが発生した場合には、RateExceededエラーを受け取り
  • CloudWatchでは、全体、または関数ごとのThrottlesメトリクスでモニタリングできる

②KMSのキーへのリクエストクォータ

  • 暗号化APIアクションの回数やキーの種類によってデフォルトのクォータが決められている

◆ エクスポネンシャルバックオフ

  • スロットリングエラーや5XXサーバー側のエラーが発生した際には、アプリケーションからの再試行が必要
  • SDKを使用していると自動再試行ロジックが実装されているので、開発者が再試行ロジックを実装する必要はない
  • SDKでは、再試行のロジックとしてエクスポネンシャルバックオフアルゴリズムを実装→無駄な再試行リクエストを減らすのが目的

◆ セキュリティのトラブルシューティング

  • AWSサービスに対してのリクエストが拒否される原因は、IAMポリシーで許可されていないか、拒否されているかのいずれか
  • IAMポリシーはIAMユーザーやIAMロールに設定されている以外に、リソースベースのポリシーもあるので確認対象が複数あることに注意

暗号化

  • 通信の暗号化を行う一般的な方法はSSL/TLS通信を行うこと
  • HTTPSプロトコルが有効なエンドポイントに対するリクエスト通信は暗号化されている

◆ AWS Certificate Manager

  • 独自ドメインのアプリケーションでの証明書の管理、設定の機能
  • CloudFront, ELB, API Gatewayと連携してユーザー所有ドメインの証明書を設定することができる
  • 所有者の確認は、メール認証かCNAME認証で行われる

◆ 保管時の暗号化

  • 暗号化に使用するキーの管理に専用ハードウェアが必要な要件 : CloudHSM

◆ KMS

  • 暗号化するためのキーを作成、管理できる
  • KMSではデータキーを生成してオブジェクトやインスタンスの暗号化を行う
  • 暗号化に使用したデーターキーはCMKによって暗号化⇒この方法を、エンベロープ暗号化
  • 既存のCMKの自動キーローテーションを有効にすることができる
  • CMKを作成して適用させるためには、新しいCMK作成後にアプリケーションまたはエイリアスを変更することが必要
  • KMSはCloudTrailと統合されている
  • cloudTrail: KMSコンソールからのコールや、KMS APIへのコード呼び出しを含む、KMSの全てのAPIコールをイベントとしてキャプチャすることできる

◆RDSインスタンスの暗号化

開発環境

◆AWS API

AWSの各サービスへのリクエストは、マネジメントコンソールで操作しても、AWS CLIで操作しても、SDKからリクエストを実行しても、SDKからリクエストを実行しても、AWSのAPIに対してリクエストが実行

◆ 署名バージョン4を使用してリクエストに署名する

EFS

  • EC2インスタンスからマウントして使用
  • 複数のAZにマウントポイントを作成できる
  • amazon-efs-utilsパッケージをLinuxにインストールすると、マウントヘルパーを使って簡単にマウントコマンドを実行
$ sudo mount -t efs fs-12345678:/ /mnt/efs

DynamoDB

####◆請求モード

*テーブル作成後でも変更可能

  • (1) オンデマンドキャパシティモード

    • 読み込み回数とサイズ、書き込み回数とサイズに応じて請求が発生
    • 結果整合性モデルより強い整合性モデルでの読み込みコストは倍
    • 急なスパイクリクエストにも対応できる
  • (2) プロビジョニング済みキャパシティモード

    • RCU と WCUを確保・設定するモード
    • 1つのWCUでできることは、最大1KBの項目を1s間に1回書き込むこと
    • 1つのRCUでできることは、最大4KBの項目を、1s間に2回結果整合で読み込むか、1s間に1回強い整合性で読み込むか

◆ 整合性モデル

  • 結果整合性モデル
  • 強い整合性モデル

◆ Primary Key

パターンとして

  1. Primary KeyをPartition Keyのみとする場合と
  2. Primary KeyをPartition Key + Sort Key とする場合
  • (1) Partition Key ( 旧 hash key )

    • 一意に特定するためのID
    • テーブル作成で1つ属性を選ぶ
    • 重複はダメ
  • (2) Sort Key (旧 range key)

    • Partition keyにレンジを加えたものをソートキー or 複合キーと呼ぶ
    • テーブル作成時に2つの属性を選び1つをパーティションキー、もうひとつをソートキー
    • 2つの値を組み合わせて1つの項目を作成

◆セカンダリインデックス

  • ハッシュキーやレンジキーだけでは検索要件を満たせないとき使用

  • (1) LSI

    • ソートキー以外にindexを作成(3つ目のキー)
    • 複合テーブルのみ(primary key = partition key & sort key)に設定可能
    • 1つのテーブルにMAX5つ作成可能/テーブル作成時に
    • Itemの絞り込みが効率よくできる
  • (2) GSI

    • ハッシュキーの代わり(別のハッシュキーを指定)
    • テーブル全体に対して検索できる
    • 1つのテーブルに5つ作成可能/テーブル作成後

◆グローバルテーブル

  • ほかのリージョンにテーブルのレプリカ作成
  • このテーブルは、各リージョンでマルチマスターとして書き込み可能なテーブルになる
  • グローバルテーブルを作成するには、まず1つのDynamoDBテーブルを作成してストームを有効にする

◆バックアップ

  • ポイントインタイムリカバリ

    • 過去35日間分の継続的なBUが作成される
    • 有効期間中の任意の時点のテーブルを作成することできる
  • バックアップ

    • 特定時点のバックアップデータを作成しておくことも可能

◆ クエリとスキャン

  • クエリ

    • 主キーの値に基づいて項目を検索する
    • テーブルやインデックスが大きくなるに従ってスキャンは低速
    • Hash keyとRange keyの複合条件にマッチする項目(item)を取得
    • クエリとスキャンならクエリの方が早い
  • スキャン

    • テーブルのすべての項目(item)および属性を取得
    • テーブルまたはインデックスが大きいほど、scanの完了に要する時間は長い
    • *一般的に、scanよりも他のオペレーションのほうが効率的(⭐️なるべく使わない)
      • テーブルの場合は、GetItem, GetBatchItem API
  • 並列スキャン

    • 複数のワーカースレッド/プロセスを同時に実行し、各ワーカーはテーブルの別のセグメントを他のワーカーと同時にスキャン
    • TotalSegments : テーブルに同時アクセスするワーカーの数
    • Segment : コールしているワーカーによってアクセスされたテーブルのセグメント
    • テーブルサイズが20GB以上であるとき有効
  • prejecttion

    • Query, Scanに対して、すべての属性ではなく一部属性のみ取得する方法

◆ DynamoDBストームを有効にする際にどの情報をDynamoDBストームに格納するか

  • テーブル内のデータが変更されるたびにストリームに書き込まれる情報を指定する
    • KEYS_ONLY : 変更された項目のキー属性のみ
    • NEW_IMAGE : 変更後に表示される項目全体
    • OLD_IMAGE : 変更前に表示されていた項目全体
    • NEW_ADN_OLD_IMAGE : 項目の新しいイメージと古いイメージの両方

◆ DynamoDB トランザクション

  • 複数のテーブルに渡って原子性、一貫性、分離性、耐久性を提供

  • PutItem : 新規項目の追加

◆ キャッシュ戦略

  • ライトスルー
  • 遅延読み込み

◆ オプティミスティックロック (楽観的排他制御)

  • 多分ダブルブッキングしないし、仮にダブルブッキングしてもそこまでやばいことにはならないから、もしダブルブッキングしたら諦めると楽観的に考えて設計されているロックのこと

◆ 条件付き更新と条件付き書き込み

  • XXX

◆ その他

  • リクエスト急増で、アプリケーションのスロットルエラーが発生

    • アプリケーションからのリクエストでExponential Backoffを使う
    • テーブルのスループット容量を上げる
  • ProvisionedThroughputExceptionが発生

    • アプリケーションからのリクエストでExponential Backoffを使う
  • テーブルスキャンのパフォーマンス向上方法

    • 並列スキャンの使用&クエリ使用
  • GSIを使用したテーブルを作成。RCUを最小限に最新の取得をする方法

    • 結果整合性のある読み込みを使用したクエリ
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('SongsRevenue')
table.put_item(
  Item={
    'Request':24,
    'Month' : '202101'
  }
  • PutItem

    • 入力で指定したアイテムで、既存のアイテムを置き換える
    • 新しい項目を作成
    • 同じキーを持つ項目がテーブルにすでに存在する場合は、新しい項目に置き換えれる
    • テーブル名と書き込む項目を指定する必要あり
  • UpdateItem

    • 入力で指定した項目属性のみを変更し、項目内の他の属性は変更されない
    • UpdateExpression : データをどう更新するか
    • ExpressionAttributeNames : キーに別名を割り当てる
    • ConditionExpression : 条件付き書き込み
  • DeleteItem

    • キーを指定して項目を削除できる
    • ReturnValuesで、削除前の項目を取得できる
table.deletet_item(
    Key={
    'Name' : "XXXX",
    'Id' : 3
    }
)
  • GetItem

    • プライマリキーが必須
    • ProjectionExpressionパラメータで、取得する属性を指定する
    • ConsistentReadで強力な整合性を指定できる
  • Query

    • 複合プライマリキー設定時の範囲検索・セカンダリインデックスでの検索
  • Scan

    • 全レコード取得
    • テーブルの項目を全てスキャンするので非効率
    • なるべくクエリで検索できるように設計
    • FilterExpressionでフィルタリングできる
  • Batch&Transaction

*データ取得➡︎getitem, scan, query

S3

  • オブジェクトストレージ
  • 無制限にデータ保存

◆ バックアップとアーカイブ

バージョニング

◆静的ウェブサイトとコンテンツの配信

  • S3バケットに静的なファイルを配置して、適切なアクセス権を設定すればHTTP/HTTPSプロトコルでアクセスできる
  • 要はブラウザからURLを入力すればアクセスできるということ
  • 静的ファイルのWeb配信は、わざわざEC2インスタンスでWebサーバーを用意しなくてもS3バケットがあれば可能

◆CloudFront + S3


用語 説明
InternalError S3内でエラーが発生しているので再試行
NoSuchBucket バケットが存在しない
BucketAlreadyExists バケットが既に存在
InvalidBucketName バケット名が無効

Lambda

  • OSの運用や管理、ミドルウェアのインストール、設定、メンテナンス、スケールアップなどをしなくても任意のコードを実行可能
  • メモリサイズは128MB-10GBの間で設定、CPU性能とネットワーク帯域はメモリサイズに依存する
  • リージョンでの起動でもVPCネットワーク内での起動も指定
  • 大容量のデータを暗号化するためには暗号化SDKを使用して、暗号化されたファイルをLambda関数でエンベロープする必要がある
  • Lambda関数のデプロイパッケージは、関数コードと依存関係を含むZIPアーカイブ
  • パッケージをLambdaに直接アップロードするか、S3バケットを使用してLambdaにアップロードすることができる
  • デプロイパッケージが50MB以上ならS3を利用
  • AWS::Lambda::Functionを利用して、Lambda関数のデプロイパッケージをCFnにおいて参照可能
  • すべてのランタイムに対してS3内のオブジェクトの場所を指定できる
  • Node.js or Python関数の場合で依存関係がない限りテンプレートにインラインで関数コードを指定できる

⭐️ 暗号化ヘルパー

  • Lambdaコンソールを使用すると、環境変数の値をLambdaに送信する前にクライアント側で暗号化できる
  • これによりLambdaコンソール、またはLambda APIに返される関数の設定で、シークレットが暗号化されずに表示されることを防止することができる

◆ プッシュイベントモデルとプルイベントモデル

  • (1)Pushイベント

    • ユーザーのアプリケーションからLambdaへ向けてイベントを発行し、コードを実行できる
    • Lambda関数に対してイベントが送信され、送信元のイベントがLambda関数を実行
    • Lambda関数のリソースポリシーで送信元からのInvokeFunctionアクションを許可する必要あり
  • (2)Pullイベント

    • Lambdaサービスがイベント元になっているリソースにデータを取りにいく
    • リソースポリシーは必要ない
    • Lambdaに割り当てるIAMロールにアタッチするIAMポリシーで、イベントリソースに対して権限を許可する必要あり

◆ Lambdaのモニタリング

  • Lambda関数からの出力はCloudWatch Logsに書き込まれる

◆ Lambdaのデプロイ

①ランタイムを決めてLambda関数を作成する
②IAMポリシーをアタッチしたIAMロールを割り当てる
③ハンドラを持つコードとそのコードが参照するライブラリ、といった依存関係をZIPにまとめてLambda関数にアップロード
④テストして出力をCloudWatch Logsで確認
⑤運用開始後は、CloudWatch, X-rayでモニタリング

*ZIPファイルが10MBよりも大きい時は、一度、S3バケットにアップロードしてからLambdaへデプロイ

◆ バージョニングとエイリアス

  • Lambda関数ではバージョン(1,2,3,latest)を作成することができるので、コードの更新時はバージョンを作成して更新
  • バージョンとエイリアスを組み合わせることで、リソースやロールバックを安全に行うことができる
  • エイリアスにはバージョンを紐付ける
  • Lambda関数を実行するARNでは、エイリアスも指定できる
  • Lambda関数エイリアスにトラフィック処理を設定することで、エイリアスを介して複数バージョン間の切り替え可能
  • LambdaエイリアスはLambda関数の特定のバージョンに対するポインタ

◆ Lambdaオーソライザー

◆ Dead Letter Queue(DLQ)

  • Lambdaイベント実行に失敗した処理をDLQに蓄積できる
  • DLQ内を調査

◆ 呼び出しタイプ(同期、非同期、ストリーム)

  • 実行トリガーによって呼び出しタイプが異なる。それによってAWS側でリトライが実行されるのか、ユーザー側でリトライを実装する必要があるか変わってくる
  • Lambda関数を実行(Invoke)する時にInvocationTypeを指定することできる
種類 説明
Event ・非同期実行
・Lambda関数が直接実行されるのではなく、キューイングされた後に実行
・Lambda関数自体は、キューから実行される
・呼び出しに失敗したら自動的に2回リトライ
・失敗後でDLQを指定した場合はSQSやSNSに送信することできる
RequestResponse ・同期実行、キューイングされずに実行
・AWSでのリトライ処理はなく実行は1回
DryRun ・関数を実行せずに必要な権限がついているかを確認できる
・クロスアカウントでの実行時の権限確認などできる

◆ Lambdaの制限

*「同時実行数」「関数とレイヤーの合計容量」以外は引き上げ申請できない

  • 同時実行数 : リージョンごとに1,000、引き上げ申請が可能に
  • 関数とレイヤーの合計容量:75GB. 引き上げ申請可能
  • 割り当てメモリ: 128-10,240MB
  • タイムアウト : 最長15min
  • 関数に設定できるレイヤー: 5つのレイヤー
  • 関数ごとのデプロイパッケージ: アップロード時のZIP 50MB. レイヤー含む解凍合計サイズ250MB(展開パッケージのサイズ制限)
  • /tmpディレクトリ: 512MB

####◆ Lambda関数のパフォーマンス向上

①メモリを増やす
②CloudWatch Logsの有効期限ポリシーを設定したり、各ロググループの保持ポリシーを調整してログ数を削減

◆ Lambdaのメトリクス

用語 説明
Invocations 呼び出し実行数(請求対象リクエスト数)
ConcurrentExecutions 実行された関数インスタンスの数
Errors タイムアウトなどのランタイムエラー、コードによって例外処理したエラーの総数
Throttles スロットリングされた数が記録される
Duration 関数が実行された時間

◆ その他

★DynamoDBテーブルに何か書き込まれたとき、Lambda実行
・DynamoDBストームを用いて、トリガーする
・Lambda側の設定も必要⇒DynamoDBストームのARNを関連付ける

  • Lambda関数の同時実行するを超えてリクエストを受けた場合、RateExceededエラーを受け取る

  • Lambdaエイリアス: 関数の特定のバージョンに対するポインタのようなもの

  • Lambda環境変数 : 変更の可能性があるパラメータを環境変数にしておけば、コードの変更をすることなく更新できる。Max512KBしか入らないので、それ以上の暗号化したい場合は、暗号化SDKを使う

  • 暗号化ヘルパー : 環境変数の値をLambdaに送信する前に、クライアント側で暗号できる

  • Lambdaプロキシ統合 : APIへのリクエストに含まれる情報を自動でLambda関数に渡すことができる

  • Lambda関数にLambda関数を重ねると再帰的な実行が行われるので注意

  • 504エラー(INTEGRATION_TIMEOUTエラー): 統合失敗の応答

  • Lambdaの設定画面で、X-RAYのトレースを有効にすると自動的にロールが作成されLambdaへアクセスできる

    • xray : PutTraceSegment
    • xray : PutTelemetryRecord
  • Lambda関数内の様々なリクエストを分析したい場合は、x-ray SDKをコードに含める必要あり

  • Lambdaのデバッグ方法: SQSのDLQを使う

Lambda@Edge

  • CloudFrontの機能
  • CloudFrontのキャッシュ処理にLambda関数によるコード処理を実行することでパフォーマンス向上
  • 認証とCognitoなどのユーザー管理サービスを呼び出すことにより、Lambda関数をトリガーとして各ビューアリクエストを承認できる

API Gateway

  • REST API, HTTP API, Websocket APIの作成、公開、モニタリング、セキュリティの設定可能
  • 作成されたAPIは全て、HTTPSエンドポイントのみ公開
  • REST API実装 :(1)API Gateway + Lambda (2)ALB + ECS
  • APIのインポート機能を使用して外部の定義ファイルからREST APIをAPI Gatewayにインポートすることができる

◆ API GatewayでREST API作成

POSTリクエストのメッセージをDynamoDBに書き込み&読み込みするAPI作成

①API GatewayをRESTで作成
API Gatewayの選択&API名の入力

②リソースの作成
リソースはAPIエンドポイントで何をするAPIなのかを想像しやすくするために一般的な名詞にする

③メソッドの作成
GET&POSTを選択し、それぞれにLambda関数を選択
Lambdaプロキシ統合を使用すると、APIへのリクエストに含まれる情報をそのままLambda関数に渡す

④テスト
クエリ文字列を指定してAPI実行

⑤デプロイ
デプロイするとAPIエンドポイントURLが生成される

◆ メソッド許可

APIに対してリクエストを実行できるユーザーを制限できる

  • エンドポイントのレスポンスをキャッシュするように設定できる
  • キャッシュによってエンドポイントへの呼び出し回数を減らすことができ、また、APIへのリクエストのレイテンシーを短くすることができる
  • ステージに対してキャッシュを有効にすると、API Gatewayは秒単位で指定した有効期限(TTL)が切れるまで、エンドポイントからのレスポンスをキャッシュする
  • APIキャッシュのデフォルト値は300s(Max3600)

◆ API GatewayのHTTP504 error

  • (1) INTEGRATION_FAILURE : 統合が失敗したときのゲートウェイレスポンス

  • (2) INTEGRATION_TIMEOUT : 統合がタイムアウトした場合のゲートウェイレスポンス

  • API Gatewayリクエストのタイムアウト : 50ms-29s

◆ APIキャッシュ


用語 説明
Count APIリクエスト数
4XXError クライアント側のエラー数
5XXError サーバー側のエラー
IntegrationLatency API Gatewayがバックエンドにリクエストを送信してからレスポンスを受け取るまでの時間
Latency API Gatewayがクライアントからリクエストを受け取ってからクライアントにレスポンスを返すまでの時間
CacheHitCount 指定された期間内にAPIキャッシュから配信されたリクエストの合計数
CacheMissCount APIキャッシュが有効になっている特定の期間における、バックエンドから提供されたリクエスト数

SQS

  • リージョンを指定してキューを作成(キューはメッセージの入れ物的なもの)
  • 作成したキューに対して、メッセージを受信・送信・削除などする
  • キューにメッセージを送る側をProducer、メッセージを受信する側をConsumerと呼ぶ
  • 暗号化 : KMSと連携
用語 説明
可視性タイムアウト コンシューマーが処理中に他のコンシューマーにキューを見えないようにする
デッドレターキュー 可視性タイムアウトの制限回数を決めて置き、制限に達したメッセージをあらかじめ指定しておいた他のキューへ移動
ロングポーリング コンシューマーからキューに対してメッセージ受信リクエストを実行するタイミングを長くする(コスト最適化)
共有キュー キューポリシーを作成できる。別のアカウントへのメッセージ送信を許可するポリシー

◆ キューの作成・管理

  • CreateQueue : キューを新規作成。属性には、キューに格納するメッセージのデフォルト値を設定

  • SetQueueAttributes : 既存のキューの属性を変更

  • GetQueueAttributes : 既存のキューの属性を取得して確認

  • GetQueueUrl : キューにAPIリクエストを実行するときのエンドポイントキューURL (ex: http://sqs.us-east-1.amazonaws.com/1233454/QueueName)

  • ListQueues : 指定したリージョンのキューURLの一覧を取得。QueuenamePrefixを使用して名前でフィルタリング可能

  • DeleteQueue : キューにメッセージがあるかどうかに関係なく、キューを削除

  • PurgeQueue : キューの中の全てのメッセージ削除

◆ メッセージの操作

  • SendMessage

  • ReceiveMessage : コンシューマーがメッセージを送信、ポーリングする

  • DeleteMessage

  • DeleteMessageBatch

  • PurgeQueue

◆ SQS Extended Client Library

  • SQSで扱えるメッセージの最大サイズは256KB
  • 256KBを超えるサイズのメッセージは、S3バケットに格納

SNS

  • 様々なメッセージ通知を効率的に行える
  • パブリッシャーが送信したメッセージを、あらかじめサブスクリプション設定済みのサブスクライバーにPUSH

◆ ファンアウト

  • SNSとSQSでファンアウトという設計がよくある
  • 1つのメッセージを複数のサブスクライバーにプッシュ+並列処理

◆ SNSの基本機能

  • (1)フィルターポリシー

    • サブスクリプションごとにフィルターポリシーを設定することできる
  • (2)トピックポリシー

    • 別アカウントへのメッセージのパブリッシュを許可するポリシー

◆ SNSトピック作成

  • CreateTopic
  • Subscribe
  • DeleteTopic

◆ メッセージ操作

  • Publish

Step Functions

  • マイクロサービスを組み合わせて簡単にワークフローを作成・制御できる
  • ステート(状態遷移)を管理するステートマシンというリソースを作成
  • 制御ロジックの実装が容易になり、制御そのものをStep Functionsに任せることができ、処理コードの開発とモニタリングに注力できる

◆ Step Functionsの実行

  • StartExecution API実行
  • CloudWatch Eventsルール実行
  • API Gatewayによる結合実行

CloudTrail

  • Cloudrailは、AWSアカウント上で行われたAPIアクションのほとんどを記録
  • ログをS3バケットに保存
  • CloudTrailを有効にすることで、追跡可能性を有効にできる

kinesis

◆ Kinesis シャードが不十分

  • リシャーディング : シャードを分割するとコストは上がるがパフォーマンスは向上する
  • インスタンスの増強 : より多くのレコードプロセッサを処理できる

◆Kinesis Data Streamsが時間と共にスケール

  • シャードの追加
  • パーティションキーに多数の異なる値が必要

*各データレコードに関連づけられているパーティションキーを使用して、特定のデータレコードが属するシャードを決定

Cognito(⭐️試験によく出る)

用語 説明
ユーザープール cognitoの認証機能。ユーザ管理/サインイン/サインアップ
IDプール 一時的なAWS認証情報を発行することで他のAWSサービスへのアクセスを許可させることができる

◆ Cognito Sync ➡︎ 現 AppSync

  • 独自のバックエンドなしにモバイルデバイスとweb間でユーザープロファイルデータを同期する

  • クライアントライブラリはローカルにデータをキャッシュするため、アプリはデバイスの接続状態にかかわらずデータを読み書きできる

  • デバイスがオンラインの時はデータを同期し、プッシュ同期を設定すると、アップデートが利用できることが他のデバイスにすぐに通知

  • 現在ではCognito Syncでなく AppSyncを使用することが推奨

  • 複数のデバイスで同じアプリケーションを利用していたとしても、アプリケーション関連のユーザーデータをデバイス間で同期する

  • PFS(Perfect Forward Secrecy) : ユーザー側でカスタマイズして利用できるサービスは限られており、CloudFrontとELBだけ

参考文献

3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?