AnsibleでNexus 3 OSSをOrange Pi 5にデプロイする方法:ステップバイステップ完全ガイド
Nexus 3 OSSは、コンテナイメージ、Python PIP、Java JARなど、多様なフォーマットに対応したオープンソースのアーティファクトリポジトリマネージャーです。
そもそも、なぜオンプレミスでアーティファクトマネージャーを運用する必要があるのでしょうか?主な理由は以下のとおりです。
プライベートインフラの活用: 機密性の高い独自コードを、自社の管理下にあるインフラストラクチャ内で安全に保護できます。
高速なアーティファクトダウンロード: 同じアーティファクトを何度もインターネットから取得するのではなく、中央のロケーションにキャッシュすることで、複数サーバー上の多くのユーザーがその恩恵を受けられます。
ビルドチェーンへの流入制御: アーティファクトを一元管理することで、使用が承認されたものだけを利用し、悪意のあるコードが混入していないことを確認できます。
アクセス権限の分離: 組織内の特定のアーティファクトに対して、より厳格なアクセス要件を設定できます。
本記事では、Ansibleプレイブックを使用してNexus 3 OSS版をダウンロード、インストール、構成する方法を解説します。
Nexus 3はRAM 8GB搭載のOrange Pi 5上で動作させますが、このプロビジョニングは最小要件を満たす任意のマシンで実行可能です。セットアップの一環として、インベントリファイルに記載したマシン群向けにPyPI.orgのプロキシも設定します。
本チュートリアルを実行するために必要なもの
Ansibleプレイブック、Nexus、PIPモジュールのソースコードをダウンロードするためのインターネット接続
RAM 8GB以上を搭載したLinuxマシン2台以上(筆者はDebian、Armbian、Fedora IoTを使用)。筆者のクラスタはRaspberry Pi 4とOrange Pi 5の混在構成です。
AnsibleコントローラーはFedoraマシン上で動作させますが、どのサーバーでもコントローラーになれます。Ansibleのインストール手順は公式ドキュメントにわかりやすくまとめられています。
プレイブックの構成
タスクをグループごとに整理すると、最終的なプレイブックの構成は以下のようになります。
[josevnz@dmaf5 Nexus3OnOrangePI]$ tree -N ansible/
ansible/
├── inventories
│ └── home
│ └── hosts.yaml
├── roles
│ ├── clients
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ └── pip.conf.j2
│ └── nexus
│ ├── files
│ │ └── swagger.json
│ ├── tasks
│ │ ├── download.yaml
│ │ ├── install.yaml
│ │ ├── main.yaml
│ │ ├── post_install.yaml
│ │ ├── pre_install.yaml
│ │ ├── repositories.yaml
│ │ ├── third_party.yaml
│ │ └── user.yaml
│ └── templates
│ ├── logrotate.nexus3.j2
│ ├── nexus3.service.j2
│ ├── nexus.rc.j2
│ └── nexus.vmoptions.j2
├── site.yaml
├── vars
│ ├── clients.yaml
│ └── nexus.yaml
└── vault
├── nexus_password.enc
└── README.md
13 directories, 21 files
それぞれの要素について簡単に説明します。
ロールは「nexus」と「clients」の2つです。nexusロールはアーティファクト管理ソフトウェアのセットアップを担当し、clientsロールは各マシンのpip設定を行います。
varsディレクトリには各ロールで使用される変数を格納しています。ファイル単位で分割することで、用途が明確になります。
パスワードはAnsible Vault機能で管理しています。
「site.yaml」が各ロールの実行を統括します。
- hosts: all
tags: clients
vars_files:
- vars/clients.yaml
roles:
- clients
- hosts: nexus_server
tags: nexus
become_user: root
become: true
vars_files:
- vars/nexus.yaml
roles:
- nexus
それでは、プレイブックが実行される環境を見ていきましょう。
ホストインベントリ
筆者の場合は非常にシンプルで、「clients」というグループと、Nexus 3サーバー本体が稼働するマシンのグループの2つに分かれています。
all:
children:
nexus_server:
hosts:
orangepi5.home:
home_lab:
hosts:
dmaf5.home:
raspberrypi.home:
orangepi5.home:
次の重要なタスクは、Nexus 3のダウンロードと構成です。
Nexus 3のインストール方法
main.yamlには、nexusロールにおける各インストールタスクの順序と目的が記述されています。
# Tasks listed here are related to the remote Nexus 3 server
# Included tasks are called in order
---
- include_tasks: third_party.yaml
- include_tasks: pre_install.yaml
- include_tasks: download.yaml
- include_tasks: install.yaml
- include_tasks: post_install.yaml
- include_tasks: user.yaml
- include_tasks: repositories.yaml
まず、「コアタスク」と呼べる部分から見ていきましょう。
third_party.yaml: OpenJDK 8(Nexus 3はJavaで書かれています)と、古くなったログを処理するためのlogrotateをインストールします。
pre_install.yaml: ここでは多くの処理が行われます。具体的には、Nexus用の必須ディレクトリの作成や、プロセスを実行するための非特権専用ユーザーの作成などです。
download.yaml: 名前のとおり、最新版のNexus 3 OSSソフトウェアを取得し、チェックサムが正しいことを確認します。インターネットからマルウェアをインストールしてしまわないためです。
続いて、「カスタムインストールグループ」に属するタスクです。
install.yaml: ソフトウェアを展開し、自動起動のためのsystemdユニットを準備し、Nexus用のJVM設定を行い、logrotateの構成を配置します。
post_install.yaml: ここからが本番です。ソフトウェアのインストールが完了し、初回起動を行います。また、REST API経由でデフォルトパスワードを変更し、カスタマイズ段階へ進めるようにします。
user.yaml: エンドユーザーがNexusの提供するサービスへ適切にアクセスできるよう準備します。これはREST APIとAnsibleクライアントコードの組み合わせで実現します。
# https://help.sonatype.com/repomanager3/installation-and-upgrades/post-install-checklist
# https://help.sonatype.com/repomanager3/integrations/rest-and-integration-api
---
- name: Enable anonymous user
tags: anonymous
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/security/anonymous"
method: PUT
body_format: raw
status_code: [ 200, 202, 204 ]
headers:
Content-Type: application/json
body: |-
{ "enabled" : true, "userId" : "anonymous", "realmName" : "NexusAuthorizingRealm" }
force_basic_auth: true
return_content: true
any_errors_fatal: true
- name: Enable Docker security realm
tags: docker_realm
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/security/realms/active"
method: PUT
body_format: raw
status_code: [ 200, 202, 204 ]
headers:
Content-Type: application/json
body: |-
[ "NexusAuthenticatingRealm", "NexusAuthorizingRealm", "DockerToken" ]
force_basic_auth: true
return_content: true
any_errors_fatal: true
ロジックは非常にシンプルです。「PUT」というHTTPメソッドを使うことで、既存のロールやユーザーに対する変更操作であることを示せます。エラー検出は、Nexusが返すHTTPステータスコードによって行います。
次のステップは、ローカルPyPIプロキシの準備です。これは複数段階のタスクであり、後ほど詳しく説明します。
Nexus 3でのPyPIプロキシ設定方法
nexusロールの最後のファイルが「repositories.yaml」です。ここでは以下の手順を踏みます。
プロキシがすでに設定済みかどうかを確認する(GET=読み取り専用操作)
存在しない場合は新規作成する(POSTメソッドでJSONペイロードにより新しいリポジトリ全体を作成)
なお、このプレイブックにはリポジトリ設定を更新するオプションは用意されていません。REST APIを使えば実現可能ですが、ここでは読者への課題として残しておきます。
PyPIプロキシを準備するタスクは以下のとおりです。
# Create proxy for repositories
# https://help.sonatype.com/repomanager3/integrations/rest-and-integration-api
# PyPi: https://pip.pypa.io/en/stable/user_guide/
---
- name: Check if the PyPi proxy exists
tags: pypi_proxy_exists
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/repositories/pypi/proxy/python_proxy"
method: GET
body_format: raw
status_code: [ 200, 202, 204, 404 ]
headers:
Content-Type: application/json
force_basic_auth: true
return_content: true
any_errors_fatal: true
register: python_local
- name: Create PyPI proxy
tags: pypi_proxy_create
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/repositories/pypi/proxy"
method: POST
body_format: raw
status_code: [ 201 ]
headers:
Content-Type: application/json
body: |-
{
"name": "python_proxy",
"online": true,
"storage": {
"blobStoreName": "default",
"strictContentTypeValidation": true
},
"proxy": {
"remoteUrl": "https://pypi.org/",
"contentMaxAge": -1,
"metadataMaxAge": 1440
},
"negativeCache": {
"enabled": true,
"timeToLive": 1440
},
"httpClient": {
"blocked": false,
"autoBlock": true,
"connection": {
"retries": 0,
"timeout": 60,
"enableCircularRedirects": false,
"enableCookies": true,
"useTrustStore": false
}
}
}
force_basic_auth: true
return_content: true
any_errors_fatal: true
when: python_local.status == 404
もう少しで完成です。あとは、Pythonライブラリの取得先として直接PyPIサイトではなく、ローカルのNexusを使うようクライアントに伝える必要があります。
クライアント側の設定方法
clientsロールははるかにシンプルで、pip.confのテンプレートを配置するだけで済みます。このテンプレートには、新しいリポジトリを検索対象にするための十分な情報が含まれています。
# Tasks here are meant to be used on our clients user
---
- name: Create installation directory for pip.conf
tags: pip_basedir
ansible.builtin.file:
state: directory
path: ""
owner: ""
group: ""
mode: "u+rwx,go-rwx"
- name: Copy pip.conf file
tags: pip_copy
ansible.builtin.template:
src: pip.conf.j2
dest: "/pip.conf"
owner: ""
group: ""
mode: u=rxw,g=r,o=r
生成されたファイルは、各マシンの「~/.config/pip/pip.conf」に配置されます。
# https://pip.pypa.io/en/stable/topics/configuration/
[global]
timeout = 60
[install]
index = https://orangepi5.home:8081/repository/python_proxy/pypi
index-url = https://orangepi5.home:8081/repository/python_proxy/simple/
trusted-host = orangepi5.home
上記は、筆者のクラスタにデプロイされた最終的なファイルの例です(URLが解決された状態)。あなたの環境ではURLが異なるはずです。
それでは、プレイブック全体を実行して結果を確認してみましょう。
プレイブックの実行方法
プレイブックを実行する際は、いくつかの引数を渡します。
ホストインベントリの場所
暗号化されたパスワードファイルの場所と、保護されたファイルの内容を解除するためのマスターパスワードを含むファイルの場所
そして最後に、メインのプレイブックファイルの場所
cd ansible
ansible-playbook --inventory inventories --extra-vars @vault/nexus_password.enc --vault-password-file $HOME/vault/ansible_vault_pass site.yaml

新しいPyPIプロキシのテスト方法
新しいプロキシをテストするために、pipと仮想環境を使ってPythonのRichライブラリをインストールしてみます。
josevnz@orangepi5:~$ python3 -m venv ~/virtualenv/rich
(rich) josevnz@orangepi5:~$ . ~/virtualenv/rich/bin/activate
(rich) josevnz@orangepi5:~$ pip install rich
Looking in indexes: https://orangepi5.home:8081/repository/python_proxy/simple/
Collecting rich
Downloading https://orangepi5.home:8081/repository/python_proxy/packages/rich/13.3.4/rich-13.3.4-py3-none-any.whl (238 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 238.7/238.7 KB 14.8 MB/s eta 0:00:00
Collecting pygments<3.0.0,>=2.13.0
Downloading https://orangepi5.home:8081/repository/python_proxy/packages/pygments/2.15.0/Pygments-2.15.0-py3-none-any.whl (1.1 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.1/1.1 MB 23.8 MB/s eta 0:00:00
Collecting markdown-it-py<3.0.0,>=2.2.0
Downloading https://orangepi5.home:8081/repository/python_proxy/packages/markdown-it-py/2.2.0/markdown_it_py-2.2.0-py3-none-any.whl (84 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 84.5/84.5 KB 6.9 MB/s eta 0:00:00
Collecting mdurl~=0.1
Downloading https://orangepi5.home:8081/repository/python_proxy/packages/mdurl/0.1.2/mdurl-0.1.2-py3-none-any.whl (10.0 kB)
Installing collected packages: pygments, mdurl, markdown-it-py, rich
Successfully installed markdown-it-py-2.2.0 mdurl-0.1.2 pygments-2.15.0 rich-13.3.4
その後、新しいリポジトリにアーティファクトが登録されていることを確認すれば、キャッシュが実際に使われたことがわかります。

PyPIアーティファクトの確認画面
次に、別のパッケージをインストールするクライアントの動作デモを見てみましょう。

REST APIによるさらなるカスタマイズ
すべてのNexusインストール環境では、サーバーがサポートするAPIを記述したJSONファイルをダウンロードできます。たとえば筆者のorangepi5.homeサーバーからは、以下のようにしてコピーを取得できます。
curl --fail --remote-name https://orangepi5.home:8081/service/rest/swagger.json
また、UIからも他のREST APIエンドポイントを試しながら、インストール環境をカスタマイズできます。

REST APIのテスト画面
まとめ
このツールが提供する機能に慣れるために、時間をかけてNexus 3の公式ドキュメント(ブック)を読むことをおすすめします。
Ansibleではなくパッケージベースのセットアップが必要な場合のために、コミュニティがDebianおよびRPMインストーラーを用意しています。
Nexus 3には非常に多くの設定項目があります。本記事で取り上げたのはその表面だけです。執筆中に、非常に充実していて最新の状態に保たれた「ThoTeam Nexus3-ossリポジトリ」のプレイブックを見つけましたが、筆者のホームラボにとっては必要以上に複雑でした。
Archivaももうひとつのオープンソースアーティファクトマネージャーです。機能面では限定的ですが、そのぶんセットアップはより簡単です。
また、ポストインストールチェックリストには、筆者のホームラボでは不要だったタスクもいくつか含まれています。自分のセットアップが完全であることを確認するために、ぜひ一度目を通しておきましょう。
-
macOS Sierraの「パージ可能」領域とは?ストレージ最適化の仕組みと活用方法を徹底解説
ハードウェア業界の「大きいほど良い」というトレンドに皮肉にも反して、Macのハードドライブ容量はここ数年で最も小さくなっています。高価なSSDの採用により、新型Macの基本ストレージ容量はわずか128GBにとどまっています。そんな中、macOS Sierraにはハードドライブの空き容量を最適化するための新機能セットが搭載されました。 ストレージを最適化する際、OSはユーザーのハードドライブの中身を解析し、ファイルを「パージ可能(消去可能)」とそれ以外の2つに分類します。 「パージ可能」とは何を意味するのか? 「パージ可能(Purgeable)」とは、macOSが必要に応じて削除しても問題ない
-
Macの「メール」で不在時の自動返信メッセージを設定する方法
会社のメールアカウントを使っている方なら、休暇や出張中に相手へ自動的に知らせられる「不在通知」機能が用意されていることが多いでしょう。しかし、個人で使っているMacではどうすればよいのでしょうか?自宅のMacでメールの自動返信を設定したいと思ったことはありませんか? 実は、macOS標準の「メール」アプリには、企業のメールシステムのような自動返信を有効にする設定項目が存在しません。iCloudにも同様の設定は用意されていません(Appleさん、ぜひ対応をお願いします)。この問題を回避する唯一の方法が、「メール」アプリの「ルール」機能を使って自動返信を実現することです。この記事では、その具体的な