1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MTV VMware Provider による vSphere から OpenShift Virtualization on IBM ROKS への "Cold/Warm" VM 移行 #1 − 準備編

1
Last updated at Posted at 2026-02-26

目次

はじめに

VMware vSphere から OpenShift Virtualization (OCPv) へ仮想マシンを移行する際、Red Hat が提供する Migration Toolkit for Virtualization (MTV) は、最も現実的な選択肢の一つです。特に VMware Provider を利用すると、単発の停止移行 (Cold migration) だけでなく、変更ブロック追跡 (Changed Block Tracking; CBT) を活用した増分同期(Warm migration)まで、段階的な移行シナリオを扱える点が魅力です。

一方で、MTV の移行がうまくいかない原因の多くは「MTV 自体の不具合」ではありません。CBT の前提条件、VDDK (VMware Disk Development Kit) の取り込み、ESXi 側の NFC サービス設定、名前解決 (DNS)、必要権限や接続性など、環境側の準備不足 に起因するケースが大半です。実行手順だけを追うと移行の途中で詰まりやすく、原因切り分けにも時間がかかります。

そこで本記事 (#1 準備編) では、MTV による vSphere → OCPv (IBM Cloud 上の ROKS) の Cold/Warm 移行を「実行できる状態」に整えることをゴールに、OCPv 側と VMware 側それぞれの準備作業と確認ポイントを、再現可能な形で整理します。実際の Migration Plan 作成〜移行実行・Cutover は、次回 (#2 実行編) で扱います。

Red Hat OpenShift on IBM Cloud (ROKS) に OpenShift Virtualization を構築し、仮想マシンを起動してみるまでをまとめた記事は下記です。OCPv 環境をこれから用意する場合は参考にしてください。

1. 概要

本記事は、Migration Toolkit for Virtualization (MTV) の VMware Provider を使って、VMware vSphere 上の仮想マシンを OpenShift Virtualization (OCPv / KubeVirt) へ移行するための“準備” を手順化してまとめるものです。

移行作業そのもの (Provider 作成 → Plan 作成 → 実行 → 検証) は #2 実行編 で扱いますが、実務ではその前段の準備で詰まることが多いため、本記事ではまず「移行が実行できる状態」まで環境を整えることをゴールにします。

本記事で扱う範囲は次のとおりです。

  • OpenShift Virtualization (OCPv) 側に Migration Toolkit for Virtualization (MTV) Operator をインストールし、基本コンポーネントが正常に起動していることを確認
  • Warm migration に必要な変更ブロック追跡 (Changed Block Tracking; CBT) を VMware 側で有効化し、考え方と設定観点を整理
  • VMware ディスク転送で利用する VDDK カスタムイメージを IBM Cloud Container Registry (ICR) へ格納し、MTV から参照できるようにする
  • ESXi ホストの NFC サービスに関する設定 (メモリー拡張) を確認し、必要に応じて調整する
  • OpenShift クラスタから vCenter / ESXi を解決・到達できるようにするための DNS フォワーディング (転送) を設定する

位置付けとして、本記事は 「準備のチェックリスト兼、詰まりポイント集」 です。“ここまで終わっていれば移行作業に進める” という状態を作ることを目的にしています。

1-1. 前提

移行元の VMware vSphere 環境と 移行先の OCPv 環境 が手元にあることを前提とします。また、本検証における VMware vSphere 環境は IBM Cloud VCF for Classic - Automated を利用して構築されていますが、OCPv 環境からネットワーク疎通と名前解決ができる vShpere 環境であれば問題ありません。

参考情報として、筆者の環境情報を下記に記載します。

  • OpenShift Virtualization
    • プラットフォーム:Red Hat OpenShift on IBM Cloud (ROKS)
    • OpenShift:4.18.30 (Kubernetes: 1.31.13)
    • 基盤:IBM Cloud Bare Metal Server for VPC
    • Workerノード:3台
    • ストレージ(VMディスク用):ODF (OpenShift Data Foundation)
    • VM向けStorageClass:ocs-storagecluster-ceph-rbd-virtualization
    • ネットワーク:ROKS のコンテナネットワーク (Calico)
    • Migration Toolkit for Virtualization Operator version:2.10.1 → 2.10.5
  • VMware vSphere
    • プラットフォーム:IBM Cloud の VCF for Classic - Automated
    • VMware vSphere version:8.0
    • VMware vCenter Server version:8.0
    • NSX Version:4.2.2.1.0.24765084

2. MTV のインストール

Migration Toolkit for Virtualization (MTV) は、VMware vSphere などの既存仮想基盤上で稼働している仮想マシンを、OpenShift Virtualization (= KubeVirt) へ移行するための Operator ベースの移行ツールです。移行の「Provider 登録」「ネットワーク/ストレージのマッピング」「移行 Plan(実行単位)の作成」「実行と進捗・ログ確認」といった一連の作業を、OpenShift の運用モデル (名前空間 / RBAC / Operators) に統合した形で提供します。

MTV が提供する中核機能は、オープンソースプロジェクト "Forklift" をベースにしています。Forklift は「VM を Kubernetes 上の KubeVirt へ移す (rehost)」ための仕組みを実装したプロジェクトで、移行元のインベントリ取得、移行対象の変換、移行ジョブのオーケストレーション等を担います。

Forklift は、Red Hat と IBM Research が2021年に共同で立ち上げたオープンソースの取り組みである "Konveyor" に端を発しますが、Konveyor の立ち上げ時点では、Forklift は「仮想マシンを KubeVirt に (最小限の停止時間で) 移行する」ためのサブプロジェクトとして位置づけられていました。いずれのサププロジェクトも Operator を軸に「Kubernetes 上で実運用しやすい形で提供する」方針が語られています。その後、Forklift プロジェクトの重心を、より「VM → KubeVirt」領域に近い場所へ戻すため、Konveyor 傘下ではなく KubeVirt コミュニティ側へ移管されました。

MTV は OpenShift に統合された移行ツールですが、実際に詰まりやすいのは MTV 自体ではなく、移行元 vSphere 側の準備や、OpenShift から vCenter/ESXi への名前解決・通信です。つまり「MTVを入れたら終わり」ではなく、移行が成立するための前提条件を揃えることが成功の鍵になります。

本章ではまず、OCPv (移行先) 側に MTV Operator を導入し、MTV のコンポーネントが正しく起動して UI へアクセスできる状態まで整えます。

2-1. 手順

  • IBM Cloud コンソール > Clusters から、OpenShift Virtualization がインストールされた ROKS クラスタの [Overview] ページに移動します。
  • 右上部の [OpenShift web console] ボタンをクリックし、新規タブとして OpenShift web console ページを開きます。
  • コンソールの左ペインから、[Operators] > [OperatorHub] に移動し、「mtv」でフィルターします。その後、「Migration Toolkit for Virtualization Operator」パネルをクリックします。
  • 更新チャンネルとバージョンを選択し、[Install] ボタンをクリックします。基本的には最新のバージョンを選択します。筆者の環境のセットアップ時点では「2.10.1」が最新でした。
  • MTV の [Install Operator] ページに遷移します。すべてデフォルト設定で [Install] ボタンをクリックします。
    • Installation mode として、「All namespaces on the cluster (default)」と「A specific namespace on the cluster」の2種類がありますが、 MTV では後者の「A specific namespace on the cluster」しか選択できません。
    • Installed Namespace として、推奨かつ自動作成される「openshift-mtv」(デフォルト) を選択します。
    • Update approval は、「Automatic」を選択します。更新チャンネル内の最新のバージョンを選択している場合に限り「Automatic」を選択できます。
  • MTV のインストール後に、ForkliftController 用のカスタムリソース (CR) を作成するように促されます。MTV に必須のコンポーネントであるため、[Create ForkliftController] をクリックし、デフォルトの設定のままインストールします。
  • OpenShift web console の左ペインに「Migration for Virtualization」というメニューが表示されるようになります。
    • 筆者の環境では Update approval = Automatic の設定により、本記事の執筆時点で、更新チャンネル 2.10 系の最新バージョン 2.10.5 に自動アップデートされています。
  • ForkliftController カスタムリソース (CR) が正常にインストールされ、起動していることを確認します。

以上で Migration Toolkit for Virtualization (MTV) のインストールは完了です。

3. VMware CBT の有効化

Changed Block Tracking (CBT) は、ESXi (VMkernel) が 仮想ディスク (VMDK) 上で変更されたブロック領域 を追跡し、後から「前回の時点から変化した部分だけ」を取得できるようにする機能です。もともとは vSphere のバックアップ/レプリケーション用途で広く使われており、vSphere API (VADP: vSphere APIs for Data Protection) を利用する製品は CBT の情報を参照して 増分バックアップ (Changed blocks only) を実現します。

MTV の Warm migration (増分同期) も同様に、移行元 vSphere から「変更されたブロックだけ」を効率よく取り込む必要があります。CBT が無効、または正常に動作していない場合、増分同期が成立せず、結果として フルコピー相当の挙動にフォールバックしたり、同期が極端に遅くなったり、失敗する 可能性があります。そのため Warm migration を前提とする場合、CBT の有効化と健全性確認は重要な準備項目です。

筆者の vSphere 環境では、CBT は既定で 無効 でした。

3-1. 手順

  • vSphere Client にログインし、[Inventory] ページを開きます。
  • CBT を有効化する仮想マシン (例: win2019-acs) を停止します。このとき、スナップショットが存在する場合はすべて削除します。

CBT を有効化する前に、対象VMに スナップショットが残っていないこと を必ず確認してください。スナップショットが存在する状態で CBT を有効化すると、変更ブロック情報が不整合になり、QueryChangedDiskAreas などのAPIが 誤った結果を返す/期待どおり動作しない 可能性があります。

  • 対象の仮想マシンで、ACTIONS > Edit settings > Advanced Parameters の画面を開きます。
  • [Attribute] フィルターに「ctk」と入力して検索して設定済みか否かを確認します。初回設定の場合はAttribute 自体 (ctkEnabledscsi0:0.ctkEnabled など) が存在しないはずです。設定が無ければ後続の手順を実施します。

パラメータ名 ctkEnabled の由来

  • CBT (Changed Block Tracking) → 機能本体
  • CTK (Change Tracking) → CBT が生成・参照する変更追跡データのファイル (.ctk)

参考:Enabling or disabling Changed Block Tracking (CBT) on virtual machines

  • 仮想マシンの CBT を有効化します。
    • Advanced Parameters の画面で、[Attribute] 欄に ctkEnabled、[Value] 欄に TRUE と入力し、[ADD] ボタンをクリックして、リストに追加します。
  • 仮想マシンに付随する仮想ディスク単位で CBT を有効化します。
    • Advanced Parameters の画面で、[Attribute] 欄に scsiX:Y.ctkEnabled (X,Yは SCSI 番号)、[Value] 欄に TRUE と入力し、[ADD] ボタンをクリックして、リストに追加します。
  • ctkEnabledscsiX:Y.ctkEnabled を追加できたら、[OK]ボタンをクリックします。
  • CBT の設定を反映させるために仮想マシンを起動します。
  • 仮想マシンのホームディレクトリで、CBT を有効化したディスク毎に <VM名>-ctk.vmdk が存在すれば有効化されてる目安になります。

3-1-1. 各ディスクの SCSI 番号一覧を取得する方法

VCF.PowerCLI PowerShell モジュールで vCenter に接続して SCSI 番号を取得できます。

VCF.PowerCLI は VMware.PowerCLI の後継のモジュールであり、現時点で VMware.PowerCLI をインポートすると「WARNING: The module 'VMware.PowerCLI' is deprecated. Please use the module 'VCF.PowerCLI' instead.」のような警告が出ます。

ここでは、PowerShell スクリプトを作成して仮想マシンの SCSI 番号の一覧を取得する方法を紹介します。

  • 下記のような PowerShell スクリプト (get-scsi-mapping.ps1) を作成し、適当なディレクトリ (例: ~/Downloads/) に置きます。

    get-scsi-mapping.ps1
    param(
        # 1台でも複数台でも指定できるように string[] にしておく
        [Parameter(Mandatory = $true)]
        [string[]]$VMName
    )
    
    # vCenter に接続している前提
    try {
        $targetVMs = Get-VM -Name $VMName -ErrorAction Stop
    }
    catch {
        Write-Host "Get-VM でエラーが発生しました: $($_.Exception.Message)" -ForegroundColor Red
        return
    }
    
    if (-not $targetVMs) {
        Write-Host "指定した VM 名に一致する VM が見つかりませんでした: $($VMName -join ', ')" -ForegroundColor Yellow
        return
    }
    
    $report = foreach ($vm in $targetVMs) {
        $vm.ExtensionData.Config.Hardware.Device |
            Where-Object { $_ -is [VMware.Vim.VirtualDisk] } |
            ForEach-Object {
                $disk = $_
    
                $controller = $vm.ExtensionData.Config.Hardware.Device |
                              Where-Object { $_.Key -eq $disk.ControllerKey }
    
                $bus  = $controller.BusNumber
                $unit = $disk.UnitNumber
    
                [PSCustomObject]@{
                    VMName      = $vm.Name
                    DiskLabel   = $disk.DeviceInfo.Label
                    SCSIBus     = $bus
                    UnitNumber  = $unit
                    SCSIID      = "scsi{0}:{1}" -f $bus, $unit
                    CapacityGB  = [math]::Round($disk.CapacityInKB / 1MB, 1)
                }
            }
    }
    
    $report | Sort-Object VMName, SCSIBus, UnitNumber | Format-Table -AutoSize
    
  • スクリプト実行までの流れ

    # HomebrewをUpdate
    $ brew update
    
    # pwshのインストール
    $ brew install --cask powershell
    
    # pwshの起動
    $ pwsh
    
    # VCF.PowerCLIモジュールのインストール
    PS /Users/hiroaki.mishima> Install-Module VCF.PowerCLI -Scope CurrentUser
    
    # vCenterに接続
    PS /Users/hiroaki.mishima> Connect-VIServer -Server vcsosv-vc.corp.example.local -User ■■■■■■■■■■■■■■■■■■■■■■■■■■ -Password ■■■■■■■■■■
    
    # Warning回避のために実行
    PS /Users/hiroaki.mishima> Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $true
    
    # スクリプトのディレクトリ(例:~/Downloads/)へ移動
    PS /Users/hiroaki.mishima> cd ./Downloads/
    
    # スクリプト実行
    PS /Users/hiroaki.mishima/Downloads> ./get-scsi-mapping.ps1 -VMName *
    
    • -VMname パラメータで SCSI 番号を取りたい仮想マシンの名前をしてします。下記の実行結果例のように、ワイルドカードも使用して、複数の仮想マシンから SCSI 番号を取得できます。

      PS /Users/hiroaki.mishima/Downloads> ./get-scsi-mapping.ps1 -VMName *acs*
      
      VMName                  DiskLabel   SCSIBus UnitNumber SCSIID  CapacityGB
      ------                  ---------   ------- ---------- ------  ----------
      centos-acs-web          Hard disk 1       0          0 scsi0:0     16.000
      rhel8-acs2              Hard disk 1       0          0 scsi0:0     12.000
      rhel8-acs2-clone1       Hard disk 1       0          0 scsi0:0     12.000
      rhel9-acs4              Hard disk 1       0          0 scsi0:0     12.000
      rhel9-acs4-clone1       Hard disk 1       0          0 scsi0:0     12.000
      ubuntu2404-acs          Hard disk 1       0          0 scsi0:0     12.000
      ubuntu2510-acs          Hard disk 1       0          0 scsi0:0     12.000
      win10-acs (<ad>¥user1)  Hard disk 1       0          0 scsi0:0     16.000
      win10-acs2 (<ad>¥user2) Hard disk 1       0          0 scsi0:0     16.000
      win2016-acs2            Hard disk 1       0          0 scsi0:0     48.000
      win2019-acs             Hard disk 1       0          0 scsi0:0     48.000
      win2022-acs             Hard disk 1       0          0 scsi0:0     16.000
      win2025-acs-ad          Hard disk 1       0          0 scsi0:0     18.000
      

4. VDDK イメージの設定

VMware vSphere から仮想ディスクを移動する場合は、Migration Toolkit for Virtualization (MTV) を VMware Virtual Disk Development Kit (VDDK) SDK と併用することを強く推奨します。MTV は VM のディスクをコピーするときに VDDK SDK を使います。

この機能を利用するには、VDDK をダウンロードし、VDDK イメージを build して、VDDK イメージをイメージレジストリに push します。VDDK パッケージにはシンボリックリンクが含まれているため、VDDK イメージの作成は、シンボリックリンク (symlink) を保持するファイルシステム上で実行する必要があります。

VDDK イメージをパブリックレジストリに保存すると、VMware ライセンスの条項に違反する可能性があります。そのため、ユーザーが自分で VDDK SDK をダウンロードし、それを組み込んだコンテナイメージ (VDDK イメージ)を build してレジストリに登録する必要があります。

IBM Cloud ROKS の場合は:

  • クラスター内部の Image Registry
    image-registry.openshift-image-registry.svc:5000/<プロジェクト>/<イメージ>:<tag>
  • または IBM Cloud Container Registry (ICR) の プライベート名前空間

いずれかの 非公開レジストリ に置くのが安全です。

4-1. 手順: IBM Cloud Container Registry (ICR) の準備

本記事での検証では、VDDK イメージを格納するレジストリとして IBM Cloud Container Registry (ICR) を利用しました。ICR で管理されたプライベート・レジストリに、カスタムした VDDK コンテナイメージを保管します。ICR を利用することで、OCPv on ROKS から利用可能なレジストリを簡単に準備できます。

ICR の 準備だけであれば Web UI での作業でも不都合はありませんが、後続の VDDK の build と ICR への push の作業ではコマンドラインでの実施が簡単です。したがって、Web UI はコマンドの実行結果の確認で利用することに留めます。

  • ibmcloud CLI を作業端末にインストールします。インストーラや Shell を利用した方法など、いくつか選択可能なオプションがあります。下記の参考ページに沿って簡単に導入できます。
  • container-registry CLI プラグインが未導入の場合は、以下のコマンドで導入します。
    ibmcloud plugin install container-registry -r 'IBM Cloud'
    
    • container-registry
      • インストールしたいプラグイン名です。

      • 例えば以下のような ICR 操作用コマンドが使えるようになります。

        • ibmcloud cr login(ICR にログインして Docker/Podman が pull/push できる状態にする)

        cr = container-registry のショートコマンド

    • -r 'IBM Cloud'
      • IBM 公式のプラグインリポジトリ (名称が “IBM Cloud”) からプラグインを取得します。
  • 作業端末にコンテナエンジンとして podman をインストールします。

MTV の VDDK イメージを ICR に置く用途なら、Podman の代わりに Docker を利用しても問題ありません。後続のコマンド例は Podman を前提に紹介していますが、基本的に本記事内でのコマンドは置き換え可能です。

  • 簡易比較
観点 Docker Podman
アーキテクチャ デーモン(dockerd)中心 デーモンレス
権限 root 前提傾向(環境次第) rootless が標準
コマンド互換 本家 多くが置き換え可能
セキュリティ 設計次第 rootless で強い
企業環境(RHEL) 使えるが方針次第 Red Hat の推奨寄り
  • コマンドの置き換え例
やりたいこと Docker Podman
イメージ取得 docker pull podman pull
ビルド docker build podman build
起動 docker run podman run
一覧 docker ps podman ps
停止 docker stop podman stop
レジストリへpush docker push podman push
レジストリログイン docker login podman login
  • ibmcloud CLI で IBM Cloud にログインします。
    ibmcloud login -a cloud.ibm.com -r us-south -g OSV-migrate --sso
    
    • ibmcloud login
      • IBM Cloud CLI でアカウントにログイン
    • -a cloud.ibm.com
      • API エンドポイント (パブリック IBM Cloud)
    • -r us-south
      • デフォルトのリージョンを us-south に設定
    • -g <resource_group_name>
      • デフォルトのリソースグループを設定 (ここでは OSV-migrate)
      • リソースグループは、IBM Cloud コンソールで [Manage] > [Account] > [Account resources] > [Resource groups] ページから作成できます。CLI を利用する場合は、ibmcloud resource group-create OSV-migrate のようなコマンドで作成できます。
      • 指定しない場合、Default リソースグループが利用されます。
    • --sso
      • シングルサインオン (SSO) でログイン (ブラウザからワンタイムコードを取る方式)
  • ibmcloud CLI で ICR にログインします。
    ibmcloud cr login --client podman
    
    • 現在の IBM Cloud ログイン情報を使って、Container Registry (*.icr.io) に対して Docker/Podman で push/pull できるように認証情報を設定します。
    • 明示的に Podman を使用してログインするには、--client podman オプションを利用します。
      • Docker を使用してログインするには、--client docker オプションを利用し、ローカル Docker デーモンを IBM Cloud Container Registry にログインさせます。
  • ICR 上に作業用の名前空間を作成します。
    ibmcloud cr namespace-add hmishima-ns
    
    • 先ほど実行した ibmcloud login-g オプションで指定したリソースグループに名前空間が作成されます。 ここでは hmishima-ns という名前空間を作成しました。
    • この後、イメージ名として us.icr.io/hmishima-ns/xxx:tag が使えるようになります。

4-2. 手順: VDDK イメージの build と ICR への push

MTV の VMware Provider で VMware ディスクを効率よく転送するために、MTV は VMware Virtual Disk Development Kit (VDDK) SDK を利用します。Red Hat ドキュメントでも、MTV インストール後に VDDK イメージを作成し、HyperConverged CR の spec.vddkInitImage に設定する必要があると明記されています。

[参考] Red Hat Documentation > Installing and using the Migration Toolkit for Virtualization

しかし、VDDK は MTV の標準イメージに同梱されていません(Broadcom ライセンス上、配布形態に注意が必要なため)。そのため、利用者が Broadcom から VDDK を入手し、自組織のレジストリ(例:ICR)に置ける“VDDK 配布用コンテナイメージ” としてパッケージ化します。

MTV の移行実行時には、VMware から取り込んだディスクに対して virt-v2v による変換処理を行う conversion Pod が作成されます。このとき spec.vddkInitImage に指定したイメージは init コンテナとして起動され、VDDK 一式を /opt 配下へコピーして、後続の変換・転送処理(conversion pod 側)が VDDK ライブラリを参照できる状態を作ります。

[参考] Red Hat Documentation > Chapter 9. Troubleshooting > 9.3. Architecture

したがって、ここでは「起動したら VDDK ディレクトリを /opt に配置する」だけに役割を絞った最小の VDDK イメージを Dockerfile を使って build し、先ほど用意した ICR の名前空間に push します。手順は下記の通りです。

  • 作業端末に VDDK 用の作業用ディレクトリを作成し、これに移動します。
    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [11:58:06]
    mkdir ~/Downloads/vddk-image && cd ~/Downloads/vddk-image
    
  • Web ブラウザーで、下記の VMware VDDK ダウンロードページ に移動します。
    • Broadcom Developer Portal > SDKs > VMware Virtual Disk Development Kit (VDDK)
    • 筆者の検証時はバージョン 8 系が最新でしたが、本記事の執筆時点では 9 系が最新です。ただし、下記の通りバージョンの選択には注意が必要です。

MTV の VDDK init イメージは必ず「Linux 版 VDDK (tarball for Linux)」を選択してください。OpenShift (ROKS含む) の Pod は Linux コンテナ で動作しているため、コンテナの中では

  • Linux カーネル
  • Linux のユーザーランド(/lib64.so ライブラリ)

が前提になっています。したがって、下記の点に留意してください。

  • Windows 版 VDDK (DLL) は Linux コンテナからロードできません。
  • Windows 版 VDDK をコンテナに入れても、vixDiskLib.dll を Linux が理解できないので 「Exec format error」や「cannot open shared object file」 になります。

また、VDDK と vSphere のメジャーバージョンを一致させてください。例えば、移行元が vSphere 8 系であれば、VDDK も 8 系を選びます。筆者の環境で確認したところ、vSphere 8 系と VDDK 9 系の組み合わせで下記のエラーが発生しました。VDDK 8 系に切り替えたところ、Warm 移行に成功しました。

nbdkit: error: /opt/vmware-vix-disklib-distrib/lib64/libvixDiskLib.so.8: cannot open shared object file: No such file or directory

  • VDDK アーカイブファイル (.tar.gz) を先ほど作成した作業用ディレクトリに保存します。

  • VDDK アーカイブファイルを展開します。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~/Downloads/vddk-image [12:01:28] C:127
    $ tar -xzf VMware-vix-disklib-8.0.3-23950268.x86_64.tar.gz
    
    • 展開後、vmware-vix-disklib-distrib/ というディレクトリが作成されます。この中にライブラリやバイナリが入っています。
  • VDDK 一式を、MTV 実行時に生成される conversion pod の init コンテナ内の /opt 配下へ配置するための VDDK 配布用コンテナイメージをローカルで作成します。そのイメージを build するために Dockerfile を用意します。事前に vmware-vix-disklib-distrib/ ディレクトリと同じ階層に移動しておきます。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~/Downloads/vddk-image [12:06:48]
    $ cat > Dockerfile <<EOF
    FROM registry.access.redhat.com/ubi8/ubi-minimal
    USER 1001
    COPY vmware-vix-disklib-distrib /vmware-vix-disklib-distrib
    RUN mkdir -p /opt
    ENTRYPOINT ["cp", "-r", "/vmware-vix-disklib-distrib", "/opt"]
    EOF
    
    • cat > Dockerfile <<EOF … EOF
      • cat > Dockerfile <<EOF から、最後の単独行 EOF までに書かれたテキストをそのまま Dockerfile というファイルに保存する。
      • ヒアドキュメント (heredoc) という書き方
        • cat:標準入力をそのまま標準出力に流すコマンド
        • >:標準出力をファイルにリダイレクト
        • Dockerfile:出力先ファイル名
        • <<EOF:ここから EOF という行が出てくるまでの内容を「標準入力」として cat に渡す
    • USER 1001 (実行ユーザーの指定)
      • コンテナ内でコマンドを実行するユーザーIDを 1001 に指定します。
      • root ではなく非特権ユーザーで動かすための指定です。
    • COPY vmware-vix-disklib-distrib /vmware-vix-disklib-distrib (VDDK ファイル群のコピー)
      • ビルドコンテキスト (podman build を実行したディレクトリ) にある vmware-vix-disklib-distrib ディレクトリを、コンテナ内の /vmware-vix-disklib-distrib にコピーします。→ 事前に tar 展開した VDDK の一式がここに入っている想定です。
    • RUN mkdir -p /opt (展開先ディレクトリの作成)
    • コンテナ内に /opt ディレクトリを作成します (既にあれば何もしない)。
    • あとで VDDK を /opt 配下にコピーするための準備です。
  • ENTRYPOINT ["cp", "-r", "/vmware-vix-disklib-distrib", "/opt"](コンテナ起動時に実行されるコマンド)

    • コンテナが起動されたときに実行されるコマンドを指定しています。
    • JSON 配列形式なので、実際には cp -r /vmware-vix-disklib-distrib /opt と同等
    • /vmware-vix-disklib-distrib ディレクトリを /opt の下に再帰コピー (-r) する。結果として、コンテナ起動時に /opt/vmware-vix-disklib-distrib が作られる。
    • 例えば、下記のようなディレクトリ構造になっていれば良いです。
      ~/Downloads
      ├── ...
      └── vddk-image
          ├── Dockerfile
          ├── vmware-vix-disklib-distrib/
          └── VMware-vix-disklib-8.0.3-23950268.x86_64.tar.gz
      
  • VDDK イメージをローカルで build します。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~/Downloads/vddk-image [13:51:16]
    $ podman build . -t us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v3 --arch amd64 --os linux
    
    • podman build .
      • カレントディレクトリ (.) の Dockerfile を使ってコンテナイメージを build
    • -t us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v2
      • レジストリ:us.icr.io (米国リージョンの IBM Cloud Container Registry)
      • 名前空間:hmishima-ns ← 例
      • リポジトリ名:vddk
      • タグ:8.0.3-amd64-v3
    • -f オプションを利用して、使用する Dockerfile のパスを指定することもできます。(例: -f Dockerfile2)
  • VDDK イメージをレジストリ (ICR) に push します。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~/Downloads/vddk-image [14:33:50]
    $ podman push us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v3
    
    • 正しく push されたか確認します。例えば、8.0.3-amd64-v3 タグのリポジトリがあることが確認できます。

      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~/Downloads/vddk-image [14:42:37] C:1
      $ ibmcloud cr images --restrict hmishima-ns/vddk
      イメージをリストしています...
      
      リポジトリー                   タグ              ダイジェスト     名前空間       作成日            サイズ    セキュリティー状況
      us.icr.io/hmishima-ns/vddk   8.0.3-amd64-v3   1a9fea1ff880   hmishima-ns   2 months ago     84 MB    -
      
      OK
      

      IBM Cloud コンソール > Containers > Container Registry > Images からも確認できます。

  • IBM Cloud (ROKS) の管理 API から、対象のクラスタに接続するための kubeconfig (接続設定ファイル) を取得します。ROKS クラスタ内で動く conversion pod が ICR から VDDK を pull して使えるようにします。

    ibmcloud ks cluster config --cluster ■■■■■■■■■■■■■■■■■■■■ --admin
    
    • ibmcloud ks
      • IBM Cloud Kubernetes Service (ROKS を含む) の CLI
    • cluster config
      • 対象クラスタの kubeconfig をローカルにセットアップするコマンド
    • --cluster
      • でクラスタ ID を指定します。
    • --admin
      • 管理者権限 (cluster-admin 相当) の kubeconfig を取得
  • 上記のコマンドを実行後、環境変数 KUBECONFIG が設定され、oc コマンドでそのクラスタを操作可能になります。

    • まだ OpenShift CLI (oc) をインストールしていない場合はバイナリをインストールしておきます。
      [参考] Red Hat Documentation > 9.8. OpenShift CLI のインストール
  • MTV が ICR から VDDK init image を pull できるように、ServiceAccount (SA) に ICR 認証情報 (imagePullSecret) が紐付けます。ROKS では ICR を利用するための image pull secret として all-icr-io が用意されており、公式手順でも default 名前空間にある all-icr-io をコピーして各プロジェクトで利用する流れが案内されています。

    [参考] IBM Cloud Docs > Copying an existing image pull secret

    • default 名前空間の all-icr-io Secret を、MTV の名前空間 openshift-mtv と移行予定先の名前空間 (例: ocpv-lab) にコピーします。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [10:48:50] C:130
      $ NSS=(openshift-mtv ocpv-lab)
      
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:11:38]
      $ for ns in "${NSS[@]}"; do
        echo "==> applying secret/all-icr-io to namespace: ${ns}"
        out=$(
          oc get secret -n default all-icr-io -o yaml \
            | sed '/^  resourceVersion:/d;/^  uid:/d;/^  selfLink:/d;/^  creationTimestamp:/d;/^  managedFields:/,/^  name:/d' \
            | sed "s/^  namespace: default$/  namespace: ${ns}/" \
            | oc apply -f - 2>&1
        )
        echo "[${ns}] ${out}"
      done
      
      ==> applying secret/all-icr-io to namespace: openshift-mtv
      [openshift-mtv] secret/all-icr-io configured
      ==> applying secret/all-icr-io to namespace: ocpv-lab
      [ocpv-lab] secret/all-icr-io configured
      
    • 正しくコピーされたか確認します。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:34:37]
      $ (
        printf "NAMESPACE\tNAME\tTYPE\tDATA\tAGE\n"
        for ns in "${NSS[@]}"; do
          oc get secret -n "${ns}" all-icr-io --no-headers 2>/dev/null \
            | awk -v ns="${ns}" 'BEGIN{OFS="\t"} {print ns,$1,$2,$3,$4}'
        done
      ) | column -t -s $'\t'
      
      NAMESPACE      NAME        TYPE                            DATA  AGE
      openshift-mtv  all-icr-io  kubernetes.io/dockerconfigjson  1     61d
      ocpv-lab       all-icr-io  kubernetes.io/dockerconfigjson  1     144m
      
    • default ServiceAccount (SA) に all-icr-io Secret を紐付けます。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:35:04]
      $ for ns in "${NSS[@]}"; do
        echo "==> linking pull secret to default SA in namespace: ${ns}"
        out=$(oc -n "${ns}" secrets link default all-icr-io --for=pull 2>&1)
        echo "[${ns}] ${out}"
      done
      
      ==> linking pull secret to default SA in namespace: openshift-mtv
      [openshift-mtv]
      ==> linking pull secret to default SA in namespace: ocpv-lab
      [ocpv-lab]
      
    • 正しく紐付いたか確認します。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:38:39]
      $ for ns in "${NSS[@]}"; do
        echo "==> ${ns}: default SA imagePullSecrets"
        oc -n "${ns}" get sa default -o jsonpath='{range .imagePullSecrets[*]}{.name}{"\n"}{end}' | sort
      done
      
      ==> openshift-mtv: default SA imagePullSecrets
      all-icr-io
      default-dockercfg-rlcgp
      ==> ocpv-lab: default SA imagePullSecrets
      all-icr-io
      default-dockercfg-gbw2t
      
    • 任意の安全策として、openshift-mtv 名前空間に存在する forklift-controller SA にも同じ secret を紐付けました。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:43:05]
      $ oc -n openshift-mtv secrets link forklift-controller all-icr-io --for=pull
      
    • テスト用の一時 Pod を作成し、VDDK init image を pull できるかテストします。
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:39:03]
      $ oc run -n openshift-mtv vddk-pulltest \
        --restart=Never \
        --image=us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v3
      pod/vddk-pulltest created
      
      # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [15:40:48]
      $ oc describe pod -n openshift-mtv vddk-pulltest | sed -n '/Events/,$p'
      Events:
        Type    Reason          Age   From               Message
        ----    ------          ----  ----               -------
        Normal  Scheduled       12s   default-scheduler  Successfully assigned openshift-mtv/vddk-pulltest to kube-d4okn6ad02tla11413g0-acsosvclust-workerp-0000033f
        Normal  AddedInterface  11s   multus             Add eth0 [172.17.32.203/32] from k8s-pod-network
        Normal  Pulling         11s   kubelet            Pulling image "us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v3"
        Normal  Pulled          4s    kubelet            Successfully pulled image "us.icr.io/hmishima-ns/vddk:8.0.3-amd64-v3" in 7.173s (7.173s including waiting). Image size: 196682694 bytes.
        Normal  Created         4s    kubelet            Created container: vddk-pulltest
        Normal  Started         4s    kubelet            Started container vddk-pulltest
      
      • Successfully pulled image ... と出力されており、正常にイメージを pull できていることが確認できます。

5. DNS の設定

MTV の VMware Provider は vCenter への接続自体は IP アドレスでも成立しますが、実際の移行処理(データ転送)では ESXi ホスト (vSphere ホスト )へ FQDN (ホスト名) で接続しようとします。そのため、OpenShift クラスタ (=MTV の Pod) から ESXi のホスト名が名前解決できることは移行成功の前提条件になります。

本記事内の検証で利用している VMware 環境 (VCF for Classic - Automated) において、ESXi ホスト名は VCS インスタンス (DNS) で管理されており、最終的にドメインコントローラー(AD DNS)へ問い合わせが委譲される構成になっています。したがって、移行開始前に VCS 側の対象ドメインをドメインコントローラーへ委譲 (DNS delegation / forwarder) できるように環境を整備し、OpenShift から ESXi の FQDN を解決できる状態にしておく必要があります。

5-1. DNS のステータス確認

  • OpenShift クラスタの DNS 機能 (DNS Operator / CoreDNS) がクラスタ全体として健全か否かを確認します。

[参考] Red Hat Documentation > 7.1. Checking the status of the DNS Operator

# hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [17:08:04]
$ oc get clusteroperator/dns
NAME   VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
dns    4.18.30   True        False         False      76d
  • NAME: dns
    • 対象の ClusterOperator 名です。
  • VERSION: 4.18.30
    • DNS Operator が「この OpenShift バージョン (4.18.30) 向けの状態」になっている、という意味です。クラスタのバージョンと揃うのが普通です。
  • AVAILABLE: True
    • DNS 機能は 提供可能(正常稼働)。
    • CoreDNS が動いていて、クラスタ内の名前解決が成立している状態です。
  • PROGRESSING: False
    • 何かの 変更・更新・再構成の途中ではない、という意味です。
    • 例えば、DNS の設定を変更してロールアウト中なら True になることがあります。
  • DEGRADED: False
    • 劣化状態 (エラーや重大な問題) ではない。
    • 例えば、CoreDNS Pod が落ち続けている、設定不整合、必要なデプロイができない、などのとき True になります。

clusteroperator は OpenShift の主要コンポーネント (Operator) の状態を表す “クラスタ全体スコープ” のリソースです。/dns はその中の DNS Operator (名前: dns) を指定しています。ここで言う "DNS" は、Pod が名前解決に使う CoreDNS (openshift-dns) と、それを管理する DNS Operator (openshift-dns-operator) の全体を指します。したがって、この結果は「DNS Operator 自体は健全」という確認です。ただし、これは “vCenter/ESXi のドメインが引けるようになっているか” までは保証しません。

標準の OpenShift では、DNS Operator はインストール時に名前空間 openshift-dns-operatordns-operator という Deployment としてデプロイされます。しかし ROKS では コントロールプレーン系コンポーネント (Operator 含む) の多くを IBM 側が管理します。そのため、名前空間 openshift-dns-operator 内で DNS Operator 本体 (Deployment) が 常にユーザーから見えるとは限りません。

  • DNS の設定である default カスタムリソース (CR) の内容を確認します。

[参考] Red Hat Documentation > 7.2. View the default DNS

# hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [12:09:21]
$ oc describe dns.operator/default
Name:         default
Namespace:
Labels:       <none>
Annotations:  <none>
API Version:  operator.openshift.io/v1
Kind:         DNS
...
Status:
  Cluster Domain:  cluster.local
  Cluster IP:      172.21.0.10
...
  • default CR に記述される内容は、下記のような「DNS の論理的な設定」です。

    • DNS フォワード (どの上流 DNS に投げるか)
    • キャッシュ設定
    • 追加のゾーン設定
  • Cluster IP は、Pod が名前解決のために問い合わせを行う IP アドレスです。この IP アドレスは、Service CIDR 範囲における10番目のアドレスとして定義されます。

  • 名前空間 openshift-dns に DNS の入口となる Service (openshift-dns/dns-default) が存在することを確認します。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [11:00:54]
    $ oc get svc -n openshift-dns
    NAME          TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
    dns-default   ClusterIP   172.21.0.10   <none>        53/UDP,53/TCP,9154/TCP   77d
    
    • dns-default Service は、クラスタ内DNSの入口(ClusterIP) です。Pod は通常、この Service の CLUSTER-IPnameserver として参照して DNS クエリを投げます。
    • PORT(S) 列の出力
      • 53/UDP, 53/TCP:DNS クエリ用
      • 9154/TCP:CoreDNS メトリクス用(監視)
  • クラスタ内の任意の(通常の)Pod の resolv.conf が、その Service を nameserver として参照して、実際に名前解決できることを確認します。

    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [11:01:33]
    $ oc run -n openshift-mtv -it --rm dns-test \
      --restart=Never \
      --image=registry.access.redhat.com/ubi9/ubi-minimal \
      --overrides='{
        "apiVersion":"v1",
        "spec":{
          "securityContext":{
            "runAsNonRoot":true,
            "seccompProfile":{"type":"RuntimeDefault"}
          },
          "containers":[{
            "name":"dns-test",
            "image":"registry.access.redhat.com/ubi9/ubi-minimal",
            "command":["sh","-lc","cat /etc/resolv.conf; echo; getent hosts kubernetes.default.svc"],
            "securityContext":{
              "allowPrivilegeEscalation":false,
              "capabilities":{"drop":["ALL"]}
            }
          }]
        }
      }'
    
    search ocpv-lab.svc.cluster.local svc.cluster.local cluster.local
    nameserver 172.21.0.10
    options ndots:5
    
    172.21.0.1      kubernetes.default.svc.cluster.local
    pod "dns-test" deleted
    
    • 上記のコマンドでは、oc run で MTV の名前空間 openshift-mtv に一時 Pod を起動し、下記の2点を確認しています。
      • cat /etc/resolv.conf で Pod の DNS 設定(nameserver, search, ndots)
        • nameserver <IP> が、1つ前のステップで確認した openshift-dns/dns-defaultCLUSTER-IP (172.21.0.10) と一致したため、Pod は dns-default Service 経由で CoreDNS を正しく使っている状態と判断できます。
      • getent hosts kubernetes.default.svc で 実際に名前解決できること
        • 172.21.0.1 kubernetes.default.svc.cluster.local から、Pod → DNS(CoreDNS)→ Service 名解決が正常に動作していると判断できます。
    • コマンドの意味
      • oc run -n openshift-mtv -it --rm dns-test ... --restart=Never
        • dns-test という一時 Pod を起動して、対話(-it)で実行し、終了後に削除(--rm)します。
        • --restart=Never は Job/Deployment ではなく Pod を1回だけ実行する指定です。
      • --image=registry.access.redhat.com/ubi9/ubi-minimal
        • 軽量な UBI(Red Hat 公式)イメージで検証します。
      • --overrides='...JSON...'
        • oc run の生成 Pod 定義に対して、警告「Warning: would violate PodSecurity "restricted:latest":...」を回避するために、PodSecurity “restricted” を満たすように、実行したいコマンドを明示的な上書きし、後述の securityContext を追記します。
      • command: ["sh","-lc","cat /etc/resolv.conf; ..."]
        • Pod 内で以下を順に実行します。
          • cat /etc/resolv.conf:Pod が参照している DNS 設定の確認
          • getent hosts kubernetes.default.svc:Kubernetes の標準 Service 名を引けるか確認
      • securityContext (restricted の必須要件)
        • runAsNonRoot: true:root 実行を禁止
        • allowPrivilegeEscalation: false:権限昇格を禁止
        • containers.seccompProfile: RuntimeDefault:seccomp をデフォルトプロファイルで適用
        • containers.capabilities.drop: ["ALL"]:Linux capability をすべて落とす

以上で、DNS のステータス確認は十分です。

5-2. DNS フォワーディングの設定

MTV(VMware Provider)は vCenter だけでなく、移行実行時に ESXi ホストへ接続してデータ転送を行う場面があります。このとき、最終的に OpenShift クラスタ内から ESXi ホストへ FQDN(ホスト名)で到達できること(= DNS で名前解決できること)が重要になります。

そこで、クラスタ内の Pod から vCenter / ESXi の FQDN を解決できるように、OpenShift の DNS Operator(dns.operator/default)に ゾーン単位の DNS フォワーディング(per-zone forwarding) を設定します。

[参考] Red Hat Documentation > 7.3. Using DNS forwarding

  • DNS Operator オブジェクトである default カスタムリソース (CR) を変更します。
    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [12:08:31]
    $ oc edit dns.operator/default
    
    • DNS フォワーディングは /etc/resolv.conf のデフォルト転送設定を “ゾーン単位で” 上書きできます。ここでは corp.example.local だけを社内 DNS(例:10.0.0.53)へ転送します。
  • 以下を spec: に追加(または既存を調整)します。
    spec:
      servers:
      - name: addns
        zones:
        - corp.example.local
        forwardPlugin:
          policy: Random
          upstreams:
          - 10.0.0.53
    
      upstreamResolvers:
        policy: Sequential
        upstreams:
        - type: SystemResolvConf
          port: 53
    
    • spec.servers[]:特定ゾーン向けの転送ルール(per-zone forwarding)
      • name: addns:このルールの識別名(任意)
      • zones: [corp.example.local]*.corp.example.local に一致する問い合わせを対象にする
      • forwardPlugin.upstreams: [10.0.0.53]:その問い合わせをこの DNS に転送
      • policy: Randomupstream が複数ある場合の選び方(今回は1個なので実質どれでも同じ)
    • spec.upstreamResolversservers にマッチしない名前解決の転送先
      • type: SystemResolvConf:ノードの /etc/resolv.conf を上流として使う
  • default CR の設定が CoreDNS に入っているか確認します。
    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [12:33:48]
    $ oc get dns.operator/default -o yaml | sed -n '/^spec:/,/^status:/p'
    
    • spec.servers に追加した内容が見えることを確認します。
  • クラスタ内 Pod から vCenter と ESXi ホスト の FQDN を名前解決できるか確認します。
    # hiroaki.mishima @ HiroakinoMacBook-Pro in ~ [12:38:40]
    $ oc run -n openshift-mtv -it --rm dns-test \
      --restart=Never \
      --image=registry.access.redhat.com/ubi9/ubi-minimal \
      --overrides='{
        "apiVersion":"v1",
        "spec":{
          "securityContext":{
            "runAsNonRoot":true,
            "seccompProfile":{"type":"RuntimeDefault"}
          },
          "containers":[{
            "name":"dns-test",
            "image":"registry.access.redhat.com/ubi9/ubi-minimal",
            "command":["sh","-lc","cat /etc/resolv.conf; getent hosts vcsosv-vc.corp.example.local; getent hosts host-km000.corp.example.local"],
            "securityContext":{
              "allowPrivilegeEscalation":false,
              "capabilities":{"drop":["ALL"]}
            }
          }]
        }
      }'
    
    search openshift-mtv.svc.cluster.local svc.cluster.local cluster.local
    nameserver 172.21.0.10
    options ndots:5
    10.0.0.10  vcsosv-vc.corp.example.local
    10.0.0.11  host-km000.corp.example.local
    pod "dns-test" deleted
    
    • nameserver 172.21.0.10
      • Pod はクラスタ DNS (名前空間 openshift-dnsdns-default Service) を使うことができています。
    • 10.0.0.10 vcsosv-vc.corp.example.local / 10.0.0.11 host-km000...
      • vCenter / ESXI ホストの FQDN が 転送先 DNS により名前解決できています。

6. VMware ESXi ホストの NFC サービスメモリーの拡張

MTV の単一の移行プラン (Migration plan) で ESXi ホストから 10 台を超える仮想マシンを移行する場合は、ホストの Network File Copy (NFC) サービスメモリーを増やす必要があります。NFC サービスメモリーは 10 個の並列接続に制限されているため、最大メモリサイズが不足すると VM 移行が失敗します。

任意の設定ですが、実施する場合は下記の Broadcom の記事を参考にしてください。

[参考] vSphere ESXi 7.0 Update 2 以降で Hostd サービスの設定を変更する方法

おわりに (予告)

本記事 (#1 準備編) では、MTV (VMware Provider) で vSphere から OpenShift Virtualization on IBM ROKS へ Cold/Warm 移行を実行するための前提条件を、OCPv 側・VMware 側それぞれの観点で整理しました。具体的には、MTV Operator の導入、Warm 移行に必須となる CBT の有効化、VDDK イメージの作成と ICR への格納、vCenter/ESXi の FQDN を解決するための DNS フォワーディング設定などを確認しています。

ここまでの準備ができていれば、「MTV を触ってみたけど Provider 登録や実行フェーズで詰まる」「Warm を選んだのに増分が効かない」「移行途中で ESXi への接続に失敗する」といった典型的なハマりどころを、かなり手前で潰せるはずです。言い換えると、本記事の到達点は “移行 Plan を作って実行できる状態が整った” というところです。

次回 (#2 実行編) では、いよいよ MTV の VMware Provider を登録し、まずは Cold 移行を確実に成功させます。その上で、Warm 移行として初回同期 → 増分同期 (CBT) → Cutover (停止 → 最終同期 → 切替) までの一連の流れを、UI の画面と確認ポイント (ログ確認、調査観点) を交えて解説します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?