2023年1月28日土曜日

【PowerCLI】仮想マシンハードウェアをバージョンアップする方法

ESXiをバージョンアップした際などに、仮想マシンのサマリ画面にて「この仮想マシンに設定されたゲストは、現在実行中のゲストと一致しません」といった警告メッセージが表示される場合がある。

これは、バージョンアップ前のESXiでは対応していなかったOS種別が、新しいESXiの仮想マシンハードウェアで対応したことの影響となる。

特に仮想マシンの動作に影響を及ぼすものではないが、警告メッセージを消したい場合は、ハードウェアバージョンアップを行ったのち、仮想マシンのゲストOS設定を修正する必要がある。ただし、仮想マシンのハードウェアバージョンアップはVMware Host Clientでは行うことはできない。

そこで本記事では、PowerCLIを用いて仮想マシンハードウェアをバージョンアップをする方法を記載する。

環境

本環境を実施した環境は以下の通り。vCenter Serverは構築していないため、ESXiに対してPowerCLIからコマンド実行を行う。

  • ESXi : 7.0 Update 3 (20328353)
  • PowerCLI : 12.7.0 build 20091289
  • 作業対象仮想マシン名 : vyos
    • 仮想マシンハードウェア(前) : vmx-14
    • 仮想マシンハードウェア(後) : vmx-19

仮想マシンハードウェアのバージョンアップ手順

1. 仮想マシンを停止

本作業の前提として仮想マシンの停止が必要となるため、あらかじめ作業対象の仮想マシンを停止しておく。

2. バージョンアップ前確認

バージョンアップ前に仮想マシンハードウェアのバージョン確認を行う。HardwareVersionが仮想マシンハードウェアを表しており、バージョンアップ前はvmx-14であることがわかる。これはESXi 6.7が対応しているバージョンとなる。

PS> Get-VM vyos| fl *

Name                    : vyos
PowerState              : PoweredOff

~(中略)~

Version                 : v14
HardwareVersion         : vmx-14 ★
PersistentId            : 528c62f8-48d4-4ccc-0a7d-a05c02f07afa
GuestId                 : debian10_64Guest

~(以下略)~

2. バージョンアップ前スナップショット取得

バージョンアップ前に念のため仮想マシンのスナップショットを取得しておく。

PS> Get-VM vyos| New-Snapshot -Name "Before hardware version upgrade"

Name                 Description                    PowerState
----                 -----------                    ----------
Before hardware v...                                PoweredOff

3. 仮想マシンハードウェアをバージョンアップ

バージョンアップは以下コマンドで実行する。今回はESXi 7.0 Update 2以降で対応しているvmx-19にバージョンアップを行った。コマンドを実行すれば処理はすぐに完了する。

PS> (Get-VM vyos).ExtensionData.UpgradeVM('vmx-19')

なお、以前のPowerCLIではSet-VMコマンドレットでバージョンアップできたようだが、PowerCLI 12.7では以下の通り実行に失敗するので注意。

PS> Get-VM vyos| Set-VM -Version "v19" -Confirm:$false
Set-VM : パラメーター 'Version' をバインドできません。値 "v19" を型 "VMware.VimAutomation.ViCore.Types.V1.VM.VMVersion"
 に変換できません。エラー: "識別子名 v19 は有効な列挙子名に一致しません。次のいずれかの列挙子名を指定して再試行してくだ
さい:
Unknown, v4, v7, v8, v9, v10, v11, v12, v13, v14"
発生場所 行:1 文字:36
+ Get-VM vyos| Set-VM -Version "v19" -Confirm:$false
+                                    ~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-VM]、ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,VMware.VimAutomation.ViCore.Cmdlets.Commands.SetVM

4. バージョンアップ後確認

バージョンアップ後の仮想マシンの状態確認を行う。HardwareVersionvmx-19になっていれば問題ない。

PS> Get-VM vyos| fl *


警告: The 'Version' property of VirtualMachine type is deprecated. Use the 'HardwareVersion' property instead.
Name                    : vyos
PowerState              : PoweredOff

~(中略)~

Version                 : Unknown
HardwareVersion         : vmx-19 ★
PersistentId            : 528c62f8-48d4-4ccc-0a7d-a05c02f07afa
GuestId                 : debian10_64Guest

~(以下略)~

5. ゲストOS設定変更&仮想マシン起動

VMware Host Clientにログインし、[対象の仮想マシン]→[設定の編集]→[仮想マシン オプション]→[一般オプション]→[ゲストOSのバージョン]から、警告メッセージに表示されていたOSを選択する。なお、仮想マシンハードウェアのバージョンをバージョンアップしていない場合は、そもそも選択肢に新しいOSは表示されないため注意しよう。

その後、仮想マシンを起動することで、警告メッセージが消えるはずだ。

6. バージョンアップ後スナップショット削除

その後の仮想マシンが問題なく起動したようであれば、作業前のバックアップを削除する。

PS> Get-VM vyos| Get-Snapshot -Name "Before hardware version upgrade" | Remove-Snapshot -Confirm:$false

以上で、PowerCLIを用いて仮想マシンハードウェアをバージョンアップをする方法の説明は終了となる。

参考

2023年1月21日土曜日

【PowerShell】Windowsのディスクのオンライン・オフラインとドライブレターを設定する

Windowsでは通常、昔から変わらない「ディスクの管理」画面を開いてディスクのオンライン・オフラインや、ドライブレターの変更作業をすることが多い。

あまりシチュエーションとしては多くないかもしれないが、定期的にディスクをオンライン・オフラインにしたりドライブレターの変更をする作業があるかもしれない。そのような場合は、PowerShellを使えば同様の作業がCLIベースで実施でき、あらかじめスクリプトなどを作っておけば自動化も可能となる。

本記事では、PowerShellを使ってWindowsのディスクのオンライン・オフラインとドライブレター変更の手順を記載する。

環境

Windows Server 2019を用いて動作確認を行った。

ディスクはCドライブ以外に2つ用意する。ディスク1をオンライン、ディスク2をオフラインにしておき、PowerShellを用いて以下の通りディスクの入れ替えを行う。

作業前

ディスクNo ドライブレター 容量 [GB] 状態
0 C 40 オンライン
1 U 30 オンライン
2 なし 32 オフライン

作業前

ディスクNo ドライブレター 容量 [GB] 状態
0 C 40 オンライン
1 なし 30 オフライン
2 U 32 オンライン

ディスクのマウント手順

1. ディスクの状態を確認

作業対象のディスクを確認する。ディスク情報を確認するコマンドレットは、以下3つが存在する。

コマンドレット 説明
Get-Disk 物理ディスクの一覧を表示する。オフラインのディスクも表示される。
Get-Volume 初期化及びフォーマット済みのディスクの一覧を表示する。オフラインのディスク上のボリュームは表示されない。
Get-Partition 各ディスクのパーティション一覧を表示する。オフラインのディスク上のパーティションは表示されない。

実行結果を以下に示す。

Get-Disk

PS C:\> Get-Disk

Number Friendly Name Serial Number                    HealthStatus         OperationalStatus      Total Size Partition
                                                                                                             Style
------ ------------- -------------                    ------------         -----------------      ---------- ----------
0      VMware Vir... 6000c298f4905127fbf4b8af93289b7c Healthy              Online                      40 GB GPT
1      VMware Vir... 6000c29155e1a0ea6d59319bfb0965df Healthy              Online                      30 GB GPT
2      VMware Vir... 6000c298d8b95c7aa7fa9c84622b5faa Healthy              Offline                     32 GB GPT

Get-Volume

PS C:\> Get-Volume

DriveLetter FriendlyName FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining      Size
----------- ------------ -------------- --------- ------------ ----------------- -------------      ----
            回復         NTFS           Fixed     Healthy      OK                     57.05 MB    499 MB
D           VMware Tools Unknown        CD-ROM    Healthy      OK                          0 B 140.61 MB
C                        NTFS           Fixed     Healthy      OK                     29.84 GB   39.4 GB
U           ボリューム   NTFS           Fixed     Healthy      OK                     20.32 GB  29.98 GB
                         FAT32          Fixed     Healthy      OK                     69.12 MB     95 MB

Get-Partition

PS C:\> Get-Partition

   DiskPath: \\?\scsi#disk&ven_vmware&prod_virtual_disk#000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

PartitionNumber  DriveLetter Offset                                        Size Type
---------------  ----------- ------                                        ---- ----
1                            1048576                                     499 MB Recovery
2                            524288000                                    99 MB System
3                            628097024                                    16 MB Reserved
4                C           644874240                                  39.4 GB Basic


   DiskPath: \\?\scsi#disk&ven_vmware&prod_virtual_disk#000100#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

PartitionNumber  DriveLetter Offset                                        Size Type
---------------  ----------- ------                                        ---- ----
1                            17408                                     15.98 MB Reserved
2                U           16777216                                  29.98 GB Basic


   DiskPath: \\?\scsi#disk&ven_vmware&prod_virtual_disk#000200#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

PartitionNumber  DriveLetter Offset                                        Size Type
---------------  ----------- ------                                        ---- ----
1                            17408                                     15.98 MB Reserved
2                            16777216                                  31.98 GB Basic

2. ディスク設定変更

確認結果より、今回はディスクNo1とディスクNo2をPowerShellにて入れ替える。

ディスクのオンライン・オフラインはSet-Diskコマンドレットで共通して操作可能だが、ドライブレターの削除(Remove-PartitionAccessPath)と追加(Set-Partition)はコマンドレットが異なる点に注意しよう。

# 取り外し対象ディスクNo
$old_disk_number=1
$old_driveletter=(Get-Disk -Number ${new_disk_number} | Get-Partition -Number 2).DriveLetter
# 取付対象ディスクNo
$new_disk_number=2
$new_driveletter="U"

# ドライブレターの削除
Get-Disk -Number ${old_disk_number} | Get-Partition -Number 2 | Remove-PartitionAccessPath -AccessPath "${old_driveletter}:"
# ディスクのオフライン
Get-Disk -Number ${old_disk_number} | Set-Disk -IsOffline $true

# ディスクのオンライン
Get-Disk -Number ${new_disk_number} | Set-Disk -IsOffline $false
# ドライブレターの付与
Get-Disk -Number ${new_disk_number} | Get-Partition -Number 2 | Set-Partition -NewDriveLetter ${new_driveletter}

ディスクの状態を戻す場合は、ディスクNoの変数を入れ替えればよい (★箇所)。

# 取り外し対象ディスクNo
$old_disk_number=2 #←★2に変更
$old_driveletter=(Get-Disk -Number ${new_disk_number} | Get-Partition -Number 2).DriveLetter
# 取付対象ディスクNo
$new_disk_number=1 #←★1に変更
$new_driveletter="U"

# ドライブレターの削除
Get-Disk -Number ${old_disk_number} | Get-Partition -Number 2 | Remove-PartitionAccessPath -AccessPath "${old_driveletter}:"
# ディスクのオフライン
Get-Disk -Number ${old_disk_number} | Set-Disk -IsOffline $true

# ディスクのオンライン
Get-Disk -Number ${new_disk_number} | Set-Disk -IsOffline $false
# ドライブレターの付与
Get-Disk -Number ${new_disk_number} | Get-Partition -Number 2 | Set-Partition -NewDriveLetter ${new_driveletter}

以上で、PowerShellを使ってィスクのオンライン・オフラインとドライブレター変更の手順は完了となる。

参考

2023年1月14日土曜日

AnsibleでVyOSを操作する

自宅ではAnsibleを導入してから、以下OSやソフトウェアに対して作業のコード化や自動化を行ってきた。導入手順などは以下記事を参照。

OS/ソフトウェア URL
Linux AnsibleでLinuxサーバの初期設定と単体テストを行う
Windows Server AnsibleからWindows Serverに接続するための事前作業
vSphere ESXi AnsibleでESXi上に仮想マシンを構築する

今回は、Ansibleを使って仮想ルーターOSであるVyOSを操作する手順を記載する。VyOSは、Ansibleに標準で導入されているvyos.vyosというモジュールで操作可能となる。

環境

今回手順を確認した環境は以下の通り。

  • コントロールノード
    • OS : AlmaLinux 8.5
    • Ansible : ansible [core 2.13.1]
  • VyOS : 1.4

VyOSの各種設定を行うPlaybook

今回のPlaybookでは、VyOSに対して各種設定を行い、設定後にコンフィグをファイルとして保存する。

以下にPlaybookの内容を説明する。

Playbook説明

変数 (vars)

Ansibleを使ってVyOSを操作する際の変数は、以下の通り設定する。VyOSはCisco機器のようなansible_become_methodの設定値は不要となる。

変数 設定値
ansible_user 任意のSSH接続用ユーザを設定。今回はvyosで設定。
ansible_password 任意のSSH接続用ユーザのパスワードを設定。
ansible_connection network_cli
ansible_network_os vyos
vyos_interface インタフェースのdescriptionやIPアドレスを設定。
vyos_ntp_server 時刻同期先のNTPサーバを設定。
vyos_snmp SNMPに必要となるコミュニティ名やTrapターゲットを設定する。なお、TrapソースのIPアドレス指定する際に、vyos_interfaceの変数からIPアドレスを取得している。
vyos_route スタティックルートを設定。

タスク (tasks)

Playbookのタスクは以下の通り。主にvyos.vyosモジュールで個別に用意されている設定モジュールを使って設定可能なものをタスクとして作成した。これ以外の設定に関しては、vyos.vyos.vyos_configを使って、VyOSのコマンドを直接流して設定することができる(当然その際には冪等性には注意すること)。

タスク モジュール 説明
事前config保存(save) & configファイル取得 vyos.vyos.vyos_config VyOSのconfigを取得する。取得内容はshow configuration commandsの内容となる。また、configが保存されていないことを想定して、save: trueを設定する。
タイムゾーン設定 vyos.vyos.vyos_config タイムゾーンを設定する。タイムゾーンを設定するモジュールはないため、直接設定コマンドを実行する。
ホスト名設定 vyos.vyos.vyos_hostname ホスト名を設定する。
インタフェース設定 vyos.vyos.vyos_interfaces インタフェースのdescriptionを設定する。本来はIPアドレスもこのモジュールで設定できるが、次のタスクでIPv6を無効化する際に、IPアドレスの再設定が必要になることから、本タスクでは設定は省略している。
インタフェース設定 (IPアドレス設定 & IPv6 無効化) vyos.vyos.vyos_config IPアドレスとIPv6の無効化設定を直接コマンドにて設定する。
SSH & Console設定 vyos.vyos.vyos_config SSHとConsoleの設定を直接設定コマンドにて設定する
NTP設定 vyos.vyos.vyos_ntp_global NTPによる時刻同期先の設定を行う。
SNMP設定 vyos.vyos.vyos_snmp_server SNMPの設定を行う。SNMP Trapのターゲット設定は本モジュールでは動作に失敗したため、次のタスクにて直接コマンドにて設定する。
SNMP設定 (Trap target) vyos.vyos.vyos_config SNMP Trapのターゲット設定を直接コマンドにて設定する。
スタティックルート設定 vyos.vyos.vyos_static_routes スタティックルートを設定する。
事後config保存(save) & configファイル取得 vyos.vyos.vyos_config VyOSのconfigを取得する。
ファイル差分確認 ansible.builtin.command Linuxのdiffコマンドにて、設定前後のconfig比較を行う。
ファイル差分表示 ansible.builtin.debug diffコマンドの比較結果を表示する。

Playbook

以上をふまえ、Playbook全体は以下となる。

set_vyos_global_settings.yml

---
- name: Set vyos global settings
  gather_facts: true
  hosts: vyos

  vars:
    ansible_user: vyos
    ansible_password: 'P@ssw0rd!'
    ansible_connection: network_cli
    ansible_network_os: vyos

    vyos_interface:
      - name: eth0
        description: OUTSIDE
        address: 192.168.3.4
        prefix: 24
      - name: eth1
        description: INSIDE
        address: 192.168.1.4
        prefix: 24

    vyos_ntp_server:
      - server: 192.168.3.2

    vyos_snmp:
      community: public
      authorization_type: ro
      trap_source: '{{ (vyos_interface | selectattr("name", "==", "eth1") | first).address }}'
      trap_target: 192.168.1.24
      trap_community: public

    vyos_route:
      dest: 0.0.0.0/0
      next_hop: 192.168.3.254

  tasks:
    # 事前config保存(save) & configファイル取得
    - name: Get configuration command
      vyos.vyos.vyos_config:
        backup: true
        backup_options:
          dir_path: "{{ lookup('env', 'PWD') }}/vyos"
          filename: "{{ inventory_hostname }}_conf_before.log"
        save: true

    # タイムゾーン設定
    - name: Set timezone
      vyos.vyos.vyos_config:
        lines:
          - set system time-zone 'Asia/Tokyo'

    # ホスト名設定
    - name: Set hostname
      vyos.vyos.vyos_hostname:
        config:
          hostname: "{{ inventory_hostname }}"
        state: replaced

    # インタフェース設定
    - name: Set interfaces
      vyos.vyos.vyos_interfaces:
        config:
          - name: "{{ item.name }}"
            description: "{{ item.description }}"
        state: replaced
      loop: "{{ vyos_interface }}"

    # インタフェース設定 (IPアドレス設定 & IPv6 無効化)
    - name: Set interfaces ipv6 address
      vyos.vyos.vyos_config:
        lines:
          - set interfaces ethernet {{ item.name }} address {{ item.address }}/{{ item.prefix }}
          - set interfaces ethernet {{ item.name }} ipv6 address no-default-link-local
      loop: "{{ vyos_interface }}"

    # SSH & Console設定
    - name: Set SSH and consle
      vyos.vyos.vyos_config:
        lines:
          - set service ssh listen-address '{{ (vyos_interface | selectattr("name", "==", "eth1") | first).address }}'
          - delete system console

    # NTP設定
    - name: Set ntp server
      vyos.vyos.vyos_ntp_global:
        config:
          servers: "{{ vyos_ntp_server }}"
        state: replaced

    # SNMP設定
    # Trap targetは「requires a community to be set!」のエラーで失敗する
    # 設定をすべて置き換えをしないよう、state: mergedを指定
    - name: Set snmp
      vyos.vyos.vyos_snmp_server:
        config:
          communities:
            - name: "{{ vyos_snmp.community }}"
              authorization_type: "{{ vyos_snmp.authorization_type }}"
          trap_source: "{{ vyos_snmp.trap_source }}"
        state: merged

    # SNMP設定 (Trap target)
    - name: Set snmp trap target
      vyos.vyos.vyos_config:
        lines:
          - set service snmp trap-target {{ vyos_snmp.trap_target }} community {{ vyos_snmp.trap_community }}

    # スタティックルート設定
    - name: Set static route
      vyos.vyos.vyos_static_routes:
        config:
          - address_families:
              - afi: ipv4
                routes:
                  - dest: "{{ vyos_route.dest }}"
                    next_hops:
                      - forward_router_address: "{{ vyos_route.next_hop }}"
        state: replaced

    # 事後config保存(save) & configファイル取得
    - name: Get configuration command
      vyos.vyos.vyos_config:
        backup: true
        backup_options:
          dir_path: "{{ lookup('env', 'PWD') }}/vyos"
          filename: "{{ inventory_hostname }}_conf_after.log"
        save: true

    # ファイル差分確認
    # 差分があった場合も処理を継続するため、failed_when: falseを付与
    - name: Diff configuration
      ansible.builtin.command: |
        diff "vyos/{{ inventory_hostname }}_conf_before.log" "vyos/{{ inventory_hostname }}_conf_after.log"
      register: result
      changed_when: false
      delegate_to: localhost
      failed_when: false

    # ファイル差分表示
    - name: Show configuration differences
      ansible.builtin.debug:
        msg: "{{ result.stdout_lines }}"

実行結果

Playbookの実行結果は以下の通り。事前と事後でconfig比較を行い、設定差分がわかるようになっている。

# ansible-playbook -i hosts -l t3034vyos vyos/set_vyos_global_settings_sample.yml 

PLAY [Set vyos global settings] ********************************************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [t3034vyos]

TASK [Get configuration command] *******************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set timezone] ********************************************************************************************************************************************************
[WARNING]: To ensure idempotency and correct diff the input configuration lines should be similar to how they appear if present in the running configuration on device
changed: [t3034vyos]

TASK [Set hostname] ********************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set interfaces] ******************************************************************************************************************************************************
changed: [t3034vyos] => (item={'name': 'eth0', 'description': 'OUTSIDE', 'address': '192.168.3.34', 'prefix': 24})
changed: [t3034vyos] => (item={'name': 'eth1', 'description': 'INSIDE', 'address': '192.168.1.34', 'prefix': 24})

TASK [Set interfaces ipv6 address] *****************************************************************************************************************************************
changed: [t3034vyos] => (item={'name': 'eth0', 'description': 'OUTSIDE', 'address': '192.168.3.34', 'prefix': 24})
changed: [t3034vyos] => (item={'name': 'eth1', 'description': 'INSIDE', 'address': '192.168.1.34', 'prefix': 24})

TASK [Set SSH and consle] **************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set ntp server] ******************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set snmp] ************************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set snmp trap target] ************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Set static route] ****************************************************************************************************************************************************
changed: [t3034vyos]

TASK [Get configuration command] *******************************************************************************************************************************************
changed: [t3034vyos]

TASK [Diff configuration] **************************************************************************************************************************************************
ok: [t3034vyos -> localhost]

TASK [Show configuration differences] **************************************************************************************************************************************
ok: [t3034vyos] => {
    "msg": [
        "0a1,2",
        "> set interfaces ethernet eth0 address '192.168.3.4/24'",
        "> set interfaces ethernet eth0 description 'OUTSIDE'",
        "1a4",
        "> set interfaces ethernet eth0 ipv6 address no-default-link-local",
        "3a7",
        "> set interfaces ethernet eth1 description 'INSIDE'",
        "4a9",
        "> set interfaces ethernet eth1 ipv6 address no-default-link-local",
        "6c11,15",
        "< set service ssh",
        "---",
        "> set protocols static route 0.0.0.0/0 next-hop 192.168.3.254",
        "> set service snmp community public authorization 'ro'",
        "> set service snmp trap-source '192.168.1.4'",
        "> set service snmp trap-target 192.168.1.24 community 'public'",
        "> set service ssh listen-address '192.168.1.4'",
        "15,16c24",
        "< set system console device ttyS0 speed '115200'",
        "< set system host-name 'vyos'",
        "---",
        "> set system host-name 't3034vyos'",
        "18,20c26",
        "< set system ntp server time1.vyos.net",
        "< set system ntp server time2.vyos.net",
        "< set system ntp server time3.vyos.net",
        "---",
        "> set system ntp server 192.168.3.2",
        "22c28,29",
        "< set system syslog global facility protocols level 'debug'",
        "\\ ファイル末尾に改行がありません",
        "---",
        "> set system syslog global facility protocols level 'debug'",
        "> set system time-zone 'Asia/Tokyo'",
        "\\ ファイル末尾に改行がありません"
    ]
}

PLAY RECAP *****************************************************************************************************************************************************************
t3034vyos                  : ok=14   changed=11   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

VyOSのconfigファイルも以下の通り出力される。

vyos/t3034vyos_conf_after.log

set interfaces ethernet eth0 address '192.168.3.4/24'
set interfaces ethernet eth0 description 'OUTSIDE'
set interfaces ethernet eth0 hw-id '00:0c:29:b8:da:49'
set interfaces ethernet eth0 ipv6 address no-default-link-local

~(以下略)~

以上で、Ansibleを使って仮想ルーターOSであるVyOSを操作する手順は完了となる。

2023年1月7日土曜日

「minikube」を使ってKubernetes検証環境を構築する手順

コンテナのオーケストレーションツールのデファクトスタンダードとなっているKubernetesは、仕組みが複雑であり、マニュアルや書籍を見るだけでは、なかなか理解を深めるのが難しい。

インフラ技術を理解するためには、実際に構築して操作することが一番早いと考えており、自宅検証環境にKubernetes環境を構築することにした。

今回は、Linux OS上に容易にKubernetes検証環境を構築できる「minikube」をインストールする手順を記載する。また、minikube起動後に、簡単なコンテナを作成し外部からアクセスするまでの流れを確認してみよう。

環境

以下に今回構築する各種ソフトウェアのバージョンを記載する。

  • ホストOS : AlmaLinux 8.6 (GUI環境を含めインストールする)
  • ホストDocker : 20.10.21
  • minikube : 1.28.0

minikubeを動作させるためのリソース要件は以下の通り。今回は、CPU 4コア、メモリ 4GB、ディスク 20GBで構成した。また、インターネット接続はプロキシ(私の環境の場合はhttp://192.168.33.23:8080)経由での接続が必要となるため、必要なプロキシ設定も手順に記載している。プロキシ設定が不要な場合は、手順を飛ばしてもらえれば問題ない。

  • 2 CPUs or more
  • 2GB of free memory
  • 20GB of free disk space
  • Internet connection

minikubeはホストOSのDockerやVirtualBoxを用いて、Kubernetesのノードを構成することで、Kubernetes環境を即座にスクラップ&ビルドしながら検証をすることができる。

以下にminikubeの環境の構成概要図を記載する。

minikubeインストール手順

1. プロキシ設定 (必要な場合のみ)

私の環境ではプロキシ経由でなければインターネット接続ができないため、以下の通り環境変数を設定する。プロキシの環境変数について小文字と大文字の両方を設定している理由は、dnfコマンドでは小文字の環境変数の設定が必要であり、minikubeの場合は大文字の環境変数の設定が必要となるためである(とてもややこしい)。

# export http_proxy=http://192.168.33.23:8080
# export https_proxy=http://192.168.33.23:8080
# export no_proxy=192.168.0.0/16
# export HTTP_PROXY=http://192.168.33.23:8080
# export HTTPS_PROXY=http://192.168.33.23:8080
# export NO_PROXY=192.168.0.0/16

2. Dockerインストール前の競合パッケージの削除

minikubeはノードをDockerコンテナやVirtualBoxの仮想マシンとして構築する。今回はDockerをドライバーとして利用することとし、まずは、Dockerをインストールする。

ただし、GUI環境をインストールしたAlmaLinuxの場合、以下の通りpodmanとcontainers-commonのパッケージが競合する旨のエラーでインストールに失敗する。

# dnf install docker-ce docker-ce-cli containerd.io -y
メタデータの期限切れの最終確認: 0:05:01 時間前の 2022年11月26日 12時46分04秒 に 実施しました。
エラー:
 問題 1: インストール済パッケージの問題 podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ podman-2:4.0.2-6.module_el8.6.0+2878+e681bc44.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ podman-3:4.2.0-4.module_el8.7.0+3344+484dae7b.x86_64 には runc >= 1.0.0-57 が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

 問題 2: インストール済パッケージの問題 containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64
  - パッケージ containers-common-2:1-27.module_el8.6.0+2878+e681bc44.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません
  - パッケージ containers-common-2:1-43.module_el8.7.0+3344+484dae7b.x86_64 には runc が必要ですが、どのプロバイダーからもインストールできません

~(中略)~

このような場合は、一度podmanとcontainers-commonのパッケージを削除したうえで、Dockerをインストールしよう。

# dnf remove podman containers-common

3. Dockerをインストール

Dockerのインストールは以下の通りコマンドを実行すればよい。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# dnf install docker-ce docker-ce-cli containerd.io -y

プロキシ環境の場合は、外部からコンテナのダウンロードができるよう、systemctlの起動設定に環境変数の設定をしておくこと。

# sed -ie '/\[Service\]/a Environment="http_proxy=http://192.168.33.23:8080" "https_proxy=http://192.168.33.23:8080" "no_proxy=192.168.0.0/16"' /usr/lib/systemd/system/docker.service

インストール完了後、Dockerのサービスを起動しておく。

# systemctl start docker
# systemctl enable docker

4. minikubeインストール

minikubeのインストールは、rpmをダウンロードしインストールするだけで完了する。

# curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm
# rpm -Uvh minikube-latest.x86_64.rpm

5. minikube操作用ユーザの作成

minikubeのDockerドライバーはroot権限で操作できないため、操作用ユーザを作成する。参考情報として、もしroot権限でminikubeを起動すると、以下のようなメッセージが表示され、起動に失敗する。

X DRV_AS_ROOT が原因で終了します: 「docker」ドライバーは root 権限で使用すべきではありません。

今回はkubeuserというユーザを作成した。また、sudoが必要なコマンドがあるためwheelグループへの所属と、Dockerドライバーを操作するためにdockerグループへ所属させておく。

# useradd kubeuser
# usermod -aG wheel,docker kubeuser
# id kubeuser
uid=1000(kubeuser) gid=1000(kubeuser) groups=1000(kubeuser),10(wheel),974(docker)

6. minikubeを起動

以上で準備が整ったため、kubeuserにスイッチし、minikube startコマンドでminikubeを起動する。初回は、800MBほどのコンテナイメージのダウンロードが行われるため、時間を要するので気長に待とう。

# su - kubeuser

$ minikube start
* Almalinux 8.6 上の minikube v1.28.0
* docker ドライバーが自動的に選択されました
* root 権限を持つ Docker ドライバーを使用
* minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
* ベースイメージを取得しています...
* ロード済み Kubernetes v1.25.3 をダウンロードしています...
    > preloaded-images-k8s-v18-v1...:  385.44 MiB / 385.44 MiB  100.00% 77.08 M
    > gcr.io/k8s-minikube/kicbase:  386.27 MiB / 386.27 MiB  100.00% 13.86 MiB
    > gcr.io/k8s-minikube/kicbase:  0 B [________________________] ?% ? p/s 24s
* docker container (CPUs=2, Memory=2200MB) を作成しています...
* ネットワークオプションが見つかりました:
  - HTTP_PROXY=http://192.168.33.23:8080
  - HTTPS_PROXY=http://192.168.33.23:8080
  - NO_PROXY=192.168.0.0/16
* Docker 20.10.20 で Kubernetes v1.25.3 を準備しています...
  - env HTTP_PROXY=http://192.168.33.23:8080
  - env HTTPS_PROXY=http://192.168.33.23:8080
  - env NO_PROXY=192.168.0.0/16
  - 証明書と鍵を作成しています...
  - コントロールプレーンを起動しています...
  - RBAC のルールを設定中です...
* Kubernetes コンポーネントを検証しています...
  - gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
* 有効なアドオン: default-storageclass, storage-provisioner
* kubectl が見つかりません。kubectl が必要な場合、'minikube kubectl -- get pods -A' を試してください
* 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネーム スペースを使用するよう設定されました

7. kubectlコマンドのエイリアスを設定

Kubernetes環境を操作するためのkubectlコマンドはminikubeには用意されておらず、minikube kubectl -- [コマンド]といったコマンドを実行する必要がある。

コマンドの簡略化と本来のKubernetes環境の操作に近づけることを目的として、エイリアスを設定しておく。

$ echo 'alias kubectl="minikube kubectl --"' >> ~/.bashrc
$ source ~/.bashrc

8. 起動状態の確認

minikube起動後のノードとPodの状態を確認しておこう。

ノードは通常1台のみ起動しているはずだ。詳細は省くが、minikubeをマルチノード構成としたい場合は、minikube start --nodes=3といった形でノード数を指定することで、複数ノードで起動させることができる。

$ kubectl get node -o=wide
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION              CONTAINER-RUNTIME
minikube   Ready    control-plane   10m   v1.25.3   192.168.49.2   <none>        Ubuntu 20.04.5 LTS   4.18.0-372.9.1.el8.x86_64   docker://20.10.20

PodとしてはKubernetes環境管理に必要となる各種Podが起動する。ステータスがRunningになっていれば問題ない。

$ kubectl get pod -A
NAMESPACE     NAME                               READY   STATUS    RESTARTS       AGE
kube-system   coredns-565d847f94-t7f4s           1/1     Running   0              2m22s
kube-system   etcd-minikube                      1/1     Running   0              2m35s
kube-system   kube-apiserver-minikube            1/1     Running   0              2m35s
kube-system   kube-controller-manager-minikube   1/1     Running   0              2m35s
kube-system   kube-proxy-2jzrw                   1/1     Running   0              2m22s
kube-system   kube-scheduler-minikube            1/1     Running   0              2m35s
kube-system   storage-provisioner                1/1     Running   1 (112s ago)   2m34s

動作確認

Kubernetesの動作確認としてにテスト用のコンテナを用いてPodを作成し、サービスとして公開してみよう。

再掲となるが、動作確認時におけるminikubeの内部構成は以下の図のようになる。

1. Podとサービスの起動確認

以下コマンドでPodを作成する。

$ kubectl create deployment hello-minikube --image=kicbase/echo-server:1.0
deployment.apps/hello-minikube created

$ kubectl get pod -o=wide
NAME                              READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
hello-minikube-7ddcbc9b8b-5g79b   1/1     Running   0          12s   172.17.0.3   minikube   <none>           <none>

作成したPodはそのままでは外部からアクセスすることができないため、Podと紐づけるサービスを作成する。なお、--type=NodePortを指定することで、ノードの持つIPアドレス(192.168.49.2)にてサービスを公開することができる。

$ kubectl expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed

$ kubectl get service -o=wide
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE    SELECTOR
hello-minikube   NodePort    10.107.255.240   <none>        8080:31931/TCP   7s     app=hello-minikube
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP          102s   <none>

公開したサービスにアクセスしてみよう。ホストOSのブラウザを開いて、直接URLを入力してもよいが、minikubeコマンドを使用することで、サービスのURLを入力した状態でデフォルトのブラウザを起動させることができる。

$ minikube service hello-minikube
|-----------|----------------|-------------|---------------------------|
| NAMESPACE |      NAME      | TARGET PORT |            URL            |
|-----------|----------------|-------------|---------------------------|
| default   | hello-minikube |          80 | http://192.168.49.2:31931 |
|-----------|----------------|-------------|---------------------------| * デフォルトブラウザーで default/hello-minikube サービスを開いています... http://192.168.49.2:31931

2. 外部からサービスにアクセスさせるためのポートフォワード設定

minikubeのサービスに対しては、通常ホストOSでなければアクセスすることができないが、もし外部からアクセスさせたい場合は、以下の通りポートフォワードすることで実現できる。

なお、ポートフォワードはフォアグラウンドで実行されるため、終了する際はCtrl + Cで終了させること。

$ kubectl port-forward service/hello-minikube --address 0.0.0.0 8080:8080
Forwarding from 0.0.0.0:8080 -> 8080
Handling connection for 8080
Handling connection for 8080
^C ←★Ctrl + Cでプロセス終了

この状態の場合は、以下の通り外部からホストOSのIPアドレス(今回は192.168.11.52)でサービスにアクセスすることができる。

ポートフォワードをバックグラウンド実行させる場合は、以下の通り実行する。

$ kubectl port-forward service/hello-minikube --address 0.0.0.0 7080:80 > /dev/null 2>&1 &
[1] 33173

$ fg
minikube kubectl -- port-forward service/hello-minikube --address 0.0.0.0 7080:80 > /dev/null 2>&1
^C ←★Ctrl + Cでプロセス終了

以上で、Linux OS上に「minikube」をインストールする手順は完了となる。

minikube環境をリセットする

最後にminikube環境をリセットする方法を紹介しておこう。環境の削除は、minikube deleteコマンドを実行するだけで完了する。

$ minikube delete
  docker の「minikube」を削除しています...
  コンテナー「minikube」を削除しています...
  /home/kubeuser/.minikube/machines/minikube を削除しています...
  クラスター「minikube」の全てのトレースを削除しました。

削除後に再度minikube startすることで、再度きれいな状態でminikubeのKubernetes環境を利用することができる。

参考

人気の投稿