PSequelとTeamSQLがお亡くなりなので、おれはTablePlusを使うことにするぜ
IntelliJ IDEA Database Tool
ここ一年くらいは IntelliJ 組み込みのデータベースクライアントでことを済まして来ました。対応するデータベースプロダクトも多いですし、専用のクライアントツールに引けを取らない機能は素晴らしいです。
その一方で、兼ねてより以下のような不満がありました。
- データベースへの接続情報等をプロジェクトごとに持ってしまうので、複数プロジェクトにまたがる際に扱いづらい。
- そう思って接続情報を保存するためだけのプロジェクトを作ってみたものの、ウィンドウが増えてくると Cmd + Tab の切り替えが面倒。
- だからと言って All Product Pack や DataGrid 単体で買うのはコスパが悪い気がする。
TeamSQL
そう思って最初に検討したのが TeamSQL です。せっかくならモダンな UI で新しいプロダクトに乗り換えたいと思ったからです。
意気揚々とアプリケーションのダウンロードのためにオフィシャルサイトを訪れた所、目に飛び込んできたのはメンテ終了のお知らせでした・・・。
TeamSQL has retired and is not available for download anymore.
PSequel
そう思って次に検討したのが PSequel です。IDEA 以前に使っていたツールになるので出戻りになります。PosgreSQL 専用のツールにはなりますし、決してモダンなツールではないものの、慣れた機能が使えれば十分かと思った次第です。
しかし、こんなブログ記事が。👀
ほんまかいな、と思ってさらに探ってみたところ、メンテ状況に関して言及するコメントのついた Issue がいくつも放置されていることがわかりました。
ああ、これはもう実質終了してますね・・。
もともとオープンソースでないプロダクトなので、作者の方が動いてくれない限りどうしようもないようです。
※とはいえ、無償でこういったプロダクトを提供し続けて頂いたことには感謝の気持ちしかないですね・・!
TablePlus
というわけで最終的に落ち着いたのが TablePlus です。
正直はじめはピンと来ていなかったのですが、一般に提供される機能は揃っていますし、UI もモダンで更新状況も活発なので素晴らしいです。
ライセンス料金ですが 1台分が 1年間の更新付きで 59$ です。フリートライアルもありますし、1ヶ月あたりに換算すれば 5$程度なので、満足して購入する分にはぜんぜん払える額ですね!
補足
その他調べた中で得た知見として、2点補足します。
まず、DB クライアント GUI アプリを選ぶポイントとしては以下の6点です。
- サポートするプラットフォーム:Windows ? MacOS ? Linux ? (or mobile ?)
- サポートするDB:MySQL ? PostgreSQL ? SQLServer ? NoSQL ?
- UI のモダンさ:気にならなければ大丈夫ですが古いアプリも多いので。
- メンテ状況:アプリ自体は多いのですがその分停止してるものも多い印象でした。
- 有償・無償:IDE などと違って有償でも高価なものは少ないです。
- クライアント機能:スキーマのブラウズ機能やフィルタ機能といった一般的なものだけでなく、リードオンリーモードや ER 図のエクスポート機能など、どうしても欲しい特定の機能がある場合は要チェックです。
あと、私は一旦 TablePlus に落ち着きましたが DBeaver もかなり良さげでした。あまり触れていないので言及こそしませんでしたが、TablePlus よりサポートする DB が多いですし、無償で提供されているので使いやすいです。
qiita.comあと、ER 図のエクスポート機能もありますね。TablePlus でサポートされていない DB を今後扱うことになったり、サポートされていない機能が使いたくなることも出てくると思うので、二つを併用していけば良いかと考えてます。
ghq list の vcs オプションとその有効な使い方
先日 ghq の v0.11.1 がリリースされました! このバージョンより ghq list コマンドに --vcs オプションが追加されています。🎉
$ ghq list --help NAME: list - List local repositories USAGE: ghq list [-p] [-e] [<query>] (省略) OPTIONS: --exact, -e Perform an exact match --vcs value Specify VCS backend for matching --full-path, -p Print full paths --unique Print unique subpaths
この機能は私が1年ほど前に提案したもので、最近になって開発者の方からフィードバックを頂いたことを受けて、PR を作成して master に取り込んで頂いたという流れになります。💪
Feature request: specify vcs argument on `ghq list` · Issue #94 · motemen/ghq · GitHub
例えば --vcs git
といったように指定すると、Git の作業ディレクトリのみをリストアップすることができます。あなたが過去に SubVersion や Mercurial のプロジェクトを ghq get
したことがあっても、その実行結果には含まれません。
vcs オプションの value として使用可能なキーワードは、README のこの辺りやソースコードのこの辺りを見ればいいんじゃないかと思います。
Accepted values are "git", "github" (an alias for "git"), "subversion", "svn" (an alias for "subversion"), "git-svn", "mercurial", "hg" (an alias for "mercurial"), and "darcs".
GitHub - motemen/ghq: Remote repository management made easy
var vcsRegistry = map[string]*VCSBackend{ "git": GitBackend, "github": GitBackend, "svn": SubversionBackend, "subversion": SubversionBackend, "git-svn": GitsvnBackend, "hg": MercurialBackend, "mercurial": MercurialBackend, "darcs": DarcsBackend, "fossil": FossilBackend, "bzr": BazaarBackend, "bazaar": BazaarBackend, }
ghq/vcs.go at v0.11.1 · motemen/ghq · GitHub
私はこの機能を使って、ローカルの全 Git リポジトリに対して git gc
をかけてます。
この処理はワンライナーでこう書けます。
ghq list --full-path --vcs=git | xargs -I{} sh -c 'echo {}; git -C {} gc --aggressive'
これを cron に仕込むなどして日次実行するようにしておけば、ヒストリーの長いプロジェクトだったりブランチを多数抱えていても、最適化がかかってディスクサイズが減らせますし、Git 実行時に不定期で始まる GC もオフにできます。😎
※ 私はこういった意図しない処理が走って時間がかかる(Homebrew の自動アップデートとか)のが苦手なので、どちらかと言えば後者の目的でやってますね!
git config gc.auto 0
read コマンドはバックスラッシュをそのまま変数にセットしないので注意が必要
とある非業務なシェルスクリプトの編集中に、ShellCheck が見慣れないエラーを吐いていることに気づいた。🤔
help コマンドで -r オプションの意味を調べてみる。
read は bash のビルトインコマンドなので、man ではなく help を使うのが正しい。
$ help read read: read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] ...(省略) If the -r option is given, this signifies `raw' input, and backslash escaping is disabled. ...(省略)
この説明だけだともう一つピンと来ないので、さらにググって調べてみる。
※-rオプションを指定しなかった場合、入力の末尾にあるバックスラッシュは行の継続と見なされる。バックスラッシュを入力するにはそれ自体をバックスラッシュでエスケープする必要がある。
readコマンドについてメモ | OpenGroove
どうやら read コマンドはバックスラッシュをメタキャラクタの一つとして扱っていて、特に末尾に置かれる場合には行継続として扱われる仕様とのこと。確かにバックスラッシュを標準入力として与えてみても、セットされる文字列にはバックスラッシュとして含まれない。
# バックスラッシュが先頭にあるケース(無視される) $ read test \foobar $ echo $test foobar # バックスラッシュが途中にあるケース(無視される) $ read test foo\bar $ echo $test foobar # バックスラッシュが末尾にあるケース(行継続される) $ read test foobar\ > baz $ echo $test foobarbaz # バックスラッシュが2文字連続するケース(エスケープされる) $ read test foo\\bar $ echo $test foo\bar
そこで r オプションを与えると、バックスラッシュもセットされる文字列に含まれるようになる。
$ read -r test \foobar $ echo $test \foobar $ read -r test foo\bar $ echo $test foo\bar $ read -r test foobar\ $ echo $test foobar\
今回 ShellCheck で引っかかったのは、シェルスクリプト中でパスワードの入力を求める箇所だった。ここに関してはバックスラッシュを入力として与えたときこれがセットされないのは不適切なので、r オプションをつけるように修正した(つまり ShellCheck は今回も神でした)👍
SQLite3 のオンラインバックアップ
どのような点で優れているか?
SQLite ロック機構に則ってデータベースの複製が行われるので、オンラインのデータベースに対して安全に処理を実行できる。 例えば、単にバックアップを取るだけならファイルコピーでも可能だが、もしデータベースが書き込み中であった場合、バックアップは壊れている恐れがある。 ちなみに、オンラインバックアップの対象はデータベース単位である。 特定のテーブルのみ取り出したいといった場合は、ユースケースに合わないので愚直に ATTACH と INSERT クエリでコピーすべし。
実施手順
オンラインバックアップの実施は非常に簡単で、sqlite3 コマンドで .backup というメタコマンドを実行する。
以下に実行例を示す。 ここでは、sample.db という SQLite データベースのバックアップを sample.db.backup として取っている。 ちなみに、sample.db.backup というファイルが既に存在する場合、上書きされてしまうので注意。
$ sqlite3 sample.db "SELECT * FROM members;" 1|Smith 2|Alisa $ sqlite3 sample.db ".backup sample.db.backup" $ sqlite3 sample.db.backup "SELECT * FROM members;" 1|Smith 2|Alisa
また、バックアップ元およびバックアップ先としてカレントディレクトリ以外を指定したい場合には、 絶対パスもしくは相対パスを用いて指定すればよい。
$ sqlite3 sample.db ".backup /var/tmp/sample.db.backup" $ sqlite3 sample.db.backup "SELECT * FROM members;" 1|Smith 2|Alisa
ちなみに、アタッチしているデータベースのバックアップを取りたい場合は、 コマンドの第1引数に、バックアップを取りたいデータベース名を指定する。
$ sqlite3 sqlite> ATTACH DATABASE "sample.db" as sample; sqlite> .backup sample sample.db.backup sqlite> .quit $ sqlite3 sample.db.backup "SELECT * FROM members;" 1|Smith 2|Alisa
インメモリデータベースの書き出し
オンラインバックアック機能を使えば、インメモリデータベースの書き出すことが可能である。
$ sqlite3 SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> CREATE TABLE members (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT); sqlite> INSERT INTO members (name) VALUES ('Smith'); sqlite> INSERT INTO members (name) VALUES ('Alisa'); sqlite> SELECT * FROM members; 1|Smith 2|Alisa sqlite> .backup sample.db sqlite> .quit $ sqlite3 sample.db SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> SELECT * FROM members; 1|Smith 2|Alisa
インメモリデータベースへの読み込み
.backup コマンドと逆の操作を実施する .restore コマンドがある。 これを利用すれば、ファイルに書き出したデータベースをインメモリデータベースとして読み込むことが可能である。 ちなみに、この操作を実施した時点で既にインメモリ上にデータベースが開かれていた場合、 そのデータベースは上書きされて消えてしまうので非常に注意。
$ sqlite3 SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .restore sample.db sqlite> SELECT * FROM members; 1|Smith 2|Alisa
ライブラリによるサポート
オンラインバックアップは、C ライブラリから利用することも可能である。 詳細は割愛するが、C ライブラリではより細かくバックアップ挙動を指定することが可能である。 ちなみに、Python の sqlite3 モジュールは未対応。
参考
Web 上で公開されているシェルスクリプトをローカルで直接実行したい
Gist 上で自分で公開しているシェルスクリプトを直接実行したかった。
パターン1: 単に実行したい
curl -sSL {URL} | sh
curl でシェルスクリプトを取得しつつ、パイプ経由で sh に流している。もっとも簡単かつポピュラーなパターンだと思う。
curl のフラグ指定は -sSL
としていて、今回のユースケースにおいて最も汎用性の高い指定を選んでいるつもり。
フラグ | 機能 |
---|---|
-sS |
出力を抑える。ただしエラーの時は出力を出す。 |
-L |
HTTP リダイレクトに従う。 |
パターン2: オプションをつけて実行したい
実は、パターン1 の方法ではオプションを渡した実行ができない。 なのでシェルスクリプトがオプションを取らない場合は良いが、シェルスクリプトがオプションを取る場合は使えない。 対処法としては、sh に第1引数に /dev/stdin を指定すれば良い。*1
curl -sSL {URL} | sh /dev/stdin foo bar
補足: Gist 上のシェルスクリプトの実行
Gist 上にアップロードしたシェルスクリプトを実行するには、シェルスクリプトを raw で得る必要がある。 Gist の UI 上で Raw ボタンを押すと、こういった URL に飛ぶ。
https://gist.githubusercontent.com/msh5/ad8c7e0af6134c0ec5c1d918a4544188/raw/077c817418717406779fa8aad992eda83e1bc4b7/mk-apache20-license.sh // 省略版 https://gist.githubusercontent.com/{ユーザ名}/{ハッシュ A}/raw/{ハッシュ B}/{ファイル名}
注意したいのは、ハッシュ B の方は Commit ハッシュなので、この URL では最新の変更に追従できないこと。 例えば Gist 上で変更を行っても、変更が反映されていない元のファイルにアクセスしてしまう。 これが意図する動作であればそれに越したことはないが、多くの場合は最新のシェルスクリプトにアクセスしたいのではなかろうか。 実はハッシュ B の部分を消してしまえば、最新の変更に追従できるようにできる。
// 最新の変更に追従してくれる URL https://gist.githubusercontent.com/{ユーザ名}/{ハッシュ A}/raw/{ファイル名}
補足: この方法の危険性
「悪意のある人によって公開されているものは危ないよね」という話と、 「ネットワークが不安定で中途半端なスクリプトが実行されてしまうと意図しない挙動になるよね」という話。 アドホック性の高い分こういう危険性もあるので、安全なところに置いてあるスクリプトにだけ使ってくれたまへ。
*1:sh はオプション指定が何もないときは空気を読んで /dev/stdin から読んでくれるが、 オプション指定があるとそれが機能しないため、シェルスクリプトの実行さえままならなくなるようだ。
はじめての Haskell
Haskell をちょくちょく触ってみていて、メモが溜まってきたのでこれをまとめた。
(2018-07-19)「Haskell の学び」を変更・追記した。
Haskell とは?
- 関数型言語
- 「ハスケル・カリー」さんから名前をとっている(だけど開発者は全く別)
- 最新の言語仕様は Haskell 2010
- モナドで有名だけど圏論の知識は必須というわけではない(らしい)
Haskell の学び
チュートリアルのオススメはこの二つ。
- How to write a Haskell program - HaskellWiki
- 短くてシンプル。
- Learn You a Haskell for Great Good!
- 一つ目と比べると詳しめ。
- 図解入りで楽しい。
モナドの説明など概念的な説明は日本語の方が嬉しいと思うが、それにはここがわかりやすい。 基本的に「日本語でおk」な説明のサイトが多いので、読んでいて意味不明だったらすぐに違うソースを探した方がいい。
入門書籍はいまのところ使っていないが、この辺りがテッパンらしい。 ちなみに、2番目の「すごいHaskellたのしく学ぼう!」は上で紹介した「Learn You a Haskell for Great Good!」の邦訳版である。 個人的に3番目を読んでみたいのだが、電子書籍版がないため躊躇している。
- 作者: Graham Hutton,山本和彦
- 出版社/メーカー: オーム社
- 発売日: 2009/11/11
- メディア: 単行本(ソフトカバー)
- 購入: 14人 クリック: 503回
- この商品を含むブログ (117件) を見る
- 作者: Miran Lipovača,田中英行,村主崇行
- 出版社/メーカー: オーム社
- 発売日: 2012/05/23
- メディア: 単行本(ソフトカバー)
- 購入: 25人 クリック: 580回
- この商品を含むブログ (73件) を見る
ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門
- 作者: 青木峰郎,山下伸夫
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/10/05
- メディア: オンデマンド (ペーパーバック)
- この商品を含むブログを見る
インストール
macOS 環境なら Haskell Platform の利用が推奨されている。 Haskell Platform には以下のツールが入っていて、これをインストールするだけですぐに Haskelll 開発が始められる。
- GHC(コンパイラ)
- Cabal(パッケージ管理)
- Stack(ビルド自動化)
- プロファイリング、カバレッジ測定ツール
- 35 のコアパッケージとその他メジャーなもの
Haskell Platform は Homebrew-Cask 経由で簡単にインストールできる。
brew cask install haskell-platform
エコシステム
エコシステム | 概要 | 他の言語での対応 |
---|---|---|
GHC | デファクトスタンダートなコンパイラ実装。 | gcc (C) |
Hackage | パッケージリポジトリ。 | PyPI (Python) |
Cabal | パッケージ管理ツール。基本的には Hacakge から取ってくる。 | pip (Python), npm (Node.js) |
Stackage | Stable Hackage の略。依存関係でエラーがでないように調整されたパッケージセットのこと。 | 該当なし(他の言語ではパッケージ開発者が決めている) |
Stack | ビルド管理ツール。 | Gradle (Java), Bundler (Ruby) |
HLint | コードスタイルチェックツール。 | pylint (Python) |
Hoogle | リファレンス検索サービス。記号類も検索しやすい。 | 該当なし |
開発エディタ
Language Server 実装の一つで VSCode などで使える。 VSCode の Market Place で検索すれば Haskell Syntax Highlighting に次いで一番上に出てくるので、普通に見れば間違えることはないかと。 Language Server 実装はいくつかあるものの、これが一番実用レベルでよろしい。(参考)
IntelliJ の Haskell サポート用プラグインがある。
IDEA でインストールできることを確認している。
gcovr を動かしてみる
インストール
gcovr は Python で実装されていて、PyPI で配布されている。
# pip install gcovr
実行手順
- カバレッジ測定を行うプログラムのソースを
-fprofile-arcs -ftest-coverage
と-lgcov
パラメータをつけて gcc コンパイルする .gcda
,.gcno
ファイルが生成されていることを確認する- 1 でコンパイルして出来たプログラムを実行して、
.gcda
ファイルが更新されることを確認する - 結果を出力する
# gcovr -r . ------------------------------------------------------------------------------ GCC Code Coverage Report Directory: . ------------------------------------------------------------------------------ File Lines Exec Cover Missing ------------------------------------------------------------------------------ hoge.c 42 36 85% 51,55,102-103,107-108 ------------------------------------------------------------------------------ TOTAL 42 36 85% ------------------------------------------------------------------------------
参考
fzf / peco でカレントディレクトリ以下のファイルを選択して消す
# fzf だとこんな感じ ls -f | fzf -m | xargs rm # Tab もしくは Shift+Tab で選択して、Enter で決定
fzf はデフォルトで複数指定できない仕様なので、複数指定用のオプション -m
を与えて有効化しているのがポイント。
# peco だとこんな感じ ls -f | peco | xargs rm # Ctrl+Space で選択して、Enter で決定
peco はデフォルトで複数指定できるのでその点は気にしなくて良いが、キーマップが厄介。 選択指定に Ctrl+Space というかぶりやすいキーアサインがされているので、他のキーアサインとかぶっている場合はマッピングを替えてやる必要がある。
ちなみに、ワイルドカード展開が効かないので、一気に消すにはおもったより便利じゃなかった。 一方で、壊れたファイル名で出来ちゃったファイル(名前指定が難しい)を消すのには便利。
Pipenv スクリプトを書く
名称として合っているのかはわからないが、npm スクリプト的なことを Pipenv でやるための方法について。
方法は wiki に書いてある
Pipenv 的には隠し機能らしく、Pipenv の wiki の Hidden Features に記載されている。 どうして隠しているのかは定かではないが、とにかくここに書かれているようにすればできる。 Pipfile の scripts セクションに、スクリプト名をキーにしてコマンドを記述する。 コマンドはきちんとセミコロンで囲った方が確実なので、そのようにするのがオススメである。
[scripts] reverse = "pyreverse -o png -p ...
実践してみる
pipenv run スクリプト名
で実行する。
ここではスクリプト名を reverse
としたので、そのように指定する。
$ pipenv run reverse ... (コマンド実行)
なんてことはなかった。
Lucene を C 言語で使う
結論からいうと、C/C++ 用のライブラリはいくつかあるんだけどどれも芳しくない。
強いて言えば Lucy だが、実装言語自体を Java に見直すのが賢いだろう。
資格取得に取り組んでみようとおもう
どうしてそういう気持ちになったか?
転職活動をして気になるのが、自分の能力が正しく伝わっているかということです。 準備として職務経歴書を作って提出し、面談では自身のキャリアを口頭で伝えるわけですが、 頑張ってアピールしているつもりでも担当者の方のリアクションが非常に涼しかったり、 逆にじぶんのレベルよりも遥かに低い質問があったりします。
自分の営業能力の低さもあいまって、そういった質問が来てしまうと、 「職務経歴書をどの程度読んでくれているのか?」 「一通り目を通して頂いているとして、自分の文章がどう受け取られ、その結果どういった評価をされているか?」 といったことが気になってくるのです。 誰かにレビューを頼むわけにもいかないので、どうしたものかと考えるわけですが、 そこでふと、資格でもとってみようかと思いました。
資格なんてとっても無駄じゃない?
職業能力というのは二つの要素によって構成されていると思います。 一つ目は知識、二つ目は業務経験です。 資格で証明可能なのは知識だけなので、そういった意味では十分ではないと思います。 しかし、先の体験を通じて、職業能力の一部を証明できるだけでも価値が高いと考えました。
あと、自分がレベルの高い資格を持ってる人に対してスゴいとおもっていることに気づきました。 といっても、自分の近くに仕事がデキてかつレベルの高い資格を持っている人がいるというわけではないのですが、 想像で「プロマネとネスペを持っていて TOEIC 900 点以上」みたいな人がいたら、 「この人スゲェな・・・」と思うと思います。 なので、自分もそういったレベルの高い資格の取得に取り組むことで、スゴい存在を目指そうと思いました。
どういった資格の取得を目指すの?
最初に目指そうとおもったのは、プロマネとネスペです。 国家資格という点でテッパンだろうというのと、知名度も難易度も十分なものということでこれを選びました。 ネスぺは今年10月、プロマネは来年4月の試験での取得を目指そうと思います。
ただ、この二つはたった今から資格取得を目指すには試験までの期間が長く、 このままではモチベーションを持て余してしまいます。 そこで、LPIC と AWS 認定試験 から受験することにしました。 民間資格は受験システムが柔軟で、予約さえできれば任意の日時に受験が可能です。 というわけで早速、一番レベルの低いものを再来週に受験してこようと思います。 ついでに言うと、この二つはおなじ受験会場を選択できたので、1日に連続で二つの試験を受験するように予約できました。 ちなみに、どうしてこの二つを選んだかと言うと、 もともと Linux は業務で慣れているので LPIC を取得することでその経験値を証明できると思ったためです。 AWS 認定の方は、逆に AWS は業務での経験はまったくないですが、利用経験を問われることが非常に多く、 AWS の社会的需要の高さを感じてこの機会に勉強してみようと思ったためです。
その他に、IT 関連では JSTQB、それ以外では TOEIC 900 点以上を目指そうと考えています。 JSTQB は、ソフトウェアテスト技術者の能力を判定するための資格です。 業務で最近ソフトウェアテストに関して体系的に調査する機会があったのですが、 ソフトウェアテスト自体に面白さに感じたので、 これを契機に資格もとりたいと思った次第です。 TOEIC は 4 年ほど前に受験して以来受験していません。 当時のスコアは 650 点で、ここからスコアを上げるには多くの勉強時間が必要なイメージがあったのと、 正直言ってここからスコアを上げていける自信がなかったので、半ば諦めて距離を置いていました。 リスニングが非常に苦手でここでスコアがとれていないという感じなので、 ここを頑張って強化できれば十分900点を取れる可能性もあると信じ、 とりあえずスコアが上がる手応えを得るために 100点アップから目指してやってみようと思います。
runc を動かしてみる
次の業務で runc が使えそうだったので、使用感を得るために試してみた。
※ runc について一部勘違いしていたので、公開時の記載より該当箇所を修正しております。ブコメにてご指摘頂いた @mapk0y さん、ありがとうございました。
runc とは?
runc とは、OCI に準拠したコンテナランタイムである。 コンテナと聞いて一番最初に思い浮かぶのは Docker だが、Docker も containerd 経由で runc を呼んでいる。
runc は、ワンタイム実行可能なコマンドラインプログラムとして実装されている。 runc はシェルコマンド経由で実行可能で、コンテナは runc のサブプロセスとして動作する。 そのため、コンテナを動かすための準備も不要だし、Docker で指摘されることが多いセキュリティ面での問題も runc レベルでは該当しない。
runcとは、OCI に準拠したコンテナランタイムである。
コンテナと聞いて一番最初に思い浮かぶのは Docker だが、Docker は一つの統合プラットフォームである。
比較するのであれば、Docker の標準ライタイムとして採用されている containerd と比較するのがレイヤ的に正しい
containerd との違いは、デーモンプログラムでない点である。
Docker では、コンテナランタイムとして containerd をデーモンプロセスとして走らせ、そのサブプロセスとしてコンテナを動作する。
一方の runc は、ワンタイム実行可能なコマンドラインプログラムとして実装されている。
runc はシェルコマンド経由で実行可能で、コンテナは runc のサブプロセスとして動作する。
そのため、コンテナを動かすための準備も不要だし、Docker で指摘されることが多いセキュリティ面での問題も該当しない。
ちなみに、rkt も runc と同じくワンタイム実行可能なコンテナランタイムとして知られているが、 rkt はランタイム機能に加えて、コンテナのライフスタイル管理やイメージ管理といった統合プラットフォームとしての機能も備えている点で違っている。
runc でコンテナを動かすにはどうするか?
ざっと以下の手順をとる。
- runc バイナリのビルド
- イメージの準備
- config.json の作成
- コンテナの実行
runc コミュニティは生成済みのバイナリを配布していないので、自分でビルドする必要がある。 自分でビルドすると聞くと「コンパイルエラーが出たらどうしよう」と身構えてしまうが、 go build の1行を実行するだけなので大したことはない。 ちなみに、libseccomp がシステムにインストールされていないとエラーがでるが、 特に seccomp の統合機能が必要なければ、単にこの機能を外してしまえばよい。 この機能を外すには、環境変数として BUILDTAGS を空文字列で渡すことで実現できる。
runc ではコンテナイメージとして、ファイルシステムのルートとしたいディレクトリを指定する。 特定の Docker イメージを runc で動かしたい場合は、export して tar 展開すればよい。 ディレクトリパスはデフォルトで ./rootfs だが、後述する config.json で任意のパスを指定することもできる。
// busybox イメージを変換する例 docker export $(docker create busybox) | tar -C rootfs -xvf -
config.json は、イメージのメタデータを指定するためのものである。
runc spec
コマンドでデフォルト設定のものを生成できるので、そこから始めて必要な設定だけ変更するようにすればよい。
ちなみに Docker と違って、環境変数の指定やコマンドパラメータの指定も config.json で行う。
コンテナ実行時にアドホックに渡すようなことは出来ないので気をつけること。
若干不便なので、頻繁に使うようであればラップしたコマンドでサポートするなど、なんとかした方がいい気がする。
systemd との連携
systemd をスーパバイザとして使う方法がよく紹介されるので、これについて補足する。 Docker や rkt と違って、runc 単体ではライフサイクルが管理できず機能不足である。 そこで systemd サービスの一つとして runc を実行するコマンドを用意しておくことで、 任意のコンテナアプリをサービスとして振る舞わせることができる。
Windows 仕様の Zip ファイルに含まれる各ファイルのファイル名を MacOS / Linux 環境で文字化けなしで確認する
Zip は仕様として、ファイル名のエンコーディング形式を指定する方法が用意されていないので、ASCII 以外では安全にファイル名を指定できない。 一方で、日本語を始めとする 非 ASCII 文字を含んだ名前のファイルというものはよくよくあって、実際には何らかのエンコーディング形式でもってファイル名を指定する。 このために一般的に使用されているエンコーディング形式は2つで、UTF-8(MacOS / Linux)と Shift_JIS (Windows)である。 ただ、MacOS / Linux と Windows 間でエンコーディング形式が違っているので、この OS 間で Zip ファイルの受け渡しを行うとファイル名の文字化けが頻発する。
Windows 以外の OS を常用している人なら誰しも経験したことがあるはずだが、ファイル名が文字化けしてしまうのは控えめに言って不便である。 なにか解決方法がないかと思い調べてみると、Windows 仕様の Zip 形式に対応するためのパッチが unzip コマンドで用意されているようだった。 それを使ってみても良かったのだけど、ファイル名をのぞくだけならサクッと Python で書けるだろうとおもったので5分で作ってみた。
Gist に投稿した Python スクリプトでも、このように curl 経由で直接実行できる。
$ curl -sS https://gist.githubusercontent.com/msh5/cda7439eb1de26bc8e643b0372edb89b/raw/list_winzipped_filenames.py | python - ~/Downloads/xxx.zip ○×契約書.pdf △□提案書.pdf
はい、便利!
Pipenv を使ってみたら最高だった
最近 Qiita でバズってるこの記事に影響されて Pipenv を使い始めているんだけど、 「おれたちが待ってたのはコレだ」感をスゴく感じられてオススメ。
特徴は以下の三つ。
- pyenv + virtualenv + pip のスイートツール
- bundler, npm ライクな依存管理
- Python.org 推奨
プロジェクトを始めるときに pyenv, virtualenv, pip を機械的に叩かないといけなかったりだとか、 requirements.txt の依存関係管理が弱かったりだとか、 Pipenv を使うことでそういった問題をまとめて解決できる。
インストールは pip install pipenv
すれば良い。
Homebrew にも対応しているので、MacOS なら brew install pipenv
でもOK。
pip install pipenv # Mac OS brew install pipenv
pipenv をプロジェクトで始めるには、まず使用するインタプリタを決定する。
指定可能なインタプリタは pyenv install --list
で確認できる。
ちなみに、新しいバージョンのインタプリタが出てこない場合は、
brew upgrade pyenv
もしくは pyenv update
すると、
ローカルの pyenv リポジトリが更新されて見えるようになる。
$ pipenv --python 3.6.5 Creating a virtualenv for this project… Using /usr/local/bin/python3.6m (3.6.5) to create virtualenv… ... Creating a Pipfile for this project… $ pipenv run python --version Python 3.6.5
pipenv --python <インタプリタ名>
を実行すると、以下の3つの処理が内部的に行われている。
- 利用するインタプリタのインストール(未インストールであれば):=
pyenv install <インタプリタ名>
- 利用するインタプリタの設定 :=
pyenv local <インタプリタ名>
- 利用する仮想環境の作成と設定 :=
virtualenv <環境名> && source <環境名>/bin/activate
なので、指定するインタプリタの仮想環境が一発で作れるというわけ。 さらに、もうひとつの処理が内部的に行われている。
- Pipfile の作成
作成される Pipfile はデフォルトでこういったものである。
[[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] [dev-packages] [requires] python_version = "3.6"
source は、pip install
時に参照する PyPI リポジトリの指定となっている。
公式の PyPI リポジトリ以外を使う人はあまりいないはずなので、基本的にここを触る必要はない。
requires はインタプリタの指定、packages, dev-packages は依存パッケージの指定である。
依存パッケージをインストールすると、自動的に packages, dev-packages に足される。
依存パッケージのインストールは pipenv install
で行う。
$ pipenv install requests Installing requests… ... $ cat Pipfile ... [packages] requests = "*" ...
バージョンを指定していないので * になっているが、そこまで気にしなくて良い。 なぜなら、おもむろに生成されている Pipfile.lock 内でインストールされた厳密なバージョンが記録されているし、 他のマシンでおなじ環境を再現するときに参照されるのも Pipfile.lock の方だからである。
$ cat Pipfile.lock ... "requests": { "hashes": [ "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" ], "index": "pypi", "version": "==2.18.4" }, ...
そして、他のマシン上で同じ環境を再現するために、Pipfile と Pipfile.lock はバージョン管理しておく。
他のマシン上で同じ環境を再現するには、リポジトリを clone した上で pipenv sync
を実行する。
$ pipenv sync Creating a virtualenv for this project… ...
エディタの話を付け加えておくと、VisualStudio Code が既に Pipenv をサポート済みである。 VSCode は内部的に pylint や isort といったコマンドを実行するが、 アプリを立ち上げると Pipenv を自動で検出して、 こういったコマンド類を仮想環境にインストールされたものから使ってくれる。 さらに、VSCode はコマンド類が見つからなかった場合、 (ユーザに対して確認を求めた上で)インストールコマンドを実行するが、 このコマンド類のインストールについても仮想環境に対して行ってくれる。 なので、VSCode ユーザにとっては至れり尽くせりといったところである。