✍️blog

技術系のこととか

プロキシ環境でWSLをインストールしたら設定しておきたいこと

日々、プロキシで消耗しているわけですが、
プロキシ環境下でWSLを使っているときにこの辺りは最低限設定するよなというところをまとめます。
一度設定したらしばらくは大丈夫なものがほとんどですが、いろんな理由で数カ月に一度はこのあたりの設定をしている気がする。。。

WSLのUbuntu 22.04を前提としています。

定番の環境変数設定

もはや言うまでもないであろうhttp_proxyの設定を行います。
$HOME/.bashrcとかに書いておくのが定番でしょうか。

export HTTP_PROXY="http://${プロキシサーバーIPやホスト名}:${ポート番号}"
export HTTPS_PROXY="http://${プロキシサーバーIPやホスト名}:${ポート番号}"

aptコマンドのプロキシ設定

aptコマンドは上記の環境変数を参照してくれず、個別に設定する必要があります。
/etc/apt/apt.confに以下の内容を追記します。

Acquire::http::Proxy http://${プロキシサーバーIPやホスト名}:${ポート番号};
Acquire::https::Proxy http://${プロキシサーバーIPやホスト名}:${ポート番号};

Dockerサービスにプロキシを設定

WSLを使う理由の一つにDockerを使いたいからというのも割とあるのかなと思います。
docker pullとかする時に利用されるプロキシを設定します。

まずは事前にsystemdを有効にします。
(dockerインストール前の方が良いかも...)
dockerの公式ドキュメントはsystemd前提?のような書き方になっているので
有効にすることでdockerのドキュメントに沿って設定できます。

docs.docker.jp

/etc/wsl.confへ以下を追記します。

[boot]
systemd=true

wsl --shutdownでwslを再起動します。

続いてdockerの設定を行います。

/etc/systemd/system/docker.service.d/override.confへ以下の内容を追記します。

[Service]
Environment = 'http_proxy=http://${プロキシサーバーIPやホスト名}:${ポート番号}' 'https_proxy=http://${プロキシサーバーIPやホスト名}:${ポート番号}'

以下のコマンドで設定を反映します。

sudo systemctl daemon-reload
sudo systemctl restart docker

docker info コマンドでプロキシが設定されているかが確認できます。

おまけ

ほかにも、pythonとかnode.jsとか作業される内容によっては設定すべきものはありそうですが、
最低限上記が設定できていればある程度の作業はできるのではないでしょうか。

ちなみに、以下のコマンドでWSL内でホスト側のIPを取得できます。

WIN_HOST_IP=$(cat /etc/resolv.conf | grep nameserver | cut -d' ' -f2)

ご活用くださいw

via GIPHY

vim9 scriptに対応するためにしたこと

vimプラグイン管理用にpathogen.vimとかvim-plugとか使っている方が多い?のかなと思いますが、
私は自作の簡易プラグイン管理スクリプトを書いて使っています。

動きは単純で設定ファイル通りにプラグインディレクトリへgit clone したりするだけの簡単なものなのですが、
当然遅延ロードなどのリッチな仕組みは用意していないので、起動までの時間が若干かかっていました。

vim9 scriptは公式ドキュメントによると
10倍から100倍の実行速度の向上が期待できます。とのことなのでvim9 scriptに書き直してみました。

その際にやったことをまとめます。

TL;DR

公式ドキュメントにVim scriptからの変更点がまとまっています。
正直これ読めば十分です。

vim-jp.org

vim-startuptime

vimの起動時間を計測するためには--startuptimeオプションを使えばよいのですが、複数回計測したりとか、時間のかかっている順にソートしたりとか
面倒なのですがそのあたりを一括でやってくれるツールとしてvim-startuptimeがあります。

github.com

Go製のツールで実行すると以下のように結果が出力されます。

このキャプチャだと、10回vimを起動させた際の 平均、最大、最小の起動時間と各スクリプトに読み込みにかかった時間が表示されています。

Before

vim scriptのままの状態で計測すると以下のような結果でした。

Total Average: 693.800000 msec
Total Max:     837.000000 msec
Total Min:     573.000000 msec

   AVERAGE        MAX        MIN
---------------------------------
602.000000 757.000000 475.000000: $HOME\_vimrc
588.400000 746.000000 463.000000: C:\Users\sabiz\vimfiles\conf\loader.vim
 21.000000  61.000000  15.000000: loading packages
 15.133333  25.000000  13.000000: C:\Users\sabiz\vimfiles\conf\plugin/molokai.vim
 12.933333  33.000000   8.000000: BufEnter autocommands
 11.666666  31.000000   9.000000: C:\Users\sabiz\vimfiles\pack\plugin\start\vim-lsp-settings\plugin\lsp_settings.vim
 10.200000  29.000000   7.000000: loading plugins
  5.533333  12.000000   5.000000: C:\Users\sabiz\vimfiles\pack\plugin\start\vim-gitgutter\plugin\gitgutter.vim
  5.066666   7.000000   4.000000: parsing arguments
  4.466666   8.000000   4.000000: C:\Program Files\Vim\vim90\syntax\syntax.vim

Top10までの抜粋しましたが、2番目に時間のかかっているloader.vimが今回vim9 scriptに書き換える対象です。
3番目との差は明らかですねw
作りが良くないという説もありますが、vim9 scriptに書き換えて速度アップをはかります。

vim9 scriptへ書き換え

vim scriptとvim9 scriptは同一のファイル内に共存することができるようです。
そのため今回は以下のようにして、vimのバージョンを確認し9以降であればvim9 scriptを呼び出すようにしました。
(vim9 scriptが有効かどうかだけを判定する方法はあるんだろうか?)

  if v:version >= 900
    call {vim9 script}
  else
    call {vim script}
  endif

書き換えの対象を以下の関数にします。
以下関数をvim9 script化します。

function! s:installAndUpdatePlugin() abort
  let job_list = []
  let idx = 0
  for k in s:plugin_names
    let clonePath = s:plugin_path . k
    if !isdirectory(clonePath)
      let cmd = 'git ' . 'clone https://github.com/' . g:plugin_list[idx] . ' ' . clonePath
      call echoraw("\x1b[33mNew:\x1b[0m\t".k."\n")
    elseif s:update_plugin
      let cmd = 'git --git-dir='.clonePath.'/.git pull origin'
      call echoraw("\x1b[33mUpdate:\x1b[0m\t".k."\n")
    else
      let cmd = 'git'
    endif
    let job = job_start(cmd, #{in_io: 'null', out_io: 'null', err_io: 'null'})
    call add(job_list, #{name: k, job: job, pos:idx})
    let idx += 1
  endfor
  call echoraw("\x1b[s") " Save cursor pos

  " Wait jobs
  while empty(job_list) == 0
    function! s:checkJobStatus(idx, val)
      let st = job_status(a:val.job)
      if st == 'dead'
        let info = job_info(a:val.job)
        if info.cmd[0] == 'git' " ignore
          return 0
        endif
        let exitval = info.exitval
        call echoraw("\x1b[u\x1b[".a:val.pos."A") " Restore cursor pos & Move cursor
        if exitval == 0
          call echoraw("\x1b[34mSuccess:\x1b[0m\t".a:val.name."\n")
        else
          call echoraw("\x1b[31mFailed:\x1b[0m\t".a:val.name."\n")
          echon " "
        endif
      endif
      return st !=# 'dead'
    endfunction
    call filter(job_list, function("s:checkJobStatus"))
  endwhile

endfunction

この関数はプラグインのリストを見て、
プラグインプラグインディレクトリになければgit cloneし既に存在し
アップデート設定が有効であればgit pullをjobで非同期に並列で行うようになっています。

関数定義

vim9 scriptでは関数はdefで定義します。

+ def! InstallAndUpdatePlugin()
- function! s:installAndUpdatePlugin() abort
...
+ enddef
- endfunction

※)diff形式のシンタックスにしています。

変数宣言

let ではなく var で宣言します。
また、代入する際にletを書く必要はありません。

+ var idx = 0
- let idx = 0
for k in s:plugin_names
...
+   idx += 1
-   let idx += 1
endfor

文字列の結合

.ではなく..を使用します。
vim scriptでも..使えたような気がするので、
変更点としては.での結合ができなくなったということでしょうか。

- 'git ' . 'clone https://github.com/' . g:plugin_list[idx] . ' ' . clonePath
+ 'git ' .. 'clone https://github.com/' .. g:plugin_list[idx] .. ' ' .. clonePath

コメント

"ではなく#を使います。

-   " Wait jobs
+  # Wait jobs

ラムダ式

元のvim scriptの方では使ってないのですが、
vim9 scriptにするにあたりインナー関数になっているところをラムダ式に変更しました。
vim scriptでは () -> {}というような書き方をするようです。

# vim9 scriptでの書き方
filter(job_list, (i, value) => {
...
})

終結

以上がvim9 scriptにするためにしたことです。
最終的に先ほどのvim scriptの関数は以下のようになりました。
変換+若干の処理変更が入っていますがほぼ同じ処理内容です。

def! InstallAndUpdatePlugin()
  var job_list = []
  var idx = 0
  for k in s:plugin_names
    var clonePath = s:plugin_path .. k
    var cmd = ''
    if !isdirectory(clonePath)
      cmd = 'git ' .. 'clone https://github.com/' .. g:plugin_list[idx] .. ' ' .. clonePath
      echoraw("\x1b[33mNew: " .. k .. "\x1b[0m")
      echoraw("\n")
    elseif s:update_plugin
      cmd = 'git --git-dir=' .. clonePath .. '/.git pull origin'
      echoraw("\x1b[33mUpdate: " .. k ..  "\x1b[0m")
      echoraw("\n")
    else
      continue
    endif
    var job = job_start(cmd, {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
    add(job_list, {'name': k, 'job': job, 'pos': idx})
    idx += 1
  endfor
  echoraw("\x1b[s") # Save cursor pos

  # Wait jobs
  while empty(job_list) == 0
    filter(job_list, (i, value) => {
      var st = job_status(value.job)
      if st == 'dead'
        var info = job_info(value.job)
        if info.cmd[0] == 'git' # ignore
          return false
        endif
        var exitval = info.exitval
        echoraw("\x1b[u\x1b[" .. value.pos .. "A") # Restore cursor pos & Move cursor
        if exitval == 0
          echoraw("\x1b[34mSuccess: " .. value.name .. "\x1b[0m")
          echoraw("\n")
        else
          echoraw("\x1b[31mFailed: " .. value.name .. "\x1b[0m")
          echoraw("\n")
          echon " "
        endif
      endif
      return st !=# 'dead'
    })
  endwhile
enddef

メインのロジックはほぼそのままで周辺の書き方を少しづつ変えた形ですね
めっちゃ楽でしたw

After

今回は高速化を狙ってvim9 scriptに書き換えていました。
vim9 script版で計測してみました。

Total Average: 113.066666 msec
Total Max:     119.000000 msec
Total Min:     110.000000 msec

  AVERAGE       MAX       MIN
------------------------------
35.466666 40.000000 34.000000: $HOME\_vimrc
23.333333 24.000000 22.000000: C:\Users\sabiz\vimfiles\conf\loader.vim
17.200000 19.000000 13.000000: loading packages
12.666666 13.000000 12.000000: C:\Users\sabiz\vimfiles\conf\plugin/molokai.vim
10.866666 13.000000  9.000000: BufEnter autocommands
 9.200000 10.000000  9.000000: C:\Users\sabiz\vimfiles\pack\plugin\start\vim-lsp-settings\plugin\lsp_settings.vim
 8.266666 10.000000  6.000000: loading plugins
 5.000000  5.000000  5.000000: C:\Users\sabiz\vimfiles\pack\plugin\start\vim-gitgutter\plugin\gitgutter.vim
 4.733333  6.000000  4.000000: parsing arguments
 3.533333  4.000000  3.000000: C:\Program Files\Vim\vim90\syntax\syntax.vim

以上のような結果でした。
対応前後で表にまとめると以下のような感じです。

項目 Before After
Total Average 693.8 ms 113.1 ms
Total Max 837.0ms 119.0 ms
Total Min 573.0ms 110.0 ms
loader.vim AVERAGE 588.4 ms 23.3 ms
loader.vim MAX 746.0 ms 24.0 ms
loader.vim MIN 463.0 ms 22.0 ms

うん、比較するのがバカバカしいほどに高速化されましたねw

※ちなみに、計測時は上記のスクリプトでいうところのgit clonepullも実行されないケースで試しています。
外部コマンド入れたらそれに依存した時間になりますからね。

今回vim9 scriptに書き換えたスクリプトは以下に置いています。
物好きな方はどうぞ参考にしてください。

github.com

まとめ

控えめに言ってvim9 script速えぇ
(今までが遅すぎたという見方はしちゃダメだ)

via GIPHY

Microsoft Storeにプロキシを設定する方法

社内のネットワークだとプロキシ必須というのはよくある話だと思いますが、
Windows10の場合設定からプロキシサーバーの設定(所謂、インターネットオプション)をしただけではMicrosoft Store(MS Store)はプロキシを利用してくれません。。。

また、個別にMS Storeの設定画面で設定できるわけでもありません。

以下のコマンドでプロキシを設定してやる必要があります。
MS Storeは内部的に WinHTTPを使用しているみたいなので
これでWinHTTPに対してプロキシの設定を行うことができます。

netsh winhttp set proxy proxy-server="{プロキシサーバーホスト名:ポート}"

WinHTTPはHTTPクライアントAPIのようなもので、
HTTPリクエストとかその辺をやりやすくするためのWindowsの機能で
IEとかEdgeとは分離されています。
正直、使ったことないので、詳しくはわかりませんけど。。。

learn.microsoft.com

ちなみに、Windows UpdateもこのWinHTTPを使用しています。
Windows Updateは社内NWだと一元管理されていたりするかと思いますが、
上記のプロキシの設定をするとWSUSサーバーと通信できなくなったりすることもあるようです。
そうすると、Windows Updateができなくなってしまいます。
learn.microsoft.com

WindowsUpdateができない場合は以下のコマンドでリセットすればプロキシの設定がもとに戻ります。

netsh winhttp reset proxy

# 設定の確認
netsh winhttp show proxy  

winhttpのプロキシ設定の存在を知っていれば、こんな問題は大したことないですけど
設定箇所が直感的じゃないと割とストレスですよね。。。

via GIPHY

WSLでネットワークが不調で外部と通信できないときにやったこと

WSLを使っていると何をきっかけにしたのか外部と通信できなくなることがあります。
感覚的にはスリープ明けに多い印象で、さっきまで通信できてたけど急にできなくなるというようなことは無いですかね。

そんな時に試したことをいくつか書いていきます。

ちなみに、外部と通信ができないとは、
curl https://example.com みたいなコマンドで名前解決が失敗しているような状態をさしています。
WSLはデフォルトだとホスト側IPがネームサーバーに設定されているので(/etc/resolv.conf)
ホスト側と通信できないためと思われます。
たぶん、WSLと通信するための仮想ネットワークアダプタが変になっているのでしょう。。。

WSLの再起動

定番ですかね。。。   コマンドプロンプトとかPowerShellから以下のコマンドを実行してWSLを終了させて、再度WSLを起動させます。
もちろん、コマンド実行前にWSLを開いている端末は閉じておく必要があります。

wsl --shutdown

ネットワークアダプターの再起動

以下のissueでコメントされている方法です。
管理者権限のあるPowershellで以下のコマンドを実行します。

github.com

echo "Restarting WSL Service"
Restart-Service LxssManager
echo "Restarting Host Network Service"
Stop-Service -name "hns"
Start-Service -name "hns"
echo "Restarting Hyper-V adapters"
Get-NetAdapter -IncludeHidden | Where-Object `
    {$_.InterfaceDescription.StartsWith('Hyper-V Virtual Switch Extension Adapter')} `
    | Disable-NetAdapter -Confirm:$False
Get-NetAdapter -IncludeHidden | Where-Object `
    {$_.InterfaceDescription.StartsWith('Hyper-V Virtual Switch Extension Adapter')} `
    | Enable-NetAdapter -Confirm:$False

PCの再起動

これも定番ですね。
感覚的にはこれで改善することが多い印象ですね。

WSLアップデート

Windows Update経由でアップデートされていることもありますが、
環境の問題でアップデートできていないこともあるので、以下のコマンドでアップデートを明示的に行います。
実施後には念のためPCの再起動をした方がよいかと思います。(WSLだけの再起動でもよいかも)

wsl --update

WSLのリセット/再インストール

最終手段ですw
当然のごとく、WSL内のデータは消えてしまうので事前にバックアップなどが必要です。
アプリからUbuntuやWSLを選んでアンインストールし、PC再起動後再度WSLをインストールします。

まとめ

WSLの再インストールまでやって改善しなかったことは無いので、
以上のいずれでも改善しないようならWSL以外の何かがおかしいです。(たぶん)

via GIPHY