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