Red Hat環境のローカルリポジトリを構築する

# 今回やりたいこと
Red Hat Enterprise Linux（RHEL）公式リポジトリのRPMパッケージをローカル環境にミラーリングし、HTTPサーバ（Apache）で公開します。
さらに、`systemd timer`を用いて定期的にリポジトリを自動同期させる仕組みを構築し、ネットワーク帯域の節約や安定したパッケージ配布環境を実現します。
これにより、社内ネットワーク環境で高速かつ安定したソフトウェアインストール・アップデートが可能となります。

# 構成図
Under Construction

# 手順
## 1.マネージャ側設定
### 1.1 必要パッケージのインストール
ローカルリポジトリをHTTPで公開するため、以下のパッケージをインストールします。
* `httpd`：Apache HTTPサーバー
* `yum-utils`：`reposync`等のユーティリティを提供
```bash
sudo dnf install httpd yum-utils -y
```
:::note info
yum-utilsがすでにインストール済みの場合、該当パッケージはスキップされます。
:::

### 1.2 Apacheサービスの起動と自動起動設定
Apacheサービスを起動し、システム起動時に自動起動するよう設定します。
```bash
sudo systemctl enable --now httpd
```

### 1.3 リポジトリ用ディレクトリの作成
RPMパッケージを格納する公開ディレクトリを作成します。
ここでは、`BaseOS`と`AppStream`の2セクションに分けて管理します。
```bash
sudo mkdir -p /var/www/html/repo/BaseOS
sudo mkdir -p /var/www/html/repo/AppStream
```

### 1.4 reposync を用いたパッケージ同期
次に、既存の Red Hat オフィシャルリポジトリから必要な RPM パッケージをローカル環境にダウンロードします。
`reposync`コマンドを利用することで、対象リポジトリのパッケージおよびメタデータ（repodata）を指定ディレクトリに取得し、ネットワークに依存しないローカルリポジトリを構築する準備が整います。

ここでは `rhel-9-for-x86_64-baseos-rpms` および `rhel-9-for-x86_64-appstream-rpms` の2つのリポジトリに対して同期を実行します。
また、`--norepopath` オプションにより、指定パス直下（ここでは`var/www/html/repo/BaseOS`と`var/www/html/repo/Appstream`）にパッケージを展開し、構造をシンプルに保っています。
```bash
# BaseOS
sudo reposync --gpgcheck --repo=rhel-9-for-x86_64-baseos-rpms \
  --download-path=/var/www/html/repo/BaseOS \
  --download-metadata --norepopath

# AppStream
sudo reposync --gpgcheck --repo=rhel-9-for-x86_64-appstream-rpms \
  --download-path=/var/www/html/repo/AppStream \
  --download-metadata --norepopath
```
:::note info
リポジトリ名（ここでは`rhel-9-for-x86_64-baseos-rpms`と`rhel-9-for-x86_64-appstream-rpms`）は`/etc/yum.repos.d/redhat.repo`内のセクション名と一致している必要があります。
事前に `dnf repolist` で正しい名称を確認しておきましょう。
:::
:::note info
`reposync`コマンドが `--download-metadata`オプション付きで実行するため、`createrepo`コマンドによるメタデータ作成は不要です。
:::

### 1.5 動作確認
以下URLにWebブラウザでアクセスし、RPMファイルが表示されればApacheの公開が成功しています。
```perl
http://<マネージャIP>/repo/BaseOS/
```
表示例：
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/b95d568f-e609-4453-95b0-e99948f9952b.png)


## 2.クライアント側設定
### 2.1 既存リポジトリの無効化（任意）
Red Hatの公式リポジトリを一時的に無効化することで、ローカルリポジトリのみを参照させることができます。
```bash
sudo sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/*.repo
```

### 2.2 .repoファイルの作成
ローカルリポジトリを参照する設定ファイル /etc/yum.repos.d/local.repo を作成します。
```bash
sudo vi /etc/yum.repos.d/local.repo
```
以下内容を記述します：
```ini
[local-BaseOS]
name=Local BaseOS
baseurl=http://<マネージャのIP>/repo/BaseOS/
enabled=1
gpgcheck=0

[local-AppStream]
name=Local AppStream
baseurl=http://<マネージャのIP>/repo/AppStream/
enabled=1
gpgcheck=0
```

| パラメータ | 説明 |
|:-:|:-:|
| [local-repo]  | リポジトリID（任意の一意名）。コマンドで`--repo=local-repo`と指定する場合などに使用されます。  |
| name=  | ユーザーが分かりやすいよう表示されるリポジトリの名前。自由に記述可能です。 |
| baseurl= | リポジトリのベースURL。構築済みのHTTPサーバ上に公開されたパスを指定します。例: http://192.168.0.100/repo/ |
| enabled=1 | このリポジトリを有効にするかどうか（1 で有効、0 で無効）。 |
| gpgcheck=0 | パッケージのGPG署名チェックを行うかどうか。検証が不要な場合は 0 に設定（オフ）。**本番環境では 1 にし、gpgkey= の指定を推奨。**  |

### 2.3 リポジトリ認識の確認
以下のコマンドを実行し、ローカルリポジトリが認識されていることを確認します。
```bash
dnf repolist
```

```:実行結果
[cloud-user@rhel-cl ~]$ dnf repolist
Failed to set locale, defaulting to C.UTF-8
Not root, Subscription Management repositories not updated
repo id                                                                  repo name
local-AppStream                                                          Local AppStream
local-BaseOS                                                             Local BaseOS
```

### 2.4 パッケージインストールの確認
ローカルリポジトリ経由でのインストール確認として、Apache HTTP Serverのインストールを試行します。
```bash
sudo dnf install httpd
```

依存関係を含むパッケージが正しく取得・インストールできれば設定完了です。

## 3.Red Hatリポジトリとの定期同期（マネージャ側）
ここでは`systemd timer`を利用して Red Hat の公式リポジトリと定期的に同期を行う仕組みを構築します。
これにより、ローカルミラーを自動で最新状態に保つことが可能になります。

### 3.1 スクリプトを作成
以下の内容で同期スクリプトを作成します。
スクリプトは`/usr/local/bin/reposync-rhel.sh`に配置し、必要に応じて編集可能とします。
```bash
#!/bin/bash
# Red Hat リポジトリ同期スクリプト
REPO_BASE_PATH="/var/www/html/repo"
LOG_FILE="/var/log/reposync.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

# 同期対象リポジトリ一覧
REPOS=(
  rhel-9-for-x86_64-baseos-rpms
  rhel-9-for-x86_64-appstream-rpms
)

mkdir -p "$REPO_BASE_PATH"

echo "[$DATE] Start reposync" >> "$LOG_FILE"

for repo in "${REPOS[@]}"; do
  echo "Syncing $repo..." >> "$LOG_FILE"
  reposync \
    --repo="$repo" \
    --download-path="$REPO_BASE_PATH/$repo" \
    --download-metadata \
    --norepopath \
    --gpgcheck >> "$LOG_FILE" 2>&1
done

echo "[$DATE] End reposync" >> "$LOG_FILE"
```

作成後、スクリプトに実行権限を付与します。
```bash
chmod +x /usr/local/bin/reposync-rhel.sh
```

### 3.2 systemd サービスユニット作成
上記スクリプトを`systemd`から実行可能とするため、サービスユニットを作成します。
ファイル：`/etc/systemd/system/reposync.service`
```ini
[Unit]
Description=Red Hat Repository Sync Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/reposync-rhel.sh
```
| パラメータ | 説明 |
|:-:|:-:|
| `[Unit]`  | ユニットのメタデータや依存関係を定義するセクション  |
| `Description` | サービスの説明。systemctl コマンド等で確認できる簡単な概要を指定 |
| `[Service]` | サービスの起動方法や挙動を定義するセクション |
| `Type=oneshot` | スクリプトなどの一度限りの処理に使用。プロセスがすぐに終了することを想定 |
| `ExecStart=/usr/local/bin/reposync-rhel.sh` | サービス起動時に実行するコマンド（同期スクリプトのパス）  |

### 3.3 systemd タイマーユニット作成
毎日定期的に同期処理を実行するため、タイマーユニットを作成します。
ファイル：`/etc/systemd/system/reposync.timer`
```ini
[Unit]
Description=Run Red Hat reposync daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
```
| パラメータ | 説明 |
|:-:|:-:|
| `[Unit]`  | タイマーのメタデータや依存関係を定義するセクション  |
| `Description` | タイマーの説明。systemctl list-timers 等で確認可能な概要 |
| `[Timer]` | タイマーのスケジュール設定などを定義するセクション |
| `OnCalendar=daily` | タイマーの実行間隔を指定。daily は毎日午前0時を意味する |
| `Persistent=true` | 前回の実行がスキップされた場合でも、次回起動時に補完的に実行されるようにする  |
| `[Install]` | ユニットの有効化時のターゲットとの関連付け設定 |
| `WantedBy=timers.target` | enable時に`timers.target`に紐づけることで、自動起動対象に登録される |


### 3.4 タイマーの有効化と起動
以下のコマンドを実行し、`systemd`にユニットを読み込ませた上で、タイマーを有効化・即時起動します。
```bash
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable --now reposync.timer
```

### 3.5 タイマーの動作確認
設定されたタイマーが有効であるか、次回実行時刻を以下のコマンドで確認します。
```bash
systemctl list-timers --all | grep reposync
```

```:出力例
Mon 2025-05-26 00:00:00 JST 6h left    -                           -           reposync.timer               reposync.service
```
この出力から、`reposync.timer`が午前0時に実行予定であることが確認できます。

希望に応じて、タイマーの実行時刻（`OnCalendar=daily`）を変更することも可能です。
例えば毎日午前3時に実行したい場合は `OnCalendar=03:00` に変更してください。

# 注意点
**Red Hatサブスクリプションの有効性**
ミラー対象のリポジトリは有効なRed Hatサブスクリプションが設定された環境でのみ利用可能です。サブスクリプションが切れていると同期に失敗します。

**リポジトリ名の正確な指定**
`reposync`コマンドの`--repo`オプションに指定するリポジトリIDは、`/etc/yum.repos.d/redhat.repo`に記載されている名称と一致している必要があります。
`dnf repolist`コマンドで事前に確認してください。

**パーミッションとSELinux設定**
Apacheが公開ディレクトリへアクセスできるよう、ファイル・ディレクトリの権限やSELinuxコンテキストを適切に設定してください。
権限不足によりHTTPアクセスが拒否される場合があります。

**GPGチェック設定**
クライアント側の`.repo`ファイルで`gpgcheck=0`としている場合は署名検証を行いません。
本番環境では`gpgcheck=1`にしてGPGキーを設定し、パッケージの信頼性を確保してください。

**ディスク容量の確保**
ミラーリングするパッケージ数が多いため、マネージャ側のサーバは最低でも**150GB〜以上**の十分なディスク容量を用意してください。
同期が失敗する要因になります。

**systemdタイマーの時刻設定**
タイマーの実行時刻は環境に応じて適切に設定してください。
ネットワーク負荷やサーバ負荷が高い時間帯を避けるのが望ましいです。