今年はいろいろなアレコレでずいぶんと働く環境に影響がでました。
今回は週4-5のリモートワークになるにあたって使うようになったものをメモします。ずっと書こう書こうと思って半年経ってただけあって、毎日がっつり使ってます。
続きを読む今年はいろいろなアレコレでずいぶんと働く環境に影響がでました。
今回は週4-5のリモートワークになるにあたって使うようになったものをメモします。ずっと書こう書こうと思って半年経ってただけあって、毎日がっつり使ってます。
続きを読むScoop Bucket を作るのは避けたいものです。 しかし、Main や Extras に追加するのもアレだし、既存のパッケージ更新はメンテされてないし、など様々な理由で自分のバケットを作ることはあるでしょう。
自分のバケットを持った時に面倒なのが、バケットの更新追従です。 幸いにも Scoop には Excavate という自動更新する仕組みがあります。今回はこれを仕込んでみましょう。
checkver
、 autoupdate
セクションを設定するbukcet/
などフォルダを掘っている場合はスクリプトで対応が必要この記事で使っている自動更新のためのスクリプトや仕組みは .github フォルダに一式が入っています。
バケットの自動更新は以下の環境で動作します。
Linux コンテナで動作するので、事実上実行環境に困らないでしょう。Windows でも実行できますが、私はLinuxのみで行っています。
3つやることがあります。
順番に見ていきましょう。
Scoop App Manifest は、checkver
、autoupdate
に適切な内容を記述することで自動更新対象のマニフェストとして認識されます。この辺りは公式の Wiki に書いてあります。
App Manifest Autoupdate · ScoopInstaller/Scoop Wiki · GitHub
といってもWikiの内容は複雑でよくわからん.... ということで実際に使っているシンプルなパターンで説明します。
今回のパターンは GitHub Releases のパッケージ更新を見てバケットを構成している場合に利用できます。ただし、プレリリースではない && バージョン1.0.0 や v1.0.0 といったパターンでタグ公開されているの2点が前提です。
実際に利用しているctop を定義したマニフェストを用意しました。
{ "description": "Top-like interface for container metrics", "homepage": "https://github.com/bcicen/ctop", "version": "0.7.5", "license": "MIT", "url": "https://github.com/bcicen/ctop/releases/download/v0.7.5/ctop-0.7.5-windows-amd64#/ctop.exe", "hash": "sha256:bffb1499d62c46b70dd25d557b653f812ccdc8b4bfb08473c063a6265faf78b3", "bin": "ctop.exe", "checkver": "github", "autoupdate": { "url": "https://github.com/bcicen/ctop/releases/download/v$version/ctop-$version-windows-amd64#/ctop.exe" } }
自動バージョン更新に必要なのは、checkver と autoupdate のセクションです。
checkver
は "github"
で問題ありません。これでリリースぺージのTagが \/releases\/tag\/(?:v|V)?([\d.]+)
パターンで公開されていれば抽出されますautoupdate
のセクションは、$version
を使って実際のリリースページのダウンロードurl を表現します。url が https://github.com/bcicen/ctop/releases/download/v0.7.5/ctop-0.7.5-windows-amd64 なので、0.7.5 というバージョンが $version に置き換えられていることがわかりますこれでバケットのjsonは準備が整いました。
リポジトリ直下にバケットのjsonを配置しているか、bucketフォルダを掘ってそこにまとめているかで微妙に異なります。
bucket フォルダを掘っている場合は、lukesampson/scoop-extras の bin フォルダの中身を、そのまま自分のリポジトリの/binに持ってくるといいでしょう。
もしもリポジトリ直下にバケットjson を置いている場合は、以下のように $dir = "$psscriptroot/.."
とします。各スクリプトにこの変更がいるので面倒です。
# auto-pr.ps1 param( # overwrite upstream param [String]$upstream = "<user>/<repo>:master" ) if(!$env:SCOOP_HOME) { $env:SCOOP_HOME = resolve-path (split-path (split-path (scoop which scoop))) } $autopr = "$env:SCOOP_HOME/bin/auto-pr.ps1" # $dir = "$psscriptroot/../bucket" # checks the parent dir $dir = "$psscriptroot/.." # checks the parent dir iex -command "$autopr -dir $dir -upstream $upstream $($args |% { "$_ " })"
これでバケットのスクリプト配置も完了です。
NOTE: 調べるとこのスクリプト名がbucket-updater.ps1 だったり auto-pr.ps1 だったりしますが、後述のExcavatorを使う場合どちらでも対応されているので大丈夫です。auto-pr.ps1 が公式でも使ってて新しいかな?
自動更新方法はWikiにもいくつかのっています。
App Manifest Autoupdate · ScoopInstaller/Scoop Wiki · GitHub
個人的には、ScoopInstaller/Excavatorを用いて docker-compose で実行するのがおすすめです。Linux で実行できるのと、docker-compose が利用できるので実行環境を選びません。あとこの方法なら Kubernetes で実行も簡単です。
docker-compose を実行すると ssh キーが生成されるので、公開鍵 id_rsa.pub をGitHub に登録して push できるようにしましょう。sshキーを再利用する場合は、id_rsa も取得しておいて、docker-compose 実行時にマウントさせればok です。
$ docker-compose up --build $ docker-compose exec bucket cat /root/.ssh/id_rsa.pub $ docker-compose exec bucket cat /root/.ssh/id_rsa
このコンテナイメージは定期的に呼び出して実行するには注意があります。/sbin/my_init
を実行した上でないと scoop コマンドがコンテナ内部で見つからずエラーが出ます。
走らせっぱなしで定期実行する前提なイメージになっているので、自分のように定期的に呼び出し実行する場合は docker-compose で次のようなラッパーコマンドを用意して呼び出すといいでしょう。
#!/bin/bash /sbin/my_init & chmod 600 /root/.ssh/id_rsa pwsh ./root/scoop/lib/install.ps1 bash -x /root/excavate.sh
これで コンテナを使っていい感じに更新されるようになります。
このような定期実行環境は、Kubernetes の cron job、後今日使えるようになった Amazon ECS のdocker-compose対応などが楽でしょう。
GitHub Actions での使用は、使用条件のここに該当するかによりそうです。
any other activity unrelated to the production, testing, deployment, or publication of the software project associated with the repository where GitHub Actions are used.
バケットのデプロイ作業なので実行は許されそうですが、自前のクラスタで実行で行えるならそれがいいでしょう。 仮にリポジトリで実行していますが、自前Kubernetes クラスタでの実行に変更を予定しています。
以下に GitHub Actions で実行する場合の Workflow を示します。
name: auto update bucket on: schedule: - cron: "0 * * * *" workflow_dispatch: jobs: update: timeout-minutes: 10 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: openssl aes-256-cbc --pbkdf2 -d -in .github/.ssh/id_rsa.cipher -k ${{ secrets.CIPHER_KEY }} >> .github/.ssh/id_rsa - run: docker-compose up working-directory: .github
パッケージの更新ログの例です。
main_1 | main_1 | ScriptBlock ID: f43b73d1-2181-437c-9d72-8b0797e62035 main_1 | Path: /root/scoop/lib/install.ps1 main_1 | py: 1.0.1.6 main_1 | DejaVuSansMono-Bront: couldn't match '\/releases\/tag\/(?:v|V)?([\d.]+)' in https://github.com/chrismwendt/bront/releases/latest main_1 | bombardier: 1.2.5 (scoop version is 1.2.4) autoupdate available main_1 | Autoupdating bombardier main_1 | Downloading bombardier-windows-386.exe to compute hashes! main_1 | Downloading https://github.com/codesenberg/bombardier/releases/download/v1.2.5/bombardier-windows-386.exe#/bombardier.exe (9.7 MB)... main_1 | Computed hash: d2bfd99019ca590610c89ccf829bf4c84ed6652821fe55e7f9bcf342106fe496 main_1 | Downloading bombardier-windows-amd64.exe to compute hashes! main_1 | Downloading https://github.com/codesenberg/bombardier/releases/download/v1.2.5/bombardier-windows-amd64.exe#/bombardier.exe (10.9 MB)... main_1 | Computed hash: 52e0c22e3a10c06f7013bbb09d713ab52fae6fba5a86a5ffcfdd6546ed86b7cf main_1 | Nov 22 12:17:39 3e2cb27a65fb powershell[86]: (7.0.2:9:80) [ScriptBlock_Compile_Detail:ExecuteCommand.Create.Warning] Creating Scriptblock text (1 of 1): main_1 | {⏎⏎ $architecture = $_.Name⏎⏎ if ($json.architecture.$architecture.$prop -and $json.autoupdate.architecture.$architecture.$prop) {⏎⏎ $json.architecture.$architecture.$prop = substitute (arch_specific $prop $json.autoupdate $architecture) $substitutions⏎⏎ }⏎⏎ } main_1 | main_1 | ScriptBlock ID: a1ca077d-4175-458e-9ad3-e0f9e4c68c86 main_1 | Path: /root/scoop/lib/autoupdate.ps1 main_1 | Writing updated bombardier manifest main_1 | ctop: 0.7.5 main_1 | warning: LF will be replaced by CRLF in bucket/bombardier.json. main_1 | The file will have its original line endings in your working directory. main_1 | Creating update bombardier (1.2.5) ... main_1 | hub add bucket/bombardier.json main_1 | warning: LF will be replaced by CRLF in bucket/bombardier.json. main_1 | The file will have its original line endings in your working directory. main_1 | hub status --porcelain -uno main_1 | hub commit -m 'bombardier: Update to version 1.2.5' main_1 | [master 603a742] bombardier: Update to version 1.2.5 main_1 | 1 file changed, 5 insertions(+), 5 deletions(-) main_1 | Pushing updates ... main_1 | hub push origin master main_1 | Warning: Permanently added the RSA host key for IP address '140.82.112.4' to the list of known hosts. main_1 | To github.com:guitarrapc/scoop-bucket.git main_1 | c5e2c3f..603a742 master -> master main_1 | hub reset --hard main_1 | HEAD is now at 603a742 bombardier: Update to version 1.2.5 main_1 | + '[' -f /root/bucket/bin/bucket-updater.ps1 ']' github_main_1 exited with code 0
難しい記述をしなくても自動更新できるのはいいことです。 実行環境だけ面倒ですね。
手の入れ方が好みじゃないので参考程度にしています。 こういう公式のやり方に乗っかる場合は、コンテナに手を入れないのがおすすめです。メンテしきれなくなるので。
IPv4 PPPoE からIPoE にしつつ、Unifi Dream Machine (UDM) で IPv4 over IPv6 環境でアクセスするまで組んだのでそのメモです。
Unifi Dream Machine はMAP-E に対応していないので、ちょっと小細工が必要だったのは学びでした。
私が欲しい内容の記事がなかったので自分で書くしかないのです。
HGW と組み合わせることで、UDMは MAP-E 方式の IPv6 に対応します。
構成は以下の通り。
結果、UDM の出口速度でIPoE VDSL から IPoE光配線 で 約6-10倍に上がったのでいったんこれで。(満足できてない)
一週間前の10倍ぐらいまでは早くなったんだけど、Wifi の速度がまだ追いつかないな pic.twitter.com/XIk4rUEjIU
— guitarrapc_tech (@guitarrapc_tech) October 16, 2020
今後のメモ
いくつか事前情報を共有します。
はたして国内に何人いるのでしょう、そんなにいない気がします。
私の個人環境は8年前から完全にWifiで統一しています。 ケーブルが嫌いというのもあるのですが、配線や配置の自由さと、ネットワーク環境でやりたい放題やるを考えたときに、Wifiもまとめて制御することを自分に課しています。有線LANは好みではないし、Wifiの技術的進展が目覚ましいのでよい。
Wifi で統一するにあたり、当然メッシュ環境が欲しくなるので以前は Amplifi を使っていました。
しかし、メッシュを広げつつ、計測やIDS/IPSを展開しつつ、今後の変化にも追随することを考えるとUnifi にしたくなります。でも Cloud Keyはいや。ということで、Unifi Dream Machine は欲しかったマシンであり、日本Ubiquiti Store で販売されてすぐに切り替えました。
私の環境において「あらゆる機器は UDM配下からのアクセスになる」というのが構成上の大前提となります。
もしもUDMに興味がなくて、「さくっとIPoEでいい感じに組みたい」だけなら適当にIPoE 対応の国内ルーターでも使えばいいと思います、好きにするのが一番。Synology とかもMAP-E対応ありますしね。
私はISPに、ぷららを利用しています。
以前は住んでいたところが VDSL だったため、何をどうあがいても100Mbps が上限でした。
とはいえ、IPv4 PPPoE だと夜間の速度が不安定になることが多くなってきたので、回線速度を安定させるため IPoE にすることにします。
IPoE にするだけで、いったん回線速度は安定しますが、せっかくなので IPv6 への対応も考えたいものです。 しかし、ぷららが提供する MAP-E 方式の IPoE 環境とUDM は相性が悪いので「UDM配下のクライアントで IPv6 ネイティブでアクセスさせるためにどんな構成にするのか」、これがこの記事のポイントです。
IPv4 で PPPoE でつないでいるときは次のような環境です。
インターネット -- | | -- ONU -- ルーター -- UDM -- 各Wifiクライアント
最終的に、MAP-E方式の IPv6 で次のような構成に持っていきます。
インターネット -- | | -- HGW -- UDM -- 各Wifiクライアント
PPPoE から IPoE までの変遷を見ていきます。
IPoE と UDMをどう組めばいいのか考えます。
UDM は MAP-E にも DS-Lite にも対応していない。これは調べればすぐにわかります。
ではどうすれば組めそうでしょうか。
まず採用しなかった方法を見てみます。
EdgeRouter の EdgeOS なら DS-Lite 構成組まれている方もいますが、UDM は UnifiOS でそういった構成は組めません。(そういえば MAP-E 組んでいる人はいませんね)
こういう MAP-E に対応していない場合のよくある対処の1つは、IPv4 アクセスは IPv4 PPPoE 回線から、IPv6 アクセスは IPv6 プラスルーター経由でアクセスさせる方法です。PPPoE を残したくないですし、なんのための IPv4 over IPv6 なのかって話で好みではありません。(過渡期としてはやむを得ないですね。ぷららの技術部門の人と話をしたときも、ぷららの人はこの構成で話していました、わかる。)
あるいは、ひかり電話なしでRAをLANにいきわたらせてしまうのも手でしょう。IPv6でクライアントがグローバルにさらされるのを避けるために、スマートスイッチでタグベースVLANを使ってIPv6を選択的に設定するのもありだと思います。(めんどくさすぎて好みじゃない)
どれも単純ではない、自分が運用したくないと感じる構成です、こういうのは避けたい。
IPv4 over IPv6 でUDMを使ってどのように組めるか調査すると、「ひかり電話」の有無で前提が大きく変わるのがわかります。ひかり電話の有無で DHCPv6 が使えるかが決まり、同時にHGW を使えるかも決まります。
構成の単純さとDHCPv6 を考えるとひかり電話はいれるのが妥当だと思います。月500円かけるだけで、いかんともしがたい課題が解決するのです。ひかり電話は使わないので、これだけのために入れるのは納得感はないですが目を瞑ります。
もう1つが HGW です。UDM はMAP-Eをしゃべられないルーターなので、事前にMAP-E をしゃべらせておく必要があります。
余談: HGWから直でなくても、MAP-E 対応ルーターが RA パススルーに対応していればワンチャンとふと思いましたが、私の借りた MAP-E対応ルーター WN-AX1167GR2 は RAパススルーがなかったです。
次の通りです。
YAMAHA などでもよく組まれているほう方法ですね。
NTT の方式でいうところの、光配線方式の接続パターンB が該当します。
では構成の変遷を見ていきましょう。
UDM が MAP-E 対応すると、ひかり電話なしでもよくなるので対応されると嬉しいですね。対応されるかは期待はあまりできなさそうですが...。
https://community.ui.com/questions/Feature-Request-IPv4-over-IPv6-in-Japan-using-IPOE-MAP-E-or-DS-LITE-etc-/452a1bbf-6880-4cc9-9c75-fae87ff68ca4community.ui.com
ぷららの場合、ぷららv6エクスプレスで IPoEを提供しています。 プロフィールページから「ぷらら光」に契約を切り替えることでIPoE に変更できます。 なかなか手間がかかる作業で、事前にNTTから承諾番号を得る必要があり、ぷららの契約切り替え自体も概ね2週間見る必要があります。
この時点では、「HGW での IPoE 接続」はしません、まずは IPoE 接続を安定させます。ということで、IPoEへの切り替えを申し込むにあたり、MAP-E対応ルータとして「ぷららWi-Fiルーター」をレンタルします。
PPPoE から IPoE への切り替え時の申し込みは次の通りです、めんどくさい。
変更予定日前に、HGWとMAP-E 対応ルーターが届きます。変更予定前日夜にでもVDSLルータとUDM の間に入れましょう。AM8:00ぐらいに切り替えが走ったのが計測できました。
IPoEへの切り替えが無事に完了すると、ぷららv6エクスプレスが開通済み、IPoE対象接続先がIPv4+IPv6へと変わります。
接続状態はVDSL方式の接続パターンCになります。すごく面倒くさい。
VDSLルーター -- HGW -- MAP-E対応ルーター -- UDM -- 各Wifiクライアント
この時点では、UDM 配下には IPv6 が配布されず IPv4のみになります。MAP-E対応ルーターを抜いて IPv6 ネイティブ接続にすることはできますが、はっきり言ってどこも接続できないのでムリ。 (GitHub も Twitter もつながらないのは意外でしたが)
なので、IPoE + IPv6 もクライアントで使いたいなら、MAP-E 対応ルーターに直接接続すれば期待通り動きます。(私はUDM を使いたいのでやらない)
通信速度は、VDSL の上限によって 100Mbps できっちり止められます。PPPoE とは違い、IPoEでは速度はある程度安定し、100Mbps 程度ならずっと維持できるのでいいでしょう。
余談ですが、UDMの代わりに Amplifi HD をおいて Bridge 接続 + Router Steeling を仕掛けると、Wifi クライアントに IPv6 が配布されたりします。Amplifi をどうしても使いたい人はこれでもいいですね。
いろいろあって、住んでいるところがVDSL回線が光ファイバー回線に更新されることになりました。(下り/上り 1Gbps)
ということで、当然 VDSL ルーターは不要になり、光コンセントからHGWに直接回線がつながるようになります。 接続状態は光配線方式の接続パターンCに相当します、一般的な光回線が入っている場所ではこの構成が多いでしょう。
HGW -- MAP-E対応ルーター -- UDM -- 各Wifiクライアント
VDSL がなくなるだけですが、これで回線速度が 300Mbps に上がりました、遅いもののだいぶん改善しました。(LAN も Wifi も同じ速度がでている) 当然ですが、まだ UDM の配下には IPv6 は渡せず IPv4 のみです。
余談: MAP-E 対応ルータの下に UDM を置くと、なぜか速度が 60~70Mbps に落ちたのですが、どうやら LAN の DHCPv6 が残っているとゴミ設定で速度が落ちるバグがある気配があります。LAN の IPv6 対応を無効にして再起動すれば速度劣化なしに300Mbpsでます。(その後は同じ設定をいれても速度劣化がなくなりました)
ごにょごにょいじった結果、HGW + Unifi で 310Mbps 出るようになったのでいったんこれで。(IPv4 Only だけど) pic.twitter.com/NjUTFANf9T
— guitarrapc_tech (@guitarrapc_tech) October 11, 2020
これで、UDM で IPv6 を配布する準備が整います。IPoE の MAP-E 接続をHGW にゆだねましょう。
HGW にするには、HGW製品が型番が300番台以降でないとだめなのと、いくつか使えなくなるサービスがあるので注意です
まずは、ぷららのプロフィールから 「ホームゲートウェイ(HGW)によるIPoE接続」への切り替えを申し込みましょう。
次の日の夜ぐらいにいきなりスパッと切り替わります。HGW で PPPoE 接続を入れていない場合は回線が切れます、MAP-E対応ルーターは不要なので外します。
これで、光配線方式の接続パターンB に無事移行できました。
HGW -- UDM -- 各Wifiクライアント
余談: ちなみに、デフォルトのLANサブネットが HGW (192.168.1.1/24) と UDM (192.168.1.1/24) でかぶります。UDM のLANを 192.168.2.1/24 あたりにずらしておきましょう。(MAP-E 対応ルータが 192.168.0.1/24 なので放置していた)
HGWに特に設定は不要なので、HGW と UDM を再起動すればすべてが期待通りに動き出します。(PPPoE は不要ですし外しておきましょう)
ようやく本題です。
ひかり電話を契約していれば、RA ではなくDHCPv6-PD (Prefix Delegate) 方式が利用できます。 早速UDM で IPv6 を HGW から受ける設定 (WAN) と、クライアントへのIPv6 配布の2点を行います。
ひかり電話がある場合、IPv6は DHCPv6-PD 方式で60bitのPrefix再委任が行われます。(ひかり電話なしだと、RAが直でおりてきて 64bit しかこない)
ということで、IPv6の構成を行います。加えて、DNS の解決ができなくなるケースを防ぐため、DNSにGoogle DNS あたりを指定します。
DHCPv6
60
8.8.8.8
と 8.8.4.4
LAN に IPv6 を配布する設定を行います。 IPv6 RA、IPv6 Priority、DHCP Range はデフォルトのままでok です。DHCPv6/RDNSS DNS は、Google DNS を指定します。
Prefix Delegation
有効
High
::2
、 Stop ::7d1
Manual
2001:4860:4860::8888
2001:4860:4860::8844
ipv6 test を行います。 HGW - UDM 接続 + DHCPv6-PD の構成を組むことで、UDM のWifi クライアントもIPv6テストが通るようになります。長かった。
HGW と UDM を直接つなげたことでルーターが1つ減ります。ということで、速度も改善します。
UDM との LAN 接続で 610Mbps まで向上します。
HGW + IPoE で 610Mbps まで改善したかな。 pic.twitter.com/KTsPpyAF5h
— guitarrapc_tech (@guitarrapc_tech) October 16, 2020
UDM の 5GHz 160 VHT と 1.7 Gbpsのネットワークアダプタで接続すると、下りがLAN より劣化しているのが気になります。(そもそも 160 VHT は非推奨です) アップロードは想定通り向上しています。
802.11ac、5G VT160。1.7Gbps 接続状態の現状メモ pic.twitter.com/wmkbuw8LM7
— guitarrapc_tech (@guitarrapc_tech) October 16, 2020
IPv6 IPoE で接続して、好きなルーターで良い感じに構成するなら、ひかり電話は契約しておくといいです。 DHCPv6-PD に持ち込めばどうとでもなれるので、ひかり電話なしで頑張るのは避けましょう。
なによりも、VDSLな住居は絶対に避けて光配線の住居を選びましょう。自分で入れるのいろいろ面倒ですしね。
以前 Windows の開発環境を scoop で構築しているということを書きました。
その際に、scoopを継続的に使っていくためのツール ScoopPlaybook を書いたことに触れました。 今回はその ScoopPlaybook の紹介です。
scoop 使っていて、YAMLでインストールするツールを定義したい方は使ってみてください。
私は普段からOS環境を壊すことをアリと考えています。 ただし壊すからには再構築にコストをなるべくかけたくないため、対象のマシン上で再構築がコマンド1つでできるようにしています。 macOS は Homebrew や defaultsをAnsible Playbookで構築し、Ubuntu は Ansible Playbook で構築しています。
Ansible Playbook を使うことで、ほどよく緩くいい感じの目指す姿が可能になります。
例えば Homebrew でインストールする場合は次のように定義できます。
# roles/homebrew/tasks/main.yaml - name: 'homebrew packages installation' homebrew: name: '{{ item.name }}' state: "{{ item.state|default('present') }}" with_items: "{{ homebrew_packages }}" # roles/homebrew/vars/main.yaml homebrew_packages: - name: autoconf - name: awscli - name: aws-iam-authenticator - name: azure-cli # and so on....
一度定義してしまえばツールを定義に追加したり、アンインストール ( state: "absent"
) を指定するだけとメンテナンスが非常に簡単です。
site.yml を置いたルートパスでいつも同じコマンドを実行するだけで、YAML定義通りに環境が構築されます、便利。
$ ansible-playbook -i hosts site.yml
sudo が必要な操作 (become) なら、実行時に入れるだけです。
ansible-playbook -i hosts site.yml --ask-become-pass
WSL との相性もよく、気軽に環境を壊してサクッと作り直すことがコストでなくなります。
自分の環境にどんなツールをいれているかを説明することがふとしたときにあるのですが、定義によって、いつでも確認したり継続的に変更をかけたり、場合によっては他人に共有できるのは個人的に好みです。
環境の再構築はWindowsでもたびたび行います。(OSいれなおしでなくてもリセットはやりますよね)
scoopを使っていくことに決めたときに、コマンドの羅列地獄になるのは嫌だと思いました。 しかしAnsible をWindows localhost に実行はサポートされていないので、Ansible Playbook のような定義とインストールを提供することにしました。(WSLからAnsible実行するというのはナシ派) その晩にザクっと書いたのが ScoopPlaybook という PowerShell Module です。
あんまり使い方とか書いていないので、どういう利用をするのか紹介します。
例えば、scoop でgow、jq、time、unzipをインストールする場合、コマンドラインで次のように実行するでしょう。
scoop install gow jq time unzip
あるいは、次のようにコマンドを分けているかもしれません。
scoop install gow scoop install jq scoop install time scoop install unzip
アンインストールもコマンドラインで制御できます。
scoop uninstall gow
入っているツールは scoop list
で見えますが、ほかの環境や再構築、追加インストールをするときはいちいち考えるの嫌になります。
ScoopPlaybook はAnsible Playbook でやっていたのと同じ目指す姿を提供します。
利用方法は Ansible Playbookに合わせています。
ルートパス/site.yml
に 利用する role のYAML定義し、ルートパス/roles/バケット/tasks/main.yml
にツールをYAML定義したら、Scoop-Playbook
コマンドを実行すると、Scoopバケットやツールが定義通りにインストール/アンインストールされるYAMLで定義して、コマンド1つで定義を実行。ただそれだけです。 実際にどうやるのかイメージしにくいので利用例を見てみましょう。
先ほどのmainバケットのツールをScoopPlaybookでYAML定義してインストールしてみましょう。 ScoopPlaybook モジュールとYAM解析モジュールをインストールします。PowerShell 5.1 以降で動作します。
PS> Install-Module ScoopPlaybook -Scope CurrentUser PS> Install-Module "PowerShell-Yaml" -Scope CurrentUser
適当にルートパスを切ります。
md ./begin cd ./begin
まずは、インストールしたいアプリの定義YAMLを ルートパス/roles/main/tasks/main.yml
に定義します。
PS> mkdir roles/main/tasks PS> New-Item roles/main/tasks/main.yml PS> vim roles/main/tasks/main.yml
- name: "Install main tools" scoop_install: state: present bucket: main name: - gow - jq - time - unzip
インストールするロールを指定したYAML定義 site.yml
をルートパスにおきます。
PS> New-Item site.yml PS> vim site.yml
今回のロールは main なのでこれを1つ指定します。
name: Windows Setup roles: - main
早速定義をドライランしてみましょう、次のコマンドを site.yml のパスで実行します。
PS> Scoop-Playbook -Mode check
scoop のバケットを更新して (scoop update
) 、ツールがインストールされるか実行計画を確認できます。
PRE [scoop : status] *************************************************************** [o] skip: [run with 'check' mode] [o] skip: [prerequisiting availability] [o] skip: [updating buckets] [o] check: [scoop-update: Updating Scoop...] [o] check: [scoop-update: Updating 'main' bucket...] [o] check: [scoop-update: Scoop was updated successfully!] [o] skip: [status checking] [o] skip: [scoop-status: Scoop is up to date.] [o] check: [scoop-status: Updates are available for:] .... 省略 PLAY [Windows Setup] *************************************************************** TASK [main : Install main tools] *************************************************** [!] check: [scoop_install: gow] => Installed: No [!] check: [scoop_install: jq] => Installed: No [!] check: [scoop_install: time] => Installed: No [!] check: [scoop_install: unzip] => Installed: No
問題なければインストールします。Mode パラメーターを省略するか、-Mode run
を明示的に付けると実行します。
PS> Scoop-Playbook
PRE [scoop : status] *************************************************************** .... 省略 PLAY [Windows Setup] *************************************************************** TASK [main : Install main tools] *************************************************** [!] changed: [scoop_install: gow] => Installed: No Installing 'gow' (0.8.0) [64bit] Loading Gow-0.8.0.exe from cache Checking hash of Gow-0.8.0.exe ... ok. Extracting dl.7z ... done. Running pre-install script... Linking ~\scoop\apps\gow\current => ~\scoop\apps\gow\0.8.0 .... 省略 'gow' (0.8.0) was installed successfully! [!] changed: [scoop_install: jq] => Installed: No Installing 'jq' (1.6) [64bit] .... 省略 'jq' (1.6) was installed successfully! [!] changed: [scoop_install: time] => Installed: No Installing 'time' (0.2018.07.25) [64bit] .... 省略 [!] changed: [scoop_install: time] => Installed: No Installing 'time' (0.2018.07.25) [64bit] .... 省略 'time' (0.2018.07.25) was installed successfully! Notes ----- Please use 'timecmd' instead of 'time' in cmd.exe. [!] changed: [scoop_install: unzip] => Installed: No Installing 'unzip' (6.00) [64bit] .... 省略 'unzip' (6.00) was installed successfully!
再度実行しても同じ結果に収束します。 もし更新があれば更新してくれます。
PS> Scoop-Playbook
Scoop-Playbook PRE [scoop : status] *************************************************************** .... 省略 PLAY [Windows Setup] *************************************************************** TASK [main : Install main tools] *************************************************** [o] skip: [scoop_install: gow] => gow 0.8.0 [o] skip: [scoop_install: jq] => jq 1.6 [o] skip: [scoop_install: time] => time 0.2018.07.25 [o] skip: [scoop_install: unzip] => unzip 6.00
何かの理由でscoop コマンドで直接インストールすることもあるでしょう、そんな時は定義に一行足せばいいだけです。
もし scoop コマンドで誤ってアンインストールしても、Scoop-Playbook
を実行すれば元通りです。
Scoop で管理したいツールを定義通りに実行する。それができます。
私は ScoopPlaybook を使ってYAML定義をして GitHub においています。
参考に私が普段使っているリポジトリを置いておきます。ルートパスはこのリポジトリの ./envs/windows/
パスです。
local-provisioner/envs/windows at main · guitarrapc/local-provisioner · GitHub
そのため、環境構築するときは次のコマンドを実行しています。
git clone https://github.com/guitarrapc/local-provisioner.git cd local-provisioner/envs/windows . ./prerequisites.ps1 sudo Scoop-Playbook
ツールの追加や削除をしたいときは、定義のYAML を修正して git commit/push するだけです。 バッチファイルやスクリプトではないので、どのように動作するかは考えず、ツールをYAMLに並べるだけなのはメンテの面で作ってよかったと思っています。 実際これなしで scoop とかいやです。
ScoopPlaybookは次の操作が可能です。これしかできないです。
scoop_bucket_install
: バケットの追加、削除scoop_install
: ツールのインストール、アンインストールscoop は任意のGitHubリポジトリなどをバケットにできます。scoop bucket add xxxx
ScoopPlaybook も scoop_bucket_install
でバケットの追加、削除をサポートしています。
例えば extras バケットを追加する場合、次のように書けます。
- name: "Install extras bucket" scoop_bucket_install: state: present bucket: extras
extras バケットは特別扱いされていますが、自分の GitHub URL を指定したい場合は次のようになります。
- name: "Install guitarrapc bucket" scoop_bucket_install: state: present bucket: guitarrapc source: https://github.com/guitarrapc/scoop-bucket.git
もしも追加したバケットを消したいならstate に absent を指定します。 (source は省略できます)
- name: "Uninstall guitarrapc bucket" scoop_bucket_install: state: absent bucket: guitarrapc
それぞれのキーは、scoop bucket
コマンドに合わせてあります。
scoop はバケットからツールのインストール、アンインストールができます。scoop install xxxx
ScoopPlaybook も scoop_install
でツールのインストール、アンインストールをサポートしています。
- name: "Install main tools" scoop_install: state: present bucket: main name: - gow
先ほど追加した gow をアンインストールするなら次のように書けます。
- name: "Uninstall main tools" scoop_install: state: absent bucket: main name: - gow
それぞれのキーは、scoop install
コマンドに合わせてあります。
すでにインストールされているツールに更新がある場合は、Scoop-Playbook
実行時に更新してくれます。便利。
scoop はユーザー権限が基本でーとか言いますが、ツールによってはFiddler のように管理者権限がないとインストールできないものもあります。 そんなときは sudo コマンドです。
sudo コマンドをインストールしておいて(scoop install sudo
相当)
- name: "Install main tools" scoop_install: state: present bucket: main name: - sudo
Scoop-Playbook を sudo つきで実行すればok です。
sudo Scoop-Playbook
一人で使ってて満足していたんですが、WinGet が出てきて未来はどうなるかと楽しみにしています。 ただ、WinGet はこのままいくとこういう YAML 定義に関しては手を出さず、誰かが何か作るのでしょう。
アンインストールやUAC考慮がない、今のWinGet 触る気はありませんが、WinGetを触る将来が来たらこういうツール書くかもしれません。 ただ、その時はたぶん PowerShell では書かない気がするかもしれない。
WSL1 を長い間使っていましたが、先日 Windows 10 Version2004 がリリースされて WSL2 に切り替えを行いました。
WSL2 いいのですが、WSL1 と同じように、あるいはちょっと欲張ろうと思うと少し困ったのでメモ。
Windows 10 May 2020 Updateがリリースされてから2週間使ってますが、もう WSL1 に戻る気はないぐらいには気に入っています。おすすめです。 具体的には、
kubernetes 周りに関しては、特段変化を感じません。
WSL1 では、Ubuntu 18.04 を動かして、中でアプリケーションやインフラにかかわるツールを動作させていました。 Docker でもいいのですが、普段使いのツールや、Windows でマウントしているファイルを(EOLを含めて) そのまま Linux で動作させたときの動作もサクッと確認できるのがいいのです。
docker とWSL の使い分けはそのカジュアルさです。 WSLは、bash と入力するだけでほぼ Linux とみなせるインタラクティブな環境に行けるので、普段使いのUbuntu 環境に利用しています。多少無茶な使い方をしても、アンインストールして store から入れなおせばフレッシュになるので壊せる開発環境という感じです。 一方のdocker は、アプリ動作環境を閉じ込めるためや、特定のソフトウェアの挙動、壊れるだろうという操作やシステム設定の変更など戻すことがめんどくさいことをするときに使っています。
基本的な利用目的は変わりません。手軽にさくっと Linux 環境として Ubuntu を利用します。 WSL1 から WSL2 に変化することで期待したのは、ディスクIOです。 概ね事前にやっていた結果と Windows 10 Version 2004 における WSL2 に違いはなく、WSL1 に比べて ext4 上でのディスク書き込みの速度が上がりました。 具体的な変化は次の通りです。
apt update|instal
が爆速になるpip3
も爆速化ディスクアクセスの改善は顕著です。具体的なシチュエーションだと、apt update/install に関しては、これまでUbuntu 18.04 を入れた後に実行すると10min 程度食うのを覚悟していたものが1min 程度になっています。pip3 も同様です、ansible 入れてみてください。
ただ、Windows のマウントディレクトリ ( /mnt/c
など) でのファイル操作はけた違いに遅くなりました。(知ってた) そのため、例えばdocker-compose で Windows のフォルダを WSL2 からマウントするのはものを選びます。100MB を超えるdocker転送は永遠に終わらない気分になります。(node_modules とかつらい)
Windows のパス上からそのまま bash
で WSL2 を起動する流れは変わらないものの、大き目なファイルサイズを伴う docker-compose
に関しては Windows上で扱うか、ext4 上に git clone するのがいいでしょう。
しれっと書きましたが、WSL2ではWSL上のファイルをWSLのdockerにボリュームマウントできるようになっています。WSL1 では、WSL 上のファイルを WSL上で実行した docker にボリュームマウントできず、ふとしたdocker操作で挙動が違って無駄に時間を費やすことがありましたがなくなりました。最高です。
WSL1 の環境を WSL2 にするにあたり、どのような対応をしたかメモしておきます。
WSL1からWSL2にすると、Docker Desktop (35GB)、wsl (9GB)、Ubuntu 18.04(5GB) で 約50GB余計にシステムボリューム(C:) を利用するようになってしまいました。
デスクトップは長い間 256GB M.2 SSD (Samsung SSD 950 Pro) でやっていましたが、WSL2 にして残り 1.8MB になったためシステムボリュームを 1TB NVMe に差し替えました。 Crucial は 最近P2 が出ましたが、ちょっと試してみたかった P1 で。
https://www.crucial.jp/catalog/ssd/p1www.crucial.jp
なお、Windows.old を含めてゴミを消しても容量はすぐに埋まりきりがなくなったので仕方ない。
なお、Windows 10も入れなおして開発環境、WSL2を組みなおしたところ利用容量が 76.1GB になったので、まぁそんなものです。知ってた。(だから 256GB で過ごせていた) Windowsの入れ直しは、Media Creation Tool で Windows 10 May 2020 Update で USBブートを作るのが今も安定でした。
幸いなことに、 Docker Desktop for Windows をインストールすると WSL2 周りは一通り入ります。(Kernel のぞく)
そのため、これまで Enable-WindowsOptionalFeature
でインストールしていた Microsoft-Windows-Subsystem-Linux、Hyper-V は不要になりました。
脱Hyper-Vは、Windows 10 Home でも利用できるようになっていますし最高ですね。(Virtual Box とかも動くし)
WSL2 でも、現状は Ubuntu 18.04 を使っています。 折を見て Ubuntu 20.04 に切り替えていきますが、まずは変化を見たいので変えていません。
WSL1 と変わらず、WSL2 においても ansible を使って環境を構築しています。 私の場合は、Windows / macOS / Ubuntu を各種環境を利用するので、全環境に対してこのリポジトリの内容を当てています。
Ubuntu 18.04 においては、WSL1/WSL2であっても ansible で当てています。 Diff は次の通りです。
いくつか初期化回りの変更をメモしておきます。
docker は、WSL1 においては docker.io の公式同様に入れなおしていましたが、WSL2 においてはデフォルトから変更していません。
- - { role: "docker", tags: [docker] } + #- { role: "docker", tags: [docker] }
また、bashログイン時の起動も止めています。
- sudo -S cgroupfs-mount - sudo usermod -aG docker $USER - sudo service docker start - # wsl1 using windows docker-compose. wsl2 don't need this line. - # export DOCKER_HOST=tcp://localhost:2375
https://github.com/guitarrapc/dotfiles-linux/commit/db47ddf5c1ba8400acb502b256c8a03bbcb5749b
WSL2でdocker の入れ直しをやめたのは、docker の入れ直しを行うことで Windows 上の Docker for Windows のイメージと WSL2 上のイメージ一覧が同期されなくなったためです。(Windows はWindows、WSL2 の UbuntuはUbuntu と個別にイメージを持つようになってしまった。)
# この結果を Windows と WSL で共有する docker image ls
WSL2 を使うにあたって、Windows の状況がそのまま利用できるメリットを手放す理由は相応のものがない限り薄く、特に docker に関しては同じイメージが使えるのが最高なのでdocker の入れ直しはやめました。
当初wsl2 なら snapも行けるしと思って試していた形跡があります。が、結局 snap使っていません。(また使えるようにファイルは残しています) 実際 systemd/snapd を動かして、snap 経由でのインストールも可能になりましたが、以下の理由で辞めています。
wsl
や bash で Ubuntu に入ると Windows のパスのまま維持しますが、snap 対応を入れたスクリプトでのログインしなおしでパスが $HOME になってしまうsnapを使うことでバージョニングを楽にインストールをしたいと思ったのですが、なかなか難しいようです。 現状あんまり snap に頑張る気もないので、やめました、はい。
WSL2 は WSL1 同様に、標準では Windows のPATH が $PATH に入ってきます。
これにより、WSL2 上で code .
とすることで Remote WSL がVS Code で使えたりします。(~/docker.cfg も Windows の docker cred のパスが入っています)
Windows PATHがWSLで使えるのはすごく便利なのですが、WSL1 で Windows のパスとWSLのパスが競合してWSLでアプリ動作がおかしくなった経験があります。
そのため、 /etc/wsl.conf
でPATH を停止しています。
[interop] appendWindowsPath = False
wsl.conf をおいて、 wsl --shutdown
を実行することでWSL上で Windows のパスが入らなくなります。
$ echo $PATH /home/guitarrapc/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/guitarrapc/.dotnet/tools
おおむねWSL2 にして幸せになります。 ディスク容量は明らかに食うようになるので、私は割り切ってシステムボリュームを1TB まで増やしてわずらわしさを感じないようにしました。 ただ、ラップトップでなくても、PCのシステムドライブはそれほど大きくないことも多いので要注意な感じがあります。