【AWS Lambda】dead_letter_queueからPagerDutyにアラートは飛ばない
本番システムで使われているAWS Lambda functionが失敗した際にPagerDutyでアラート通知を受けたいと思い、開発用のLambda functionにdead_letter_queueを設定し、そのSNS queueにPagerDutyのエンドポイントをsubscribeさせた。
しかし、Lambda functionを失敗させてからいくら待ってもアラートが来ない。確認のため、Slackに通知を投げる別のLambda functionも合わせてsubscribeさせたが、そちらには通知が飛ぶ。
PagerDuty側の原因ではないかと思い調べてみたところ、PagerDutyとAWSのIntegrationで表示されるのはAWS CloudWatchのみだった。PagerDutyは、CloudWatchからSNS queueに送られたメッセージを受信し、そこからAlarm状態を検知することでAlertを飛ばす。しかし、今回は aws lambda invoke
コマンドでLambda functionを実行させていたため、dead_letter_queueから送られたメッセージは空だった。これではPagerDutyがAlarm状態だとみなさない。
メッセージの中身を解析して人為的に同じ内容を飛ばすようにしても良いが、そうするくらいであればCloudWatchのAlarmを設定した方が早い。結局dead_letter_queueの使用をやめ、CloudWatchからSNS queue経由でPagerDutyにメッセージを飛ばすように変更した。dead_letter_queueは失敗検知には便利だが、あくまで「実行に失敗したイベント」を拾うためのものであり、アラートの完全な代用にはならない。
ArgoCDを使ってみる
ArgoCDをローカルで動かしてみたいと思い、以前使ったKubernetes講座のmanifestファイルでやってみた。
まず、以下のチュートリアルのステップ4まで行い、 argocd
namespaceでArgoCDのサーバを起動させる。
その後、 argocd
namespaceにAppProjectとApplicationのmanifestファイルを作れば、宣言的にArgoCDの設定を定義できる。ローカルのKubernetesクラスタで動かしたので、namespaceはdefaultに設定した。
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: default namespace: argocd spec: description: argocd project clusterResourceWhitelist: - group: '*' kind: '*' namespaceResourceBlacklist: - group: '' kind: ResourceQuota - group: '' kind: LimitRange - group: '' kind: NetworkPolicy destinations: - namespace: 'default' server: 'https://kubernetes.default.svc'
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: wordpress-challenge namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io spec: project: default source: repoURL: https://github.com/Udomomo/kubernetes-challenge-1-wordpress targetRevision: argocd path: app destination: server: https://kubernetes.default.svc namespace: default
これらのファイルをapplyするだけで設定は完了する。レポジトリの argocd
ブランチをトラックするように設定したので、後は app
ディレクトリ下にあるアプリケーションコードを更新し、syncさせれば設定が反映される。
AppProjectやApplicationの設定を更新したい場合は、当該manifestファイルを更新してapplyし直せば良い。
このようにArgoCDを使ってアプリケーションを管理する場合、ArgoCDの管理下のレポジトリにmanifestファイルをプッシュすれば、自分が権限を持っていない種類のresourceでもArgoCDを通してapplyできてしまうことが考えられる。そこで、resourceの種類ごとにブラックリスト/ホワイトリストを設定することも可能。 clusterResourceWhitelist
clusterResourceBlacklist
namespaceResourceWhitelist
namespaceResourceBlacklist
の4種類が設定できる。
上記のmanifestファイルでは、 namespaceResourceBlacklist
にいくつか指定してみている。試しにLimitRangeのmanifestファイルをプッシュすると、ArgoCDがSyncを拒否して失敗した。
【Kubernetes】CKADに合格しました
10月末にCKAD (Certified Kubernetes Application Developer) を受けて合格した。試験に受かるのは久しぶり。
受験の経緯
仕事で扱っているシステムがKubernetes上で動いており、自身のKubernetesの知識不足に危機感を持っていたのがきっかけ。今まではその都度調べてなんとかなっていた状態だったが、同じチームの先輩がCKADとCKA (Certified Kubernetes Administrator) に合格したことを社内でシェアしていてこの試験のことを知った。選択問題ではなく実際にクラスタ内でコマンドを打って問題を解く形式なのが気に入り、まずはCKADを受験してみることにした。
学習法
学習開始は7月末。
- KodeCloud
自分の場合付け焼き刃の知識が多く、Kubernetesの基礎が一部怪しかったので、有料コースを取った。
Udemy上にも同じ講師の同様のコースがあるので、セール期間中ならそちらでも良い。自分が申し込もうとしたときはUdemyのセール期間が終わっていて2万くらいしていたので、講師の方が運営するこちらのサービスを利用した。
このコースはKubernetesのresourceの種類ごとに教材が豊富で、Katacodaを使った演習や模擬試験も多く揃っていた。説明は全編英語だが聞き取りやすい。ただし教材の一部には日本語字幕がついていないので英語が全くわからない人には厳しいかもしれない。ちなみにコースの途中で受験料が15%オフになるクーポンをもらうことができた。(((KodeCloudでの話なので、Udemyだともらえるのかはわからない。))
当日の問題形式に慣れるために、最後についているmock exam(1時間x2回分)はそれぞれ2回ずつ行った。
- CKAD-Exercise
コースを一通り終えた後は、CKAD-Exerciseを2周ほどしてコマンドの練習をした。このレポジトリはよく試験対策に使われているが、全てkubectlコマンドの一問一答であるため、知識に不安がある人はこれ以外の教材も併用すべき。
- Kubernetes完全ガイド
レファレンスとしてお世話になった。PCの横に置いておき、副読本として使うのがおすすめ。
試験当日
申し込みは以下のページから行う。日本語版もあるらしいが、ローカライズの質がわからなかったので英語にした。 training.linuxfoundation.org
当日は本人確認としてパスポートの提示が必要なことに注意。期限が切れている人はあらかじめ再発行しなければいけない。
試験監督とは全てチャットで会話するので、英語のスピーキングは必要ない。Web試験での不正防止のためか、事前確認はとても厳重。試験前に他のアプリケーションは全て閉じる必要があり、またWebカメラを通じて部屋全体360度の様子と、机の上に一切何も置いていないのを見せる必要がある。自分の場合、机のそばの壁に貼ってある掲示物も剥がせと言われた。さらに、試験中の私語や、部屋に他の人が入ってくるのもNGとなる。これから受験する人は、試験時間になる前にPCのプロセスと机まわりを徹底的に片付けておき、家族や同僚などがいるなら誰も部屋に入って来ないよう事前に調整しておく方がいい。事前確認で15-30分はかかるので、部屋を押さえる時間帯にも余裕を取ろう。
試験中も時々チャットが飛んできて、口に手を当てるのをやめろ・両方の手のひらをWebカメラに向けろ等と言われた。慣れていないととても緊張するが、言われた通り落ち着いて対応するのが重要。
試験の心構え
- 時間が足りないので、極力YAMLを書かないこと。kubectlでできることは全てそれで済ませるべき。YAMLを書かなければいけない場合でも、
-o yaml --dry-run=client
をつけてファイルに出力すれば、YAMLのひな形が手に入る。 - 学習中にKubernetesドキュメントを調べたときは、何の例がどのページに載っていたか覚えておくと良い。試験中はKubernetesドキュメントを開けるので、マニフェストファイルの内容をコピペしたいときに時間を節約できる。
- 試験が始まったら
.vimrc
を編集して、タブをスペースに変更すると良い。これをやらないと、Kubernetesドキュメントからコピペしたときに、タブとスペースの混在によってkubectl apply
がエラーになってしまう。他にも、kubectlコマンドにエイリアスを設定したという人もいるようだ。
kubectl port-forwardでクラスタ外からPodにアクセスする
Cluster内にIngressを立てたがうまく動作しないことがあり、デバッグのためPod内のアプリケーションにアクセスしたいと思った。今までは、テスト用のPodを立ててその中からcurl等でリクエストを送っていた。
kubectl run test-pod --image nginx -- /bin/sh -c 'curl <target_pod's_ip_address>'
しかし、 kubectl port-forward
コマンドを使うことで、テスト用Podなしでデバッグができることを教えてもらった。
kubectl port-forward <target_pod's_name> 8080:80
このようにすることで、ホストの8080番ポートがPodの80番ポートにPort-forwardingされるため、 localhost:8080
でアクセスが可能になる。ブラウザで見られるのがありがたい。
kubectl port-forward
のオプションにはServiceも指定できるが、内部的にはPodを指定するのと同じであり、ClusterIPを通さず直接Podにアクセスしていることに注意したい。ClusterIPにアクセスしたい場合は以下の記事が参考になる。
sh -cでコマンドを渡すときはシングルクォートを使う
KubernetesのPod内の環境変数が正しく設定されているかを確認しようとして、以下のようにしたところ、何も出力されなかった。
$ kubectl exec -it pod_name -- /bin/sh -c "echo $VAR_NAME"
Podの中に入って確認すると正しく出る。
$ kubectl exec -it pod_name -- /bin/sh # echo $VAR_NAME test
これは、 /bin/sh -c
に渡したコマンドがダブルクォートだったことが原因。 sh -c
を使うと、 -c
以下で渡したコマンドを sh
で実行させることができるが、ダブルクォートにしてしまうと kubectl
を実行しているシェルで変数が解釈されてしまう。 $VAR_NAME
という環境変数はPodの中にはあるがhostでは設定されていないので、単なる echo
を渡していることと同じになり、何も出力されずに終わる。
正しく確認するには、シングルクォートで渡せば良い。シングルクォートで囲われた内容は展開されないため、 $VAR_NAME
がPodに渡る。
$ kubectl exec -it pod_name -- /bin/sh -c 'echo $VAR_NAME' test
netcatのzero I/Oモードで疎通確認する
疎通確認をする際はcurlかwgetを使うことが多かったが、CKADの講座で講師がnetcatを使っているのを見て調べてみた。
netcatはサービスとの通信を確認できるコマンドであり、たいていのLinuxディストリビューションに同梱されている。KubernetesのPodに入ってコマンドを打つ場合、imageにcurlが入っていないというようなことも多いので、使えるようにしておくと便利かもしれない。
netcatでの通信は、基本的に相手のホスト名とポートを指定すればよい。
nc google.com 80
これに加え、netcatではzero I/Oモードを使ったポートスキャンを行うことができる。これはパケットを飛ばさず、相手のポートに接続できるかのみを確認するモードで、接続に成功すればすぐに接続が閉じられる。実際にデータのリクエスト・レスポンスをすることがないので、疎通確認に適している。
CKAD講座では、Podの中からService名を指定して疎通できるか確認していた。
nc -z -v -w 1 service-name 80
-z
でzero I/Oモードを使える。 -v
は詳細な出力をするオプション。 -w
はタイムアウト判定までの秒数を指定するもので、これを指定しないと接続に失敗した場合コマンドが終了しない。
【GitHub Actions】AWS Lambdaの環境変数を自動で更新する
最近システムのリリースフローの自動化を進めることが多い。先日はLambda関数の更新の自動化を行った。この関数は環境変数を持っており、これを頻繁に更新する必要があった。
新しい環境変数をどのように渡すかが最も難しいポイントだったが、この環境変数はAWS CLIコマンドにおいてJSONファイル形式で渡すことができる。
aws lambda update-function-configuration --function-name "${function_name}" --environment fileb://env.json
--environment
オプションの後にファイルパスを指定する。 AWS CLIでは fileb://
とつけることで、ファイルの中身をバイナリコンテンツとして渡すことができる。面倒なファイル読み込みの処理を書かずに済むため、この記法はとても気に入っている。また、このJSONファイルをGitHub上に置けるため、環境変数のバージョン管理がしやすくなるという利点もある。
JSONファイルのフォーマットは以下の通り。 SECRET_ENV
は機密性の高い環境変数であり、値はGitHub ActionsのSecretsに登録してある。JSONファイル上では値を適当なものにしておく。
# env.json { "Variables": { "NORMAL_ENV": "example", "SECRET_ENV": "to_be_converted" } }
workflowファイルには以下のように記載する。 jq
コマンドでJSONファイルの SECRET_ENV
の値を置換しているのがポイント。 --arg
オプションとして secret_env
として ${{ secrets.SECRET_ENV }}
の値を渡し、その値をJSONファイル内の to_be_converted
と入れ替えている。
- name: Update lambda envvar env: LAMBDA_FUNCTION_NAME: dev_function ENV_JSON_FILE: env.json SECRET_ENV: ${{ secrets.SECRET_ENV }} run: | jq --arg secret_env "${SECRET_ENV}" '.Variables.SECRET_ENV = $secret_env' "${ENV_JSON_FILE}" > env_converted.json aws lambda update-function-configuration --function-name "${LAMBDA_FUNCTION_NAME}" --environment fileb://env_converted.json