cronの失敗をGoogle Apps Scriptで通知する
はじめに
cronが面倒くさい。特に失敗を通知するのが。
そもそも標準エラー出力があった時だけ通知されるようにするのも面倒なんですが、
AWSを使ってると迷惑メール扱いされないようにAmazon SES使うなり、DNS逆引き設定するなりしないといけないわけです。
こんなのサーバ毎にやってられんわけです。
ということで、そんな面倒なcronの失敗通知をGoogle Apps Scriptを使うことで楽にします。
スプレッドシート
まずは以下のようなスプレッドシートを作ります。

Google Apps Script
スプレッドシートの [ ツール ] > [ スクリプトエディタ ] を開き、以下の関数を登録します。
function doPost(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('メーリングリスト');
var to_emails = sheet.getRange(1, 1, sheet.getLastRow()).getValues();
var subject = 'エラー通知';
var body = "以下の処理でエラーが発生しました。\n\n";
body += "タスク名: " + e.parameter.task_name;
GmailApp.sendEmail(to_emails.join(','), subject, body);
}
続いて、作成した関数を公開します。
スクリプトエディタの [ 公開 ] > [ ウェブアプリケーションとして導入... ] を選択します。
GASを初めて公開する場合、Googleの認証が出るので許可してください。
公開の設定は以下になります。

ここで表示される「現在のウェブアプリケーションのURL」にリクエストを送ることでメールが送信されるようになります。
スクリプトを更新する場合
再度、 [ 公開 ] > [ ウェブアプリケーションとして導入... ] が必要になります。
この時にプロジェクトバージョンを上げないと反映されないので注意してください。
自分も毎回やり忘れます。
cron
cronの処理は何でもいいんですが、
例としてLet's Encriptの更新処理をcronに登録します。
/etc/crontab
# エラーはGASで通知するので、全ての出力をリダイレクト 0 6 * * mon root /opt/cron/certbot_renew.sh >> /var/log/certbot_renew.log 2>&1
certbot_renew .sh
#!/usr/bin/env bash
/opt/certbot/certbot-auto renew --no-self-upgrade --deploy-hook "systemctl restart nginx"
# 証明書の更新に失敗したらGAS経由でメール通知
if [ $? != 0 ]; then
TASK_NAME="certbot_renew.sh"
curl -X POST -d task_name=$TASK_NAME https://script.google.com/macros/s/${APP_ID}/exec
fi
最後に
メールにこだわらなくていいなら、Slackとかに通知した方が楽。
以上、現場からでした。
ポートマッピングを使わずにDockerコンテナにアクセスする方法
この記事はDocker Advent Calendar 2018の16日目になります。
はじめに
記事書いといてアレなんですが
基本的にはポートマッピングを使ったほうがいいと思うので、あんまり使い所はないかもしれません。
自分の場合は、とあるライブラリでWebSocketのコネクションがどうしても上手くいかず
今回の方法に行き着いた感じです。
どこかで誰かの参考になれば幸いなので記事にしたいと思います。
Linuxの場合
コンテナ起動
例として、apacheコンテナを使用していきます。
以下のdocker-compose.ymlを用意して、コンテナを起動します。
$ vi docker-compose.yml
version: '3'
services:
web:
image: httpd:2.4-alpine
expose:
- "80"
network_mode: host # ホストのネットワークでコンテナを実行
$ docker-compose up -d
network_mode: host とすることで、ホストのネットワークに対してポート番号をexposeするため、マッピング無しでアクセス可能となります。
この設定はLinux環境限定のようです。
確認
$ docker ps --format "table {{.Image}}\t{{.Ports}}\t{{.Names}}"
IMAGE PORTS NAMES
httpd:2.4-alpine test_web_1
$ curl http://localhost
<html><body><h1>It works!</h1></body></html>
ポートマッピングしていませんが、アクセスできました。
Docker for Windowsの場合
Hyper-VでDockerデーモンが動いている都合上、仕方ないのかもしれませんが、
network_mode: host は使えないのでネットワークの設定が必要になります。
コンテナ起動
以下のdocker-compose.ymlを用意して、apacheコンテナを起動します。
$ vi docker-compose.yml
version: '3'
services:
web:
image: httpd:2.4-alpine
expose:
- "80"
networks:
my_network:
ipv4_address: 172.99.0.2 # コンテナのIPを指定
networks:
my_network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.99.0.0/24 # ネットワークアドレスを指定
$ docker-compose up -d
ネットワークアドレスは172以外は自由に設定できます。
他のdocker networkで使われていないものを指定してください。
ルーティングテーブル設定
Docker for Windowsでは、デフォルトで以下の構成になっているようです。
- 仮想スイッチ:10.0.75.0/24
- DockerNAT:10.0.75.1
- MobyLinuxVM:10.0.75.2
この内のMobyLinuxVMに、先ほどのネットワークアドレスをルーティングします。
$ route -p add 172.99.0.0/24 10.0.75.2 ※管理者権限のコマンドプロンプトで実行
ルーティングテーブルを確認
$ route print
設定を削除する時はこちら
$ route delete 172.99.0.0
この設定については、以下の記事が大変参考になりました。 qiita.com
確認
$ docker ps --format "table {{.Image}}\t{{.Ports}}\t{{.Names}}"
IMAGE PORTS NAMES
httpd:2.4-alpine 80/tcp test_web_1
$ curl http://172.99.0.2
<html><body><h1>It works!</h1></body></html>
アクセスできました。
Docker for Macの場合
すいません。分かりませんでした。
ただ、Macの場合はWndowsと違ってDocker for MacとVirtualBoxが共存できるので
VirtualBox上のDockerで network_mode: host を使えば良いかなと思います。
最後に
Macについては思いっきり手抜きとなってしまいましたが、
そもそも今回の記事はDocker for WindowsとVirtualBoxが共存できないことがきっかけになっています。
前述のWebSocketの件で最初は仕方なくVagrantで環境構築したんですが
DockerとVagrantを切り替えるために毎回PCを再起動する状況にノイローゼ寸前だったので、必死に調べた結果となります。
*1
何卒ご容赦ください。
以上、現場からでした。
プライベートDockerHubをゆるく使う
Dockerを使ってるとDockerHubも使いたくなることがあると思いますが、
業務だとimageをパブリックな所に置けなかったりしますよね。
Docker Registryを使えばプライベートなDockerHubを割と簡単に構築できるので、
作り方や使い方などを備忘録も兼ねて公開したいと思います。
imageを共有できれば良いや程度のゆるい感じでやっていきます。
使用マシン
- registry-host(Registryコンテナを起動するマシン)
- my-pc(自分の作業PC)
自分の場合、社内の空きPCをregistry-hostとして使いました。
構築
registry-hostに以下のdocker-compose.ymlを用意してコンテナを起動します。
[registry-host]$ mkdir ~/docker_hub && cd ~/docker_hub
[registry-host]$ vi docker-compose.yml
version: '2'
services:
registry:
image: registry:2
volumes:
- ./registry:/var/lib/registry
ports:
- "5000:5000"
restart: always
[registry-host]$ docker-compose up -d
volumesの指定は登録したリポジトリデータを永続化するためのものです。
初回構築時にはdocker-compose.ymlだけあれば良いです。
登録
事前設定
httpで通信する場合、my-pcのDockerでregistry-hostを許可する設定が必要です。
registry-hostの部分はご自身の環境のIPやホスト名に置き換えてください。

これでmy-pcからregistry-hostへimageをpushできます。
例としてalpine linuxを登録してみます。
[my-pc]$ docker pull alpine:latest [my-pc]$ docker tag alpine:latest registry-host:5000/my-alpine:latest [my-pc]$ docker push registry-host:5000/my-alpine:latest
登録の確認
リポジトリ一覧
[my-pc]$ curl http://registry-host:5000/v2/_catalog
{"repositories":["my-alpine"]}
タグ一覧
repositoriy名を指定して、タグ一覧を取得します。
この例ではmy-alpineを指定しています。
[my-pc]$ curl http://registry-host:5000/v2/my-alpine/tags/list
{"name":"my-alpine","tags":["latest"]}
Pull
[my-pc]$ docker pull registry-host:5000/my-alpine:latest
削除
リポジトリの削除
[registry-host]$ cd ~/docker_hub/registry/docker/registry/v2/repositories [registry-host]$ rm -rf <repositoriy-name>
タグの削除
[registry-host]$ cd ~/docker_hub/registry/docker/registry/v2/repositories [registry-host]$ rm -rf <repositoriy-name>/_manifests/tags/<tag-name>
たぶん削除用のAPIとかあると思うんですが、今のところディレクトリ削除で何とかなってます。
削除自体あまりしないですし、壊れたらまたPushすればいいやってノリです。
今回はゆるく使うということでimageの管理は適当ですが、
ちゃんと管理したい人はPortusというのを使うと色々出来そうです。
まぁ自分だったら、これ以上は面倒なので素直にaws ECRとかを使いますが。
以上、現場からでした。
vscodeで効率良くコードレビューする小技
コードレビューする時の変更箇所を比較する方法って色々あると思うんですが、
自分的にvscodeのGitLensを使ったやり方がいい感じなのでご紹介します。
手順
レビューするブランチをコミットせずにマージします。
マージ後、resetでステージからも外します。
$ git checkout ${baseブランチ}
$ git merge --no-commit --no-ff ${レビューするブランチ}
$ git reset
vscodeで変更ファイルに色がつくので、
右クリックで[Compare File with Previous Revision]を選択します。
すると、こんな感じで差分が表示されます。

全体のコードを見つつ、差分は色付きで表示してくれるのでレビューしやすくなると思います。
定義へ移動とかも使えますし。
サイドバーの[ソース管理]でも同じように表示されますが
自分としては[エクスプローラー]でツリーを見ながらレビューしたいのでこの方法を使ってます。
コードレビューでお困りでしたら一度お試しください。
レビュー後は、マージした差分を取り消すのをお忘れなく
$ git reset --hard HEAD $ git clean -fd
vscodeは知れば知るほど便利なエディタですね。
vscodeのextension(プラグイン)を過去のバージョンに戻す
vscodeのextensionを自動更新のままにしていたら、rubyのextensionが更新されて定義へ移動が効かなくなりました。
とりあえずダウングレードしたら直ったので、バージョンの戻し方を備忘録として書いておきます。
パッケージファイルのダウンロード
マーケットからは最新バージョンしかダウンロードできないので、
以下のURLを組み立ててダウンロードします。
https://${publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${publisher}/extension/${extension_name}/${version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage
publisherやextension_nameはマーケットURLのitemNameパラメータで確認できます。
https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby
マーケットのChangelogから戻したいバージョンも確認します。
${publisher} -> rebornix
${extension_name} -> Ruby
${version} -> 0.16.0
今回の場合は以下のURLでダウンロードしました。
https://rebornix.gallery.vsassets.io/_apis/public/gallery/publisher/rebornix/extension/Ruby/0.16.0/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage
ダウンロード後にファイルの拡張子を.vsixに変更します。
インストール
vscodeですべてのコマンドの表示(F1)-> vsixと入力。
[拡張機能: VSIXからのインストール]でダウンロードしたファイルを選択すれば完了です。
思った以上に面倒だった。
最後にextensionの自動更新をオフにしておくことを忘れずに。
setting.json
"extensions.autoUpdate": false
以上、現場からでした。