AWS CloudFormationについて調べてみた

CloudFormation、なんとなく使っているけどいろいろ機能があるので改めて調べてみた。



目次



CloudFormationとは

インフラストラクチャをテンプレートとしてコードで扱うことでAWSおよびサードパーティのリソースをモデル化しプロビジョニング、管理することができる。

CloudFormation概念

下記3つのコンポーネントで構成されている

  • テンプレートyaml、もしくはjson形式でプロビジョニングするリソースの情報を記述するテキストファイル。CloudFormationを始める場合、まずはテンプレートから作成を行う。
  • スタック:関連リソースをまとめたもの。単一のユニットで管理する。
  • 変更セット:スタックの実行中に変更を加える必要がある場合、変更セットを作成し実装前に確認できる。

テンプレートセクション

セクション 説明
Description テンプレートに関するコメントを記述する。
Metadata テンプレートに対する追加情報を記述する。CloudFormationデザイナーを使用すると自動で追加されるものもある。
Parameters スタック作成・更新時に選択できる値を指定できる。
Mappings キーと値をマッピングする。変数としての使用をする。
Conditions テンプレート内のリソース作成やプロパティ設定を制御する。本番環境と開発環境で異なる設定をしたい場合などに利用する。
Transform テンプレートの特定部分を処理し、それを異なる形式に変換する。
Resources スタックに含めるEC2インスタンスやS3バケットなどのAWSリソースを宣言する。
Outputs スタックの作成が完了した後に返される値を定義する。

組み込み関数

組み込み関数 短縮形 説明
Fn::And !And 条件をtrueまたはfalseで評価するために使用する。Fn::EqualsやFn::Containsなど一緒に使われる。
Fn::Contains !Contains 指定された文字列が文字列リストの少なくとも1つと一致する場合trueを返す。
Fn::Equals !Equals 2つの値を比較し、同じ場合trueを返す。
Fn::If !If テンプレートで条件分岐作成するために使用される。
Fn::Or !Or 指定された条件の中に少なくとも1つがtrueであるかを判定するために使用される。
Fn::Not !Not 指定された条件がfalseであるかとうかを判定するために使用される。
Fn::Sub !Sub 文字列内の変数をその評価された値に置き換える。
Fn::Ref !Ref リソースの値を参照するために使用される。リソースの物理IDを返す。

デザイナー

AWS CloudFormation テンプレートを作成、参照、および変更するためのグラフィックツール。デザイナー を使用すると、ドラッグアンドドロップインターフェースを使用してテンプレートリソースを図示し、統合された JSON および YAML エディタ を使用して詳細を編集できる。新しい AWS CloudFormation ユーザーでも経験豊富なユーザーでも、AWS CloudFormation デザイナーを使用すればテンプレートのリソース間の相互関係をすばやく確認し、簡単にテンプレートを変更できる。

StackSets

複数のアカウントおよび AWS リージョン のスタックを 1 度のオペレーションで、作成、更新、削除できるようにすることで、スタックの機能を拡張する。管理者アカウントを使用して、AWS CloudFormation テンプレートを定義および管理し、指定の AWS リージョン の選択されたターゲットアカウントにスタックをプロビジョニングする基盤としてテンプレートを使用する。




感想

何回もまとめてるけど忘れてしまう。。。( ̄д ̄;;)

Amazon ECS(Fargate)でコンテナ環境を作ってみた

ECSもそろそろ覚えたいので触ってみることにしました(*´ω`*)

やること

下記サイトを参考にECS Fargateでコンテナ環境を作成する。
AWS Fargate の Linux コンテナによるコンソールの使用開始 - Amazon ECS

実践!

1.ECSクラスター作成
 1-1.ECS-[今すぐ始める]

 1-2.[クラスターの作成]

 1-3.クラスターの作成が表示されたら下記を入力
  ・クラスター名:sample-cluster
  ・VPC:デフォルト
  ・サブネット:デフォルト
  ・AWS Fargate(サーバーレス):✅
  ・Amazon EC2 インスタンス:□
  ・ECS Anywhere を使用した外部インスタンス:□


 1-4.[作成]

2.タスク定義作成
 2-1.ECS-[タスク定義]-[新しいタス定義の作成]-プルダウンから[JSONを使用した新しいタスク定義の作成

 2-2.新しいタスク定義の作成が表示されたら、task_definition.jsonに下記を入力

{
    "family": "sample-fargate", 
    "networkMode": "awsvpc", 
    "containerDefinitions": [
        {
            "name": "fargate-app", 
            "image": "public.ecr.aws/docker/library/httpd:latest", 
            "portMappings": [
                {
                    "containerPort": 80, 
                    "hostPort": 80, 
                    "protocol": "tcp"
                }
            ], 
            "essential": true, 
            "entryPoint": [
                "sh",
        "-c"
            ], 
            "command": [
                "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
            ]
        }
    ], 
    "requiresCompatibilities": [
        "FARGATE"
    ], 
    "cpu": "256", 
    "memory": "512"
}


 2-3.[作成]

3.サービス作成
 3-1.ECS-[クラスター]-[sample-cluster]
 3-2.ECS-サービス内の[作成]
 3-2.作成が表示されたら下記を選択
  ・既存のクラスター:sample-cluster
  ・コンピューティングオプション:起動タイプ
  ・起動タイプ:FARGATE
  ・プラットフォームのバージョン:LATEST
  ・アプリケーションタイプ:サービス
  ・タスク定義:sample-fargate
  ・リビジョン:1(最新)
  ・サービス名:sample-service
  ・サービスタイプ:レプリカ
  ・必要なタスク:1


 3-3.[作成]

4.サービス表示
 4-1.ECS-[クラスター]-[sample-cluster]

 4-2.[タスク]タブ-実行中のタスクを選択

 4-3.パブリックIPを選択

 4-4.[Amazon ECS Sample App]ページが表示されることを確認




感想

とりあえずサイトに従ってやってみたが値の設定がよくわからない箇所があるのでもう少し調べないといけないな・・・(;・∀・)

SSH公開鍵認証について調査・検証してみた

SSHは接続するだけなら簡単に設定できるが、いろいろいじくりまわすと細かい機能によってうまく接続できなくなるので、仕様の確認と様々なケースでの接続検証をしてみた。

SSHとは

Secure Shell(セキュアシェル)の略称で、リモートコンピュータと通信するためのプロトコル。 well-knownポートの22番を使用する。認証部分を含めネットワーク上の通信がすべて暗号化されるため、安全に通信することができる。

SSH認証方式

・パスワード認証:接続先にアカウントを作成し、そのアカウントで認証を行う。
・公開鍵認証  :[公開鍵]と[秘密鍵]を使用する認証方式。
         SSH鍵を生成し、接続元に秘密鍵、接続先に公開鍵を保存、
         鍵の保持で認証を行う。

authorized_keysとは

リモートコンピュータ側で公開鍵を保存するために使用するファイル。SSH鍵を作成すると秘密鍵(id_rsa)と、公開鍵(id_rsa.pub)が作成され、リモートコンピュータへ公開鍵をコピーするが、リモートコンピュータではauthorized_keys内の公開鍵で認証を行うため、id_rsa.pubの中身をauthorized_keysへコピーする必要がある。ssh-copy-idコマンドでは自動的にid_rsa.pubをauthorized_keysへコピーを行う。

knows hostsリストとは

SSH (Secure Shell) プロトコルで使用され、接続先のホストの公開鍵を記録する。SSHクライアントが接続を試みるリモートサーバーの公開鍵が、以前に保存されたものと一致することを確認することで、「man-in-the-middle」攻撃を防ぐ。



やること

  1. 公開鍵で接続できるか検証
  2. 接続元の秘密鍵を別の接続元にコピーして接続できるか検証
  3. 公開鍵を転送して別の送信元から接続できるか検証
  4. knows hostsリストによって拒否されること検証

構成

サーバ ホスト名 OS IPアドレス
接続元1 src-server01 Rockey8.6 192.168.10.171/24
接続元2 src-server02 Rockey8.6 192.168.10.172/24
リモートコンピュータ1 dst-server01 Rockey8.6 192.168.10.173/24
リモートコンピュータ2 dst-server02 Rockey8.6 192.168.10.174/24

前提

構成のサーバが作成されていて、22番ポートが解放されていること。
CentOS系を使用する場合はSELINUXが邪魔をするのでオフにするか、いい感じで設定を入れておくこと。

実践!

1.公開鍵で接続できるか検証
 1-1.src-server01とdst-server01で接続用ユーザ(src)作成

root@src-server01# useradd src
root@src-server01# passwd src

root@dst-server01# useradd src
root@dst-server01# passwd src


 1-2.src-server01でsrcユーザのSSH鍵を生成

root@src-server01# su - src
src@src-server01$ ssh-keygen -t rsa
※選択はすべて空白でENTERキーを入力。
Generating public/private rsa key pair.
Enter file in which to save the key (/home/src/.ssh/id_rsa): [ENTER]
Created directory '/home/src/.ssh'.
Enter passphrase (empty for no passphrase): [ENTER]
Enter same passphrase again: [ENTER]
Your identification has been saved in /home/src/.ssh/id_rsa.
Your public key has been saved in /home/src/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:prOvJPNFLdzeTONLEGeJJHi+8GM73makWqu/8l1uieo src@localhost.localdomain
The key's randomart image is:
+---[RSA 3072]----+
|       .. .      |
|      . .o . .   |
|       o  o +    |
|      ...o +     |
|       oS.+ o    |
|       +=o.* .   |
|    o +.o=..*.   |
|     =.=++++o.   |
|      *@E*o.o    |
+----[SHA256]-----+

src@src-server01$ chmod 700 ~/.ssh


 1-3.src-server01からdst-server01へsrcユーザの公開鍵をコピー

src@src-server01$ ssh-copy-id -i ~/.ssh/id_rsa.pub src@192.168.10.173


 1-4.src-server01からdst-server01へパスワードなしでSSH接続できることを確認

src@src-server01$ ssh src@192.168.10.173
src@dst-server01$
※まぁ通常の使い方なので大丈夫ですね


2.接続元の秘密鍵を別の接続元にコピーして接続できるか検証
 src-server01のsrcユーザの秘密鍵をsrc-server02へコピーし検証する

 2-1.src-server02でsrcユーザ作成

root@src-server02# useradd src
root@src-server02# passwd src


 2-2.src-server02のsrcユーザのSSHディレクトリを作成

root@src-server02# su - src
src@src-server02$ mkdir ~/.ssh
src@src-server02$ chmod 600 ~/.ssh


 2-3.src-server01からsrc-server02へ秘密鍵をコピー

src@src-server01$ scp ~/.ssh/id_rsa src@192.168.10.172:/home/src/.ssh/id_rsa
src@192.168.10.172's password:
id_rsa                                        100% 2590     6.0MB/s   00:00


 2-4.src-server02からdst-server01へパスワードなしでSSH接続できることを確認

src@src-server02$ ssh src@192.168.10.173
src@dst-server01$


3.公開鍵を別の接続先へ転送して接続元から接続できるか検証
 dst-server01のsrcユーザの公開鍵をdst-server02へコピーし検証する
 3-1.dst-server02でsrcユーザ作成

root@dst-server02# useradd src
root@dst-server02# passwd src


 3-2.dst-server02のsrcユーザのSSHディレクトリを作成

root@dst-server02# su - src
src@dst-server02$ mkdir ~/.ssh
src@dst-server02$ chmod 700 ~/.ssh


 3-3.dst-server01のsrcユーザの公開鍵をdst-server02へコピー

src@dst-server01$ scp ~/.ssh/authorized_keys src@192.168.10.174:/home/src/.ssh/authorized_keys
src@192.168.10.174's password:
authorized_keys                               100%  563   762.4KB/s   00:00


 3-4.src-server01からdst-server02へパスワードなしでSSH接続できることを確認

src@src-server01$ ssh src@192.168.10.174
src@dst-server02$


4.knows hostsリストによって拒否されること検証
 dst-server01を同じIPアドレスで再作成し、known_hostsによって接続できないことを検証する
 4-1.dst-server01を削除
 4-2.dst-server01を再作成
 4-3.dst-server01でsrcユーザを作成

root@dst-server01# useradd src
root@dst-server01# passwd src


 4-4.dst-server01のsrcユーザのSSHディレクトリを作成

root@dst-server01# su - src
src@dst-server01$ mkdir ~/.ssh
src@dst-server01$ chmod 700 ~/.ssh

 4-5.src-server01からdst-server01へ公開鍵をコピー

src@src-server01$ ssh-copy-id -i ~/.ssh/id_rsa.pub src@192.168.10.173
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/src/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed

/usr/bin/ssh-copy-id: ERROR: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ERROR: @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
ERROR: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ERROR: IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
ERROR: Someone could be eavesdropping on you right now (man-in-the-middle attack)!
ERROR: It is also possible that a host key has just been changed.
ERROR: The fingerprint for the ECDSA key sent by the remote host is
ERROR: SHA256:VY3P9hESLPjaFPumaBXQiP+uQ7SGx3LkIg0zt4k1hjs.
ERROR: Please contact your system administrator.
ERROR: Add correct host key in /home/src/.ssh/known_hosts to get rid of this message.
ERROR: Offending ECDSA key in /home/src/.ssh/known_hosts:1
ERROR: ECDSA host key for 192.168.10.173 has changed and you have requested strict checking.
ERROR: Host key verification failed.
※すでにここでエラーになる。。。

src@src-server01$ rm -rf ~/.ssh/known_hosts
※known_hostsを削除して接続を試みる

src@src-server01$ ssh-copy-id -i ~/.ssh/id_rsa.pub src@192.168.10.173
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/src/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
src@192.168.10.173's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'src@192.168.10.173'"
and check to make sure that only the key(s) you wanted were added.
※今度はコピーOK!

src@src-server01$ ssh src@192.168.10.173
※パスワードなしでの接続もOK!




感想

~/.sshとauthoraized_keysのパーミッションではまった。。。特に~/.ssh。これも600にしないと正しく動かなかった。はぁ時間かかった( ̄д ̄;;)

Amazon ECS(Elastic Container Service)について調べてみた

ECSを使っていこうと思ったけど、いろいろ覚えることがありそうだったのでまずは調べてみた。

ECSとは

コンテナ化されたアプリケーションを簡単にデプロイ、管理、スケーリングできる、完全マネージド型のコンテナオーケストレーションサービス。ECS Anywhere を使用すると、Amazon ECS コンソールと AWS CLI から、オンプレミスのコンテナワークロードの管理ができる。




ECS起動タイプ

ECSでは下記2種類の起動タイプのコンテナ実行環境を提供している。

  • Fargate起動タイプ
  • EC2起動タイプ

Fargate起動タイプとは

Amazon ECSで使用できるテクノロジーであり、サーバーやAmazon EC2インスタンスクラスターを管理することなくコンテナを実行できる。


EC2起動タイプとは

EC2インスタンスにコンテナクラスタを設定してデプロイしコンテナを実行する。




ECSコンポーネント

ECSでは下記コンポーネントが動作し環境構築・維持を行っている。

  • クラスタ
  • コンテナ
  • イメージ
  • タスク定義
  • タスク
  • サービス
  • コンテナエージェント

クラスターとは

タスクまたはサービスの論理グループ。クラスターを使用して、アプリケーションを分離できる。

アプリケーションの単位かな。

コンテナとは

ソフトウェアアプリケーションの実行に必要なものをすべて保持するソフトウェア開発の単位。コードや、ランタイム、システムツール、システムライブラリなどが含まれる。

Dockerのコンテナと同じイメージ。

イメージとは

Dockerfileから構築されるコンテナのイメージ。コンテナに含まれるすべてのコンポーネントを指定するプレーンテキストファイル。これらのイメージは構築された後にダウンロード可能な場所であるレジストリに保存される。

DockerfileをECSではイメージという模様。

タスク定義とは

アプリケーションを形成する1つ以上のコンテナを記述するテキストファイル。JSON形式。最大10個のコンテナを記述することができる。

コンテナのリソースに関する設定ができる模様。CPU、メモリなど。ALBへの関連付けもここで行う。

タスクとは

タスク定義をインスタンス化したもの。

これはまんまですね。

サービスとは

ECSクラスタで必要な数のタスクを同時実行して維持できる機能。

Kubernetesのスケジューラーのようなものかな。

コンテナエージェントとは

ECSクラスター内の各コンテナインスタンス上で実行される。実行中のタスクとリソースのコンテナの使用率に関する情報をECSへ送信する。また、ECSからのリクエストを受信すると、タスクを開始および停止する。

エージェントが動いているんですね( ̄д ̄)フムフム



感想

EKSとの違いがよくわからなかったけど、おそらくECSはコンテナランタイム(Dockerなど)のマネージド化で、EKSはKubernetesのマネージド化という感じかな。次回以降使ってみて確認していきたいと思います。( ̄△ ̄)

terraformでAmazon EC2を作成し、ユーザーデータを使って初期設定をしてみた

terraformでユーザーデータを渡す場合いくつかやり方があって、少し癖があったのでまとめてみた。

EC2ユーザーデータとは

EC2ではインスタンスを起動後にユーザーデータを渡して、自動設定タスクを実行したり、スクリプトを実行することができる機能。




やること

terraformでAmazon EC2を作成し、初期設定まで完了させる。
今回はhttpdをインストールし、自動起動設定を行い、トップページに表示させるhtmlファイルの作成および配置までを行う。

前提

下記をもとにterraformのインストールまで完了していること。 amegaeru.hatenablog.jp

実践!

1.ヒアドキュメントでユーザーデータを受け渡し

ヒアドキュメントとは
ヒアドキュメントとは、プログラミング言語などの機能の一つで、特殊な記号などを含む文字列リテラルソースコード中に記述するための特別な記法のこと。

 1-1.tfファイル作成

$ vi main.tf
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "sample" {
  ami                                         = "ami-07c2a88388bb80eb0"
  instance_type                          = "t2.micro"
  availability_zone                     = "ap-northeast-1a"
  subnet_id                                = "subnet-08ced1e54ca9c6451"
  key_name                                = "sample-key"
  associate_public_ip_address   = "true"
  user_data = <<EOF
    #!/bin/bash
    yum install -y httpd
    echo "<html><body>Hello World!</body></html>" > /var/www/html/index.html
    systemctl enable --now httpd
  EOF

  tags = {
    Name = "sample-instance"
  }
}


 1-2.terraform実行

$ terraform init
$ terraform validate
$ terraform plan
$ terraform apply
※Enter a value:が表示されたら[yes]を入力


 1-3.動作確認1(terraform showコマンド)

$ terraform show
# aws_instance.sample:
resource "aws_instance" "sample" {
    ami                                  = "ami-07c2a88388bb80eb0"
    arn                                  = "arn:aws:ec2:ap-northeast-1:xxxxxxxx:instance/i-0f00269ca2d8a8d01"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1a"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-0f00269ca2d8a8d01"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t2.micro"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    key_name                             = "sample-key"
    monitoring                           = false
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-00fbe50b3d4fb355f"
    private_dns                          = "ip-172-31-47-60.ap-northeast-1.compute.internal"
    private_ip                           = "172.31.47.60"
    public_dns                           = "ec2-13-231-213-119.ap-northeast-1.compute.amazonaws.com"
    public_ip                            = "13.231.213.119"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-08ced1e54ca9c6451"
    tags                                 = {
        "Name" = "sample-instance"
    }
    tags_all                             = {
        "Name" = "sample-instance"
    }
    tenancy                              = "default"
    user_data                            = "3876765ecb6ea8c6b0d1737c4391ae33d2d0eb4e"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-08591299bb5c05e63",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    cpu_options {
        core_count       = 1
        threads_per_core = 1
    }

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
        instance_metadata_tags      = "disabled"
    }

    private_dns_name_options {
        enable_resource_name_dns_a_record    = false
        enable_resource_name_dns_aaaa_record = false
        hostname_type                        = "ip-name"
    }

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/xvda"
        encrypted             = false
        iops                  = 100
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-0ab26bbb43da00eba"
        volume_size           = 8
        volume_type           = "gp2"
    }
}


 1-4.動作確認2(ブラウザ表示)
  ブラウザから接続し[Hello World!]が表示されることを確認
  ※接続IPはEC2のインスタンスから確認


 1-5.削除

$ terraform destroy
※Enter a value:が表示されたら[yes]を入力


2.外部ファイルでユーザデータを受け渡し
 2-1.スクリプト作成

$ vi script.sh
#!/bin/bash
yum install -y httpd
echo "<html><body>Hello World!</body></html> > /var/www/html/index.html
systemctl enable --now httpd


 2-2.trファイル作成

$ vi main.tf
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "sample" {
  ami                                         = "ami-07c2a88388bb80eb0"
  instance_type                          = "t2.micro"
  availability_zone                     = "ap-northeast-1a"
  subnet_id                                = "subnet-08ced1e54ca9c6451"
  key_name                                = "sample-key"
  associate_public_ip_address   = "true"
  user_data = file("script.sh")

  tags = {
    Name = "sample-instance"
  }
}


 2-3.terraform実行

$ terraform apply
※Enter a value:が表示されたら[yes]を入力


 2-4.動作確認1(terraform showコマンド)

$ terraform show
# aws_instance.sample:
resource "aws_instance" "sample" {
    ami                                  = "ami-07c2a88388bb80eb0"
    arn                                  = "arn:aws:ec2:ap-northeast-1:xxxxxx:instance/i-00e962baabd76623f"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1a"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-00e962baabd76623f"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t2.micro"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    key_name                             = "sample-key"
    monitoring                           = false
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-09ad59bb16d6d34bb"
    private_dns                          = "ip-172-31-44-223.ap-northeast-1.compute.internal"
    private_ip                           = "172.31.44.223"
    public_dns                           = "ec2-54-248-13-131.ap-northeast-1.compute.amazonaws.com"
    public_ip                            = "54.248.13.131"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-08ced1e54ca9c6451"
    tags                                 = {
        "Name" = "sample-instance"
    }
    tags_all                             = {
        "Name" = "sample-instance"
    }
    tenancy                              = "default"
    user_data                            = "3ce9f5f33c8fdd06711792cc996744ebff4ae6c8"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-08591299bb5c05e63",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    cpu_options {
        core_count       = 1
        threads_per_core = 1
    }

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
        instance_metadata_tags      = "disabled"
    }

    private_dns_name_options {
        enable_resource_name_dns_a_record    = false
        enable_resource_name_dns_aaaa_record = false
        hostname_type                        = "ip-name"
    }

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/xvda"
        encrypted             = false
        iops                  = 100
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-05c42553881cb5283"
        volume_size           = 8
        volume_type           = "gp2"
    }
}


 2-5.動作確認2(ブラウザ表示)
  ブラウザから接続し[Hello World!]が表示されることを確認


 2-6.削除

$ terraform destroy
※Enter a value:が表示されたら[yes]を入力



感想

ヒアドキュメントではechoで複数行使えなかったので外部ファイルからの受け渡しが楽でした(*´ω`*)

terraformでAmazon EC2インスタンスを作成してみた

眠い。眠すぎるのでterraformでAmazon EC2でも作ります((-_-)zzz

terraformとは

HashiCorp社によって作成されたオープンソースのIaC(Infrastracture as Code)ツール。

※as aじゃないみたいです。( ;∀;)

terraformの使い方

設定値を記載したtfファイルを作成し、terraformコマンドで各リソースの作成を行う。



やること

AWS CloudShellにterraformをインストールし、EC2インスタンスを作成する。

前提

  • 事前にAWS VPC、Subnet、SecurityGroup、KeyPairが作成されていること
    ※ CloudShellだとSecretKeyが不要なので少し楽♪

実践!

1.terraformインストール

$ TER_VER=`curl -s https://api.github.com/repos/hashicorp/terraform/releases/latest | grep tag_name | cut -d: -f2 | tr -d \"\,\v | awk '{$1=$1};1'` 
$ wget https://releases.hashicorp.com/terraform/${TER_VER}/terraform_${TER_VER}_linux_amd64.zip
$ unzip terraform_${TER_VER}_linux_amd64.zip
$ sudo mv terraform /usr/local/bin/
$ terraform --version
Terraform v1.4.6
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v5.0.0


2.EC2作成
 2-1.tfファイル作成

$ vi main.tf
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "sample" {
  ami                                         = "ami-07c2a88388bb80eb0"
  instance_type                          = "t2.micro"
  availability_zone                     = "ap-northeast-1a"
  subnet_id                                = "subnet-08ced1e54ca9c6451"
  key_name                                = "sample-key"
  associate_public_ip_address   = "true"

  tags = {
    Name = "sample-instance"
  }
}


 2-2.terraform初期化

$ terraform init
Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.0.0...
- Installed hashicorp/aws v5.0.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.


 2-3.tfファイル構文チェック

$ terraform validate
Success! The configuration is valid.


 2-4.plan実行

$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.sample will be created
  + resource "aws_instance" "sample" {
      + ami                                  = "ami-07c2a88388bb80eb0"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + availability_zone                    = "ap-northeast-1"
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "20230415"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = "subnet-08ced1e54ca9c6451"
      + tags                                 = {
          + "Name" = "sample-instance"
        }
      + tags_all                             = {
          + "Name" = "sample-instance"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.


 2-5.作成実行

$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.sample will be created
  + resource "aws_instance" "sample" {
      + ami                                  = "ami-07c2a88388bb80eb0"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + availability_zone                    = "ap-northeast-1a"
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "20230415"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = "subnet-08ced1e54ca9c6451"
      + tags                                 = {
          + "Name" = "sample-instance"
        }
      + tags_all                             = {
          + "Name" = "sample-instance"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

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.sample: Creating...
aws_instance.sample: Still creating... [10s elapsed]
aws_instance.sample: Still creating... [20s elapsed]
aws_instance.sample: Still creating... [30s elapsed]
aws_instance.sample: Creation complete after 32s [id=i-089e05ecb75248a81]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.


 2-6.確認

$ terraform show

# aws_instance.sample:
resource "aws_instance" "sample" {
    ami                                  = "ami-07c2a88388bb80eb0"
    arn                                  = "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxx:instance/i-089e05ecb75248a81"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1a"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-089e05ecb75248a81"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t2.micro"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    key_name                             = "20230415"
    monitoring                           = false
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-0b2ef805aa79892b5"
    private_dns                          = "ip-172-31-35-9.ap-northeast-1.compute.internal"
    private_ip                           = "172.31.35.9"
    public_dns                           = "ec2-18-182-64-188.ap-northeast-1.compute.amazonaws.com"
    public_ip                            = "18.182.64.188"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-08ced1e54ca9c6451"
    tags                                 = {
        "Name" = "sample-instance"
    }
    tags_all                             = {
        "Name" = "sample-instance"
    }
    tenancy                              = "default"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-08591299bb5c05e63",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    cpu_options {
        core_count       = 1
        threads_per_core = 1
    }

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
        instance_metadata_tags      = "disabled"
    }

    private_dns_name_options {
        enable_resource_name_dns_a_record    = false
        enable_resource_name_dns_aaaa_record = false
        hostname_type                        = "ip-name"
    }

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/xvda"
        encrypted             = false
        iops                  = 100
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-0528030a6c085e51a"
        volume_size           = 8
        volume_type           = "gp2"
    }
}


3.EC2インスタンス削除

$ terraform destroy
aws_instance.sample: Refreshing state... [id=i-089e05ecb75248a81]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.sample will be destroyed
  - resource "aws_instance" "sample" {
      - ami                                  = "ami-07c2a88388bb80eb0" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxx:instance/i-089e05ecb75248a81" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-1a" -> null
      - cpu_core_count                       = 1 -> null
      - cpu_threads_per_core                 = 1 -> null
      - disable_api_stop                     = false -> null
      - disable_api_termination              = false -> null
      - ebs_optimized                        = false -> null
      - get_password_data                    = false -> null
      - hibernation                          = false -> null
      - id                                   = "i-089e05ecb75248a81" -> null
      - instance_initiated_shutdown_behavior = "stop" -> null
      - instance_state                       = "running" -> null
      - instance_type                        = "t2.micro" -> null
      - ipv6_address_count                   = 0 -> null
      - ipv6_addresses                       = [] -> null
      - key_name                             = "20230415" -> null
      - monitoring                           = false -> null
      - placement_partition_number           = 0 -> null
      - primary_network_interface_id         = "eni-0b2ef805aa79892b5" -> null
      - private_dns                          = "ip-172-31-35-9.ap-northeast-1.compute.internal" -> null
      - private_ip                           = "172.31.35.9" -> null
      - public_dns                           = "ec2-18-182-64-188.ap-northeast-1.compute.amazonaws.com" -> null
      - public_ip                            = "18.182.64.188" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-08ced1e54ca9c6451" -> null
      - tags                                 = {
          - "Name" = "sample-instance"
        } -> null
      - tags_all                             = {
          - "Name" = "sample-instance"
        } -> null
      - tenancy                              = "default" -> null
      - user_data_replace_on_change          = false -> null
      - vpc_security_group_ids               = [
          - "sg-08591299bb5c05e63",
        ] -> null

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> null
        }

      - cpu_options {
          - core_count       = 1 -> null
          - threads_per_core = 1 -> null
        }

      - credit_specification {
          - cpu_credits = "standard" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - maintenance_options {
          - auto_recovery = "default" -> null
        }

      - metadata_options {
          - http_endpoint               = "enabled" -> null
          - http_put_response_hop_limit = 1 -> null
          - http_tokens                 = "optional" -> null
          - instance_metadata_tags      = "disabled" -> null
        }

      - private_dns_name_options {
          - enable_resource_name_dns_a_record    = false -> null
          - enable_resource_name_dns_aaaa_record = false -> null
          - hostname_type                        = "ip-name" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/xvda" -> null
          - encrypted             = false -> null
          - iops                  = 100 -> null
          - tags                  = {} -> null
          - throughput            = 0 -> null
          - volume_id             = "vol-0528030a6c085e51a" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.sample: Destroying... [id=i-089e05ecb75248a81]
aws_instance.sample: Still destroying... [id=i-089e05ecb75248a81, 10s elapsed]
aws_instance.sample: Still destroying... [id=i-089e05ecb75248a81, 20s elapsed]
aws_instance.sample: Destruction complete after 30s

Destroy complete! Resources: 1 destroyed.
$ terraform show
The state file is empty. No resources are represented.



感想

CloudFormationとどっちが楽だろう。あんまり変わらない気がするから好みかな。

Grafanaのプルダウンメニューで1つのグラフで対象ごとに表示させてみた

同じメトリクスなのに対象が違うと複数グラフを表示させていたが、動的に対象を変更できるようなので試してみた。
こんな感じ。対象分だけグラフを作らなければいけないので不便。。。

やること

Grafanaのダッシュボードで変数機能を使い、プルダウンで1つのグラフから動的に対象を変更する。

前提

  • Prometheus、Grafanaがインストールされていること
  • 複数ノードのメトリクスが取得できていること

環境


実践!

1.ダッシュボードを作成
 1-1.GrafanaWebコンソールからログイン

 1-2.左側の[Create]-[Dashboard]

 1-3.[Add an empty panel]をクリック

 1-4.[Metrics]に下記を入力
   node_cpu_seconds_total
   ※今回はこのメトリクスで作成します。
   ※グラフが表示されない場合はほかの項目を選択すると表示されたりします。バグかな。。。

 1-5.[Apply]

  これだと全対象が表示されて見づらいので選択できるようにしていきます。


2.変数を作成
 2-1.[Panel Title]-[Edit]

 2-2.[歯車]
 2-3.[Variables]-[Add variable]

 2-4.下記を入力
  ・General
   ・Name:instance
   ・Type:Query
   ・Label:空白
   ・Hide:空白
   ・Description:空白
  ・Query Options
   ・Data Source:Prometheus
   ・Refresh:Never
   ・Qury:label_values(node_cpu_seconds_total,instance)
   ・Regex:空白
   ・Sort:Disable
  ・Selection Options
   ・Multi-value:オフ
   ・Include All Option:オフ
  ・Value Group tags
   ・Enable:オフ

 2-5.[Update]
 2-6.左上の[←]でPanel編集画面に戻り、画面上に[instance]のプルダウンが表示されていることを確認


3.Metrics編集
 3-1.Panel編集画面で[Metrics]を下記に修正
  node_cpu_seconds_total{instance="$instance"}

  ※修正がバグる場合はメモ帳などで編集して、貼り付ける
  ※下記は正しいように見えるが}の色がおかしく正しくグラフが表示されない。。。

 3-2.[Appy]

4.動作確認
 ダッシュボード画面でプルダウンを変更しグラフが変化することを確認



 


感想

まぁ見れることが重要なのでずらっと並べてもよいのですがオサレなほうがやる気がでるので(*´ω`*)