20200704のAWSに関する記事は22件です。

AWS App2Container で既存アプリケーションをコンテナ化しよう

はじめに

2020/7/1 に 既存の.NET および Java アプリケーションをコンテナ化するための
AWS App2Container というツールがリリースされました。

AWS App2Container の発表 - アプリケーションをコンテナ化して AWS クラウドに移行する
https://aws.amazon.com/jp/about-aws/whats-new/2020/07/announcing-aws-app2container/

AWS App2Container は、起動中アプリケーションとその依存関係をコンテナイメージに
パッケージ化してECS タスクと Kubernetes ポッド定義を生成します。
またこれらをAWS 上にデプロイするための CloudForamtion テンプレートおよび、
CI/CD パイプライン用のテンプレートまで作成することもできます。

AWS App2Container 自体は無料で利用可能で、デプロイする AWS リソースに対し
通常の利用料金が発生します。
Javaアプリケーションのコンテナ化、ECS on Fargate と EKS のデプロイをそれぞれ実施しました。

前提条件

Java アプリケーションの場合の環境の前提条件は以下の通りです。

サポートされる Java アプリケーションフレームワーク

  • Tomcat
  • Spring Boot
  • JBoss (standalone mode)
  • Weblogic (standalone mode)
  • Websphere (standalone mode)

サポートされる Linux ディストリビューション

  • Ubuntu
  • CentOS
  • RHEL
  • Amazon Linux

また作業環境が以下の条件を満たしている必要があります。
これらのインストール手順や設定手順は割愛します。

  • AWS CLI がインストール済みであること
  • Docker Engine のインストール済みであること
  • サーバーの root アクセス権があること
  • tar コマンドが利用可能であること
  • ストレージに 20GB 以上の空き容量があること

IAM ユーザー必要な権限は以下のドキュメントに記載されています。
コンテナ化したアプリケーションをデプロイする際には、AdministratorAccess が
前提となっているようです。

App2ContainerでのIDおよびアクセス管理
https://docs.aws.amazon.com/app2container/latest/UserGuide/iam-a2c.html

今回は Amazon Linux 2 上に Spring Boot アプリケーションを起動し、検証しました。

アプリケーションの準備

Spring Boot CLI を使用して Hello World アプリケーションを準備します。
手順は以下に記載のある通りです。
https://spring.pleiades.io/spring-boot/docs/current/reference/html/spring-boot-cli.html

hello.groovy
@RestController
class WebApplication {

    @RequestMapping("/")
    String home() {
        "Hello World!"
    }

}

アプリケーションを起動し、

$ spring run hello.groovy

正常に応答することを確認しておきます。

$ curl localhost:8080
Hello World!

App2Container のインストール

インストール

インストールパッケージをダウンロードし、展開します。

$ curl -o AWSApp2Container-installer-linux.tar.gz https://app2container-release-us-east-1.s3.us-east-1.amazonaws.com/latest/linux/AWSApp2Container-installer-linux.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  104M  100  104M    0     0  8360k      0  0:00:12  0:00:12 --:--:-- 9605k

$ sudo tar xvf AWSApp2Container-installer-linux.tar.gz
install.sh
README
termsandconditions.txt
security/
security/app2container.sig
security/app2container.cert
AWSApp2Container.tar.gz

install.sh を実行します。
利用規約への同意が必要です。

$ sudo ./install.sh

Determining user ...
Determining Installer Path ...
The AWS App2Container tool is licensed as "AWS Content" under the terms and conditions of the AWS Customer Agreement, located at https://aws.amazon.com/agreement and the Service Terms, located at https://aws.amazon.com/service-terms. By installing, using or accessing the AWS App2Container tool, you agree to such terms and conditions. The term "AWS Content" does not include software and assets distributed under separate license terms (such as code licensed under an open source license).
Do you accept the terms and conditions above? (y/n): y
Installing AWS App2Container ...
~~以降省略~~
Installation of AWS App2Container completed successfully!
You are currently running version 1.0.0.
To get started, run 'sudo app2container init'
AWS App2Container was installed under /usr/local/app2container/AWSApp2Container.

正常にインストールされたことを確認します。

$ sudo app2container --version
app2container version 1.0.0

初期設定

init コマンドで初期設定を行います。
内容は記載のとおりですが、コンテナ化に関連するアーティファクトの格納ディレクトリや
使用する AWS CLI のプロファイルなどが指定できます。
アーティファクトの格納先 S3 バケット(オプション) は App2Container で AWS 環境への
デプロイを行う場合は指定が必要です。

$ sudo app2container init
Workspace directory path for artifacts[default: /root/app2container]:
AWS Profile (configured using 'aws configure --profile')[default: default]:
Optional S3 bucket for application artifacts: <your_bucket_name>
Report usage metrics to AWS? (Y/N)[default: y]: N
Require images to be signed using Docker Content Trust (DCT)? (Y/N)[default: n]: N
Configuration saved

アプリケーションのコンテナ化

既存アプリケーションの分析

inventory コマンドで実行中のアプリケーションを一覧表示します。
以下の例の場合、java-generic-65424cc9 がアプリケーションIDとなり、
後続のコマンド実行時に指定が必要です。

$ sudo app2container inventory
{
                "java-generic-65424cc9": {
                                "processId": 2493,
                                "cmdline": "/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64/bin/java ... /usr/local/bin:/usr/local/lib/spring-boot-cli-2.3.1.RELEASE.jar org.springframework.boot.loader.JarLauncher run ./hello.groovy ",
                                "applicationType": "java-generic"
                }
}

analyze コマンドを実行すると、init 時に指定したアーティファクトディレクトリに
analysis.json が保存されます。アプリケーション実行のための依存関係が記述されており、
必要に応じて手動で値を書き換えることもできます。

$ sudo app2container analyze --application-id java-generic-65424cc9
✔ Created artifacts folder /root/app2container/java-generic-65424cc9
✔ Generated analysis data in /root/app2container/java-generic-65424cc9/analysis.json
? Analysis successful for application java-generic-65424cc9

? Next Steps:
1. View the application analysis file at /root/app2container/java-generic-65424cc9/analysis.json.
2. Edit the application analysis file as needed.
3. Start the containerization process using this command: app2container containerize --application-id java-generic-65424cc9

analysis.json の例 (クリックで展開)
analysis.json
{
       "a2CTemplateVersion": "1.0",
       "createdTime": "2020-07-04 09:31:254",
       "containerParameters": {
              "_comment1": "*** EDITABLE: The below section can be edited according to the application requirements. Please see the analysisInfo section below for details discovered regarding the application. ***",
              "imageRepository": "java-generic-65424cc9",
              "imageTag": "latest",
              "containerBaseImage": "amazonlinux:2",
              "appExcludedFiles": [],
              "appSpecificFiles": [],
              "applicationMode": false,
              "logLocations": [],
              "enableDynamicLogging": false,
              "dependencies": []
       },
       "analysisInfo": {
              "_comment2": "*** NON-EDITABLE: Analysis Results ***",
              "processId": 2493,
              "appId": "java-generic-65424cc9",
              "userId": "1001",
              "groupId": "1001",
              "cmdline": [
                     "/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64/bin/java",
                     "-cp",
                     "/usr/local/bin:/usr/local/lib/spring-boot-cli-2.3.1.RELEASE.jar",
                     "org.springframework.boot.loader.JarLauncher",
                     "run",
                     "./hello.groovy"
              ],
              "osData": {
                     "ANSI_COLOR": "0;33",
                     "CPE_NAME": "cpe:2.3:o:amazon:amazon_linux:2",
                     "HOME_URL": "https://amazonlinux.com/",
                     "ID": "amzn",
                     "ID_LIKE": "centos rhel fedora",
                     "NAME": "Amazon Linux",
                     "PRETTY_NAME": "Amazon Linux 2",
                     "VERSION": "2",
                     "VERSION_ID": "2"
              },
              "osName": "amzn",
              "ports": [
                     {
                            "localPort": 8080,
                            "protocol": "tcp6"
                     }
              ],
              "Properties": {
                     "classpath": "/usr/local/bin:/usr/local/lib/spring-boot-cli-2.3.1.RELEASE.jar",
                     "jdkVersion": "11.0.7"
              },
              "AdvancedAppInfo": null,
              "env": {
                     "HOME": "/home/ssm-user",
                     "JAVA_HOME": "/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64",
                     "LANG": "C.UTF-8",
                     "OLDPWD": "/usr/local",
                     "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
                     "PWD": "/home/ssm-user",
                     "SHLVL": "1",
                     "SPRING_HOME": "/usr/local",
                     "TERM": "xterm-256color"
              },
              "cwd": "/home/ssm-user",
              "procUID": {
                     "euid": "1001",
                     "suid": "1001",
                     "fsuid": "1001",
                     "ruid": "1001"
              },
              "procGID": {
                     "egid": "1001",
                     "sgid": "1001",
                     "fsgid": "1001",
                     "rgid": "1001"
              },
              "userNames": {
                     "1001": "ssm-user"
              },
              "groupNames": {
                     "1001": "ssm-user"
              },
              "fileDescriptors": [
                     "/dev/pts/8",
                     "/dev/pts/8",
                     "/dev/pts/8",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter/2.3.1.RELEASE/spring-boot-starter-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot/2.3.1.RELEASE/spring-boot-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-context/5.2.7.RELEASE/spring-context-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.3.1.RELEASE/spring-boot-autoconfigure-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.3.1.RELEASE/spring-boot-starter-logging-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar",
                     "/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64/lib/modules",
                     "/home/ssm-user/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar",
                     "/home/ssm-user/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar",
                     "/home/ssm-user/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.13.3/log4j-to-slf4j-2.13.3.jar",
                     "/home/ssm-user/.m2/repository/org/apache/logging/log4j/log4j-api/2.13.3/log4j-api-2.13.3.jar",
                     "/home/ssm-user/.m2/repository/org/slf4j/jul-to-slf4j/1.7.30/jul-to-slf4j-1.7.30.jar",
                     "/home/ssm-user/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-core/5.2.7.RELEASE/spring-core-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-jcl/5.2.7.RELEASE/spring-jcl-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/yaml/snakeyaml/1.26/snakeyaml-1.26.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.3.1.RELEASE/spring-boot-starter-web-2.3.1.RELEASE.jar",
                     "/usr/local/lib/spring-boot-cli-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.3.1.RELEASE/spring-boot-starter-json-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.0/jackson-databind-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.0/jackson-annotations-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.11.0/jackson-core-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.11.0/jackson-datatype-jdk8-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.11.0/jackson-datatype-jsr310-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.11.0/jackson-module-parameter-names-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.3.1.RELEASE/spring-boot-starter-tomcat-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.36/tomcat-embed-core-9.0.36.jar",
                     "/home/ssm-user/.m2/repository/org/glassfish/jakarta.el/3.0.3/jakarta.el-3.0.3.jar",
                     "/home/ssm-user/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.36/tomcat-embed-websocket-9.0.36.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-web/5.2.7.RELEASE/spring-web-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-beans/5.2.7.RELEASE/spring-beans-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-webmvc/5.2.7.RELEASE/spring-webmvc-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-aop/5.2.7.RELEASE/spring-aop-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-expression/5.2.7.RELEASE/spring-expression-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy-templates/2.5.12/groovy-templates-2.5.12.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy/2.5.12/groovy-2.5.12.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy/2.5.12/groovy-2.5.12.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy-xml/2.5.12/groovy-xml-2.5.12.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-context/5.2.7.RELEASE/spring-context-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot/2.3.1.RELEASE/spring-boot-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.3.1.RELEASE/spring-boot-autoconfigure-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-beans/5.2.7.RELEASE/spring-beans-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-web/5.2.7.RELEASE/spring-web-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter/2.3.1.RELEASE/spring-boot-starter-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.3.1.RELEASE/spring-boot-starter-logging-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar",
                     "/home/ssm-user/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar",
                     "/home/ssm-user/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar",
                     "/home/ssm-user/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.13.3/log4j-to-slf4j-2.13.3.jar",
                     "/home/ssm-user/.m2/repository/org/apache/logging/log4j/log4j-api/2.13.3/log4j-api-2.13.3.jar",
                     "/home/ssm-user/.m2/repository/org/slf4j/jul-to-slf4j/1.7.30/jul-to-slf4j-1.7.30.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-core/5.2.7.RELEASE/spring-core-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-jcl/5.2.7.RELEASE/spring-jcl-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/yaml/snakeyaml/1.26/snakeyaml-1.26.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.3.1.RELEASE/spring-boot-starter-web-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.3.1.RELEASE/spring-boot-starter-json-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.0/jackson-databind-2.11.0.jar",
                     "/usr/local/lib/spring-boot-cli-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.0/jackson-annotations-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.11.0/jackson-core-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.11.0/jackson-datatype-jdk8-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.11.0/jackson-datatype-jsr310-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.11.0/jackson-module-parameter-names-2.11.0.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.3.1.RELEASE/spring-boot-starter-tomcat-2.3.1.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.36/tomcat-embed-core-9.0.36.jar",
                     "/home/ssm-user/.m2/repository/org/glassfish/jakarta.el/3.0.3/jakarta.el-3.0.3.jar",
                     "/home/ssm-user/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.36/tomcat-embed-websocket-9.0.36.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-webmvc/5.2.7.RELEASE/spring-webmvc-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-aop/5.2.7.RELEASE/spring-aop-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/springframework/spring-expression/5.2.7.RELEASE/spring-expression-5.2.7.RELEASE.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy-templates/2.5.12/groovy-templates-2.5.12.jar",
                     "/home/ssm-user/.m2/repository/org/codehaus/groovy/groovy-xml/2.5.12/groovy-xml-2.5.12.jar"
              ],
              "dependencies": {}
       }


コンテナ化

containerize コマンドでアプリケーションをコンテナ化できます。
この際、AWS CLI に適切なクレデンシャル情報が設定されている必要があります。
(sudo で実行する場合、root ユーザーに設定されたプロファイル)
現在のところ、EC2 でインスタンスプロファイルを設定している場合でも、IAM ロールの
一時クレデンシャルは使用されないようですので、アクセスキーを別途設定しています。

$ sudo app2container containerize --application-id java-generic-65424cc9
✔ AWS prerequisite check succeeded
✔ Docker prerequisite check succeeded
✔ Extracted container artifacts for application
✔ Entry file generated
✔ Dockerfile generated under /root/app2container/java-generic-65424cc9/Artifacts
✔ Generated dockerfile.update under /root/app2container/java-generic-65424cc9/Artifacts
✔ Generated deployment file at /root/app2container/java-generic-65424cc9/deployment.json
? Containerization successful. Generated docker image java-generic-65424cc9

? You're all set to test and deploy your container image.

Next Steps:
1. View the container image with "docker images" and test the application.
2. When you're ready to deploy to AWS, please edit the deployment file as needed at /root/app2container/java-generic-65424cc9/deployment.json.
3. Generate deployment artifacts using "app2container generate app-deployment --application-id java-generic-65424cc9"

containerize コマンドにより generate app-deployment コマンド実行時に必要な
deployment.json や Dockerfile、コンテナイメージなどが生成されます。

$ sudo tree /root/app2container/java-generic-65424cc9/
/root/app2container/java-generic-65424cc9/
├── Artifacts
│   ├── ContainerFiles.tar ★アプリケーション実行の依存関係をまとめた tar
│   ├── Dockerfile 
│   ├── Dockerfile.update ★ 作成されたイメージをベースイメージとした Dockerfile のサンプル
│   ├── entryfile ★ コンテナ起動時の CMD 
│   └── excludedFiles ★ コンテナ化時に除外されたファイルのリスト
├── analysis.json
└── deployment.json

Dockerfile の例 (クリックで展開)
FROM amazonlinux:2
MAINTAINER AWS
WORKDIR /
# Copying Entryfile
COPY entryfile /entryfile
# Pre install packages
RUN yum -y install tar && yum -y install gzip && yum -y install shadow-utils.x86_64
# Adding and unpacking Tar file
COPY ContainerFiles.tar /
RUN tar xvfP /ContainerFiles.tar --directory / --skip-old-files --same-owner --ignore-failed-read && rm -rf /ContainerFiles.tar
# Follow the below example to update files# COPY ["generic_config_file", "/root/app2container/java-generic-65424cc9/Artifacts/generic_config_file"]# Environment Variables
ENV HOME /home/ssm-user
ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64
ENV PWD /home/ssm-user
ENV TERM xterm-256color
ENV LANG C.UTF-8
ENV OLDPWD /usr/local
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
ENV SHLVL 1
ENV SPRING_HOME /usr/local
# Exposing ports
EXPOSE 8080
# User and user group
RUN groupadd -f -r -g 1001 ssm-user
RUN id -u ssm-user > /dev/null 2>&1 || useradd -r -g 1001 -u 1001 ssm-user
USER ssm-user:ssm-user
WORKDIR /home/ssm-user
# Image Entrypoint
CMD /entryfile


deployment.json についても 手動で編集することが可能です。
ECS のパラメーターについて、デフォルトで cpu:2, memory:4096 が設定されており、
Fargate タスク実行時のリソースとして確保されるようですので、必要に応じて変更すべきかと思います。

deployment.json の例 (クリックで展開)
deployment.json
{
       "a2CTemplateVersion": "1.0",
       "applicationId": "java-generic-65424cc9",
       "imageName": "java-generic-65424cc9",
       "exposedPorts": [
              {
                     "localPort": 8080,
                     "protocol": "tcp6"
              }
       ],
       "environment": [],
       "ecrParameters": {
              "ecrRepoTag": "latest"
       },
       "ecsParameters": {
              "createEcsArtifacts": true,
              "ecsFamily": "java-generic-65424cc9",
              "cpu": 2,
              "memory": 4096,
              "dockerSecurityOption": "",
              "enableCloudwatchLogging": false,
              "publicApp": true,
              "stackName": "a2c-java-generic-65424cc9-ECS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              },
              "gMSAParameters": {
                     "domainSecretsArn": "",
                     "domainDNSName": "",
                     "domainNetBIOSName": "",
                     "createGMSA": false,
                     "gMSAName": ""
              }
       },
       "eksParameters": {
              "createEksArtifacts": false,
              "stackName": "a2c-java-generic-65424cc9-EKS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              }
       }
}[


この時点で コンテナイメージが作成されているため、ローカルで実行して検証することもできます。
現在稼働中の環境を再現するためだとはおもいますが、なかなかのイメージサイズになってます。

$ sudo docker image ls
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
java-generic-65424cc9   latest              d7843b85b3b9        About an hour ago   3.95GB
amazonlinux             2                   fa0a6a710ca7        3 days ago          163MB

$ sudo docker run --rm -d -p 8080:8080 java-generic-65424cc9:latest
34e6266424e130f0b6fcb6213547cc7b744123b24805db37bea3e4da9edc094c

$ sudo docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                    NAMES
34e6266424e1        java-generic-65424cc9:latest   "/bin/sh -c /entryfi…"   6 seconds ago       Up 5 seconds        0.0.0.0:8080->8080/tcp   vigilant_lederberg

$ curl http://localhost:8080
Hello World!

アプリケーションのデプロイ

デプロイ用リソース作成

generate app-deployment コマンドで、アプリケーションを AWS にデプロイするための
CloudFormation テンプレート等の各種リソースが生成されます。
--deploy オプションを付与することで、そのままデプロイまで実行できますが、
ここではまずはアーティファクトの生成のみを実行します。

$ sudo app2container generate app-deployment --application-id java-generic-65424cc9
✔ AWS prerequisite check succeeded
✔ Docker prerequisite check succeeded
✔ Created ECR Repository
✔ Registered ECS Task Definition with ECS
✔ Uploaded CloudFormation resources to S3 Bucket: <your_bucket_name>
✔ Generated CloudFormation Master template at: /root/app2container/java-generic-65424cc9/EcsDeployment/ecs-master.yml
? ECS CloudFormation templates and additional deployment artifacts generated successfully for application java-generic-65424cc9

? You're all set to use AWS CloudFormation to manage your application stack.

Next Steps:
1. Edit the CloudFormation template as necessary.
2. Create an application stack using the AWS CLI or the AWS Console. AWS CLI command:

        aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/EcsDeployment/ecs-master.yml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-ECS

3. Set up a pipeline for your application stack using "app2container:

        app2container generate pipeline --application-id java-generic-65424cc9"

実行が成功すると、アーティファクトディレクトリに ECS をデプロイするための
タスク定義、CloudFormation のマスターテンプレート、パイプライン用定義ファイルが配置されます。
EKS 用のリソースはデフォルトでは作成されませんので、記事後半を参照ください。

CloudFormation ではネストされたスタックが生成されるため、残りのテンプレートは init 時に
指定した S3 バケットにアップロードされています。

$ sudo tree /root/app2container/java-generic-65424cc9/
/root/app2container/java-generic-65424cc9/
├── Artifacts
│   ├── ContainerFiles.tar
│   ├── Dockerfile
│   ├── Dockerfile.update
│   ├── entryfile
│   └── excludedFiles
├── EcsDeployment
│   └── ecs-master.yml ★ CloudForamtion テンプレート
├── analysis.json
├── deployment.json
├── pipeline.json ★ パイプライン作成用定義ファイル
└── taskDef.json ★ ECS用タスク定義

$ aws s3 ls s3://<your_bucket_name>/a2c-<application-id>/ecs/subtemplates/
2020-07-04 11:58:23      12258 ecs-cluster.yml
2020-07-04 11:58:23       2327 ecs-dns.yml
2020-07-04 11:58:24      16521 ecs-gmsa-automation-doc.yml
2020-07-04 11:58:24       2545 ecs-gmsa-execute.yml
2020-07-04 11:58:24       7216 ecs-gmsa-iam-roles.yml
2020-07-04 11:58:24       6112 ecs-gmsa-lambda-functions.yml
2020-07-04 11:58:24       3713 ecs-gmsa.yml
2020-07-04 11:58:24      16909 ecs-lb-webapp.yml
2020-07-04 11:58:24      19955 ecs-master.yml
2020-07-04 11:58:24      10882 ecs-private-app.yml
2020-07-04 11:58:24       9586 ecs-public-load-balancer.yml
2020-07-04 11:58:24       3377 ecs-vpc.yml

また、この時点で ECS へのタスク定義登録および、ECR へのイメージ push が自動で行われています。

ECS on Fargate へのデプロイ

generate app-deployment コマンドで生成された ecs-master.yml を使用してデプロイします。

$ sudo aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/EcsDeployment/ecs-master.yml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-ECS

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - a2c-java-generic-65424cc9-ECS

作成された ELB にリクエストを投げると、メッセージが返ってきました。

$ aws cloudformation describe-stacks --stack-name a2c-java-generic-65424cc9-ECS --query 'Stacks[].Outputs[2]'
[
    {
        "ExportName": "a2c-java-generic-65424cc9-ECS-PublicLoadBalancerDNSForCLIOutput",
        "OutputKey": "PublicLoadBalancerDNSName",
        "OutputValue": "a2c-j-Publi-XXXXXXXXXXXX-111111111.ap-northeast-1.elb.amazonaws.com"
    }
]

$ curl http://a2c-j-Publi-XXXXXXXXXXXX-111111111.ap-northeast-1.elb.amazonaws.com
Hello World!

コンテナを前提に作成されたアプリケーションと比較すると、事前の十分な検証が必要で
運用面等々の課題もあるかもしれませんが
数ステップでコンテナ化~ECS on Fargate へのデプロイまで行えるのは非常に魅力的です。

CI/CD パイプラインの作成

デプロイ用リソースの作成

generate pipeline を使用すると、AWS CodePipeline で CI/CD パイプラインを作成するために
必要なアーティファクトを生成することができます。
app-deployment と同様に --deploy オプションを使用することもできます。

generate pipline を実行するには、generate app-deployment で生成された pipeline.json の
releaseInfo に デプロイされた ECS のクラスタ名とサービス名を追記する必要があります。

pipeline.json
{
        "a2CTemplateVersion": "1.0",
        "sourceInfo": {
                "CodeCommit": {
                        "repositoryName": "a2c-java-generic-65424cc9-ecs",
                        "branch": "master"
                }
        },
        "imageInfo": {
                "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/java-generic-65424cc9:latest"
        },
        "releaseInfo": {
                "ECS": {
                        "beta": {
                                "clusterName": "",
                                "serviceName": "",
                                "enabled": false
                        },
                        "prod": {
                                "clusterName": "a2c-java-generic-65424cc9-ECS-Cluster",
                                "serviceName": "a2c-java-generic-65424cc9-ECS-LBWebAppStack-XXXXXXXXXXXX-Service-YYYYYYYYYYYY",
                                "enabled": true
                        }
                }
        }
}

ここでは prod に先ほどデプロイしたリソースを指定しています。
generate pipeline を実行すると、CodePipline をデプロイするための
CloudFormation と CodeDeploy 用の buildspec.ymlテンプレートが作成されます。

$ sudo app2container generate pipeline --application-id java-generic-65424cc9
✔ Created CodeCommit repository
✔ Generated buildspec file(s)
✔ Generated CloudFormation templates
✔ Committed files to CodeCommit repository
? Pipeline resource template generation successful for application java-generic-65424cc9

? You're all set to use AWS CloudFormation to manage your pipeline stack.

Next Steps:
1. Edit the CloudFormation template as necessary.
2. Create a pipeline stack using the AWS CLI or the AWS Console. AWS CLI command:

        aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/Artifacts/Pipeline/CodePipeline/ecs-pipeline-master.yml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-ecs-pipeline-stack

$ sudo tree /root/app2container/java-generic-65424cc9/
/root/app2container/java-generic-65424cc9/
├── Artifacts
│   ├── ContainerFiles.tar
│   ├── Dockerfile
│   ├── Dockerfile.update
│   ├── Pipeline
│   │   └── CodePipeline
│   │       ├── Dockerfile
│   │       ├── buildspec.yml
│   │       └── ecs-pipeline-master.yml
│   ├── entryfile
│   └── excludedFiles
├── EcsDeployment
│   └── ecs-master.yml
├── analysis.json
├── deployment.json
├── pipeline.json
└── taskDef.json

パイプラインのデプロイ

ecs-pipeline-master.yml を使用してデプロイします。
こちらもネストされたスタックとしてデプロイされます。

$ sudo aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/Artifacts/Pipeline/CodePipeline/ecs-pipeline-master.yml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-ecs-pipeline-stack

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - a2c-java-generic-65424cc9-ecs-pipeline-stack

これにより、Dockerfile および buildspec.yml が CodeCommit で管理された状態となり、
レポジトリへの変更を検知してパイプラインが起動します。
CodeBuild で コンテナイメージの Build & Push および、タスク定義の編集を行い、
ECS クラスターへのデプロイを行なう、パイプラインを簡単に作成することができます。

image.png

EKS のデプロイ

EKS デプロイ用アーティファクトの作成

EKS 関連のリソースを作成するには containerize コマンドで作成された deployment.json の
eksParameters を編集し、createEksArtifacts を true に変更する必要があります。

       "eksParameters": {
              "createEksArtifacts": true,
              "stackName": "a2c-java-generic-65424cc9-EKS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              }
       }

再度、generate app-delopyment コマンドを実行します。
pipeline.json は上書きされてしまうので、ご注意ください。

$ sudo app2container generate app-deployment --application-id java-generic-65424cc9
✔ AWS prerequisite check succeeded
✔ Docker prerequisite check succeeded
✔ Created ECR Repository
✔ Uploaded CloudFormation resources to S3 Bucket: <your_bucket_name>
✔ Generated CloudFormation Master template at: /root/app2container/java-generic-65424cc9/EksDeployment/amazon-eks-master.template.yaml
? EKS CloudFormation templates and additional deployment artifacts generated successfully for application java-generic-65424cc9

? You're all set to use AWS CloudFormation to manage your application stack.You're all set to use AWS CloudFormation to manage your application stack.

Next Steps:
1. Edit the CloudFormation template as necessary.
2. Create an application stack using the AWS CLI or the AWS Console. AWS CLI command:

        aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/EksDeployment/amazon-eks-master.template.yaml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-EKS

3. Setup a pipeline for your application stack using app2container:

        app2container generate pipeline --application-id java-generic-65424cc9

EKS クラスターデプロイ用の CloudFormation テンプレートと deployment と service を作成する
ための マニフェストファイル が作成されます。namespace が default だったりするので
こちらも必要に応じてカスタマイズします。

$ sudo tree /root/app2container/java-generic-65424cc9/
/root/app2container/java-generic-65424cc9/
├── Artifacts
│   ├── ContainerFiles.tar
│   ├── Dockerfile
│   ├── Dockerfile.update
│   ├── Pipeline
│   │   └── CodePipeline
│   │       ├── Dockerfile
│   │       ├── buildspec.yml
│   │       └── ecs-pipeline-master.yml
│   ├── entryfile
│   └── excludedFiles
├── EcsDeployment
│   └── ecs-master.yml
├── EksDeployment ★
│   ├── amazon-eks-master.template.yaml
│   └── java-generic-65424cc9.pem
├── analysis.json
├── deployment.json
├── eks_deployment.yaml ★
├── eks_service.yaml ★
├── pipeline.json
└── taskDef.json

EKS クラスターへのデプロイ

amazon-eks-master.template.yaml を使用して、EKS クラスターをデプロイします。
そこそこ時間がかかります。

$ sudo aws cloudformation deploy --template-file /root/app2container/java-generic-65424cc9/EksDeployment/amazon-eks-master.template.yaml --capabilities CAPABILITY_NAMED_IAM --stack-name a2c-java-generic-65424cc9-EKS

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - a2c-java-generic-65424cc9-EKS

EKS についても CI/CD パイプラインを作成することができますが、
手順は ECS と同様であるため割愛します。

参考

App2Container Documenet
https://docs.aws.amazon.com/app2container/latest/UserGuide/what-is-a2c.html

以上です。
参考になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Toolkit for VS Codeのセットアップ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambda 待望の RDS Proxy を CloudFormation で作ってみる

2020/06/30、RDS Proxy がプレビューを終了し、ついに GA (正式リリース) となったことが発表されました。

これまでアンチパターンと言われていた、AWS Lambda と RDS との接続について解決策のひとつとなることから、サーバーレス界隈では待望の機能であったと思います。

この記事では、CloudFormation でこの RDS Proxy を作ってみたいと思います。が、その前に、RDS Proxy について少し振り返ってみたいと思います。

RDS Proxy は AWS Lambda にとって何が嬉しいのか

AWS Lambda はいわゆるサーバーレスのサービスです。そのため、常在的に起動しているリソースは基本的にありません。なんらかのイベントが発生したことを契機に、Lambda 上で実装したアプリケーションを動作させるためのリソースがスピンアップするので、例えば HTTP 要求が着信した、特定の時刻になった、というようなイベントごとに、計算リソースが立ち上がります。

そういったサービスの性質上、同時に発生するイベントの数が多くなればなるほど、起動する AWS Lambda の数が増えることになります。500 件同時に HTTP 要求が着信すれば、500 個の AWS Lambda リソースが立ち上がっている可能性もあります。

この性質と、リレーショナルなデータベース製品との相性が、これまではアンチパターンと言われていました。Lambda のリソースは互いに疎なかたちで起動されることから、誤解を恐れずに言えば、立ち上がった Lambda の数だけデータベースとのコネクションが生成されることになり、これは一般的なフレームワークに搭載されている、いわゆる「コネクションプール」の仕組みとは大きく異なっています。

コネクションが多く生成されるほど、データベースサーバー側の消費メモリも増えることになりますが、上記のような Lambda というサービスの性質上、実装のなかでコネクションプールのような仕組みをもたせることはできず、サービスの外にコネクションプールの役割を果たす何らかのレイヤーを置く必要があるということが、容易に想像できるのではないかと思います。

このコネクションプールとしてのレイヤーを提供する役割を果たすのが、今回 GA された RDS Proxy となります。

RDS Proxy の制約

このように、AWS Lambda としては待望のリリースである RDS Proxy ですが、もちろん銀の弾丸というわけではなく、制約を理解して使っていく必要があります。いくつか、注意すべき制約をピックアップしてみます。

  1. Aurora を含む、RDS for MySQL 5.6 and 5.7、もしくは RDS for PostgreSQL 10.11 and 11.5 に対応しており、RDS MySQL 8.0 や RDS Oracle などの DB エンジンでは利用できない
  2. 自身で EC2 インスタンス上に構築した RDB と RDS Proxy を接続することはできない
  3. 書き込み用のインスタンスのみに対応しており、 読み込み専用のインスタンス (リードレプリカ) に対する RDS Proxy は作れない
  4. Aurora Serverless や Aurora Multi-Master と Proxy を接続することはできない

特に 3. のリードレプリカと Proxy が接続できない制約は、データベースへの読み込みワークロードをスケールできないので、現時点では大きいと思います。そのため、読み込みに関しては、Proxy を通さないエンドポイントを使う必要があります。ここは今後の対応に期待ですね。

CloudFormation で作ってみる

今回は、MySQL 5.7 互換の Aurora クラスターを構築し、RDS Proxy を CloudFormation から作成してみました。Aurora を配置する VPC やサブネットの ID などは、適宜変更したうえでそのまま使えるかと思います。

なお、CDK でも、2020/07/02 にリリースされた v1.49.0 から L2 Construct が追加され、RDS Proxy がかなり簡潔に書けるようになっています。こちらの README に例があるので、こちらも試してみるとよいかもしれません。

AWSTemplateFormatVersion: 2010-09-09

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Database Configuration"
        Parameters:
          - AuroraUserName
          - AuroraDatabaseName
    ParameterLabels:
      AuroraUserName:
        default: "Master User Name"
      AuroraDatabaseName:
        default: "Database Name"

Parameters:
  AuroraUserName:
    Type: String
    AllowedPattern: "[a-zA-Z0-9-]+"
    ConstraintDescription: "must be between 1 to 16 alphanumeric characters."
    Description: "The database admin account user name, between 1 to 16 alphanumeric characters."
    MaxLength: 16
    MinLength: 1
    Default: "root"

  AuroraDatabaseName:
    Type: String
    AllowedPattern: "[a-zA-Z0-9_]+"
    ConstraintDescription: "must be between 1 to 64 alphanumeric characters."
    Description: "The database name, between 1 to 64 alphanumeric characters."
    MaxLength: 64
    MinLength: 1
    Default: "test"

Resources:
  ### Aurora MySQL のパスワードを生成 ###
  AuroraMasterPassword:
    Type: AWS::SecretsManager::Secret
    Properties:
      GenerateSecretString:
        GenerateStringKey: password
        PasswordLength: 16
        SecretStringTemplate: !Sub "{\"username\":\"${AuroraUserName}\"}"
        ExcludeCharacters: "\"@/\\"

  AuroraSecretAttachment:
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId: !Ref AuroraMasterPassword
      TargetId: !Ref AuroraCluster
      TargetType: AWS::RDS::DBCluster

  ### Aurora MySQL の生成 ###
  AuroraSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: vpc-0123456789abcedfg
      GroupDescription: "Security Group for Aurora"
      SecurityGroupIngress:
        - IpProtocol: tcp
          SourceSecurityGroupId: !Ref RdsProxySecurityGroup
          FromPort: 3306
          ToPort: 3306

  AuroraSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: "Aurora Subnet Group"
      SubnetIds:
        - subnet-0123456789abcedfg
        - subnet-abcdefg0123456789

  AuroraClusterParameterGroup:
    Type: AWS::RDS::DBClusterParameterGroup
    Properties:
      Description: "Aurora Cluster Parameter Group"
      Family: aurora-mysql5.7
      Parameters:
        time_zone: UTC

  AuroraCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DatabaseName: !Ref AuroraDatabaseName
      DBClusterParameterGroupName: !Ref AuroraClusterParameterGroup
      Engine: aurora-mysql
      MasterUsername: !Ref AuroraUserName
      MasterUserPassword: !Sub "{{resolve:secretsmanager:${AuroraMasterPassword}:SecretString:password::}}"
      DBSubnetGroupName: !Ref AuroraSubnetGroup
      VpcSecurityGroupIds:
        - !Ref AuroraSecurityGroup

  AuroraParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: "Aurora Parameter Group"
      Family: aurora-mysql5.7

  AuroraInstance1:
    Type: AWS::RDS::DBInstance
    Properties:
      DBClusterIdentifier: !Ref AuroraCluster
      DBInstanceClass: db.t3.small
      DBParameterGroupName: !Ref AuroraParameterGroup
      Engine: aurora-mysql

  ### RDS Proxy の生成 ###
  ##### RDS Proxy が Aurora へ接続するためのセキュリティグループ #####
  RdsProxySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: vpc-01234567890abcdefg
      GroupDescription: "Security Group for RDS Proxy"

  ##### RDS Proxy が Aurora へ接続するためのパスワードを取得する IAM ロール #####
  RdsProxyRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: rds.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AllowGetSecretValue
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - secretsmanager:GetSecretValue
                  - secretsmanager:DescribeSecret
                Resource: !Ref AuroraSecretAttachment

  RdsProxy:
    Type: AWS::RDS::DBProxy
    Properties:
      DBProxyName: rds-proxy-for-aurora
      EngineFamily: MYSQL
      RoleArn: !GetAtt RdsProxyRole.Arn
      Auth:
        - AuthScheme: SECRETS
          SecretArn: !Ref AuroraSecretAttachment
          IAMAuth: DISABLED
      VpcSecurityGroupIds:
        - !Ref RdsProxySecurityGroup
      VpcSubnetIds:
        - subnet-0123456789abcedfg
        - subnet-abcdefg0123456789

  RdsProxyTargetGroup:
    Type: AWS::RDS::DBProxyTargetGroup
    DependsOn:
      - AuroraCluster
      - AuroraInstance1
    Properties:
      DBProxyName: !Ref RdsProxy
      DBClusterIdentifiers:
        - !Ref AuroraCluster
      TargetGroupName: default

Outputs:
  RDSProxyEndpoint:
    Value: !GetAtt RdsProxy.Endpoint
    Export:
      Name: rds-proxy-endpoint

  AuroraMasterPassword:
    Value: !Ref AuroraMasterPassword
    Export:
      Name: aurora-master-password

RDS Proxy が Aurora に接続するための接続情報を、認証情報を管理するサービスである Secrets Manager に格納する必要がある点や、RDS Proxy の Target Group を Aurora クラスターおよびインスタンスが立ち上がったあとに作成するよう、DependsOn 句で明示的に指定してあげる必要がある点などが、注意が必要です。

Lambda から利用するときは、最後に Outputs で出力した RDS Proxy の接続エンドポイントを、Lambda の環境変数などにインポートし、認証情報は Secrets Manager から取得するように実装すると良いと思います。

まとめ

CloudFormation で RDS Proxy を作る実例はあまり見かけなかったので、本記事にて取り上げてみました。次回は、実際に RDS Proxy を通した環境と通さない環境で、Lambda から接続してみてパフォーマンスがどう変わるのか、試してみたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails5.2から導入されたcredentials.yml.encの使い方

Rails5.2では新規アプリを作成した時にconfig/secrets.ymlが生成されず
代わりにconfig/credentials.yml.encが生成されるようになったみたいです。

既に本番環境などでRailsの古いバージョンで運用していてRails5.2にアップグレードする場合は
config/secrets.ymlではなく、config/credentials.yml.encの仕組みが使われるみたいです。

Rails5.2までは従来のconfig/secrets.ymlを使用するやり方などもあるみたいですが
Rails6アップグレードのことも考えconfig/credentials.yml.encを導入してみましたので
忘備録のために投稿します。

1. credentials.yml.encとmaster.keyの生成と設定

credentials.yml.encは直接エディタから編集する事はできないので、ターミナルでエディタを指定して作成、編集する。

$ EDITOR=vim bundle exec credentials:edit

ちなみに、.bash_profileなどに以下のように設定しておけば、EDITOR="vim"の指定は不要になります。

~/.bash_profile
$ echo 'export EDITOR="vim"' >> ~/.bash_profile
$ source ~/.bash_profile

$ bundle exec credentials:edit

上記のコマンドを実行すると、config/credentials.yml.encとconfig/master.keyが生成される。
config/master.keyはgitで管理しないため必ず.gitignoreに追加する。

.gitignore

# Ignore master key for decrypting credentials and more.
/config/master.key

生成されたconfig/credentials.yml.encを以下のように修正する。

config/credentials.yml.enc

# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base:
  • 今回はsecret_keyだけ設定する。AWSの設定は既存のままいくのでコメントアウトのまま
  • 上記の画面にawsのaccess_key_idやsecret_access_key、その他APIキーなどを入力すれば暗号化されて保存される
  • 環境変数など使用せず、直接入力して問題ない
  • シングルクオーテーションやダブルクオーテーションは不要

本番環境ではcredentialを使うので config/environments/production.rb で次の変数にtrueをセットする

config/environments/production.rb

config.require_master_key = true

2.Capistranoによる自動デプロイ

本番環境のshared/configにmaster.keyを配置しないとデプロイできない。
本番環境のサーバーにscpコマンドなどで、config/master.keyを転送する。

$ scp -i ~/.ssh/example.pem config/master.key ec2-user@x.x.x.x:/var/www/AppName/shared/config/master.key

ex. /var/www/AppName/shared/config/master.key

もしくは、本番環境サーバーのbashファイルにRAILS_MASTER_KEY環境変数を設定する。
Capistranoは.bash_profileに書いても読み込まれないので、~/.bashrcに記載する必要がある。
config/master.keyをRAILS_MASTER_KEYとしてexportします。つまり、.bashrcに以下のように設定する。

~/.bashrc
export RAILS_MASTER_KEY='XXXXXXXXXXXXXXXXXXX'

次に、config/deploy.rbでデプロイ時の設定ファイルにシンボリックリンクを指定する。

set :linked_files, fetch(:linked_files, []).push('config/master.key')

3.Capistranoを使ってデプロイできれば完了。

$ bundle exec cap production deploy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでAWS S3 の大きいファイルの読込

やりたいこと

  • amazon s3 から大きめのファイルをダウンロードしたい
  • いちどに取得しよとすると大変そうなので少しずつ取得したい。
  • PHP で取得を行う

接続情報を準備する

define('S3', [  
        'KEY'   => AWSのS3のKEYを設定する,
        'PASS'  => AWSのS3のパスワードを設定する,
        'DIR'   => AWSのS3のディレクトリを設定する(s3://<bucket>[/<key-or-prefix>]))
]);

接続を行う

  • AWS SDK for PHP を使用して接続する
  • Amazon S3 ストリームラッパー を使用して接続操作を行う
require_once 'aws/vendor/autoload.php';

// S3 接続を行う
$s3 = S3Client::factory([
    'credentials' => [
        'key'       => S3['KEY'],
        'secret'    => S3['PASS'],
        ],
        'region' => 'ap-northeast-1',
    'version' => 'latest',
]);
$s3->registerStreamWrapper();
  • 関数は registerStreamWrappe を使用する
  • registerStreamWrapper を使用すると、ファイルの操作と同じく S3 にアップされているファイルを操作できる。

操作を行う

  • たとえば、指定しファイルがあるか確認を行う
    $readFileName = S3['DIR'].'/確認したいファイル名.XX';
    if(file_exists($readFileName)) {
        echo 'ファイルあり';
    }
  • たとえば、freadを使用して読み込みを行う
    $readFileName = S3['DIR'].'/読み込みたいファイル名.XX';
    $fp = fopen($readFileName, "r");
    while(!feof($fp)) {
        $file = fread($fp, 4096);
    }
    close($fp);
  • 上記のことからわかるように、接続後一般的なファイル操作で S3 のファイルを操作できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AzureAD SAML SSOを使うときの SAMLRequestを生成する

前提

  • SAML初心者です
  • 全体的によくわかってないけれどやってみた結果をまとめてみました
  • ちょっと冗長です

経緯

  • AzureADをIDプロバイダ(IdP)、AWSをサービスプロバイダ(SP)として使う設定をします
  • Microsoftのチュートリアル に沿って設定しました
  • https://myapps.microsoft.com へアクセスし、Azureログインした上で、AWSアイコンをクリックすると、AWSへ設定したロールでアクセスできました

image.png

  • IdP側に各SPへのメニューがあるので、これで使えるのでまあ問題ないと思うのですが、サインオンしていない状態でSPにアクセスした場合はどうするのでしょう

調べる

  • サインオンしていない場合はIdPへリダイレクトするのが標準のようです
    • 実際そういうサービスはよく見かけます
    • 「SP-Initiated SSO」と言うようです
  • SP側から「AuthnRequest」を持ってIdPへリダイレクトするらしいです
  • 「AuthnRequest」ってなんでしょう...ありました シングル サインオンの SAML プロトコル
  • 必要な情報をXMLに詰め込んだモノみたいです。これをどうやって連携しつつIdPへリダイレクトするのでしょう...
  • IdPのsaml2受付URLへGETパラメータ SAMLRequest で指定するようです
    • https://idp.example.com/saml2?SAMLRequest=連携情報
  • GETパラメータにXMLそのまま載せられないですよね。どうするんだろう...
  • みつけました 「DeflateしてBase64エンコードしてURLエンコードする」難易度高いな...
  • Deflateは圧縮ですね.とりあえずpythonで試すので zlib でできそうです
  • 圧縮結果はバイナリなのでbase64でエンコードしてGETパラメータに乗せるのでURLエンコードするってことみたいです
  • 途中で気づいたのですが、Deflateは「ヘッダとチェックサムを含めない」という指定がありました
    • zlib.compress() だとヘッダ、チェックサムが付加されるので zlib.compressobj(wbits=) を使えば良さそうです

SP-Initiated SSOをやってみる

SAMLRequestに指定する文字列を生成する

  • AuthnRequest XML → Deflate → base64 → urlエンコードして、printしています
get_saml_request_param.py
import datetime
import zlib
from base64 import b64encode
from urllib import parse


def build_saml_request(request_id, issuer):
    issue_instant=datetime.datetime.utcnow().isoformat(timespec='milliseconds') # 現在時刻でいいかな
    return f'''
        <samlp:AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
            ID="{request_id}" Version="2.0" IsPassive="false" ForceAuthn="false"
            IssueInstant="{issue_instant}Z"
            xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
            <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">{issuer}</Issuer>
        </samlp:AuthnRequest>'''

def deflate(text):
    compressobj = zlib.compressobj(wbits=-zlib.MAX_WBITS)
    return compressobj.compress(text.encode()) + compressobj.flush()

def get_saml_request_param(text):
    return parse.quote_plus(b64encode(deflate(text)))

saml_request_text = build_saml_request(
    request_id='id356a192b7913b04c54574d18c28d46e6395428ab', # 実際はハッシュとかにするのかな
    issuer='https://signin.aws.amazon.com/saml')             # Identifier (Entity ID)

print(get_saml_request_param(saml_request_text))
  • request_id は適当(ただし英字から始める必要あり)
  • issuer はAzure側のSAML SSO設定の値 Identifier (Entity ID) を使います

image.png

  • 実行すると下記のようになります
  • 出力された長い文字列を使います
$ python get_saml_request_param.py
jZFNS8NAEIbv%2FRVh7002X226JIWgCIUK0loP3qab0S5kd%2BPOpoq%2F3hotGgR1jgPvxzwzCT6nJNBtJ%2BreH8wGn3okH7zo1lDFemeEBVIkDGgk4aXY1tdrkYRcaPTQgAc2Cb7N6rJiqknzGcSLZD9fxOmeZzLP8nnWxIVMiiab4Sxd5FlSwJ4Fd%2BhIWVOxkyULVnQDROqIFXuAlpAFV9ZJHKqdV%2BM4oh5XhjwYf%2FLgCZ%2Fy%2BZRnt7wQeSziIuR5ej%2FW1ETo%2FCn0whrqNbotuqOSuNusK3bwviMRRaQejTIhPFMIGl6tCaXV0TupsdkASgwEf8fVOeuttC1bjvTlcIH7D3A492bLv1uW0YfxV1oZ%2Ffzz8g0%3D

ブラウザからテストしてみる

  • GETすればいいので、URLを組み立てればブラウザで確認できますね
  • Azure側のSAML SSO設定ページの Login URL を使います

image.png

URLはこんな感じです(もっと長い)

https://login.microsoftonline.com/cd91xxxxxxxxxxxx/saml2

上で生成したSAMLRequest文字列をパラメータとしてくっつけます
(キチントためすなら、さらに &RelayState= + SAML SSO設定ページの Relay State を指定します)

https://login.microsoftonline.com/cd91xxxxxxxxxxxx/saml2?SAMLRequest=jZFNS8NAEIbv%2F...snip...zz8g0%3D

できたURLをブラウザで開くと、MicrosoftアカウントのSigninページが表示されて、正常にサインインできれば、AWSのコンソール画面へ遷移します :hand_splayed:
(Microsoftアカウントへログイン済みであれば、Signinページは表示されず、AWSのコンソール画面へ遷移します)

エラー

  • AADSTS750054: SAMLRequest or SAMLResponse must be present as query string parameters in HTTP request for SAML Redirect binding.
    • GETパラメータに SAMLRequest=<request> が指定されていません
  • AADSTS750056: SAML message was not properly base64-encoded.
    • SAMLRequestパラメータの内容がbase64デコードできない内容になっています
    • base64エンコードがうまくできていないか、URLエンコードが悪いかもしれません
  • AADSTS7500529: The value '1......' is not a valid SAML ID. The ID must not begin with a number.
    • AuthnRequestXML内のID値は英字から始まる必要があります。数字から始めてはいけません
  • AADSTS700016: Application with identifier 'https://signin.aws.amazon.com/saml' was not found in the directory 'cd91xxxxxxxxxxxx'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
    • AuthnRequestで指定したIssuerと一致する設定がありません。Azure SAML SSO設定の Identifier (Entity ID) を確認します

リンク

下記ページを参照させていただき、助けられました。ありがとうございます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラウド上のPython2系のスクリプトを3系に移行しアップデートする作業メモ

image.png

これは何

  • いまだに動いている Python2系のスクリプトを3系にアップデートするときの作業(事前準備含む)の備忘メモ

前提

  • pyenvを使用してPythonのバージョン管理を行っている
  • Dockerやvirtualenv, Pipenvは未使用

概要

  1. 移行するPythonを決める
  2. ローカルで検証する
  3. 本番(stg)でバージョンを上げる

手順

  • 以下で簡単に移行手順を示します

事前調査

現在の動作環境を確認

  • 使用しているOSによってアップデートする先のPythonのバージョンが限られているので、事前に調査する
  • サーバ上で pyenv install --listして、移行できるPythonのバージョンを確認する
  • 以下はLinuxのOSが Linux: Amazon Linux AMI release 2016.03 だった場合の例
[ec2-user@app]$ pyenv install --list
Available versions:
# 中略
  3.6.0
  3.6-dev
  3.6.1
  3.6.2
  3.6.3
  3.6.4
  3.7.0b2
  3.7-dev
  3.8-dev
# 後略

移行先のPythonバージョンを決定

  • 先ほどのpyenv install --listでアップデートできるバージョンの中から、Pythonのバージョンを選定する
    • パッチバージョンの数字の後にdevb* が入っているものは、stableでないバージョンなので避ける
  • Python Developer’s Guideに各バージョンのメンテナンス期限などが書かれているので、EOLができる限り長いものを選ぶ
  • 先ほどのLinux: Amazon Linux AMI release 2016.03の例では、 上記の理由より3.6.4にするのが妥当

image.png

ローカルでの動作検証

Python3系で使用できないロジックの洗い出し

  • futurizeでPythonのコードのアップデートを試みます
    • applyされなかったファイルやメソッドをについて検証していきます
  • Pythonの公式でも推奨されているやり方っぽいです

image.png

Python3系の記法に自動変換を行ってみる

  • 2to3というライブラリで、Python2でのみ通用する記法を(ある程度)自動的に3系の記法に変換してくれます
  • 3系への影響範囲が大きい場合は、こちらで一気に変換してみても良いかもしれません(過信は禁物、動作検証はすべき)
  • これも、Python3の公式ドキュメントで記載されている方法論になります

image.png

Pythonバージョンの切り替え&スクリプト実行

  • 上記のライブラリでのコードやロジックの移行にある程度目処がついたら、実際にローカルで動かしていきます
  • 主な順序は「pyenvでバージョン切り替え」「ライブラリのインストール」「スクリプトの実行」となります
  • DBとの接続が必要な部分など、ローカルだけでは完結しないロジックがある場合はスキップするなど、実行可能な部分だけでも実行する

コケた場合のバックアップ方法をメモする

  • ローカルで問題なく動作した場合、stgや本番環境のアップデートを行うことになります
  • その前に、「仮にPython3のコードでの動作に問題があった場合」の切り戻しオペレーションをドキュメントか何かに記載しておきましょう
  • 具体的に想定される切り戻し作業
    • pyenvで旧バージョンのPythonに切り替え
    • アップデートしたコードのcommitをrevertする
    • 旧バージョンでライブラリをインストールし直す

移行実施

  • 以降でいよいよ本番のスクリプトのPythonバージョンを変更していきます
  • stg環境があればstg環境で先に実施する

Pythonバージョンの切り替え

  • pyenvでPythonのバージョンを切り替えていきます
# 3.6.4をインストール
$ pyenv install 3.6.4
$ pyenv versions  
  system  
* 2.7 (set by /home/ec2-user/.pyenv/version)
  3.6.4 # 追加されているはず
$ pyenv local 3.6.4
$ pyenv rehash
$ pyenv versions  
  system  
  2.7 (set by /home/ec2-user/.pyenv/version)
* 3.6.4 # 変更されているはず
$ python --version
Python 3.6.4 # 変更されているはず

ライブラリの再インストール

  • Python3環境にライブラリをインストールします
  • 以下はrequirements.txtを用いてインストールする例です
$ pip install -r requirements.txt
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests->-r requirements.txt (line 5))
  Cache entry deserialization failed, entry ignored
  Downloading https://files.pythonhosted.org/packages/e1/e5/df302e8017440f111c11cc41a6b432838672f5a70aa29227bf58149dc72f/urllib3-1.25.9-py2.py3-none-any.whl (126kB)
    100% |████████████████████████████████| 133kB 9.1MB/s
Collecting certifi>=2017.4.17 (from requests->-r requirements.txt (line 5))
  Cache entry deserialization failed, entry ignored
  Cache entry deserialization failed, entry ignored
  Downloading https://files.pythonhosted.org/packages/57/2b/26e37a4b034800c960a00c4e1b3d9ca5d7014e983e6e729e33ea2f36426c/certifi-2020.4.5.1-py2.py3-none-any.whl (157kB)
    100% |████████████████████████████████| 163kB 7.3MB/s
# 以下略

スクリプトの動作確認

  • 手動で動かせるスクリプトの場合は、実際にスクリプトを動かしてみます
  • エラーを吐かずに想定通り動作する場合は、移行成功です
  • 一応動作ログを取得してファイルに吐き出すなり、ドキュメントに貼り付けておくなりしておくとベストです
[ec2-user@app]$ python main.py

参考ドキュメント

image.png
image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS 認定デベロッパー – アソシエイト問題集

はじめに

  • 本問題集は、私がAWS 認定デベロッパー – アソシエイトを受験するにあたって、無料の問題集が欲しいと思い作成しました。少しでも皆様のお役に立てれば幸いです。
  • ソースはAWS公式サイトを前提としています。もし、間違いが有りましたらご指摘ください。
  • 徐々に更新して問題数は増やしていこうと思っています。

問題

問1

以下に当てはまるものを選択肢から選択してください。
DynamoDBのSort Key以外に絞り込み検索を行うことが出来る。Partition Keyが同一で他のアイテムからの検索の為に使用できる。

A. Local Secondary Index(LSI)
B. Global Secondary Index(GSI)

正解を表示

問2

以下に当てはまるものを選択肢から選択してください。
DynamoDBの読み込みキャパシティーユニットの計算をしてください。項目サイズが3.5KB、1秒当たりの読込項目数が1000回/秒、強力な整合性のある読込をする場合の必要なキャパシティユニット。

A. 1000RCU
B. 2000RCU
C. 3000RCU
D. 3500RCU

正解を表示

問3

以下に当てはまるものを選択肢から選択してください。
DynamoDBの書き込みキャパシティーユニットの計算をしてください。項目サイズが1.1KB、1秒当たりの書込項目数が1000回/秒の場合の必要なキャパシティユニット。

A. 1000WCU
B. 1100WCU
C. 2000RCU
D. 4400RCU

正解を表示

問4

以下に当てはまるものを選択肢から選択してください。
DynamoDBのテーブル操作は公開APIを使用する事が出来ます。
「1件のアイテムを書き込むAPI」は何でしょうか?

A. PutItem
B. UpdateItem
C. AddItem
D. WriteItem

正解を表示

問5

以下に当てはまるものを選択肢から選択してください。
DynamoDBのテーブルからデータを読み取るには、GetItem、Query や Scan などのオペレーションを使用します。ですが、デフォルトではすべての項目属性を返します。すべての属性ではなく、一部の属性のみを取得するには、何を指定すれば良いでしょうか?

A. S3 Select
B. DynamoDB Select
C. プロジェクション式
D. ラムダ式

正解を表示

問6

以下に当てはまるものを選択肢から選択してください。
DynamoDBのテーブルの項目を自動的に削除する機能は何でしょうか?

A. Automatic deletion
B. TTL
C. VACUUM
D. SQS

正解を表示

問7

以下に当てはまるものを選択肢から選択してください。
Lambdaの関数がイベントの処理を終了すると、Lambda は呼び出しに関するメトリクスを Amazon CloudWatch に送信します。Lambdaの実行回数を計測したメトリックスを選択してください。

A. Duration
B. Throttles
C. IteratorAge
D. Invocations

正解を表示

問8

以下に当てはまるものを選択肢から選択してください。
Lambdaの関数呼び出しのパフォーマンスについてLambdaパフォーマンスメトリクスとして計測されます。イベントソースマッピングにおいてストリームの最後のデータを読み込んだ時刻からイベントをLambda関数に送信するまでの時間を計測したパフォーマンスメトリクスを選択してください。
(ストリームがレコードを受信した時刻 - イベントソースマッピングがイベントを関数に送信したときの時刻)

A. Duration
B. DeadLetterErrors
C. IteratorAge
D. Invocations

正解を表示

問9

以下に当てはまるものを選択肢から選択してください。
Lambda はイベントを処理するインスタンスの総数として同時実行メトリクスを報告しています。 プロビジョニングされた同時実行でイベントを処理している関数インスタンスの数を確認できる同時実行メトリクスを選択してください。

A. ProvisionedConcurrentExecutions
B. ProvisionedConcurrencyUtilization
C. UnreservedConcurrentExecutions
D. ConcurrentExecutions

正解を表示

問10

以下に当てはまるものを選択肢から選択してください。
Lambda の機能として、Lambda関数を異なるバージョンにデプロイ管理する事が出来る機能を選択してください。

A. タグ
B. エイリアス
C. バージョン

正解を表示

問11

以下に当てはまるものを選択肢から選択してください。
AWS Lambda では、関数の実行と保存に使用できるコンピューティングおよびストレージリソースの量が制限されています。制限の数を引き上げるには、サポートセンターコンソールにおいて上限緩和申請を行う必要が有ります。同時実行数のデフォルト制限数を以下から選択してください。

A. 100
B. 1000
C. 10000

正解を表示

問12

以下に当てはまるものを選択肢から選択してください。
Amazon DynamoDB と AWS Lambda はトリガー (DynamoDB ストリーム 内のイベントに自動的に応答するコード) を作成できます。トリガーを使用すると、DynamoDB テーブル内のデータ変更に対応するアプリケーションを構築できます。必要な設定方法を以下から選択してください。

A. 特別な設定は要らない
B. DynamoDBテーブルのストリームを有効にする
C. DynamoDBテーブルのストリームを有効にした上で、AWS Lambda 関数のイベントソースマッピングを作成する。イベントソースマッピングの --event-source にDynamoDBのARNを指定する
C. DynamoDBテーブルのストリームを有効にした上で、DynamoDBのAttributesにAWS Lambda関数のARNを設定し、イベントソースマッピングを作成する。

正解を表示

問13

以下に当てはまるものを選択肢から選択してください。
AWS Lambda 関数を使用して、Amazon Kinesis データストリームのレコードを処理できます。Lambda関数の呼び出しが増加したためにパフォーマンスが悪化しました。適切な対処方法を以下から1つ選択してください。

A. Lambda関数の割り当てメモリを増やす
B. Lambda関数のエイリアスを使用する
C. Kinesis ストリームのシャード数を増やす
D. Kinesis ストリームの割り当てメモリを増やす

正解を表示

問14

以下に当てはまるものを選択肢から選択してください。
Lambdaオーソライザーについて適切に述べているものを選択してください。

A. Lambda関数を実行する際の認証機能
B. Lambda 関数を使用して、API へのアクセスを制御する API Gateway の機能
C. Lambda 関数の新しいバージョンを自動的にデプロイし、新しいバージョンへのトラフィックを徐々に増やしていくことが出来る機能
D. Amazon RDS Proxy データベースプロキシを作成できる機能

正解を表示

問15

以下に当てはまるものを選択肢から選択してください。
Lambda環境変数を使用して、データベース接続情報などの情報を安全に保存する事が出来ます。また開発者は、コードを更新することなく関数の動作を制御出来ます。環境変数を保管時に暗号化しておきたいと思います。以下選択肢から適切なものを1つ選択してください。

A. IAMロールをLambda関数に割り当てる
B. KMSを使用する
C. Lambda Secretを使用する

正解を表示

問16

以下に当てはまるものを選択肢から選択してください。
Amazon S3やAmazon SNS などのサービスはLambda関数を非同期に呼び出してイベントを処理することが出来ます。関数を非同期的に呼び出す場合は、関数コードからのレスポンスを待機しません。
Lambda は関数の非同期イベントキューを管理し、エラー発生時に再試行を行います。関数からエラーが返された場合、Lambda はその関数をあと 2 回再試行します。
この場合、Lambda関数は合計何回実行されることになるでしょうか?

A. 2回
B. 3回
C. 4回
D. 無限

正解を表示

問17

以下に当てはまるものを選択肢から選択してください。
Amazon API Gateway は、CloudWatch にメトリクスデータを毎分送信します。
API Gateway がバックエンドにリクエストを中継してから、バックエンドからレスポンスを受け取るまでの時間を観測できるAPI Gateway メトリクスを1つ選択してください。

A. IntegrationLatency
B. Latency
C. Backend Latency

正解を表示

問18

以下に当てはまるものを選択肢から選択してください。
Lambda関数にデッドレターキューを設定することが出来ます。非同期呼び出しが失敗したイベントを送信できるトピックを選択してください。2つ選択します。

A. Amazon Simple Queue Service (SQS)
B. Amazon Simple Notification Service(SNS)
C. Amazon Kinesis
D. Amazon Simple Storage Service (S3)

正解を表示

問19

以下に当てはまるものを選択肢から選択してください。
Lambdaオーソライザーには2種類あります。以下選択肢から2つ選択してください。

A. セッションベース
B. トークンベース
C. APIベース
D. リクエストパラメータベース

正解を表示

問20

以下に当てはまるものを選択肢から選択してください。
CodeDeployのアプリケーション仕様ファイルでデプロイを管理するために CodeDeploy によって使用される YAML 形式または JSON 形式ファイルの名前。ここでは、Amazon ECS または AWS Lambda デプロイの AppSpec file の名前を指します。

A. deployspec.yaml / deployspec.json
B. appspec.yaml / appspec.json
C. codespec.yaml / codespec.json
D. deploy.yaml / deploy.json

正解を表示

問21

以下に当てはまるものを選択肢から選択してください。
AWS Lambda フックは、ライフサイクルイベントの名前の後の新しい行に文字列で指定された 1 つの Lambda 関数です。各フックはデプロイごとに 1 回実行されます。置き換えタスクセットが作成される前にタスクを実行するために使用するライフサイクルイベントを選択してください。

A. BeforeAllowTraffic
B. BeforeInstall
C. AfterInstall
D. AfterAllowTestTraffic
E. AfterAllowTraffic

正解を表示

問22

以下に当てはまるものを選択肢から選択してください。
EC2/オンプレミス のデプロイのフックは、デプロイごとに 1 回インスタンスに対して実行されます。フックには実行するスクリプトを 1 つまたは複数指定することができます。デプロイが正常に完了したことを確認するために使用するライフサイクルイベントを選択してください。

A. DownloadBundle
B. ValidateService
C. BeforeBlockTraffic
D. AfterBlockTraffic
E. BeforeAllowTraffic

正解を表示

問23

以下に当てはまるものを選択肢から選択してください。
CodePipeline パイプラインに手動の承認アクションを追加する方法を以下から選択してください。

A. 出来ない
B. CodePipelineコンソールのアクション編集ページでアクションプロバイダーの承認を[手動承認]、SNSトピックのARNを指定する
C. CodeBuildコンソールのアクション編集ページでアクションプロバイダーの承認を[手動承認]、SNSトピックのARNを指定する
D. CodeDeployコンソールのアクション編集ページでアクションプロバイダーの承認を[手動承認]、SNSトピックのARNを指定する

正解を表示

問24

以下に当てはまるものを選択肢から選択してください。
AWS CodeCommitのリポジトリ制限値について。アカウント毎にいくつまでか?

A. 100
B. 1000
C. 10000
D. 上限はない

正解を表示

問25

以下に当てはまるものを選択肢から選択してください。
CodeBuildのビルドアーティファクト (キャッシュ、ログ、出力された生のテストレポートファイルそしてビルド結果など) を保管している時の暗号化の設定方法として、記載が正しいものを選択してください。

A. デフォルトで暗号化されています。Amazon S3 のカスタマーマスターキー (CMKs) が使用されています。
B. 署名バージョン 4 の署名プロセスで署名された TLS 接続を使用して保護する
C. 暗号化する事は出来ません。

正解を表示

問26

以下に当てはまるものを選択肢から選択してください。
AWS CodeBuild でビルドを計画するにあたって、CodeBuildのビルド仕様に関して記載された仕様ファイルをソースコードに含めることにしました。適切なものを1つ選択してください。

A. deployspec.ymlをソースディレクトリのルートに配置
B. codebuild.ymlをソースディレクトリのルートに配置
C. buildspec.yml をソースディレクトリのルートに配置

正解を表示

問27

以下に当てはまるものを選択肢から選択してください。
AWS CodeBuildの環境変数のうち、ビルドが実行されている AWS リージョンを取得できるものを選択してください。

A. BUILD_DEFAUT_REGION/BUILD_REGION
B. CODE_BUILD_DEFAULT_REGION/CODE_BUILD_REGION
C. DEPLOY_DEFAULT_REGION/DEPLOY_REGION
D. AWS_DEFAULT_REGION/AWS_REGION

正解を表示

問28

以下に当てはまるものを選択肢から選択してください。
AWS CodeBuild 内でユーザーやロール、または AWS のサービスによって実行されたアクションを記録する事が出来るサービスを選択してください。

A. S3
B. CloudWatch
C. Amazon S3 Glacier
D. AWS CloudTrail

正解を表示

問29

以下に当てはまるものを選択肢から選択してください。
AWS Command Line Interface (AWS CLI)、または AWS SDK を使用して、AWS CodeBuild で使用するエンドポイントを指定する事が出来ます。
AWS CLI を使用して、AWS CodeBuild にアクセスするエンドポイントを指定するには、CodeBuild コマンドに 何の引数を指定すれば良いでしょうか?

A. --endpoint-uri 引数
B. --endpoint-url 引数
C. --access-point-uri 引数
D. --access-point-url 引数

正解を表示

問30

以下に当てはまるものを選択肢から選択してください。
AWS Elastic Beanstalkの拡張状態ヘルスレポートを有効にすることで、環境内のリソースに関する追加の情報を収集できます。Elastic Beanstalk は、収集された情報を分析して環境全体の状態をより的確に示し、アプリケーションの使用を妨げる可能性のある問題を特定する事が可能となります。
環境内で実行されている Amazon EC2 インスタンスに関する詳細なヘルス情報をするには、どのような設定を行えば良いでしょうか?

A. EC2インスタンスのヘルス情報を収集する事は出来ない
B. SSM エージェントをEC2にインストール
C. ヘルスエージェントをEC2にインストール
D. CloudWatchエージェントをEC2にインストールする

正解を表示

問31

以下に当てはまるものを選択肢から選択してください。
AWS Elastic Beanstalkのデプロイオプションについて、以下の特徴を示すものを選択してください。
低速のデプロイ方法で、かつ、デプロイ時に既存のインスタンスを更新するのではなく、常に新しいアプリケーションバージョンを新しいインスタンスにデプロイします。

A. Rolling
B. Always new deploy
C. Rolling with additional batch
D. Immutable

正解を表示

問32

以下に当てはまるものを選択肢から選択してください。
AWS Elastic Beanstalk アプリケーションで、完了するまでに長い時間がかかるオペレーションまたはワークフローを実行する場合、それらのタスクを専用のワーカー環境にオフロードできます。
ソースファイルに定期的なタスクを定義する必要が有ります。そのファイル名を選択してください。

A. batch.yaml
B. cron.yaml
C. task.yaml
D. work.yaml

正解を表示

問33

以下に当てはまるものを選択肢から選択してください。
Elastic Beanstalk コンソールまたは EB CLI を使用して新しいバージョンのアプリケーションをアップロードするたびに、Elastic Beanstalk はアプリケーションバージョンを作成します。使用しなくなったバージョンを削除しないと、最終的にはアプリケーションバージョンクォータに到達し、そのアプリケーションの新しいバージョンを作成できなくなります。
クォータに到達するのを回避する方法を選択してください。

A. アプリケーションにアプリケーションバージョンクォータ削除ポリシーを適用する
B. アプリケーションにアプリケーションバージョンライフサイクルポリシーを適用する
C. アプリケーションにアプリケーションバージョンデプロイポリシーを適用する
D. アプリケーションにアプリケーションバージョンスケジュール設定を行う

正解を表示

問34

以下に当てはまるものを選択肢から選択してください。
環境を作成するときに使用する、環境の名前、ソリューションスタックと環境リンクを設定するために、YAML 形式の環境マニフェストをアプリケーションソースバンドルのルートに含めることができます。
含めるファイルを以下から選択してください。

A. cron.yaml
B. appspec.yaml
C. conf.yaml
D. env.yaml

正解を表示

問35

以下に当てはまるものを選択肢から選択してください。
AWS SAM は、AWS でサーバーレスアプリケーションを構築するために使用することができるオープンソースフレームワークです。AWS SAM を使用してサーバーレスアプリケーションを定義するにはCloud Formationテンプレートにおいて AWS SAMテンプレート仕様を使用する必要が有ります。
必要な定義を以下選択肢から選択してください。

A. Transform: AWS::Serverless-2016-10-31
B. Serverless: AWS::Transform-2016-10-31
C. Type: AWS::Serverless-2016-10-31
D.Runtime: AWS::Serverless-2016-10-31

正解を表示

問36

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation には、スタックの管理に役立ついくつかの組み込み関数が用意されています。実行するまでわからない値をプロパティに代入するには、テンプレートで組み込み関数を使用できます。
テンプレートのリソースから属性の値を返す組み込み関数を以下から選択してください。

A. Fn::FindInAZs
B. Fn::GetAZs
C. Fn::GetAtt
D. Fn::FindInMap

正解を表示

問37

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation を使用する際、関連リソースを単一のユニットとして管理でき、これを作成、更新、削除することで、リソースのコレクションを作成、更新、削除することが出来ます。

A. テンプレート
B. コレクションセット
C. スタック
D. 変更セット

正解を表示

問38

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation の組み込み関数について
指定されたリージョンのアベイラビリティーゾーンを含んだ配列を返す組み込み関数を以下から選択してください。

A. Fn::FindInAZs
B. Fn::GetAZs
C. Fn::GetAtt
D. Fn::FindInMap

正解を表示

問39

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation のスタックで実行中のリソースに変更を加える場合、スタックを更新する必要が有りますが、実際にリソースに変更を加える前に変更点を確認する事が出来ます。

A. テンプレート
B. 変更セット
C. CodeCommit
D. CodePipeline

正解を表示

問40

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation のスタックを削除することでスタックとスタック内のすべてのリソースを削除出来ます。
スタックの削除時に、必要なスタック内のリソースを保持するには何を設定すれば良いでしょうか?

A. リソースポリシー
B. IAMポリシー
C. 削除ポリシー
D. appspec.yml

正解を表示

問41

以下に当てはまるものを選択肢から選択してください。
AWS CloudFormation において AWS 認証情報のない一時的なアクセス権をユーザーに付与する必要があります。一時的なアクセス権を付与する場合は、何を設定すれば良いでしょうか?

A. IAMユーザー
B. IAMポリシー
C. IAMロール
D. AWS Security Token Service (AWS STS)

正解を表示

問42

以下に当てはまるものを選択肢から選択してください。
AWS X-Ray はアプリケーションが処理するリクエストに関するデータを収集するサービスです。データを表示、フィルタリング、洞察を取得して問題の識別や最適化の機会を識別するために使用するツールを提供しています。インターセプター(HTTPリクエストのトレース)、クライアントハンドラー(AWS SDKクライアントの計測)、HTTPクライアントの計測が可能です。
X-Rayの概念でホスト、リクエスト、レスポンス、行った作業(開始・終了時刻、サブセグメント)、発生した問題(エラー、障害、例外)のデータを記録しているものを1つ選択してください。

A. サンプリング
B. セグメント
C. サブセグメント

正解を表示

問43

以下に当てはまるものを選択肢から選択してください。
DynamoDBの様なセグメントを送信しないサービスでは、X-Ray SDK はトレースの情報を何をもって表示するでしょうか?

A. サンプリング
B. セグメント
C. サブセグメント

正解を表示

問44

以下に当てはまるものを選択肢から選択してください。
X-Rayにおいて効率的にトレースを行ってアプリケーションが処理するリクエストの代表的なサンプルを提供するため、X-Ray SDK によってサンプリングアルゴリズムが適用され、トレースするリクエストが決定されます。デフォルトでは、X-Ray SDK は 1 秒ごとに最初のリクエスト(リザーバサイズ)と、追加リクエストの 5%(固定レート) を記録します。以下設定の場合の、トレース可能なリクエスト数を計算してください。
リザーバサイズ:30
固定レート:50%

A. 80
B. 45
C. 130
D. 150

正解を表示

問45

以下に当てはまるものを選択肢から選択してください。
X-Rayにおいてサンプリングされている場合でも、複雑なアプリケーションでは大量のデータが生成されます。AWS X-Ray コンソールでは、操作が簡単なサービスグラフのビューを提供します。特定の条件を指定してトレースを検索することが出来るものを選択してください。

A. ラムダ式
B. トレース式
C. フィルタ式
D. リクエストビュー

正解を表示

問46

以下に当てはまるものを選択肢から選択してください。
AWS X-Ray デーモンを実行するにポートをリッスンする必要が有ります。デフォルトポートについて、以下から選択してください。

A. TCPポート2000
B. UDPポート2000
C. HTTPポート80
D. HTTPSポート8080

正解を表示

問47

以下に当てはまるものを選択肢から選択してください。
ECSクラスターは、タスクまたはサービスの論理グループです。 EC2 を使用してタスクまたはサービスを実行している場合、クラスターはコンテナインスタンスのグループ化でもあります。

A. All Deployment
B. Blue-Green Deployment
C. Application Deployment
D. Traffic Deployment

正解を表示

問48

以下に当てはまるものを選択肢から選択してください。
AWS OpsWorks スタックには、一連のスタックコマンドが用意されており、このスタックコマンドを使用して、スタックのインスタンスに対してさまざまな操作を実行できます。スタック コマンドを実行するには、[Stack] ページで、[Run Command] をクリックします。インスタンスに対して指定された一連のレシピを実行するスタックコマンドを以下から選択してください。

A. Run Commands
B. Execute Recipes
C. All At Once Commands
D. Run Recipes

正解を表示

問49

AWS OpsWorksのすべてのインスタンスには、サービスと定期的に通信する AWS OpsWorks スタックエージェントがあります。AWS OpsWorks スタックでは、インスタンスの状態のモニタリングにこの通信が使用されます。エージェントとサービスとの通信が約 5 分以上途絶えると、AWS OpsWorks スタックではインスタンスが失敗したと見なすにはどのような設定を行えばよいでしょうか?

A. 出来ない
B. AWSサポートコンソールから依頼する
C. Auto healing enabledを有効にする
D. Auto Recovely を有効にする

正解を表示

問50

AWS OpsWorks スタックは、Chef クックブックを使用して、パッケージのインストールや設定、アプリケーションのデプロイなどのタスクを処理します。カスタムクックブックはオンラインリポジトリ (.zip ファイルのようなアーカイブまたは Git のような ソース管理マネージャー) に保存する必要があります。
各クックブックディレクトリには、標準ディレクトリとファイルが少なくとも 1 つ (通常はすべて)、標準の名前で含まれていますが、クックブックの属性を記したファイルを以下から選択してください。

A. recipes
B. attributes
C. configs
D. cookbooks

正解を表示

正解

問1の正解

A. Local Secondary Index(LSI)

  • DynamoDBにおいては、Partition Key とSort Keyを併せて絞り込み検索を行うことが出来ます。Sort Key以外で絞込検索を行いたいときに、Local Secondary Index(LSI)を使用します。
  • Global Secondary Index(GSI)はLSIと異なり、Partition Key属性の代わりに検索を行う為のIndexです。
  • よって正解は、AのLocal Secondary Index(LSI)となります。

ベーステーブルのプライマリキーを使用してデータのクエリを実行する必要があるのは、一部のアプリケーションだけです。ただし、代替のソートキーが役に立つ場合があります。アプリケーションにソートキーという選択肢を提供するために、Amazon DynamoDB テーブルに 1 つ以上のローカルセカンダリインデックスを作成して、それらのインデックスに対して Query または Scan リクエストを実行できます。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/LSI.html

問題文へ戻る

問2の正解

A. 1000RCU

DynamoDBの読込キャパシティユニットの計算式は以下です。

1秒辺りの読込項目数 × 項目のサイズ(4KBブロック)
※「整合性のある読込(≠強い整合性のある読込)」の場合は 上記に 1/2 を掛ける。
※項目のサイズは4KBブロックで有る。よって、3.5KBの場合は4KBとみなす。要は、4KBの入れ物の中に納まったら、4KBとみなす。4.1KBの様に4KBの入れ物に納まらなかったら、4KBのブロックを2つ消費する考え

今回の例だと、
1秒辺りの読込項目数=1000
項目のサイズ=3.5KB
なので
1000 × 1 = 1000RCUとなります。

1 つの読み込みキャパシティーユニットは、最大サイズ 4 KB の項目について、1 秒あたり 1 回の強力な整合性のある読み込み、あるいは 1 秒あたり 2 回の結果整合性のある読み込みを表します。
例えば、10 ユニットのプロビジョニングされた読み取りキャパシティーでテーブルを作成するとします。これにより、最大 4 KB の項目について、1 秒あたり 10 回の強い整合性のある読み込み、または 20 回の結果的に整合性のある読み込みを行えます。
4 KB を超える項目の読み込みには、より多くの読み取りキャパシティーユニットを消費します。たとえば、8 KB (4 KB × 2) の項目の強い整合性のある読み込みは、2 ユニットの読み込みキャパシティーユニットを消費します。同じ項目の結果的に整合性のある読み込みは、読み込みキャパシティーを 1 ユニットしか消費しません。
読み込みの項目サイズは、次の 4 KB の倍数に切り上げられます。たとえば、3,500 バイトの項目の読み込みは、4 KB の項目の読み取りと同じスループットを消費します。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/ProvisionedThroughput.html#ProvisionedThroughput.CapacityUnits.Read

問題文へ戻る

問3の正解

C. 2000WCU

DynamoDBの書込キャパシティユニットの計算式は以下です。

1秒辺りの書込項目数 × 項目のサイズ(1KBブロック)

今回の例だと、
1秒辺りの読込項目数=1000
項目のサイズ=1.1KB
なので1KBブロックが2つ必要となります。
よって、
1000 × 2 = 2000RCUとなります。

1 つの書き込みキャパシティーユニットは、最大サイズが 1 KB の項目について、1 秒あたり 1 回の書き込みを表します。
例えば、10 ユニットのプロビジョニングされた書き込みキャパシティーでテーブルを作成するとします。これにより、1 秒あたり最大でサイズが 1 KB の項目について、1 秒あたり 10 回の書き込みを行えます。
書き込みの項目サイズは、次の 1 KB の倍数に切り上げられます。たとえば、500 バイトの項目の書き込みは、1 KB の項目の書き込みと同じスループットを消費します。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/ProvisionedThroughput.html#ProvisionedThroughput.CapacityUnits.Write

問題文へ戻る

問4の正解

A. PutItem

「B. UpdateItem」は更新を掛けるAPIですので、違います。
「C. AddItem」、「D. WriteItem」というAPIは有りませんので、違います。

DynamoDBの主なAPIをまとめました。

API 説明
PutItem 項目を作成します。
GetItem 項目を読み取ります。
UpdateItem 項目を更新します。
DeleteItem 項目を削除します。
BatchGetItem 1 つ以上のテーブルから最大 100 個の項目を読み取ります。
BatchWriteItem 1 つ以上のテーブルから最大 25 個の項目を作成または削除します。

DynamoDB は、作成、読み込み、更新、削除 (CRUD) の 4 つの基本的なオペレーション機能を提供します。
PutItem — 項目を作成します。
GetItem — 項目を読み取ります。
UpdateItem — 項目を更新します。
DeleteItem — 項目を削除します。
これらの各オペレーションでは、作業対象の項目のプライマリキーを指定する必要があります。たとえば、GetItem を使用して項目を読み込むには、その項目のパーティションキーとソートキー (該当する場合) を指定する必要があります。
4 つの基本的な CRUD オペレーションに加えて、DynamoDB は以下も提供します。
BatchGetItem — 1 つ以上のテーブルから最大 100 個の項目を読み取ります。
BatchWriteItem — 1 つ以上のテーブルから最大 25 個の項目を作成または削除します。
これらのバッチ操作は、複数の CRUD オペレーションを単一のリクエストにまとめます。さらに、応答のレイテンシーを最小限に抑えるため、バッチオペレーションは項目を並列で読み書きします。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithItems.html

問題文へ戻る

問5の正解

C. プロジェクション式

プロジェクション式を使用する事で1つ以上の属性を指定して、取得する事が出来ます。

例:プロジェクション式を使用する場合(CLIの例)

aws dynamodb get-item \
    --table-name ProductCatalog \
    --key file://key.json \
    --projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"

上記例の通り、 --projection-expression を指定します。

問題文へ戻る

問6の正解

B. TTL

設定方法は、TTL属性にしたい属性を設定し、有効にするだけです。
該当の属性内の値は時間をエポック形式で含む数値データ型とします。

Amazon DynamoDB Time to Live (TTL) では、項目ごとのタイムスタンプを定義して、項目が不要になる時期を特定できます。指定されたタイムスタンプの日付と時刻の直後に、DynamoDB は書き込みスループットを消費することなく、テーブルから項目を削除します。TTL は、ワークロードのニーズに合わせて最新の状態に保たれている項目のみを保持することで、保存されたデータボリュームを削減する手段として、追加料金なしで提供されます。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/TTL.html

問題文へ戻る

問7の正解

D. Invocations

Lambdaの呼び出しメトリスの主なものを以下にまとめました。

メトリクス 説明
Invocations 関数コードが実行された回数を記録します。
Errors 関数エラーが発生した呼び出しの数。
DeadLetterErrors 非同期呼び出しの場合、Lambda がイベントをデッドレターキューに送信しようとしたが、失敗した回数。
DestinationDeliveryFailures 非同期呼び出しの場合、Lambda がイベントを送信先に送信しようとしたが、失敗した回数。
Throttles スロットリングされた呼び出しリクエストの数。AWSアカウント単位でLambdaの同時期同数超過が発生した回数
ProvisionedConcurrencyInvocations プロビジョニングされた同時実行で関数コードが実行される回数。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-invocation

問題文へ戻る

問8の正解

C. IteratorAge

Lambdaのパフォーマンスメトリスの主なものを以下にまとめました。

メトリクス 説明
Duration 関数コードがイベントの処理に費やす時間。
IteratorAge ストリームから読み取るイベントソースマッピングの場合、イベントの最後のレコードの所要時間。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-performance

問題文へ戻る

問9の正解

A. ProvisionedConcurrentExecutions

Lambdaの同時実行メトリクスを以下にまとめました。

メトリクス 説明
ConcurrentExecutions イベントを処理している関数インスタンスの数。
ProvisionedConcurrentExecutions プロビジョニングされた同時実行でイベントを処理している関数インスタンスの数。
ConcurrentExecutions イベントを処理している関数インスタンスの数。
ProvisionedConcurrencyUtilization Lambdaのバージョン、エイリアス機能を使用した場合、ProvisionedConcurrentExecutions の値を、割り当て済みのプロビジョニングされた同時実行の合計量で割った値。
UnreservedConcurrentExecutions リージョン内の同時実行が予約されていない場合に、Lambda関数が同時実行処理されているイベントの数。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-concurrency

問題文へ戻る

問10の正解

C. バージョン

バージョンを使用して、AWS Lambda 関数のデプロイを管理できます。たとえば、安定した実稼働バージョンのユーザーに影響を与えることなく、ベータテスト用の新しいバージョンの関数を公開できます。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-versions.html

問題文へ戻る

問11の正解

B. 1000

ちなみに、同時実行数は「呼び出されたイベントの数/秒 x 平均実行時間」で求められます。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/gettingstarted-limits.html

問題文へ戻る

問12の正解

C. DynamoDBテーブルのストリームを有効にした上で、AWS Lambda 関数のイベントソースマッピングを作成する。イベントソースマッピングの --event-source にDynamoDBのARNを指定する

Amazon DynamoDB は AWS Lambda と統合されているため、トリガー (DynamoDB ストリーム 内のイベントに自動的に応答するコード) を作成できます。トリガーを使用すると、DynamoDB テーブル内のデータ変更に対応するアプリケーションを構築できます。
テーブルで DynamoDB ストリーム を有効にした場合、書き込む AWS Lambda 関数にストリームの Amazon リソースネーム (ARN) を関連付けることができます。テーブルの項目が変更されるとすぐに、新しいレコードがテーブルのストリームに表示されます。AWS Lambda はストリームをポーリングし、新しいストリームレコードを検出すると、Lambda 関数を同期的に呼び出します。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.Lambda.html

AWS CLI を使用して、AWS Lambda でイベントソースを追加する事が出来ます。

$ aws lambda create-event-source-mapping --function-name ProcessDynamoDBRecords \
 --batch-size 100 --starting-position LATEST --event-source DynamoDB-stream-arn

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-ddb-example.html#with-ddb-attach-notification-configuration

問題文へ戻る

問13の正解

C. Kinesis ストリームのシャード数を増やす

Lambda関数の呼び出しが増加したためにパフォーマンスが悪化したという条件ですので、スループット向上の為、Kinesisストリームのシャード数を増やすことが有効と思われます。
Lambda関数自体の処理性能が悪い場合は、「A. Lambda関数の割り当てメモリを増やす」が有効です。
「B. Lambda関数のエイリアスを使用する」はパフォーマンスには無関係です。「D. Kinesis ストリームの割り当てメモリを増やす」はでたらめです。

シャードを追加して Kinesis ストリーム処理のスループットを向上させます。 Kinesis ストリームは 1 つ以上のシャードで構成されます。 Lambda は、最大で 1 つの同時呼び出しを使用して各シャードをポーリングします。たとえば、ストリームに 100 個のアクティブなシャードがある場合は、最大で 100 個の Lambda 関数呼び出しが同時に実行されます。シャードの数を増やすと、直接的な結果として、Lambda 関数の同時呼び出しの最大数が増えます。また、Kinesis ストリーム処理のスループットが増える場合があります。Kinesis ストリームのシャード数を増やす場合は、データの適切なパーティションキー (パーティションキーを参照) を選択していることを確認し、関連レコードが同じシャードに割り当てられ、データが適切に配分されるようにします。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/best-practices.html#stream-events

問題文へ戻る

問14の正解

B. Lambda 関数を使用して、API へのアクセスを制御する API Gateway の機能

「A. Lambda関数を実行する際の認証機能」はIAM機能です。「C. Lambda 関数の新しいバージョンを自動的にデプロイし、新しいバージョンへのトラフィックを徐々に増やしていくことが出来る機能」はLambda 関数のローリングデプロイの機能についてです。「D. Amazon RDS Proxy データベースプロキシを作成できる機能」はLambdaコンソールを使用して作成できるデータベースプロキシの事です。

Lambda オーソライザー (以前のカスタムオーソライザー) は、Lambda 関数を使用して API へのアクセスを制御する API Gateway の機能です。
Lambda オーソライザーは、OAuth や SAML などのベアラートークン認可戦略を使用する、または発信者 ID を判断するためにリクエストパラメータを使用するカスタム認証スキームを実装する場合に便利です。
クライアントが API のメソッドの 1 つにリクエストを送信すると、API Gateway は Lambda オーソライザーを呼び出します。これは発信者 ID を入力として受け取り、IAM ポリシーを出力として返します。
Lambda オーソライザーには 2 種類あります。
トークンベース の Lambda オーソライザー (TOKEN オーソライザーとも呼ばれる) は、JSON ウェブトークン (JWT) や OAuth トークンなどのベアラートークンで発信者 ID を受け取ります。
リクエストパラメータベースの Lambda オーソライザー (REQUEST オーソライザーとも呼ばれる) は、ヘッダー、クエリ文字列パラメータ、stageVariables、および $context 変数の組み合わせで、発信者 ID を受け取ります。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html

問題文へ戻る

問15の正解

B. KMSを使用する

Lambda は、環境変数を保管時に暗号化して安全に保存します。別の暗号化キーを使用したり、クライアント側で環境変数値を暗号化したり、AWS Secrets Manager で AWS CloudFormation テンプレートを使用して環境変数を設定したりするように Lambda を設定できます。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.html

問題文へ戻る

問16の正解

B. 3回

1回実行された後、2回再試行されるので、合計3回となります。

問題文へ戻る

問17の正解

A. IntegrationLatency

API Gateway メトリクスを以下まとめました。

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

問題文へ戻る

問18の正解

A. Amazon Simple Queue Service (SQS)
B. Amazon Simple Notification Service(SNS)

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-async.html#dlq

問題文へ戻る

問19の正解

B. トークンベース
D. リクエストパラメータベース

Lambda オーソライザーには 2 種類あります。

トークンベース の Lambda オーソライザー (TOKEN オーソライザーとも呼ばれる) は、JSON ウェブトークン (JWT) や OAuth トークンなどのベアラートークンで発信者 ID を受け取ります。

リクエストパラメータベースの Lambda オーソライザー (REQUEST オーソライザーとも呼ばれる) は、ヘッダー、クエリ文字列パラメータ、stageVariables、および $context 変数の組み合わせで、発信者 ID を受け取ります。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html

問題文へ戻る

問20の正解

B. appspec.yaml / appspec.json

EC2/オンプレミス デプロイの AppSpec file の名前は appspec.yml または appspec.json にする必要があります。​Amazon ECS または AWS Lambda デプロイの AppSpec file の名前は appspec.yaml または appspec.json にする必要があります。​
https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file.html

問題文へ戻る

問21の正解

B. BeforeInstall

BeforeInstall – 置き換えタスクセットが作成される前にタスクを実行するために使用します。1 つのターゲットグループが元のタスクセットに関連付けられています。オプションのテストリスナーが指定されている場合、それは元のタスクセットに関連付けられます。この時点で、ロールバックはできません。

AfterInstall – 置き換えタスクセットが作成され、ターゲットグループの 1 つがそれに関連付けられた後、タスクを実行するために使用します。オプションのテストリスナーが指定されている場合、それは元のタスクセットに関連付けられます。このライフサイクルイベントでのフック関数の結果により、ロールバックをトリガーできます。

AfterAllowTestTraffic – テストリスナーが置き換えタスクセットにトラフィックを提供した後、タスクを実行するために使用します。この時点でのフック関数の結果により、ロールバックをトリガーできます。

BeforeAllowTraffic – 2 番目のターゲットグループが置き換えタスクセットに関連付けられた後、かつ、トラフィックが置き換えタスクセットに移行される前に、タスクを実行するために使用します。このライフサイクルイベントでのフック関数の結果により、ロールバックをトリガーできます。

AfterAllowTraffic – 2 番目のターゲットグループが置き換えタスクセットにトラフィックを提供した後、タスクを実行するために使用します。このライフサイクルイベントでのフック関数の結果により、ロールバックをトリガーできます。

Amazon ECS デプロイでのフックの実行順

image.png

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#reference-appspec-file-structure-hooks-list-ecs

問題文へ戻る

問22の正解

B. ValidateService

ApplicationStop – このデプロイライフサイクルイベントは、アプリケーションリビジョンがダウンロードされる前でも発生します。アプリケーションを適切に中止するか、現在インストールされているパッケージを削除してデプロイの準備をする場合は、このイベントのスクリプトを指定できます。このデプロイライフサイクルイベントに使用される AppSpec file とスクリプトは、前回正常にデプロイされたアプリケーションリビジョンのものです。

DownloadBundle – このデプロイライフサイクルイベント中に、CodeDeploy エージェントはアプリケーションリビジョンファイルを一時的な場所にコピーします。
Amazon Linux、Ubuntu Server、および RHEL Amazon EC2 インスタンスの /opt/codedeploy-agent/deployment-root/deployment-group-id/deployment-id/deployment-archive フォルダ。
Windows Server Amazon EC2 インスタンスの C:\ProgramData\Amazon\CodeDeploy\deployment-group-id\deployment-id\deployment-archive フォルダ。
このイベントは CodeDeploy 用に予約されていて、スクリプトを実行するために使用することはできません。
DownloadBundle デプロイライフサイクルイベント中に失敗するデプロイをトラブルシューティングするには、「「不明なエラー: 読み取り用に開いていません」で失敗した DownloadBundle デプロイライフサイクルイベントのトラブルシューティング」を参照してください。

BeforeInstall – このデプロイライフサイクルイベントは、ファイルの復号や現在のバージョンのバックアップの作成などの事前インストールタスクに使用できます。

Install – このデプロイのライフサイクルイベントでは、CodeDeploy エージェントが一時的なロケーションからリビジョンファイルを最終的な送信先フォルダにコピーします。このイベントは CodeDeploy 用に予約されていて、スクリプトを実行するために使用することはできません。

AfterInstall – アプリケーションの設定や、ファイルのアクセス許可の変更などのタスクに、このデプロイライフサイクルイベントを使用できます。

ApplicationStart – 通常、このデプロイライフサイクルイベントを使用して、ApplicationStop 中に停止されたサービスを再起動します。

ValidateService – これが最後のデプロイライフサイクルイベントです。デプロイが正常に完了したことを確認するために使用されます。

BeforeBlockTraffic – このデプロイライフサイクルイベントを使用して、ロードバランサーから登録解除される前のインスタンスでタスクを実行できます。
BeforeBlockTrafficデプロイライフサイクルイベント中に失敗するデプロイをトラブルシューティングするには、「失敗した ApplicationStop、BeforeBlockTraffic、および AfterBlockTraffic デプロイライフサイクルイベントのトラブルシューティング」を参照してください。

BlockTraffic – このデプロイライフサイクルイベント中は、現在トラフィックの処理中であるインスタンスに対するインターネットトラフィックのアクセスがブロックされます。このイベントは CodeDeploy 用に予約されていて、スクリプトを実行するために使用することはできません。

AfterBlockTraffic – このデプロイライフサイクルイベントを使用して、ロードバランサーから登録解除された後のインスタンスでタスクを実行できます。
AfterBlockTraffic デプロイライフサイクルイベント中に失敗するデプロイをトラブルシューティングするには、「失敗した ApplicationStop、BeforeBlockTraffic、および AfterBlockTraffic デプロイライフサイクルイベントのトラブルシューティング」を参照してください。

BeforeAllowTraffic – このデプロイライフサイクルイベントを使用して、ロードバランサーに登録される前のインスタンスでタスクを実行できます。

AllowTraffic – このデプロイライフサイクルイベント中は、デプロイ後のインスタンスに対するインターネットトラフィックのアクセスが許可されます。このイベントは CodeDeploy 用に予約されていて、スクリプトを実行するために使用することはできません。

AfterAllowTraffic – このデプロイライフサイクルイベントを使用して、ロードバランサーに登録された後のインスタンスでタスクを実行できます。

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-server

問題文へ戻る

問23の正解

B. CodePipelineコンソールのアクション編集ページでアクションプロバイダーの承認を[手動承認]、SNSトピックのARNを指定する

https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/approvals-action-add.html#approvals-action-add-console

問題文へ戻る

問24の正解

B. 1000

AWS アカウントあたり最大 1,000 件。この制限は変更が可能です。
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/limits.html

問題文へ戻る

問25の正解

A. デフォルトで暗号化されています。Amazon S3 のカスタマーマスターキー (CMKs) が使用されています。

保管時のデータの暗号化 - ビルドアーティファクト (キャッシュ、ログ、出力された生のテストレポートファイルそしてビルド結果など) は、デフォルトで暗号化されます。この暗号化には、AWS Key Management Service が管理する Amazon S3 のカスタマーマスターキー (CMKs) が使用されます。これらの CMK を使用しない場合は、カスタマー管理 CMK を独自に作成して設定する必要があります。

ビルド出力アーティファクトを暗号化するために CodeBuild で使用する AWS KMS キーの識別子は、 CODEBUILD_KMS_KEY_ID 環境変数に保存できます。

ビルドプロジェクトの作成時にカスタマー管理 CMK を指定できます。

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/security-encryption.html

問題文へ戻る

問26の正解

C. buildspec.yml をソースディレクトリのルートに配置

buildspec をソースコードの一部として含める場合、デフォルトの buildspec ファイルの名前は buildspec.yml で、ソースディレクトリのルートに配置する必要があります。
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-name-storage

問題文へ戻る

問27の正解

D. AWS_DEFAULT_REGION/AWS_REGION

AWS CodeBuild の環境変数を以下まとめました。

CodeBuildの環境変数 説明
AWS_DEFAULT_REGION ビルドが実行されている AWS リージョン (例
AWS_REGION ビルドが実行されている AWS リージョン (例
CODEBUILD_BUILD_ARN ビルドの Amazon リソースネーム (ARN) (例
CODEBUILD_BUILD_ID ビルドの CodeBuild ID (例
CODEBUILD_BUILD_IMAGE CodeBuild ビルドイメージ識別子 (例
CODEBUILD_BUILD_NUMBER プロジェクトの現在のビルド番号。
CODEBUILD_BUILD_SUCCEEDING 現在のビルドが成功かどうか。ビルドが失敗の場合は 0 に設定され、成功の場合は 1 に設定されます。
CODEBUILD_INITIATOR ビルドを開始したエンティティ。CodePipeline でビルドが開始された場合は、パイプラインの名前を表します (例
CODEBUILD_KMS_KEY_ID CodeBuild がビルド出力アーティファクトを暗号化するために使用している AWS KMS キーの識別子 (例
CODEBUILD_LOG_PATH CloudWatch Logs でのビルドのログストリーム名。
CODEBUILD_RESOLVED_SOURCE_VERSION ビルドのソースコードのバージョンの識別子。その形式は、ソースコードリポジトリによって異なります。
CODEBUILD_SOURCE_REPO_URL 入力アーティファクトまたはソースコードリポジトリの URL。Amazon S3 では、これは s3
CODEBUILD_SOURCE_VERSION Amazon S3 では、入力アーティファクトに関連付けられたバージョン ID。CodeCommit では、ビルドするソースコードのバージョンに関連付けられたコミット ID またはブランチ名。GitHub、GitHub Enterprise Server、Bitbucket の場合、ビルドするソースコードのバージョンに関連付けられたコミット ID、ブランチ名、またはタグ名を指します。
CODEBUILD_SRC_DIR CodeBuild がビルドに使用するディレクトリパス
CODEBUILD_START_TIME Unix タイムスタンプとして指定されたビルドの開始時間 (ミリ秒単位)。
CODEBUILD_WEBHOOK_ACTOR_ACCOUNT_ID Webhook イベントをトリガーしたユーザーのアカウント ID。
CODEBUILD_WEBHOOK_BASE_REF 現在のビルドをトリガーする Webhook イベントの基本参照名。プルリクエストでは、ブランチ参照を表します。
CODEBUILD_WEBHOOK_EVENT 現在のビルドをトリガーした Webhook イベント。
CODEBUILD_WEBHOOK_PREV_COMMIT 現在のビルドをトリガーする Webhook プッシュイベントの前の最新のコミットの ID。
CODEBUILD_WEBHOOK_HEAD_REF 現在のビルドをトリガーする Webhook イベントのヘッド参照名。ブランチ参照またはタグ参照を表します。
CODEBUILD_WEBHOOK_TRIGGER ビルドをトリガーした Webhook イベントを表示します。
HOME この環境変数は常に /root に設定されます。

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-env-vars.html

問題文へ戻る

問28の正解

D. AWS CloudTrail

AWS CodeBuild は AWS CloudTrail と統合されています。
このサービスは、CodeBuild 内でユーザーやロール、または AWS のサービスによって実行されたアクションを記録するサービスです。
CloudTrail は、CodeBuild コンソールからのコールや、CodeBuild API へのコード呼び出しを含む、CodeBuild のすべての API コールをイベントとしてキャプチャします。
証跡を作成する場合は、S3 バケットへの CloudTrail イベント (CodeBuild のイベントなど) の継続的な配信を有効にすることができます。
証跡を設定しない場合でも、CloudTrail コンソールの [Event history (イベント履歴)] で最新のイベントを表示できます。
CloudTrail によって収集された情報を使用して、CodeBuild に対するリクエスト、リクエスト元の IP アドレス、リクエスト者、リクエスト日時などの詳細を確認できます。

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/cloudtrail.html

問題文へ戻る

問29の正解

B. --endpoint-url 引数

たとえば、米国東部 (バージニア北部) リージョン で連邦情報処理標準 (FIPS) エンドポイントを使用して、プロジェクトビルド名のリストを取得するには、このコマンドを実行します。

aws codebuild list-projects --endpoint-url https://codebuild-fips.us-east-1.amazonaws.com

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/endpoint-specify.html#endpoint-specify-cli

問題文へ戻る

問30の正解

C. ヘルスエージェントをEC2にインストール

環境内で実行されている Amazon EC2 インスタンスに関する詳細なヘルス情報を提供するため、Elastic Beanstalk は、拡張ヘルスをサポートする各プラットフォームのバージョンの Amazon マシンイメージ (AMI) にヘルスエージェントを含めます。
状態エージェントは、ウェブサーバーログとシステムメトリクスをモニタリングして、Elastic Beanstalk サービスに中継します。
Elastic Beanstalk は、これらのメトリクスを Elastic Load Balancing および Amazon EC2 Auto Scaling のデータと共に分析し、環境の状態に関する全体像を提示します。
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/health-enhanced.html

問題文へ戻る

問31の正解

D. Immutable

Immutable (変更不可) – 低速のデプロイ方法。
既存のインスタンスを更新するのではなく、常に新しいアプリケーションバージョンを新しいインスタンスにデプロイします。また、デプロイが失敗した場合に迅速かつ安全にロールバックできるという追加の利点もあります。
この方法では、Elastic Beanstalk は変更不可の更新を実行してアプリケーションをデプロイします。
変更不可能な更新では、環境内で 2 番目の Auto Scaling グループが起動し、新しいインスタンスがヘルスチェックに合格するまで、新しいバージョンが旧バージョンと並行してトラフィックを提供します。

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features.deploy-existing-version.html#deployments-scenarios

問題文へ戻る

問32の正解

B. cron.yaml

ソースバンドルで cron.yaml という名前のファイルに定期的なタスクを定義し、定期的な間隔でワーカー環境のキューにジョブを自動的に追加できます。
たとえば、次の cron.yaml ファイルは 2 つの定期的なタスクを作成します。
最初のタスクは 12 時間ごとに実行され、2 番目のタスクは毎日午後 11 時 (UTC) に実行されます。

version: 1
cron:
 - name: "backup-job"
   url: "/backup"
   schedule: "0 */12 * * *"
 - name: "audit"
   url: "/audit"
   schedule: "0 23 * * *"

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html#worker-periodictasks

問題文へ戻る

問33の正解

B. アプリケーションにアプリケーションバージョンライフサイクルポリシーを適用する

アプリケーションにアプリケーションバージョンライフサイクルポリシーを適用することで、クォータに到達するのを回避できます。ライフサイクルポリシーにより、古いアプリケーションバージョンを削除するか、アプリケーションの合計数が指定した数を超えた場合にアプリケーションバージョンを削除するよう Elastic Beanstalk に指示されます。
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/applications-lifecycle.html

問題文へ戻る

問34の正解

D. env.yaml

このファイル形式には環境グループのサポートが含まれます。グループを使用するには、マニフェスト内の環境の名前の末尾に +記号を指定します。環境を作成あるいは更新する場合、グループ名を --group-name (AWS CLI) または --env-group-suffix (EB CLI) と指定します。
次の例では、マニフェストが、ウェブサーバー環境に依存しているワーカー環境のコンポーネントへのリンクを持つウェブサーバー環境を定義します。マニフェストは、グループを使用して同じソースバンドルで複数の環境を作成することを許可します。

~/myapp/frontend/env.yaml
AWSConfigurationTemplateVersion: 1.1.0.0
SolutionStack: 64bit Amazon Linux 2015.09 v2.0.6 running Multi-container Docker 1.7.1 (Generic)
OptionSettings:
  aws:elasticbeanstalk:command:
    BatchSize: '30'
    BatchSizeType: Percentage
  aws:elasticbeanstalk:sns:topics:
    Notification Endpoint: me@example.com
  aws:elb:policies:
    ConnectionDrainingEnabled: true
    ConnectionDrainingTimeout: '20'
  aws:elb:loadbalancer:
    CrossZone: true
  aws:elasticbeanstalk:environment:
    ServiceRole: aws-elasticbeanstalk-service-role
  aws:elasticbeanstalk:application:
    Application Healthcheck URL: /
  aws:elasticbeanstalk:healthreporting:system:
    SystemType: enhanced
  aws:autoscaling:launchconfiguration:
    IamInstanceProfile: aws-elasticbeanstalk-ec2-role
    InstanceType: t2.micro
    EC2KeyName: workstation-uswest2
  aws:autoscaling:updatepolicy:rollingupdate:
    RollingUpdateType: Health
    RollingUpdateEnabled: true
Tags:
  Cost Center: WebApp Dev
CName: front-A08G28LG+
EnvironmentName: front+
EnvironmentLinks:
  "WORKERQUEUE" : "worker+"

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environment-cfg-manifest.html

問題文へ戻る

問35の正解

A. Transform: AWS::Serverless-2016-10-31

AWS CloudFormation によってホストされるマクロである AWS::Serverless 変換は、AWS Serverless Application Model (AWS SAM) 構文で記述されたテンプレート全体を受け取り、それを準拠した AWS CloudFormation テンプレートに変換および拡張します。
次の例では、テンプレートは AWS SAM 構文を使用して Lambda 関数とその実行ロールの宣言を簡素化しています。

Transform: AWS::Serverless-2016-10-31
Resources:
  MyServerlessFunctionLogicalID:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://testBucket/mySourceCode.zip'

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/transform-aws-serverless.html

問題文へ戻る

問36の正解

C. Fn::GetAtt

Fn::GetAtt 組み込み関数は、テンプレートのリソースから属性の値を返します。

使用方法(JSONの場合)

{ "Fn::GetAtt" : [ "logicalNameOfResource", "attributeName" ] }

使用方法(YAMLの場合)

Fn::GetAtt: [ logicalNameOfResource, attributeName ]

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html

問題文へ戻る

問37の正解

C. スタック

AWS CloudFormation を使用する際、関連リソースはスタックと呼ばれる単一のユニットとして管理します。
スタックを作成、更新、削除することで、リソースのコレクションを作成、更新、削除します。
スタック内のすべてのリソースは、スタックの AWS CloudFormation テンプレートで定義されます。
Auto Scaling グループ、Elastic Load Balancing ロードバランサー、および Amazon Relational Database Service (Amazon RDS) データベースインスタンスを含むテンプレートを作成したとします。
これらのリソースを作成するには、作成したテンプレートを送信することによってスタックを作成します。
すると、AWS CloudFormation によってすべてのリソースがプロビジョニングされます。スタックの操作には、AWS CloudFormation コンソール、API、または AWS CLI を使用できます。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#w2aab5c15b9

問題文へ戻る

問38の正解

B. Fn::GetAZs

組み込み関数 Fn::GetAZs は、指定されたリージョンのアベイラビリティーゾーンを含んだ配列を返します。アベイラビリティーゾーンへのアクセス権は顧客ごとに異なります。テンプレート作成者は、組み込み関数 Fn::GetAZs を使用することで、呼び出し元のユーザーのアクセス権にうまく適応するテンプレートを作成することができます。この方法により、特定のリージョンのすべてのアベイラビリティーゾーンをハードコーディングする必要はありません。

使用方法(JSONの場合)

{ "Fn::GetAZs" : "region" }

使用方法(YAMLの場合)

Fn::GetAZs: region

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html

問題文へ戻る

問39の正解

B. 変更セット

スタックで実行中のリソースに変更を加える必要がある場合は、スタックを更新します。リソースに変更を加える前に、変更案の概要である変更セットを生成できます。変更セットで、変更が実行中のリソース、特に重要なリソースに与える可能性のある影響を、実装前に確認できます。
たとえば、Amazon RDS データベースインスタンスの名前を変更すると、AWS CloudFormation によって新しいデータベースが作成され、古いものは削除されます。古いデータベースのデータは、バックアップしていない限り、失われます。変更セットを生成すると、変更によってデータベースが置き換えられることがわかり、スタックを更新する前に対応策を立てることができます。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#w2aab5c15c11

問題文へ戻る

問40の正解

C. 削除ポリシー

スタックを削除する場合は、削除するスタックを指定します。AWS CloudFormation はそのスタックとスタック内のすべてのリソースを削除します。AWS CloudFormation コンソール、API、または AWS CLI を使用してスタックを削除できます。
スタックを削除してもその中のいくつかのリソースを保持する場合は、削除ポリシーを使用してそのリソースを保持できます。
すべてのリソースの削除が完了すると、AWS CloudFormation はスタックが正常に削除されたというシグナルを送信します。AWS CloudFormation がリソースを削除できない場合、スタックは削除されません。削除されなかったリソースは、スタックが正常に削除されるまで保持されます。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html#w2aab5c17c17

問題文へ戻る

問41の正解

D. AWS Security Token Service (AWS STS)

「C. IAMロール」でもアクセス権を付与できますが、本設問では、一時的なという条件が有りますので、「D. AWS Security Token Service (AWS STS) 」が正解となります。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-iam-template.html#using-iam-template-grant-access

問題文へ戻る

問42の正解

B. セグメント

アプリケーションロジックを実行しているコンピューティングリソースは、セグメントとしての動作に関するデータを送信します。セグメントには、リソース名、リクエストの詳細、行った作業の詳細が含まれています。

https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-concepts.html#xray-concepts-segments

問題文へ戻る

問43の正解

C. サブセグメント

Amazon DynamoDB のような独自のセグメントを送信しないサービスでは、X-Ray はサブセグメントを使用してサービスマップ上に推測セグメントとダウンストリームノードを生成します。これにより、トレースをサポートしていない場合でも、外部の場合でも、すべてのダウンストリーム依存関係を表示することができます。
サブセグメントは、クライアントとしてのダウンストリーム呼び出しのアプリケーションビューを表します。ダウンストリームサービスも計測されている場合、送信するセグメントは、アップストリームクライアントのサブセグメントから生成された推測セグメントを置き換えます。利用可能であれば、サービスグラフのノードはサービスのセグメントからの情報を常に使用しますが、2 つのノード間のエッジはアップストリームサービスのサブセグメントを使用します。
たとえば、実装された AWS SDK クライアントで DynamoDB を呼び出すと、X-Ray SDK はその呼び出しのサブセグメントを記録します。DynamoDB はセグメントを送信しないため、トレースの推測セグメント、サービスグラフの DynamoDB ノード、およびサービスと DynamoDB の間のエッジにはサブセグメントの情報が含まれます。

https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-concepts.html#xray-concepts-subsegments

問題文へ戻る

問44の正解

B. 45

X-Rayのサンプリングルールのカスタマイズはリザーバサイズと固定レートの設定値を変更することにより実現できます。以下の計算式でトレース可能なリクエスト数を設定することが出来ます。

トレース可能なリクエスト数 = リザーバサイズ + リザーバサイズ × 固定レート

リザーバサイズ:30
固定レート:50%
の場合
トレース可能なリクエスト数 = 30 + 30 × 0.5
答え. 45

問題文へ戻る

問45の正解

C. フィルタ式

サンプリングされている場合でも、複雑なアプリケーションでは大量のデータが生成されます。AWS X-Ray コンソールでは、操作が簡単なサービスグラフのビューを提供します。問題を識別しアプリケーションを最適化するために役立つ健全性とパフォーマンス情報が表示されます。高度なトレースでは、個別のリクエストのトレースを掘り下げたり、フィルタ式を使用して特定のパスまたはユーザーに関連するトレースを検索したりできます。

https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-concepts.html#xray-concepts-filterexpressions

問題文へ戻る

問46の正解

B. UDPポート2000

AWS X-Ray デーモンは、UDP ポート 2000 のトラフィックをリッスンし、未加工のセグメントデータを収集して AWS X-Ray API に中継するソフトウェアアプリケーションです。デーモンは AWS X-Ray SDK と連動します。SDK によって送信されたデータが X-Ray サービスに到達するように実行する必要があります。

https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-daemon.html

問題文へ戻る

問47の正解

B. Blue-Green Deployment

BeanstalkのBlue-Green Deploymentを実行することで、ダウンタイムを回避できます。デプロイ後、2つの環境の CNAME を入れ替えする必要が有ります。

アプリケーションのバージョンを更新するときに AWS Elastic Beanstalk がインプレース更新を実行するため、アプリケーションはわずかな期間、ユーザーに利用不可になることがあります。Blue-Green Deployment を実行することで、このダウンタイムを回避できます。この場合、個別の環境に新しいバージョンをデプロイしてから、2 つの環境の CNAME を入れ替えて、すぐに新しいバージョンにトラフィックをリダイレクトします。

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features.CNAMESwap.html

問題文へ戻る

問48の正解

B. Execute Recipes

https://docs.aws.amazon.com/ja_jp/opsworks/latest/userguide/workingstacks-commands.html

問題文へ戻る

問49の正解

C. Auto healing enabledを有効にする

自動ヒーリングはレイヤーレベルで設定されます。次のスクリーンショットにあるように、レイヤー設定を編集することで自動ヒーリングの設定を変更できます。

https://docs.aws.amazon.com/ja_jp/opsworks/latest/userguide/workinginstances-autohealing.html

問題文へ戻る

問50の正解

B. attributes

https://docs.aws.amazon.com/ja_jp/opsworks/latest/userguide/workingcookbook-installingcustom-repo.html

問題文へ戻る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2でデプロイ時に使うコマンド

EC2 serverへ

local
$ cd .ssh
$ ssh -i XXXX.pem ec2-user@xx.xxx.xx.xxx

nginx再起動

本番環境
$ sudo service nginx restart

mysql restart

本番環境
$ sudo service mysqld restart

kill unicorn

本番環境
$ ps aux | grep unicorn
↓
ec2-user  6906  1.0 10.5 431816 106508 ?       Sl   06:49   0:02 unicorn master -c /var/www/chat-space/current/config/unicorn.rb -E deployment -D

$ kill 6906

deploy

ローカル
$ bundle exec cap production deploy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】CloudFormationでS3バケット作成とライフサイクルルールを設定する

CloudFormationでS3バケット作成、ライフサイクルルール・バケットポリシーの設定をしたのでCloudFormationのテンプレート紹介と説明をしていきます。(CloudFormationはCFnと以下略)

そもそもS3バケットの作成目的はCloudWatch LogsからS3へエクスポートするためでした。
その前提で、バケットポリシーを設定しています。
いずれCloudWatch LogsからS3へエクスポートするLambdaを開発したブログも書こうと思っています。

構築内容

  • S3バケット作成
  • ライフサイクルルールの設定
    • 30日後にストレージクラスを標準IA
    • 1年後に削除
  • バケットポリシー
    • CloudWatch LogsからS3へエクスポート可能

CFnテンプレート

GitHub Gistにもあげておきました -> s3.yml

AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  CWLogsExportBucketName:
    Description: "S3 buket name for CW Logs backup"
    Type: String
  CWLogsExportBucketLifecycleStatus:
    Description: "Apply lifecycle or not"
    Type: String
    AllowedValues: ["Disabled", "Enabled"]

Resources:
  CWLogsExportBucket:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketName:
        Ref: CWLogsExportBucketName
      AccessControl: BucketOwnerFullControl
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      LifecycleConfiguration:
        Rules:
          - ExpirationInDays: 365
            Id: CWLogsExportBucketLifecycleRule
            Status:
              Ref: CWLogsExportBucketLifecycleStatus
            Prefix: logs/
            Transitions:
              - StorageClass: STANDARD_IA
                TransitionInDays: 30
      Tags:
        - Key: "isTest"
          Value: "True"

  CWLogsExportBucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket:
        Ref: CWLogsExportBucket
      PolicyDocument:
        Statement:
          - Action:
              - "s3:GetBucketAcl"
            Effect: "Allow"
            Resource:
              Fn::Sub: "arn:aws:s3:::${CWLogsExportBucketName}"
            Principal:
              Service:
                - Fn::Sub: "logs.${AWS::Region}.amazonaws.com"
          - Action:
              - "s3:PutObject"
            Effect: "Allow"
            Resource:
              Fn::Sub: "arn:aws:s3:::${CWLogsExportBucketName}/*"
            Condition:
              StringEquals:
                s3:x-amz-acl: "bucket-owner-full-control"
            Principal:
              Service:
                - Fn::Sub: "logs.${AWS::Region}.amazonaws.com"

解説

CWLogsExportBucket

S3バケットの作成します

DeletionPolicy, UpdateReplacePolicy

スタックを削除しても作成したS3バケットは残すようにDeletionPolicyでRetainを指定します。
また、既存のS3バケットを更新する際にCFnが新たに作成し直そうとしても、既存のバケットが削除されないようにUpdateReplacePolicyで同様にRetainを指定しています。
せっかくログをS3にエクスポートしたのに設定更新のときに既存のバケットが削除されちゃった、みたいな事故を防ぐことができます。

PublicAccessBlockConfiguration

バケットの公開をブロックするための設定パラメータです。
今回は内部でしか使用しないので、明示的に全ての公開に関するブロック設定をtrueにします。
これで完全に非公開になります。

LifecycleConfiguration

ExpirationInDays

オブジェクトが作成されてから削除するまでの日数を指定します。
今回は1年保存すればいいので、365になっています。

Prefix

Prefixを指定することで、ライフサイクルルールを特定のオブジェクトだけに適用できます。
複数のオブジェクトがある場合に重宝します。

Transitions

ストレージクラスを移行するために使用します。
今回は30日経過したら標準IAのストレージクラスに移行するようにしてあります。
頻繁にログ分析をせず、バックアップ目的の場合は低アクセスのはずなので、それに見合うストレージクラスに移行するとコストカットできます。
半年経過したらGlacierに移行するってのもありですね。

CWLogsExportBucketPolicy

CWLogsExportBucketのバケットポリシーを作成します

PolicyDocument

PolicyDocumentにバケットポリシーの内容を記述していきます。
今回はCloudWatch Logsから作成したバケットにエクスポートできるように最小限のポリシーを適用しました。
ポリシーを引き受け可能なサービスをPrincipalでCloudWach Logsに限定して、Resourceで作成するS3バケットを指定することで最小限のポリシーになります。

Reference

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS IAMをまとめる

はじめに

AWSのIAMについて自分なりに理解が曖昧な部分があったので、
備忘を兼ねてまとめようかと思います。

IAMとは

IAMとは「Identity and Access Management」の略です。
AWSのリソースへのアクセスを安全にするため認証/認可サービスです。

AWSアカウント

IAMを理解する上でAWSアカウントについて知る必要があります。
AWSには大きく分けて2種類のアカウントがあります。

1. ルートアカウント(AWSアカウント)

AWSヘのサインアップ時に作成されるアカウント。
AWSの全サービスに対してネットワーク上のどこからでも操作できる権限を持っている。
請求、セキュリティ、ネットワークに関して独立している
非常に強力なアカウントであるため、利用には十分に気をつける必要がある。
日常的には、利用しないことが推奨される。

2. IAMユーザーアカウント

AWSのサービスの利用者に対して、権限を付与したアカウント。
ユーザーの権限を正しく制限することで、より安全にAWSを利用できるようになる。
日常的には、こちらを利用することが推奨される。

IAMユーザーとIAMグループ

IAMユーザー

AWSのサービスを利用するための認証情報(ID)です。
1つのAWSアカウントあたり5000ユーザーまで作成できる。
IAMユーザーの認証情報は2通りある。

1.ユーザーIDとパスワード

AWSマネジメントコンソールにログインするときに必要。
MFA(多要素認証)と併用することが推奨される。

2. アクセスキーとシークレットアクセスキー

CLI(Command Line Interface)やSDKからAWSのリソースにアクセスするときに必要。
1ユーザーあたり2つまで作成できる。

セキュリティ上、IAMユーザーのパスワードやアクセスキーID/シークレットアクセスきーはの
認証情報は定期的にローテーションすることが推奨される。

IAMグループ

IAMユーザーの集合を管理する。
1つのAWSアカウントあたり100グループまで作成できる。
グループの目的は権限を容易にかつ、正確に管理すること。
複数のユーザーに権限を個別に与えると、権限の付与もれなどのミスが
発生する恐れがあるため、グループで権限を一括して付与することでミスを防ぐ。
ユーザーは複数のグループに所属できるが、グループがグループに所属するといった
グループのネストを取ることはできない。

IAMポリシー

AWSヘのアクセスに関する権限設定を表します。
AWSのサービスとリソースに対する権限を指定します。
IAMポリシーには2種類あります。

1. 管理ポリシー

複数のIAMユーザー/IAMグループ/IAMロールに割り当てることができます。
それぞれ最大10個までの管理ポリシーを割り当てることができます。
管理ポリシーにはさらに2種類あります。

1. AWS管理ポリシー

よく利用される権限をまとめたものを、AWS側があらかじめ用意してくれているポリシー。
例)AdministratorAccess、S3FullAccess

2. カスタマー管理ポリシー

IAM管理者が定義することができるポリシー。

2. インラインポリシー

個々のIAMユーザー/IAMグループ/IAMロールに直接設定します。

IAMポリシーに設定する権限

IAMポリシーに設定する権限はJSON形式で記述される。
Effect/ Action/ Resource/ Conditionで構成される。

例えば以下のポリシーがあります。


{
    "Effect": "Allow",
    "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
    ],
    "Resource": "arn:aws:s3::::*/*",
    "Condition": {
        "IpAddress": {
            "aws:SourceIp": "172.31.1.0/24"
        }
    }

}

それぞれの要素について説明します。

・ Effect
後続のActionで指定される権限に対して、AllowまたはDenyを記述します。
Effectは「明示的Deny」をもち、あるAWSのサービスまたはリソースに対して1つでも
Denyがあれば、アクセスが拒否されます。

・ Action
Effectの対象となるAWS操作を記述します。
今回はs3のオブジェクトに対してPut、Get、Deleteの権限を与えています。
またワールドカードの指定もできるため、「s3:*」を指定することで、s3に対する
全ての権限を付与することもできる。

・ Resource
操作対象となるAWSリソースの指定をします。
指定するリソースはARN(Amazon Resource Name)で記述します。
ARNはAWSリソースに対して、一意に設定される名前となります。
ARNの記述方法は以下になります。

arn:aws:{AWSサービス名}:{リージョン名}:{アカウント名}:{リソース名}

・ Condition
アクセス権限が有効になるための条件を記述します。
Conditionが設定されていない場合は、ActionとResourceで指定されたアクセス権限が常に有効になります。

IAMロール

一時的にAWSリソースへアクセス権限を付与する場合に使用します。
IAMロールを利用すると、AWSサービスから別のAWSサービスへのアクセスを許可します。
ロールにはパスワードやアクセスキーが関連づけられない代わりに、
一時的なセキュリティ認証情報(STS)が動的に付与されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS IAMまとめ

はじめに

AWSのIAMについて自分なりに理解が曖昧な部分があったので、
備忘を兼ねてまとめようかと思います。

IAMとは

IAMとは「Identity and Access Management」の略です。
AWSのリソースへのアクセスを安全にするため認証/認可サービスです。

AWSアカウント

IAMを理解する上でAWSアカウントについて知る必要があります。
AWSには大きく分けて2種類のアカウントがあります。

1. ルートアカウント(AWSアカウント)

AWSヘのサインアップ時に作成されるアカウント。
AWSの全サービスに対してネットワーク上のどこからでも操作できる権限を持っている。
請求、セキュリティ、ネットワークに関して独立している
非常に強力なアカウントであるため、利用には十分に気をつける必要がある。
日常的には、利用しないことが推奨される。

2. IAMユーザーアカウント

AWSのサービスの利用者に対して、権限を付与したアカウント。
ユーザーの権限を正しく制限することで、より安全にAWSを利用できるようになる。
日常的には、こちらを利用することが推奨される。

IAMユーザーとIAMグループ

IAMユーザー

AWSのサービスを利用するための認証情報(ID)です。
1つのAWSアカウントあたり5000ユーザーまで作成できる。
IAMユーザーの認証情報は2通りある。

1.ユーザーIDとパスワード

AWSマネジメントコンソールにログインするときに必要。
MFA(多要素認証)と併用することが推奨される。

2. アクセスキーとシークレットアクセスキー

CLI(Command Line Interface)やSDKからAWSのリソースにアクセスするときに必要。
1ユーザーあたり2つまで作成できる。

セキュリティ上、IAMユーザーのパスワードやアクセスキーID/シークレットアクセスきーはの
認証情報は定期的にローテーションすることが推奨される。

IAMグループ

IAMユーザーの集合を管理する。
1つのAWSアカウントあたり100グループまで作成できる。
グループの目的は権限を容易にかつ、正確に管理すること。
複数のユーザーに権限を個別に与えると、権限の付与もれなどのミスが
発生する恐れがあるため、グループで権限を一括して付与することでミスを防ぐ。
ユーザーは複数のグループに所属できるが、グループがグループに所属するといった
グループのネストを取ることはできない。

IAMポリシー

AWSヘのアクセスに関する権限設定を表します。
AWSのサービスとリソースに対する権限を指定します。
IAMポリシーには2種類あります。

1. 管理ポリシー

複数のIAMユーザー/IAMグループ/IAMロールに割り当てることができます。
それぞれ最大10個までの管理ポリシーを割り当てることができます。
管理ポリシーにはさらに2種類あります。

1. AWS管理ポリシー

よく利用される権限をまとめたものを、AWS側があらかじめ用意してくれているポリシー。
例)AdministratorAccess、S3FullAccess

2. カスタマー管理ポリシー

IAM管理者が定義することができるポリシー。

2. インラインポリシー

個々のIAMユーザー/IAMグループ/IAMロールに直接設定します。

IAMポリシーに設定する権限

IAMポリシーに設定する権限はJSON形式で記述される。
Effect/ Action/ Resource/ Conditionで構成される。

例えば以下のポリシーがあります。


{
    "Effect": "Allow",
    "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
    ],
    "Resource": "arn:aws:s3::::*/*",
    "Condition": {
        "IpAddress": {
            "aws:SourceIp": "172.31.1.0/24"
        }
    }

}

それぞれの要素について説明します。

・ Effect
後続のActionで指定される権限に対して、AllowまたはDenyを記述します。
Effectは「明示的Deny」をもち、あるAWSのサービスまたはリソースに対して1つでも
Denyがあれば、アクセスが拒否されます。

・ Action
Effectの対象となるAWS操作を記述します。
今回はs3のオブジェクトに対してPut、Get、Deleteの権限を与えています。
またワールドカードの指定もできるため、「s3:*」を指定することで、s3に対する
全ての権限を付与することもできる。

・ Resource
操作対象となるAWSリソースの指定をします。
指定するリソースはARN(Amazon Resource Name)で記述します。
ARNはAWSリソースに対して、一意に設定される名前となります。
ARNの記述方法は以下になります。

arn:aws:{AWSサービス名}:{リージョン名}:{アカウント名}:{リソース名}

・ Condition
アクセス権限が有効になるための条件を記述します。
Conditionが設定されていない場合は、ActionとResourceで指定されたアクセス権限が常に有効になります。

IAMロール

一時的にAWSリソースへアクセス権限を付与する場合に使用します。
IAMロールを利用すると、AWSサービスから別のAWSサービスへのアクセスを許可します。
ロールにはパスワードやアクセスキーが関連づけられない代わりに、
一時的なセキュリティ認証情報(STS)が動的に付与されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

会員制ライブ動画配信サイトの骨組をAWSで作ろう

こんにちは?
今日は、タイトルのことを↓のような方法で実現してみます。


  • S3にHLS動画を置く。パブリックアクセスは許可しない。
  • CloudFront経由でのみ、その動画を再生できるようにする。
    ただしCloudFrontの暗号鍵で署名したCookieが必要とするよう設定する。
  • CloudFrontにドメインを割り当てる。
  • AWS SDKのCloudFrontクライアントが使えて署名Cookieを操作できる言語(本記事ではPHP)で、動画配信WEBアプリケーションを作る。
  • WEBサーバーに、CloudFrontとセカンドレベルドメインまで同じドメインを割り当てる。
    またCloudFrontの暗号鍵を持たせる。(これでCloudFrontとWEBサーバーで署名Cookieを共有できる)
  • あとは署名Cookie発行をWEBアプリケーションの業務ロジックでコントロールすれば、会員制動画配信が実現可能!(これ以降は本記事では割愛します。)

ついでにCORS対応を施して、
Safari以外のブラウザ(本記事ではChrome)でHLS動画再生も実現します。


正味作業時間はそれほどかかりませんでしたが、

  • つまづきポイントが多い
  • 回避不能な待ち時間が発生する

関係でブヒブヒ言うハメになったので、スクリーンショット付きで詳しく説明していきます。
結構長いですが、お付き合いくださいませ...。

おことわり

本記事中のAWSリソースなどは執筆のために一時的に作成したものです。
流用はできませんので、あしからずご了承くださいませ。

必要なもの

  • AWSアカウント。
    ドメイン取得などを実施するので若干料金が発生します。2,000円くらいあれば十分。
    またドメイン名を何にするか決めておくとスムーズです。
    (本記事の例ではyagrush.netにしています。)

  • シェルが使えてHLS動画が再生できる端末(Macおすすめ。)

  • Docker & docker-compose(Docker Desktopならdocker-composeも付いてくるので、おすすめ。)

  • Chrome

HLS(HTTP Live Streaming)とは

Appleさんが作った動画配信技術。
AbemaTVとかでも使われてるそうです。
本記事ではこのHLSを使っていきます。

昨今の事情に合ったメリットがいっぱいあります。

  • HTTPと相性が良く、一般的なWEBサーバーで動画配信できる。
  • 再生品質をリアルタイム変更できるので安定して配信しやすい。
  • 暗号や認証対応が充実。
    etc...

Safariが一番相性良いですが、他ブラウザでも再生方法はあります。
(後のほうで説明します。)

HLSの動画ファイル形式

.ts.m3u8という拡張子の2種類のファイルで構成されます。
(.mp4 から変換してくれるソフトやオンラインサービスがいっぱいあります。)

.tsファイル

動画データファイル。
1本の動画を数秒単位で細切れにしたもの。
HLS動画はこの .ts ファイル何百何千個で構成されており、しかもそれが再生品質パターン分あったりする。

.m3u8ファイル

HLS動画ファイルのメイン。
山ほどある .ts のファイルパスや再生する順番が記録されている。

ちなみに他の.m3u8ファイルを入れ子にもできる。
例えば、低品質用 .m3u8 にサッと挿げ替えれば、動画再生を止めずに再生品質を下げれたり。

本物のライブ配信システムは .ts をリアルタイムでガシガシ作成していき .m3u8 をガンガン書き換えることで実現しているそうです。

作業開始

.m3u8ファイルと.tsファイルを用意する

いきなり言われても大変ですよね。

そこで、こちらのサイトで公開されているサンプルHLS動画ファイルをお借りします。
すごく使いやすかったので。(もし怒られたら、差し替えします…。)

Adaptive Streamingサンプル

再生品質400K, 2K, 4Kそれぞれ Tears00000~00010.ts の計10個ずつあれば10秒ほど再生できます。
動作確認には十分。

※ 全編だと恐らく.tsファイルが数千個以上あります。
  迷惑をかけるので、無理なダウンロードはやめましょう!

.m3u8

https://tech.jstream.jp/analytics/ex0/all-tears.m3u8
https://tech.jstream.jp/media/ToS/400K/Tears.m3u8
https://tech.jstream.jp/media/ToS/2K/Tears.m3u8
https://tech.jstream.jp/media/ToS/4K/Tears.m3u8

.ts(400K)

https://tech.jstream.jp/media/ToS/400K/Tears00000.ts
https://tech.jstream.jp/media/ToS/400K/Tears00001.ts

https://tech.jstream.jp/media/ToS/400K/Tears00009.ts
https://tech.jstream.jp/media/ToS/400K/Tears00010.ts

.ts(2K)

https://tech.jstream.jp/media/ToS/2K/Tears00000.ts
https://tech.jstream.jp/media/ToS/2K/Tears00001.ts

https://tech.jstream.jp/media/ToS/2K/Tears00009.ts
https://tech.jstream.jp/media/ToS/2K/Tears00010.ts

.ts(4K)

https://tech.jstream.jp/media/ToS/4K/Tears00000.ts
https://tech.jstream.jp/media/ToS/4K/Tears00001.ts

https://tech.jstream.jp/media/ToS/4K/Tears00009.ts
https://tech.jstream.jp/media/ToS/4K/Tears00010.ts

tsファイル00000~00010を一発ダウンロードするシェルの例.悪用しないでね!
URLBASE=https://tech.jstream.jp/media/ToS/400K

mkdir -p media/ToS/400K
cd media/ToS/400K
wget $URLBASE/Tears.m3u8
for i in `seq 0 10`
do
  fileno=`printf %05d $i`
  wget $URLBASE/Tears$fileno.ts
  if [ $? -gt 0 ]; then
    exit 99
  fi
done

cd ../..

S3作業

S3は動画ファイル置き場です。
CloudFront経由かつ特定ドメインからの再生 のみアクセスできるよう、設定を施します。

まずはバケットを作る

スクリーンショット 2020-07-03 16.24.49.png

スクリーンショット 2020-07-03 16.26.46.png

スクリーンショット 2020-07-03 16.28.12.png

CloudFront経由でアクセスするので、パブリックアクセス許可は不要です。

スクリーンショット 2020-07-04 0.44.10.png

HLS動画ファイルをS3にアップロード

サンプル動画の.m3u8に合わせたディレクトリ構造でアップロードしてください。

S3バケット/
  all-tears.m3u8
  media/
   ToS/
    400K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts
    2K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts
    4K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts

CloudFront作業

ここで一旦、CloudFrontの作業に移ります。

CloudFrontは、S3の門番役です。
特定アクセスのみ動画データを転送するよう、色々設定します。

CloudFrontディストリビューション作成

スクリーンショット 2020-07-03 17.03.00.png

スクリーンショット 2020-07-03 17.03.22.png

以下の設定だけを変更して、

設定項目名
Origin Domain Name クリックするとドロップリストが出るので、先ほど作成したS3を選んでください。
Origin ID ドロップリストを選択すれば自動的にセットされると思います。
Ristrict Buchet Access YESを選んでください。
Whitelist Headers 左のリストからOriginを選択して【Add >>】ボタンを押し、右のリストにOriginが移動するようにしてください。
Ristrict Viewer Access YESを選んでください。

それ以外は触らないでOKです。
最後に【Create Distribution】ボタンを押してください。

スクリーンショット 2020-07-03 17.04.39.png

スクリーンショット 2020-07-03 17.06.45.png

スクリーンショット 2020-07-03 17.08.00.png

スクリーンショット 2020-07-03 17.08.19.png

CloudFrontディストリビューションが作成されます。
ちなみにID(本例ではERDBXHEEWQCAE)をクリックすると詳細画面に遷移できます。

スクリーンショット 2020-07-03 17.08.57.png

S3がCloudFrontからのアクセスを許可するのに必要な情報を調べる

Origin Access Identityという値を調べます。
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

これはCloudFrontがS3にアクセスするための特別なユーザーで、ディストリビューション作成したときに自動的に作成されているはずです。

これのIDを控えておいてください。
欄がせまくて途中で見切れていますが、ダブルクリックで全選択→クリップボードなどで確実に控えましょう。

スクリーンショット 2020-07-03 17.21.37.png

再びS3作業

バケットポリシーを設定する

S3のバケットポリシー設定画面を開きます。

スクリーンショット 2020-07-03 17.36.25.png

テキストボックスに↓のJSONコードをコピペしてください。
ただし2箇所、あなたの環境に合わせて変更する必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Grant a CloudFront Origin Identity access",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E1DCCPJY6X9NYO"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::yagrush-hls/*"
        }
    ]
}
  • "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity のあとに、さきほどコピーしたCFディストリビューションのOrigin Access IdentityのIDを貼り付けてください。
  • "Resource": "arn:aws:s3::: のあとに、あなたが作成したS3のバケット名/*を貼り付けてください。

最後に【保存】ボタンを押してください。
エラーが表示されなければOK。

CORS構成を設定する

CORSとは

異なるサーバー間でリソース(動画とか)を共有できるようにする仕組みです。
これをちゃんと設定しないと、Safari以外のブラウザではS3に置かれたHLS動画を再生できません。
ある意味クロスサイトスクリプティングみたいなことになってしまい、エラーになります。

ちなみにSafariだけは(HLSを開発したAppleさんだけあって)ダイレクトにプラグインが起動してあっけなく再生できてしまいます。

設定する

S3バケットの【アクセス権限】タブから【CORSの設定】画面を開きます。

image.png

↓のXMLをコピペして下さい。
ただ1ヶ所、変更して頂く必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://web.yagrush.net:8000</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
  • <AllowedOrigin>の中のhttp://web.yagrush.net:8000は、みなさんの環境に合わせて書き換えてください。(トップレベルとセカンドレベルドメイン(本例ではyagrush.net)の部分は、予め決めたものから変えないで下さいね。)

またこの値は、後ほど構築するWEBサーバーのURLに使用するので控えておいてください。

最後に【保存】ボタンを押して下さい。
エラーにならなければOK。

※ XMLのタグを小文字にしたり、<AllowedOrigin>の値の末尾に/が付いてたりするだけですぐエラーになります。かなりセンシティブなので、コピペや編集の際はご注意を。

Route53作業

ドメインを取得する

ちょっと料金がかかります。

また、ここ、ウェイトポイントです!
購入したドメインが有効になるまで数時間かかる場合があります。

では、AWSのRoute53にアクセスしましょう。
そして、ドメインを作成する画面まで進んでください。

スクリーンショット 2020-07-03 17.42.28.png

スクリーンショット 2020-07-03 17.43.13.png

スクリーンショット 2020-07-03 17.43.36.png

指定したドメインが世界でまだ使われていなければOK。
カートに入れて購入します。

スクリーンショット 2020-07-03 17.44.24.png

ドメイン購入は結構ウルサイです。
ちゃんと個人情報を入力しないといけません。
(※ 一度買ったことがあれば、この手順は発生しないと思います。)

スクリーンショット 2020-07-03 17.51.00.png

その後も「規約に同意しろ」とか色々質問が出ますが、ここでは説明は省略します。
無事購入すると、世界中に浸透させる処理が開始されます。

これがまたリアル数時間かかります。
完了するとAWSからメールが来ると思うので、それまで休憩するのも良いでしょう。

スクリーンショット 2020-07-03 17.53.42.png

ドメインが有効になったら続きをやりましょう。

CloudFrontに振るサブドメインを決める

本例ではcf.を付けてcf.yagrush.netにしています。

ドメインとCloudFrontを結びつける

Route53でCNAMEという設定を追加すると、そういうことができます。
別名を登録する感じです。

その前にまずCloudFrontの画面で、CloudFrontディストリビューションのデフォルトアドレスを調べておきましょう。
↓このへんに表示されているやつですね。

image.png

本例ではd14br4vlcj23gd.cloudfront.netです。
※ またもや欄がせまくて途中で見切れているので、クリップボードコピーするときはご注意ください。

Route53にCNAMEレコードを追加する

まずはRoute53の画面を辿って「レコードセットの作成」まで進んでください。

image.png

image.png

image.png

「レコードセットの作成」ボタンを押すと、画面右側に設定小窓が出るので、先ほど調べておいた情報を設定して【作成】ボタンを押します。

image.png

これでOK。

image.png

再びCloudFront作業へ

CloudFront用サーバー証明書を取得する

CloudFrontディストリビューションの詳細設定画面を開いてください。

image.png

image.png

中段あたりにある【Request or Import a Certificate with ACM】ボタンを押して下さい。
image.png

「証明書のリクエスト」画面が開きます。

image.png
まずこのとき、画面右上のリージョン表示が「東京」などではなく「バージニア北部」になっていることを確認してください。(CloudFrontのエンドポイントはバージニア北部にあるため、バージニア北部で取得した証明書じゃないと使えないそうです。罠ポイント。)

それでは、先ほどのCloudFront用サブドメインを入力して【次へ】を押して下さい。
image.png

「DNSの検証」を選択して【次へ】。
image.png

タグは、必要でしたらお好みで設定してください。
【確認】ボタンを押します。
image.png

内容に誤りがなければ【確定とリクエスト】を押して下さい。
image.png

なんだか不安にさせられる画面になりました...
でも大丈夫、【続行】を押して下さい。
image.png

こんな画面に遷移しました。
これまた不穏な...

もちろんこのままではダメです。
画面中段あたり、CloudFront用ドメインの左にある ▼ を押して下さい。

image.png

小窓が展開されます。
その中にあるボタン【Route53でのレコードの作成】を押して下さい。
image.png

【作成】を押して下さい。
image.png

これで処理が進みます。
image.png

はい、来ました!ここもウェイトポイントです!
証明書が使えるようになるまで数時間かかる場合があります...。
(わりとすぐの場合もあります。)

完了すると↓に変わるはずです。
時間をおいてチェックしてみてください。
image.png

OKになったら作業の続きを。

CloudFrontに証明書をセットする

CloudFrontの詳細画面をまた開いてください。

中段あたりのSSL Certificateで、2番目の選択肢Custom SSL Certificate(example.com)がアクティブになり選択できるようになっているはずです。
それを選択しましょう。

※ たまに、証明書OKなのに選択肢Custom SSL Certificate(example.com)がアクティブになるまで時間がかかる場合があるようです...。

そしてその下にあるボックスをクリックするとドロップリストが開き、先ほどの証明書が選択できます。

更にそれらより上の方、Alternate Domain NamesにCloudFront用サブドメインを入力します。

全部終わったら、一番右下の【Yes, Edit】ボタンを押しましょう。
問題なければ、前の画面にスッと戻るはずです。
(もしエラーだと、赤字で下の方に表示されます。)

image.png

CloudFrontキーペアを作成する

今作業をしているAWSアカウントがルートアカウントでない場合、ログアウトしてルートアカウントでAWSコンソールにログインしなおしてください。(ルートアカウントじゃないとできない作業なのです。)

ルートアカウントで画面右上のユーザーメニューから「マイセキュリティ資格情報」を開きます。

image.png

ルートアカウントのみ【CloudFrontのキーペア】というタブが出現します。
それを開くと【新しいキーペアの作成】ボタンがあるので押して下さい。
image.png

image.png

こうなればOK。

  • 【プライベートキーファイルのダウンロード】
  • 【パブリックキーファイルのダウンロード】

は、ダウンロードしておいてください。
後で使います。

後はもうルートアカウントじゃなくてOK。

WEBアプリケーションを作る

以上でAWS作業からは離れます。

次にDockerとPHPを使ってWEBアプリケーションを作りましょう。
動画配信サイトにあたる部分です。

本記事ではローカルに構築して、hostsファイルを書き換えて対応します。
本格的にリモートに構築すると面倒なので...。

hostsを編集する

WEBサーバーのURL(本例ではweb.yagrush.net)をローカル(127.0.0.1)に向けます。

sudo vim /etc/hosts
/etc/hosts.
127.0.0.1   localhost web.yagrush.net

これでweb.yagrush.netのURLでアクセスするかぎり、HLS動画を再生できます。
CloudFrontをだます ...って言い方もアレですけどね。

さすがに記事が辛くなってきた:sob:
あと少し...!

WEBアプリケーション一式セットをダウンロードする

今回、動作確認済のWEBアプリケーション一式セットを予めご用意しました。
https://github.com/yagrush/hls-web

git cloneでもいいですが、ZIPダウンロード&解凍でもOK。
wgetコマンドが使える方は↓の一発コマンドをどうぞ。

wget https://github.com/yagrush/hls-web/archive/master.zip -O hls-web.zip; unzip hls-web.zip; rm -f hls-web.zip

#ついでにディレクトリを移動しておく
cd hls-web-master

CloudFrontのプライベートキーファイルを配備する

前の方の手順でCloudFrontキーペアを作成してプライベートキーファイルをダウンロードしたと思います。
(こんな名前のファイル pk-XXXXXXXXXXXXXXXXXXX.pem
それを hls-web-master/backend/storage/app に置いてください。

設定をカスタマイズする

数か所、みなさんの環境に合わせて変更して頂く必要があります。
(一応目印として**hls**というコメントを付けてあります。)

hls-web-master/backend/resources/views/play_video.blade.php, hls-web-master/backend/app/Http/Controllers/PlayVideoController.php

cf.yagrush.netyagrush.netの部分を、みなさんのケースに合わせて書き換えて下さい。

hls-web-master/backend/app/Http/Controllers/PlayVideoController.php

みなさんのCloudFrontキーペアのプライベートキーファイル名に合わせてXXXXXXXXXXXXXXXXXXXの部分を書き換えて下さい。
ちなみにキーペアIDも、プライベートキーファイル名のXXXXXXXXXXXXXXXXXXXと同じです。

hls-web-master/backend/resources/views/play_video.blade.php
...
...
    var videoSrc = 'https://cf.yagrush.net/all-tears.m3u8'; //**hls**
...
...
hls-web-master/backend/app/Http/Controllers/PlayVideoController.php
...
...
        $resourceKey = "https://cf.yagrush.net/*"; //**hls**
...
...
            'private_key' => storage_path() . '/app/pk-XXXXXXXXXXXXXXXXXXX.pem', //**hls**
            'key_pair_id' => 'XXXXXXXXXXXXXXXXXXX' //**hls**
...
...
        $domain = 'yagrush.net';  //**hls**
...
...

起動

hls-web-master/で以下のコマンドを打ってください。(数分かかるかも。)

make init

問題なければ、

  • ポート8000でnginxコンテナがWEBサーバーのフロントとして起動します。
  • PHPを処理するためのバックエンドとしてphp-fpmコンテナが起動します。
  • Laravelフレームワークのためだけにポート3306でmysqlコンテナが起動しますが、気にしないでください。

もしポート被りで起動に失敗したら、hls-web-master/docker-compose.ymlを編集してポートを変更するなどしてくださいね。

動画再生してみる

動画再生ページにChromeでアクセスしてみて下さい。
(本例だと http://web.yagrush.net:8000/play_video

再生されましたでしょうか?
↓こんな感じ。

image.png

今回は動画データの一部だけしか配備してないので、10秒ほどで停止します。

お時間あればSafariでもアクセスしてみて下さい。
ちなみにSafari以外での再生のために hls.js を採用しました。

動画に直アクセスできないのを確認してみる

以下のコマンドでcookieを使わずにアクセスしてみます。
(例によってyagrush.netはみなさんの環境に合わせて書き換えて下さいね。)

まずはOriginヘッダを付けて送信してみます。

curl -X GET -H 'Origin: http://web.yagrush.net:8000' -i -v -f https://cf.yagrush.net/all-tears.m3u8

403エラー!
拒否されちゃいました。

Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to cf.yagrush.net (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=cf.yagrush.net
*  start date: Jul  3 00:00:00 2020 GMT
*  expire date: Aug  3 12:00:00 2021 GMT
*  subjectAltName: host "cf.yagrush.net" matched certs "cf.yagrush.net"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0xxxxxxxxxxxxx)
> GET /all-tears.m3u8 HTTP/2
> Host: cf.yagrush.net
> User-Agent: curl/7.64.1
> Accept: */*
> Origin: http://web.yagrush.net:8000
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* The requested URL returned error: 403 
* stopped the pause stream!
* Connection #0 to host cf.yagrush.net left intact
curl: (22) The requested URL returned error: 403 
* Closing connection 0

今度はプライベートキーファイルまで付けて送信してみます。

curl -X GET -H 'Origin: http://web.yagrush.net:8000' -i -v -f -E backend/storage/app/pk-XXXXXXXXXXXXXXXXXX.pem https://cf.yagrush.net/all-tears.m3u8

やはり怒られました。

Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to sample.flhls.net (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* could not load PEM client certificate, LibreSSL error error:09FFF06C:PEM routines:CRYPTO_internal:no start line, (no key found, wrong pass phrase, or wrong file format?)
* Closing connection 0
curl: (58) could not load PEM client certificate, LibreSSL error error:09FFF06C:PEM routines:CRYPTO_internal:no start line, (no key found, wrong pass phrase, or wrong file format?)

終了

以下のコマンドでWEBアプリケーションを終了&破棄します。

make destroy

おつかれさまでしたぁーー!!!

WEBアプリケーション変更点 まとめ

今回は、定番のこちら -> 最強のLaravel開発環境をDockerを使って構築する【新編集版】 をベースに以下の手を加えました。

PHP用AWS SDKインストールをビルド工程(Makefile @ create-project)に追加。

docker-compose exec app composer require aws/aws-sdk-php

★ CloudFrontキーペアのプライベートキーファイルをbackend/storage/appに配備。

backend/routes/web.phpにルーティング設定追記。

Route::get('/play_video', 'PlayVideoController@show');

★ ソースコード2つ作成。

  • backend/app/Http/Controllers/PlayVideoController.php
  • backend/resources/views/play_video.blade.php

CloudFront+S3+Video.js+ 署名付きCookieでクローズドな動画配信 を参考に書きました。
↑お時間あれば是非ご覧になってみて下さい。

参考文献

今回はこれらのサイトにお世話になりました。
ありがとうございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS無料枠のつもりが請求が来てしまった話

ある日

Gmailに気になるメールが。
image.png

請求メール?

image.png

5000円くらい請求されてる!?
AWSアカウントはいくつか持っているが、EC2のみ利用しており、アカウント作成から1年経っていない、かつ無料枠内におさめているはず…(t2.micro×1台のみ)
なんでだ!?

原因

AWS Organizations を設定していることが原因でした。
下記みたいな組織構成です。

マスターAWSアカウント・・・2017年あたりに作成
  ├ メンバーAWSアカウント1・・・2020年初に作成
  ├ メンバーAWSアカウント2・・・2020年初に作成
  └ メンバーAWSアカウント3・・・2020年初に作成

AWSのドキュメントによると下記の記載が…

お客様の AWS アカウントが、貴社によって AWS Organizations で作成されている場合、すべてのメンバーアカウントの無料利用枠の開始日は、その組織のマスターアカウントが作成された日となります。詳細については、AWS Organizations ユーザーガイドを参照してください。

とっくに枯れきったアカウントをマスターアカウントにしたのが原因でした……:sob:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【RDS/Rails】Railsサーバ(AWS Cloud9で構築)とRDS(MySQL)間の接続を確立する

目標

Railsサーバ(AWS Cloud9によって構築)とRDS(MySQL)間の接続を確立する

はじめに

ほぼメモです。
Railsはデフォルトでsqlliteをデータベースとして利用する設定になっているので、
それをRDSで構築したMySQLを利用するよう設定変更しました。

前提

・RailsサーバがCloud9によって構築済みであること(※)。

※以下記事の「Cloud9にチャレンジ!」までを実施する
[初心者向け]Cloud9で五分でできる、"Yay! You’re on Rails!"(Cloud9にチャレンジ!)

作業の流れ

項番 タイトル
1 RDSを構築する
2 Railsサーバから接続する

手順

1.RDSを構築する

以下記事の「1.RDSを作成する」を実施します。

【RDS】EC2とRDS(MySQL)間の接続を確立する(1.RDSを作成する)

2.Railsサーバから接続する

①Railsの新規アプリケーション作成

$ rails new test_app

作成後、アプリケーション配下へ移動します。

$ cd test_app

②mysql-develをyumインストール

$ sudo yum install mysql-devel

③Gemfile編集

デフォルトでsqlliteのgemをインストールする仕様となっているので、
mysqlをインストールするよう以下のように編集します。

gem 'sqlite3'⇒コメントアウト
gem 'mysql2'⇒追加

ファイル名: Gemfile
#gem 'sqlite3'
gem 'mysql2'

④MySQLのgemインストール(bundle install)

$ bundle install

⑤database.yml編集
development環境にmysqlのデータベースを利用するようdatabase.ymlを編集(デフォルトのsqlliteへの接続定義は上書き削除)(※)

※以下に関しては値を置換する必要があります。
<db_username><db_password><rds_endpoint>
⇒前手順「1.RDSを構築する」で構築したRDSの内容に従って書き換え

<db_name>
⇒任意の名前でOK。

ファイル名: database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <db_username>
  password: <db_password>
  host: <rds_endpoint>
  database: <db_name>
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default

⑥データベース作成

$ rails db:create

⑦アプリケーション起動

rails s

⑧検証テーブル作成

$ rails generate model user name:string
$ rails db:migrate

⑨Mysql接続
mysql -h <rds_endpoint> -u <db_username> -p <db_name>

$ mysql -h database-test.cgfjapta11py.ap-northeast-1.rds.amazonaws.com -u admin -p practice
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 5.7.22-log Source distribution

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

接続後、一応データベース及びテーブルが正常に作成されているか確認
show databases;
show tables;

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| innodb             |
| mysql              |
| performance_schema |
| practice           |
| sys                |
| testdb             |
+--------------------+
7 rows in set (0.00 sec)

mysql> show tables;
+----------------------+
| Tables_in_practice   |
+----------------------+
| ar_internal_metadata |
| schema_migrations    |
| users                |
+----------------------+
3 rows in set (0.00 sec)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAA対策メモ(EC2, Lambda & IAM編)

SAA対策の自分用のメモ。
どんどん更新して加筆修正していく予定。

EC2

インスタンス起動時にパブリックIPアドレスを自動振り分けするか、無効にするのか選べる
パブリックIPアドレスはECインスタンスを再起動すると変わる
EC2の課金はrunningの時のみ

プライマリプライベートIPアドレス
最初に付与するプライベートIPアドレス
指定しなくても自動割り当て
EC2インスタンスを削除しない限りずっと同じ

セカンダリプライベートIPアドレス
ENI(Elastic Network Interface)をEC2にアタッチすることで、を割り当てることができる。
取り外し自由であり、他のEC2インスタンスにも付け替え可能

  • オンデマンドインスタンス

デフォルト。初期費用などなし。従量課金。

  • リザーブドインスタンス 
    1 or 3年間、最大75%引き、全額/一部前払いか前払いなしで割引率は変わる。

  • スタンダード リージョンやAZを指定、その中でなら配置転換可能。他へは手続きが必要。

    • コンバーティブル インスタンスファミリーの変更が可能。割引率は低い
  • スポットインスタンス
    最大90%割引、希望額の時のみ起動でき、逆にそうでないときは強制終了となる。処理が中断してもOK、再実行が可能なシステムに使用。

    • スポットブロック 予め決められた時間の起動を保証(最大6時間)、処理の中断を避けられる。
    • スポットフリート 予め指定した性能キャパシティを満たすように構成してくれる。1つのインスタンスが終了しても、また別の同性能のインスタンスを起動し、維持してくれる。
  • ハードウェア占有
    専用のホストコンピュータであるが、配置するホストコンピュータを指定することはできない
    プライベートアドレスは必ずつく。再起動しても変わらない。

  • Dedicated Host
    ホストコンピュータにはIDが付与されており、使用可能な任意のホストコンピュータでEC2起動可。ユーザーがホストコンピュータを選ぶこともできる。

ユーザーデータ
インスタンス初回起動時に1回だけスクリプトを実行できる
プレイスメントグループ単一AZ内のEC2インスタンスを論理的にグルーピング。高速処理可能。クラスターコンピューティング向き。

プレイスメントグループ
1つのAZ内のEC2インスタンスグループであり、インスタンス間で低レイテンシーネットワークパフォーマンスを実現

インスタンスタイプはなるべく最新の世代を使う

T2/3はバースト可能パフォーマンスインスタンス。通常は低負荷で、稀に高負荷なアクセスとなるシステムで使用。

ベースラインパフォーマンス
予めインスタンスごとに決められたCPUリソース使用率。これを下回るとCPUクレジットは蓄積され、上回るとクレジットは消費される。この消費部分をバーストという。追加でクレジットを購入し、性能の低下を防ぐためにUnlimitedというオプションがある。

AMIはどちらか選ぶ
EBS-Backed インスタンス→データを永続保存可能
Instance store-Backed インスタンス→一時的に保存

Lambda

コードで実行できるサーバーレスコンピューティング
イベントドリブンなので、他のサービスと連携しやすい(S3やCloudWatch Events、API Gatewayなど)
実行するコード = Lambda関数
従量課金(リクエスト量と処理量)
オートスケーリング可能
実行時間の上限は15分間で、大量のデータのバッチ処理には不向き
イベントをトリガーにして、短い時間で処理を行うのに適している。

  • Pullモデル
    アプリケーションからストリーム(DynamoDBストリームなど) へイベントを発行し、Lambdaはそのストリームからイベントを取り出し、コードを実行

  • pushモデル
    ユーザのアプリケーションからLambdaへ向けてイベントを発行し、コードを実行します。たとえば、S3でバケット通知をLambdaへ向けて設定して、コードを実行。Pushモデルは3回リトライを実行。

レイテンシー対策にSQSを使用
コールドスタートなので、急増したトラフィックに対応できないかも?

IAM

IAMユーザーはIAMグループに入れてからIAMポリシーで権限付与
最小権限の原則、必要最低限の権限のみ付与する
IAMユーザーのデフォルト権限はなし

IAMポリシーの種類

  • AWS管理ポリシー
    AWSによって定義されているポリシーのテンプレート
    例 PowerUserAccess IAM以外全てへのアクセス権限を持っている

  • カスタマー管理ポリシー
    ユーザーが自身で作成・カスタマイズするポリシー

  • インラインポリシー
    IAMユーザーなどに埋め込まれたポリシーに対して、ポリシー設定を個別に反映

IAMロール
AWSリソースの操作権限をAWSのサービスやアプリに付与する。
アクセスキーIDやシークレットアクセスキーによる認証より、IAMロールを用いた認証が推奨されている

スイッチロール
あるIAMユーザーが異なるAWSアカウントの管理を行うためにアクセスする。管理される側のAWSアカウントでIAMロールを作成し、それをアタッチする。

AWS organizations
複数のAWSアカウントを一元管理する。
OU(組織単位)で管理
マスターアカウントとメンバーアカウント

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAA対策メモ(EC2, IAM編)

SAA対策の自分用のメモ。
どんどん更新して加筆修正していく予定。

EC2

インスタンス起動時にパブリックIPアドレスを自動振り分けするか、無効にするのか選べる
パブリックIPアドレスはECインスタンスを再起動すると変わる
EC2の課金はrunningの時のみ

プライマリプライベートIPアドレス
最初に付与するプライベートIPアドレス
指定しなくても自動割り当て
EC2インスタンスを削除しない限りずっと同じ

セカンダリプライベートIPアドレス
ENI(Elastic Network Interface)をEC2にアタッチすることで、を割り当てることができる。
取り外し自由であり、他のEC2インスタンスにも付け替え可能

オンデマンドインスタンス デフォルト。初期費用などなし。従量課金。
リザーブドインスタンス 1 or 3年間、最大75%引き、全額/一部前払いか前払いなしで割引率は変わる。
 スタンダード リージョンやAZを指定、その中でなら配置転換可能。他へは手続きが必要。
 コンバーティブル インスタンスファミリーの変更が可能。割引率は低い

スポットインスタンス 最大90%割引、希望額の時のみ起動でき、逆にそうでないときは強制終了となる。処理が中断してもOK、再実行が可能なシステムに使用。
 スポットブロック 予め決められた時間の起動を保証(最大6時間)、処理の中断を避けられる。
 スポットフリート 予め指定した性能キャパシティを満たすように構成してくれる。1つのインスタンスが終了しても、また別の同性能のインスタンスを起動し、維持してくれる。

ハードウェア占有
専用のホストコンピュータであるが、配置するホストコンピュータを指定することはできない
プライベートアドレスは必ずつく。再起動しても変わらない。

Dedicated Host
ホストコンピュータにはIDが付与されており、使用可能な任意のホストコンピュータでEC2起動可。ユーザーがホストコンピュータを選ぶこともできる。

ユーザーデータ
インスタンス初回起動時に1回だけスクリプトを実行できる
プレイスメントグループ単一AZ内のEC2インスタンスを論理的にグルーピング。高速処理可能。クラスターコンピューティング向き。

プレイスメントグループ
1つのAZ内のEC2インスタンスグループであり、インスタンス間で低レイテンシーネットワークパフォーマンスを実現

インスタンスタイプはなるべく最新の世代を使う

T2/3はバースト可能パフォーマンスインスタンス。通常は低負荷で、稀に高負荷なアクセスとなるシステムで使用。

ベースラインパフォーマンス
予めインスタンスごとに決められたCPUリソース使用率。これを下回るとCPUクレジットは蓄積され、上回るとクレジットは消費される。この消費部分をバーストという。追加でクレジットを購入し、性能の低下を防ぐためにUnlimitedというオプションがある。

AMIはどちらか選ぶ
EBS-Backed インスタンス→データを永続保存可能
Instance store-Backed インスタンス→一時的に保存

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAA対策メモ(EC2とLambda編)

SAA対策の自分用のメモ。
どんどん更新して加筆修正していく予定。

EC2

インスタンス起動時にパブリックIPアドレスを自動振り分けするか、無効にするのか選べる
パブリックIPアドレスはECインスタンスを再起動すると変わる
EC2の課金はrunningの時のみ

プライマリプライベートIPアドレス
最初に付与するプライベートIPアドレス
指定しなくても自動割り当て
EC2インスタンスを削除しない限りずっと同じ

セカンダリプライベートIPアドレス
ENI(Elastic Network Interface)をEC2にアタッチすることで、を割り当てることができる。
取り外し自由であり、他のEC2インスタンスにも付け替え可能

オンデマンドインスタンス デフォルト。初期費用などなし。従量課金。
リザーブドインスタンス 1 or 3年間、最大75%引き、全額/一部前払いか前払いなしで割引率は変わる。
 スタンダード リージョンやAZを指定、その中でなら配置転換可能。他へは手続きが必要。
 コンバーティブル インスタンスファミリーの変更が可能。割引率は低い

スポットインスタンス 最大90%割引、希望額の時のみ起動でき、逆にそうでないときは強制終了となる。処理が中断してもOK、再実行が可能なシステムに使用。
 スポットブロック 予め決められた時間の起動を保証(最大6時間)、処理の中断を避けられる。
 スポットフリート 予め指定した性能キャパシティを満たすように構成してくれる。1つのインスタンスが終了しても、また別の同性能のインスタンスを起動し、維持してくれる。

ハードウェア占有
専用のホストコンピュータであるが、配置するホストコンピュータを指定することはできない
プライベートアドレスは必ずつく。再起動しても変わらない。

Dedicated Host
ホストコンピュータにはIDが付与されており、使用可能な任意のホストコンピュータでEC2起動可。ユーザーがホストコンピュータを選ぶこともできる。

ユーザーデータ
インスタンス初回起動時に1回だけスクリプトを実行できる
プレイスメントグループ単一AZ内のEC2インスタンスを論理的にグルーピング。高速処理可能。クラスターコンピューティング向き。

プレイスメントグループ
1つのAZ内のEC2インスタンスグループであり、インスタンス間で低レイテンシーネットワークパフォーマンスを実現

インスタンスタイプはなるべく最新の世代を使う

T2/3はバースト可能パフォーマンスインスタンス。通常は低負荷で、稀に高負荷なアクセスとなるシステムで使用。

ベースラインパフォーマンス
予めインスタンスごとに決められたCPUリソース使用率。これを下回るとCPUクレジットは蓄積され、上回るとクレジットは消費される。この消費部分をバーストという。追加でクレジットを購入し、性能の低下を防ぐためにUnlimitedというオプションがある。

AMIはどちらか選ぶ
EBS-Backed インスタンス→データを永続保存可能
Instance store-Backed インスタンス→一時的に保存

Lambda

Lambda
コードで実行できるサーバーレスコンピューティング
イベントドリブンなので、他のサービスと連携しやすい(S3やCloudWatch Events、API Gatewayなど)
実行するコード = Lambda関数
従量課金(リクエスト量と処理量)
オートスケーリング可能
実行時間の上限は15分間で、大量のデータのバッチ処理には不向き
イベントをトリガーにして、短い時間で処理を行うのに適している。

Pullモデル
アプリケーションからストリーム(DynamoDBストリームなど) へイベントを発行し、Lambdaはそのストリームからイベントを取り出し、コードを実行
pushモデル
ユーザのアプリケーションからLambdaへ向けてイベントを発行し、コードを実行します。たとえば、S3でバケット通知をLambdaへ向けて設定して、コードを実行。Pushモデルは3回リトライを実行。

レイテンシー対策にSQSを使用
コールドスタートなので、急増したトラフィックに対応できないかも?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CDKでLambda作ってSAMでローカルで動作確認したメモ

最近仕事でCDKを触り始めたので、個人でも適当なSlack botでも作ってみようとかと思って触ってみてます。デプロイがとてもラクとはいえ、Lambdaを動作確認しながら作っていくのに毎回デプロイするのはつらみです…

調べてみると、CDKで作ったLambdaでもSAMを使ってローカルで動かす方法があるようなので、スタックの作成からLambdaのローカル実行まで一通り試してみました。

環境

  • OS
    • Windows10 WSL(Ubuntu 18.04 LTS)
    • macOS Mojave
  • CDK 1.46.0
  • SAM 0.53.0
  • Docker 19.03.11
    • VirtualBox上のUbuntu 18.04 LTS

CDKでLambdaの作成

CDKインストール

npmでインストール。

# CDKインストール
npm install -g aws-cdk
/home/hotaru/.anyenv/envs/nodenv/versions/12.16.3/bin/cdk -> /home/hotaru/.anyenv/envs/nodenv/versions/12.16.3/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.46.0
added 216 packages from 186 contributors in 13.791s

テンプレート生成

まずは適当なディレクトリを作成。のちのちSlack botを作っていくリポジトリにする予定なので、それらしい名前で掘っておく。

mkdir slack-auto-stamp-bot
cd slack-auto-stamp-bot

cdk init でテンプレートを生成。オプションなしで叩くとどんなテンプレートがあるのか教えてくれます。

cdk init
Available templates:
* app: Template for a CDK Application
   └─ cdk init app --language=[csharp|fsharp|java|javascript|python|typescript]
* lib: Template for a CDK Construct Library
   └─ cdk init lib --language=typescript
* sample-app: Example CDK Application with some constructs
   └─ cdk init sample-app --language=[csharp|fsharp|java|javascript|python|typescript]

基本的には app を使います。言語はTypeScriptでいくので、

cdk init app -l typescript
Applying project template app for typescript
Initializing a new git repository...
Executing npm install...

(以下略)

と言った感じ。生成後のディレクトリ構成は以下の通り。

/slack-auto-stamp-bot
├── README.md
├── bin
│   └── slack-auto-stamp-bot.ts
├── cdk.json
├── jest.config.js
├── lib
│   └── slack-auto-stamp-bot-stack.ts
├── node_modules
├── package-lock.json
├── package.json
├── test
│   └── slack-auto-stamp-bot.test.ts
└── tsconfig.json

lib 配下のファイルにリソースを定義していきます。その前に、構築したいリソース毎にパッケージが別れているので、必要なものを追加しておきます。

# LambdaとAPI Gatewayを追加
npm add @aws-cdk/aws-lambda @aws-cdk/aws-apigateway
npm WARN slack-auto-stamp-bot@0.1.0 No repository field.
npm WARN slack-auto-stamp-bot@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ @aws-cdk/aws-apigateway@1.46.0
+ @aws-cdk/aws-lambda@1.46.0
added 17 packages from 1 contributor and audited 794 packages in 13.799s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

この記事ではLambdaしか使いませんが、のちのちAPI Gatewayを使用する予定なので一緒にいれました。
CDKでLambdaを作っていく前に、Lambda本体のコードを作ります。こちらはRubyで。

mkdir -p lambda/stamp-bot-function
cd lambda/stamp-bot-function/
touch app.rb

とりあえずeventをそのまま返すコードでも置いときます。

lambda/stamp-bot-function/app.rb
# frozen_string_literal: true

require 'json'

def handler(event:, context:)
  {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.generate(event)
  }
end

今度はLambdaのリソースを作っていきます。すでに仕事で触っていたのでなんてことないですが、初めてのときはこちらが参考になりました。

lib/slack-auto-stamp-bot-stack.ts
import * as cdk from '@aws-cdk/core'
import * as lambda from '@aws-cdk/aws-lambda'

export class SlackAutoStampBotStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props)

        const stampBotFunctionProps: lambda.FunctionProps = {
            runtime: lambda.Runtime.RUBY_2_7,
            code: lambda.Code.fromAsset('lambda/stamp-bot-function'),
            handler: 'app.handler'
        }
        const stampBotFunction = new lambda.Function(this, 'stampBotFunction', stampBotFunctionProps)
    }
}

stampBotFunctionProps のところでLambdaの設定をいろいろ書いてます。最低限 runtimecodehandler の指定が必要です。ちなみに lambda.Code.fromAsset() で渡しているパスは、プロジェクトルートからの相対パスです。
Function のコンストラクタには Stack(このクラス自身) 、 スタック内で一意となる論理ID、スタックの設定( 作成した stampBotFunctionProps )を渡します。

デプロイ

デプロイする前に、初回はアセット格納用のS3バケットが必要になるので、 cdk bootstrap を実行して作成しておきます。

cdk bootstrap
(node:18789) ExperimentalWarning: The fs.promises API is experimental
 ⏳  Bootstrapping environment aws://xxxxxxxxxxxx/ap-northeast-1...
CDKToolkit: creating CloudFormation changeset...
 0/3 | 2:18:23 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket       | StagingBucket
 0/3 | 2:18:25 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket       | StagingBucket Resource creation Initiated
 1/3 | 2:18:47 PM | CREATE_COMPLETE      | AWS::S3::Bucket       | StagingBucket
 1/3 | 2:18:49 PM | CREATE_IN_PROGRESS   | AWS::S3::BucketPolicy | StagingBucketPolicy
 1/3 | 2:18:50 PM | CREATE_IN_PROGRESS   | AWS::S3::BucketPolicy | StagingBucketPolicy Resource creation Initiated
 2/3 | 2:18:50 PM | CREATE_COMPLETE      | AWS::S3::BucketPolicy | StagingBucketPolicy
 3/3 | 2:18:52 PM | CREATE_COMPLETE      | AWS::CloudFormation::Stack | CDKToolkit
 ✅  Environment aws://xxxxxxxxxxxx/ap-northeast-1 bootstrapped.

こんなスタックができます。
image.png

まずはビルドします。

npm run-script build

作成されるスタックの確認。 cdk diff でスタックの変更内容を確認できます。

cdk diff
Stack SlackAutoStampBotStack
IAM Statement Changes
┌───┬─────────────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                            │ Effect │ Action         │ Principal                    │ Condition │
├───┼─────────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${stampBotFunction/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.amazonaws.com │           │
└───┴─────────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                        │ Managed Policy ARN                                                             │
├───┼─────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${stampBotFunction/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴─────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Parameters
[+] Parameter AssetParameters/81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9/S3Bucket AssetParameters81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9S3Bucket1EF80AD6: {"Type":"String","Description":"S3 bucket for asset \"81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9\""}
[+] Parameter AssetParameters/81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9/S3VersionKey AssetParameters81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9S3VersionKey462471F6: {"Type":"String","Description":"S3 key for asset version \"81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9\""}
[+] Parameter AssetParameters/81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9/ArtifactHash AssetParameters81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9ArtifactHash5F87EF54: {"Type":"String","Description":"Artifact hash for asset \"81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9\""}

Conditions
[+] Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::IAM::Role stampBotFunction/ServiceRole stampBotFunctionServiceRoleE8B84E9C
[+] AWS::Lambda::Function stampBotFunction stampBotFunction1C7A789E

Lambdaの実行に必要なIAMロールも勝手に作ってくれてます。
では、デプロイします。

# デプロイ
cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬─────────────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                            │ Effect │ Action         │ Principal                    │ Condition │
├───┼─────────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${stampBotFunction/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.amazonaws.com │           │
└───┴─────────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                        │ Managed Policy ARN                                                             │
├───┼─────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${stampBotFunction/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴─────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
SlackAutoStampBotStack: deploying...
[0%] start: Publishing 81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9:current
[100%] success: Published 81ffb93ce7b48a8e0dca23f447c0835e5b3d9832e0e2cebd6ead445127e6ddf9:current
SlackAutoStampBotStack: creating CloudFormation changeset...





 ✅  SlackAutoStampBotStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/SlackAutoStampBotStack/3be0c370-b2fc-11ea-968b-06ef10f7e39e

できました。
image.png

適当に動作確認。問題なさそうです。
image.png
image.png

ローカルでテストしたい

動作確認しながら作っていくとなると毎回デプロイは大変なので、ローカルでLambdaを動かしたいです。
公式ドキュメントにSAMでローカル実行する方法が記載されていたので、こちらを参考にやってみます。
SAMとDockerが必要になりますが、こちらはインストール済みとします。自分はVagrantで立てたUbuntuにDockerを入れているので、SAMはそちらに入れました。

まず、SAMで使用するためのCloudFormationテンプレートを生成します。

cdk synth --no-staging > template.yaml

生成したテンプレートから対象のLambdaの論理IDを探します。 TypeAWS::Lambda::Function のリソースですね。
Dockerが別ホストで実行されている場合など、Lambda本体のパスが変わってしまう場合は aws:asset:path を必要に応じて修正します。

template.yaml
  stampBotFunction1C7A789E: # <- これを確認
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:

# (略)

    Metadata:
      aws:cdk:path: SlackAutoStampBotStack/stampBotFunction/Resource
      aws:asset:path: /home/vagrant/docker/slack-auto-stamp-bot/lambda/stamp-bot-function # <- 必要に応じてパスを修正
      aws:asset:property: Code

ここまでできたら、あとは適当にLambdaに渡すeventでも作成して…

event_sample/oshi.json
{
  "kotori": "Aya Uchida",
  "you": "Shuka Saito",
  "shizuku": "Kaori Maeda"
}

sam local invoke で実行!

sam local invoke stampBotFunction1C7A789E --event event_sample/oshi.json
Invoking app.handler (ruby2.7)

Fetching lambci/lambda:ruby2.7 Docker container image......
Mounting /home/vagrant/docker/slack-auto-stamp-bot/lambda/stamp-bot-function as /var/task:ro,delegated inside runtime container
START RequestId: a974a2ee-c7dd-1ec1-9ff2-c418511d44bf Version: $LATEST
END RequestId: a974a2ee-c7dd-1ec1-9ff2-c418511d44bf
REPORT RequestId: a974a2ee-c7dd-1ec1-9ff2-c418511d44bf  Init Duration: 372.29 ms    Duration: 3.59 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 22 MB

{"statusCode":200,"headers":{"Content-Type":"application/json"},"body":"{\"kotori\":\"Aya Uchida\",\"you\":\"Shuka Saito\",\"shizuku\":\"Kaori Maeda\"}"}

実行できました!

所感

使用する言語の知識は必要になりますが、CloudFormationのyamlよりも内容把握しやすかったりするので、個人的にはCDKとても良きです。
ローカルでの動作確認の手段もちゃんと検証できたので、いろいろ作って遊んでみたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

direnv ええな

用意する物(私の環境)

  • mac
  • brew install direnv

ディレクトリごとに環境変数を変更できるやつ

brewでinstallしたら .zshrc に次を追記

export EDITOR=vim
eval "$(direnv hook zsh)"

下準備

個人的にterraformの勉強中ですので

$ mkdir XXXXXXXXX
$ cd XXXXXXXXX
$ touch main.tf

では .envrc の設定をしようか

$ direnv edit .

これでvimが開かれて .envrc の編集になるので次のように設定

AWS_PROFILE=`YOUR_PROFILE`
AWS_DEFAULT_REGION=ap-northeast-1

こうすると万が一 .envrc をpushしてもぎり耐えれる

$ direnv allow

とりあえず一番簡単な例

main.tf
resource "aws_instance" "example" {
  ami           = "ami-0f9ae750e8274075b"
  instance_type = "t3.micro"
}

これ書いたら

$ terraform init
$ terraform plan
$ terraform apply

でインスタンスが立つんですけど、これだとNameがないのでどれが自分の立てたやつかわからないんですよね。。。。

ということでこれを辞めて

$ rm main.tf
$ touch output.tf

どうやら .tf ファイルはまとめ上げて実行されるらしいので main.tfoutput.tf で同じresourceを書くとエラーが出るんですよね。。 

なので rm で消しました。

$ terraform apply

Error: Duplicate resource "aws_instance" configuration

  on output.tf line 9:
   9: resource "aws_instance" "example" {

A aws_instance resource named "example" was already declared at
main.tf:1,1-34. Resource names must be unique per type in each module.

では新規作成の output.tf でterraform実行後に生成されたインスタンスidを出力させます。

output.tf
provider "aws" {
  region = "ap-northeast-1"
}

variable "example_instance_type" {
  default = "t3.micro"
}

resource "aws_instance" "example" {
  ami           = "ami-0f9ae750e8274075b"
  instance_type = var.example_instance_type
}

output "example_instance_id" {
  value = aws_instance.example.id
}

おそらくこんな感じで帰ってきます

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.example: Creating...
aws_instance.example: Still creating... [10s elapsed]
aws_instance.example: Creation complete after 13s [id=i-03497d1ecfeda9410]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

example_instance_id = i-03497d1ecfeda9410

aws コンソールで検索すると確かにできてました。わーい

では使わないので削除します。

$ terraform destroy
aws_instance.example: Refreshing state... [id=i-03497d1ecfeda9410]

消えました。ちなみに気づいたかもしれませんが

$ ls    
output.tf                terraform.tfstate        terraform.tfstate.backup

なんかファイルできてるんですよね。これは生成したインスタンスの状態が記録された物らしいです。ということはこれを消してしまうとdestroyはできないということですね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初めての共同執筆で学んだことと失敗談

縁あって会社の同僚と技術本を共同執筆することになりました。
全員執筆は初めてだったのでてんやわんやになりながらもなんとか無事書き終えはしましたが、「ああすればよかったのかな」と思う事もそれなりにありました。
これから技術書の執筆にチャレンジする方や、次の機会(といっても今のところ予定はなし)のためにメモを残します。
これから執筆にチャレンジされる方の参考になれば嬉しいです。

執筆時の心情とやったこと

執筆準備期間

執筆の話が出たのが昨年の夏頃で内容は AWS 関連の入門書でした。
まずは、出版社の方と大綱スケジュールと執筆内容の認識合わせを行い、大まかな計画(本の章などをどうするか)をたてます。
僕らは年末に re:Invent が控えているので年明けから本格的に書き出す計画でそれまではかるく作業をすすめることにしました。
振り返るとこのあたりで決めごとをきちんと抑えずにふわっと始めたのが後半のバタバタに繋がった気がします・・

執筆初期

re:Invent の影響を受けなさそうなところから執筆していく。
.md 形式で執筆してファイルを GitLab のリポジトリで管理し、執筆単位にフィーチャーブランチを切って執筆を行い、MR を RC ブランチに投げて執筆者以外の二人がレビューするという方法で進める。
期限も緩めで空いた時間に作業する感じだったので特に問題もなく執筆が進んでいく。

執筆中期

re:Invent も終わりサービスアップデートのラッシュも一段落ついたのでメイン部分を書いていく。
ただ、このあたりの時期は業務も繁忙期に入る & 新しい AWS の機能の理解のために勉強する必要があるので執筆作業が滞り、アウトプット量がどんどん落ちていく。
「まだ期間的に余裕があるから大丈夫!」と執筆活動から目を背けて多忙な日々を送る。

執筆終期

期限も迫り焦りも出てくる中、自分たちが書いている内容が必要なページ数に達しているのかが判断がつかなくなってきてアウトプット量を把握すべく、GitLab のパイプラインを利用して .md を PDF に変換する仕組みを組み込む。
.md → Re:VIEW → PDF の順に変換するパイプランを設定して自分たちの執筆量をおおよそだが把握できるようになるが、ページ数がちょっと足りないかもと余計に焦る結果に。
その後、ついでにという気持ちで textlint で文章のチェック機能を導入。すると恐ろしい量の error が発生。確認するとルールのメンテナンスが必要なので対応を諦める・・(これが後の苦労の始まり)
執筆環境がローカルに依存している事も気になったので Gitpod を利用して執筆できるようにコンテナイメージや Theia のプラグインを整備。
Gitpod の workspace にテキスト校正くん、vscode-textlint、CharacterCount を導入してファイルの保存時にフォーマットをかけるようにしてテンションアップ。
記載しているプログラムコードのクロスチェックを週末に行い、手順が適切かチェックを行うなど、このあたりは自分の中ではラストスパート感があった。

校正期

なんとか書き上げて出版者の方に製本用の調整をかけていただく。すごく良い感じの出来上がりテンションも上がったがここからが一番つらかった。。
初校が出来上がり確認をしていると、誤字や脱字がわんさかと・・
ここから、再校、念校と重ねていくもその度、誤字や脱字が見つかる見つかる。
校を重ねるたびに全ページ見直してチェックをして今度こそ大丈夫と思っても新しい問題が目につくことで泥沼に・
都度、修正依頼を出版社の方にお願いして訂正してもらうのですが、何度も依頼を出すことになり只々心苦しくなるばかり・・
執筆初期と終期で書き方が変わってしまっており、表記の揺れなども多く確認を重ねるたびに更なる泥沼に陥る。
画面キャプチャも初期に撮ったものと内容が変わっており取り直しと内容追記を行い事になり混迷の極みに。
校を重ねるにつれて修正をお願い可能な期間(=執筆者の確認期間)が短くなるので業務終了後はひらすら PDF とにらめっこ。
「もうこれで大丈夫だ!」と思っていても新しい校を確認すると不備を見つけてしまうので終盤は完全に自分不信に・
最後は出版社の方のはからいもあり一旦はこれで大丈夫というところまで持っていく事ができ無事入稿。

校正時期が一番しんどかった・・

反省点

振り返ってみてこうすればよかったという点は以下の通り。

textlint の導入の遅さ

技術の執筆はリポジトリでブランチモデルで管理というのはなんとなく知っていたのですが、知っていたていどの知識で始めたので環境周りについて深く詰めずに執筆開始。
基本なんとなくの精神で文字を書くことはできたのですが、文章として適切かどうかを意識せずに書いてしまい、手直しの多い結果になってしまった。
textlint を導入したが時期が遅くルールを自分たちに合わせてきちんとメンテナンスできていかなったのでノイズが多くなってしまい、誤字や脱字を見落とすことになってしまった。
明確化&厳格化してルールを満たしてない場合は MR を弾くとかそういった対応を最初からやりつつ、適時メンテンナスを行っていれば校正期につらい思いをしなくても良かったのでは?と思ってしまいます。
やっぱり何事も事前準備は大事です。

もっと短期間で集中してアウトプットすればよかった

本格的な着手から入稿まで半年ほどかかったことになります。
お話を頂いた時期から考えると10ヶ月以上の時間を使い執筆を終えました。
初期に書いた内容も AWS の機能が増強されると内容が陳腐化してしまい加筆、修正する羽目に。
すべてが無駄になったわけではないですが結果非効率な時間の使い方になってしまいました。
増えた機能を追いかけるとあれも書きたいこれも書きたいという欲求に駆られてしまうので後ろ髪を引かれつつも我慢。
進歩の早いクラウドを対象にするのなら短期間で最新の情報を本に含めて出版しないと内容の陳腐化が早いと痛感しました。

良かったこと

結構あったので共同著書に参加して良かったと感じています。

業務上接点の殆どないメンバーと情報共有ができた。

拠点や事業部が違うので殆ど接点のなかったメンバーと色々と情報共有しながら執筆は、新しい知識を得る機会になって良い刺激的になります。

主体的な行動ベースで執筆がすすんだ

誰がリーダーということもなくその時に対応できる人がアクションしていくことでいろいろな作業が進んだ。
自分を含めて 3 名だったので意思決定もスムーズに進み、出版社の方とのやりとりは気づいた人が適時対応するという形で「誰かがやってくれるだろう」とやるべきことを後回しにすることはなかった。
リポジトリのメンテナンス等も人数が少ないがゆえに「やっときますー」の一言でさっとやれるフットワークはやはり大事です。
意思決定に時間がかかると「面倒くさいからいいや」って気持ちが強くなる事が多いのでフットワーク軽く物事をすすめることができたのでストレスがなかったです。

GitLab の理解が進んだ

個人的には GitHub で事が足りるので GitLab を利用するのは執筆が初めてでした。
執筆当初は GitHub は無料ユーザーのプライベートリポジトリはコラボレーターが 3 名まで(だったはず・・)という制約があった。
そのため、プライベートリポジトリのコラボレーターの人数制限のない、GitLab を利用して執筆を始めた。
(今は GitHub もコラボレーターの人数制限もなくなっている。)

textlintを導入時にパイプラインを組み込んで、同じものを GitHub Actions にも用意したので自分の中で一気に理解が進んだのは収穫。
もう、GitLab はお友達。

本を書くという事がいかに難しいかがよくわかった

typo の多い自分としては、お金を出して読んでもらうための文章を書くというのは非常に気を使う作業だった。
書きたいことはたくさんあるがその中で対象読者に伝えるべき内容を吟味して書くというのは文章を書くための良い勉強になった。
当然のことながら、要件定義書を書くのとは全く違う難しさを経験して理解できたのは大きな収穫。
これぞまさしく、百見は一触に如かず。

クラウドな執筆環境を用意できた

文章を書くのは、Gitpod でリポジトリは GitLab。
PDF を作るのは GitLab のパイプライン。
すべての作業はブラウザ上で完結できるので基本どんなマシンでも作業ができる状態にできた。
ローカルでの作業は作業終盤の大きくなった PDF のプレビューのみ。
クラウド時代の執筆環境の入門としてはまずまずな手応え。

次あればやりたいこと

反省点の改善は当然としてそれ以外にも以下の事をやってみたい。

クラウドな執筆環境を更にすすめる

これからは、GitHub にリポジトリをおいて GitHub Codespaces で執筆。 GitHub Actions で PDF 作成とかになると思ってる。
(早期アクセス権持ってないので使い勝手はわかりません。あくまで予想・・)
Chromebook を使ってブラウザ上でお手軽に執筆が完結する日もそう遠くないと信じたい。
ただ、この構成は GitHub がおちたら何もできなくなるので全てを GitHub に依存していいのか?ってことをきちんと考えないといけない。
まとめて管理することで得れるメリットは大きいので GitHub さんにおちないように頑張ってもらうしかないかな。

最後に

色々と書きましたが、初めての事だらけで「ああすれば良かったのかなー」とか思うこともたくさんありましたが、手探りで勧めながらも貴重な経験も多くあり、個人的良い経験になりました。
機会があればチャレンジした方が良いこと間違いなしです!
この経験を生かしてもう一回くらいチャレンジしてみたい。

けど、カクテイシンコクメンドクサイナ・・・

おまけ

今回の執筆活動で利用したものをベースに .md ファイルを PDF に変換する CI を含む GitHub と GitLab のリポジトリのテンプレートを作ってます。
興味があれば利用してみてください。

GitHub 用
GitLab 用

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS] AWS 利用費 の変遷をふり返ってみる

はじめに

_s__o_ です。

2019 年 1 月頃から (個人的に) AWS 利用 (運用) を開始しました。今月 (2020 年 7 月) で約 1 年半。費用としては、現在は、だいたい「6 \$ 強/月」におさまっています。自身の備忘も兼ねて、初期から今までのコスト変遷を追うとともに、コスト変動タイミングで何をしたか、少し振り返っていきたいと思います。

AWS 利用の動機

そもそも、なぜ AWS 利用をしようと思ったのか。理由は主に下記 3 点です。

  • 2018 年 11 月末に結婚。妻と家計を共有できる Web アプリが欲しかった
  • 2018 年 12 月時点、AWS 絡みの案件にアサインされる目処が立っており、自己研鑽をしたかった
  • サーバ運用も生業としていたので、仕事勘を養いたかった

一番上の理由が主です。夫婦間でしか利用しない Web アプリのため、サービス (サーバ) の要件は下記程度でした。

  • 簡単な Web アプリが動く程度のスペックで OK
  • 夜間帯は停止していて OK
  • 何かあっても、最悪 1 日前に戻せれば OK
  • でも、独自ドメインでアクセスしたい (個人的願望)

AWS 利用費の変遷

それでは、本題です。

年表

とりあえず、2018 年 12 月から追っていきたいと思います。当該月に特記があった場合は、特記事項列にイベント内容を記載しています。

年月 費用 EC2 稼働時間 特記事項
2019 年 1 月 13.79 $ 744.1 h 利用開始。EC2 (t2.micro) + Route53 (ドメインは AWS 以外で購入)
2019 年 2 月 7.43 $ 673.3 h インスタンスタイプ見直し (t2.micro → t2.nano)
2019 年 3 月 7.68 $ 744.0 h -
2019 年 4 月 6.57 $ 572.6 h 夜間帯 (0:00~06:00) は停止するようにした
2019 年 5 月 5.29 $ 557.9 h インスタンスタイプ見直し (t2.nano → t3.nano) + EIP の利用停止
2019 年 6 月 5.77 $ 540.1 h -
2019 年 7 月 5.91 $ 558.1 h -
2019 年 8 月 5.91 $ 558.2 h -
2019 年 9 月 5.77 $ 540.1 h -
2019 年 10 月 6.01 $ 558.1 h -
2019 年 11 月 46.26 $ 569.1 h RI (t3.nano) を購入。38\$/年
2019 年 12 月 2.00 $ 650.1 h RI 購入に伴い、停止時間を 03:00~06:00 に変更
2020 年 1 月 2.00 $ 651.0 h -
2020 年 2 月 2.00 $ 609.0 h -
2020 年 3 月 2.00 $ 651.0 h -
2020 年 4 月 2.00 $ 630.0 h -
2020 年 5 月 2.00 $ 650.1 h -
2020 年 6 月 2.01 $ 630.0 h -

特記事項補足

上記年表の特記事項において、下記で少し補足します。

2019 年 1 月

利用開始です。最初は何も考えず「t2.micro」 & 24 時間 365 日稼働で動かしていました。案の定、費用が 10 \$ 越えをしていますね。この費用がきっかけとなって、次月以降に費用見直しが走ります。

また、EC2 と同時に Route53 (パブリックホストゾーン) の利用も開始しています。ドメインは AWS 以外の場所で購入 (1,000 円/年 程度) しているので、AWS 的にはパブリックホストゾーンの利用費用のみ発生しています。利用費用は「0.5 \$/月」です。

ちなみに、利用開始時のシステム構成は下記のとおりです (今も特に変わっていません)。

項目
OS AmazonLinux2
Web nginx
DB sqlite3
言語 Python (Django)
AP uWSGI
備考 1 SSL は nginx に実装
備考 2 cron で 1 日 1 回 sqlite の dump を S3 にバックアップ

(参考)
AWS Amazon Linux2 で Django 2.2以降の環境を構築する

2019 年 2 月

インスタンスタイプを t2.micro から t2.nano に見直しました。このとき、はじめて t2.nano の存在を知りました。。。

(参考)
【速報】新EC2インスタンスタイプt2.nanoが発表されました!

2019 年 4 月

夜間帯 (0:00~6:00) は停止するようにしました。Lambda + CloudWatch で時限停止・時限起動するようにしています。

ちなみに停止中は Sorry 画面を表示するようにしています。Sorry 画面は S3 の静的 Web サイトを使っていますが、HTTPS アクセスだったので CloudFront もかませています。実装に関しては下記のサイトが非常に参考になりました。

(参考)
HTTPS + Route53フェイルオーバーでsorryページを表示する

2019 年 5 月

インスタンスタイプを t2.nano から、次世代の t3.nano に変更しています。

また、この時まではパブリックアクセスのために EIP を利用していました。EIP は、1 つまでなら無料ですが、条件付きです。その条件というのは「EIP が使用中であること」。つまり、EIP を付与した EC2 インスタンスは、稼働させ続ける必要があります。EC2 を動かせば EC2 の稼働費用が発生し、EC2 を止めれば EIP の非稼働費用が発生するということです。2019 年 4 月に夜間帯停止の運用を始めたため、この仕様に気付くことができました。

というわけで、コストをおさえるために EIP の使用を停止しました。代わりに「パブリック IP を Route53 に自動登録するスクリプト」をサーバに仕込みました。このスクリプトはサーバ更新の度に起動され、メタデータから (起動の度に毎回変化する) パブリック IP を取得して、Route53 の A レコードを自動更新してくれます。

(参考)
【EC2】T系ファミリーの概要と、T2,T3の仕様の違いについてのまとめ
EIPで料金発生するパターンとしないパターン

2019 年 11 月

1 年通して使うだろうなという目処が立ったので、さらなるコスト低廉を目指して t3.nano の RI (Reserved Instance) を購入しました。38 \$/年です。

(参考)
RI(リザーブドインスタンス)について出来るだけ簡単にまとめてみた

2019 年 12 月

RI 購入に伴い、従量課金から解放されました。つまり、1 日 1 時間動かそうが 24 時間動かそうが、すべて前払いの定額……ということです。これによって夜間停止の運用は不要となりましたが、下記の理由から夜間停止を完全廃止とせず、時間短縮という形の変更に留めました。

  • 再起動によって不要メモリなどを解放したい
  • 常時稼働前提じゃないシステムの方が、今後 拡張しやすい (AutoScale など)
  • 折角 Sorry ページの仕組みを作ったので、もったいない
  • 折角 パブリック IP 自動更新の仕組みを作ったので(ry

現在の利用費

そんなわけで、現在 (2020 年 6 月) の利用費は下記のとおりです。

項目 金額 備考
EC2 0.00 $ RI 利用のため 0
EBS 1.31 $ EBS & スナップショット 3 世代
IoT 0.01 $ Raspberry Pi 検証用
Route53 0.50 $ Hosted Zone 利用料
消費税 0.19 $
合計 2.01 $

上記に加えて、年額で下記が発生しています。

項目 金額 備考
RI 利用料 38 $/年 t3.nano
独自ドメイン使用料 10.13 $/年 1,089 円/年を 2020/07/04 時点の為替レートで換算
合計 48.13 $/年

年額費用を月割りすると、だいたい「4.01 \$/月」。月々が「2.00 \$/月」強なので、合算して 「6.00 \$/月」強 が、今々の AWS 利用料となります。

まとめ

以上、約 1 年半の AWS 利用費のふり返りでした。最初の「13.79 \$」に比べれば、だいぶスリム化できている気がします。

費用低廉を考える中で、AWS のコストに関する細かい仕様を学べることができました。(文字通り) 身銭を切ったことで、学習に対する真剣度が上がったのかもしれません。「コスト管理」はクラウドサービスの命題でもあるので、この経験は今後強く生きてきそうな気がします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む