Rider on Windows 開発環境構築 (コンテナだけWSL)
§ 概要
JetBrains社のRiderによる ASP.NETの開発環境を作成します。
まず、WSL(Ubuntu)環境を構築し、その上にDocker Engineを構築します。
さらに、Windows上にDocker CLIをインストールし、RiderからはそのDocker CLIを介して、WSL上のDocker Engineを操作します。
これにより、Linux環境で動作する.NETアプリケーションを、Windows単体で開発・デバグできることを目的としています。
また、Windows上にminikubeをインストールし、Kubernetes上の.NETアプリをデバグする方法や、docker-composeを使った構築も行っています。
なお、Rider on Windows 開発環境構築(全部WSL上)では、JetBrainsのGatewayを使用した全部WSL上で開発する方法で構築しています。
§ セットアップ手順
◆ お品書き
今回セットアップするものと記事執筆時のバージョンは以下の通りです。
名 | リビジョン |
---|---|
Windows 11 | 22H2 |
WSL2 | 1.00.00 |
Ubuntu | 22.04.01 LTS |
JetBrains Rider | 2022.3 EAP9 |
Docker CLI (Windows) | 20.10.21 |
Docker Engine (Linux) | 20.10.21 |
◆ Windowsの準備
OS
systemdに対応したWSLをインストールするため、OSはWindows11 22H2以降である必要があります。
仮想化可能かどうかの確認
以下の手順で、PCが仮想化可能かどうか調べます。
仮想化が無効になっていれば、Windowsを再起動し、PCのUEFIメニューから仮想化を有効にします(PCによりUEFIメニューの呼び出し方や、仮想化の有効方法が異なります)。
既存のWSLの無効化
既存のWSLが有効になっている場合は、Windowsの機能ダイアログを表示し、"Linux用Windowsサブシステム"を無効にします。
.NET SDK
.NET 6.0 SDKおよび.NET 7.0 SDKの最新版をインストールします。
◆ WSLインストール
Github上のmicrosoft/WSLページから、1.00.00のAssetsの"Microsoft.WSL_1.00.0.0_x64_ARM64.msixbundle"をダウンロードします。
そして、PowerShellを管理者モードで起動してインストールします。
> Add-AppxPackage Microsoft.WSL_1.00.0.0_x64_ARM64.msixbundle
◆ Windows Terminal
Ubuuntuをインストールする前に、Windows Terminalをインストールしておきます。
◆ Docker Desktopの設定
Docker Desktopをインストールしている場合は、"Enable integration with my default WSL distro"の設定を無効にしてください。
後からDocker Desktopをインストールする場合も同様です。
◆ Ubuntu-20.04
WSLコマンドによるインストール
Ubuntu 20.04 LTSをインストールします。
> wsl --install Ubuntu-20.04
途中、Ubuntuコンソールが起動し、デフォルトで使用するユーザアカウント、パスワードを聞かれるので入力します。ここで入力するUNIXユーザアカウントは、Windowsのユーザアカウントと一致する必要はありません (下記の例では、UNIXユーザアカウントは"scott"にしています)。
Installing, this may take a few minutes...
Please create a default UNIX user accout. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: scott # 任意のアカウント名
New password: **** # 上記アカウントのパスワード
Retype new password: **** # 確認のためもう一度
wsl.conf ファイルの設定
WSL用の設定ファイルを作成するために、エディタを起動します。
$ sudo nano /etc/wsl.conf # wsl.confファイルを新規作成
[boot]
systemd = true
[network]
generateResolvConf = false
[interop]
appendWindowsPath = false
[user]
default = scott
各項目の説明です。
- systemd(true)は、PID:1でsystemdプロセスを起動させるためのオプションです。これにより、systemctlコマンドが動作するようになり、デーモンの管理などが楽になります。
- generateResolvConf(false)は、/etc/resolv.confファイルを起動時に自動更新させないようにします。これは、DNSによる名前解決できない不具合を回避するためのものです。/etc/resolv.confファイルは、後で手動で作成します。
- appendWindowsPath(false)は、PATH変数にWindowsのPathを引き継がないようにするものです。
- default(管理ユーザアカウント)は、ログイン時のユーザを指定するものです。ログイン時のユーザはレジストリにも書き込まれますが、ファイルのバックアップなどをおこなった際にその情報が失われてしまうため、明示的に指定します。
wsl.confの設定を反映させるために、exitコマンドでいったんUbuntuコンソールを終了します。
$ exit # Ubuntuから抜ける
logout
Powershellを起動し、WSLを再起動します。
> wsl --shutdown # WSLをシャットダウン
> wsl -d Ubuntu-20.04 # WSLを起動
DNS設定ファイルの作成
/etc/resolv.confファイルを作成します。
$ sudo rm -f /etc/resolv.conf # 念のため古いものを削除
$ sudo nano /etc/resolv.conf # 新規作成
nameserver 8.8.8.8
google.comへのpingが通れば成功です (結果内のアドレス等は実行環境依存です)。
$ ping google.com -c 1
PING google.com (172.217.161.78) 56(84) bytes of data.
64 bytes from nrt20s20-in-f14.1e100.net (172.217.175.78): icmp_seq=1 ttl=115 time=34.1 ms
最新状態に更新
Ubuntu 20.04を最新状態にした後、いったん、WSLを終了させます。
$ sudo apt update
...(略)...
$ sudo apt full-upgrade -y
...(略)...
$ exit
Logout
> wsl --shutdown # WSLをシャットダウン
◆ ディストリビューション名の変更
将来的にWSL上に別のUbuntuサーバーを構築することを考え、ディストリビューション名の"Ubuntu-20.04"を変更します。
まず、今の"Ubuntu-20.04"ディストリビューションのバックアップを作成します (バックアップ先のパスとファイル名は適当に付けてください)。
> wsl --export "Ubuntu-20.04" D:\backup\backup.tar
ディストリビューションを格納するディレクトリを作成します。下の例では、ユーザーフォルダー直下にwslimagesというディレクトリを作成しています。
> mkdir $Env:USERPROFILE\wslimages
次に、作成したバックアップイメージを読み込みます。wsl --importの各引数の意味は順番に以下の通りです(backendは例ですので、任意の名前にしてください)。
- 新しいディストリビューション名 (下記の例ではbackend)
- ディストリビューションのイメージファイル (下記の例では$Env:USERPROFILE\wslimages\backend)
- wsl --exportコマンドで作成したバックアップイメージ
> wsl --import "backend" $Env:USERPROFILE\wslimages\backend D:\backup\backup.tar
wslコマンドでは、起動するディストリビューションを"-d <<ディストリビューション名>>"で指定できます。
しかし、毎回入力するのは面倒なので、"-d"オプションを省略したときのデフォルトのディストリビューションを指定することができます。
以下のコマンドで、デフォルトのディストリビューションを指定します。
> wsl --set-default "backend"
作成したバックアップファイルはもう不要ですので、削除してもかまいません。
> rm D:\backup\backup.tar
◆ Ubuntu 22.04にアップグレード
do-release-upgrade
Ubuntuも最新のLTSである22.04にアップグレードします。
まず、Windows Terminalで作成したUbuntuのディストリビューションを起動します。
立ち上がったら、do-release-upgradeコマンドで、OSをアップグレードします。
なお、途中画面が切り替わり、"Restart services during package upgrades without asking?"と聞かれたら"Yes"と答えておきます。
$ sudo do-release-upgrade # 最新のディストリビューションに更新
...(略)...
Installing the upgrade can take several hours. Once the download has
finished, the process cannot be canceled.
Continue [yN] Details [d] y # 処理を続行するか聞かれるのでyを入力
Fetching
...(略)...
Building dependency tree
Reading state information... Done
Searching for obsolete software
Reading state information... Done
Remove obsolete packages?
70 packages are going to be removed.
Continue [yN] Details [d] y # 使わないパッケージ消していいか聞かれるのでyを入力
...(略)...
System upgrade is complete.
Action required
Exit all other instances of Ubuntu WSL before continuing.
Unsaved progress may otherwise be lost.
To continue please press [ENTER] # ENTERキーを入力
WSL restart required
Exit this instance of Ubuntu WSL.
The upgrade will then be complete.
To continue please press [ENTER] # ENTERキーを入力
...(略)...
$ exit # いったんUbuntuから抜ける
ここで、WSLを再起動します。Windows TerminalでPowerShellを開き、以下のコマンドを実行します。
> wsl --shutdown # WSLをいったん終了
(終了後、Windows TerminalでUbuntu立ち上げ)
◆ systemdサービスの不具合対応
systemdを有効にしただけでは、起動に失敗するサービスがいくつかあります。その設定を変更します。なお、"systemctl --failed"コマンドを実行することで、起動に失敗したサービスを調べることができます。
$ systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
* systemd-remount-fs.service loaded failed failed Remount Root and Kernel File Systems
* systemd-sysusers.service loaded failed failed Create System Users
systemd-remount-fs.service
Ubuntuをインストールした際に、通常、ルートのファイルシステムには"cloudimg-rootfs"が付けられるのですが、WSLの場合にはこのラベルが付きません。そのため、systemd-remount-fs.serviceの起動に失敗します。
$ cat /etc/fstab
LABEL=cloudimg-rootfs / ext4 defaults 0 0
ルートファイルシステムにこのラベルを付けることで、エラーを回避します。
まず、"/"をマウントしているデバイスを調べます。以下の結果の場合、デバイスは"/dev/sdc"です(WSLがインストールされている環境により値は異なります)。
$ mount | grep ext4
/dev/sdc on / type ext4 (rw,relatime,discard,errors=remount-ro,data=ordered)
...(略)...
以下のコマンドでラベル名を付けます。
$ sudo e2label /dev/sdc cloudimg-rootfs
systemd-sysusers.service
これは、/usr/lib/systemd/system/systemd-sysusers.service 内のLoadCredentialでWSLでロードされていないモジュールを使用するオプションが指定されているのが原因です。
# Optionally, pick up a root password and shell for the root user from a
# credential passed to the service manager. This is useful for importing this
# data from nspawn's --set-credential= switch.
LoadCredential=passwd.hashed-password.root
LoadCredential=passwd.plaintext-password.root
LoadCredential=passwd.shell.root
直接このファイルを修正するのではなく、以下のコマンドで上書きするオプションを記述します。
$ sudo systemctl edit systemd-sysusers.service
"Service"と"LoadCredential="の二行を追加します。追加する場所は、必ず"### Anything~"と"### Lines below this~"の間に記述してください。
### Editing /etc/systemd/system/systemd-sysusers.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
[Service]
LoadCredential=
### Lines below this comment will be discarded
◆ NVIDIA CUDAドライバーの不具合対応
Windows側でNVIDIAドライバーを使用している場合、グラフィックドライバーがうまくロードできない不具合が発生します。
これを回避するために、以下の対策を行います。なお、ビデオドライバーを更新すると、libcuda.soが再インストールされる可能性があり、その場合はこの作業をもう一度行う必要があります。
libcuba.so.1の不具合回避
WSLの不具合を以下の手順で回避します。
まず、PowerShellを管理者として実行します。
まず、シンボリックリンクになっているかどうかを確認します。下のように、libcuda.soとlibcuda.so.1がシンボリックリンクでは無いためエラーが発生します。
PS> ls C:\Windows\System32\lxss\lib
Directory: C:\Windows\System32\lxss\lib
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2022/11/13 21:23 149912 libcuda.so
-a--- 2022/11/13 21:23 149912 libcuda.so.1
-a--- 2022/11/13 21:23 149912 libcuda.so.1.1
エラーの原因であるファイルをシンボリックリンクに変更します。
PS> cd C:\Windows\System32\lxss\lib
PS> rm libcuda.so
PS> rm libcuda.so.1
PS> New-Item -Value libcuda.so.1.1 -Path . -Name libcuda.so -ItemType SymbolicLink
PS> New-Item -Value libcuda.so.1.1 -Path . -Name libcuda.so.1 -ItemType SymbolicLink
PS> ls
Directory: C:\Windows\System32\lxss\lib
Mode LastWriteTime Length Name
---- ------------- ------ ----
la--- 2022/11/17 18:54 0 libcuda.so -> libcuda.so.1.1
la--- 2022/11/17 18:54 0 libcuda.so.1 -> libcuda.so.1.1
-a--- 2022/11/13 21:23 149912 libcuda.so.1.1
Ubuntu側でエラーの原因となるパッケージを再インストールし、WSLを再起動します。
$ sudo apt reinstall libc-bin
(この後、Ubuntuを再起動)
◆ Docker
Docker Engineをインストールします。
GPGキー追加
公式マニュアルにならい、まず、Dockerの公式GPGキーを追加します。
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
aptリポジトリへの追加
Dockerリポジトリをインストール用ソースに追加します(アーキテクチャ(amd64)、Ubuntuバージョン(jammy)は固定で書いてしまっています)。
$ echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list
aptコマンドでDocker Engineをインストールします。
$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
接続証明書作成
DockerEngineに接続するための証明書を生成します。
まず、証明書作成の作業するディレクトリに移動します。
$ mkdir -p ~/.docker
$ cd ~/.docker
サーバー証明書とクライアント証明書を発行する認証局を作成します。途中入力するパスフレーズはそれぞれの証明書に署名するときに使用します。
$ openssl genrsa -aes256 -out ca-key.pem 4096
Enter PEM pass phrase: ****
Verifying - Enter PEM pass phrase: ****
$ openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem: ****
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Hokkaido
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:For Test
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
サーバー証明書を発行します。ca-key.pemのパスフレーズは、認証局を作成したときのパスフレーズを入力してください。
$ openssl genrsa -out server-key.pem 4096
$ openssl req -subj "/CN=localhost" -sha256 -new -key server-key.pem -out server.csr
$ echo subjectAltName = DNS:localhost,IP:127.0.0.1 >> extfile.cnf
$ echo extendedKeyUsage = serverAuth >> extfile.cnf
$ openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Certificate request self-signature ok
subject=CN = localhost
Enter pass phrase for ca-key.pem: ****
クライアント証明書を発行します。ca-key.pemのパスフレーズは、認証局を作成したときのパスフレーズを入力してください。
$ openssl genrsa -out key.pem 4096
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf
$ openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Certificate request self-signature ok
subject=CN = client
Enter pass phrase for ca-key.pem: ****
不要なファイルを消し、秘密鍵と公開鍵のパーミッションを適切なものに変更します。
$ rm client.csr server.csr extfile.cnf extfile-client.cnf
$ chmod 0400 ca-key.pem key.pem server-key.pem
$ chmod 0444 ca.pem server-cert.pem cert.pem
認証局の公開鍵と、サーバー証明書の公開鍵と秘密鍵を、rootの.dockerディレクトリにコピーします。
$ sudo mkdir /root/.docker
$ sudo cp ca.pem server-cert.pem server-key.pem /root/.docker
$ sudo chown -R root:root /root/.docker
認証局の公開鍵と、クライアント証明書の公開鍵と秘密鍵を、Windows側のホームディレクトリ下の.dockerディレクトリにコピーします。なお、<<Windowsのユーザ>>は、この作業を行っているユーザのWindows上のアカウント名です。(つまりは、ユーザーのホームディレクトリ)。
$ mkdir -p /mnt/c/Users/<<Windowsのユーザ>>/.docker
$ cp ca.pem cert.pem key.pem /mnt/c/Users/<<Windowsのユーザ>>/.docker
設定変更
Windows側からリモートでDocker Engineを操作するために待ち受けポートを追加します。
$ sudo systemctl edit docker.service
"### Lines below this comment will be discard"の前に、以下の設定を追加します。
### Anything between here and the comment below will become the new contents of the file
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --containerd=/run/containerd/containerd.sock \
--tlsverify \
--tlscacert=/root/.docker/ca.pem \
--tlscert=/root/.docker/server-cert.pem \
--tlskey=/root/.docker/server-key.pem
### Lines below this comment will be discarded
一般ユーザーでの実行
sudo無しでdockerを起動させるために、システムグループ"docker"を追加し、今ログイン中のユーザをそのグループに追加します。追加後、いったん再起動します。
$ sudo adduser $USER docker
$ sudo usermod -aG docker $USER
(Ubuntu再起動)
インストール確認
Docker Engineが正常にインストールできたかどうか、以下のコマンドで確認できます。
"Server: Docker Engine"が表示されていれば、設定成功です。
$ docker -H tcp://127.0.0.1:2376 --tlsverify version
Client: Docker Engine - Community
Version: 20.10.21
API version: 1.41
Go version: go1.18.7
Git commit: baeda1f
Built: Tue Oct 25 18:01:58 2022
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.21
API version: 1.41 (minimum version 1.12)
Go version: go1.18.7
Git commit: 3056208
Built: Tue Oct 25 17:59:49 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.10
GitCommit: 770bd0108c32f3fb5c73ae1264f7e503fe7b2661
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
◆ Chocolatey
Windows用パッケージマネージャのChocolateyをインストールします。
PowerShellを管理者モードで起動し、以下のコマンドを実行します。
> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
インストールが完了したら、いったん、PowerShellを閉じます。
◆ Docker-CLI
chocolateyによるインストール
Windows用のdockerコマンドをインストールします。
PowerShellを管理者モードで起動し、以下のコマンドを実行します。
> choco install docker-cli -y
Chocolatey v1.2.0
Installing the following packages:
docker-cli
By installing, you accept licenses for the packages.
Progress: Downloading docker-cli 20.10.21... 100%
docker-cli v20.10.21 [Approved]
docker-cli package files install completed. Performing other installation steps.
ShimGen has successfully created a shim for docker.exe
The install of docker-cli was successful.
Software installed to 'C:\ProgramData\chocolatey\lib\docker-cli'
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
環境変数設定
WindowsからWSL内のDocker Engineにアクセスするためには、以下の環境変数を設定しておきます。
> [Environment]::SetEnvironmentVariable("DOCKER_HOST", "tcp://localhost:2376", [EnvironmentVariableTarget]::User)
> [Environment]::SetEnvironmentVariable("DOCKER_TLS_VERIFY", "1", [EnvironmentVariableTarget]::User)
設定を反映させるために、PowerShellをいったん終了します。
◆ 開発用自己署名証明書作成
.NET開発で使用する自己署名証明書を作成します。PowerShellで以下のコマンドを実行します。
なお、ここで入力したパスワードは、プロジェクト作成毎に必要となります。
> cd ~
> mkdir certificates
> cd certificates
> dotnet dev-certs https -ep localhost.pfx -p <<任意のパスコード>>
> dotnet dev-certs https -ep localhost.crt --format pem
◆ Skaffold
インストール
ビルドツールSkaffoldをchocoを使ってインストールします。
> choco install skaffold -y
Chocolatey v1.2.0
Installing the following packages:
skaffold
By installing, you accept licenses for the packages.
Progress: Downloading skaffold 2.0.2... 100%
skaffold v2.0.2 [Approved]
skaffold package files install completed. Performing other installation steps.
Progress: 100% - Completed download of C:\ProgramData\chocolatey\lib\skaffold\tools\skaffold.sha256 (93 B).
Download of skaffold.sha256 (93 B) completed.
Downloading skaffold 64 bit
from 'https://github.com/GoogleContainerTools/skaffold/releases/download/v2.0.2/skaffold-windows-amd64.exe'
Progress: 100% - Completed download of C:\ProgramData\chocolatey\lib\skaffold\tools\skaffold-windows-amd64.exe (68.39 MB).
Download of skaffold-windows-amd64.exe (68.39 MB) completed.
Hashes match.
C:\ProgramData\chocolatey\lib\skaffold\tools\skaffold-windows-amd64.exe
Added C:\ProgramData\chocolatey\bin\skaffold.exe shim pointed to '..\lib\skaffold\tools'.
ShimGen has successfully created a shim for skaffold.exe
The install of skaffold was successful.
Software install location not explicitly set, it could be in package or
default install location of installer.
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
これで、C:\ProgramData\chocolatey\bin\skaffold.exe がインストールされました。
◆ git
インストール
git CLIをchocoを使ってインストールします。
> choco install git -y
Chocolatey v1.2.0
Installing the following packages:
git
By installing, you accept licenses for the packages.
Progress: Downloading git.install 2.38.1... 100%
Progress: Downloading git 2.38.1... 100%
git.install v2.38.1 [Approved]
git.install package files install completed. Performing other installation steps.
The package git.install wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Note: To confirm automatically next time, use '-y' or consider:
choco feature enable -n allowGlobalConfirmation
Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint):
Timeout or your choice of '' is not a valid selection.
Exiting chocolatey abnormally. Please manually clean up anything that
was not finished.
PS C:\Users\kodama> choco install git -y
Chocolatey v1.2.0
Installing the following packages:
git
By installing, you accept licenses for the packages.
git v2.38.1 [Approved]
git package files install completed. Performing other installation steps.
The install of git was successful.
Software installed to 'C:\ProgramData\chocolatey\lib\git'
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
◆ minikube
インストール
Kubernetes実行環境Minikubeをchocoを使ってインストールします。なお、インストール時にKubernetesのCLI (kubectl) も同時にインストールされます。
> choco install minikube -y
Chocolatey v1.2.0
Installing the following packages:
minikube
By installing, you accept licenses for the packages.
Progress: Downloading Minikube 1.28.0... 100%
kubernetes-cli v1.25.4 [Approved]
kubernetes-cli package files install completed. Performing other installation steps.
The package kubernetes-cli wants to run 'chocolateyInstall.ps1'.
Extracting 64-bit C:\ProgramData\chocolatey\lib\kubernetes-cli\tools\kubernetes-client-windows-amd64.tar.gz to C:\ProgramData\chocolatey\lib\kubernetes-cli\tools...
C:\ProgramData\chocolatey\lib\kubernetes-cli\tools
Extracting 64-bit C:\ProgramData\chocolatey\lib\kubernetes-cli\tools\kubernetes-client-windows-amd64.tar to C:\ProgramData\chocolatey\lib\kubernetes-cli\tools...
C:\ProgramData\chocolatey\lib\kubernetes-cli\tools
ShimGen has successfully created a shim for kubectl-convert.exe
ShimGen has successfully created a shim for kubectl.exe
The install of kubernetes-cli was successful.
Software installed to 'C:\ProgramData\chocolatey\lib\kubernetes-cli\tools'
Minikube v1.28.0 [Approved]
minikube package files install completed. Performing other installation steps.
ShimGen has successfully created a shim for minikube.exe
The install of minikube was successful.
Software installed to 'C:\ProgramData\chocolatey\lib\Minikube'
Chocolatey installed 2/2 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
これで、 C:\ProgramData\chocolatey\bin\kubectl.exe と C:\ProgramData\chocolatey\bin\minikube.exe がインストールされました。
minikube初期化
PowerShellでminikubeを初期化します。PowerShellで以下のコマンドを実行します。
> minikube start
😄 Microsoft Windows 11 Enterprise 10.0.22623 Build 22623 上の minikube v1.28.0
❗ Kubernetes 1.25.0 has a known issue with resolv.conf. minikube is using a workaround that should work for most use cases.
❗ 追加の詳細情報はこちらを参照してください: https://github.com/kubernetes/kubernetes/issues/112135
🆕 Kubernetes 1.25.3 が利用可能です。アップグレードしたい場合、--kubernetes-version=v1.25.3 を指定してください
✨ 既存のプロファイルを元に、docker ドライバーを使用します
👍 minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
🚜 ベースイメージを取得しています...
🤷 docker 「 minikube 」 container がありません。再生成します。
🔥 docker container (CPUs=2, Memory=1984MB) を作成しています...
❗ 外部 Docker ホスト localhost 上で 0.0.0.0 をリッスンしています。ご承知おきください
🐳 Docker 20.10.17 で Kubernetes v1.25.0 を準備しています...
🔎 Kubernetes コンポーネントを検証しています...
▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
🌟 有効なアドオン: storage-provisioner, default-storageclass
🏄 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました
途中、"❗ Kubernetes 1.25.0 has a known issue with resolv.conf. minikube is using a workaround that should work for most use cases."、"🆕 Kubernetes 1.25.3 が利用可能です。アップグレードしたい場合、--kubernetes-version=v1.25.3 を指定してください"というメッセージが出た場合は、kubernetesに不具合があるバージョンですので、いったん、minikubeを停止し、"--kubernetes-version"オプションを付けて、起動します。
minikubeを停止します。
> minikube stop
✋ 「minikube」ノードを停止しています...
🛑 SSH 経由で「minikube」の電源をオフにしています...
🛑 1 台のノードが停止しました。
kubernetesのバージョンを指定して、minikubeの起動を行います。なお、次回以降はバージョン指定は不要です (今回指定した1.25.3が使用されます)。
> minikube start --kubernetes-version=1.25.3
😄 Microsoft Windows 11 Enterprise 10.0.22623 Build 22623 上の minikube v1.28.0
✨ 既存のプロファイルを元に、docker ドライバーを使用します
👍 minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
🚜 ベースイメージを取得しています...
🔄 「minikube」のために既存の docker container を再起動しています...
🐳 Docker 20.10.17 で Kubernetes v1.25.3 を準備しています...
🤦 クラスターを再起動できません (リセットします): apiserver healthz: apiserver process never appeared
▪ 証明書と鍵を作成しています...
▪ コントロールプレーンを起動しています...
▪ RBAC のルールを設定中です...
🔎 Kubernetes コンポーネントを検証しています...
▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
🌟 有効なアドオン: storage-provisioner, default-storageclass
🏄 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました
◆ JetBrains Rider
インストール
まず、JetBrains Toolboxをインストールします。
インストール後、Toolboxを起動し、入社可能内にあるRiderのメニューから入手可能バージョンを選択します。
バージョン内から、"2022.3 EAP9"を選びインストールします。
インストール完了後、"Install JetBrains ETW Host Service"をインストールするかどうか聞かれますので、"Apply"をクリックします。
起動
ToolboxからRiderを起動します。初回起動時にUSER AGREEMENTが表示されますので、"Continue"をクリックします。
また、JetBrainsのライセンスがあればライセンスの登録を行ってください。
設定
- Riderから接続するDocker Engineの設定
設定 | 値 |
---|---|
Name | (任意) |
Connect to Docker daemon with: | WSL |
WSL | backend |
- Docker CLIのパス指定
設定 | 値 |
---|---|
Docker executable | C:\ProgramData\chocolatey\bin\docker.exe |
Use compose V2 | チェックする |
- CloudCodeの設定
設定 | 値 |
---|---|
Cloud SDK | Allow the plugin to manage and install the Cloud SDK |
automatically update the SDK | チェックする |
Deployment Tools | Use custom specified dependencies |
Path to Skaffold executable | C:\ProgramData\chocolatey\bin\skaffold.exe |
Path to Kubectl executable | C:\ProgramData\chocolatey\bin\kubectl.exe |
Path to Minikube executable | C:\ProgramData\chocolatey\bin\minikube.exe |
§ サンプルプロジェクト
◆ 準備
新規ソリューション作成
サンプルとして、ASP.NETのWebAPIアプリを作成します。
Riderを起動し、New Solutionを選択し、.NET > ASP.NET Core Web Applicationを選択します。
以下の内容でプロジェクトを作成します。
項目名 | 値 |
---|---|
Solution name | apisample |
Project name | apisample |
Solution directory | C:\Users<Windowsのアカウント>\RiderProjects |
SDK | 6.0 or 7.0 |
Type | Web API |
Language | C# |
Auth | No authentication |
Docker Support | Linux |
このテンプレート(ASP.NET Core Web Application)は、API (/weatherforecast) を呼び出すと、5件の日付、気温、天気を示すJsonを返すというサンプルが自動的に生成されます。
◆ スタンドアローン
初期状態では、コンテナを使用しないで、.NET内部のWeb Server (Kestrel) が有効になっている設定が用意されています。
実行とデバグ
まず、テストのためControllerのところにブレークポイントを設定します。
Controllers/WeatherForecastController.csを開き、Get()メソッドにブレークポイントを設定します。
そして、デバグ開始ボタンを押すと、デバグ実行が開始されます。
SwaggerのUIが表示されたら、"GET" > "Try it" > "Execute"の順にクリックします。
すると、先ほど指定したブレークポイントで停止するはずです (左側のResume Programを押すと実行が再開されます)。
◆ Docker: Dockerfile
このセクションでは、Dockerコンテナで.NETアプリケーションを起動してみます。
証明書コピー
以前作成した開発用自己署名証明書をソリューション下のプロジェクトディレクトリにコピーします。
$ cp ~/certificates/localhost.pfx ~/RiderProjects/apisample/apisample
実行構成
Dockerfile用の実行構成はデフォルトでは用意されませんので、新規に追加します。
実行メニューからEdit configuration...を選択します。
左上端の"+"をクリックし、Docker > Dockerfileの構成を追加します。
まず、Build横のModify optionsのContext folderを有効にします。
そして、Context folderにプロジェクトのルートディレクトリ(/home/scott/RiderProjects/apisample)を指定します (Context folderには"."と表示されます)。
そして、以下のように値を設定します。
Field | Value | Memo |
---|---|---|
Name | Docker(WSL) | 構成メニュー一覧に表示される名前です |
Dockerfile | apisample\Dockerfile | |
Image tag | apisample | docker imagesコマンドを実行したときに分かりやすくなります |
Container name | apisample | docker psコマンドを実行したときに分かりやすくなります |
そして、Run横のModifyメニューからBind portsを選び、以下のポートを入力します。なお、Host port側の値は下の例では5000, 5001になっていますが、別に、1024以上の任意の値ならなんでも構いません。
Host port | Container port | Protocol |
---|---|---|
5000 | 80 | tcp |
5001 | 443 | tcp |
最終的には、以下のような設定になります。
Dockerfile
テンプレートによってDockerfileが自動的に生成されています。
このDockerfileに対して、以下の点を修正します。
- https接続のための証明書をビルド用にコピー (COPY localhost.pfx)
- DockerのコンテキストをDockerfileのあるディレクトリから、一つ親のディレクトリに変更したことによるかCOPYコマンドのパスの変更 (各COPY)
- コンテナイメージ内で証明書をインポート (dotnet dev-certs --import)
- dotnet buildとdotnet publishのConfiguraitonを"Release"から"Debug"に変更
- ASPNETCORE_ENVIRONMENTとASPNETCORE_URLS環境変数の追加
- dotnet buildでインポートされた証明書データのコピー (COPY cryptography/x509stores)
修正した結果は、以下の通りです。
なお、<<パスワード>>の部分には、開発用自己署名証明書作成で入力したパスワードを指定します。
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["apisample/apisample.csproj", "apisample/"]
RUN dotnet restore "apisample/apisample.csproj"
COPY ["apisample/localhost.pfx", "apisample/"]
COPY ["apisample/", "apisample/"]
WORKDIR "/src/apisample"
RUN dotnet dev-certs https --clean --import localhost.pfx -p <<パスワード>>
RUN dotnet build "apisample.csproj" -c Debug -o /app/build
FROM build AS publish
RUN dotnet publish "apisample.csproj" -c Debug -o /app/publish
FROM base AS final
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT "Development"
ENV ASPNETCORE_URLS "https://+:443;http://+:80"
COPY /root/.dotnet/corefx/cryptography/x509stores/my/* /root/.dotnet/corefx/cryptography/x509stores/my/
COPY /app/publish .
ENTRYPOINT ["dotnet", "apisample.dll"]
ビルドと実行
構成を今回作成した実行構成("Docker(WSL)")にしてデバグボタンを押すと、ビルドと実行が開始されます。なお、実行するには、DockerEngineをインストールしたWSLが起動している必要があります。
アクセス先は、"https://localhost:5001/swagger/index.html" になります。
なお、スタンドアローン環境と同様にブレークポイントを設定するなどのデバグを行うことも可能です。
WSL側からの確認
dockerコマンドを使用することで、コンテナの動作を確認することもできます。
まず、docker imagesで、apisampleイメージがビルドされていることが確認できます。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
apisample latest 26ae20867dff 3 minutes ago 212MB
mcr.microsoft.com/dotnet/sdk 6.0 0ff04a23cb9e 2 days ago 737MB
mcr.microsoft.com/dotnet/aspnet 6.0 33a9c85ed2f6 2 days ago 208MB
s
また、docker psで、コンテナが起動していることが確認できます (デバグ中に試してください)。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34570a50a11c 26ae20867dff "/riderDebugger/linu…" 4 minutes ago Up 4 minutes 0.0.0.0:5000->80/tcp, :::5000->80/tcp, 0.0.0.0:5001->443/tcp, :::5001->443/tcp, 0.0.0.0:57000->57100/tcp, :::57000->57100/tcp, 0.0.0.0:57200->57300/tcp, :::57200->57300/tcp apisample
◆ Cloud Code: Kubernetes
このセクションでは、Cloud Codeプラグインを使って、Kubernetes上のコンテナとしてプログラムを動作させます。なお、この設定を行う際には、Docker: Dockerfileで作成したDockerfileが必要です。
minikube
Cloud Code: Kubernetesをローカルで実行するためには、minikubeを動作させておきます。
> minikube start
skaffold init
最初にskaffold用の設定ファイルを作成します。PowerShellを開き、プロジェクトディレクトリでskaffold initコマンドを実行します (javaがインストールされていない場合は警告が出ますが無視してください)。
> cd ~\RiderProjects\apisample
> skaffold init --generate-manifests
time="2022-11-22T23:59:59+09:00" level=warning msg="Skipping Jib: no JVM: [java -version] failed: exec: \"java\": executable file not found in %PATH%" subtask=-1 task=DevLoop
skaffoldファイルの生成元としてDockerを選択します。カーソルでDockerを選び、スペースキーを押してからEnterを押します。
? Which builders would you like to create kubernetes resources for? [Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
> [ ] Buildpacks (sample1/sample1.csproj)
> [x] Docker (sample1/Dockerfile)
kubernetesを開くポートを聞かれますので空白のままにします。
? Select port to forward for sample1 (leave blank for none):
skaffold.yamlに書き込まれる内容が表示され、実際に書き込むか聞かれますので"y"を入力します。
apiVersion: skaffold/v4beta1
kind: Config
metadata:
name: apisample
build:
artifacts:
- image: apisample
context: apisample
docker:
dockerfile: Dockerfile
manifests:
rawYaml:
- apisample\deployment.yaml
apisample\deployment.yaml - apiVersion: v1
kind: Service
metadata:
name: apisample
labels:
app: apisample
spec:
clusterIP: None
selector:
app: apisample
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apisample
labels:
app: apisample
spec:
replicas: 1
selector:
matchLabels:
app: apisample
template:
metadata:
labels:
app: apisample
spec:
containers:
- name: apisample
image: apisample
? Do you want to write this configuration, along with the generated k8s manifests, to skaffold.yaml? (y/N) y
sample1\deployment.yamlとskaffold.yamlが生成された旨が表示されます。
Generated manifest apisample\deployment.yaml was written
Configuration skaffold.yaml was written
You can now run [skaffold build] to build the artifacts
or [skaffold run] to build and deploy
or [skaffold dev] to enter development mode, with auto-redeploy
skaffold.yaml修正
出力されたskaffold.yamlがそのままでは動作しないので、以下の点を変更します。
なお、エクスプローラウィンドウ上、Solutionモードではskaffold.yamlが表示されないので、File Systemモードにします。
変更点は以下の通りです。
- Dockerを実行するContextを、apisampleディレクトリではなく一つ上のソリューション全体のディレクトリにしているので、その指定部分であるContextとdockerfileを変更します
apiVersion: skaffold/v4beta1
kind: Config
metadata:
name: apisample
build:
artifacts:
- image: apisample
context: .
docker:
dockerfile: apisample\Dockerfile
manifests:
rawYaml:
- apisample\deployment.yaml
deployment.yaml修正
apisample内のdeployment.yamlを修正します。
Docker用のdeployment.yamlからの変更点は以下の通りです。
- デバグ用のSSHポートとして、Deploymentのポートに22を追加
- Serviceのportsに5022:22のマッピングを追加
apiVersion: v1
kind: Service
metadata:
name: apisample
labels:
app: apisample
spec:
type: ClusterIP
clusterIP: None
selector:
app: apisample
ports:
- port: 5100
targetPort: 80
name: http
- port: 5143
targetPort: 443
name: https
- port: 5022
targetPort: 22
name: dotnet-debug
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apisample
labels:
app: apisample
spec:
replicas: 1
selector:
matchLabels:
app: apisample
template:
metadata:
labels:
app: apisample
spec:
containers:
- name: apisample
image: apisample
ports:
- containerPort: 443
- containerPort: 80
- containerPort: 22
Dockerfile
現在のバージョンのCloud CodeプラグインとRiderでは、そのままではデバグできません。デバグするためには、作成されたコンテナとSSH経由でリモートデバグを行います。
そのための設定をDockerに追加します。具体的に追加した点は、以下の通りです。
- デバグツールをインストールするためのツールとSSHサーバをインストールします (apt-get install)
- rootにパスワードでSSHログインできるようにします (下の例ではパスワードは"hogefuga")
- ENTRYPOINTで、SSHサーバを起動した後で、完成したdllを起動します
修正済みのDockerファイルは以下の通りになります。
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
RUN apt-get update \
&& apt-get install -y unzip procps curl bash openssh-server \
&& rm -rf /var/lib/apt/lists/*
RUN echo "root:hogefuga" | chpasswd
RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
RUN update-rc.d ssh enable
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["apisample/apisample.csproj", "apisample/"]
RUN dotnet restore "apisample/apisample.csproj"
COPY ["apisample/localhost.pfx", "apisample/"]
COPY ["apisample/", "apisample/"]
WORKDIR "/src/apisample"
RUN dotnet dev-certs https --clean --import localhost.pfx -p hogehoge
RUN dotnet build "apisample.csproj" -c Debug -o /app/build
FROM build AS publish
RUN dotnet publish "apisample.csproj" -c Debug -o /app/publish
FROM base AS final
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT "Development"
ENV ASPNETCORE_URLS "https://+:443;http://+:80"
COPY /root/.dotnet/corefx/cryptography/x509stores/my/* /root/.dotnet/corefx/cryptography/x509stores/my/
COPY /app/publish .
#ENTRYPOINT ["dotnet", "apisample.dll"]
ENTRYPOINT ["bash", "-c", "/etc/init.d/ssh start && dotnet apisample.dll"]
実行構成
新規実行構成として、Cloud Code: Kubernetesを選択します。
左上端の"+"をクリックし、Cloud Code: Kubernetesを選択します。
Nameには任意の名前を入れ、DeploymentにはSwitch context and deploy toを選び、"minikube"を選択します。
ビルドと実行
構成を今回作成した実行構成("Kubernetes")にしてデバグボタンを押すと、ビルドと実行が開始されます。
アクセス先は、"https://localhost:5143/swagger/index.html"になりますが、前述した通り、このままではデバグできません。(ブレークポイントなどが使用できません)。
SSH接続
実行されたコンテナとSSH接続するための設定を作成します。
設定の"Tools" > "SSH Configurations"を選択します。
SSH接続先として、以下の接続先を追加します。
Field | Value | Memo |
---|---|---|
Visible only for this project | チェック | Kubernetes上でコンテナが動作しているときだけ接続できますので、このプロジェクト内でのみ有効にします |
Host | localhost | |
Port | 5022 | 上述のdeployment.yamlに記載したSSHポート |
Username | root | Dockerfileに記述されたユーザ(root) |
Authentication Type | password | Dockerfileに記述されたログイン方法 |
Password | hogefuga | Dockerfileに記述されたパスワード |
"Test Connection"をクリックして、"Successfully connected!"と表示されればokです。
リモートデバグ
デバグボタンで実行した後、そのプロセスにリモートで接続します。
"Run" > "Attach To Remote Process.."を選択します。
接続先を上記で追加したSSH接続先を指定します。
なお、"Remote debugger tools are not loaded to the remove host"と表示された場合は、まだデバグツールがロードされていませんので、"click to load"をクリックして、デバグツールのロードを開始します。
デバグツールがロードされれば、接続先のプロセス一覧が表示されますので、"dotnet (apisample.dll)"を選び、"Attach with .NET Core Debugger"をクリックします。すると、デバグが開始されます。
◆ Docker: docker compose
Docker Composeを使うこともできます。
Dockerfile
Dockerfileは Cloud Code: Kubernetes と同じものを使用します。
docker-compose.ymlファイル
プロジェクト直下にファイル(docker-compose.yml)を作成します。
プロジェクト直下にファイルを作成するために、左側のエクスプローラーの表示を"Solution"から"File System"にします。
新規ファイルを作成するために、ルートの"apisample"の上で右クリックし、"Add" > "File"を選択します。
ファイル名は、"docker-compose.yaml"にします。
version: "3"
services:
apisample-dc:
image: ${DOCKER_REGISTRY-}apisample-dc
build:
context: .
dockerfile: apisample/Dockerfile
networks:
- private_net
ports:
- "5280:80"
- "5243:443"
- "5222:22"
networks:
private_net:
実行構成
新規実行構成として、Docker: Docker-composeを選択します。
左上端の"+"をクリックし、Docker > Docker-composeの構成を追加します。
そして、Compose-filesに、追加したdocker-compose.yamlを指定します。
リモートデバグ
Kubernetesと同様に、デバグボタンを押すだけではデバグできません。リモートデバグを使用します。
リモートデバグの方法は Cloud Code: Kubernetes と同じですが、接続先のSSHのポートは、docker-compose.yamlで定義したポート(5222)になります。
変更履歴
変更内容 | 説明 | 日付 |
---|---|---|
DOCKER_HOSTへの設定を"localhost:2376"から"tcp://localhost:2376"に変更 | "localhost:2376"だとdocker-composeコマンドが解釈できなかったため | 2022/12/01 |
COMPOSE_CONVERT_WINDOWS_PATHの設定追加 | Windows上でdocker compose(CLI)を行うとエラーになるのを回避 | 2022/12/05 |
dockerを一般ユーザで動作させる際のコマンドsudo addgroup --system groupを削除 | dockerと間違えてgroupというグループを追加していた。そもそもこのコマンドは不要 | 2022/12/06 |
Docker Desktopの設定追記 | WSL側のDockerと競合が発生しやすい設定の無効化 | 2022/12/07 |
Discussion