💨

Windows コンテナーのログを取得したい

2023/12/28に公開

ごきげんよう!mihohoi です。
AKS で Windows コンテナーを動かすことができるのはご存知でしょうか。
ほとんどの場合は Linux ノードの上にコンテナーを作成していきますが、どうしても Windows コンテナーで稼働させたいアプリケーションも中にはあります。
そういった場合に、AKS では Windows ノードを追加し、その上で Windows コンテナーを稼働させることができます。

https://learn.microsoft.com/ja-jp/virtualization/windowscontainers/about/

Linux と同じように運用しても問題ないのか?それは少し違うと個人的には思います。ということで、今回は「ログ」についてまとめます。

Windows コンテナーのベースイメージとして複数用意されています。servercore もそのうちの一つです。Windows Server の運用をしていた方は分かるかと思いますが、EventLog など Windows では Linux と異なるログの出力方法があります。
そのようなログを取得したい場合、コンテナーとして標準出力に出せるのかというと少し工夫が必要です。今回は実際に Windows コンテナーを作成して確認していきます。

AKS を作成して、Windows ノードプールを追加する

それではまず AKS クラスターを作成し、Windows ノードを追加します。基本的にはドキュメントに記載の通りですが、若干変えています。
まずは、変数を設定しておきます

myResourceGroup=<リソースグループ名>
myAKSCluster=<クラスター名>
location=eastus

# クラスターの Windows Server ノードの管理者資格情報として使用するユーザー名を作成します。
WINDOWS_USERNAME=azureadmin
# Windows 管理者ユーザー名のパスワードを作成します。
WINDOWS_PASSWORD=<password>

Windows パスワード要件は、こちらを参照してください。毎回何にしようか悩んでます。

はじめにリソースグループを作成します。

az group create \
  --name $myResourceGroup \
  --location $location

AKS を作成します。今回は、--windows-admin-username パラメーターと --windows-admin-password パラメーターを指定し、Windows Server ノードの管理者資格情報を設定します。

az aks create \
  --name $myAKSCluster \
  --resource-group $myResourceGroup \
  --location $location \
  --enable-addons monitoring \
  --node-count 2 \
  --generate-ssh-keys \
  --windows-admin-username $WINDOWS_USERNAME \
  --windows-admin-password $WINDOWS_PASSWORD \
  --vm-set-type VirtualMachineScaleSets \
  --network-plugin azure

作成したクラスターに Windows ノードプールを追加します。VM サイズを指定しているのは、少し大きめのリソースを使いたいからです。

az aks nodepool add --resource-group $myResourceGroup --cluster-name $myAKSCluster --os-type Windows --name win01 --node-vm-size Standard_D8s_v3 --node-count 1

しばらくすると、ノードが追加されます。クラスターに接続します。

az aks get-credentials --resource-group $myResourceGroup --name $myAKSCluster

ノードプールが Linux および Windows と 2 種類作成されていることを確認します。以下は表示例です。Windows Server 2022 がノードとして追加されていることがわかります。

% kubectl get node -o wide
NAME                                STATUS   ROLES   AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION      CONTAINER-RUNTIME
aks-nodepool1-19368188-vmss000000   Ready    agent   33m   v1.27.7   10.224.0.33   <none>        Ubuntu 22.04.3 LTS               5.15.0-1052-azure   containerd://1.7.5-1
aks-nodepool1-19368188-vmss000001   Ready    agent   33m   v1.27.7   10.224.0.4    <none>        Ubuntu 22.04.3 LTS               5.15.0-1052-azure   containerd://1.7.5-1
akswin01000000                      Ready    agent   12m   v1.27.7   10.224.0.62   <none>        Windows Server 2022 Datacenter   10.0.20348.2113     containerd://1.6.21+azure

準備はこれで完了です。次はようやく Windows コンテナーを作成していきます。

Windows コンテナーデプロイ

テスト用に servercore を作成し、デプロイします。すでに存在している Azure Container Registry に対してイメージを保存します。もし作成されていない場合は、こちらを参照して作成してください。

既存の Azure Container Registry と作成した AKS を統合させます。

myACR=<Azure Container Registry 名>
az aks update -n $myAKSCluster -g $myResourceGroup --attach-acr $myACR

ローカルで Dockerfile を作成します。まずは、何もない状態のコンテナーを作成します。

FROM mcr.microsoft.com/windows/servercore:ltsc2022

# IISをインストール
RUN powershell -Command Add-WindowsFeature Web-Server

# IISを実行
CMD ["powershell", "-Command", "Start-Service W3SVC; while ($true) { Start-Sleep -Seconds 30 }"]

この Dockerfile をビルドし、ACR に格納します。

% az acr login --name $myACR
% docker build -t $myACR.azurecr.io/servercore:v2 .
% docker push $myACR.azurecr.io/servercore:v2

格納できたら、AKS にデプロイするためにファイルを作成します。yaml ファイルは以下の通りです。名前などは適宜変更してください。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: win01
spec:
  selector:
    matchLabels:
      app: win01
  template:
    metadata:
      labels:
        app: win01
    spec:
      nodeSelector:
        "kubernetes.io/os": windows
      containers:
      - name: win01
        image: $myACR.azurecr.io/servercore:v2
        resources:
          limits:
            memory: 800M
            cpu: 1

実行し、ログを確認します。

%  kubectl apply -f sample-win2.yaml
deployment.apps/win01 created
%  kubectl get po
NAME                          READY   STATUS    RESTARTS   AGE
win01-7489f89d4d-l4px2        1/1     Running   0          7s
% kubectl logs win01-7489f89d4d-l4px2
"コンテナは実行中です... && timeout /t -1"

ログが表示されていることがわかりました。

Windows コンテナーのログを確認したい

Linux の場合は、stdout/err が特に何も設定せずに Log Analytics から閲覧することができます。
Windows コンテナーの場合も ContainerLogv2 で、stdout/err が Log Analytics に出力されます。ただ、それ以外にも出力したいものはあります。例えば、EventLog などです。そのため、Linux とはログの出力方法が異なります

Windows コンテナーでも stdout/err は kubectl からおなじみのコマンドで閲覧できます。例えばこんな感じです。

% kubectl logs win-sample-7b4b4b6c9f-74pqd
2023-12-27 04:50 hello, log
2023-12-27 04:55 hello, log

ただし、イベントログなどは stdout/err に表示されません。
試しに先ほど作成したコンテナーに入り、EventLog を作成してみます。

% kubectl exec -it win01-8c546d895-rxtm5 -- powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows

PS C:\> Get-EventLog -LogName Application

   Index Time          EntryType   Source                 InstanceID Message
   ----- ----          ---------   ------                 ---------- -------
      57 Dec 27 09:37  Error       Software Protecti...   3221233670 License Activation (slui.exe) failed with the following error code:...
      56 Dec 27 09:37  Information Software Protecti...   1073742827 The Software Protection service has completed licensing status check....
      55 Dec 27 09:37  0           Software Protecti...   1073742726 The Software Protection service has started....
      54 Dec 27 09:37  Error       Software Protecti...   3221226513 Failed to collect hardware data. Error code 0xD0000034.
()

kubectl los で出力されているかを確認します。(別のコンテナーを立ち上げたので名前が異なってます)

 % kubectl logs win01-8c546d895-rxtm5
 

標準出力側には出てきません。そこで LogMonitor が登場します。

そこで LogMonitor

LogMonitor の詳しい仕組みなどは以下の方にも詳細に記載されています。
https://techcommunity.microsoft.com/t5/containers/windows-containers-log-monitor-opensource-release/ba-p/973947

仕組み的には以下の図(ブログから抜粋)のとおり、LogMonitor を通して EventLog やカスタムのログファイルなどを stdout に出力しようということのようです。
LogMonitor の仕組み

では、実際に LogMonitor を導入してみましょう。
LogMonitor はこちらから入手できます。ダウンロードしたのち、コンテナー化するアプリケーションと同じフォルダに格納します。

LogMonitor の導入

先ほどの Dockerfile/yaml ファイルは一旦忘れて、あらたに Dockerfile を作成するところから進みます。

#LogMonitor directory contains LogMonitor.exe and LogMonitorConfig.json file
COPY ServiceMonitor.exe C:/
COPY LogMonitor/ C:/LogMonitor

WORKDIR /LogMonitor

# Application
RUN mkdir C:\inetpub\wwwroot\test
#IISアプリケーションプール作成
RUN ["powershell.exe" , "Install-WindowsFeature Web-Mgmt-Service"]
RUN ["powershell.exe", "New-WebAppPool -Name testPool"]

#IISアプリ作成
RUN ["powershell.exe", "New-WebApplication -Name 'testPool' -Site 'Default Web Site' -PhysicalPath 'C:\\inetpub\\wwwroot\\test' -ApplicationPool 'testPool'"]

EXPOSE 80

#LogMonitor起動
ENTRYPOINT C:\\LogMonitor\\LogMonitor.exe

ちなみに、Service Monitor はこちらからダウンロードしました。
LogMonitorConfig.json (LogMonitorでどのような内容を取得するかを記載する設定ファイル) はひとまず以下のようにしています。
EventLog の system と application を出力します。また、それぞれ異なった Level のログ (以上、だったかと) を取得するように設定しています。

{
  "LogConfig": {
    "sources": [
            {
        "type": "EventLog",
        "startAtOldestRecord": true,
        "eventFormatMultiLine": false,
        "channels": [
          {
            "name": "system",
            "level": "Error"
          },
          {
            "name": "application",
            "level": "Error"
          }
        ]
      },
            {
        "type": "File",
        "directory": "c:\\LogMonitor\\logs",
        "filter": "*.log",
        "includeSubdirectories": true
      }
    ]
  }
}

フォルダ構成は以下のようにしています。
フォルダ構成

作成した Dockerfile は、先ほどと同じようにコンテナー化して、Azure Container Registry に push します。コマンドは同じ内容なので省きます。
次に、AKS にデプロイするために yaml を作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: logmonitor
  labels:
    app: logmonitor
spec:
  replicas: 1
  template:
    metadata:
      name: logmonitor
      labels:
        app: logmonitor
    spec:
      nodeSelector:
        "kubernetes.io/os": windows
      containers:
      - name: logmonitor
        image: $myACR.azurecr.io/logmonitor:v1
        resources:
          limits:
            cpu: 1
            memory: 800M
  selector:
    matchLabels:
      app: logmonitor

これを AKS にデプロイします。そして、しばらく待ったのちに、kubectl コマンドを使ってログを見てみましょう。

% kubectl logs logmonitor-64fc45964d-lz4l6
<Source>EventLog</Source><Time>2022-08-06T10:00:12.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7023</EventId><Message>The DiagHost service terminated with the following error:   The RPC server is unavailable.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T10:00:12.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7031</EventId><Message>The DiagHost service terminated unexpectedly.  It has done this 1 time(s).  The following corrective action will be taken in 60000 milliseconds: Restart the service.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T10:00:53.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7023</EventId><Message>The DiagHost service terminated with the following error:   The RPC server is unavailable.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T10:00:53.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7031</EventId><Message>The DiagHost service terminated unexpectedly.  It has done this 1 time(s).  The following corrective action will be taken in 60000 milliseconds: Restart the service.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T03:01:54.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7023</EventId><Message>The DiagHost service terminated with the following error:   The RPC server is unavailable.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T03:01:54.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7031</EventId><Message>The DiagHost service terminated unexpectedly.  It has done this 2 time(s).  The following corrective action will be taken in 120000 milliseconds: Restart the service.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T03:03:54.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7023</EventId><Message>The DiagHost service terminated with the following error:   The RPC server is unavailable.</Message></LogEntry>
<Source>EventLog</Source><Time>2022-08-06T03:03:54.000Z</Time><LogEntry><Channel>System</Channel><Level>Error</Level><EventId>7034</EventId><Message>The DiagHost service terminated unexpectedly.  It has done this 3 time(s).</Message></LogEntry>

stdout に出力されましたね。では、Log Analytics でも確認してみましょう。
Log Analytics

LogMessage にログが出力されました。もう少し見やすくできないかなとも思いましたが、必要な内容については後で加工したり、アラートの場合は内容を grep できればいいので今回は特に何もしていません。
Log Analytics では必要以上な情報もテーブルで見れるので、見たいものだけ出力できるように KQL を書き換えてみましょう。

おわりに

なかなか奥が深いな、Windows コンテナー。ログの取得については、EventLog 以外にも取得できる項目があるので、使用する場合はぜひ GitHub のドキュメントを見てください。

参考

https://techcommunity.microsoft.com/t5/containers/windows-containers-log-monitor-opensource-release/ba-p/973947

https://github.com/microsoft/windows-container-tools

GitHubで編集を提案
Microsoft (有志)

Discussion