EC2 インスタンスのメタデータを取得する ec2-metadatafs コマンドが便利すぎた。
AWS の EC2 インスタンスのメタデータを取得する ec2-metadatafs を使ってみたら便利すぎたのでメモ。
ec2-metadatafs ってなに?
ec2-metadatafs は AWS の EC2 インスタンスのメタデータを取得できるコマンド。
ec2-metadatafs の特徴は EC2 インスタンスのメタデータをファイルシステム上にマウントすることによって ls
とか cat
とか grep
とかの CLI ツールと一緒に使うことが容易になること。
また、メタデータをファイルシステム上に配置するのでシェルの補完機能を最大限に活用することができるのがとても便利。
さっそく使ってみる。
$ mkdir metadata $ ec2-metadatafs --tags metadata/ 2019/08/12 05:38:35 [INFO] forked child with PID 3459 2019/08/12 05:38:35 [INFO] child process successfully mounted $ tree metadata/ metadata/ ├── dynamic │ └── instance-identity │ ├── document │ ├── pkcs7 │ ├── rsa2048 │ └── signature ├── meta-data │ ├── ami-id │ ├── ami-launch-index │ ├── ami-manifest-path │ ├── block-device-mapping │ │ ├── ami │ │ └── root │ ├── events │ ├── hostname │ ├── iam │ │ ├── info │ │ └── security-credentials │ │ └── ec2-describetag-role │ ├── identity-credentials │ ├── instance-action │ ├── instance-id │ ├── instance-type │ ├── local-hostname │ ├── local-ipv4 │ ├── mac │ ├── metrics │ ├── network │ │ └── interfaces │ │ └── macs │ │ └── 06:e5:0c:b8:f7:3e │ │ ├── device-number │ │ ├── interface-id │ │ ├── ipv4-associations │ │ ├── local-hostname │ │ ├── local-ipv4s │ │ ├── mac │ │ ├── owner-id │ │ ├── public-hostname │ │ ├── public-ipv4s │ │ ├── security-group-ids │ │ ├── security-groups │ │ ├── subnet-id │ │ ├── subnet-ipv4-cidr-block │ │ ├── vpc-id │ │ ├── vpc-ipv4-cidr-block │ │ └── vpc-ipv4-cidr-blocks │ ├── placement │ │ └── availability-zone │ ├── profile │ ├── public-hostname │ ├── public-ipv4 │ ├── public-keys │ │ └── 0 │ │ └── openssh-key │ ├── reservation-id │ ├── security-groups │ └── services │ ├── domain │ │ └── amazonaws.com │ └── partition └── tags ├── Tag1 └── Tag2
備忘録までにそれぞれのコマンドがやっていることを軽く書いておく。
まず metadata
ディレクトリを作っているところ。
$ mkdir metadata
EC2 インスタンスのメタデータをマウントするディレクトリを作っている。 メタデータをマウントする場所はどこでもいいと思うけどユーザーが複数いてそれぞれのユーザーがメタデータを取得するのなら、メタデータはどのユーザーからも見える場所にマウントするとよいと思う。
次は ec2-metadatafs
コマンドを実行しているところ。
$ ec2-metadatafs --tags metadata/ 2019/08/12 05:38:35 [INFO] forked child with PID 3459 2019/08/12 05:38:35 [INFO] child process successfully mounted
ec2-metadatafs コマンドを使って EC2 インスタンスのメタデータをさきほど作った metadata
にマウントする。それだけ。
あと EC2 インスタンスのタグを取得するために --tags
オプションを指定しているがタグは取得しないのなら指定する必要はない。
次は EC2 インスタンスのメタデータをマウントした metadata
ディレクトリを tree してみたところ。
EC2 インスタンスのメタデータがファイルシステム上にマウントされているのがわかる。
$ tree metadata/
metadata/
├── dynamic
│ └── instance-identity
│ ├── document
│ ├── pkcs7
│ ├── rsa2048
│ └── signature
└── meta-data
├── ami-id
# 長いので省略
ec2-metadatafs を使ってみる
EC2 インスタンスのメタデータがファイルシステム上にマウントされる、ただそれだけのことなのだが実際に使ってみると想像以上に便利なのでいくつか使用例を書いておく。
試しにインスタンスタイプを取得してみる。
$ cat metadata/meta-data/instance-type t2.micro
簡単。
もう一つ試しに EC2 インスタンスが動いているアベイラビリティゾーンを取得してみる。
$ cat metadata/meta-data/placement/availability-zone ap-northeast-1a
すごく簡単。
ec2-metadatafs が便利なところはシェルの補完機能が働くので「あのメタデータどこだっけ?」ってときも雰囲気で入力して補完機能に任せる、みたいな使い方ができること。これが本当に便利。
補完機能を使うのすら面倒なときは find
コマンドとかを使えば一切考える必要もない。
$$ find metadata/ -name "*zone*" metadata/meta-data/placement/availability-zone
繰り返すが便利。
あとタグを取得できるのが地味だけどかなり便利。
$ ls metadata/tags/
Tag1 Tag2
$ cat metadata/tags/Tag1
Tag1Value
EC2 インスタンスのメタデータを取得する方法はいろいろある
EC2 インスタンスのメタデータを取得する方法は ec2-metadatafs の他にもあるのでメモしておく。 それぞれがメリット・デメリットがあるので、状況によって使い分けるのがいいと思う。
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/
にアクセスすると EC2 インスタンスのメタデータを取得できる。
$ curl http://169.254.169.254/latest/meta-data/ ami-id ami-launch-index ami-manifest-path block-device-mapping/ events/ hostname identity-credentials/ instance-action instance-id instance-type local-hostname local-ipv4 mac metrics/ network/ placement/ profile public-hostname public-ipv4 public-keys/ reservation-id security-groups services/
インスタンスタイプを取得してみる。
$ curl http://169.254.169.254/latest/meta-data/instance-type t2.micro
難しいことは一切ないが URL を打ち込むのが面倒くさいし URL を打ち間違えたときに 404 が返ってくるのがイラつく。コピペしたくなってくる。「あれ、インスタンスタイプの URL はなんだったっけ?」というときは http://169.254.169.254/latest/meta-data/
にアクセスして結果を眺めて「あ、instance-type だったな」とやる以外にないのが不便。
あと、どうやってもタグを取得できないのが地味に結構不便。
ただ、http://169.254.169.254/latest/meta-data/
の素晴らしいところは EC2 デフォルトの状態でも使えるということ。
あと、スクリプトの中からメタデータを取得したいときみたいなときは事前に知りたいメタデータの URL とかを調べているだろうし動作も確認しているだろうから、URL を打ち込むのが面倒くさいとか URL を打ち間違えたとかはないはず。
ec2-metadata コマンド
ec2-metadata
は EC2 インスタンスのメタデータを取得するコマンド。
$ ec2-metadata --help ec2-metadata v0.1.2 Use to retrieve EC2 instance metadata from within a running EC2 instance. e.g. to retrieve instance id: ec2-metadata -i to retrieve ami id: ec2-metadata -a to get help: ec2-metadata --help For more information on Amazon EC2 instance meta-data, refer to the documentation at http://docs.amazonwebservices.com/AWSEC2/2008-05-05/DeveloperGuide/AESDG-chapter-instancedata.html Usage: ec2-metadata <option> Options: --all Show all metadata information for this host (also default). -a/--ami-id The AMI ID used to launch this instance -l/--ami-launch-index The index of this instance in the reservation (per AMI). -m/--ami-manifest-path The manifest path of the AMI with which the instance was launched. -n/--ancestor-ami-ids The AMI IDs of any instances that were rebundled to create this AMI. -b/--block-device-mapping Defines native device names to use when exposing virtual devices. -i/--instance-id The ID of this instance -t/--instance-type The type of instance to launch. For more information, see Instance Types. -h/--local-hostname The local hostname of the instance. -o/--local-ipv4 Public IP address if launched with direct addressing; private IP address if launched with public addressing. -k/--kernel-id The ID of the kernel launched with this instance, if applicable. -z/--availability-zone The availability zone in which the instance launched. Same as placement -c/--product-codes Product codes associated with this instance. -p/--public-hostname The public hostname of the instance. -v/--public-ipv4 NATted public IP Address -u/--public-keys Public keys. Only available if supplied at instance launch time -r/--ramdisk-id The ID of the RAM disk launched with this instance, if applicable. -e/--reservation-id ID of the reservation. -s/--security-groups Names of the security groups the instance is launched in. Only available if supplied at instance launch time -d/--user-data User-supplied data.Only available if supplied at instance launch time.
インスタンスタイプを取得してみる。
$ ec2-metadata --instance-type
instance-type: t2.micro
<メタデータの名前>: <メタデータの値>
みたいな感じで出力されるので、メタデータの値たとえばインスタンスタイプの t2.micro
の部分だけを取得するなら cut とかで切り出す感じ。ちょっと面倒くさい。
$ ec2-metadata --instance-type | cut -d ' ' -f 2 t2.micro
URL を打ち込む必要がないしショートオプションを使うとタイプ量はさらに少なくなるのが便利。 あと AMI が Amazon Linux ならデフォルトで使えるメリットが大きい。
ただ、メタデータの値を cut とかで切り出すのが面倒くさい。 あと、どうやってもタグを取得できないのが地味に結構不便。
ec2-metadatafs のインストール
ec2-metadatafs コマンドが便利な点と使い方の雰囲気は書いたのでインストール方法も書いておく。
といっても、curl で https://github.com/jszwedko/ec2-metadatafs/releases/download/<バージョン>/linux_amd64
からダウンロードして実行パーミッションを付けてパスが通ったところに置くだけ。
$ curl -sL https://github.com/jszwedko/ec2-metadatafs/releases/download/1.0.0/linux_amd64 > ec2-metadatafs $ chmod +x ec2-metadatafs $ sudo mv ec2-metadatafs /usr/bin/
ec2-metadatafs は EC2 メタデータをファイルシステム上にマウントするために FUSE に依存しているので FUSE をインストールしておく。
$ sudo yum install -y fuse
あとタグを取得するときは IAM ロールが必要になるのでつけておく。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeTags"], "Resource": ["*"] } ] }
IAM ロールを設定したくないときは ec2-metadatafs
コマンドを使うときに --aws-access-key-id
オプションとか --aws-secret-access-key
とかを指定してあげてもいい。
ec2-metadatafs を使い終わったら
ec2-metadatafs
を使い終わったらというか「あんまり便利じゃないしやっぱ使わなくていいや」というお気持ちになったときは EC2 インスタンスのメタデータをアンマウントしておく。
$ fusermount -u metadata
これだけ。
AWS CLI で意図していないプロファイルを使ってしまうのを防止するコマンドを書いたメモ。
AWS CLI で意図していないプロファイルを使ってしまうのを防止するコマンドを書いたメモ。
動機
AWS CLI はプロファイルを --profile
オプションや AWS_DEFAULT_PROFILE
環境変数で指定できるようになっていて AWS アカウントや IAM ユーザーが複数あってもあまり手間なくいろいろな操作を行うことができる反面、使うプロファイルを間違うといとも簡単に悲惨なことが起こり得る。
日常の作業の多くは AWS アカウント向け / 操作対象の環境向けのスクリプトを書くなりして操作の入り口から分けてしまうなどの対策を取ればかなりの事故は減らせるが、ちょっとしたお試しとか突発的な作業をするときはどうしても生の aws
コマンドを触ってしまいがちでどうしても事故が発生しやすくなってしまう。
そこで、AWS CLI を使うときに Github のリポジトリを消すときの Please type in the name of the repository to confirm.
みたいに処理対象を入力させるシステムがあったら事故が減らせるのでは? と思った。
↓こういうやつ。
ラップコマンドの実行イメージ
実行イメージはこんな感じ。
AWS CLI のラップコマンド staging-hoge-aws
を実行すると対象のアプリケーションと対象の環境を聞いてくる。この実行イメージは hoge
が対象のアプリケーションで staging
が環境。
staging-hoge-aws
コマンドはコマンド内にハードコーディングされたアプリケーションおよび環境とユーザーが入力するアプリケーションおよび環境が 一致するときだけ実際の aws コマンドを実行する。この実行イメージは aws s3 ls
が実際のコマンド。
$ staging-hoge-aws s3 ls
Enter target application name: hoge
Enter target environment name: staging
2019-07-27 11:13:21 xxx-bucket
2019-07-27 11:13:21 yyy-bucket
staging-hoge-aws
コマンドはユーザーが入力するアプリケーションか環境が間違っているとメッセージを表示して実際のコマンドは実行しない。
$ staging-hoge-aws s3 ls
Enter target application name: fuga
Invalid application name: fuga
このラップコマンドはアプリケーションと環境の組み合わせ分を作っておく。
たとえば hoge
アプリケーションは本番環境とステージング環境があるなら production-hoge-aws
と staging-hoge-aws
を作っておく。
本番環境用のラップコマンドはアプリケーションと環境の確認に加えて「本番環境をいじろうとしてるけど本当にいいの?」的なことを聞いてきてユーザーが yes
を入力したときだけ実際の aws コマンドを実行する。ユーザーが yes
以外を入力したときは実際の aws コマンドは実行しない。
$ production-hoge-aws s3 ls Enter target application name: hoge Enter target environment name: production You will make changes to the production environment!!!!! Are you sure you want to continue (yes/no)?: yes # ユーザーが yes を入力したときだけ実際の aws コマンドが実行される 2019-07-27 11:13:21 xxx-bucket 2019-07-27 11:13:21 yyy-bucket
ラップコマンドの中身
staging-hoge-aws
はこんな感じになっている。
単純に対象のアプリケーションと環境がハードコーディングしてあってユーザーの入力と一致するときに実際の aws コマンドを実行するだけ。
新しいアプリケーションあるいは環境用のコマンドをつくるときは TARGET_APP
と TARGET_ENV
だけ書き換える感じ。
#!/bin/bash TARGET_APP=hoge TARGET_ENV=staging PROFILE=${TARGET_ENV}-${TARGET_APP} echo -n 'Enter target application name: ' read APP_NAME if [ "${APP_NAME}" != "${TARGET_APP}" ]; then echo "Invalid application name: ${APP_NAME}" exit 1 fi echo -n 'Enter target environment name: ' read ENV_NAME if [ "${ENV_NAME}" != "${TARGET_ENV}" ]; then echo "Invalid environment name: ${ENV_NAME}" exit 1 fi if [ "${ENV_NAME}" == "production" ]; then echo "You will make changes to the production environment!!!!!" echo -n 'Are you sure you want to continue (yes/no)?: ' read CONFIRM if [ "${CONFIRM}" != "yes" ]; then exit 1 fi fi echo '' aws --profile $PROFILE "$@"
プロファイル
config ファイル
config
ファイルはこんな感じにしておく。
[profile staging-hoge] output = json region = ap-northeast-1 [profile production-hoge] output = json region = ap-northeast-1
credentials ファイル
credentials
ファイルはこんな感じにしておく。
[staging-hoge] aws_access_key_id = <ステージング環境のアクセスキー> aws_secret_access_key = <ステージング環境のシークレットキー> [production-hoge] aws_access_key_id = <本番環境のアクセスキー> aws_secret_access_key = <本番環境のシークレットキー>
参考にしたサイト
本番環境とステージング環境を取り違える事故を減らしたくて Twitter で聞いてみたら本職のインフラエンジニアから DevOps やってる人まで珠玉の知見を教えてもらいまくったのを参考にした。感謝しかない……っ!!
ipa ファイルから CFBundleVersion を確認するワンライナーのメモ。
ipa ファイルから CFBundleVersion を確認するワンライナーのメモ。
したいこと
ipa ファイル (iOS のアプリ) しかない状態で CFBundleVersion を確認したい。 中間ファイルとかは作りたくない。
確認する方法
CFBundleVersion は ipa ファイルのなかの Payload/<アプリ>.app/Info.plist
に記述されているので、それを確認すればよい。
Info.plist の中身はバイナリーだけど plutil で XML なり JSON なりに変換できるので簡単に読める。
個人的には XML よりも JSON のほうが扱いやすいので Info.plist の中身は plutil で JSON に変換して jq で CFBundleVersion を抜き出してる。
実際の確認
unzip -p <IPA ファイルのパス> Payload/<アプリ>.app/Info.plist | plutil -convert json -o - -- - | jq -r .CFBundleVersion
でいける。
↓ hoge.app
というアプリの CFBundleVersion を確認する例。
$ unzip -p hoge.ipa Payload/hoge.app/Info.plist | plutil -convert json -o - -- - | jq -r .CFBundleVersion 2.1.14
以上。
"草 API サービス" Pixela のブリーダーセットをいただきました!
pixela-client-go が v1.1.0 にバージョンアップしました。
pixela-client-go が v1.1.0 にバージョンアップしました。
v1.1.0 アップデート内容
optionalData プロパティに対応
日付ごとの要素 Pixel の optionalData
プロパティに対応しました。
optionalData
プロパティ の使い方に関しては 公式ブログ にとても詳しく書かれているので参照してください。
publishOptionalData プロパティに対応
Graph の publishOptionalData
プロパティに対応しました。
publishOptionalData
プロパティ の使い方に関しては 公式ブログ にとても詳しく書かれているので参照してください。
現場からは以上です。
Pixela の Go クライアントを作りました
Pixela の Go クライアントを作りました。
書くこと
- Pixela とは?
- 使い方
- インストール
- 動機
- まとめ
Pixela とは?
任意の数値を登録してアレのあれっぽくグラフを作れるクールな API サービスです。
詳しくは↓
使い方
package main import ( "log" "github.com/ebc-2in2crc/pixela-client-go" ) func main() { client := pixela.NewClient("YOUR_NAME", "YOUR_TOKEN") // 新しいユーザーを作る result, err := client.CreateUser(true, true, "") if err != nil { log.Fatal(err) } if result.IsSuccess == false { log.Fatal(result.Message) } // 新しいグラフを作る result, err = client.Graph("graph-id").Create( "graph-name", "commit", pixela.TypeInt, pixela.ColorShibafu, "Asia/Tokyo", pixela.SelfSufficientNone, false, false, ) if err != nil { log.Fatal(err) } if result.IsSuccess == false { log.Fatal(result.Message) } // ピクセルに値を記録する result, err = client.Pixel("graph-id").Create("20180915", "5", "") if err != nil { log.Fatal(err) } if result.IsSuccess == false { log.Fatal(result.Message) } // ピクセルの値をインクリメントする result, err = client.Pixel("graph-id").Increment() if err != nil { log.Fatal(err) } if result.IsSuccess == false { log.Fatal(result.Message) } // 新しい webhook を作る webhook, err := client.Webhook().Create("graph-id", pixela.SelfSufficientIncrement) if err != nil { log.Fatal(err) } if webhook.IsSuccess == false { log.Fatal(webhook.Message) } // webhook を呼び出す result, err = client.Webhook().Invoke(webhook.WebhookHash) if err != nil { log.Fatal(err) } if result.IsSuccess == false { log.Fatal(result.Message) } }
一応すべての API をサポートしています。
と書いておきながら 対応しました。Pixel
の optionalData
プロパティと Graph
の publishOptionalData
プロパティは自分が使っていないせいか今のところサポートしていません。
インストール
$ go get -u github.com/ebc-2in2crc/pixela-client-go
動機
Pixela はシンプルでいろんなことに応用できるとても便利な API サービスです。 最近は Go のコードを書く機会があったので Go から Pixela を使いたいと思って Go クライアントを探したのですが、なんとなく車輪を再発明してみたくなったので作りました。
まとめ
バグとかあると思いますし「こーしたら使いやすくなる」とかあったらイシュー作ったり声かけてもらえると嬉しいです。
ということで Pixela の Go クライアントの紹介でした。
AWS の CloudWatch ロググループの保持期限を一括で設定するメモ。
AWS の CloudWatch ロググループの保持期限を一括で設定するメモ。 コンソールからたくさんのロググループの保持期限を手で変更していくのが面倒くさかったので AWS CLI で一括設定。
やったこと
aws logs describe-log-groups
コマンドで全ロググループを取得できるので取得したロググループに対して aws logs put-retention-policy
コマンドで保持期限を設定するだけ。
たとえば以下のコマンドでロググループの保持期限を30日に一括設定できる。
$ aws logs describe-log-groups | grep 'logGroupName' | sed -e 's/.*logGroupName": "//' -e 's/",.*//' | xargs -n1 -I{} aws logs put-retention-policy --log-group-name {} --retention-in-days 30
jq を使うと上のコマンドと同じことをもう少し簡潔に書ける。
$ aws logs describe-log-groups | jq -r '.logGroups[].logGroupName' | xargs -n1 -I{} aws logs put-retention-policy --log-group-name {} --retention-in-days 30