前回のLinux Emulatorを動かすに続き、もう少し踏み込んで設定します。
そもそも、Linux Emulator環境を本格的に使う場合、FreeBSDの公式パッケージで提供されているパッケージだけでは足りません。必要なソフトをコンパイルしてインストールするなど追加の手間がかかります。
そこで、パッケージの管理をRHEL系標準のdnfで行うようにし、必要なパッケージはRockyLinux公式からインストールできるようにします。
これで、より多くのパッケージが手軽に使えるようになり、Linux Emulator環境を本格的に使えるようになります。
前提
- FreeBSD 15 amd64
- RockRockyLinux 9.7(RHEL 9.7互換)
- ベースパッケージだけFreeBSD公式のlinux_base-rl9を使い、ほかのパッケージはすべてdnfで管理する
設定方針
まずdnfを動かすために必要なパッケージをrpmから展開します。
そのあと、パッケージのインベントリーの整合性をとるために、dnfで同じパッケージを上書きインストールします。
dnfが動くようになったらネットワークツールのパッケージや開発ツールなどをdnfでインストールしてきます。
Playbook
roles/freebsd/tasks/linux_emulation_rockylinux.yaml
必要なパッケージのインストール
rpm形式のパッケージをインストールするためにrpm2cpio、パッケージ情報が記述されたxmlファイルをパースするためにxmlstarletをまず最初にインストールします。
- name: Ensure rpm2cpio installed
community.general.pkgng:
name: rpm2cpio
state: present
- name: Ensure xmlstarlet installed
community.general.pkgng:
name: xmlstarlet
state: present
各種定義
インストール対象のRockyLinuxのバージョン、アーキテクチャ、サイトを定義します。
- name: Set RockyLinux version and architecture
set_fact:
rockylinux_ver: "9.7"
rockylinux_arch: "x86_64"
- name: Set RockyLinux package site
set_fact:
rockylinux_devel_site: "https://dl.rockylinux.org/pub/rocky/{{ rockylinux_ver }}/devel/{{ rockylinux_arch }}/os"
パッケージの情報取得
まず全パッケージ情報を取得し、それをパースしてsqlite3フォーマットのパッケージ情報データベースを取得します。
そしてそのデータベースを読み出し、パッケージ情報のJSONデータを生成します。
次に、dnfに必要なパッケージを定義し、そのパッケージ情報にマッチするrpmパッケージをダウンロードし、展開します。
この時、冪等性を実現するために/compat/linux/var/db/rpm2cpio_stampsを作成し、一度展開したパッケージを除外するようにします。
- name: Get repomd.xml
get_url:
url: "{{ rockylinux_devel_site }}/repodata/repomd.xml"
dest: /compat/linux/repomd.xml
- name: Extract primary sqlite path
shell: |
xml sel \
-N r="http://linux.duke.edu/metadata/repo" \
-t \
-m '//r:data[@type="primary_db"]/r:location' \
-v '@href' \
-n \
/compat/linux/repomd.xml
register: primary_db
changed_when: false
- name: Download primary sqlite
get_url:
url: "{{ rockylinux_devel_site }}/{{ primary_db.stdout }}"
dest: /compat/linux/primary.sqlite.bz2
- name: Generate package JSON
shell: |
sqlite3 /compat/linux/primary.sqlite <<'EOF'
.mode json
select
substr(location_href,
instr(location_href, 'Packages/') + 9,
1) as category,
pkgKey,
name as basename,
version,
release,
arch,
location_href as path,
replace(
location_href,
'Packages/' ||
substr(location_href,
instr(location_href, 'Packages/') + 9,
1) ||
'/',
''
) as rpm,
'{{ rockylinux_devel_site }}/' || location_href as url
from packages;
EOF
register: package_json
changed_when: false
- debug:
var: package_json
when:
- verbose | default(false)
- name: Build package list
set_fact:
rockylinux_packages: "{{ package_json.stdout | from_json }}"
- debug:
var: rockylinux_packages
when:
- verbose | default(false)
- name: Set RockyLinux yum/dnf packages
set_fact:
dnf_packages:
- audit_libs_rpm
- ca-certificates_rpm
- crypto_policies_rpm
- cyrus_sasl_lib_rpm
- dnf_rpm
- dnf_data_rpm
- dnf_plugins_core_rpm
- elfutils_libelf_rpm
- elfutils_libs_rpm
- expat_rpm
- file_libs_rpm
- filesystem_rpm
- gnupg2_rpm
- gpgme_rpm
- ima_evm_utils_rpm
- json_c_rpm
- libassuan_rpm
- libcap_ng_rpm
- libcomps_rpm
- libcurl_rpm
- libdnf_rpm
- libevent_rpm
- libgomp_rpm
- libgpg_error_rpm
- libmodulemd_rpm
- libnghttp2_rpm
- librepo_rpm
- libselinux_rpm
- libsolv_rpm
- libssh_rpm
- libtasn1_rpm
- libxml2_rpm
- libyaml_rpm
- lua_libs_rpm
- openldap_rpm
- p11_kit_rpm
- p11_kit_trust_rpm
- python3_rpm
- python3_dnf_rpm
- python3_gpg_rpm
- python3_libs_rpm
- python3_libdnf_rpm
- python3_hawkey_rpm
- python3_libcomps_rpm
- python3_rpm_rpm
- rocky_repos_rpm
- rocky_gpg_keys_rpm
- setup_rpm
- shadow_utils_rpm
- rpm_rpm
- rpm_libs_rpm
- rpm_build_libs_rpm
- rpm_sign_rpm
- rpm_sign_libs_rpm
- tpm2_tss_rpm
- yum_rpm
- yum_utils_rpm
- name: Clean and initialize package list
set_fact:
cleaned_dnf_packages: |
{{ dnf_packages
| map('regex_replace', '_rpm$', '')
| map('regex_replace', '_', '-')
| list }}
filtered_rockylinux_packages: []
- name: Filter RockyLinux package list
set_fact:
filtered_rockylinux_packages: >-
{{
filtered_rockylinux_packages +
[
(
rockylinux_packages
| selectattr('basename', 'equalto', item)
| rejectattr('rpm', 'search', 'i686')
| list
)
| selectattr('release', 'equalto', (
rockylinux_packages
| selectattr('basename', 'equalto', item)
| rejectattr('rpm', 'search', 'i686')
| map(attribute='release')
| list
| community.general.version_sort
| last
))
| first
]
}}
when: >-
rockylinux_packages
| selectattr('basename', 'equalto', item)
| rejectattr('rpm', 'search', 'i686')
| list
| length > 0
loop: "{{ cleaned_dnf_packages }}"
- name: Ensure /compat/linux/rpm exists
file:
path: /compat/linux/rpm
state: directory
- name: Get rpm
get_url:
url: "{{ item.url }}"
dest: "/compat/linux/rpm/{{ item.rpm }}"
force: false
loop: "{{ filtered_rockylinux_packages }}"
loop_control:
label: "{{ item.rpm }}"
- name: Ensure /compat/linux/var/db/rpm2cpio_stamps directory exists
file:
path: /compat/linux/var/db/rpm2cpio_stamps
state: directory
- name: Deploy packages
shell: |
rpm2cpio < /compat/linux/rpm/{{ item.rpm }} | cpio -id
touch /compat/linux/var/db/rpm2cpio_stamps/{{ item.rpm }}
args:
chdir: /compat/linux
creates: "/compat/linux/var/db/rpm2cpio_stamps/{{ item.rpm }}"
loop: "{{ filtered_rockylinux_packages }}"
loop_control:
label: "{{ item.rpm }}"
notify:
- run_linux_ldconfig
dnfの設定
FreeBSDのLinux Emulationはdnfによるパッケージ管理のために必要なLinuxのいくつかの機能が実装されておらず、そのままだとdnfの実行時にエラーになってしまいます。したがって、それらを無効化することでエラーを回避します。
- name: Ensure /etc/rpm directory exists
file:
path: /compat/linux/etc/rpm
state: directory
- name: Deploy /etc/rpm/macros.freebsd
copy:
dest: /compat/linux/etc/rpm/macros.freebsd
mode: "0644"
content: |
%_file_caps_path %{nil}
%__file_context_path %{nil}
%_selinux_policy_targeted 0
- name: Ensure /etc/dnf/vars directory exists
file:
path: /compat/linux/etc/dnf/vars
state: directory
- name: Deploy /etc/dnf/vars/releasever
copy:
dest: /compat/linux/etc/dnf/vars/releasever
mode: "0644"
content: "{{ rockylinux_ver.split('.')[0] }}"
- name: Disable history_record
lineinfile:
path: /compat/linux/etc/dnf/dnf.conf
regexp: '^history_record='
line: "history_record=False"
create: yes
- name: Enable nocaps for FreeBSD Linux Emuldation
lineinfile:
path: /compat/linux/etc/dnf/dnf.conf
regexp: '^tsflags='
line: "tsflags=nocaps"
パッケージインベントリーの整合性合わせ
展開したrpmパッケージをdnfでもう一度インストールしなおします。
このとき、CA証明書のトラストチェーンの再構成、GPG鍵の整合性合わせ、パッケージデータベースの再生成を同時に行います。
- name: Deploy dnf_install.sh
copy:
dest: /compat/linux/dnf_install.sh
mode: "0755"
content: |
#!/bin/bash
/usr/bin/update-ca-trust
rm -f /var/lib/dnf/history.sqlite*
export SQLITE_DEFAULT_JOURNAL_MODE=TRUNCATE
dnf install -y --setopt=history_record=true rocky-gpg-keys --nogpgcheck
dnf install -y \
{% for pkg in filtered_rockylinux_packages -%}
{{ pkg.basename }}{% if not loop.last %} \
{% endif %}
{%- endfor %}
- name: dnf install
command: chroot /compat/linux /bin/bash /dnf_install.sh
register: result
changed_when: false
- debug:
var: result.stdout_lines
dnfの動作確認
ここまで来るとdnfが動作します。
# chroot /compat/linux dnf list Rocky Linux 9 - BaseOS 6.8 kB/s | 4.3 kB 00:00 Rocky Linux 9 - BaseOS 14 MB/s | 23 MB 00:01 Rocky Linux 9 - AppStream 8.7 kB/s | 4.8 kB 00:00 Rocky Linux 9 - AppStream 19 MB/s | 20 MB 00:01 Rocky Linux 9 - Extras 6.5 kB/s | 3.1 kB 00:00 Rocky Linux 9 - Extras 30 kB/s | 17 kB 00:00 Installed Packages aardvark-dns.x86_64 2:1.16.0-1.el9 @System acl.x86_64 2.3.1-4.el9 @baseos alternatives.x86_64 1.24-2.el9 @baseos ...
後はdnfで必要なパッケージをインストールするだけです。
ネットワーク関連パッケージのインストール
- name: Set RockyLinux network packages
set_fact:
network_packages:
- iproute
- iputils
- net-tools
- nmap
- name: Install network packages
command: >
chroot /compat/linux /usr/bin/dnf install -y {{ network_packages | join(' ') }}
register: result
changed_when: false
- debug:
var: result.stdout_lines
開発用パッケージのインストール
- name: Set RockyLinux development tool packages
set_fact:
devtool_packages:
- cpio
- hostname
- make
- openssl
- passwd
- procps-ng
- pkgconf
- pkgconf-pkg-config
- sudo
- tar
- tzdata
- vi
- wget
- xz
- name: Install development tool packages
command: >
chroot /compat/linux /usr/bin/dnf install -y {{ devtool_packages | join(' ') }}
register: result
changed_when: false
- debug:
var: result.stdout_lines
開発用ライブラリーパッケージのインストール
- name: Set RockyLinux development library packages
set_fact:
dev_library_packages:
- bzip2-devel
- libffi-devel
- libuuid-devel
- libxcrypt-devel
- ncurses-devel
- nss-devel
- openssl-devel
- readline-devel
- sqlite-devel
- tk-devel
- xz-devel
- zlib-devel
- name: Install development tool packages
command: >
chroot /compat/linux /usr/bin/dnf install -y {{ dev_library_packages | join(' ') }}
register: result
changed_when: false
- debug:
var: result.stdout_lines