まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:rpm

2024 年になってから yum(dnf) 関連のブログエントリばかり書いてる気がしますが、今回のテーマも yum(dnf) 関連です。

前回のブログでも書いたのですが、yum は指定したモジュールを「ダウンロードだけ実行する(インストールは行わない)」ことを指定するパラメータがあります:
"yum install xxxxx" でインストールされるモジュールをダウンロードだけする

yum はダウンロードした .rpm ファイルを一時フォルダに格納して、その .rpm ファイルを使ってローカルインストールを実行します。インストールは普通に rpm ツールを使って実行するだけなのですが、今回のブログテーマはその手前、「ダウンロード」する部分に着目します。

例えば以下のような場面に遭遇しているとします(あまり関係ないですが RHEL 8.8 で実行した内容です):
# yum install ansible
Updating Subscription Management repositories.
Last metadata expiration check: 2:22:50 ago on Tue 02 Jan 2024 05:03:04 AM UTC.
Dependencies resolved.
================================================================================
 Package  Arch    Version           Repository                             Size
================================================================================
Installing:
 ansible  noarch  2.9.27-1.el8ae    ansible-2-for-rhel-8-x86_64-rpms       17 M
Installing dependencies:
 sshpass  x86_64  1.09-4.el8        rhel-8-for-x86_64-appstream-eus-rpms   30 k

Transaction Summary
================================================================================
Install  2 Packages

Total download size: 17 M
Installed size: 96 M
Is this ok [y/N]:

コマンドラインからは "yum install ansible" と入力しました。"ansible" というモジュールをインストールしようとしています。 色々と調べた結果、"ansible" というツールに加えて、その実行条件となる "sshpass" というライブラリモジュールも(現在の環境には足りてないと判断されて)インストールしようとしている、という場面です。通常はここで "y" と入力してインストール開始、、という流れになると思っています。普通はこの画面にこれ以上着目する必要もないのですが、今回は(たまにはいい機会だと思うので)この画面をもう少し詳しく見てみます。

このピンク色の部分をよく見ると、以下のような挙動を行おうとしていることが分かります:
ansible-2-for-rhel-8-x86_64-rpms リポジトリから ansible-2.9.27-1.el8ae.noarch.rpm をダウンロード(約 17MB
rhel-8-for-x86_64-appstream-eus-rpms リポジトリから sshpass-1.09-4.el8.x86_64.rpm をダウンロード(約 30kB


ではこれらの2つのファイルは具体的にはどこからダウンロードされるのでしょう? その答を調べるにはリポジトリに登録されている情報を調べる必要があります。CentOS や RHEL の場合、"/etc/yum.repos.d/" 以下に ".repo" という拡張子を持つファイルが1つ以上あり、その中にリポジトリの情報が記述されています。

私の環境では "/etc/yum.repos.d/redhat.repo" というファイルが1つだけ存在していて、このファイルの中に全てのリポジトリの情報が含まれていました。その一部だけを紹介しますが、以下のような内容になっていました(一部伏字にしています):
  :
  :
[rhel-8-for-x86_64-baseos-rpms]
name = Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)
baseurl = https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/rhel8/8.8/x86_64/baseos/os
enabled = 1
gpgcheck = 1
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
sslverify = 1
sslcacert = /etc/rhsm/ca/katello-server-ca.pem
sslclientkey = /etc/pki/entitlement/xxxxxxxxxxxx-key.pem
sslclientcert = /etc/pki/entitlement/xxxxxxxxxxxx.pem
metadata_expire = 86400 enabled_metadata = 1 : : [rhel-8-for-x86_64-appstream-eus-rpms] name = Red Hat Enterprise Linux 8 for x86_64 - AppStream - Extended Update Support (RPMs) baseurl = https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/eus/rhel8/8.8/x86_64/appstream/os
enabled = 1 gpgcheck = 1 gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release sslverify = 1 sslcacert = /etc/rhsm/ca/katello-server-ca.pem sslclientkey = /etc/pki/entitlement/xxxxxxxxxxxx-key.pem
sslclientcert = /etc/pki/entitlement/xxxxxxxxxxxx.pem
metadata_expire = 86400 enabled_metadata = 1 : : [ansible-2-for-rhel-8-x86_64-rpms] name = Red Hat Ansible Engine 2 for RHEL 8 x86_64 (RPMs) baseurl = https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os
enabled = 1 gpgcheck = 1 gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release sslverify = 1 sslcacert = /etc/rhsm/ca/katello-server-ca.pem sslclientkey = /etc/pki/entitlement/xxxxxxxxxxxx-key.pem
sslclientcert = /etc/pki/entitlement/xxxxxxxxxxxx.pem
metadata_expire = 86400 enabled_metadata = 1 : :

ピンク色で記載しているのがリポジトリ名です。今回の処理でダウンロード元に指定されている2つのリポジトリがともに含まれていることがわかります(今回はリポジトリファイルが1つだけなので、1つのファイルを確認するだけで分かったのですが、複数のリポジトリファイルが存在している場合は全て調べないと分からない可能性があります)。

ではリポジトリファイルに記載されている情報を使って、目的の2つのファイルをダウンロードしてみます(単にダウンロードするだけなら前回のブログの応用で可能なのですが、今回は yum の仕組みを理解することを目的として wget を使ってダウンロードすることにします)。

では wget を使って2つのファイルをダウンロードしてみます。まずは ansible のファイルをダウンロードしてみます。

yum の実行結果やリポジトリファイルに書かれている情報から、ansible のファイルは ansible-2.9.27-1.el8ae.noarch.rpm というファイル名であることや、このファイルは(リポジトリの baseurl である)以下の文字列を含む URL からダウンロードされることがこの時点で推測できます:
https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/eus/rhel8/8.8/x86_64/appstream/os

では単純に https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/eus/rhel8/8.8/x86_64/appstream/os/ansible-2.9.27-1.el8ae.noarch.rpm という URL からダウンロードできるのでは? という予想もあると思いますが(現にそういう単純なパターンのケースもありますが)、ここはちゃんと調べてみましょう。ここからは wget を併用して調べてみます(手元の PC から直接接続できる URL であれば wget ではなくブラウザを使ってもいいのですが、以下の手順ではネットワークが繋がっていない可能性があることと、鍵ファイルも必要になることから wget を使うことにします。wget の方法で覚えておけば色んなケースに対応できてある意味安心です)。

まずはシンプルに baseurl の値から wget を実行してみます。一般的には baseurl の値に HTTP クライアントでアクセスするとファイルやフォルダの一覧(の HTML)が表示されるので、その画面から次にどの URL にアクセスすればよいか、を推測することができます。

というわけで wget で baseurl の値をヒントにアクセスしてみます:
# wget https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os
--2024-01-02 09:59:30--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 403 [('PEM routines', 'PEM_read_bio', 'no start line')]
2024-01-02 09:59:30 ERROR 403: [('PEM routines', 'PEM_read_bio', 'no start line')].

おっと、接続はできているのですが 403 エラーが出てしまいました。「権限がない」という意味ですが、これは??

この 403 エラーの原因はリポジトリに記述されていました。改めて ansible-2-for-rhel-8-x86_64-rpms リポジトリの内容を確認してみます:
  :
  :
[ansible-2-for-rhel-8-x86_64-rpms]
name = Red Hat Ansible Engine 2 for RHEL 8 x86_64 (RPMs)
baseurl = https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os
enabled = 1 gpgcheck = 1 gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release sslverify = 1 sslcacert = /etc/rhsm/ca/katello-server-ca.pem sslclientkey = /etc/pki/entitlement/xxxxxxxxxxxx-key.pem
sslclientcert = /etc/pki/entitlement/xxxxxxxxxxxx.pem

metadata_expire = 86400 enabled_metadata = 1 : :

よく見ると、この URL にアクセスするには SSL の証明書が必要という情報が書かれていました。この情報が抜けていてアクセスに失敗していたようです。sslcacert は CA 証明書、sslclientkey は秘密鍵、sslclientcert はクライアント証明書で、それぞれのファイルの位置がフルパスで記述されています。

そして wget では以下のオプションを指定することができます:
 ・CA証明書: "--ca-certificate=(ファイルパス)"
 ・秘密鍵: "--private-key=(ファイルパス)"
 ・クライアント証明書: "--certificate=(ファイルパス)"

これらの情報を使い、CA 証明書、秘密鍵、クライアント証明書をそれぞれ指定するオプションを追加して再度先ほどのコマンドを実行してみます:
# wget --ca-certificate=/etc/rhsm/ca/katello-server-ca.pem --private-key=/etc/pki/entitlement/xxxxxxxxxxxx-key.pem --certificate=/etc/pki/entitlement/xxxxxxxxxxxx.pem https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os
--2024-01-02 10:19:58--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/
Loaded CA certificate '/etc/rhsm/ca/katello-server-ca.pem'
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 407 [text/html]
Saving to: ‘index.html’

index.html          100%[===================>]     407  --.-KB/s    in 0s

2024-01-02 10:19:58 (29.8 MB/s) - ‘index.html’ saved [407/407]

今度は成功したようです。wget は text/html のウェブページに対して(ファイル名がないような URL で)実行すると、結果を "index.html" というファイルに保存してくれます。今回も成功して "index.html" というファイルができていたので、その内容を確認すると以下のように記載されていました:
        <!DOCTYPE html>
        <html>
            <body>
                <ul>

                    <li><a href="Packages/">Packages/</a></li>

                    <li><a href="config.repo">config.repo</a></li>

                    <li><a href="repodata/">repodata/</a></li>

                </ul>
            </body>
        </html>

3つのパスへのリンクが含まれる HTML になっていました。一般的にインストールファイルは "Packages/" フォルダ以下にあるので、今度はさっきの URL の後ろに "Packages/" を足して実行してみます:
# wget --ca-certificate=/etc/rhsm/ca/katello-server-ca.pem --private-key=/etc/pki/entitlement/xxxxxxxxxxxx-key.pem --certificate=/etc/pki/entitlement/xxxxxxxxxxxx.pem https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/
--2024-01-02 10:19:58--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/
Loaded CA certificate '/etc/rhsm/ca/katello-server-ca.pem'
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 295 [text/html]
Saving to: ‘index.html.1’

index.html.1        100%[===================>]     295  --.-KB/s    in 0s

2024-01-02 10:34:15 (8.24 MB/s) - ‘index.html.1’ saved [295/295]

今度は "index.html.1" というファイルに結果が保存されたようです。このファイルを確認します:
        <!DOCTYPE html>
        <html>
            <body>
                <ul>

                    <li><a href="a/">a/</a></li>

                    <li><a href="s/">s/</a></li>

                </ul>
            </body>
        </html>

ダウンロードされる .rpm ファイルは "Packages/" フォルダ直下に用意されているケースもありますが、多くの場合(ファイルが多いこともあってか)ファイル名の頭文字がついたサブフォルダの下に用意されているケースが多いです。今回のそのようでこの "Packages/" フォルダには "a/" と "s/" というサブフォルダが用意されていました。今回の目的のファイル名は "ansible-2.9.27-1.el8ae.noarch.rpm" だったので、おそらく "a/" サブフォルダの中に保存されている可能性が高いと推測できます。

というわけで再度、今度は URL の最後に更に "a/" を付けて wget を再実行してみます:
# wget --ca-certificate=/etc/rhsm/ca/katello-server-ca.pem --private-key=/etc/pki/entitlement/xxxxxxxxxxxx-key.pem --certificate=/etc/pki/entitlement/xxxxxxxxxxxx.pem https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/a/
--2024-01-02 10:19:58--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/a/
Loaded CA certificate '/etc/rhsm/ca/katello-server-ca.pem'
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7647 (7.5K) [text/html]
Saving to: ‘index.html.2’

index.html.2        100%[===================>]   7.47K  --.-KB/s    in 0s

2024-01-02 10:43:45 (293 MB/s) - ‘index.html.2’ saved [7647/7647]

今度は "index.html.2" というファイルに結果が保存されたようです。このファイルを確認します:
        <!DOCTYPE html>
        <html>
            <body>
                <ul>

                    <li><a href="ansible-2.8.0-1.el8ae.noarch.rpm">ansible-2.8.0-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.8.1-1.el8ae.noarch.rpm">ansible-2.8.1-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.8.2-1.el8ae.noarch.rpm">ansible-2.8.2-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.8.3-1.el8ae.noarch.rpm">ansible-2.8.3-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.8.4-1.el8ae.noarch.rpm">ansible-2.8.4-1.el8ae.noarch.rpm</a></li>

                        :
                        :

                    <li><a href="ansible-2.9.26-1.el8ae.noarch.rpm">ansible-2.9.26-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.9.27-1.el8ae.noarch.rpm">ansible-2.9.27-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-2.9.4-1.el8ae.noarch.rpm">ansible-2.9.4-1.el8ae.noarch.rpm</a></li>

                        :
                        :

                    <li><a href="ansible-test-2.9.5-1.el8ae.noarch.rpm">ansible-test-2.9.5-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-test-2.9.6-1.el8ae.noarch.rpm">ansible-test-2.9.6-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-test-2.9.7-1.el8ae.noarch.rpm">ansible-test-2.9.7-1.el8ae.noarch.rpm</a></li>

                    <li><a href="ansible-test-2.9.9-1.el8ae.noarch.rpm">ansible-test-2.9.9-1.el8ae.noarch.rpm</a></li>

                </ul>
            </body>
        </html>

"ansible-2.9.27-1.el8ae.noarch.rpm" 、やっと見つかりました!このフォルダの下にあったんですね。

というわけで最後に "ansible-2.9.27-1.el8ae.noarch.rpm" を URL の最後に追加して wget を実行します:
# wget --ca-certificate=/etc/rhsm/ca/katello-server-ca.pem --private-key=/etc/pki/entitlement/xxxxxxxxxxxx-key.pem --certificate=/etc/pki/entitlement/xxxxxxxxxxxx.pem https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/a/ansible-2.9.27-1.el8ae.noarch.rpm
--2024-01-02 10:19:58--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/dist/layered/rhel8/x86_64/ansible/2/os/Packages/a/ansible-2.9.27-1.el8ae.noarch.rpm
Loaded CA certificate '/etc/rhsm/ca/katello-server-ca.pem'
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17705052 (17M) [application/octet-stream]
Saving to: ‘ansible-2.9.27-1.el8ae.noarch.rpm’

ansible-2.9.27-1.el 100%[===================>]  16.88M  --.-KB/s    in 0.06s

2024-01-02 10:53:08 (270 MB/s) - ‘ansible-2.9.27-1.el8ae.noarch.rpm’ saved [17705052/17705052]

長い道のりを経て、やっと "ansible-2.9.27-1.el8ae.noarch.rpm" がダウンロードできました!

もう1つのファイル "sshpass-1.09-4.el8.x86_64.rpm" も同様にして "rhel-8-for-x86_64-appstream-eus-rpms" リポジトリからダウンロードできます:
# wget --ca-certificate=/etc/rhsm/ca/katello-server-ca.pem --private-key=/etc/pki/entitlement/xxxxxxxxxxxx-key.pem --certificate=/etc/pki/entitlement/xxxxxxxxxxxx.pem https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/eus/rhel8/8.8/x86_64/appstream/os/Packages/s/sshpass-1.09-4.el8.x86_64.rpm
--2024-01-02 10:19:58--  https://rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com/pulp/repos/customer/Library/content/eus/rhel8/8.8/x86_64/appstream/os/Packages/s/sshpass-1.09-4.el8.x86_64.rpm
Loaded CA certificate '/etc/rhsm/ca/katello-server-ca.pem'
Resolving rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)... 161.xx.xx.xx
Connecting to rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com (rhha02.updates.jp-tok.iaas.service.xxxxxxxxxx.com)|161.xx.xx.xx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 30568 (30K) [application/octet-stream]
Saving to: ‘sshpass-1.09-4.el8.x86_64.rpm’

sshpass-1.09-4.el8. 100%[===================>]  29.85K  --.-KB/s    in 0s

2024-01-02 11:07:37 (185 MB/s) - ‘sshpass-1.09-4.el8.x86_64.rpm’ saved [30568/30568]

まとめると、、
・yum コマンドの実行結果にリポジトリの情報が含まれている
・/etc/yum.repos.d/ 以下にリポジトリの URL や鍵に関する情報が含まれている
・これらの情報を組み合わせつつ、wget でフォルダ階層を調べながら目的ファイルの URL を調べていくことでファイルのダウンロードも可能

となります。

Ubuntu の標準形式でありながら、CentOS や RHEL(RedHat Enterprise Linux) ではそのままでは扱えない deb パッケージを rpm パッケージに変換する方法があります。

具体的には alien コマンドを利用します。 まずこの alien コマンドを CentOS や RHEL 環境上でビルドします:
# yum install rpm-build
# cd /tmp
# wget http://ftp.debian.org/debian/pool/main/a/alien/alien_8.92.tar.gz
# rpmbuild -ta alien_8.92.tar.gz
  :
  :
書き込み完了: /root/rpmbuild/RPMS/noarch/alien-8.92-1.noarch.rpm
  :
  :
# rpm -ivh /root/rpmbuild/RPMS/noarch/alien-8.92-1.noarch.rpm

ここまでの作業で alien コマンドがインストールできているので、このコマンドを使って deb パッケージを rpm パッケージへ変換します:
# alien --to-rpm --scripts xxx.deb
xxx.rpm generated

こうして出来上がった rpm ファイルは rpm コマンドや yum コマンドで導入可能です。
 

このページのトップヘ