Docker Desktop 2.2でAzureADの認証問題が解消された
先日のDocker Desktop 2.2では、docker-composeの問題があるけれど、このリリースでいろんなことが改善されました。例えば、リリースのブログエントリーにある中だとこんなところですね。
– WSL 2への対応
– gRPC FUSEを採用したことによるWindowsファイルシステムの改善
– ダッシュボードの追加
特にダッシュボードはdocker-composeで起動した場合にいい感じにグループ化してくれたり、コンテナの詳細情報がわかりやすくなったりでこれだけでもDocker 2.2にバージョンアップしていいなーと思うわけですが、個人的にうれしかったのがAzureAD利用時にファイル共有で再認証が必要なくなったことです。
これまでは、ファイルのマウントを行っているようなコンテナは以前のエントリーの通りSambaの認証情報をちょこちょこ再設定する必要があったんですが、Docker Desktop 2.2からは特に再設定しなくてもコンテナが起動できるようになりました。
小さいことなんですが、とっても嬉しい
Windows版のDocker Desktop 2.2を適用するとdocker-compsoeがUnicodeDecodeErrorで失敗する
Docker Desktop 2.2の修正がすごく魅力的(特にAzureADの部分)で、さっそくアップデートしたら docker-compose が全滅するようになりました。
たとえば、こんな単純の docker-compose であっても、
version: "3.4" services: redis: image: redis:3.2.11
docker-compose up するとこうなります。
λ docker-compose up Traceback (most recent call last): File "docker-compose", line 6, in File "compose\cli\main.py", line 71, in main File "compose\cli\main.py", line 101, in dispatch File "compose\cli\utils.py", line 86, in get_version_info File "compose\cli\utils.py", line 107, in get_build_version File "ntpath.py", line 85, in join UnicodeDecodeError: 'ascii' codec can't decode byte 0x90 in position 7: ordinal not in range(128) [11924] Failed to execute script docker-compose
単純にDocker Desktop 2.1.0.5 にダウングレードするのが簡単ですが、docker-compose だけを再インストールするというのでも対応は可能なようです。
過去バージョンのリンク先
https://docs.docker.com/docker-for-windows/release-notes/#docker-desktop-community-2105
GitHubのissue
https://github.com/docker/compose/issues/7169
.NET CoreでPublishSingleFile=trueの時に設定ファイルを含めない方法
少し前に記事にした通り、こんな感じのコマンドラインで単一ファイルとしてビルドした場合、コンテンツを含めすべてのファイルがexeファイルの中に含められ、実行時に「%LocalAppData%\Temp.net[exe名]\ハッシュのディレクトリ」みたいなディレクトリに展開して実行されます。
dotnet publish -r win-x86 -c Release -p:PublishSingleFile=true -p:TieredCompilationQuickJit=true -p:PublishReadyToRun=true
設定ファイルの値を後で変えるときに困るのでどうにかならないのかなぁと調べていたら、ここに書いてありました。→ https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#build-system-interface
コンテンツのビルド時動作と同じように、ファイルに対してCopyToPublishDirectoryとExcludeFromSingleFileを定義してあげればよいようです。
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> <AssemblyName>Sample</AssemblyName> </PropertyGroup> 略 <ItemGroup> <None Update="settings*.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <ExcludeFromSingleFile>true</ExcludeFromSingleFile> </None> </ItemGroup> </Project>
dotnet-ef コマンドをDockerなどでインストールする場合は–version指定をお忘れなく
データベースのマイグレーションを実行するコンテナを別に一つ作っているんですが、EntityFramework Core 3.1にアップグレードしたコンテナをビルドして実行したらこんなメッセージが表示されました。
It was not possible to find any compatible framework version
The framework ‘Microsoft.NETCore.App’, version ‘3.1.1’ was not found.
– The following frameworks were found:
3.1.0 at [/usr/share/dotnet/shared/Microsoft.NETCore.App]You can resolve the problem by installing the specified framework and/or SDK.
The specified framework can be found at:
– https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=3.1.1&arch=x64&rid=alpine.3.10-x64
3.1.1 を探しに行っている??
Dockerfile では、mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.10 をベースイメージに指定しているので、3.1.1 を使われると困ってしまう。
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.10 AS build 略 RUN dotnet tool install --global dotnet-ef ENV PATH="$PATH:/root/.dotnet/tools"
ベースイメージで指定した.NET Coreと同じバージョンを指定しましょう
RUN dotnet tool install --global dotnet-ef --version 3.1.0 ENV PATH="$PATH:/root/.dotnet/tools"
EntityFramework Core は .NET Core 3に依存しないけれど、周辺のツール類は.NET Core 3に依存するんですね。
StackExchange.RedisのConnectionMultiplexer.Connectで作ったコネクションは使いまわそう
Redisを使っている部分(非.NET Core)で高負荷時に下記のようなメッセージが出るというので調査した時のメモです。
“No connection is available to service this operation: SET test; IOCP: (Busy=0,Free=1000,Min=2,Max=1000), WORKER: (Busy=24,Free=32743,Min=2,Max=32767), Local-CPU: n/a
ググってみると、StackExchange.Redisのバージョンを下げると問題が解消したとか、タイムアウトを長くしたら解消したとかいうものが出てくるのですが、他のライブラリとのバージョンの競合でバージョンは下げられないし、タイムアウトは対症療法でしかないということで、コードを確認していきます。
そもそもRedisからデータを取得するだけなのにやけに遅いんですよね。
調べてみると、こんな共通のコードをいたるところから呼び出していました。
public class RedisClient { public async Task GetAsync(string key) { using (var redis = await ConnectionMultiplexer.ConnectAsync(this.ConnectionString)) { var db = _redis.GetDatabase(); var result = await db.StringGetAsync(key); return (result.IsNull) ? default(T) : JsonConvert.DeserializeObject(result); } } }
Redisからデータを取得する際に毎回コネクションを作っているので、接続を作るのが遅いし、おそらくクライアント側の資源を使いつくしているせいで冒頭のメッセージが出ているっぽい。このあたりの方針は、StackExchange.RedisのREADMEに記載があって、HttpClientなんかと同じように、StackExchange.RedisのConnectionMultiplexer.Connectメソッドで作られたコネクションは、複数個所から共有して呼び出されることを想定しているようです。
単純にやるなら、Connectionをstaticとして保持しちゃう、ちゃんとやるならFactoryを導入してConnectionの生存期間を制御できるようにする。ってところでしょうか。
public class RedisClient { private static ConnectionMultiplexer _redis; private static ConnectionMultiplexer GetClient() { return _redis ?? (_redis = ConnectionMultiplexer.Connect(configuration.ConnectionString)); } public async Task GetAsync(string key) { var db = GetClient().GetDatabase(); var result = await db.StringGetAsync(key); return (result.IsNull) ? default(T) : JsonConvert.DeserializeObject(result); } }
.NET Core からは、IDistributedCache インターフェイスを使うとこの辺りは面倒見てくれるようになりますよね。
https://docs.microsoft.com/ja-jp/aspnet/core/performance/caching/distributed?view=aspnetcore-3.1
base64コマンドをalpineで利用する場合は、事前にapk add –update coreutilsする
DockerのベースイメージをUbuntuからalpineに変更したときに、base64コマンドではまったのでメモ
alpine ベースのイメージで decode コマンドを使いたい場合は、事前に下記のパッケージを更新しておきましょう
RUN apk add --update coreutils
環境毎に異なるバイナリーファイルを切り替えるために、そのファイルをbase64でエンコードしたものを環境変数経由でコンテナに与え、起動時にbase64コマンドで特定ディレクトリに復元していました。
echo $base64_file_data | base64 --decode > /myapp/data/data.txt
コンテナの中に入ってこんなコマンドを実行すると、
docker run -it --rm alpine sh # echo dGVzdA== | base64 --decode
こうなります。
base64: unrecognized option: decode
BusyBox v1.29.3 (2019-01-24 07:45:07 UTC) multi-call binary.Usage: base64 [-d] [FILE]
Base64 encode or decode FILE to standard output
-d Decode data
-d を使えと言われるのでこうすると、一応ちゃんとデコードできます。
# echo dGVzdA== | base64 -d test
検索すると、パッケージを更新しておくと同じように動くよ。とのことなので
https://stackoverflow.com/questions/57920449/the-error-base64-unrecognized-option-w-is-output-in-alpine-linux
こうしてみると、ちゃんと動きます。
# apk add --update coreutils # echo dGVzdA== | base64 --decode test
実際使うときは、Dockerfile側で
RUN apk add --update coreutils
してあげればいいですね。