2023年8月26日土曜日

QNAP NASにオレオレ認証書をインポートする

QNAP NASの管理画面へのアクセスはHTTPS通信となる。初期設定においては、NAS自体が作成したSSLサーバ証明書が導入されている。

外部公開する際は、myQNAPcloudにてLet’s EncryptなどのSSLサーバ証明書の設定を行うことができるが、内部ネットワークで使う場合は、オレオレ認証局が発行したSSLサーバ証明書(オレオレ証明書)を使いたい場合がある。

本記事では、QNAP NASにオレオレ認証局にて作成した証明書をインポートする手順を記載する。

環境

今回作業を実施した環境は以下の通り

  • QNAP NAS
    • 型番 : TS-231P
    • QTS : 5.1.0
  • オレオレ認証局用Linuxサーバ
    • OS : CentOS Stream release 8

オレオレ認証局の構築

Linux環境にて秘密鍵とCSR (証明書署名要求)を作成し、CSRをもとにオレオレ認証局にて署名を行い、SSLサーバ証明書を作成する。このあたりの流れは、以下記事に詳しく記載したので参照いただきたい。

オレオレ認証書を作成

オレオレ認証局が構築されている前提にてSSLサーバ証明書の作成を行う。

今回作成する証明書関連のファイルを以下に記載する。

ファイル名 種別
t1013qnap.key 秘密鍵
t1013qnap.csr CSR (証明書署名要求)
san.txt SAN (サブジェクト代替名)
t1013qnap.crt SSLサーバ証明書

1. サーバの秘密鍵及びCSR作成

QNAP NASでは秘密鍵やCSR作成をすることができないようなので、Linux上で秘密鍵とCSRを作成する。

まずは秘密鍵を作成する。

# cd ~
# openssl genrsa 2048 > t1013qnap.key

~(中略)~

Country Name (2 letter code) [JP]: ★そのままEnter
State or Province Name (full name) [Tokyo]: ★そのままEnter
Locality Name (eg, city) [Default City]: ★そのままEnter
Organization Name (eg, company) [Default Company Ltd]: ★そのままEnter
Organizational Unit Name (eg, section) []: ★そのままEnter
Common Name (eg, your name or your server's hostname) []:t1013qnap ★ホスト名などを入力
Email Address []: ★そのままEnter

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ★そのままEnter
An optional company name []: ★そのままEnter

次にCSRを作成する。

# openssl req -new -key t1013qnap.key > t1013qnap.csr

2. SAN(サブジェクト代替名)の設定ファイル作成

SSLサーバ証明書に付与するサブジェクト代替名の情報をsan.txtに記載する。今回はDNS名1つとIPアドレスを1つ記載した。

# cat << EOF > san.txt
subjectAltName = DNS:*.example.com, IP:192.168.11.13
EOF

3. SSL証明書を作成

CAスクリプトを使用しCSRに対して署名を行うことで、SSLサーバ証明書を作成できる。

先ほど作成したCSRとsan.txtを以下の通り/etc/pki/tls/misc/ディレクトリ(CAスクリプトを配置するディレクトリ)にコピーする。CAスクリプトを使う場合、CSRのファイル名はnewreq.pemにする必要があるので注意すること。

# cd ~
# cp qnap.csr /etc/pki/tls/misc/newreq.pem
# cp san.txt /etc/pki/tls/misc/

CAスクリプトにて署名すると、newcert.pemというファイル名でSSLサーバ証明書が作成される。

# cd /etc/pki/tls/misc/
# ./CA -sign
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem:

~(中略)~

        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            localityName              = Default City
            organizationName          = Default Company Ltd
            commonName                = t1013qnap
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:*.example.com, IP Address:192.168.11.13
Certificate is to be certified until Jul 19 05:53:58 2033 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0b:41:b7:3e:ac:a2:ca:1c:2b:ec:1b:39:b2:31:8b:4a:e3:35:25:15
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, ST=Tokyo, O=Default Company Ltd, CN=My Private CA

~(中略)~

eQnnVBcS0wDHX0ATguHY7krprVFGHfQVDht0ZhRgmYESXgBNP9KoudbF6hOaTrnw
2B76Kr1Sv5hS/jjFZQFutis/jI0=
-----END CERTIFICATE-----

# ls -l newcert.pem
-rw-r--r-- 1 root root 4186  7月 22 14:54 newcert.pem

CAスクリプトで作成した証明書をコピーして保存する。

# cp newcert.pem ~/qnap.csr

【参考】CAスクリプトを使わない場合のSSLサーバ証明書の作り方

CAスクリプトを使わない場合のSSLサーバ証明書作成コマンドは以下となる。

# openssl x509 -days 3650 -req -signkey t1013qnap.key -in t1013qnap.csr -out t1013qnap.crt -extfile san.txt

QNAP NASにインポート

1. QNAP NASの管理画面にログイン

QNAP NASの管理画面にログインし、[コントロールパネル] > [セキュリティ] > [SSLサーバ証明書とプライベートキー]を開き、[証明書の交換]ボタンを選択する。

2. SSLサーバ証明書をインポート

[証明書の交換]ダイアログボックスが開くので、[証明書のインポート]を選択し、[次へ]を選択する。

証明書のインポート画面にて以下を選択し、[適用]ボタンを選択する。

項目 設定値
証明書 SSLサーバ証明書 (t1013qnap.crt)
プライベートキー 秘密鍵 (t1013qnap.key)
中間証明書(任意) 設定不要

3. インポート後に再度QNAP NASにアクセス

証明書インポート後の管理画面の表示は自動更新されないため、一度別の画面に遷移してから[SSLサーバ証明書とプライベートキー]の画面を再表示しよう。

発行者、代替名、有効期限が更新されていれば、正常に証明書のインポートが完了となる。

一度ブラウザを落とし、再度QNAP NASにアクセスすると、以下の通りブラウザの証明書エラーが消えることが確認できた。

以上で、QNAP NASにオレオレ認証局にて作成した証明書をインポートする手順は完了となる。

2023年8月19日土曜日

TerraformでオンプレESXiに仮想マシンを作成・削除してみる

先日、TerraformをAlmaLinuxにインストールして使ってみた。

Terraformは主にAWSやAzureといったクラウドの設定をする際に利用されるツールという印象が強いが、オンプレミスのvSphere環境などでも各種設定を行うことができる

本記事では、TerraformでオンプレESXiに仮想マシンを作成・削除する手順を作る方法を記載する。

環境

環境は以下の通り。

  • ESXi : 7.0 Update 3
  • OS : AlmaLinux 9.2
  • Terraform : v1.5.2

以下URLの手順にてTerraformがインストール済みであることを前提とする。

Terraformによる仮想マシン作成手順

通常のTerraformと同じく、tfファイルを作ってterraform initterraform applyで仮想マシンを作成し、terraform destoryで仮想マシンが削除されることを確認する。

1. tfファイルを作成

TerraformでESXiを操作する場合は、「Terraform Provider for VMware vSphere」を用いる。

マニュアルに使用例は書いてあるが、vCenter Serverが存在する環境の実行例がとなるので、ESXiに対して実行する際の注意点を以下に記載する。

  • vsphere_datacenterha-datacenterを指定
  • vsphere_compute_clusterは不要。ただし、vsphere_virtual_machineのリソース指定において、resource_pool_idは必須項目なので、vsphere_resource_poolを空で作って作成しておく
  • guest_idは以下URLから[Enumerated Types]→[VirtualMachineGuestOsIdentifier]にアクセスし作成するOSの種類に合わせて正しく指定する。
  • 仮想マシン作成後にTerraformが応答待ちになってしまうことから、wait_for_guest_net_timeout = -1を設定する

上記をもとに作成したtfファイルは以下の通り。

main.tf

terraform {
  required_version = ">= 1.2.0"
}

locals {
  esxi_user              = "[ESXiのユーザ名]"
  esxi_password          = "[ESXiのユーザのパスワード]"
  esxi_server            = "[ESXiのIPアドレス]"
}

provider "vsphere" {
  user                 = local.esxi_user
  password             = local.esxi_password
  vsphere_server       = local.esxi_server
  allow_unverified_ssl = true
}

data "vsphere_datacenter" "datacenter" {
  name = "ha-datacenter"
}

data "vsphere_datastore" "datastore" {
  name          = "ssd_01"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_datastore" "media" {
  name          = "nfs_01"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_resource_pool" "pool" {
}

data "vsphere_network" "network" {
  name          = "Network_01"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

resource "vsphere_virtual_machine" "vm" {
  name             = "terraform-testvm"
  resource_pool_id = data.vsphere_resource_pool.pool.id
  datastore_id     = data.vsphere_datastore.datastore.id
  num_cpus         = 1
  memory           = 1024
  guest_id         = "other5xLinux64Guest"

  network_interface {
    network_id = data.vsphere_network.network.id
  }

  disk {
    label = "disk0"
    size  = 16
    thin_provisioned = true
  }

  cdrom {
    datastore_id = data.vsphere_datastore.media.id
    path = "/04_ISO/Linux/AlmaLinux/AlmaLinux-9.2-x86_64-dvd.iso"
  }

  wait_for_guest_net_timeout = -1
}

2. Terraform実行

上記tfファイルをesxi_vm_linuxディレクトリに作成し、Terraformを実行する。

# cd esxi_vm_linux
# terraform init
~(省略)~

# terraform apply 
data.vsphere_datacenter.datacenter: Reading...
data.vsphere_resource_pool.pool: Reading...
data.vsphere_datacenter.datacenter: Read complete after 0s [id=ha-datacenter]
data.vsphere_datastore.media: Reading...
data.vsphere_datastore.datastore: Reading...
data.vsphere_network.network: Reading...
data.vsphere_datastore.media: Read complete after 0s [id=192.168.1.1:/nfs]
data.vsphere_resource_pool.pool: Read complete after 0s [id=ha-root-pool]
data.vsphere_datastore.datastore: Read complete after 0s [id=63942c98-19e3f477-d004-90e2ba3d67d0]
data.vsphere_network.network: Read complete after 0s [id=HaNetwork-Network_01]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # vsphere_virtual_machine.vm will be created
  + resource "vsphere_virtual_machine" "vm" {
      + annotation                              = (known after apply)
      + boot_retry_delay                        = 10000
      + change_version                          = (known after apply)
      + cpu_limit                               = -1
      + cpu_share_count                         = (known after apply)
      + cpu_share_level                         = "normal"
      + datastore_id                            = "63942c98-19e3f477-d004-90e2ba3d67d0"
      + default_ip_address                      = (known after apply)
      + ept_rvi_mode                            = "automatic"
      + extra_config_reboot_required            = true
      + firmware                                = "bios"
      + force_power_off                         = true
      + guest_id                                = "other5xLinux64Guest"
      + guest_ip_addresses                      = (known after apply)
      + hardware_version                        = (known after apply)
      + host_system_id                          = (known after apply)
      + hv_mode                                 = "hvAuto"
      + id                                      = (known after apply)
      + ide_controller_count                    = 2
      + imported                                = (known after apply)
      + latency_sensitivity                     = "normal"
      + memory                                  = 1024
      + memory_limit                            = -1
      + memory_share_count                      = (known after apply)
      + memory_share_level                      = "normal"
      + migrate_wait_timeout                    = 30
      + moid                                    = (known after apply)
      + name                                    = "terraform-testvm"
      + num_cores_per_socket                    = 1
      + num_cpus                                = 1
      + power_state                             = (known after apply)
      + poweron_timeout                         = 300
      + reboot_required                         = (known after apply)
      + resource_pool_id                        = "ha-root-pool"
      + run_tools_scripts_after_power_on        = true
      + run_tools_scripts_after_resume          = true
      + run_tools_scripts_before_guest_shutdown = true
      + run_tools_scripts_before_guest_standby  = true
      + sata_controller_count                   = 0
      + scsi_bus_sharing                        = "noSharing"
      + scsi_controller_count                   = 1
      + scsi_type                               = "pvscsi"
      + shutdown_wait_timeout                   = 3
      + storage_policy_id                       = (known after apply)
      + swap_placement_policy                   = "inherit"
      + tools_upgrade_policy                    = "manual"
      + uuid                                    = (known after apply)
      + vapp_transport                          = (known after apply)
      + vmware_tools_status                     = (known after apply)
      + vmx_path                                = (known after apply)
      + wait_for_guest_ip_timeout               = 0
      + wait_for_guest_net_routable             = true
      + wait_for_guest_net_timeout              = -1

      + cdrom {
          + datastore_id   = "192.168.1.1:/nfs"
          + device_address = (known after apply)
          + key            = (known after apply)
          + path           = "/04_ISO/Linux/AlmaLinux/AlmaLinux-9.2-x86_64-dvd.iso"
        }

      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = "<computed>"
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "disk0"
          + path              = (known after apply)
          + size              = 16
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 0
          + uuid              = (known after apply)
          + write_through     = false
        }

      + network_interface {
          + adapter_type          = "vmxnet3"
          + bandwidth_limit       = -1
          + bandwidth_reservation = 0
          + bandwidth_share_count = (known after apply)
          + bandwidth_share_level = "normal"
          + device_address        = (known after apply)
          + key                   = (known after apply)
          + mac_address           = (known after apply)
          + network_id            = "HaNetwork-Network_01"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

vsphere_virtual_machine.vm: Creating...
vsphere_virtual_machine.vm: Creation complete after 1s [id=564de646-7f10-7d49-33d3-7c55f22ef581]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

作成した結果をVMware Host Clientにて確認してみると、問題なくterraform-testvmの仮想マシンが作成され、起動まで実行されていることがわかる。

「設定の編集」を確認すると、USBコントローラなどがない、必要最低限の構成で仮想マシンが作成されていた。

Terraformによる仮想マシン削除手順

最後に作成した仮想マシンを削除してみよう。仮想マシンの削除はterraform destroyをすればよい。

# terraform destroy 
data.vsphere_resource_pool.pool: Reading...
data.vsphere_datacenter.datacenter: Reading...
data.vsphere_datacenter.datacenter: Read complete after 0s [id=ha-datacenter]
data.vsphere_network.network: Reading...
data.vsphere_datastore.media: Reading...
data.vsphere_datastore.datastore: Reading...
data.vsphere_datastore.datastore: Read complete after 0s [id=63942c98-19e3f477-d004-90e2ba3d67d0]
data.vsphere_datastore.media: Read complete after 0s [id=192.168.1.1:/nfs]
data.vsphere_resource_pool.pool: Read complete after 0s [id=ha-root-pool]
data.vsphere_network.network: Read complete after 0s [id=HaNetwork-Network_01]
vsphere_virtual_machine.vm: Refreshing state... [id=564de646-7f10-7d49-33d3-7c55f22ef581]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # vsphere_virtual_machine.vm will be destroyed
  - resource "vsphere_virtual_machine" "vm" {
      - boot_delay                              = 0 -> null
      - boot_retry_delay                        = 10000 -> null
      - boot_retry_enabled                      = false -> null
      - change_version                          = "2023-08-11T09:27:30.121451Z" -> null
      - cpu_hot_add_enabled                     = false -> null
      - cpu_hot_remove_enabled                  = false -> null
      - cpu_limit                               = -1 -> null
      - cpu_performance_counters_enabled        = false -> null
      - cpu_reservation                         = 0 -> null
      - cpu_share_count                         = 1000 -> null
      - cpu_share_level                         = "normal" -> null
      - datastore_id                            = "63942c98-19e3f477-d004-90e2ba3d67d0" -> null
      - efi_secure_boot_enabled                 = false -> null
      - enable_disk_uuid                        = false -> null
      - enable_logging                          = false -> null
      - ept_rvi_mode                            = "automatic" -> null
      - extra_config                            = {} -> null
      - extra_config_reboot_required            = true -> null
      - firmware                                = "bios" -> null
      - force_power_off                         = true -> null
      - guest_id                                = "other5xLinux64Guest" -> null
      - guest_ip_addresses                      = [] -> null
      - hardware_version                        = 19 -> null
      - host_system_id                          = "ha-host" -> null
      - hv_mode                                 = "hvAuto" -> null
      - id                                      = "564de646-7f10-7d49-33d3-7c55f22ef581" -> null
      - ide_controller_count                    = 2 -> null
      - latency_sensitivity                     = "normal" -> null
      - memory                                  = 1024 -> null
      - memory_hot_add_enabled                  = false -> null
      - memory_limit                            = -1 -> null
      - memory_reservation                      = 0 -> null
      - memory_share_count                      = 10240 -> null
      - memory_share_level                      = "normal" -> null
      - migrate_wait_timeout                    = 30 -> null
      - moid                                    = "59" -> null
      - name                                    = "terraform-testvm" -> null
      - nested_hv_enabled                       = false -> null
      - num_cores_per_socket                    = 1 -> null
      - num_cpus                                = 1 -> null
      - pci_device_id                           = [] -> null
      - power_state                             = "on" -> null
      - poweron_timeout                         = 300 -> null
      - reboot_required                         = false -> null
      - resource_pool_id                        = "ha-root-pool" -> null
      - run_tools_scripts_after_power_on        = true -> null
      - run_tools_scripts_after_resume          = true -> null
      - run_tools_scripts_before_guest_reboot   = false -> null
      - run_tools_scripts_before_guest_shutdown = true -> null
      - run_tools_scripts_before_guest_standby  = true -> null
      - sata_controller_count                   = 0 -> null
      - scsi_bus_sharing                        = "noSharing" -> null
      - scsi_controller_count                   = 1 -> null
      - scsi_type                               = "pvscsi" -> null
      - shutdown_wait_timeout                   = 3 -> null
      - swap_placement_policy                   = "inherit" -> null
      - sync_time_with_host                     = false -> null
      - sync_time_with_host_periodically        = false -> null
      - tools_upgrade_policy                    = "manual" -> null
      - uuid                                    = "564de646-7f10-7d49-33d3-7c55f22ef581" -> null
      - vapp_transport                          = [] -> null
      - vbs_enabled                             = false -> null
      - vmware_tools_status                     = "guestToolsNotRunning" -> null
      - vmx_path                                = "terraform-testvm/terraform-testvm.vmx" -> null
      - vvtd_enabled                            = false -> null
      - wait_for_guest_ip_timeout               = 0 -> null
      - wait_for_guest_net_routable             = true -> null
      - wait_for_guest_net_timeout              = -1 -> null

      - cdrom {
          - client_device  = false -> null
          - datastore_id   = "192.168.1.1:/nfs" -> null
          - device_address = "ide:0:0" -> null
          - key            = 3000 -> null
          - path           = "04_ISO/Linux/AlmaLinux/AlmaLinux-9.2-x86_64-dvd.iso" -> null
        }

      - disk {
          - attach           = false -> null
          - controller_type  = "scsi" -> null
          - datastore_id     = "63942c98-19e3f477-d004-90e2ba3d67d0" -> null
          - device_address   = "scsi:0:0" -> null
          - disk_mode        = "persistent" -> null
          - disk_sharing     = "sharingNone" -> null
          - eagerly_scrub    = false -> null
          - io_limit         = -1 -> null
          - io_reservation   = 0 -> null
          - io_share_count   = 1000 -> null
          - io_share_level   = "normal" -> null
          - keep_on_remove   = false -> null
          - key              = 2000 -> null
          - label            = "disk0" -> null
          - path             = "terraform-testvm/terraform-testvm.vmdk" -> null
          - size             = 16 -> null
          - thin_provisioned = true -> null
          - unit_number      = 0 -> null
          - uuid             = "6000C29e-8a40-b94b-d566-a61c53225832" -> null
          - write_through    = false -> null
        }

      - network_interface {
          - adapter_type          = "vmxnet3" -> null
          - bandwidth_limit       = -1 -> null
          - bandwidth_reservation = 0 -> null
          - bandwidth_share_count = 50 -> null
          - bandwidth_share_level = "normal" -> null
          - device_address        = "pci:0:7" -> null
          - key                   = 4000 -> null
          - mac_address           = "00:0c:29:2e:f5:81" -> null
          - network_id            = "HaNetwork-Network_01" -> null
          - use_static_mac        = false -> null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

vsphere_virtual_machine.vm: Destroying... [id=564de646-7f10-7d49-33d3-7c55f22ef581]
vsphere_virtual_machine.vm: Destruction complete after 1s

Destroy complete! Resources: 1 destroyed.

ESXiの「最近のタスク」においても、仮想マシンの電源をOFFしてから削除処理が実行されていることがわかる。

以上で、TerraformでオンプレESXiに仮想マシンを作成・削除する手順は完了となる。

2023年8月12日土曜日

TerraformをAlmaLinuxにインストールして簡単な動作確認をしてみた

Terraformは、HashiCorp社にて開発された各種プラットフォームのITインフラの設定をIaC (Infrastructure as code)にて設定可能とするOSSツールとなる。

今回は、TerraformをAlmaLinuxにインストールし、簡単な動作確認を行う手順を記載する。

環境

環境は以下の通り。

  • OS : AlmaLinux 9.2
  • Terraform : v1.5.2

Terraformインストール手順

1. HashiCorpのレポジトリ追加

TerraformはHashicorpのリポジトリで公開されている。yum-config-managerコマンドを使って、以下の通りリポジトリの追加を行う。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo

2. Terraformインストール

dnfを用いてTerraformをインストールする。gitperlの各種ライブラリが依存関係パッケージとして、大量にインストールされる。

# dnf install terraform
メタデータの期限切れの最終確認: 0:00:16 前の 2023年07月07日 21時12分38秒 に実施しました。
依存関係が解決しました。
====================================================================================================================================================
 パッケージ                                 アーキテクチャー           バージョン                               リポジトリー                  サイズ
====================================================================================================================================================
インストール:
 terraform                                  x86_64                     1.5.2-1                                  hashicorp                      21 M
依存関係のインストール:
 emacs-filesystem                           noarch                     1:27.2-8.el9_2.1                         appstream                     7.9 k
 git                                        x86_64                     2.39.3-1.el9_2                           appstream                      61 k
 git-core                                   x86_64                     2.39.3-1.el9_2                           appstream                     4.2 M
 git-core-doc                               noarch                     2.39.3-1.el9_2                           appstream                     2.6 M
 perl-AutoLoader                            noarch                     5.74-480.el9                             appstream                      21 k
 perl-B                                     x86_64                     1.80-480.el9                             appstream                     179 k
 perl-Carp                                  noarch                     1.50-460.el9                             appstream                      29 k
 perl-Class-Struct                          noarch                     0.66-480.el9                             appstream                      22 k

~(中略)~

 perl-subs                                  noarch                     1.03-480.el9                             appstream                      12 k
 perl-vars                                  noarch                     1.05-480.el9                             appstream                      13 k
弱い依存関係のインストール:
 perl-IO-Socket-SSL                         noarch                     2.073-1.el9                              appstream                     216 k
 perl-Mozilla-CA                            noarch                     20200520-6.el9                           appstream                      12 k
 perl-NDBM_File                             x86_64                     1.15-480.el9                             appstream                      22 k

トランザクションの概要
====================================================================================================================================================
インストール  68 パッケージ

ダウンロードサイズの合計: 34 M
インストール後のサイズ: 123 M
これでよろしいですか? [y/N]: y

~(以下略)~

インストール後、Terraformのバージョンを確認しておこう。

# terraform -v
Terraform v1.5.2
on linux_amd64
+ provider registry.terraform.io/kreuzwerker/docker v3.0.2

3. terraformコマンドのTab補完を使えるようにする

Terraformを使用する際は、その名の通りterraformコマンドを使用する。その際にTab補完を使えるよう、以下の通りコマンドを実行する。

# touch ~/.bashrc
# terraform -install-autocomplete
# source ~/.bashrc

実行後の~/.bashrcは以下の通り。最終行にTab補完用のコマンドが実行されるようになっている。

~/.bashrc

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

complete -C /usr/bin/terraform terraform   # <- ★追加される

これによって、例えばterraform a[TAB]とキーを入力すれば、terraform applyのコマンドが補完されるようになる。

# terraform apply   <- ★Tabで補完されるようになる

Terraform動作確認 (Docekrコンテナ作成)

ここからは、公式サイトで公開されている以下のチュートリアル通りに確認作業を進める。

前提として、事前にTerraformを導入したOSにDockerをインストールすること。Dockerのインストール手順は以下を参照いただきたい。

1. 作業用ディレクトリ作成

Terraformでは、作業用ディレクトリを作成し、そこに*.tfという拡張子を持つファイルにてTerraformのコードを記載する。Terraformコマンドはtfファイルのコードを解釈し、必要な一時ファイル等をディレクトリ内に作成し、各プラットフォームに対して操作を行う。

今回は以下の通りディレクトリを作成する。

# mkdir learn-terraform-docker-container
# cd learn-terraform-docker-container

2. tfファイルを作成

作成したディレクトリ内にmain.tfというファイルを作成し、以下の通り記述する。

main.tf

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.image_id
  name  = "tutorial"

  ports {
    internal = 80
    external = 8000
  }
}

3. Terraform初期化 (terraform init)

Terraformを初期化するため、terraform initコマンドを実行する。このコマンドを実行すると、プロバイダと呼ばれるプラットフォームとのインタフェースとなるファイルが.terraformディレクトリにダウンロードされる。使用するプロバイダによってはかなり容量が大きいため注意しよう(例えばAWSのプロバイダであれば400MB程度)。

# terraform init

Initializing the backend...

Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "~> 3.0.1"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

なお、Terraformで使用可能なプロバイダは、以下URLから確認できる。

4. Terraform実行前確認 (terraform plan)

実行前に実行内容を確認するため、terraform planコマンドを実行する。

# terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # docker_container.nginx will be created
  + resource "docker_container" "nginx" {
      + attach                                      = false
      + bridge                                      = (known after apply)
      + command                                     = (known after apply)
      + container_logs                              = (known after apply)
      + container_read_refresh_timeout_milliseconds = 15000
      + entrypoint                                  = (known after apply)
      + env                                         = (known after apply)
      + exit_code                                   = (known after apply)
      + hostname                                    = (known after apply)
      + id                                          = (known after apply)
      + image                                       = (known after apply)
      + init                                        = (known after apply)
      + ipc_mode                                    = (known after apply)
      + log_driver                                  = (known after apply)
      + logs                                        = false
      + must_run                                    = true
      + name                                        = "tutorial"
      + network_data                                = (known after apply)
      + read_only                                   = false
      + remove_volumes                              = true
      + restart                                     = "no"
      + rm                                          = false
      + runtime                                     = (known after apply)
      + security_opts                               = (known after apply)
      + shm_size                                    = (known after apply)
      + start                                       = true
      + stdin_open                                  = false
      + stop_signal                                 = (known after apply)
      + stop_timeout                                = (known after apply)
      + tty                                         = false
      + wait                                        = false
      + wait_timeout                                = 60

      + ports {
          + external = 8000
          + internal = 80
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # docker_image.nginx will be created
  + resource "docker_image" "nginx" {
      + id           = (known after apply)
      + image_id     = (known after apply)
      + keep_locally = false
      + name         = "nginx"
      + repo_digest  = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

5. Terraform実行 (terraform apply)

Terraformの処理をするため、terraform applyコマンドを実行する。

# terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # docker_container.nginx will be created
  + resource "docker_container" "nginx" {
      + attach                                      = false
      + bridge                                      = (known after apply)
      + command                                     = (known after apply)
      + container_logs                              = (known after apply)
      + container_read_refresh_timeout_milliseconds = 15000
      + entrypoint                                  = (known after apply)
      + env                                         = (known after apply)
      + exit_code                                   = (known after apply)
      + hostname                                    = (known after apply)
      + id                                          = (known after apply)
      + image                                       = (known after apply)
      + init                                        = (known after apply)
      + ipc_mode                                    = (known after apply)
      + log_driver                                  = (known after apply)
      + logs                                        = false
      + must_run                                    = true
      + name                                        = "tutorial"
      + network_data                                = (known after apply)
      + read_only                                   = false
      + remove_volumes                              = true
      + restart                                     = "no"
      + rm                                          = false
      + runtime                                     = (known after apply)
      + security_opts                               = (known after apply)
      + shm_size                                    = (known after apply)
      + start                                       = true
      + stdin_open                                  = false
      + stop_signal                                 = (known after apply)
      + stop_timeout                                = (known after apply)
      + tty                                         = false
      + wait                                        = false
      + wait_timeout                                = 60

      + ports {
          + external = 8000
          + internal = 80
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # docker_image.nginx will be created
  + resource "docker_image" "nginx" {
      + id           = (known after apply)
      + image_id     = (known after apply)
      + keep_locally = false
      + name         = "nginx"
      + repo_digest  = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes   <- ★yesを入力

docker_image.nginx: Creating...
docker_image.nginx: Creation complete after 9s [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 1s [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

6. 実行後確認

実行後にDockerコンテナとコンテナイメージの状況を確認すると、NGINXのコンテナイメージがダウンロードされ、コンテナとして起動していることがわかる。

# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS                  NAMES
c70291e91ade   021283c8eb95   "/docker-entrypoint.…"   27 seconds ago   Up 26 seconds   0.0.0.0:8000->80/tcp   tutorial

# docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    021283c8eb95   4 days ago   187MB

NGINXコンテナは8000番ポートで接続できる。実際に接続すると、NGINXのウェルカムページが表示された。

7. Dockerコンテナ削除 (terraform destroy)

Terraformで作成したDockerコンテナを削除するため、terraform destroyコマンドを実行する。

# terraform destroy
docker_image.nginx: Refreshing state... [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_container.nginx: Refreshing state... [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # docker_container.nginx will be destroyed
  - resource "docker_container" "nginx" {
      - attach                                      = false -> null
      - command                                     = [
          - "nginx",
          - "-g",
          - "daemon off;",
        ] -> null
      - container_read_refresh_timeout_milliseconds = 15000 -> null
      - cpu_shares                                  = 0 -> null
      - dns                                         = [] -> null
      - dns_opts                                    = [] -> null
      - dns_search                                  = [] -> null
      - entrypoint                                  = [
          - "/docker-entrypoint.sh",
        ] -> null
      - env                                         = [] -> null
      - group_add                                   = [] -> null
      - hostname                                    = "c70291e91ade" -> null
      - id                                          = "c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2" -> null
      - image                                       = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbda" -> null
      - init                                        = false -> null
      - ipc_mode                                    = "private" -> null
      - log_driver                                  = "json-file" -> null
      - log_opts                                    = {} -> null
      - logs                                        = false -> null
      - max_retry_count                             = 0 -> null
      - memory                                      = 0 -> null
      - memory_swap                                 = 0 -> null
      - must_run                                    = true -> null
      - name                                        = "tutorial" -> null
      - network_data                                = [
          - {
              - gateway                   = "172.17.0.1"
              - global_ipv6_address       = ""
              - global_ipv6_prefix_length = 0
              - ip_address                = "172.17.0.2"
              - ip_prefix_length          = 16
              - ipv6_gateway              = ""
              - mac_address               = "02:42:ac:11:00:02"
              - network_name              = "bridge"
            },
        ] -> null
      - network_mode                                = "default" -> null
      - privileged                                  = false -> null
      - publish_all_ports                           = false -> null
      - read_only                                   = false -> null
      - remove_volumes                              = true -> null
      - restart                                     = "no" -> null
      - rm                                          = false -> null
      - runtime                                     = "runc" -> null
      - security_opts                               = [] -> null
      - shm_size                                    = 64 -> null
      - start                                       = true -> null
      - stdin_open                                  = false -> null
      - stop_signal                                 = "SIGQUIT" -> null
      - stop_timeout                                = 0 -> null
      - storage_opts                                = {} -> null
      - sysctls                                     = {} -> null
      - tmpfs                                       = {} -> null
      - tty                                         = false -> null
      - wait                                        = false -> null
      - wait_timeout                                = 60 -> null

      - ports {
          - external = 8000 -> null
          - internal = 80 -> null
          - ip       = "0.0.0.0" -> null
          - protocol = "tcp" -> null
        }
    }

  # docker_image.nginx will be destroyed
  - resource "docker_image" "nginx" {
      - id           = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx" -> null
      - image_id     = "sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbda" -> null
      - keep_locally = false -> null
      - name         = "nginx" -> null
      - repo_digest  = "nginx@sha256:08bc36ad52474e528cc1ea3426b5e3f4bad8a130318e3140d6cfe29c8892c7ef" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes   <- ★yesを入力

docker_container.nginx: Destroying... [id=c70291e91ade2fef0b1051a92a7a7e657d9b32c8bf63cafb7e5a3a4b7449bca2]
docker_container.nginx: Destruction complete after 0s
docker_image.nginx: Destroying... [id=sha256:021283c8eb95be02b23db0de7f609d603553c6714785e7a673c6594a624ffbdanginx]
docker_image.nginx: Destruction complete after 0s

Destroy complete! Resources: 2 destroyed.

削除後にDockerコンテナとコンテナイメージを確認すると、いずれも削除されていることが確認できる。

# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

以上で、TerraformをAlmaLinuxにインストールし、簡単な動作確認を行う手順は完了となる。

参考

2023年8月5日土曜日

Ansible Lintの「よくあるエラー」を解消する

先日、Ansibleを6.0.0から8.1.0にバージョンアップした。

その際にAnsible Lintもバージョンアップされ、今まではエラーとならなかったPlaybookにおいて新たにエラーが出力されるようになった。

本記事では、今回私が遭遇したAnsible Lintの「よくあるエラー」を解消するための方法を記載する。

環境

  • Ansible : 2.15.1
  • Ansible Lint : 6.17.2

Ansible Lintのよくあるエラー

yaml[octal-values]: Forbidden implicit octal value “0644”

https://ansible.readthedocs.io/projects/lint/rules/yaml/

modeのパーミッションをダブルクォートで囲む。

誤った記載

mode: 0644

正しい記載

mode: "0644"

no-changed-when: Commands should not change things if nothing needs doing.

https://ansible.readthedocs.io/projects/lint/rules/no-changed-when/

commandshellモジュールを使う際は、changed_whenにて変更有無の条件を定義する。例えば、以下の例ではコマンド実行結果が0の場合はchangedのステータスに設定する。

正しい記載

    - name: Install go command
      ansible.builtin.command:
        cmd: "{{ item }}"
        chdir: "{{ cri_dockerd.dir_git }}"
      become: true
      environment: "{{ proxy_env }}"
      register: result_cmd              # <- add
      changed_when: result_cmd.rc == 0  # <- add
      loop:
        - "wget https://storage.googleapis.com/golang/getgo/installer_linux"
        - "chmod +x ./installer_linux"
        - "./installer_linux"
      when: result.rc != 0

no-free-form: Avoid using free-form when calling module actions. (ansible.builtin.service)

https://ansible.readthedocs.io/projects/lint/rules/no-free-form/

1行で書くのではなく、きちんとYAMLで書く。

誤った記載

    - name: Enable service
      ansible.builtin.service: name={{ item }} enabled=yes state=started
      loop: "{{ service_enable_list }}"
      become: true

正しい記載

    - name: Enable service
      ansible.builtin.service:
        name: "{{ item }}"
        enabled: true
        state: started
      loop: "{{ service_enable_list }}"
      become: true

run-once[task]: Using run_once may behave differently if strategy is set to free.

https://ansible.readthedocs.io/projects/lint/rules/run-once/

Ansibleの実行戦略(strategy)がfreeの場合、run_onceの指定はお勧めできない(想定通りに動作しない可能性がある)、というもの。freeの場合は、各タスクにおいてすべてのホストの実行の終了を待たずに、次のタスクが実行されるため。

なお、デフォルトはlinearとなり、各タスクのすべてのホストの実行が終了してから、次のタスクに遷移する。

解決策はrun_onceを使わなければよいが、使いたい場合もあるので、その場合は以下の通りタスクのname# noqa: run-once[task]のコメントを付与すると、Ansible Lintがエラーを表示しなくなる。

    - name: Remove local repository # noqa: run-once[task]
      ansible.builtin.file:
        path: "{{ dir_output_config_dest }}"
        state: absent
      delegate_to: localhost
      run_once: true

jinja[invalid]: You need to install “jmespath” prior to running json_query filter

https://ansible.readthedocs.io/projects/lint/rules/jinja/

jmespathがインストールされていないと出力されるエラー。pipにてjmespathをインストールする。

# python3 -m pip install jmespath
WARNING: Running pip install with root privileges is generally not a good idea. Try `python3 -m pip install --user` instead.
Collecting jmespath
  Using cached jmespath-1.0.1-py3-none-any.whl (20 kB)
Installing collected packages: jmespath
Successfully installed jmespath-1.0.1

fqcn[canonical]: You should use canonical module name ansible.windows.win_file instead of ansible.builtin.win_file.

モジュール名が誤っている。ansible.builtin.win_fileではなくansible.windows.win_fileのように正しいモジュール名を記載する。

誤った記載

    - name: Remove windows sciprt & config file
      ansible.builtin.win_file:
        path: "{{ dir_output_config_src }}"
        state: absent

正しい記載

    - name: Remove windows sciprt & config file
      ansible.windows.win_file:
        path: "{{ dir_output_config_src }}"
        state: absent

name[casing]: All names should start with an uppercase letter.

nameの最初の文字は大文字にする。

誤った記載

- name: create test vm from snapshot
  gather_facts: true
  hosts: vmware_servers

正しい記載

- name: Create test vm from snapshot
  gather_facts: true
  hosts: vmware_servers

args[module]: Unsupported parameters for (basic.py) module: login_password, login_user, server_url. Supported parameters include: exact_match, host_inventory, host_ip, host_name, http_login_password, http_login_user, remove_duplicate. (warning)

サポートされてないモジュールのパラメータ指定を行った際にエラーとなる。今回であれば、Zabbixモジュールの記載方法誤り(バージョンアップによって記載方法が変わったため)。Zabbixモジュールの記載については、以下別記事を参照。

yaml[truthy]: Truthy value should be one of [false, true]

yes/noではなくtrue/falseで記載を統一する。

誤った記載

- name: Reboot
ansible.builtin.reboot:
async: 1
poll: 0
changed_when: no
become: yes

正しい記載

- name: Reboot
ansible.builtin.reboot:
async: 1
poll: 0
changed_when: false
become: true

以上。

EdgeRouter X (ER-X)のファームウェアバージョンアップ手順

先日購入したEdgeRouter X (ER-X)だが、新しいファームウェアがリリースされていたので、ファームウェアバージョンアップを実施してみた。



ファームウェアダウンロードURL

ファームウェアは以下URLからダウンロードできる。2020年1月時点では、数か月に1回は新しいバージョンがリリースされているようだ。
今回は「EdgeRouter ER-X/ER-X-SFP/EP-R6/ER-10X: Firmware v2.0.8」にバージョンアップすることにする。


バージョンアップ用のファイルは「ER-e50.v2.0.8.5247496.tar」といったtar形式のファイルでダウンロードでき、このバージョンの場合は80MB程度の容量となる。tarのまま利用するため、特に解凍する必要はない。

バージョンアップ手順

バージョンアップは管理GUIから行うが、一部CLIからの作業も必要になる。
  1. GUIにログインし、画面下部の「System」タブをクリックする。

  2. 「Upgrade System Image」にある「Upload a file」ボタンをクリックする。


  3. ダウンロードしたtarファイルを選択する。


  4. しばらくすると以下のダイアログボックスにエラーメッセージが表示される。
[System Upgrade Failed]
There wes an error upgrading the system.


このメッセージが表示されたとしても、アップグレードは成功しているパターンがあるので、以降はCLIで確認する。
  1. 現在のバージョンを確認すると、v2.0.4となっている。
$ show version
Version:      v2.0.4
Build ID:     5199165
Build on:     06/05/19 15:49
Copyright:    2012-2018 Ubiquiti Networks, Inc.
HW model:     EdgeRouter X 5-Port
HW S/N:       18E8292F820C
Uptime:       22:38:16 up 3 days, 38 min,  1 user,  load average: 1.21, 1.11, 1.03
ストレージ容量を確認してみると、「/」の空き容量が56.4MBとなっている。空き容量がバージョンアップ用ファイルの80MBより少ないことが、失敗メッセージの原因なのかもしれない。
$ show system storage
Filesystem                Size      Used Available Use% Mounted on
ubi0_0                  214.9M    153.8M     56.4M  73% /root.dev
overlay                 214.9M    153.8M     56.4M  73% /
devtmpfs                123.0M         0    123.0M   0% /dev
tmpfs                   123.7M         0    123.7M   0% /dev/shm
tmpfs                   123.7M      1.8M    121.9M   1% /run
tmpfs                     5.0M         0      5.0M   0% /run/lock
tmpfs                   123.7M         0    123.7M   0% /sys/fs/cgroup
tmpfs                   123.7M      4.0K    123.7M   0% /tmp
tmpfs                   123.7M     68.0K    123.6M   0% /var/log
tmpfs                   123.7M         0    123.7M   0% /run/shm
tmpfs                   123.7M         0    123.7M   0% /lib/init/rw
none                    123.7M    104.0K    123.6M   0% /opt/vyatta/config
overlay                 123.7M      4.0K    123.7M   0% /opt/vyatta/config/tmp/new_config_94812a33023843b680924b175f4b863d
tmpfs                    24.7M         0     24.7M   0% /run/user/1000
バージョンアップ用のファイルのアップロード状況は以下で確認できる。どうやら今回対象となるv2.0.8のファイルはアップロードできているようだ。
$ show system image storage
Image name                        Read-Only   Read-Write        Total
------------------------------ ------------ ------------ ------------
v2.0.8.5247496.191120.1124            80512           48        80560
v2.0.4.5199165.190605.1549            79756          168        79924
  1. 不要なバージョンアップ用のファイルを削除を試みると、「System has already been upgraded and needs a reboot before upgrade」と、すでにアップグレードされているので再起動せよとのメッセージが表示される。
$ delete system image
System has already been upgraded and needs a reboot before upgrade
  1. ER-Xを再起動する。
$ reboot
  1. 再起動後、再度バージョンを確認するとv2.0.8に上がっていることが確認できる。
$ show version
Version:      v2.0.8
Build ID:     5247496
Build on:     11/20/19 11:24
Copyright:    2012-2019 Ubiquiti Networks, Inc.
HW model:     EdgeRouter X 5-Port
HW S/N:       18E8292F820C
Uptime:       19:15:15 up 1 min,  1 user,  load average: 1.49, 0.52, 0.19
  1. 先ほど削除できなかった不要なバージョンアップ用ファイルも削除することができる。今回は前回バージョンとなるv2.0.4を削除した。
$ delete system image
The system currently has the following image(s) installed:

v2.0.8.5247496.191120.1124     (running image) (default boot)
v2.0.4.5199165.190605.1549

You are about to delete image [v2.0.4.5199165.190605.1549]
Are you sure you want to delete ? (Yes/No) [Yes]: yes
Removing old image... Done
削除すると、「/」の空き容量が133.3MBとなり、バージョンアップ用ファイルが再度アップロード可能となる。
$ show system image storage
Image name                        Read-Only   Read-Write        Total
------------------------------ ------------ ------------ ------------
v2.0.8.5247496.191120.1124            80512          160        80672

$ show system storage
Filesystem                Size      Used Available Use% Mounted on
ubi0_0                  214.9M     76.9M    133.3M  37% /root.dev
overlay                 214.9M     76.9M    133.3M  37% /
devtmpfs                123.0M         0    123.0M   0% /dev
tmpfs                   123.6M         0    123.6M   0% /dev/shm
tmpfs                   123.6M      1.3M    122.4M   1% /run
tmpfs                     5.0M         0      5.0M   0% /run/lock
tmpfs                   123.6M         0    123.6M   0% /sys/fs/cgroup
tmpfs                   123.6M      4.0K    123.6M   0% /tmp
tmpfs                   123.6M     56.0K    123.6M   0% /var/log
tmpfs                   123.6M         0    123.6M   0% /lib/init/rw
tmpfs                   123.6M         0    123.6M   0% /run/shm
none                    123.6M    104.0K    123.5M   0% /opt/vyatta/config
tmpfs                    24.7M         0     24.7M   0% /run/user/1000

以上でバージョンアップ作業は完了となる。

更新履歴

  • 2020/1/15 新規作成
  • 2023/8/5 ファームウェアダウンロードURL変更に伴い更新

2023年8月2日水曜日

Ubuntu 20.04 LTS/22.04 LTSのインストール手順&初期設定手順

先日、日本におけるLinuxディストリビューションの検索数のトレンドを調べたところ、Ubuntuの検索数がCentOSやDebianと比較すると圧倒的に多いことがわかった。普段インフラエンジニアとして業務に携わる場合、ほぼRed Hat系のOS一択になっていたので、この結果は意外なものであった。

仕事で使うことがないことに加え、以前のUbuntuでは、デスクトップ環境が「Unity」と呼ばれるUbuntu独自のもので、個人的に使い勝手が悪かったこともあり、敬遠してしまっていた。しかし、現在のUbuntuではデスクトップ環境はGNOMEになったということもあり、今回インストールして使ってみることにした。

なお、本記事では「Ubuntu 20.04 LTS」及び「Ubuntu 22.04 LTS」にて動作確認をしている。

Ubuntuをダウンロードする

Ubuntuには本家からダウンロードできる「Ubuntu Desktop」と「Ubuntu Server」だけでなく、日本語環境利用に最適化された「Ubuntu 日本語 Remix イメージ」が存在する。日本語環境で使用することから、「Ubuntu 日本語 Remix イメージ」をダウンロードして進める。ダウンロードするバージョンは「Ubuntu 20.04 LTS」または「Ubuntu 22.04 LTS」となる。

Ubuntuをインストールする

  1. 「ようこそ」では「Ubuntuをインストール」を選択する。

  2. 「キーボードレイアウト」では「Japanese」を選択する。

  3. 「アップデートと他のソフトウェア」では「通常のインストール」を選択する。

  4. 「インストールの種類」では「ディスクを削除してUbuntuをインストール」を選択する。

  5. 「どこに住んでいますか?」では「Tokyo」を選択する。

  6. 「あなたの情報を入力してください」では必要な情報を入力する。今回は以下で設定した。

    • あなたの名前:ubnt
    • コンピューターの名前:デフォルトでは「<ユーザ名>-virtual-machine」となる。今回はホスト名に修正
    • ユーザー名の入力:ubnt

  7. インストールが開始される。環境にもよるが10分ほどでインストールは完了する。

Ubuntuの初期設定を行う

インストール完了後の初期設定として以下を実施していく。

  • ネットワーク設定・プロキシ設定
  • aptのプロキシ設定
  • SSH有効化
  • open-vm-toolsをインストール
  • xrdpのインストール
  • 時刻同期

ネットワーク設定・プロキシ設定

GUIの「アクティビティ」→「設定」→「ネットワーク」を開き、以下を設定する。ここで設定するプロキシサーバを設定することで、GUI上の「端末」などではhttp_proxyなどの環境変数が設定されるようだ。

  • 有線:IPv4を「手動」に設定し、固定IPアドレスを設定 (DHCP環境で問題ない場合は「自動 (DHCP)」で設定
  • ネットワークプロキシ:プロキシ環境の場合は、プロキシサーバを設定

aptのプロキシ設定

GUIでプロキシ設定を行っても、GUIでソフトウェアの更新を実施した際に失敗する。これはaptのプロキシ設定が不足することが原因となるため、「/etc/apt/apt.conf」のファイルを新規作成し、以下の通りプロキシ設定を追加する。

$ sudo vi /etc/apt/apt.conf
Acquire::http::proxy "http://192.168.33.23:8080";
Acquire::https::proxy "http://192.168.33.23:8080";
Acquire::ftp::proxy "http://192.168.33.23:8080";

「不完全な言語サポート」の対応を実施

インストール後、「不完全な言語サポート」のメッセージが表示される。

GUIでも実施可能であるが、コマンドラインで実施する場合は、以下の通りcheck-language-supportで不足する言語を確認したのち、aptで不足する言語のインストールを行う。

$ check-language-support
firefox-locale-en hunspell-en-au hunspell-en-ca hunspell-en-gb hunspell-en-us hunspell-en-za hyphen-en-ca hyphen-en-gb hyphen-en-us language-pack-en language-pack-gnome-en libreoffice-help-en-gb libreoffice-help-en-us libreoffice-l10n-en-gb libreoffice-l10n-en-za mythes-en-au mythes-en-us thunderbird-locale-en thunderbird-locale-en-gb thunderbird-locale-en-us wamerican wbritish

$ sudo apt update
$ sudo apt install $(check-language-support)

SSH有効化

Ubuntu DesktopではSSHサーバがデフォルトではインストールされていないため、インストールする。

$ sudo apt install openssh-server -y

open-vm-toolsをインストール

Ubuntu Desktopではopen-vm-toolsがデフォルトではインストールされていないため、インストールする。

$ sudo apt install open-vm-tools -y
$ sudo reboot

xrdpのインストール

Windowsと同様にリモートデスクトップ接続 (RDP) によるリモート操作を有効にするため、xrdpをインストールする。xrdpをインストールするだけで必要な設定は十分であり、即座にリモートデスクトップによる接続が可能になり、非常に使い勝手がよい。

$ sudo apt install xrdp -y
$ xrdp -v
xrdp 0.9.12
  A Remote Desktop Protocol Server.
  Copyright (C) 2004-2018 Jay Sorg, Neutrino Labs, and all contributors.
  See https://github.com/neutrinolabs/xrdp for more information.

時刻同期

Ubuntuでは時刻同期ではChronyでもNTPDでもなく、「systemd-timesyncd」で実装されている。

ただし、初期では同期先のNTPサーバの設定がされていないため、時刻同期サービスは動いていたとしても同期はされていない状態となっている。同期状態はtimedatectl statusコマンドで確認できるが、インストール直後は「System clock synchronized」の値が「No」になっている。

$ timedatectl status
               Local time: 日 2020-06-07 15:01:54 JST
           Universal time: 日 2020-06-07 06:01:54 UTC
                 RTC time: 日 2020-06-07 06:01:54    
                Time zone: Asia/Tokyo (JST, +0900)   
System clock synchronized: no                        
              NTP service: active                    
          RTC in local TZ: no                     

設定は「/etc/systemd/timesyncd.conf」に対して行う。デフォルトではすべてコメントアウトされているので、上位NTPサーバの設定のみ追加する。

$ sudo vi /etc/systemd/timesyncd.conf
[Time]
NTP=192.168.33.23   ←★アンコメントして上位のNTPサーバを追加
#FallbackNTP=ntp.ubuntu.com
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048

設定修正後、「systemd-timesyncd」サービスを再起動する。念のため、サービスの自動起動も有効にしておこう。

$ sudo systemctl restart systemd-timesyncd
$ sudo systemctl enable systemd-timesyncd

「System clock synchronized」が「yes」に変わったことを確認する。

$ timedatectl status
               Local time: 日 2020-06-07 15:14:02 JST
           Universal time: 日 2020-06-07 06:14:02 UTC
                 RTC time: 日 2020-06-07 06:14:02    
                Time zone: Asia/Tokyo (JST, +0900)   
System clock synchronized: yes                       
              NTP service: active                    
          RTC in local TZ: no               

まとめ

上記設定にて、リモートデスクトップ接続して利用できるUbuntuのデスクトップ環境が構築できた。インストール後から積極的に使用しているが、Windwosにはない便利なソフトウェアも多数あることから重宝し始めている。

このまま、将来的にはWindows環境からUbuntu環境に作業環境を移したいと考えている。実際に、本記事の作成はUbuntu環境のgeditをメインに使用して作成をしており、Windowsで実施していた作業は、すべてUbuntuで実施できそうだ。

参考

更新履歴

  • 2020/6/14 新規作成
  • 2023/8/2 Ubuntu 22.04における記述を追記
  • 2023/8/27 時刻同期について自動起動有効化のコマンド追記

人気の投稿