出力を入力へ

プログラミングに関する自分が考えた事を中心にまとめます

GitHub Secretsの更新をgithub-secrets-writerで自動化する

GitHub Actionsでクレデンシャル情報を利用するためにGitHub Secretsを利用しているわけだけど, この値の設定や更新を自動化したい.

具体的には AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY の更新を自動化したい. また,現状は単一のbotユーザの権限で,複数リポジトリに同じアクセスキーを設定しているので アクセスキーを更新したら複数リポジトリをまとめて更新したい.

リポジトリが少ないうちは手動対応でもよかったけれど リポジトリ数が増えるにつれて設定忘れや更新もれが発生しそうなこと, そもそも面倒なので自動化する.

自動更新の仕組み

おおまかな手順としては以下の通り

  1. アクセスキーを更新してダウンロード
  2. cliツールを利用して特定リポジトリのsecretsを更新
  3. すべてのリポジトリに対して 2 を繰り返す

cliによるsecretesの更新

secretsの更新に githubの公式クライアントツールの cli を利用したい. ところが,cliはsecretsの更新APIには対応しておらず,要望は上がっているが まだすぐに実装されそうというものではない.

その代替としては, github-secrets-writer というのがあるのでこれを利用する. その名前の通り,github secretsの更新に特化したcliツールである.

github-secrets-writerを利用する

手順としてはREADMEにある通り.

GITHUB_TOKENはGitHub公式ヘルプなどを参考に作成する. 権限について,パブリックリポジトリのsecretesのみを更新するのであれば public_repo だけで, プライベートリポジトリのsecretsも更新するのであれば repo のフルコントロールが必要になる.

あとは更新するリポジトリとsecrets名および値を指定して実行するだけ. key=value 形式で設定値が記載されているファイルがあれば --from-file で簡単に指定できるが, 残念ながらAWSアクセスキーはcsv形式なので--from-fileで簡単に利用できる形式ではないので 諦めて --from-literal で直接指定して実行する.

出力が少しわかりにくく, secretName1: 204 No Content のように表示されていれば上手く更新されている. 新しくsecretsの項目を作った場合は secretName1: 201 Created のようになる. 一方で,権限不足等であれば以下のように表示される.

secretname3: GET https://api.github.com/repos/thaim/samplerepo/actions/secrets/public-key: 404 Not Found []
ERROR: encountered some failures, see above

github-secrets-writerによる自動更新を自動化する

アクセスキーの更新は90日で更新してねという推奨があるので, アクセスキーの発行や上記cliの操作自体も自動化したい.

アクセスキーを発行するAPI自体は存在するので lambdaでアクセスキーを発行してそのままsecretsを更新するような処理を実装して CloudWatchで定期的に呼び出してあげればよい.

が,そこそこ面倒なので止めた. まずは手元で自動化できればよさそう.

Organizationレベルで共通のSecrets

ここまで手順を整理したところで, GitHubが最近 SecretsをOrganizations レベルで共有できる Organizations Secretsを発表している ことに気が付いた.

これを設定・利用すればそもそも,リポジトリ毎のSecretsを更新してまわるなんて不要になる.

wheneverのカスタムjob_typeで月末バッチを実現する

cronジョブをRubyで書くためのgem wheneverで 月末バッチを実現するためのカスタムスクリプトを実装したい. このとき,wheneverのカスタムjob_typeで実現したのでそのまとめ.

月末バッチの実装

cronで月末バッチをスケジュールする場合,月末の判定が面倒. 月末となる日は30日や31日,もしくは28日や29日(2月のうるう年)のような条件があるので, 日付を決め打ちにすることができない. cron書式とは別に月末判定を実施して処理する仕組みが必要である.

よくある実装としてはcronで呼び出されるスクリプトの冒頭で, 翌日が1日か判定して1日でなければ処理を終了する方法である. 例えば以下のような方法で翌日の日付を判定することで月末かを確認できる.

if [ `date - d tomorrow "+%d"` == "01" ]; then
  run_batch.sh
fi

cronだったら一行で実現したいので以下みたいになる

0 0 * * * "[ `date - d tomorrow \"+\%d\"` == \"01\" ] && run_batch.sh"

cronにおける注意点として,ダブルクオテーションに対するエスケープはもちろん, % に対するエスケープ処理が必要な点にある. 詳細はman 5 crontab を参照.

wheneverにおける実装

ではRubyでcron書式を実装する wheneverではどのように実装するか. wheneverでは以下のように記載する.

every '0 0 27-31 * *' do
  rake "app_server:task"
end

これを bundle exec whenever でcron書式に変換すると以下のように変換される.

0 0 27-31 * * /bin/bash -l -c 'cd /home/thaim/work && RAILS_ENV=production bundle exec rake app_server:task --silent'

これは wheneverの仕組みによるもので, パスの変更やRAILS_ENVの指定などをユーザが考慮する必要がなくなる. 一方で,今回のような月末判定ロジックを組込むにはwheneverの仕組みと重複するので難しい.

対策として,独自の変換ロジックとして job_typeをカスタマイズする方法である. 上記 wheneverのrakeはwheneverが実装するjob_typeによる変換方式が適用されたものである. これを月末判定ありのjob_typeを定義してあげればよい. 例えば以下のような rake_lastday job_typeを定義する.

job_type :rake_lastday, "[ `date -d tomorrow \"+%d\"` == \"01\" ] && cd :path && :environment_variable=:environment bundle exec rake :task --silent :output"

これを利用すると 月末判定付きのcronが生成されるようになる.

every '0 0 27-31 * *' do
  rake_lastday "app_server:task"
end

という記述が以下のように変換される

0 0 27-31 * * /bin/bash -l -c ''[ `date -d tomorrow "+\%d"` == "01" ] && cd /home/thaim/work && RAILS_ENV=production bundle exec rake app_server:task --silent'

補足: 拡張書式としてのL

ちなみに,cron書式にて日付に 'L’ を使えば月末日を自動で判定してくれるよ, みたいな記事がStackOverflowとか英語Wikipediaに記載がある. ただし,これは一般的なcronでは実装されていない,独自方言であり基本的には使えない.

例えば JavaのジョブスケジューラライブラリQuartzなんかには 拡張書式として月末日のLがサポートされている. ただし,一般的なcronでは扱われているような書式ではないので この書式がサポートされていることを期待しない方がよさそう.

Terraformでリソースをインポートしたり削除したり

TerraformでTerraform管理外の既存のリソースを管理下に入れる方法と外す方法. 管理下に入れるコマンドが import なら管理から外すのは export だろ,と思ったけどそんなコマンドはなかった.

リソースをインポートする

まずはインポートする方法から. Terraform importコマンドを利用することでリソースをTerraformの管理下に置く.

実行コマンドは terraform import [options] ADDRESS ID の書式の通り. ADDRESSは Resource Adressingにある通りで, tfファイルでリソースを指定するときに利用する書式. aws_s3_bucket.my_bucket_name とかそういうやつ.

IDはTerraformのドキュメントに記載されたIDで,リソースドキュメントの最後に記載されている. 例えばS3ならS3 bucketリソースに記載の通りバケット名. EC2インスタンスならインスタンスリソースに記載の通りインスタンスID.

このIDがリソースによってフォーマットが大きく異なり,基本的には上記の通りリソース名だが, SQSのようにIDがURLだと https://queue.amazonaws.com/80398EXAMPLE/MyQueue のように記載したり, ECSタスク定義のようにIDが存在しないとARNとして arn:aws:ecs:us-east-1:012345678910:task-definition/mytaskfamily:123 のように記載したりと たまに例外があるので注意が必要.

$ AWS_DEFAULT_REGION=ap-northeast-1 terraform import aws_s3_bucket.sample sample-bucket-name
aws_s3_bucket.sample: Importing from ID "sample-bucket-name"...
aws_s3_bucket.sample: Import prepared!
  Prepared aws_s3_bucket for import
  Prepared aws_s3_bucket_policy for import
aws_s3_bucket_policy.sample: Refreshing state... [id=sample-bucket-name]
aws_s3_bucket.sample: Refreshing state... [id=sample-bucket-name]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

リソースを除外する

importを取り消したいときなどの逆操作について. この操作がないと既存リソースを一度削除する必要が出てくるので リソースを除外するコマンドがないわけないだろうと思ったが Terraform Command一覧を見てもそれらしいものが無いので困っていた.

結論としては terraform state rm サブコマンドが目的の Terraformの管理下から除外するコマンドだった. サブコマンドが存在するのは terraform state コマンドと terraform workspace コマンドだけで,これに注意する必要があった.

実行コマンドは terraform state rm [options] ADDRESS... の書式通り.

$ AWS_DEFAULT_REGION=ap-northeast-1 terraform state rm aws_s3_bucket.sample
Removed aws_s3_bucket.sample
Successfully removed 1 resource instance(s).

Terraform backendがTerraform Cloudのような外部管理であってもリソースの追加/削除は可能なので いろんなところで利用することになりそう.

そして再度確認したら,きちんと 実践Terraformに記載されていた. あらためて見ると24章のリファクタリングは重要な操作なので再確認が必要.

Ubuntu on WSL2 でsnapを利用する

Ubuntu20.04 LTS と WSL2を試してみたところ snapコマンドが上手く利用できなかったのでそのまとめ

WSL2

もともとWSL2もInsider Previewを利用して試していたけど, とうとうGA版がリリースされたということで改めて試してみた.

WSL2の利用方法は Insider Previewの頃と変わらず. Insider Previewを利用せずともWSL2が利用できるようになった.

WSL2におけるsnapdとsystemd

Ubuntuの新しいパッケージ管理システムであるsnap. ところが WSL2上のUbuntuではsnapコマンドが実行できない.

$snap install hello-world
error: cannot communicate with server: Post http://localhost/v2/snaps/hello-world: dial unix /run/snapd.socket: connect: no such file or directory

原因は snapコマンドが systemdに依存しており,WSL2ではsystemdが起動していないこと. snapコマンドはsnapdと通信して動作するが,snapdはsystemdサービスとして動作するので systemdが動作していないとsnapdも動作せず,snapコマンドは正常に実行できない.

$ cat /etc/systemd/system/multi-user.target.wants/snapd.service
[Unit]
Description=Snap Daemon
Requires=snapd.socket
OnFailure=snapd.failure.service
# This is handled by snapd
# X-Snapd-Snap: do-not-start

[Service]
# Disabled because it breaks lxd
# (https://bugs.launchpad.net/snapd/+bug/1709536)
#Nice=-5
OOMScoreAdjust=-900
ExecStart=/usr/lib/snapd/snapd
EnvironmentFile=-/etc/environment
Restart=always
WatchdogSec=5m
Type=notify
SuccessExitStatus=42
RestartPreventExitStatus=42
KillMode=process

[Install]
WantedBy=multi-user.target

WSL2ではsystemdはinitシステムとして動作していない. WSL2ではWindowsとのを実現するために独自のセットアップを実行しており, Ubuntuなどで採用されているsystemdは利用されていない. このため,systemctlコマンドなどは動作しない.

$ systemctl status snapd
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

WSL2上でsystemdを実行する

無理矢理systemdを起動してあげることで対処する. この記事に従いsystemdを起動すると systemctlが利用できるようになるし,snapdも動作するようになる.

$ systemctl status snapd
● snapd.service - Snap Daemon
     Loaded: loaded (/lib/systemd/system/snapd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2020-05-24 13:46:21 JST; 5min ago
TriggeredBy: ● snapd.socket
   Main PID: 444
      Tasks: 27 (limit: 30645)
     Memory: 170.6M
     CGroup: /user.slice/user-1000.slice/session-c2.scope/system.slice/snapd.service
             └─444 /usr/lib/snapd/snapd

 5月 24 13:50:47 DESKTOP-JCB3AFB snapd[801]: rip    0x5580ad845031
 5月 24 13:50:47 DESKTOP-JCB3AFB snapd[801]: rflags 0x286
 5月 24 13:50:47 DESKTOP-JCB3AFB snapd[801]: cs     0x33
 5月 24 13:50:47 DESKTOP-JCB3AFB snapd[801]: fs     0x0
 5月 24 13:50:47 DESKTOP-JCB3AFB snapd[801]: gs     0x0
 5月 24 13:50:47 DESKTOP-JCB3AFB systemd[1]: snapd.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
 5月 24 13:50:47 DESKTOP-JCB3AFB systemd[1]: snapd.service: Failed with result 'watchdog'.
 5月 24 13:50:48 DESKTOP-JCB3AFB systemd[1]: snapd.service: Scheduled restart job, restart counter is at 2.
 5月 24 13:50:48 DESKTOP-JCB3AFB systemd[1]: Stopped Snap Daemon.
 5月 24 13:50:48 DESKTOP-JCB3AFB systemd[1]: Starting Snap Daemon...

あとは 通常通りsnapコマンドを実行すればいいだけ. ただし,当然ながらsystemdはあまり正常な状態ではないようで, systemctl restartなどでsnapdを含む適当サービスを再起動するとエラーになる.

$ sudo systemctl restart snapd
[sudo] thaim のパスワード:
Warning! D-Bus connection terminated.
Failed to restart snapd.service: 接続が相手からリセットされました
See system logs and 'systemctl status snapd.service' for details.

一応snapコマンドでhello-worldをインストール・実行できたのである程度は動作する,はず. ただし,現状では可能な限りsnapコマンドは利用しない方がよさそう.

参考

書評: 新 企業の研究者を目指す皆さんへ

もともと自分が学生だった頃に読んだ本の新版. 当時はまだ企業における研究とは何か理解しておらず,その後の自分の企業研究者人生に大きな影響を与えてくれた. その新版が出たということで読んでみた.

企業の研究者を目指す人という書き方ではあるが, 企業の研究者ではなくなった今の自分でも読んでよかったと思えた.

概要

企業の研究者や,研究者を目指す学生に向けて著者のキャリアの中で感じた 企業において必要なこと,研究者において必要なことなどを記載している. 著者はソフトウェアに関する研究者ではあるが,分野に依存しない 一般的な研究者へのメッセージ・考え方を示している.

新版での追加内容として,旧版が出版されてからの著者のキャリアとして 数理研やPFNなどの経験を踏まえた内容となっている. 旧版のIBMにおける研究に対する考え方を知る本という立ち位置から, 企業という枠を超えて研究者とは何かについて知ることができる.

よかったところ

新版で追加された内容では,2章におけるソリューションを設計するが深く刺さった. 設計型の研究を上手く成果に結び付けることが難しいことは,自分も多く経験しており, 論文にすることの難しさや,成果としての評価の難しさを今でこそ理解している. さらっと書かれており,学生が読むとしたらスルーされるだろうけれど, もっと早く出会えていたら自分の悩みにもっと向き合えていたかもと思う.

旧版からあった内容で,改めて深く考えたのが6章のインテグリティについてである. もちろん,研究成果の捏造といった重大な事件はやっていないし,実際に見たことはなかったけど, 進捗のごまかしという点では大なり小なり見てきたし手を出してしまったこともある. あとはやるだけだからとか,ここのバグを直せば完了だからと,成果をごまかして報告したり, 逆に毎週良い成果を報告したいから,まだ今週は上手くいっていないことにして次週に報告しよう, といって報告しなかったりという場面に多々出会ってきた. これはコミュニケーションの問題でもあるが,社内だからこそ包み隠さず報告することが大切だし, 過剰にアピールせず等身大に伝える,ということの大切さと難しさを再度考えてしまった.

よくなかったところ

特に疑問に思ったところはなく,基本的に非常に満足できる内容だった.

あえて言うのであれば企業という視点が軽くなったように感じた. タイトルの「企業の」ということが本質ではなく,アカデミックの研究者を目指す人にも読んで欲しい内容だと思った. 「企業の研究者」と述べているからにはもっと企業特有の話を記載して欲しいとも感じた. 例えば2章の研究の出口はまさに企業とアカデミックで大きく異なるところだと思っているので, もう少し掘り下げて欲しかった(技術移転はそれだけで1冊本になりそうなほど難しいトピックだと思う).

まとめ

企業で研究するならぜひとも一度は読んで欲しい本だと思うし, 研究でなく開発よりでも非常に参考になる. 自分も読んでいてまた研究したいなと思ってしまった.

新 企業の研究者をめざす皆さんへ

新 企業の研究者をめざす皆さんへ

MySQL 5.7.30 でvalidate_password プラグインを回避する

いつも Docker での動作検証しかしていなかったので, Docker以外の環境とかMySQLの初期化処理とか知らなかった.

事の始まり

AWS EC2 / Amazon Linux2 に MySQL をインストールして利用したい. このとき,開発・検証環境だから弱いパスワードを許可したかった(もちろん本当はよくないけれど).

ところが,弱いパスワードを設定しようとするとエラーになる. 軽く検索すると設定ファイルにパスワードポリシーの変更を追記するといいよという記事がたくさんヒットする. ただし,設定項目が記事によって異なる,タイポ?バージョンで違う? しかも設定を反映するとMySQLがエラーで起動しなくなる. とりあえず非公式情報は参考にならなそう.

ということで,なぜパスワードが変更できないのか,なぜ設定変更するとMySQLが起動しなくなるのか, その設定を変更する正しい手順はどうすればいいのか について調査した.

したいこと

  • Amazon Linux2 に MySQL 5.7.30 をインストールする
  • validate_passwordプラグインの制限を緩和する
  • この設定のセットアップ手順を確立する

なぜ上手くいかなかったのか

validate_passwordプラグインによるパスワードポリシー設定

弱いパスワードが設定できなかったのはデフォルトで validate_passwordプラグインが有効になっているため. このプラグインにより,弱いパスワードを設定することができなくなっている.

dev.mysql.com

このプラグインがデフォルトで有効になるのはyumリポジトリからMySQLをインストールした場合などで, 今回のAmazon Linux2ではYumリポジトリからインストールしていたのでこのプラグインが有効化されていた.

dev.mysql.com

Note

If you installed MySQL 5.7 using the MySQL Yum repository, MySQL SLES Repository, or RPM packages provided by Oracle, validate_password is enabled by default after you start your MySQL Server for the first time.

実際に Dockerの公式イメージ(mysql:5.7.30)で確認するとプラグインは有効になっておらず, validate_passwod プラグインのみ差異があることがわかる. 公式DockerイメージはDebianベースなので確かに公式ドキュメントの通りvalidate_passwordプラグインは有効にならない.

Yumリポジトリからインストールした場合

mysql> show plugins;
+----------------------------+----------+--------------------+----------------------+---------+
| Name                       | Status   | Type               | Library              | License |
+----------------------------+----------+--------------------+----------------------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     |
| validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     |
+----------------------------+----------+--------------------+----------------------+---------+
45 rows in set (0.00 sec)

Dockerで起動した場合

mysql> show plugins;
+----------------------------+----------+--------------------+---------+---------+
| Name                       | Status   | Type               | Library | License |
+----------------------------+----------+--------------------+---------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL    | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL    | GPL     |
+----------------------------+----------+--------------------+---------+---------+
44 rows in set (0.01 sec)

対策としては,セキュアなパスワードを利用するか,ポリシーを変更するか,プラグインをアンインストールするか.

プラグインの反映タイミング

パスワードの制限を緩和するためには,ポリシーとして validate_password_policy = OFF を設定すればよい. これにより利用できるパスワードの制限を変更できる. もう少しパスワードポリシーをカスタマイズしたい場合は, 以下のプラグインオプションが参考になる.

dev.mysql.com

一方で初回起動前にこの設定を my.cnf に記載すると,validate_password プラグインがインストールされる前に反映しようとして, 無効な設定としてエラーになってしまう.

2020-05-04T10:31:49.970600Z 0 [ERROR] unknown variable 'validate_password_policy=LOW'

これは公式ドキュメントにも記載されている.

This option is available only if the validate_password plugin has been previously registered with INSTALL PLUGIN or is loaded with --plugin-load-add. See Section 6.4.3.1, “Password Validation Plugin Installation”.

ではこのプラグイン自体を最初から無効化すればいいかというとそれは難しい. プラグインの設定反映はMySQLをインストールしたときの systemdの設定ファイルによるもので, /usr/lib/systemd/system/mysqld.service には

# Needed to create system tables
ExecStartPre=/usr/bin/mysqld_pre_systemd

の記載があり, この /usr/bin/mysqld_pre_systemd で validate_passwordプラグインのインストールを含む 証明書の作成やシステムテーブルの作成などの処理(mysqld --initialize)を実行している.

validate_passwordプラグインを有効にしないオプションなどは存在せず, このpreスクリプトを実行しないと自分で初期化処理が必要になるので このスクリプトを実行しない選択肢は基本的にない. このスクリプトを自前でカスタマイズするのもリスクが高いので, Yumリポジトリからインストールした場合は基本的にvalidate_passwordプラグインは有効になっている想定がよさそう.

初回起動直後にプラグインをアンインストールしようとしても, 初期パスワードの変更前にパスワード変更以外の操作は受け付けないので, 初回起動→複雑なパスワード設定→プラグインアンインストール→簡易なパスワードの設定 といった無意味な手順が生じてしまう.

以上から,一度MySQLを起動してプラグインを反映した上でパスワードポリシーを変更して再起動, という手順がよさそう.

validate_passwordプラグインを回避するセットアップ手順

MySQLのインストール

Amazon Linux2ではMariaDBが有効になっている. MySQL5.7を利用したい場合はMySQLリポジトリを追加し, MySQL8を無効化して 明示的に5.7を有効化・インストールする必要がある.

dev.classmethod.jp

このタイミングでパスワードポリシーも変更したいが,それは実行しない. 自動起動の設定は反映されていないので sudo systemctl enable mysqld自動起動を有効にだけしておく.

MySQLのセットアップ

MySQLの初回起動後に /etc/my.cnf にパスワードポリシーの変更設定を記載する. 設定ファイルの末尾に validate_password_policy = OFF を追記だけしてあげればよい.

その後MySQLを再起動すればパスワードポリシーが変更される. あとは初期パスワードを弱いパスワードでも自由に設定できる.

初期パスワードはログ(/var/log/mysql.log)に出力されているので, これを利用してパスワードを変更する.

パスワード変更時にpassword関数を利用する方法はDeprecatedなのでpassword関数は利用しない. またSET PASSWORD FOR root@localhost = 'password' よりはALTER USERの方が推奨のようで, ALTER USER root@localhost IDENTIFIED BY 'password' でよい.

dev.mysql.com

Note

SET PASSWORD ... = PASSWORD('auth_string') syntax is deprecated as of MySQL 5.7.6 and will be removed in a future MySQL release.

SET PASSWORD ... = 'auth_string' syntax is not deprecated, but ALTER USER is the preferred statement for account alterations, including assigning passwords. For example:

参考

dev.mysql.com

hub.docker.com

hirose31.hatenablog.jp

qiita.com

SRE NEXT 2020 に参加しました

2020-01-25 に開催された SRE NEXT 2020 に参加しました.

sre-next.dev

現在自分はインフラエンジニアとして働いており, 運用も合わせて行っているので勝手に自分もSREを名乗れるかな?と考えて 自分が今後目指すべきキャリアを見極めようと考えて参加しました.

以下自分が聴講したセッションとその感想です.

[A0]基調講演: 分散アプリケーションの信頼性観測技術に関する研究

さくらインターネットにおける(というより発表者の?)SREを研究に昇華させた取組み.

speakerdeck.com

単なるアプリケーションの信頼性に限らず,クラウドを構築・提供する事業者としてのサービスの信頼性を どのように取組むかといった将来のSREに向けた取組みであると,まさにSRE NEXT だった.

一方で,これは今自分が取組む内容とはかけ離れていて,同じSREでもここまで違うんだな,と他人事に思えた. 最後のパネルディスカッションの中で,将来のSREはアプリ開発の中に原則は残りつつも, 究極的にはクラウド事業者だけが気を付ければいい職掌になる,といった内容の話があり, この基調講演の他人事のように思えた感じはクラウド事業者とクラウド利用者の差なのだなと感じた. だとすると,この発表のようなクラウド事業者としてのSRE NEXT ではなく, サービス開発者側のSRE NEXT を探さないといけない.

[C1] 絶え間なく変化するメルカリ・メルペイにおけるSREの組織と成長

メルカリおよびメルペイにおけるSREを組織化するに向けて取り組んできた成果.

speakerdeck.com

メルカリとメルペイで (マイクロサービス化できているかという視点から)組織構成や取組みが異なることは初めて知ったし, これだけ技術的に優れているメルペイであってもSREがチームとして動くようになるまでには大きな苦労を伴うことは, どこでも簡単ではないんだなと現実を知った感じ.

ただ,どちらの発表もなぜそうなったのか,どうやってそうしたのかというプラクティスがあまり共有されなかったのが残念だった. メルカリのマイクロサービス移行の過去の取組みとしてchocon開発移行の状況は紹介されていても, SREがボトルネックになりそうという問題があまり理解できなかったし,組織編成でどうして解決できるのかも伝わらなかった. 時間があれば聞いてみたかったところ. メルペイもToilを受け入れて戦う必要があるし採用は辛い,チーム化も辛いと,課題はよくわかるのだけれど, サービスがリリースされたら採用できました,人が増えたら解決できました,と聞こえてしまい, どのようにToilを対処したのか,どのように頑張ったのかがわからなかった.

[C2] 成長を続ける広告配信プラットフォームのモニタリングを改善してきた話

Voyage におけるアラートや監視の取組み.

speakerdeck.com

ユーザ視点でサービスが正常であるかを判断し,サービスの外側から重点的に監視するというのは, あたりまえではあるけどその通りだと思った.実際,自分のところではできていないから対処しないといけない. アラートも目的に応じて通知先をふりわけるというのも必要なこと. それでSREが楽になるだけでなく開発者も気にしてくれるようになるのであればこれ以上はない. アラートの見直しは障害が起きたとき,監視システムを置き換えたとき,人が増えたとき,というのはなるほどと思った. 障害が起きたときの見直しは当然だけど,人が増えたときにそれを切っ掛けにするというのは 大変だけど効果がありそうなので取組みたい.

ツール選択には複数の指標をもとに,ツールと仲良くなって判断するというのも, なかなかできていないので耳が痛い話.もっと普段からいろいろ挑戦してみないと.

[D3] Practices for Making Alerts Actionable

グリーにおける静観対応となるアラートの問題と, アラートの計測とふりかえりによるアラートの見直し,自動復旧の検討の取組み紹介.

speakerdeck.com

最近自分のところでもアラートの対応に課題があることは認識しており, どのように対応すべきか考えていたのでとても参考になった.

アラートに問題があるならアラートを計測してふりかえるという, あたりまえのことにきちんと取組めているのはすばらしいと思うしぜひ真似していきたい. 自動復旧も,既に障害で動いていない場合などこれ以上悪くならない場合には 導入しやすいというプラクティスもその通りなのでぜひ取組みたい.

[D4] 100万回線のIoT通信を支えるソラコムにおけるOpsDevの実践

ソラコムにおけるOpsDev (=SRE)の取組み.

www.slideshare.net

開発者も運用をするし,開発者もSREもサポートをするし,インシデント通知はエンジニア以外の全社員に通知するのは,すごい取組みだと思った. これがきちんと実践できているのであれば,サービスの信頼性や顧客満足度を全員が意識するようになるので, カルチャーとしてはすばらしいと思う.

ただ,カスタマーサポートも非常に難しい職掌だし,エンジニアと兼務して取組める気がしない. エンジニアのスキルだけでもキャッチアップするのが大変な,さまざまな技術が求められる時代なのに, 加えてカスタマーサポートもは自分だったら対応できない. どのようにエンジニアがサポートを実践しているのか, どのようにバックオフィス系の社員が障害アラートを認識して対応しているのかは気になるところ.

[C5] スクラムを1年回してSREと開発組織がどう変わったのか

HAMOS(ビズリーチ)におけるSREとしてのスクラムの取組み. 特定のタスクに取組めず,割り込みの多いSREがどのようにスクラムを実践してきたか紹介があった.

speakerdeck.com

どれに取組めばいいのかわからないので,タスクの優先度を定量的に評価することで全員が合意の元で判断できるようにする,というのはすばらしい取組み. 一方で,タスクの優先度を定量化するのはそう簡単ではなく, 下手をすれば設定したい優先度に向けて定量化の式を毎回見直したくなる気がする.

開発チームとの共依存について, ペアプロ等で相互に技術移管して割り込みで他者に仕事を依頼するのではなく, 自分ごととして対処できるようにするというのは理想的な状態. 現状,自分たちではまだまだ1人がやることが多くて技術移管までできそうにないのが辛いところ. このあたりは属人化の問題と関連しているのだろうけれど, どうしてもスピードが優先されるスタートアップにおいてなかなか 長期的な運用を見据えてスピードを犠牲にする判断はできない. 自分たちの取組みが必要なところかも.

[C6] Designing fault-tolerant microservices with SRE and circuit breaker centric architecture

クックパッドにおける既存のアプリの信頼性を担保しつつも機械学習サービスなど新しい技術領域を取り入れていく取組み.

このあたりは自分たちも近い将来同じ課題にぶつかることが想定されるので非常に参考になった. とはいえ,機械学習エンジニア側で開発リソースや自分たちで運用することができる前提なので なかなか同じようにはいかなそう. それでも信頼性の異なるサービスをサーキットブレイカーで分けるとか, デザインドキュメントで期待値をすりあわせるとか,できれば自分たちも取り入れたい.

若干ながら機械学習チームをつき離しているようにも聞こえたが, 何が大切なのかを共有できており,相互に信頼・尊重しているからこそできる無駄のない取組みだろう. そのようなチームができるように自分たちも頑張りたい.

[B7] SRE Practices in Mercari Microservices

メルカリにおけるマイクロサービスを実践していく中での,SLI/SLOを更新し続けるための取組み,オンコールへの対応,Toil(リアクティブなタスク)への取組み.

speakerdeck.com

これまでの発表内容が随所に出てくる,まさにロングセションに相応わしくSREの個々のプラクティスが一本にまとまるようで聞いていて非常に面白かった.

SLI/SLOを始めから完璧を目指さず更新していく体制を整えること,それを実現するためのポストポーテムの実践と SLO Decision Matrixを参考にしつつも 内容に応じて自分たちで判断することこは理想的なチームであるように見える.

アラートをアクション可能として,REDでアラートしてUSEで調査するという, 障害対応とはこのように実践するんだといわんばかりの体制だった.

Toilを減らしリアクティブなタスクに対処するため, デザインドキュメントで期待値を調整し,Production Readiness Checkでチェックするというのは 開発者とサービスリリース後にもめないためのリスクを減らす仕組みとしてよさそう. 一方でこれを実践しても形骸化せずサービスの品質に落とし込めるのは メルカリの優秀なエンジニアがいてこそだろうか.

[A8]基調講演: Webサービスを1日10回デプロイするための取り組み

Lobi(面白法人カヤック)における 10 deploy per dayを実現するために, デプロイを構成するあらゆる要素の高速化と誰でも安全にデプロイできる仕組みを実現する取組み.

speakerdeck.com

デプロイを高速化するためにエラー検知やロールバックを含めて高速化するところはなるほどと気付きを得た. 安全に誰でもデプロイできるようにするために,自動化するのはもちろん,計測して管理するのも王道だしよいプラクティスだと思った.

自分のところでは,デプロイが大変だと認識していてもまだデプロイも自動化できていない. デプロイ作業を計測して,デプロイの大変さを再共有し,自動化に向けた対応を強化するのはいいかもしれない. ChangeLogの生成自動化もやりたいところなので,早めに完了させたい.

全体をふりかえって

自分にもすぐに取組めそうなプラクティスから,すぐには取組めないけど将来の目標に見据えられるようなすばらしい取組みまで, さまざまな知見を共有できたすばらしい1日だった.

今までは先進技術として面白く感じていても他人事であったのが, やっと自分もインフラエンジニア・SREエンジニアとなって自分ごととなり, 自分事という新しい視点で話を聞けて非常に刺激になった.

取り入れられるプラクティスは積極的に取り入れて 今度は自分が発表する側に立てるようになりたい.