bashで変数の中で変数を使う
今回も既出の情報シリーズをお送りいたします
やりたいこと
例えば ${hoge_${fuga}} とか ${hoge_$(echo ${fuga})} みたいなことがやりたいと思ってもそのままやろうとすると怒られる。
$ echo ${hoge_${fuga}} bash: ${hoge_${fuga}}: bad substitution $ echo ${hoge_$(echo ${fuga})} bash: ${hoge_$(echo ${fuga})}: bad substitution
なぜなら、変数展開時の記述方式を満たしていないので
Shell Parameter Expansion (Bash Reference Manual)
evalを使う
evalは式の展開を2段階に分けれます
「eval」コマンドは、指定した文字列を評価後に連結して、現在のシェルに実行させます。主にシェルスクリプトや環境設定用のファイルで使用します
$ hoge=hoge $ fuga=fuga $ hoge_fuga=hogefuga $ eval "echo \${hoge_${fuga}}" hogefuga
最初の式の展開では評価してほしくない ${hoge_${fuga}} を \ でエスケープしています。なので ${fuga} だけが最初に評価され、その後に echo ${hoge_fuga} が評価されるので構文エラーになりません。もちろん $() も使えます。
便利ですね!
RubyのHashで値が一致するキーを探す
Hash#keyを使う
=> {:a=>"value1", :b=>"value2", :c=>"value2"}
irb(main):019:0> h.key('value1')
=> :a
irb(main):020:0> h.key('value2')
=> :b
irb(main):021:0> h.key('value3')
=> nil
一致する値がない場合は nil 、複数一致するキーがある場合はいずれかを返す。
便利です!
メールヘッダーのRFCを読んだメモ
なにこれ
RFC5322を読んだメモ
この辺を使って読みました。フィールド定義のところしか読めてないですが
Mouse Dictionary - Chrome Web Store
Google Translate - Chrome Web Store
イントロダクション
- RFC5322はRFC2822の更新版
- メールヘッダー(封筒って言われている)の仕様のみを記載している
フィールド定義
フィールド名:フィールド値で書かれる- フィールドの順序は保証されていない
- 必須のフィールドはorigination date(orig-date), originator address(from)のみ。他はオプション扱い
The Origination Date Field
orig-date
- orig-date = "Date:" date-time CRLF
- 作成者がメッセージを作成完了し、メール転送準備が整ったとき。
- メールの送信ボタンを押したときとか。
- 転送の開始時間などは考慮されてない
- 作成者がメッセージを作成完了し、メール転送準備が整ったとき。
Originator Fields
- from = "From:" mailbox-list CRLF
- 送信元
- sender = "Sender:" mailbox CRLF
- reply-to = "Reply-To:" address-list CRLF
- 返信時に送信すべき宛先。なければFromに対して送信される
Destination Address Field
- to = "To:" address-list CRLF
- cc = "Cc:" address-list CRLF
- cc -> carbon copyの略
- bcc = "Bcc:" [address-list / CFWS] CRLF
Identification Fields
- message-id = "Message-ID:" msg-id CRLF
- 3.6の図だとオプショナル扱いだが、全てのメッセージに必要(SHOULD)
- 特定のバージョンの特定のメッセージを特定できる一意な識別子。一意であることは生成するホストで保証する
- メッセージが変更されてもmessage-idは変更されない
- in-reply-to = "In-Reply-To:" 1*msg-id CRLF
- 全てのReplyのメッセージに必要(SHOULD)
- 親メッセージ(返信元)のmessage-idが含まれる。親メッセージが複数の場合は複数
- 新しいメッセージの場合、in-reply-toフィールド自体が存在しない
- references = "References:" 1*msg-id CRLF
- 親メッセージにrefelencesフィールドが存在する場合
- 親のreferencesフィールドに親のmessage-idを加える
- 親メッセージにrefelencesフィールドが存在しないが、in-reply-toフィールドが存在する場合
- 親in-reply-toフィールドの値をreferencesに格納、その後に親のmessage-idを加える
- 親メッセージにin-reply-to, references, message-id(これは必須では?)が含まれない場合
- referencesフィールドは付与しない
- これだけ見ると最初の返信メッセージにはreferencesフィールドは付与しないように見えるが、Gmailでは最初に返信したメッセージにもreferencesフィールドが付与されている
- スレッド機能はreferencesフィールドをたどることで実装されている。故に複数の親メッセージを持つreplyに対してreferencesフィールドを生成することは非推奨
- referencesフィールドは付与しない
- 親メッセージにrefelencesフィールドが存在する場合
- msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
- id-left = dot-atom-text / obs-id-left
- id-right = dot-atom-text / no-fold-literal / obs-id-right
- no-fold-literal = "[" *dtext "]"
Informational Fields
- 読み飛ばした
Resent Fields
- 読み飛ばした
Trace Fields
- 読み飛ばした
単語メモ
- envelope
- 封筒, 包むもの
- semantics
- セマンティクス。意味論?
- facilitate
- 楽にする、容易にする
- dictate
- 口述する、意図する
- consist
- 構成する、成り立つ
- for instance
- 例えば
参考
「入門 監視」を読んだ
なにこれ
こちらを読んだのでそのメモです。
メモ
1章 監視のアンチパターン
- ツールで監視を決めるな。やりたいことに合わせてツールを選び、組み合わせ、必要であれば作る
- 監視はスキル。全員が一定水準を満たすべき
- 誰かに責任を押し付けてはいけない
- メトリクスは高頻度で投げる。最低でも1分に1回
- 障害→監視の追加を繰り返すのはNG。何回か繰り返すようならアプリケーションを安定して動くように作り直すべき
2章 監視のデザインパターン
- できる限り構造化ログを使う
- ログ量が少なかったり、複雑な解析を行わなければ非構造化でもよし
- ダッシュボードはそのシステムを一番知ってる人に作らせる
- メトリクスはアラートを出すために集めているわけではない。質問を投げかけるためにある
- エモい
- 使えるならSaaS使おう
3章 アラート、オンコール、インシデント管理
- 通知方法
- 即時対応が必要→SMSなどのページャ
- 注意が必要→チャット
- アラートレポートで改善点を見つけ出す
- オンコール
- バックアップ担当は作らないほうがいい。2倍のシフト数になる
- オンコール担当は責任を負う。何回も対応できないなら問題あり
- インシデント管理プロセスは作っておこう
4章 統計入門
- 中央値はサンプリングしたデータの真ん中の値
- (n+1)/2 番目の値
- パーセンタイル
- データを昇順にならべて小さい方から数えて任意の位置に存在する値
- 90パーセンタイル → 小さい順から並べて90番目のデータ
- 標準偏差
- 正規分布なデータにしか適用できない。監視では使えないことが多い
5章 ビジネスを監視する
- ビジネスKPIはアプリケーション、インフラの調子をも示してくれる
- KPIを全員がすぐに目が届くところに表示しておく
- 成功よりも失敗のメトリクスを追う。Goal(サービスが満たすべき目標)に直結するので
- 何をKPIにすべきかは人と話して決める
- プロダクトオーナー、エンジニアリングマネージャ、シニアエンジニア
6章 フロントエンド監視
- フロントエンドのパフォーマンス監視のゴールは動き続けることではなく、素早くロードされること
- フロントエンドのパフォーマンス改善はビジネスに大きなインパクトを与える
- 特にロード時間。業績に影響を与えた実績あり
- ロード時間は4秒以下を目指せ
- JavaScriptの仕組みは理解しておこう(=監視対象の仕組みは理解しておこう)
- Navigation Timing API
- ブラウザが提供するAPI。ここを通じてページパフォーマンスのメトリクスを公開
- 各処理の開始、終了時間をメトリクスとして提供
- ログ収集はSaaSを使おう
- Sentryとか
- シンセティック監視
- 外部監視的なやつ。外からcurl叩くイメージ
- CIでロード時間を定期的に計測
7章 アプリケーション監視
- APMはビジネスコンテキストまでは理解してくれてない。当然だけど。
- ビルド、デプロイの監視
- デプロイ後、エラー率が高まってないかの相関を調べれる
- healthエンドポイントパターン
- ヘルスチェック用のエンドポイントを作る
- 依存性があるリソース(DB, Cache, 外部エンドポイント)があれば、その接続まで含めてヘルスチェックしたほうがよい
- ただし、リソースにかかる負荷が大きくなるので要検討
- アプリケーションロギング
- 構造化ログを使おう
- ログにするかメトリクスにするかはユースケース次第。チームで相談しよう
- ログレベルの問題点
- ログレベルはアプリケーションを作るときに決まる。また、全て正常に動いている前提で重要度が振られる
- ある問題が発生した場合、DEBUGレベルの情報が必要な場合でもデフォルトがINFOで取得してたら情報を失う
- インフラの構成によってはそれはERRORなのか?というものも出てくる
- 例えばリトライ処理もできている場合、接続失敗はERRORとして出すか?
- ログレベルはアプリケーションを作るときに決まる。また、全て正常に動いている前提で重要度が振られる
- ログはディスクに書き込み、その後ネットワーク越しに送るが良い
- ログ送信が非同期になるから
- 分散トレーシング
8章 サーバ監視
- OS標準(CPU, MEM, DISK)のメトリクスは取得するが、アラートは設定しないのがおすすめ
- メモリ
- ディスク
/proc/diskstatsから情報を取得してることが多いiostat -x- iowaitが高くなってないか
- utilが100%になってないか
- ロードアベレージ
- CPUに処理してもらうのを待っているプロセスがいくつあるか
- システムによっては高くても動くものはあるので一概に高いと良くないとは言えない
- SNMP
- サーバ監視で使うのはやめたほうがよい
- WEBサーバ
- 秒間リクエスト数
- 5XX、4XXの数
- データベースサーバ
- コネクション数
- MySQLでは=スレッド数
- 秒間クエリ数
- コネクション数
- ロードバランサ
- WEBサーバと同じ
- キュー
- キューの長さ
- キューの消費率
- キャッシュ
- キャッシュから追い出されたアイテム数
- ヒット、ミス比率
- NTP
- ntpstatコマンドの終了コードで監視するのがおすすめ
- スケジュールジョブの監視
- デッドマン装置
- 失敗していることを検知、アラートを上げたり自動復旧したりする仕組み
- https://ja.wikipedia.org/wiki/デッドマン装置
- Cron Job Monitoringサービスも存在する
- Cron, CloudWatch Event自体が動いることの監視よりも、各ジョブ対してそれがなすべきことがなされていないことを監視するほうがよいと理解した
- デッドマン装置
9章 ネットワーク監視
- 現状すぐに利用することはなさそうなので読み飛ばした
10章 セキュリティ監視
11章 監視アセスメントの実行
- 監視アセスメントのデモだったので省略
感想
書かれていることが普段の監視でやっていること大きなズレが無くて安心しました。サーバ監視の章は具体的なコマンド、実装例が書かれていて参考になりました。また監視を構築する上でコミュニケーションはとても大切で、それが今足りてないかもなという気づきもあり読んでよかったです。
Linuxコンテナのタイムゾーンを変更する
最初にしていた勘違い
コンテナのタイムゾーンってホストOSのタイムゾーンが自動的に同期されるよね
↓
されませんでした
Linuxってどこでタイムゾーンを設定してるの?
色々調べたところ、以下の優先順位で設定されます。
- 環境変数
TZ - /etc/localtime (/usr/local/etc/localtime)
ただしこれはGNU Cライブラリを利用している場合、他のCライブラリを使っている場合は異なる挙動になると思います。これはPOSIXというUNIX OSの標準規格で定義されているようです。
docker runしてコンテナを起動するとき、何もオプションを付けなければ環境変数TZには何も入っていないので /etc/localtime が利用されます。このファイルはコンテナイメージ独自のものなので残念ながらホストOSのタイムゾーンが同期されることはありませんでした。
タイムゾーンを変更する
前述の通り、これはGNU Cライブラリを利用しているコンテナイメージにしか適用されない認識です。
docker run -e TZ=Asia/Tokyo- 環境変数でTZを指定します
docker run -it --rm -v /etc/localtime:/etc/localtime- ホストの
/etc/localtimeをマウントします。これならホストOSとタイムゾーンの同期が取れます
- ホストの
最後に
誤りあればご指摘お願いします!
Dockerfileで引数を元にベースイメージを指定する
目的
- docker buildの引数でDockerfileのベースイメージ(FROM部分)を指定する
やりかた
Dockerfile
ARG BASE_IMAGE
FROM ${BASE_IMAGE}:latest
RUN hogehoge
コマンド
docker build --build-arg BASE_IMAGE=XXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ruby .
--build-argを環境変数で指定してあげれば環境差異を吸収できる
備考
- ARGはFROMの前における唯一の命令
- FROMの前に宣言したARGはFROMでしか使えない。FROM以降で再度ARGを使いたい場合、もう一度定義してあげる
ARG BASE_IMAGE
FROM ${BASE_IMAGE}:latest
ARG BASE_IMAGE
RUN hogehoge
参考
aws-sdk-goでpaginate
なにこれ
aws-sdk-goの場合
- paginateできるAPIは
HogehogePagesWithContextみたいな関数が用意されているのでこれを使う
サンプル
今回の場合、 ecs.DescribeContainerInstances の引数として渡すインスタンスのARNリストを ecs.ListContainerInstancesPagesWithContext で取得する。引数で渡すARNの上限となる100ずつでページ分割する。
package main import ( "context" "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ecs" ) const ClusterName = "your-cluster-name" func main() { var instancesList [][]string sess := session.Must(session.NewSessionWithOptions(session.Options{ SharedConfigState: session.SharedConfigEnable, })) svc := ecs.New(sess) ctx := context.Background() err := svc.ListContainerInstancesPagesWithContext(ctx, &ecs.ListContainerInstancesInput{ Cluster: aws.String(ClusterName), MaxResults: aws.Int64(100), // DescribeContainerInstances limitation }, func(p *ecs.ListContainerInstancesOutput, b bool) bool { var instances []string for _, arn := range p.ContainerInstanceArns { instances = append(instances, aws.StringValue(arn)) } instancesList = append(instancesList, instances) return true }) if err != nil { panic(fmt.Sprintf("failed to list container instances for cluster %s: %v", ClusterName, err)) } fmt.Println("Container instances list: ", instancesList) }
ListContainerInstancesPagesWithContextの引数について- ctx
- groutineのキャンセル、タイムアウトなどで利用。このへんまだわかってない
- ecs.ListContainerInstancesInput
- ListCOntainerInstancesのインプット。MaxResultsを100にすることで各ページ100ずつ出力してくれる
- func
- 各ページ毎で実行する処理を各。今回は上限100ずつのArnのSliceをappendする
- ctx
参考
https://github.com/aws/aws-sdk-go#api-request-pagination-and-resource-waiters