「大事な選択をする時はすぐに決断せず、まず一晩寝てから考えた方がいい」というアドバイスを聞いたことがある人は多いはず。実際に、デューク大学の研究チームが発表した新たな論文では、「一晩寝てから決断した方がすぐに決断するよりも合理的な選択ができる」という結果が示されました。
⇧ まぁ、ちょっと前に、
勉強や仕事などで解決策が見つからずに行き詰まった際に「一晩寝たら解決策が思い浮かんだ」という経験をしたことがある人は多いはず。一晩眠るとアイデアが思いつく現象には睡眠中の脳の記憶整理機能が関係しているとされているのですが、新たにイェール大学の研究チームによって記憶整理機能のメカニズムの一端が解明されました。
「一晩寝たら解決策が浮かぶ」という現象のメカニズムが一部解明される、脳は睡眠中に1日の出来事を1秒未満に圧縮して整理している - GIGAZINE
⇧ というような話が出てましたし、然もありなん、といった感じですかね。
無理とは分かってはいるものの、毎日8時間は眠りたいと願って幾星霜、日々睡眠不足の生活に耐え忍ぶ、どうもボクです。
2024年10月22日(火)追記:↓ ここから
とりあえず、
⇧ 上記の記事に追記したのだけど、Oxidizedのドキュメントが最近、更新されており、Gitリポジトリのbranchを指定できるかもしれないようです。
branchが指定できるのであれば、本記事の内容は不要になります。
不毛な時間を費やしたことになってしまうのである...
2024年10月22日(火)追記:↑ ここまで
必要なライブラリを確認
今回、Docker Composeで「Oxidized」を動作させるので、
⇧ ドキュメント通りであれば、最低限、
- Docker
- Docker Compose
- Git
が、ホスト側にインストールされている必要があるので、確認しておく。
⇧ 以前、インストールしていたのでインストールされている。
インストールしていない場合は、
⇧ 上記サイト様を参考にインストールしておく。
マウント先となるホスト側のディレクトリを作成
今回、Docker Composeで動作させる予定なので、Dockerコンテナ側から見たマウント先となるホスト側のディレクトリを作成しておく。
Dockerの公式のドキュメントによると、
-
ボリューム(volume) は、 「Docker によって管理されている」ホストファイルシステム上の一部に保管します( Linux 上では
/var/lib/docker/volumes
)。 Docker 以外のプロセスは、このファイルシステム上の一部を変更すべきではありません。ボリュームは Docker 内のデータを保持するために一番良い方法です。 -
バインド マウント(bind mount) は、ホストシステム上の「どこにでも」保管できます。これには重要なシステムファイルやディレクトリも含みます。Docekr ホスト上の Docker 以外のプロセスも、 Docker コンテナも、常にデータを変更できます。
-
tmpfs マウント は、ホストシステムのメモリ上にのみ保管します。そして、ホストシステムのファイルシステムには一切書き込まれません。
⇧ Dockerコンテナのデータの保存先としては、3つの方法が用意されているようですが、データ永続化の観点で考えた場合、
- Dockerコンテナ再起動
- Dockerホスト再起動
のどちらも発生したケースにも対応し得るのは、
- ボリューム(volume)
- バインド マウント(bind mount)
のどちらかになると。
この2つの違いについては、
ファイルやディレクトリは Docker ホスト上にあらかじめ存在している必要はありません。存在しなければ、必要に応じて作成されます。
バインド マウントは高性能ですが、ホストマシンのファイルシステムで利用可能な、特定のディレクトリ構造に依存します。新しい Docker アプリケーションを開発する場合は、代わりに 名前付きボリューム の利用を検討してください。バインド マウントは Docker CLI コマンドを使って直接管理できません。
⇧ という説明なのだけど、
No | 項目 | 内容 | |
---|---|---|---|
和名 | 英名 | ||
1 | バインドマウント | bind mount | 初期リリース時から存在した |
2 | ボリューム | volume | 初期リリース時は存在しなかった |
⇧ という感じで、「2. ボリューム(volume)」は後発だけあって、機能が豊富らしい。
ちなみに、Docker Composeの設定には、
⇧ という感じで、記述の方法が2種類あるらしく、
⇧「create_host_path」の指定をしないと、Dockerコンテナ起動時にホスト側のディレクトリの作成がされないという事象が起こると。
「create_host_path」はというと、
⇧ マウントの型で「bind」を選択している場合の追加オプションということらしい。
話が脱線しましたが、
⇧ 上記の記事の時に発覚している「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」を確認すると、
■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箇所に全て集約している。
しかし、
⇧「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リポジトリが用意されているとは思いますが、今回は特に用意できていないので、
⇧ 公式の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あるかと思っていたのですが見当たらない。
どうやら、
⇧ というような、様々な理由が存在するようです。
今回のケースだと、要するに「Oxidized」側が用意してくれていないということらしい。
ちなみに、DockerイメージからDockerfileの作成できないのかについては、
⇧ リバースエンジニアリング的な扱いになるようなので、完全な実現はできないっぽい。
致し方無いので、
⇧ ベースイメージの「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の内容を元に、作成・編集する。
■/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」を参考にするしかない。
⇧ 各項目の設定の意味について説明がないものが多いので、正確な設定は難しいが...
■/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」の例を参考にするしかない。
⇧「Configuration.md」の「Advanced Configuration」には存在しなかった、「ip」が出てきたりと、設定の全量が分かり辛過ぎるのだが...
■/opt/app/oxidized/.config/oxidized/router.db
[対象機器のホスト名]:[対象機器のIPアドレス]:[model_mapのキー]:[対象機器のSSHユーザー]:[対象機器のSSHユーザーのパスワード]
⇧ 保存。
Oxidizedのmodelクラスを用意する
で、既存のmodelクラス以外を利用せざるを得ない場合は、
⇧ modelクラスを用意する必要がありますと。
「Oxidized」が用意しているmodelクラスの内、標準的なLinuxディストリビューションに対応しているらしい、
⇧「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としては、
⇧ 上記のページの説明だと、
- Output: File
- Output: Git
- Output: Git-Crypt
- Output: Http
- Output types
の5つの選択肢が用意されているようなのだけど、「2. Output: Git」を選んだ場合は、「Oxidized」の処理内で「Rugged」というライブラリを利用しているため、「Git」のローカルリポジトリが「bare repository」として生成され、「git commit」まで処理されますと。
つまり、「Git」のリモートリポジトリを用意しておく必要がありますと。
今回は、過去に作成していたGitHubのプライベートなGitリポジトリを利用することにします。
Oxidizedのconfigのoutputをgitにした際のデフォルトのリポジトリがbareでbranchがmasterな問題に対応する
で、ようやっと本題。
⇧ 上記で連携いただいた方法である
『事前に、「bare repository」をローカルに用意して、「main」ブランチにしておくことで、「master」ブランチで処理されてしまうのを回避できるか』
ですが、結論としては、期待通りの動きになりました。
では、以下、実際に行ったことを備忘録としてまとめておきます。
GitHub Appに紐付けたプライベートリポジトリだからなのか、
⇧ 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
⇧ とかすれば良いと。
ちなみに、
⇧「hook」で「git push」が実現できるらしいのだけど、残念なことに「proxy」に対応していないため、利用したくても利用できないという...
う~む、「proxy」に対応していないってのは、厳しいですな...
それにしても、公式のドキュメントの情報が散逸してるのと、そもそも情報が無いのとで、不毛な時間が際限なく浪費されていくからして、本当にドキュメントは整備して欲しいのよね...
毎度モヤモヤ感が半端ない…
今回はこのへんで。