うなすけとあれこれ

2019年07月08日

異常独身男性エントリ

abnormal bachelor

オタク!退職エントリより
異常独身男性エントリ書いて!

— 衰咲ふち💬アーバンキャット (@otoroesaki) July 2, 2019

経緯

「異常独身男性注意マスキングテープ (マスキングテープ - テープ幅 15mm)」を 限界集落 で購入しました! https://t.co/7Z8WodNZtK #booth_pm

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) June 17, 2019

異常独身男性にマスキングテープ貼り付けるいたずらをやっていこうと思います

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) June 17, 2019

左隣に座ってる同僚には絶対貼りたい

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) June 17, 2019

ふちちゃん、一枚セールスしたわよ! pic.twitter.com/sgvFb7L114

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) June 17, 2019

アアアアアーーーアアアアアーアーアーアーアーアーアアアーーーーーアアーア

異常独身男性:背面有〼 Tシャツ ブラック Mを買ったよ。 https://t.co/kWBTbhCXKp #suzurijp @suzurijpさんから

— うなすけ (@yu_suke1994) June 17, 2019

そして

pic.twitter.com/HcTk2jQFtU

— うなすけ (@yu_suke1994) July 5, 2019

異常独身男性 pic.twitter.com/WLL3xaBUUg

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) July 8, 2019

異常独身男性 pic.twitter.com/GYMkDIDBO4

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) July 8, 2019

絶対に嫌シリーズ

うなすけくんには異常独身男性界を背負って立ってほしい

— 衰咲ふち💬アーバンキャット (@otoroesaki) June 23, 2019

今生まれ出づる異常独身男性ニューエイジ
うなすけ

— 衰咲ふち💬アーバンキャット (@otoroesaki) June 28, 2019

独身男性の皆さん買いましょう

衰咲ふちの限界集落で異常独身男性シリーズが発売されたわよ! #衰咲

異常独身男性:背面有〼Tシャツ https://t.co/jk7jWiaztm

異常独身男性ステッカー(COLOR) | 限界集落 https://t.co/MIDepETLUe

異常独身男性マスキングテープ | 限界集落 https://t.co/wEfJrhzywj pic.twitter.com/7csRAsAb5E

— 衰咲ふち💬アーバンキャット (@otoroesaki) June 15, 2019

カラー色々!選べる異常独身男性!
ブルーカラーもホワイトカラーも一緒に仲良く異常独身男性着ようね!(皮肉) pic.twitter.com/zkiVFOaoZb

— 衰咲ふち💬アーバンキャット (@otoroesaki) June 15, 2019
Tweet
2019年07月08日
2019年06月25日

Fortitude60を組みました

Fortitude60

経緯

2018年10月頃のgroup buyから積みっぱなしになっていたFortitude60を、重い腰を上げてようやく組み立てました。

Fortitude60 group buy round1

発端は、友人の @nikuzuki_29 が職場で布教された結果「自作キーボードを組んでみたい」という気持ちになり、では僕も、とスイッチ、キーキャップを揃えて組み立てることにした、という流れになります。

構成

組み立て

肉好きが初心者であることから、一日中遊舎工房のフリースペースを使うつもりで早起きして秋葉原に行き、組み立てを開始しました。(事実、閉店まで居ました)

僕も久々の半田付けであることから、まずはmeishiを各々組み立てて慣れておく作戦をとったのが良かったです。

遊舎工房で1日かけて組み立てたのですが、その場でArch LinuxからFirmwareを焼こうとするとエラーになってしまいました。レンタルスペースで焦っていたのもあったのでその場での解決は諦めましたが、帰宅後プルリクを出しmergeされました。

✌️

Install avrdude in Arch or Manjaro Linux by unasuke · Pull Request #6132 · qmk/qmkfirmware https://t.co/qhmxedwFbM

— うなすけ (@yusuke1994) June 16, 2019

CとHを取り違えたので、若干ヒビが入ってしまいました。

fortitude60(ヒビ)

トラブル

右手側が全く反応しません。テスターを買ったので、追い追い時間を見つけて調査と修正、あるいは再度購入をしていこうと思っています。

これから

適当なTai-HaoのキーキャップとBlank keycapsを購入したのですが、キーごとに高さが違う構成なので、PimpMyKeyboardで改めて好みのを買おうと思っています。またTRRS、USBケーブルも味気ないので買おうかなと考えており、沼感が出てきました。

Tweet
2019年06月25日
2019年05月11日

Itamae v1.10.4 をリリースしました

7f9b8f00 6834 11e9 9544 1fd0e8427412

v1.10.3からのdiffはこちらです。

https://github.com/itamae-kitchen/itamae/compare/v1.10.3…v1.10.4

Changelogs

Suppress Ruby warnings

RUBYOPT=-w を指定したときに出る警告を修正するもの。

Run test cases correctly by pocke · Pull Request #289 · itamae-kitchen/itamae

これは v1.10.3 にmergeされている Add integration test with itamae local command で、test filesを列挙する正規表現が誤っていた問題を修正するもの。 これで 0 examples139 examples になりました。よかったですね。

このあたりはpull req authorのpockeさんがブログに書いてくれていますね。メンテナとして気付けなかった僕達のミスでもあります。ありがとうございます。

Itamaeのテストを壊してしまっていた話 - pockestrap

Refine itamae docker‘s created message by pocke · Pull Request #288 · itamae-kitchen/itamae

itamae docker コマンドに --tag オプションを指定した場合、成功したときのmessageにtagも表示するようにしたもの。

Add description to –tag option of docker subcommand by pocke · Pull Request #286 · itamae-kitchen/itamae

itamae docker コマンドのhelp messageに --tag オプションの説明を足したもの。

Tweet
2019年05月11日
2019年04月30日

高専DJ部 #22 でした

CDJ

セトリ

  1. Flying Out (Extended Mix) - M.I.K.E. Push
  2. Black Mirror (Extended Mix) - James Dymond
  3. Kick Back (Original Mix) - Ashley Smith
  4. Fight My Way feat. Moses Keenan (Extended Mix) - Morgan Page, Moses Keenan
  5. With You feat. Emelie Cyreus (Progressive Extended Mix) - Magnificence, Venomenal, Emelie Cyreus
  6. Never Say Never (Extended Mix) - SICK INDIVIDUALS
  7. Turn Back Time (Original Mix) (Original Mix) - 3D Nation
  8. Burn (Original Mix) - DallasK, KSHMR
  9. We Are the Sound (Original Mix) - Betsie Larkin

徐々にテンションが上っていく感じの曲順になるようにやってみましたが、総評としてはパリピでしたね。精進します。

遅刻

イベント自体は3月末にあったので公開がとても遅れてしまいました。

今回、高専DJ部の開催スケジュール的に平成最後の開催となるので、IMAP++とのコラボを持ちかけたらなんと実現してしまいました。 Webサイトもmazcoさんに特別にデザインしてもらったりと、本当に記念となる回にできたかなと思います。

また、 #unasukefmのために購入したZOOM H4n Proで録音したものを内々に共有したりもしました。冒頭のmixcloudはそこから切り出したものになります。

Tweet
2019年04月30日
2019年04月22日

Conference Week in Fukuoka 2019

RubyKaigi 2019

4/15からの1週間、福岡のConference Weekで何をしてきたのかという日記です。

#unasukefm 収録

カンファレンス開始前の15日には、GMOペパボで @udzura さんを相手に #unasukefm の収録を行いました。

Haconiwaについて聴いてる #unasukefm pic.twitter.com/gp67dELrVQ

— カルパス (@yoshi_hirano) 2019年4月15日

最新エピソードを配信しました。RubyKaigi 2019のLocal Organizerである @udzura さんにRubyKaigiの舞台裏、福岡移住の話、Haconiwaについて聴いています。ぜひ聴いて下さい - https://t.co/9JjFL6dOBv #4 - #kaigieffect (@udzura) by Railsdm Podcast #rubykaigi2019https://t.co/kjOtdiYJUO

— Railsdm (@railsdm) 2019年4月22日

ハッシュタグ #unasukefmの様子を見るに、皆さんに楽しんでいただけたようでなによりです。

実はudzuraさんを相手に収録をしたいというのは、Railsdm PodcastがunasukefmとしてSeason 2を開始したときからほとんど決まっていたようなものなのです。達成でき、HaconiwaやCloudNativeの話ができてよかったです。

CloudNative Days Fukuoka 2019

そして1番目のカンファレンス、CloudNative Days Fukuoka 2019に参加しました。

ここではKubernetesだけに留まらない、CloudNativeな技術に関する様々なトークを聞くことができました。特に僕が今課題を感じている点である、秘匿情報の管理についてVaultを使うケースを知れたのはよかったです。

懇親会でも、福岡でしか会えない方々をはじめ、Rubyコミュニティとはまた違うCloudNativeなコミュニティの方々とお話しすることができました。

RubyKaigi 2019

次に、1日挟んで迎えたRubyKaigi 2019です。挟んだとは言ったものの、僕は今回(も)helperとしてお手伝いする立場なので、17日も1日中設営作業をしていました。

https://photos.app.goo.gl/svaNw2jvBtzusJ259 ← 様子を軽くまとめました。

今回はネットワーク斑としてケーブルの敷設、同時通訳レシーバーの受け渡し、スピーカーへの同時通訳打ち合わせ案内などを主に担当しました。英語が咄嗟に出てこない&聞きとれないのがまだまだ課題として感じられる3日間でした。

なるほどね pic.twitter.com/jqoAAe4vng

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) 2019年4月18日

2019年 pic.twitter.com/CCBO4FeLDX

— Yuki AKAMATSU (@ukstudio) 2019年4月21日

今になっても、「ああ、良かったなぁ」というふんわりとした感想しか出てきません。

Tweet
2019年04月22日
2019年03月24日

未読のGitHub notificationを定期的に通知させる

botの様子

participating notification

皆さんは https://github.com/notifications/participating を普段どれだけ見ていますか。僕はこの機能をよく使うのですが、集中していたりすると見に行くのを忘れて、コメントされているのに返事をしそこねてしまったまま長い時間経ってしまうということがしばしばありました。

要件

push型の通知であること

こっちからアクセスしに行かなくても、「未読がこれだけあるよ」と教えてほしいわけです。

即時的でないこと

とはいっても、コメントされて数秒で通知が来る、という即時性は求めていません。なぜなら、例えば社のリポジトリに関することであれば、GitHubのコメントやmergeをSlackに流しているからです。コメントの応酬はそっちで見れます。

https://slack.github.com/

ユースケースとしては、「出社してまず見る」とか、「集中してて気づかなかったけどあのpull reqにコメントついてるっぽい」だとか、そういうのを求めていました。

GitHub notification reminderをつくった

https://github.com/unasuke/github-notification-reminder

これをheroku schedulerで定期的に叩くことによって、このように通知させています。

botの様子

Deploy to herokuボタンを作ったので同様の問題にお困りの方はご活用ください。

困っていること

GitHubのREST API v3でNotificationsを取得するendpointとresponseは以下URLの通りです。

https://developer.github.com/v3/activity/notifications/#list-your-notifications

ここで、通知の対象であるissueやpull requestの情報を見ようとすると、subject.url がそれっぽいなということになります。しかしよく見ると、domainが api.github.com になっています。例としてdocumentに載っている https://api.github.com/repos/octokit/octokit.rb/issues/123 ですが、ここにweb browserからaccessすると、JSONが返ってきます。この中に、html_url として、human accessableなURLが入っています。

これ、しんどくないですか。いわゆるGraphQLが解決しようとした、RESTによるN+1の実例じゃないか!となりました。そしてGraphQL API v4にはまだNotification Objectは来ていないのですね。

この件、supportに投げたのですが、僕の英語力が未熟なのか、「 https://developer.github.com/v3/pulls/#get-a-single-pull-request を使うといいよ」と返事が来ました。そういうことなのでしょう。

ただ、get-a-single-pull-requestしようにも、responseの中にissueやpull requestのnumberが単体では含まれないので、二進も三進も。(このscriptではgsubでhtmlを組み立てています)

こういう書き捨てのscriptのreadmeを頑張ることについて

よしいっちょブログに書くか〜となり、そんならREADME.mdを整備しておかないと「映え」ないなとなって、heroku appならdeploy to herokuボタン欲しいよなといろいろとmeta dataをつくっていて、正直面倒なんです。

じゃあなんで書くかというと、codeにcommentを書くように、あとで見る自分のためなんですね。未来の自分が環境構築するときに困らないように、という目的があるのかなと思いました。

Tweet
2019年03月24日
2019年02月15日

unasuke.fm が始まりました

unasukefm

経緯

一言で表わすと、「ノリと勢い」で始まりました。

音質改善の足しに、とKyashで投げ銭をしたのをきっかけに、あれよあれよと話が進んで、いつのまにかRailsdm podcast Season 2として unasuke.fm をやることになりました。

Railsdm Podcastに投げ銭したい

— うなすけ (@yu_suke1994) 2018年12月24日

2019年からの Railsdm Podcast は、某うなすけさんが聞き手で、毎回ゲストを変えてトークしていくという内容でリニューアルしていく方向です。実質 https://t.co/Yosts9pvuRです。 #railsdm

— カルパス (@yoshi_hirano) 2018年12月24日

Season 2 episode 1

まずepisode 1として、onkさんをゲストに収録を行いました。以下から聞くことができます。

ジングル

KORG Gadget for iOSで作成しました。カルパスさんから頂いたふんわりとしたイメージをもとに作ってみました。

上のはイントロで使ったshort verで、アウトロで使用したlong verは以下です。

機材

そもそも始めたばかりのpodcastでrebuild.fmレベルの環境・質を実現することは現実的ではありません。

Podcasting Guide 2017 – Tatsuhiko Miyagawa’s Blog

それでも、これまでの収録を聴いて「もっとよくできそうなんだけどな」という気持ちになっていたのも確かです。

今回の収録では、僕がそのとき持っていた機材だけで収録を行いました。それらを以下にまとめます。

録音編

録音にあたって、今回は以下の機材を使用しました。

これはさっちんさんに教えていただいたものです。

> https://t.co/pbAOT5yItE

マイクなら絶対これ。tsとかDiscordとかしてても設定ちゃんとすれば周りの音入らない。スピーカーでも全然OK
tsなら音楽流しながらでもボイスチャット出来る。

— 02/09 11:00 🍲 (@sachin21__) 2017年9月21日

購入してから自宅でのボイスチャットに使用していたものをそのまま持ち込んで録音しました。このマイクに関しては、普段の通話で問題になったことがなく(通話相手から何か言われたことがない、という意味)、それなりに安心して収録に臨めました。

収録ではマイクをUni(単一方向のみ集音)にして僕に向けていました。反対側にカルパスさんが居たのですが、カルパスさんの声が入ることがなく綺麗に音声を拾えていました。こちら側の音声についてはそれなりの質で収録できたのではないかなと思っています。

うなすけ君の編集後の音が全体的にかつてないほどクリアなので、クオリティ爆上がりしてる。それとともに今までスマンという気持ちがかなり溢れてる。

— カルパス (@yoshi_hirano) 2019年1月29日

今回onkさんが京都に居るという都合上、Hangout経由で収録しました。そのため、2人が同時に発声しているタイミングだとどちらか(どちらも?)の声が抑えられてしまい、何を話しているのか不明瞭な部分ができてしまいました。これはどうしようもないですね。

また今後ですが、既にある機材の他にもHolyGrailさんの環境を参考に、以下の機材を用意するつもりです。

ここ何ヶ月かかけていろいろ機材を揃えて環境はほぼ整ったので来年のなんらかの活動にご期待ください! pic.twitter.com/HzVtiqKrsk

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) 2018年12月22日

機材に関してはキリがないので、あまり凝りすぎてもよくないでしょう。上記構成からさらに買い足していったり、上位機種への乗り換えなどはするつもりはありません。たぶんしないと思う。しないんじゃないかな。

自分はVTuberになるために機材に10万弱かけてきたがうなすけくんははたしてどうかな

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) 2019年1月11日

機材構成に関しては、他のpodcastでの事例が探すと色々出てくるので、それらを参考にしてみるのもいいかもしれません。

podcastの運営に参加することになった結果、沼にはまっていっているように見えるかもしれませんが、オーディオインターフェースは既に所持していましたし、追加で欲しくなったのはPCMレコーダーくらいなものなので沼ではないです。

4月にどういう機材を手元に揃えているのかは誰にもわかりません。

ちょうど先日「Jonanは配信機材をRubyKaigiに持ち込んでいて現地から配信していた。ポッドキャストであれば映像も不要だしオーディオインターフェースとマイクだけで収録が可能なので実質ありとあらゆる場所で収録ができるようになるのでは?」という話をしたところなので期待ができそうですね。

— HolyGrail / 蜘蛛糸まな🕸️@新人VTuber (@HolyGrail) 2019年1月11日

編集編

録音した音声の編集は以下のような環境で行っています。

編集環境に関してはこれ以上のupdateはするつもりはありませんし、してもあまり意味がないかなと思っています。

ただ、マスタリングにあたって、低音域と高音域を削るイコライザーはかませましたが、ノイズ軽減などは今回はしていません。それについては改善の余地があると思います。

今後

今後お話ししてみたい方々をカルパスさんと話して十数人ほどリストアップしています。1年くらいは続くと思います。

#unasukefm の次回の配信は、来週 or 再来週の前半を予定しています。

— Railsdm (@railsdm) 2019年2月15日
Tweet
2019年02月15日
2019年01月30日

[WIP]kibela2esa をつくりました

kibela esa migration params

HolyGrail/kibela2esa: Kibela 2 esa.io

りゆう

やっぱりWIPっていいですよね。

どういうことをしているのか

  1. exportされたmarkdownを読みこむ
  2. exportされた画像を読みこむ(pathと名前だけ持っておく)
  3. 画像をesaにアップロードして、S3のURLを持っておく
  4. markdown内の画像URLをesaのS3 URLに置換する
  5. frontmatterなどの処理や整形した結果のmarkdownをesaに投稿する

できること

(まだ)できないこと

たいへんだったこと

まとめ

esaが好きです。

HolyGrail/kibela2esa: Kibela 2 esa.io

Tweet
2019年01月30日
2018年12月24日

OCI Image Format Specification v1.0.1を読んで

skopeo

まえおき

発端

めちゃくちゃ興味あり〼 https://t.co/gHfAV5rbEU

— うなすけ (@yu_suke1994) 2018年11月30日

頭の中には設計があるんですが、…
OCIの仕様を再確認するところから…

— Uchio KONDO 🔫 (@udzura) 2018年11月30日

とりあえずブログかキータ

— Uchio KONDO 🔫 (@udzura) 2018年11月30日

という訳で、書きました。

OCI Image とは

Open Container Initiativeによって定められた、コンテナイメージフォーマットの標準仕様です。

詳しくは Open Container Initiativeによるコンテナランタイムとコンテナイメージの最初の標準化作業が完了、「OCI v1.0」発表 - Publickey にて。

OCI Imageを触ってみる

現在、OCI ImageをdownloadできるDocker HubのようなWebサイトは知る限りありません。なので、自分でOCI Imageを作成する必要があります。

まずはDocker Imageから

まず、Docker Hubにて公開されているDocker imageをdownloadするところからです。以下のコマンドで、Docker Hubからダウンロードしたimageをtarballとして扱うことができるようになります。

$ docker image pull ruby:2.5.3-slim-stretch
$ docker save ruby:2.5.3-slim-stretch --output ruby_253_slim_stretch.tar

このtarを展開してみましょう。

$ tar -xf ruby_253_slim_stretch

すると、manifest.json というファイルができているので、見てみます。

[
  {
    "Config":"b1c1603e80c648f3ab902b0259ab846a7779d0780124bf9e417dd4b8c3cea296.json",
    "RepoTags":[
      "ruby:2.5.3-slim-stretch"
    ],
    "Layers":[
      "aeff88bcdbbd12ea45c023c45f97b870492092899651c811b2ef26ae7fdf3120/layer.tar",
      "c61a4dce9ddcebd63027d09811998052c9b2cdb3a379c297277cf755dfcf1420/layer.tar",
      "de2944e57fc93c2f354420cb36210fd1181687a990ffd7123600fdaecba3ee83/layer.tar",
      "49c3631e8651776127d66adb995e78af1e2cfc52b7a10a20df0d92d837258419/layer.tar",
      "eb50b8a8210f1b43ff1571598e66b694844b2dcf6fbaa0691e8af6b7c80dcaa7/layer.tar"
    ]
  }
]

なるほど、これはOCI image specを読むとわかるのですが、OCIに定められている形式のJSONではありませんね。

skopeo

ここで、containers/skopeo というtoolを使用して、Docker imageをOCI imageに変換してみます。

$ skopeo copy docker://ruby:2.5.3-slim-stretch oci:ruby-oci:latest

すると、 ruby-oci/index.json というファイルができているので、見てみます。

{
  "schemaVersion":2,
  "manifests":[
    {
      "mediaType":"application/vnd.oci.image.manifest.v1+json",
      "digest":"sha256:a3843587af4f3e838f3e1a10649631144d4dcf4391980b64f3b902d81048057c",
      "size":976,
      "annotations":{
        "org.opencontainers.image.ref.name":"latest"
      },
      "platform":{
        "architecture":"amd64",
        "os":"linux"
      }
    }
  ]
}

なるほど、これは OCI Image Specに定められている image manifest fileですね。

以下、OCI Image Format Specification v1.0.1

自分なりに理解しようと翻訳したもののメモになります。 正確性の保証はないです。誤訳とかあります。最後のほう力尽きてます。


Open Container Initiative Image Format Specification v1.0.1

Overviewで語られていること

high level image manifest にはcontentsとdependencies of the image including the content-addressable(連想?) identity of one of more file system layer changeset archives、展開すると最終的に実行可能なファイルシステムになる

image configuration にはapplication arguments, environmentsなどの情報

image indexには high level manifest list of manifests and discriptorsのpointが含まれる

それらのmanifestsは異なるimageの実装 ←プラットフォームや他の属性によって変化することができる

Build diagram

一度作成されたOCI imageは名前によって探索(discovered)、ダウンロード、hashによる検証、署名による信頼、OCI Runtime Bundleへの展開ができる

(No Title)

Understanding the specification

components of the specは以下を含む

optional featureとしてSignaturesやNamingが仕様に含まれるかもしれない。

OCI Image Media Types

HTTP responseのContent-Typeで上の値を返すなどのように、typeを返すなにかしらの方法を実装してもよい(MAY)、また実装はmedia typeとdigestを期待してよい? 実装は返却されたmedia typeを尊重する必要がある(SHOULD)

Compatibility Matrix

前方・後方互換を可能な限り維持する必要がある。

似た、または関連するmedia typeは以下

Relations

Image indexは複数のImage manifestを持つ。Image manifestとImage JSON(config)は1対1。Image manifestはLayerのtar archiveを複数持つ。 Discriptorは全ての参照を持つ。

OCI Content Discriptors

properties

Digests

こういう形式

sha256とsha512がRegistered algorithmsとされている。sha256はMUSTでsha512はMAY。

Example

{
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "size": 7682,
  "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
  "urls": ["https://example.com/example-manifest" ]
}

OCI Image Layout Specification

OCI Image LayoutはOCI content-addressable blobs と location-addressable references のための directory構造を表す(?) Layoutではtarやzipなどのarchive formats、nfsなどの共有ファイルシステム、http、ftp、rsyncなどのネットワークによるファイル取得を使用してもよい。

あるimage layoutと参照は、manifestと指定された順序で適用されるfilesystem layerとOCI runtime specificationのconfig.jsonへ変換できるimage configurationがあればOCI Runtime Specification bundleを何らかのtoolによって作成できる。(?)

Content

Example

$ cd example.com/app/
$ find . -type f
./index.json
./oci-layout
./blobs/sha256/3588d02542238316759cbf24502f4344ffcc8a60c803870022f335d1390c13b4
./blobs/sha256/4b0bc1c4050b03c95ef2a8e36e25feac42fd31283e8c30b3ee5df6b043155d3c
./blobs/sha256/7968321274dc6b6171697c33df7815310468e694ac5be0ec03ff053bb135e768

$ shasum -a 256 ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51
afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51

Blobs

Example

$ cat ./blobs/sha256/9b97579de92b1c195b85bb42a11011378ee549b02d7fe9c17bf2a6b35d5cb079 | jq
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
...
$ cat ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 | jq
{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 7023,
    "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 32654,
      "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0"
    },
...
$ cat ./blobs/sha256/5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270 | jq
{
  "architecture": "amd64",
  "author": "Alyssa P. Hacker <alyspdev@example.com>",
  "config": {
    "Hostname": "8dfe43d80430",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": null,
    "Image": "sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b",
...
$ cat ./blobs/sha256/9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0
[gzipped tar stream]

oci-layout file

これ。

{
    "imageLayoutVersion": "1.0.0"
}

index.json

必須。image-layoutの参照、descriptorsのentry pointになる。/index.json に置かれる。 "org.opencontainers.image.ref.name" にイメージのtagが格納される?

{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.index.v1+json",
      "size": 7143,
      "digest": "sha256:0228f90e926ba6b96e4f39cf294b2586d38fbb5a1e385c05cd1ee40ea54fe7fd",
      "annotations": {
        "org.opencontainers.image.ref.name": "stable-release"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      },
      "annotations": {
        "org.opencontainers.image.ref.name": "v1.0"
      }
    },
    {
      "mediaType": "application/xml",
      "size": 7143,
      "digest": "sha256:b3d63d132d21c3ff4c35a061adf23cf43da8ae054247e32faa95494d904a007e",
      "annotations": {
        "org.freedesktop.specifications.metainfo.version": "1.0",
        "org.freedesktop.specifications.metainfo.type": "AppStream"
      }
    }
  ],
  "annotations": {
    "com.example.index.revision": "r124356"
  }
}

OCI Image Manifest Specification

imageと、そのコンポーネントのために生成された一意なIDからハッシュ可能なimageのconfigurationimage modelをサポートした参照可能なimageを作成すること、platform固有のmanifestを含んだ"fat manifest"による複数architecture対応のimageの実現、OCI Runtime Specificationへの変換の3つを目標にしている。

Image Manifest

image indexはarchitectureやOSごとに展開可能なそれぞれのimageの情報を持つが、image manifestは特定のarchitecture、OSに対する単一のcontainer imageにおけるconfigurationとlayerの集合を提供する。

Image Manifest Property Descriptions

Example

{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 7023,
    "digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 32654,
      "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 16724,
      "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 73109,
      "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
    }
  ],
    "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}

OCI Image Index Specification

Image Index Property Descriptions

Example

{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7682,
      "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      }
    }
  ],
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}

Image Layer Filesystem Changeset

change types

file types

File attributes

hardlinks

Platform-specific attributes

Createing

rootfs-c9d-v1/
    etc/
        my-app-config
    bin/
        my-app-binary
        my-app-tools

色々とfilesystemについての解説が続く

Non-Distributable Layers

OCI Image Configuration

用語

properties

Example

{
    "created": "2015-10-31T22:22:56.015925234Z",
    "author": "Alyssa P. Hacker <alyspdev@example.com>",
    "architecture": "amd64",
    "os": "linux",
    "config": {
        "User": "alice",
        "ExposedPorts": {
            "8080/tcp": {}
        },
        "Env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "FOO=oci_is_a",
            "BAR=well_written_spec"
        ],
        "Entrypoint": [
            "/bin/my-app-binary"
        ],
        "Cmd": [
            "--foreground",
            "--config",
            "/etc/my-app.d/default.cfg"
        ],
        "Volumes": {
            "/var/job-result-data": {},
            "/var/log/my-app-logs": {}
        },
        "WorkingDir": "/home/alice",
        "Labels": {
            "com.example.project.git.url": "https://example.com/project.git",
            "com.example.project.git.commit": "45a939b2999782a3f005621a8d0f29aa387e1d6b"
        }
    },
    "rootfs": {
      "diff_ids": [
        "sha256:c6f988f4874bb0add23a778f753c65efe992244e148a1d2ec2a8b664fb66bbd1",
        "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
      ],
      "type": "layers"
    },
    "history": [
      {
        "created": "2015-10-31T22:22:54.690851953Z",
        "created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"
      },
      {
        "created": "2015-10-31T22:22:55.613815829Z",
        "created_by": "/bin/sh -c #(nop) CMD [\"sh\"]",
        "empty_layer": true
      }
    ]
}

Annotations

Rules

Pre-Defined Annotation Keys

Back-compatibility with Label Schema

org.opencontainers.image org.label-schema Compatibility notes
created build-date Compatible
url url Compatible
source vcs-url Compatible
version version Compatible
revision vcs-ref Compatible
vendor vendor Compatible
title name Compatible
description description Compatible
documentation usage URLの場合にはCompatible
authors Label Schemaにはない要素
licenses Label Schemaにはない要素
ref.name Label Schemaにはない要素
schema-version OCI Image Specにはない要素
docker.*, rkt.* OCI Image Specにはない要素

Conversion to OCI Runtime Configuration

Verbatim Fields

annotation fields

Parsed Fields

Optional Fields

Annotations

Considerations

Extensibility

Canonicalization

JSON

Extended Backus-Naur Form

Tweet
2018年12月24日
2018年11月30日

Railsのテストを実行する環境をdockerで構築したが使いみちがない

docker-compose ps ※ Rails アプリのテストではなく、Rails本体のテストについての話です。

僕がそうだったように、皆さんにもふと「Rails本体のテストを実行してみたいな〜」と思うことがあるでしょう。

ところが、Rails本体のテストというのは大変です。ActiveRecordひとつ取ってみても、網羅するためにはMySQL、PostgreSQL、MariaDB、SQLiteの4つのRDBを用意しなければいけません。

もちろん、公式でそのような環境を構築するためのものは用意されています。

https://github.com/rails/rails-dev-box

rails-dev-boxを使うと、Vagrantを用いて、Rails本体の開発環境を構築できます。(yahondaさんありがとうございます)

ですが、Dockerが仮想環境の主流となっている今、VagrantでなくDockerを使いたい、そう思うのもおかしくはないでしょう。ないですよね?

なので、docker-compose を使用して、Railsのテストを実行する環境を構築してみました。以下、それに伴って行なったことの解説になります。

Dockerfile

FROM ruby:2.5.3-stretch

WORKDIR /rails
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \
  && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt update && apt install --assume-yes \
    ffmpeg \
    sqlite3 \
    imagemagick \
    mupdf \
    mupdf-tools \
    poppler-utils \
    libmariadbclient-dev \
    libsqlite3-dev \
    postgresql-contrib \
    libpq-dev \
    libxml2 \
    libxml2-dev \
    libxslt1-dev \
    libncurses5-dev \
    mysql-client \
    git \
    make \
    nodejs \
    yarn \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

COPY . .
RUN bundle install --jobs=4
RUN npm install
RUN cd actionview && npm install

FROM から WORKDIR の指定までは飛ばして、aptによるパッケージのインストールを見てみます。 ここで指定しているパッケージ郡ですが、 https://github.com/rails/rails-dev-box/blob/master/bootstrap.sh を参考にしました。

続く COPY . . で、 rails/rails のファイルを一気にimageに追加しています。いわゆるDocker image buildのお作法としては、Gemfile、Gemfile.lock 、package.json などのファイルをCOPYして、bundle installなりnpm installなりを行ってからアプリケーションのコードをCOPYしてくるのが一般的です。しかしRailsのしかも開発環境では、Rails gem自体がActiveRecordやActiveModelなどの複数のgemに依存しており、それらがmonorepo構成で rails/rails に含まれているため、このようにしないと bundle installが実行できません。

あとは bundle installとnpm installを実行しているだけです。

docker-compose.yml

version: '3'
services:
  rails:
    build: .
    command: /bin/bash
    environment:
      - MYSQL_HOST=mariadb
      - PGHOST=postgres
      - PGUSER=postgres
      - REDIS_URL=redis://redis:6379
      - MEMCACHE_SERVERS=memcached
    tty: true
    volumes:
      - ".:/rails"
    links:
      - mysql
      # - mariadb
      - postgres
      - redis
      - memcached
      - rabbitmq
  mysql:
    image: mysql:5.7
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
  postgres:
    image: postgres:11.1-alpine
  mariadb:
    image: mariadb:10.4.0-bionic
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
  redis:
    image: redis:5.0.1-alpine
  memcached:
    image: memcached:1.5.12-alpine
  rabbitmq:
    image: rabbitmq:3.7.8-alpine

Rails本体のテストを行うにあたり、必要な関連サービスはMySQL PostgreSQL MariaDB Redis Memcached RabbitMQ の6つになります。SQLiteについてはrails service内に含まれています。

testの実行

`$ docker-compose up -d rails でrails serviceが立ち上がります。そしたら、

$ docker-compose exec rails bash

でcontainerに入り、testを実行します。

とはいえ、test suiteはTravis CIで実行されることに最適化されているため、以下のようなpatchを当てる必要がありました。

testそのものは、travis.ymlを参考に、このように実行します。

$ GEM=am,amo,as,av,aj,ast ci/travis.rb

このコマンドでは、ActionMailer、ActiveModel、ActiveSupport、ActionView、ActiveJob、ActiveStorageのtestを実行します。

例えばActiveRecordの、SQLite3でのテストの実行結果は以下のようになりました。

root:/rails# time GEM=ar:sqlite3 ci/travis.rb

[Travis CI] activerecord with sqlite3
Running command: bundle exec rake sqlite3:test

...snip...

Rails build finished successfully

real    63m17.484s
user    12m22.931s
sys     6m50.865s
root@ebdba3a4da12:/rails#

あきらめたやつ

multi stage buildによる Node.js ランタイムの構築

tootsuite/mastodon などで採用されているテクニックですが、multi stage buildを用いてNode.js、npm、yarnのバイナリを main imageに追加することにより、パッケージマネージャやバイナリの直接ダウンロードと比較して高速に別言語のランタイムを構築することができます。今回もmsatodonと同様にNode.js、npm、yarn を COPY --from node で持ってこようとしたのですが、 cannot find module'../lib/utils/unsupported.js' というエラーが発生し、解決策として出てくるのがNode.jsのサイインストールばかりだったので、aptからインストールすることにしました

で、これどうするのか

どうすればいいんでしょうね。

他の皆さんはどうしているのか

気になったのでTwitterで聞いてみたところ、Travis, VPS, localなどがあるようですね。確かにlocalhostに直にインストールしてしまうのが一番楽だと思いました。

皆さんRailsのテストってどうやってますかね。あ、RailsアプリのテストではなくRails本体のテストのことです。

— うなすけ (@yu_suke1994) 2018年11月21日

VPS借りてUbuntu 18.04入れて回してます。期待する答えじゃないかもしれませんが、何か困ってますかね。

— Yasuo Honda (@yahonda) 2018年11月21日

homebrewある環境だったらMySQLとPostgreSQL bottleで入れてActiveRecordのtestに必要なdatabaseやuser作るのは1分ぐらいあればできるので僕はローカルにインストールしてますね。

— Ryuta Kamizono (@kamipo) 2018年11月21日

すごい手抜きなやり方だとRailsをforkした自分のリポジトリに対してtravis設定して雑にpushしながらテストするとかですかね?

— sue445 (@sue445) 2018年11月21日
Tweet
2018年11月30日
古い投稿