Fluentd で使いたい Gem の依存関係の解決は Bundler に任せられる
Fluentd は Gem によるライブラリの追加ができて、例えばログを直接 BigQuery に転送したいのであれば fluent-plugin-bigquery のような Gem をインストールしておくことによってそれを実現することができる。
こういったプラグインを追加するコマンドとして提供されているのが fluent-gem
というコマンドで、例えば先程挙げた Gem をインストールしたいのであれば
fluent-gem install fluent-plugin-bigquery
のようにコマンドを叩けば Gem をインストールしてくれる。こういった Fluentd 向けのプラグインは rubygems.org にて様々提供されているので、使っているうちにあれもこれもと追加したくなるのだが、徐々にパッケージの依存関係がややこしくなっていき、最終的に人間による依存関係の解決はできなくなってしまう。
Fluentd でも Bundler が使える
Fluentd で使う Gem をインストールするためには fluent-gem
という特別なコマンドを使うので、コマンドの裏ではさぞ特殊なことをやっているのだろうと思ったのだが、ソースコードを見るとそんなことはなく、ただ単純に Gem をインストールしているだけのようだった。
また Fluentd の起動オプションには Gemfile を読み込ませる --gemfile
オプションがあり、これで指定した Gemfile を使って起動時に Bundler が Gem をインストールしてプラグインが使えるようになる。
つまり Fluentd においても Gem の依存関係の解決は Bundler に一任することができるようになっている。
Dockerfile にしてみる
例えば fluent-plugin-bigquery と fluent-plugin-google-cloud を同時に使いたい場合、このような Gemfile を書くことになる。
source "https://rubygems.org" gem 'fluentd', '~> 1.13.x' gem 'fluent-plugin-bigquery', '~> 2.2.x' gem 'fluent-plugin-google-cloud', '~> 0.12.x'
Dockerfile ではビルド時に bundle install
しておくことをおすすめする。 Fluentd の起動時にも bundle install
は実行されるが、 Gem のインストール時に必要なネイティブライブラリなどは予め用意しておく必要があるからである。また Fluentd の公式イメージである fluent/fluentd をベースイメージとする際は、実行ユーザーが fluent
になっているため、 apt-get install
などを実行するのであれば予め root
を指定する必要がある。ただし bundle install
の実行ユーザーは fluent
になっているほうがファイルの権限管理などに面倒がない。
FROM fluent/fluentd:v1.13-debian COPY Gemfile Gemfile.lock /fluentd/etc/ USER root RUN apt-get update \ && apt-get install -y --no-install-recommends \ build-essential \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* USER fluent RUN cd /fluentd/etc \ && bundle install -j8 --path vendor/bundle CMD [ "fluentd", "--gemfile", "/fluentd/etc/Gemfile" ]
また、このとき Gemfile.lock をどう用意するかも考える必要があるが、一度 Gemfile.lock なしでビルドしたイメージから docker cp
などを使って /fluentd/etc/
以下にある Gemfile.lock を取り出すと一応用意することができる。
% docker build -t fluentd . % docker run --rm -d --name fluentd fluentd tail -f /dev/null % docker cp fluentd:/fluentd/etc/Gemfile.lock . % docker kill fluentd
ここまでの流れをサンプルリポジトリにまとめたので参考までに。
Nuxt2でコンポーネントから今表示しているページのタイトル要素を取りたいとき
Nuxt2 でコンポーネントから今表示しているページのタイトル要素を取りたいケースがある。
具体的に言うと Twitter のツイートボタンを自前で実装するときに使えるリンク形式でツイートを発行できる機能があり、このツイートするテキスト部分ににページのタイトルを含めたかった。
https://twitter.com/intent/tweet?url=[ツイートしたいURL]&text=[タイトルを含むテキスト]
このとき、 Nuxt のコンポーネント側からタイトルを知る方法として一番最初に思いつくのは document.title
という JavaScript の古典的な API である。
export default { data() { return { pageTitle: '' } }, mounted() { this.pageTitle = document.title } }
これは確かに最初に表示したページやコンポーネントがロードされたタイミングのページのタイトルを取得することはできるが、 Nuxt 内に <nuxt-link>
のを含んでいて、遷移の際にコンポーネントがそのまま表示され続けるような場合は値の変更がされない。考えてみれば「それはそう」だし。単純に自分の想定があまい。
じゃあページ変更をトリガーすれば良いんだろうということで、 $route
を watch
によって監視することでページ遷移のタイミングで document.title
を取得し直せばよいのだろうということでこういうコードを書いた。
export default { data() { return { pageTitle: '' } }, mounted() { this.pageTitle = document.title }, watch: { $route(newValue) { this.pageTitle = document.title } } }
しかしこれもうまく行かなかった。たしかに watch.$route
はページ遷移のときに通っていくのだが、このタイミングで document.title
を叩いても返ってくるのは遷移前のページのタイトルなのである。つまり document.title
が変更される前にここを通っているため、ページ遷移をすると1ページ前に見ていたタイトルしか取得できないように見える。
最終的に StackOverflow でこういう記事を見つけた。
記事内のコードに書いてあるとおりで、HTML DOM を監視する JavaScript API である MutationObserver
を使って <title>
タグを監視して更新するといったもの。
書いてみるとまあ確かに動く(単純に Mutation Observer を使っているだけなので)。
export default { data() { return { pageTitle: '' } }, mounted() { this.pageTitle = document.title new MutationObserver(() => { this.pageTitle = document.title }).observe(document.querySelector('title'), { childList: true }) } }
動いたのはいいが、なんだかもやもやするコードである。本当は上位から表示しているページのタイトルの内容を通知するといいのだろうが、 layout に埋め込まれているコンポーネントの場合、そのデータのやりとりが若干ややこしくなってしまう。正直ページタイトルを取得するためにそこまでやりたくはないし、こういうユースケースはよくありそうなので、できれば Nuxt 側で取れるようになってほしいなと思った。
GitHub Actions をつかって Google Cloud Functions にデプロイする
Google Cloud Functions ってやつ、 Slack の Webhook 系のアクションだとか、情報を整形して別の API に横流しするだけの Proxy 系アプリケーションなんかのホスト先として便利に使ってたのだけども、その簡単さからCDの構築をサボっていて、よくリポジトリの状態と実際に展開されているコードが違うみたいな状態のまま放置してしまうなどどうにもうまく管理ができていなかったんですよね。まあ先述の通りそんなに重要なアプリケーションを管理しているわけでもないので、長らく自分の中での「動いてるからいいや」の代表的な存在だったのですが、やっぱりCVEなんかで報告されているような脆弱性を抱えるライブラリをそのまま放置するのはよくないなという気持ちになり、重い腰を上げてCD環境を整備することにしたのでそのメモ。
続きを読むcurlコマンドでHTTPステータスコードだけを取得する場合は--write-outオプションを使うと良い
シェルスクリプトを書いているとcurlコマンドなんかで指定したURLのHTTPステータスコードだけがほしいという場合がある。
結論から言うと --write-out
/ -w
というオプションを使うと実現できる
% curl -s -o /dev/null --write-out "%{http_code}" https://www.example.com/ 200
-o /dev/null
にしているのは取得内容を標準出力に表示しないようにするもので、こうすることで文字列として出力されるのはHTTPステータスコードだけになりパイプやシェルスクリプトで処理がしやすいなどのメリットがある。
--write-out
で出力できる内容いろいろ
ところで --write-out
とはなにか。こういうとき、脳死でGoogle検索すると上位にQiitaというウェブサイトがでてきてしまうのだが、原典をみるのが一番確実である。
curl が指定URLにアクセスしたときに取得する様々な情報を簡易的なテンプレート表現で出力させることができるコマンドで、HTTPステータスコードの %{http_code}
以外にも、アクセスのために必要な処理にかかった各種の時間なども出力させることができる。
curl のバージョンによっては使えないパラメータも多々あるので、手元のバージョンで使えるものを確認するには curl --manual
で --write-out
の項を確認するとよい。