シェルスクリプトマガジン

test

香川大学SLPからお届け!(Vol.95掲載)

投稿日:2025.03.25 | カテゴリー: コード

著者:遠藤幸太郎

AIと自然言語処理技術の発展により、「ChatGPT」に代表される、人間と自然な形で対話できる会話型AIが注目を集めています。今回は、PythonでAIチャットボットアプリを開発していきます。米Google社の「Gemini API」を利用し、対話だけでなく、音声や映像ファイルをアップロードして分析できるようにします。

シェルスクリプトマガジン Vol.95は以下のリンク先でご購入できます。

図3 「win.py」ファイルに記述するコード

from PySide6.QtWidgets import (
  QApplication, QMainWindow, QLabel
)
from PySide6.QtCore import Qt
import sys

class MainWindow(QMainWindow):
  def __init__(self):
    super().__init__()
    self.setWindowTitle("ウィンドウタイトル")
    self.setGeometry(100, 100, 400, 300)
    label = QLabel("テキスト", self)
    label.setGeometry(0, 0, 400, 300)
    label.setAlignment(Qt.AlignCenter)

if __name__ == "__main__":
  app = QApplication(sys.argv)
  window = MainWindow()
  window.show()
  sys.exit(app.exec())

図5 基本的なチャットボットアプリのコード

from PySide6.QtWidgets import (
  QApplication, QMainWindow, QWidget,
  QVBoxLayout, QHBoxLayout, QPushButton,
  QTextEdit, QLineEdit,
        ①
)
from PySide6.QtCore import Qt, QThread, Signal
import os, sys, re ②
import google.generativeai as genai
from dotenv import load_dotenv
from markdown2 import markdown

MAX_HISTORY_LENGTH = 10

class ChatWindow(QMainWindow):
  def __init__(self):
    super().__init__()
    self.history = []
    self.setWindowTitle("ChatBot")
    self.setGeometry(100, 100, 600, 400)
    self.central_widget = QWidget()
    self.setCentralWidget(self.central_widget)
    self.main_layout = QVBoxLayout()
    self.chat_layout = QVBoxLayout()
    self.input_layout = QHBoxLayout()
    self.file_layout = QHBoxLayout()
    self.chat_display = QTextEdit()
    self.chat_display.setReadOnly(True)
    self.main_layout.addWidget(self.chat_display)
    self.input_box = QLineEdit()
    self.input_box.setPlaceholderText("ここにメッセージを入力")
    self.input_layout.addWidget(self.input_box)
    self.send_button = QPushButton("送信")
    self.send_button.clicked.connect(self.handle_send)
    self.input_layout.addWidget(self.send_button)
    self.main_layout.addLayout(self.input_layout)
        ③
    self.central_widget.setLayout(self.main_layout)
  def handle_send(self):
    user_message = self.input_box.text().strip()
    if not user_message: return
    self.send_button.setEnabled(False)
    self.chat_display.append(f"<b>あなた:</b> {user_message}")
        ④
    self.input_box.clear()
    self.response_thread = BotResponseThread(
      user_message, self.history ⑤
    )
    self.response_thread.response_ready.connect(
      self.display_bot_response
    )
    self.response_thread.start()
  def safe_markdown(self, text):
    lines = text.splitlines()
    formatted_lines = []
    for i, line in enumerate(lines):
      if re.match(r"^\s*(\d+\.\s+|[-*+]\s+)", line) and (
        i + 1 < len(lines) and lines[i + 1].strip()
      ):
        formatted_lines.append(line)
        formatted_lines.append("")
      else:
      formatted_lines.append(line)
    formatted_text = "\n".join(formatted_lines)
    return markdown(formatted_text)
  def display_bot_response(self, response_text):
    html_content = self.safe_markdown(response_text)
    self.chat_display.append(f"<b>Bot:</b> {html_content}")
    self.send_button.setEnabled(True)
        ⑥

class BotResponseThread(QThread):
  response_ready = Signal(str)
  def __init__(self, user_message, history): ⑦
    super().__init__()
    self.user_message = user_message
        ⑧
    self.history = history
  def run(self):
    response_text = self.get_bot_response(self.user_message) ⑨
    self.response_ready.emit(response_text)
  def get_bot_response(self, message): ⑩
    input_text = message
    self.history.append({"role": "user", "parts": [input_text]})
        ⑪
    response = model.generate_content(self.history)
    self.history.append(response.candidates[0].content)
    if len(self.history) > MAX_HISTORY_LENGTH:
      self.history.pop(0)
    return response.text

def initialize_genai():
  load_dotenv()
  api_key = os.getenv("GOOGLE_API_KEY")
  genai.configure(api_key=api_key)
  return genai.GenerativeModel("gemini-1.5-flash")

if __name__ == "__main__":
  model = initialize_genai()
  app = QApplication(sys.argv)
  window = ChatWindow()
  window.show()
  sys.exit(app.exec())

図9 図5の③で示す箇所に挿入するコード

self.file_label = QLabel("ファイルが選択されていません")
self.file_label.setAlignment(Qt.AlignLeft)
self.file_layout.addWidget(self.file_label)
self.upload_button = QPushButton("ファイルを選択")
self.upload_button.clicked.connect(self.handle_file_selection)
self.file_layout.addWidget(self.upload_button)
self.main_layout.addLayout(self.file_layout)
self.selected_file_path = None

図10 図5の④で示す箇所に挿入するコード

if self.selected_file_path:
  self.chat_display.append(
    f"<b>添付ファイル:</b> {self.selected_file_path}"
  )
  file_path = self.selected_file_path
  self.selected_file_path = None
  self.file_label.setText("ファイルが選択されていません")
else:
  file_path = None

図11 図5の⑥で示す箇所に挿入するコード

def handle_file_selection(self):
  file_dialog = QFileDialog()
  file_path, _ = file_dialog.getOpenFileName(
    self, "ファイルを選択"
  )
  if file_path:
    self.selected_file_path = file_path
    self.file_label.setText(
      f"選択したファイル: {file_path.split('/')[-1]}"
    )

図12 図5の⑪で示す箇所に挿入するコード

if file_path:
  attached_file = genai.upload_file(path=file_path)
  while attached_file.state.name == "PROCESSING":
    time.sleep(10)
    attached_file = genai.get_file(attached_file.name)
  self.history.append(
    {"role": "user", "parts": [attached_file]}
  )
else:
  pass

Pythonあれこれ(Vol.95掲載)

投稿日:2025.03.25 | カテゴリー: コード

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第25回では、人間がどのように文章の意味を理解するかという認知能力に関わる、少し不思議で面白い現象について取り上げます。

シェルスクリプトマガジン Vol.95は以下のリンク先でご購入できます。

図4 タイポグリセミア度を算出する関数tl()の定義コード

import re

# タイポグリセミアに関係する部分を取り出して文字のリストを返す
def s2cl(s):
  sp_chars = '[,.;:.,。、??!!]'
  s2 = re.sub(sp_chars, '', s.strip()).split()
  return list("".join(
    [x[1:-1] for x in filter(lambda x: len(x) > 3, s2)]
  ))

# タイポグリセミア度を計算する関数
def tl(s1, s2):
  s1_chars = s2cl(s1)
  s2_chars = s2cl(s2)
  # 入れ換えた文字を数える
  ctr = 0
  for i in range(len(s1_chars)):
    if s1_chars[i] != s2_chars[i]:
      ctr += 1
  # タイポグリセミア度を返す
  return ctr / len(s1_chars)

図5 関数make_candidate_index()の定義コード

def make_candidate_index(orig, debug=False):
  tmp = ' '
  candidate = ' '
  stopwords = ' ,.!?!?.。,、「」\"\#\*\&\n'
  indexes = []
  # ストップワード文字と、それに隣接する文字を空白に変換
  for i in range(1, len(orig)-1):
    tmp = tmp[:i] + \
          (' ' if orig[i-1] in stopwords \
                  or orig[i+1] in stopwords \
                  or orig[i] in stopwords \
               else orig[i])
  # 直前、直後がストップワード文字の文字を空白に変換
  for i in range(1, len(tmp)-1):
    candidate = candidate[:i] + \
                (' ' if (tmp[i-1] in stopwords \
                         and tmp[i+1] in stopwords) \
                        or (tmp[i] in stopwords) \
                     else tmp[i])
  # debug=True フラグで動作確認できるようにする
  if debug:
    print('ORG:' + orig)
    print('TMP:' + tmp)
    print('CDD:' + candidate)
  # 候補の文字位置のリストを要素にするリストを作成
  flag:bool = False
  for i in range(1, len(candidate)-1):
    if candidate[i] not in stopwords:
      if not flag: 
        flag = True; subindexes = [i]
      else: 
        subindexes.append(i)
    else:
      if flag: 
        indexes.append(subindexes)
      flag = False
  return indexes

図7 タイポグリセミア文を作成する関数typoglycemia()の定義コード

from functools import reduce
import random
 
def typoglycemia(orig, tlval, debug=False):
  if tlval < 0.0 or tlval > 1.0:
    print('tlvalは0.0以上1.0以下でなくてはいけません')
    return None
  # 最初にインデックスのリストを作成する
  indexes = make_candidate_index(orig)
  # indexesに含まれる全要素数を計算する
  denominator = len(reduce(lambda x, y: x+y, indexes))
  # 文字を交換すべき処理対象のリスト
  procs = []
  # 交換する文字数
  swap_nums = 0
  while swap_nums < tlval * denominator:
    # 対象を決める
    target_idx = random.randint(0, len(indexes) - 1)
    target_list = indexes[target_idx]
    if debug: print('---\n処理の対象: ' + str(target_list))
    # 単語が十分に長い場合は、処理対象の2文字を特定する
    if len(target_list) >= 4:
      char_idx = 0
      swap_idx = 0
      while char_idx == swap_idx:
        char_idx = random.randint(0, len(target_list) - 1)
        swap_idx = random.randint(0, len(target_list) - 1)
      c1 = target_list[char_idx]
      c2 = target_list[swap_idx]
      target_list.remove(c1)
      target_list.remove(c2)
      procs.append([c1, c2])
      swap_nums += 2
    # 処理対象の単語が2文字または3文字の場合
    elif len(target_list) == 2 or len(target_list) == 3:
      procs.append(target_list)
      indexes.remove(target_list)
      swap_nums += len(target_list)
      target_list = []
    else:
      print('エラー')
      return None
    if debug:
      print('処理リスト: ' + str(procs))
      print('処理後対象: ' + str(target_list))
  if debug: print('---\n残り: ' + str(indexes) + '\n')
  # procsに入れられた情報に基づき文字の入れ替え処理を行う
  chars:list[str] = list(orig)
  for l in procs:
    if len(l) == 2:
      tmp = chars[l[0]]
      chars[l[0]] = orig[l[1]]
      chars[l[1]] = tmp
    else:
      tmp = chars[l[0]]
      if random.randint(0, 1) == 0: # 時計回りの3文字入れ替え
        chars[l[0]] = orig[l[1]]
        chars[l[1]] = orig[l[2]]
        chars[l[2]] = tmp
      else:                         # 反時計回りの3文字入れ替え
        chars[l[0]] = orig[l[2]]
        chars[l[2]] = orig[l[1]]
        chars[l[1]] = tmp
  return ''.join(chars)

図8 タイポグリセミア度「0.7」の文を作成した例

org = 'The superpowered quick brown fox jumps over the beautiful lazy dog.'
typo = typoglycemia(org, 0.7, debug=True)
typo

特集2 ベクトル検索エンジンのVald(Vol.95記載)

投稿日:2025.03.25 | カテゴリー: コード

著者:湯川 輝一朗

ベクトル検索エンジン「Vald」は、純国産のオープンソースソフトウエア(OSS)です。画像や音声などの非構造データを数値ベクトル化にして検索に利用します。クラウド上でも動作し、大規模な高速検索に向いています。ライセンスはApache License 2.0であり、無料利用が可能です。本特集では、Valdについて解説します。

シェルスクリプトマガジン Vol.95は以下のリンク先でご購入できます。

図7 values.yamlファイル

defaults:
  ## Log level
  logging:
    level: debug
  ## 利用するDockerイメージのtag(componentごとに個別設定も可能)
  image:
    tag: v1.7.16
  server_config:
    ## ヘルスチェックの設定
    healths:
      liveness:
        livenessProbe:
          initialDelaySeconds: 60
      readiness:
        readinessProbe:
          initialDelaySeconds: 60
    ## O11yのための設定
    servers:
        grpc:
          server:
            grpc:
                interceptors:
                - RecoverInterceptor
                - TraceInterceptor
                - MetricInterceptor
  ## 以下もO11yのための設定
  grpc:
    client:
      dial_option:
        interceptors:
          - TraceInterceptor
  observability:
    enabled: true
    otlp:
      collector_endpoint: "opentelemetry-collector-collector.default.svc.cluster.local:4317"
    trace:
      enabled: true
  networkPolicy:
    enabled: true
    custom:
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: pyroscope
      egress:
        - to:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: opentelemetry-collector-collector

## gatewayの設定
gateway:
  lb:
    minReplicas: 3
    maxReplicas: 3
    resources:
      requests:
        cpu: 150m
        memory: 150Mi
    hpa:
      enabled: false
    ingress:
      # Kubernetesのingressを利用する
      enabled: true
      # ingressのホスト
      host: localhost
    service:
      # k3dでingressを利用するための設定
      annotations:
        traefik.ingress.kubernetes.io/service.serversscheme: h2c

## vald-agentの設定
agent:
  minReplicas: 6
  maxReplicas: 6
  ## Production環境では推奨しないが、今回はParallelで行う
  podManagementPolicy: Parallel
  resources:
    requests:
      cpu: 150m
      memory: 150Mi
  ngt:
    # 次元数
    dimension: 784
    # 距離関数
    distance_type: l2
    # ベクトルのオブジェクトタイプ
    object_type: float
    # 自動Indexを行うためのチェック周期(Index Mangerを利用するためマイナスにして無効化)
    auto_index_check_duration_limit: "-1m"
    # 自動Indexの周期(Index Mangerを利用するためマイナスにして無効化)
    auto_index_duration_limit: "-20s"
    # 自動インデックス作成操作のバッチプロセスプールサイズ
    auto_create_index_pool_size: 100
    # インデックス構築時のデフォルトバッチサイズ
    default_pool_size: 100
    
## vald-discovererの設定
discoverer:
  resources:
    requests:
      cpu: 150m
      memory: 50Mi
      
## vald-managerの設定
manager:
  index:
    resources:
      requests:
        cpu: 150m
        memory: 30Mi
    indexer:
      # Index Managerを有効化
      enable: true
      # 自動インデックス作成の制限期間
      # これにより、各Vald Agentで強制インデックス作成がトリガーされる
      auto_index_duration_limit: 1m
      # 自動インデックス作成のチェック期間
      # これにより、コミットされていないインデックスが制限を超えた場合、各Vald Agnetでのインデックス作成がトリガーされる
      auto_index_check_duration: 40s

特集1 はじめてのシェルスクリプト(Vol.95記載)

投稿日:2025.03.25 | カテゴリー: コード

著者:麻生 二郎

シェルスクリプトは、LinuxやUNIX系OSのコマンドのみで記述できるプログラムです。さまざまな処理をテキストファイルに書き込み、LinuxやUNIX系OSの環境ですぐに試せるので便利です。本特集では、はじめてシェルスクリプトを書く人向けにその記述テクニックを分かりやすく紹介します。

シェルスクリプトマガジン Vol.95は以下のリンク先でご購入できます。

図5 引数の受け取りを試すシェルスクリプト(test1.sh)

#!/bin/bash -e

echo $1
echo $2
echo $3

図6 readコマンドを試すシェルスクリプト(test2.sh)

#!/bin/bash -e

read -p 'Please input: ' INPUT01
echo $INPUT01 | tee input.txt

図7 ifを試すシェルスクリプト(test3.sh)

#!/bin/bash -e

if [ $1 == '100' ]; then
    echo 'good'
elif [ $1 == '0' ]; then
    echo 'bad'
else
    echo 'unknown'
fi

図8 caseを試すシェルスクリプト(test4.sh)

#!/bin/bash -e

case $1 in
    100)
        echo 'very good'
        ;;
    80)
        echo 'pretty good'
        ;;
    60)
        echo 'good'
        ;;
    0)
        echo 'bad'
        ;;
esac

図9 Whileを試すシェルスクリプト(test5.sh)

#!/bin/bash -e

i=0
while [ $i -le 10 ]
do
    echo $i
    i=$((i + 1))
done

図10 forを試すシェルスクリプト(test6.sh)

#!/bin/bash -e

for i in 0 1 2 3 4 5
do
    echo $i
done

図11 関数を試すシェルスクリプト(test7.sh)

#!/bin/bash -e

function output()
{
    echo $1
}

output run1
output run2

レポート2(Vol.95掲載)

投稿日:2025.03.25 | カテゴリー: コード

著者:末安 泰三

米FerretDB社は2025年3月5日、MongoDB互換のドキュメント指向データベース管理システム「FerretDB」のバージョン2.0をリリースした。米Microsoft社のNoSQLデータベース実装「DocumentDB」を採用したことで、従来版比で20倍以上の性能を出せるケースがあるという。

シェルスクリプトマガジン Vol.95は以下のリンク先でご購入できます。

図1 「docker-compose.yml」ファイルに記述する内容

services:
  postgres:
    image: ghcr.io/ferretdb/postgres-documentdb:17-0.102.0-ferretdb-2.0.0
    platform: linux/amd64
    restart: on-failure
    environment:
      - POSTGRES_USER=username
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=postgres
    volumes:
      - ./data:/var/lib/postgresql/data

  ferretdb:
    image: ghcr.io/ferretdb/ferretdb:2.0.0
    restart: on-failure
    ports:
      - 27017:27017
    environment:
      - FERRETDB_POSTGRESQL_URL=postgres://username:password@postgres:5432/postgres

networks:
  default:
    name: ferretdb

シェルスクリプトマガジンvol.95 Web掲載記事まとめ

投稿日:2025.03.25 | カテゴリー: コード

004 レポート 米Adobe社の商用利用可能な動画生成AI
005 レポート MongoDB代替のFerretDB新版 コード掲載
006 製品レビュー パソコン「Dell Pro 13 Premium」
007 NEWS FLASH
008 特集1 はじめてのシェルスクリプト/麻生二郎 コード掲載
013 インタビュー Linux Foundation Japan 福安徳晃氏
014 特集2 ベクトル検索エンジンのVald/湯川輝一朗 コード掲載
022 特集3 Hinemos入門 ジョブ編/倉田晃次、加藤達也
030 Markdownを活用する/藤原由来
039 Raspberry Pi Pico W/WHで始める電子工作/米田聡
046 Pythonあれこれ/飯尾淳 コード掲載
052 香川大学SLPからお届け!/遠藤幸太郎 コード掲載
058 中小企業手作りIT化奮戦記/菅雄一
064 SSHによるリモート管理入門/大津真
074 Techパズル/gori.sh
075 コラム「小売業のビジネスリーダーを育成する講義」/シェル魔人

Vol.95

投稿日:2025.03.25 | カテゴリー: バックナンバー

 シェルスクリプトは、UNIX/Linuxコマンドを組み合わせてプログラムを記述します。コマンドの羅列でも動作するので、プログラムとしてはとてもシンプルです。このシェルスクリプトは、UNIX系OSやLinuxの環境があれば、すぐに試せます。特集1では、はじめてシェルスクリプトを書く人向けにポイントとなる記法を紹介しています。
 特集2では、国産オープンソースソフトウエアのベクトル検索エンジン「Vald」を解説しています。ベクトル検索エンジンは、画像や音声などの非構造データを数値ベクトル化にして検索に利用します。大規模な高速検索に向くValdの仕組みや導入方法を理解しましょう。
 特集3では、エンタープライズシステムの監視やジョブ管理、運用の自動化などを実現する国産オープンソースの統合運用管理ソフトウエア「Hinemos」のジョブ管理機能を紹介しています。シェルスクリプトマガジン Vol.92の特集2に次ぐ第2弾です。
 このほか、連載「Pythonあれこれ」では、「タイポグリセミア」という最初と最後の文字さえ合っていれば、順番はめちゃくちゃでもちゃんと読める現象をPythonプロブラムと絡めています。とても面白い内容です。
 今回も読み応え十分のシェルスクリプトマガジン Vol.95。お見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

Vol.95 補足情報

投稿日:2025.03.21 | カテゴリー: コード

特集3 Hinemos入門 ジョブ編

Hinemosの運用管理機能を提供する「Hinemosマネージャ」などのソフトウエアを、「Red Hat Enterprise Linux 9」が稼働するホストにインストールする手順を、こちらで紹介しています。

連載 Markdownを活用する

静的サイトジェネレータ「Hugo」およびバージョン管理システム「Git」のインストール、Gitのセットアップ、サイトの構築手順は、こちらから参照できます。

連載香川大学SLPからお届け!

記事で紹介したコードを拡張して、アプリのボタンなどの見栄えを調整しました。コードを記したファイルはここからダウンロードできます(ファイルはZIPで圧縮しています)。

情報は随時更新致します。

Hinemos導入とエージェント起動

投稿日:2025.03.21 | カテゴリー: コード

 2025年4月号特集3を読むための準備として、Linuxディストリビューション「Red Hat Enterprise Linux 9」(RHEL9)環境にHinemosをインストールしてエージェントを起動する方法を紹介します。このコンテンツは、2024年10月号のシェルスクリプトマガジンVol.92特集2を基にしています。以下では、インストール先のホスト名が「rhel-manager」、IPアドレスが「172.16.63.245」の場合を例に、作業手順を解説します。他のホスト名やIPアドレスを利用している場合には、適宜読み替えてください。
 Hinemosのシステムは、「マネージャサーバ」「クライアント」「管理対象ノード」で構成されます。(図1)。


 マネージャサーバは、Himemosの運用管理機能を提供するHinemosマネージャ(以下、マネージャ)が稼働するマシンです。管理対象の情報を保持したリポジトリと、監視やジョブといった各機能で扱うデータを保管するデータベースを保持します。
 クライアントは、オペレータが利用するGUIベースの操作端末です。OSに専用ソフトウエアをインストールして使う「リッチクライアント」と、Webブラウザで操作できる「Webクライアント」の2種類があります。今回は、マネージャサーバにWebクライアントをインストールして、それをWebブラウザで使うことにします。
 管理対象ノードは、監視やジョブ実行などを行うHinemosの管理対象となるマシンです。利用する機能によっては、管理対象ノードに「Hinemosエージェント」(以下、エージェント)やSNMP*サーバーなどのソフトウエアをインストールする必要があります。今回は、マネージャサーバ自身にエージェントをインストールして、管理対象ノードにします。

【SNMP】 リモート機器を監視、制御するためのネットワークプロトコル。Simple Network Management Protocolの略。

マネージャの導入準備

 マネージャをインストールする前に、マネージャの動作に必要なパッケージをインストールします。rhel-managerに管理者(rootユーザー)でログインしてから、次のコマンドを実行してください。

# dnf install -y java-1.8.0-openjdk tar unzip vim ↵
# dnf install -y google-noto-sans-cjk-ttc-fonts java-1.8.0-openjdk-devel lsof net-snmp net-snmp-utils sysstat tcpdump wsmancli zip ↵

 なお、2回目のdnfコマンドでインストールしているパッケージは必須ではありませんが、インストールが推奨されているものです。特別な理由がなければインストールすることをお勧めします。以下では、これらの推奨パッケージもインストールしたものとします。
 続いて、次のコマンドを実行してロケール(言語設定)を日本語にします。

# dnf install -y glibc-langpack-ja ↵
# localectl set-locale LANG=ja_JP.UTF-8 ↵

 さらにSELinux*を無効にします。SELinuxが有効になっていると、マネージャをインストールできないからです。SELinuxを無効にするには、「/etc/selinux/config」ファイルの「SELINUX」行を次のように書き換えてから、RHEL9を再起動します。

SELINUX=disabled

【SELinux】 強制アクセス制御と呼ばれるセキュリティ機能を提供するセキュリティモジュール。Security-Enhanced Linuxの略。

 なお、同行が「SELINUX=enforcing」の場合には、SELinuxが有効になります。「SELINUX=permissive」の場合には、SELinuxによるアクセス制御は無効になりますが、監査ログの記録は有効になります。
 マネージャサーバがクライアントや管理対象ノードからの接続を受け付けられるように、ファイアウォールの設定もします。RHEL9では、デフォルトでファイアウォールが有効になっています。そのため、ファイアウォールを無効にするか、接続を待ち受けるポートを開放する必要があります。
 ファイアウォールを無効にするには、次のコマンドを実行します。

# systemctl stop firewalld ↵
# systemctl disable firewalld ↵

 ファイアウォールを有効にしておきたい場合には、ポートを開放する設定をします。例えば、TCPの22番ポートと80番ポートを開放するには、次のようにfirewalldコマンドを実行します。

# firewall-cmd --permanent --add-port={22/tcp,80/tcp}  ↵

 同様の手順で、表1に示すポートをすべて開放する設定をしてください*1。設定後、次のコマンドを実行することでファイアウォールに反映されます。

# firewall-cmd --reload ↵

*1 開放するポートの詳細については、「Hinemos ver.7.1 基本機能マニュアル」(https://github.com/hinemos/hinemos/releases/download/v7.1.0/ja_Base_Linux_7.1_rev1.pdf)の「2.2.9 ネットワークの要件」を参照してください。

表1 マネージャサーバで開放すべきポート

プロトコルリッチクライアントや管理対象ノードからの接続待ち受けポートWebクライアントの接続待ち受けポート
TCP22,8080,8081,8082,8083,8443,8444,8445,2400180,443
UDP161,162,514

 最後に、マネージャサーバのホスト名の名前解決ができることを確認します。名前解決ができない場合、マネージャがうまく動作しないことがあります。
 次のようにpingコマンドを実行して、自分自身から応答があることを確認してください。

# ping rhel-manager ↵

 「Name or service not known」と表示される場合には、名前解決ができていません。そのときには、次のコマンドを実行して名前解決用の情報を登録します。他のホスト名やIPアドレスを利用している場合には、適宜読み替えてください。

# echo 172.16.63.245 rhel-manager >> /etc/hosts ↵

 以上で事前準備は完了です。

マネージャの導入と起動

 マネージャやWebクライアント用コンポーネント、管理対象ノードにインストールするエージェントのパッケージは、GitHubリポジトリのリリースページ(https://github.com/hinemos/hinemos/releases)から入手できます。ここから、最新版をインストールしてください。
 今回は、2024年9月上旬時点の最新版である「Hinemos ver.7.1.0」のパッケージをインストールします。マネージャのパッケージは「hinemos-7.1-manager-7.1.0-1.el9.x86_64.rpm」、Webクライアント用コンポーネントのパッケージは「hinemos-7.1-web-7.1.0-1.el9.x86_64.rpm」です。これらを「/tmp」ディレクトリなどにダウンロードし、ダウンロードしたディレクトリで次のコマンドを実行するとインストールできます。

# rpm -ivh hinemos-7.1-manager-7.1.0-1.el9.x86_64.rpm ↵
# rpm -ivh hinemos-7.1-web-7.1.0-1.el9.x86_64.rpm ↵

 GitHubリポジトリからも直接インストールできます。それには、次のようにrpmコマンドを実行します。

# rpm -ivh https://github.com/hinemos/hinemos/releases/download/v7.1.0/hinemos-7.1-manager-7.1.0-1.el9.x86_64.rpm  ↵
# rpm -ivh https://github.com/hinemos/hinemos/releases/download/v7.1.0/hinemos-7.1-web-7.1.0-1.el9.x86_64.rpm ↵

 パッケージのインストール後、次のコマンドを実行するとマネージャとWebクライアントが起動します。

# systemctl start hinemos_manager ↵
# systemctl start hinemos_web ↵

エージェントの導入と起動

 続いて、マネージャサーバにエージェントを導入して、自分自身を管理対象ノードとして取り扱えるようにします*2。それにはまず、次のコマンドを実行して、エージェントの実行に必要なパッケージをインストールします。

# dnf install -y openssh-clients ↵

*2 マネージャサーバ以外のコンピュータにエージェントをインストールする場合の作業手順については、「Hinemos ver.7.1 基本機能マニュアル」の「2.2.5Hinemosエージェントの要件」などを参照してください。

 ファイアウォールも設定します。ファイアウォールを無効にするか、表2に示すポートを開放してください。

表2 管理対象ノードで開放すべきポート

プロトコル開放すべきポート
TCP22
UDP161,24005

 さらに、次のコマンドを実行してsnmpdサービス(SNMPサーバー)を起動します。これにより、マネージャサーバのCPUやメモリーなどのリソース情報をHinemosが取得できるようになります。

# systemctl start snmpd ↵

 ここまでの作業で、エージェントをインストールする準備が整いました。エージェントのパッケージは「hinemos-7.1-agent-7.1.0-1.el.noarch.rpm」です。これを「/tmp」ディレクトリなどにダウンロードし、ダウンロードしたディレクトリで次のコマンドを実行するとインストールできます。

# HINEMOS_MANAGER=172.16.63.245 rpm -ivh hinemos-7.1-agent-7.1.0-1.el.noarch.rpm ↵

 シェル変数HINEMOS_MANAGERには、マネージャサーバのIPアドレスを設定します。
 先ほどと同様に、GitHubリポジトリからも直接インストールできます。それには、次のようにrpmコマンドを実行します。

# HINEMOS_MANAGER=172.16.63.245 rpm -ivh https://github.com/hinemos/hinemos/releases/download/v7.1.0/hinemos-7.1-agent-7.1.0-1.el.noarch.rpm ↵

 最後に、次のコマンドを実行すればエージェントが起動します。

# systemctl start hinemos_agent ↵

  • shell-mag ブログの 2025年3月 のアーカイブを表示しています。

  • -->