アーカイブ

Archive for 2020年1月

Docker Desktop 2.2でAzureADの認証問題が解消された

2020年1月24日 コメントを残す

先日のDocker Desktop 2.2では、docker-composeの問題があるけれど、このリリースでいろんなことが改善されました。例えば、リリースのブログエントリーにある中だとこんなところですね。
– WSL 2への対応
– gRPC FUSEを採用したことによるWindowsファイルシステムの改善
– ダッシュボードの追加
特にダッシュボードはdocker-composeで起動した場合にいい感じにグループ化してくれたり、コンテナの詳細情報がわかりやすくなったりでこれだけでもDocker 2.2にバージョンアップしていいなーと思うわけですが、個人的にうれしかったのがAzureAD利用時にファイル共有で再認証が必要なくなったことです。

これまでは、ファイルのマウントを行っているようなコンテナは以前のエントリーの通りSambaの認証情報をちょこちょこ再設定する必要があったんですが、Docker Desktop 2.2からは特に再設定しなくてもコンテナが起動できるようになりました。

小さいことなんですが、とっても嬉しい

カテゴリー:ASP.NET Core, Azure AD, Docker, WSL

Windows版のDocker Desktop 2.2を適用するとdocker-compsoeがUnicodeDecodeErrorで失敗する

2020年1月22日 コメントを残す

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

カテゴリー:Docker

.NET CoreでPublishSingleFile=trueの時に設定ファイルを含めない方法

2020年1月16日 コメントを残す

少し前に記事にした通り、こんな感じのコマンドラインで単一ファイルとしてビルドした場合、コンテンツを含めすべてのファイルが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>

カテゴリー:ASP.NET Core, C#

dotnet-ef コマンドをDockerなどでインストールする場合は–version指定をお忘れなく

2020年1月16日 コメントを残す

データベースのマイグレーションを実行するコンテナを別に一つ作っているんですが、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に依存するんですね。

カテゴリー:ASP.NET, ASP.NET Core, C#, Docker

StackExchange.RedisのConnectionMultiplexer.Connectで作ったコネクションは使いまわそう

2020年1月14日 コメントを残す

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する

2020年1月10日 コメントを残す

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

してあげればいいですね。

カテゴリー:Docker