※当サイトの記事には、広告・プロモーションが含まれます。

Oxidizedのconfigのoutputをgitにした際のデフォルトのリポジトリのbranchの問題に対応する

gigazine.net

「大事な選択をする時はすぐに決断せず、まず一晩寝てから考えた方がいい」というアドバイスを聞いたことがある人は多いはず。実際に、デューク大学の研究チームが発表した新たな論文では、「一晩寝てから決断した方がすぐに決断するよりも合理的な選択ができる」という結果が示されました。

合理的な選択をするには「寝る」ことが重要という研究結果 - GIGAZINE

⇧ まぁ、ちょっと前に、

gigazine.net

勉強や仕事などで解決策が見つからずに行き詰まった際に「一晩寝たら解決策が思い浮かんだ」という経験をしたことがある人は多いはず。一晩眠るとアイデアが思いつく現象には睡眠中の脳の記憶整理機能が関係しているとされているのですが、新たにイェール大学の研究チームによって記憶整理機能のメカニズムの一端が解明されました。

「一晩寝たら解決策が浮かぶ」という現象のメカニズムが一部解明される、脳は睡眠中に1日の出来事を1秒未満に圧縮して整理している - GIGAZINE

⇧ というような話が出てましたし、然もありなん、といった感じですかね。

無理とは分かってはいるものの、毎日8時間は眠りたいと願って幾星霜、日々睡眠不足の生活に耐え忍ぶ、どうもボクです。

2024年10月22日(火)追記:↓ ここから

とりあえず、

ts0818.hatenablog.com

⇧ 上記の記事に追記したのだけど、Oxidizedのドキュメントが最近、更新されており、Gitリポジトリのbranchを指定できるかもしれないようです。

branchが指定できるのであれば、本記事の内容は不要になります。

不毛な時間を費やしたことになってしまうのである...

2024年10月22日(火)追記:↑ ここまで

必要なライブラリを確認

今回、Docker Composeで「Oxidized」を動作させるので、

github.com

⇧ ドキュメント通りであれば、最低限、

  1. Docker
  2. Docker Compose
  3. Git

が、ホスト側にインストールされている必要があるので、確認しておく。

⇧ 以前、インストールしていたのでインストールされている。

インストールしていない場合は、

docs.docker.com

docs.docker.com

qiita.com

⇧ 上記サイト様を参考にインストールしておく。

マウント先となるホスト側のディレクトリを作成

今回、Docker Composeで動作させる予定なので、Dockerコンテナ側から見たマウント先となるホスト側のディレクトリを作成しておく。

Dockerの公式のドキュメントによると、

docs.docker.jp

  • ボリューム(volume) は、 「Docker によって管理されている」ホストファイルシステム上の一部に保管します( Linux 上では /var/lib/docker/volumes )。 Docker 以外のプロセスは、このファイルシステム上の一部を変更すべきではありません。ボリュームは Docker 内のデータを保持するために一番良い方法です。

  • バインド マウント(bind mount) は、ホストシステム上の「どこにでも」保管できます。これには重要なシステムファイルやディレクトリも含みます。Docekr ホスト上の Docker 以外のプロセスも、 Docker コンテナも、常にデータを変更できます。

  • tmpfs マウント は、ホストシステムのメモリ上にのみ保管します。そして、ホストシステムのファイルシステムには一切書き込まれません。

https://docs.docker.jp/storage/index.html

⇧ Dockerコンテナのデータの保存先としては、3つの方法が用意されているようですが、データ永続化の観点で考えた場合、

  1. Dockerコンテナ再起動
  2. Dockerホスト再起動

のどちらも発生したケースにも対応し得るのは、

  1. ボリューム(volume)
  2. バインド マウント(bind mount)

のどちらかになると。

この2つの違いについては、

docs.docker.jp

バインド マウントbind mount は初期の Docker から存在しています。 ボリューム と比較すると、バインド マウントは機能が限定的です。

https://docs.docker.jp/storage/bind-mounts.html

バインド マウントを使う時、「ホストマシン」上のファイルやディレクトリを、コンテナ内にマウントします。ファイルやディレクトリは、ホストマシン上の絶対パスとして参照されます。

https://docs.docker.jp/storage/bind-mounts.html

対照的に、ボリュームを使う場合は、新しいディレクトリがホストマシン上の Docker のストレージディレクトリ内に作成され、 Docker が内容を直接管理します。

https://docs.docker.jp/storage/bind-mounts.html

ファイルやディレクトリは Docker ホスト上にあらかじめ存在している必要はありません。存在しなければ、必要に応じて作成されます。

https://docs.docker.jp/storage/bind-mounts.html

バインド マウントは高性能ですが、ホストマシンのファイルシステムで利用可能な、特定のディレクトリ構造に依存します。新しい Docker アプリケーションを開発する場合は、代わりに 名前付きボリューム の利用を検討してください。バインド マウントは Docker CLI コマンドを使って直接管理できません。

https://docs.docker.jp/storage/bind-mounts.html

⇧ という説明なのだけど、

No 項目 内容
和名 英名
1 バインドマウント bind mount 初期リリース時から存在した
2 ボリューム volume 初期リリース時は存在しなかった

⇧ という感じで、「2. ボリューム(volume)」は後発だけあって、機能が豊富らしい。

ちなみに、Docker Composeの設定には、

docs.docker.jp

⇧ という感じで、記述の方法が2種類あるらしく、

github.com

stackoverflow.com

⇧「create_host_path」の指定をしないと、Dockerコンテナ起動時にホスト側のディレクトリの作成がされないという事象が起こると。

「create_host_path」はというと、

docs.docker.jp

⇧ マウントの型で「bind」を選択している場合の追加オプションということらしい。

話が脱線しましたが、

ts0818.hatenablog.com

⇧ 上記の記事の時に発覚している「Oxidized」の問題を回避するにあたり、ホスト側のディレクトリを事前に作成しておく必要があるので、事前にディレクトリを作成する方向で。

Linux環境において、マウント先のホスト側のディレクトリの一般的なパスがどうなるのかよく分からんので、ChatGPTに確認したところ、

No ディレクトリパス 用途
1 /home/username/ ユーザーのホームディレクト /home/john/myproject
2 /opt/ サードパーティ製アプリケーションのインストール /opt/myapp
3 /var/www/ Webアプリケーションのホスティング /var/www/mywebsite
4 /srv/ サービスデータの格納 /srv/myproject
5 /usr/local/ ローカルのアプリケーションやライブラリのインストール /usr/local/myapp
6 /etc/ 設定ファイルの保存 /etc/myapp/config
7 /var/lib/ 永続データの保存 /var/lib/mysql

⇧ という回答になった。

今回は「Oxidized」を利用したアプリケーションの構築になるということで、「2. /opt/」のケースになるんかな?

「Oxidized」の公式のドキュメントの「Config」を確認すると、

github.com

https://github.com/ytti/oxidized/blob/master/docs/Configuration.md#advanced-configuration

---
username: oxidized
password: S3cr3tx
model: junos
interval: 3600 #interval in seconds
log: ~/.config/oxidized/log
debug: false
threads: 30 # maximum number of threads
# use_max_threads:
# false - the number of threads is selected automatically based on the interval option, but not more than the maximum
# true - always use the maximum number of threads
use_max_threads: false
timeout: 20
retries: 3
prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
crash:
  directory: ~/.config/oxidized/crashes
  hostnames: false
vars:
  enable: S3cr3tx
groups: {}
rest: 127.0.0.1:8888
pid: ~/.config/oxidized/oxidized.pid
input:
  default: ssh, telnet
  debug: false
  ssh:
    secure: false
output:
  default: git
  git:
      user: Oxidized
      email: oxidized@example.com
      repo: "~/.config/oxidized/oxidized.git"
source:
  default: csv
  csv:
    file: ~/.config/oxidized/router.db
    delimiter: !ruby/regexp /:/
    map:
      name: 0
      model: 1
      username: 2
      password: 3
    vars_map:
      enable: 4
model_map:
  cisco: ios
  juniper: junos    

⇧ 上記が設定項目の全量らしいのですが、Dockerコンテナ側のディレクトリとしては、

~/.config/oxidized    

⇧ の1箇所に全て集約している。

しかし、

github.com

⇧「Oxidized」が用意しているmodelクラス以外を利用したい場合については、

~/.config/oxidized/model

⇧ の場所に自分で用意したmodelクラスを配置する必要がありますと。

というわけで、ホスト側のディレクトリとしては、

■OxidizedをDockerコンテナとして稼働させる場合のマウント先のホスト側のディレクト

/opt/app/oxidized/.config/oxidized    

■OxidizedをDockerコンテナとして稼働させる場合のマウント先のホスト側のディレクトリ(modelクラス用)

/opt/app/oxidized/.config/oxidized/model

⇧ のようなものを作成することにして、別途、作業用のディレクトリとしては、

■作業用のディレクト

/home/[user]/work/app

を用意することにする。

⇧ というようなディレクトリがホスト側に用意できました。

Oxidizedのリポジトリをgit cloneする

実業務だと、開発用のGitリポジトリが用意されているとは思いますが、今回は特に用意できていないので、

github.com

⇧ 公式のGitリポジトリを利用することにします。

作業用のディレクトリに移動し、git cloneします。

■作業用のディレクトリに移動

cd [作業用のディレクトリ]    

HTTPSでgit cloneする

git clone https://github.com/ytti/oxidized.git

⇧ git cloneできました。

Dockerfileを編集する

git cloneしてきた公式のGitリポジトリのDockerfileについては、「oxidized-web」のものになってしまっているので、「oxidized」のものに書き変える必要がある。

で、Docker Hub上にDockerfileあるかと思っていたのですが見当たらない。

どうやら、

www.kimoton.com

⇧ というような、様々な理由が存在するようです。

今回のケースだと、要するに「Oxidized」側が用意してくれていないということらしい。

ちなみに、DockerイメージからDockerfileの作成できないのかについては、

stackoverflow.com

qiita.com

リバースエンジニアリング的な扱いになるようなので、完全な実現はできないっぽい。

致し方無いので、

github.com

github.com

github.com

⇧ ベースイメージの「OS(Operation System)」としては「Ubuntu 24.04 LTS」を利用していく形になるのですが、「oxidized」に必要なものになっているかは分かりませんが、

# Stage 1: Build x25519 and any necessary dependencies
FROM docker.io/phusion/baseimage:noble-1.0.0 AS x25519-builder

# install necessary packages for building gems
RUN apt-get update && apt-get install -y \
    build-essential \
    git \
    ruby-dev \
    && rm -rf /var/lib/apt/lists/*

# create bundle directory
RUN mkdir -p /usr/local/bundle
ENV GEM_HOME=/usr/local/bundle

# Install the x25519 gem
RUN gem install x25519 --no-document

# Stage2: build an oxidized container from phusion/baseimage-docker and install x25519 from stage1
FROM docker.io/phusion/baseimage:noble-1.0.0

ENV DEBIAN_FRONTEND=noninteractive

##### Place "static" commands at the beginning to optimize image size and build speed
# add non-privileged user
ARG UID=30000
ARG GID=$UID
RUN groupadd -g "${GID}" -r oxidized && useradd -u "${UID}" -r -m -d /home/oxidized -g oxidized oxidized

# link config for msmtp for easier use.
RUN ln -s /home/oxidized/.config/oxidized/.msmtprc /home/oxidized/

# create parent directory & touch required file
RUN mkdir -p /home/oxidized/.config/oxidized/
RUN touch /home/oxidized/.config/oxidized/.msmtprc

# setup the access to the file
RUN chmod 600 /home/oxidized/.msmtprc
RUN chown oxidized:oxidized /home/oxidized/.msmtprc

# add runit services
COPY extra/oxidized.runit /etc/service/oxidized/run
COPY extra/auto-reload-config.runit /etc/service/auto-reload-config/run
COPY extra/update-ca-certificates.runit /etc/service/update-ca-certificates/run

# set up dependencies for the build process
RUN apt-get -yq update \
    && apt-get -yq upgrade \
    && apt-get -yq --no-install-recommends install ruby \
    # Build process of oxidized from git (beloww)
    git \
    # Allow git send-email from docker image
    git-email libmailtools-perl \
    # Allow sending emails in the docker container
    msmtp \
    # Debuging tools inside the container
    inetutils-telnet \
    # Use ubuntu gems where possible
    # Gems needed by oxidized
    ruby-rugged ruby-slop ruby-psych \
    ruby-net-telnet ruby-net-ssh ruby-net-ftp ruby-net-scp ruby-ed25519 \
    # Gem dependencies for inputs
    ruby-net-http-persistent ruby-mechanize \
    # Gem dependencies for sources
    ruby-sqlite3 ruby-mysql2 ruby-pg ruby-sequel ruby-gpgme\
    # Gem dependencies for hooks
    ruby-aws-sdk ruby-xmpp4r \
    # Gems needed by oxidized-web
#    ruby-charlock-holmes ruby-haml ruby-htmlentities ruby-json \
#    puma ruby-sinatra ruby-sinatra-contrib \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# copy the compiled gem from the builder stage
COPY --from=x25519-builder /usr/local/bundle /usr/local/bundle

# Set environment variables for bundler
ENV GEM_HOME="/usr/local/bundle"
ENV PATH="$GEM_HOME/bin:$PATH"

# gems not available in ubuntu noble
RUN gem install --no-document \
    # dependencies for hooks
    slack-ruby-client cisco_spark \
    # dependencies for specific inputs
    net-tftp

# build and install oxidized
COPY . /tmp/oxidized/
WORKDIR /tmp/oxidized

# docker automated build gets shallow copy, but non-shallow copy cannot be unshallowed
RUN git fetch --unshallow || true

# Ensure rugged is built with ssh support
RUN CMAKE_FLAGS='-DUSE_SSH=ON' rake install

# web interface
#RUN gem install oxidized-web --no-document
#RUN gem install oxidized --no-document

# clean up
WORKDIR /
RUN rm -rf /tmp/oxidized

EXPOSE 8888/tcp  

⇧ 上記のような感じに書き換えますか。

物凄く、紛らわしいのですが、「oxidized」は、「Rakefile」でインストールされるらしい。

「Dockefile」を別のディレクトリにコピーしたかったのですが、「Oxidized」の「Dockefile」の構成が密結合してしまっており(「Rakefile」で「Git」コマンド利用していたりと「Dockerfile」以外の要因が密接に絡んでくる)、移動が難しいのでgit cloneしてきた場所のままにして移動はしないように注意。

書き換え。

Dockerイメージを生成する

Dockefileを元に、Dockerイメージを生成します。

docker build . -t [NAME]:[TAG]

docker-compose.ymlを作成・編集する

公式のGitHubのREADMEの内容を元に、作成・編集する。

github.com

■/home/ts0818/work/app/docker-compose.yml

---
version: "3"
services:
  oxidized:
    restart: always
    image: app-oxidized:v1.0
    ports:
      - 8888:8888/tcp
    environment:
      CONFIG_RELOAD_INTERVAL: 600
    volumes:
      - type: bind
        source: /opt/app/oxidized/.config/oxidized
        target: /home/oxidized/.config/oxidized    

⇧ ホスト側のディレクトリとマウントしておく。

Oxidizedのconfigを作成・編集する

公式のGitHubの「Configuration.md」の「Advanced Configuration」を参考にするしかない。

github.com

⇧ 各項目の設定の意味について説明がないものが多いので、正確な設定は難しいが...

■/opt/app/oxidized/.config/oxidized/config

---
#username: oxidized
#password: S3cr3tx
#model: junos
#interval: 3600 #interval in seconds
interval: 60
log: ~/.config/oxidized/logs/app-oxidized.log
#debug: false
debug: true
#threads: 30 # maximum number of threads
threads: 3
# use_max_threads:
# false - the number of threads is selected automatically based on the interval option, but not more than the maximum
# true - always use the maximum number of threads
use_max_threads: false
timeout: 20
retries: 3
prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
crash:
  directory: ~/.config/oxidized/crashes
  hostnames: false
#vars:
#  enable: S3cr3tx
groups: {}
#rest: 127.0.0.1:8888
rest: false
pid: ~/.config/oxidized/oxidized.pid
input:
  default: ssh, telnet
  debug: false
  ssh:
    secure: false
output:
  default: git
  git:
    user: Oxidized
    email: oxidized@example.com
    repo: "~/.config/oxidized/test-personal-github-app.git"
source:
  default: csv
  csv:
    file: ~/.config/oxidized/router.db
    delimiter: !ruby/regexp /:/
    map:
      name: 0
      ip: 1
      model: 2
      username: 3
      password: 4
    vars_map:
      enable: 5
model_map:
  test_local: linuxgeneric
#  cisco: ios
#  juniper: junos

⇧ modelクラスについて、通常のLinuxにも対応している「linuxgeneric.rb」を利用する設定にしてます。

設定項目の全量と各設定項目についての説明を、公式のドキュメントで整備して欲しいんよね...

雰囲気でやるしかないから、障害が起きてもやむを得ない感はありますな...

Oxidizedのrouter.dbを作成・編集する

公式のGitHubの「Sources.md」の「Source: CSV」の例を参考にするしかない。

github.com

⇧「Configuration.md」の「Advanced Configuration」には存在しなかった、「ip」が出てきたりと、設定の全量が分かり辛過ぎるのだが...

■/opt/app/oxidized/.config/oxidized/router.db

[対象機器のホスト名]:[対象機器のIPアドレス]:[model_mapのキー]:[対象機器のSSHユーザー]:[対象機器のSSHユーザーのパスワード]    

⇧ 保存。

Oxidizedのmodelクラスを用意する

で、既存のmodelクラス以外を利用せざるを得ない場合は、

github.com

⇧ modelクラスを用意する必要がありますと。

「Oxidized」が用意しているmodelクラスの内、標準的なLinuxディストリビューションに対応しているらしい、

github.com

⇧「linuxgeneric.rb」を継承させたmodelクラスを用意します。

■vi /opt/app/oxidized/.config/oxidized/model/linuxgenericextra.rb

require 'oxidized/model/linuxgeneric.rb'

class LinuxGenericExtra < LinuxGeneric
  using Refinements

  post do |cfg|
    cfg = add_comment 'HOST IP ADDRESS'
    cfg += cmd 'ip a'
    cfg
  end

end

⇧ で保存。

Oxidizedのconfigのoutputをgitにした際のGitリポジトリを用意

「Oxidized」のoutputとしては、

github.com

⇧ 上記のページの説明だと、

  1. Output: File
  2. Output: Git
  3. Output: Git-Crypt
  4. Output: Http
  5. Output types

の5つの選択肢が用意されているようなのだけど、「2. Output: Git」を選んだ場合は、「Oxidized」の処理内で「Rugged」というライブラリを利用しているため、「Git」のローカルリポジトリが「bare repository」として生成され、「git commit」まで処理されますと。

つまり、「Git」のリモートリポジトリを用意しておく必要がありますと。

今回は、過去に作成していたGitHubのプライベートなGitリポジトリを利用することにします。

Oxidizedのconfigのoutputをgitにした際のデフォルトのリポジトリがbareでbranchがmasterな問題に対応する

で、ようやっと本題。

github.com

⇧ 上記で連携いただいた方法である

『事前に、「bare repository」をローカルに用意して、「main」ブランチにしておくことで、「master」ブランチで処理されてしまうのを回避できるか』

ですが、結論としては、期待通りの動きになりました。

では、以下、実際に行ったことを備忘録としてまとめておきます。

GitHub Appに紐付けたプライベートリポジトリだからなのか、

stackoverflow.com

⇧ stackoverflowにあるように、

■ユーザーのPAT(Personal Access Token)で認証してgit cloneする

git clone https://<your account>:<PAT(Personal Access Token)>@github.com/<your account or organization>/<repo>.git    

GitHub AppのInstall Access Tokenで認証してgit cloneする

git clone https://x-access-token:<Install Access Token>@github.com/<your account or organization>/<repo>.git    

⇧ のように認証情報をURLに組み込む必要があるようです。

「PAT(Personal Access Token)」の権限は、「repo」にチェックされてれいれば良いようです。

「organization」の管理してるリポジトリに対して、「PAT(Personal Access Token)」による認証をするには、以下、設定で「Authorize」ボタンを押下する必要がある。

今回は「organization」のリポジトリではなく、個人のプライベートリポジトリですが、git cloneできました。

「PAT(Personal Access Token)」の値で、アルファベットの「O」と数字の「0」を見間違えるという発狂しそうなミスをしたことを反省いたします...

転送とかできない環境につき、目視で転記せざるを得ない状況だったので...

実行したところ、

⇧「main」ブランチで処理されていることが確認できました。

後は、別途、シェルスクリプトなどで、

git push origin main    

⇧ とかすれば良いと。

ちなみに、

github.com

⇧「hook」で「git push」が実現できるらしいのだけど、残念なことに「proxy」に対応していないため、利用したくても利用できないという...

う~む、「proxy」に対応していないってのは、厳しいですな...

それにしても、公式のドキュメントの情報が散逸してるのと、そもそも情報が無いのとで、不毛な時間が際限なく浪費されていくからして、本当にドキュメントは整備して欲しいのよね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。