commit
ede28f5208
11 changed files with 230 additions and 0 deletions
@ -0,0 +1 @@ |
|||||
|
inventory |
||||
@ -0,0 +1,4 @@ |
|||||
|
[defaults] |
||||
|
# Use the provided inventory |
||||
|
inventory=inventory |
||||
|
interpreter_python=auto_silent |
||||
@ -0,0 +1,154 @@ |
|||||
|
# This is an Ansible Playbook to build a bootc container image using Podman for two architectures: amd64 and arm64. |
||||
|
- name: Build bootc container image |
||||
|
hosts: builder |
||||
|
vars: |
||||
|
build_name: "example-flightctl" |
||||
|
bootc_project: '{{ playbook_dir }}/examples/flightctl' |
||||
|
image_from: |
||||
|
x86_64: "registry.redhat.io/rhel9/rhel-bootc:9.4" |
||||
|
aarch64: "quay.io/redhat-et/rhel-bootc-tegra:base" |
||||
|
image_to: "edge-registry.itix.fr/bootc/hello-world:latest" |
||||
|
validate_certs: true |
||||
|
# This file must be present on all builder hosts as well as on the control node if pushing to/pulling from a remote registry |
||||
|
# You can create it with: |
||||
|
# sudo REGISTRY_AUTH_FILE=/etc/containers/auth.json podman login registry.redhat.io |
||||
|
# sudo REGISTRY_AUTH_FILE=/etc/containers/auth.json podman login quay.io |
||||
|
auth_file: "/etc/containers/auth.json" |
||||
|
tasks: |
||||
|
|
||||
|
- name: Install pre-requisite packages |
||||
|
ansible.builtin.dnf: |
||||
|
name: |
||||
|
- podman |
||||
|
- buildah |
||||
|
- skopeo |
||||
|
- rsync |
||||
|
state: present |
||||
|
|
||||
|
- name: Check if Podman auth file exists |
||||
|
ansible.builtin.stat: |
||||
|
path: "{{ auth_file }}" |
||||
|
register: podman_auth_file |
||||
|
when: auth_file is defined |
||||
|
|
||||
|
- assert: |
||||
|
that: |
||||
|
- podman_auth_file.stat.exists |
||||
|
fail_msg: | |
||||
|
Podman auth file {{ auth_file }} does not exist. Please create it to authenticate to container registries. |
||||
|
You can create it using the 'podman login' command. |
||||
|
Example: |
||||
|
sudo REGISTRY_AUTH_FILE=/etc/containers/auth.json podman login registry.redhat.io |
||||
|
sudo REGISTRY_AUTH_FILE=/etc/containers/auth.json podman login quay.io |
||||
|
ansible-playbook build.yaml -e auth_file=/etc/containers/auth.json |
||||
|
when: auth_file is defined |
||||
|
|
||||
|
- name: Pull bootc base image |
||||
|
containers.podman.podman_image: |
||||
|
name: "{{ image_from[ansible_architecture] }}" |
||||
|
arch: "{{ ansible_architecture }}" |
||||
|
state: present |
||||
|
pull: true |
||||
|
validate_certs: '{{ validate_certs | default(omit) }}' |
||||
|
auth_file: "{{ auth_file | default(omit) }}" |
||||
|
|
||||
|
- name: Create a temporary directory for the build |
||||
|
ansible.builtin.tempfile: |
||||
|
state: directory |
||||
|
suffix: bootc_build_ |
||||
|
register: temp_build_dir |
||||
|
|
||||
|
- name: Copy the bootc project directory to the builder |
||||
|
ansible.posix.synchronize: |
||||
|
mode: push |
||||
|
src: "{{ bootc_project }}/" |
||||
|
dest: "{{ temp_build_dir.path }}/bootc/" |
||||
|
archive: no |
||||
|
recursive: yes |
||||
|
compress: no |
||||
|
delete: no |
||||
|
|
||||
|
- name: Build bootc container image |
||||
|
containers.podman.podman_image: |
||||
|
name: "localhost/{{ build_name }}-{{ ansible_architecture }}:latest" |
||||
|
build: |
||||
|
extra_args: "--from={{ image_from[ansible_architecture] }}" |
||||
|
cache: false |
||||
|
file: "{{ temp_build_dir.path }}/bootc/Containerfile" |
||||
|
path: "{{ temp_build_dir.path }}/bootc" |
||||
|
force: true |
||||
|
push: false |
||||
|
state: build |
||||
|
|
||||
|
- name: Export the built image to the temporary directory |
||||
|
containers.podman.podman_image: |
||||
|
name: "localhost/{{ build_name }}-{{ ansible_architecture }}:latest" |
||||
|
push: true |
||||
|
push_args: |
||||
|
compress: false |
||||
|
dest: "{{ temp_build_dir.path }}/{{ build_name }}-{{ ansible_architecture }}.tar" |
||||
|
format: oci |
||||
|
transport: oci-archive |
||||
|
state: present |
||||
|
|
||||
|
- name: Change ownership of the exported image archive to the ansible user |
||||
|
ansible.builtin.file: |
||||
|
path: "{{ file.path }}" |
||||
|
mode: "{{ file.mode }}" |
||||
|
loop: |
||||
|
- path: "{{ temp_build_dir.path }}/{{ build_name }}-{{ ansible_architecture }}.tar" |
||||
|
mode: '0644' |
||||
|
- path: "{{ temp_build_dir.path }}" |
||||
|
mode: '0755' |
||||
|
loop_control: |
||||
|
loop_var: file |
||||
|
label: "{{ file.path }}" |
||||
|
|
||||
|
# The synchronize module is used here to efficiently transfer large files |
||||
|
- name: Fetch the exported image archive to the control node |
||||
|
ansible.posix.synchronize: |
||||
|
mode: pull |
||||
|
src: "{{ temp_build_dir.path }}/{{ build_name }}-{{ ansible_architecture }}.tar" |
||||
|
dest: "{{ playbook_dir }}/builds/" |
||||
|
archive: no |
||||
|
compress: no |
||||
|
delete: no |
||||
|
delegate_to: localhost |
||||
|
|
||||
|
- name: Remove the temporary build directory |
||||
|
ansible.builtin.file: |
||||
|
path: "{{ temp_build_dir.path }}" |
||||
|
state: absent |
||||
|
|
||||
|
- block: |
||||
|
|
||||
|
- name: Remove the Podman manifest if it exists |
||||
|
ansible.builtin.command: |
||||
|
cmd: > |
||||
|
podman manifest rm -i localhost/{{ build_name }}:latest |
||||
|
|
||||
|
- name: Create a manifest list for multi-architecture image |
||||
|
ansible.builtin.command: |
||||
|
cmd: > |
||||
|
podman manifest create localhost/{{ build_name }}:latest |
||||
|
|
||||
|
- name: Add architecture-specific images to the manifest list |
||||
|
ansible.builtin.command: |
||||
|
cmd: > |
||||
|
podman manifest add localhost/{{ build_name }}:latest oci-archive:{{ playbook_dir }}/builds/{{ build_name }}-{{ architecture }}.tar |
||||
|
loop: '{{ architectures }}' |
||||
|
loop_control: |
||||
|
loop_var: architecture |
||||
|
|
||||
|
- name: Push the multi-architecture manifest to the remote registry |
||||
|
ansible.builtin.command: |
||||
|
cmd: > |
||||
|
podman manifest push --quiet --rm --all --tls-verify={{ validate_certs | default('true') }} localhost/{{ build_name }}:latest {{ image_to }} |
||||
|
environment: |
||||
|
REGISTRY_AUTH_FILE: "{{ auth_file | default(omit) }}" |
||||
|
delegate_to: localhost |
||||
|
run_once: true |
||||
|
become: yes |
||||
|
vars: |
||||
|
# Computes the list of architectures based on the "ansible_architecture" values of the builder hosts |
||||
|
architectures: '{{ hostvars | dict2items | map(attribute="value") | selectattr("ansible_architecture", "defined") | map(attribute="ansible_architecture") | list }}' |
||||
@ -0,0 +1 @@ |
|||||
|
*.tar |
||||
@ -0,0 +1,43 @@ |
|||||
|
FROM registry.redhat.io/rhel9/rhel-bootc:9.4 |
||||
|
|
||||
|
ARG ADMIN_USERNAME=demo \ |
||||
|
ADMIN_PASSWORD=redhat |
||||
|
|
||||
|
RUN <<EOF |
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
# Enable EPEL and Ansible AAP repos |
||||
|
dnf config-manager --enable ansible-automation-platform-2.5-for-rhel-9-$(arch)-rpms |
||||
|
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm |
||||
|
|
||||
|
# Install packages |
||||
|
dnf install -y mkpasswd podman skopeo flightctl-agent cockpit cockpit-podman cockpit-files \ |
||||
|
cockpit-ostree cockpit-pcp cockpit-system greenboot greenboot-default-health-checks \ |
||||
|
stress-ng yq podman-compose tmux tcpdump htop iptraf-ng |
||||
|
dnf clean all |
||||
|
|
||||
|
# Create admin user if specified |
||||
|
if [ -n "$ADMIN_USERNAME" ]; then |
||||
|
useradd -m -G wheel -p "$(echo -n "$ADMIN_PASSWORD" | mkpasswd -m bcrypt --stdin)" "$ADMIN_USERNAME" |
||||
|
fi |
||||
|
EOF |
||||
|
|
||||
|
ADD --chown=root:root root / |
||||
|
|
||||
|
RUN <<EOF |
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
# Enable systemd services and sockets |
||||
|
systemctl enable flightctl-agent.service cockpit.socket |
||||
|
|
||||
|
# Make sure the flightctl-agent is the only one that can apply updates |
||||
|
systemctl mask bootc-fetch-apply-updates.timer |
||||
|
|
||||
|
# Set proper ownership and SELinux context on SSH authorized keys |
||||
|
if [ -n "$ADMIN_USERNAME" -a -f "/etc/ssh/authorized_keys/$ADMIN_USERNAME.keys" ]; then |
||||
|
chown "$ADMIN_USERNAME:$ADMIN_USERNAME" "/etc/ssh/authorized_keys/$ADMIN_USERNAME.keys" |
||||
|
fi |
||||
|
semanage fcontext -a -t ssh_home_t "/etc/ssh/authorized_keys(/.*)?" |
||||
|
restorecon -Rf /etc/ssh/authorized_keys |
||||
|
|
||||
|
EOF |
||||
@ -0,0 +1,4 @@ |
|||||
|
- if: |
||||
|
- path: /etc/greenboot/check/ |
||||
|
op: [created, updated, removed] |
||||
|
run: systemctl restart --no-block greenboot-healthcheck.service |
||||
@ -0,0 +1,3 @@ |
|||||
|
AuthorizedKeysFile /etc/ssh/authorized_keys/%u.keys .ssh/authorized_keys |
||||
|
PermitRootLogin prohibit-password |
||||
|
#LogLevel DEBUG |
||||
@ -0,0 +1,13 @@ |
|||||
|
Defaults !visiblepw |
||||
|
Defaults always_set_home |
||||
|
Defaults match_group_by_gid |
||||
|
Defaults always_query_group_plugin |
||||
|
Defaults env_reset |
||||
|
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS" |
||||
|
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" |
||||
|
Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" |
||||
|
Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" |
||||
|
Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" |
||||
|
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin |
||||
|
root ALL=(ALL) NOPASSWD: ALL |
||||
|
%wheel ALL=(ALL) NOPASSWD: ALL |
||||
@ -0,0 +1,2 @@ |
|||||
|
KEYMAP="fr-oss" |
||||
|
FONT="eurlatgr" |
||||
@ -0,0 +1,2 @@ |
|||||
|
kargs = ["console=tty0", "console=ttyS0"] |
||||
|
match-architectures = ["x86_64"] |
||||
@ -0,0 +1,3 @@ |
|||||
|
[builder] |
||||
|
build-aarch64.example.tld ansible_user=john ansible_become=yes |
||||
|
build-x86_64.example.tld ansible_user=john ansible_become=yes |
||||
Loading…
Reference in new issue