Nicolas Massé 4 months ago
parent
commit
e38433b39e
  1. 25
      bootc/Containerfile
  2. 37
      bootc/Containerfile.rh
  3. 55
      bootc/Containerfile.vanilla
  4. 6
      bootc/artefacts-iso.sh
  5. 2
      bootc/artefacts-qcow2.sh
  6. 1
      bootc/build.sh
  7. 25
      bootc/common.sh
  8. 7
      bootc/env.sh
  9. 8
      tekton/README.md
  10. 2
      tekton/common/kustomization.yaml
  11. 172
      tekton/common/mosquitto.yaml
  12. 13
      tekton/common/storage.yaml
  13. 5
      tekton/common/task-buildah.yaml
  14. 24
      tekton/common/task-ota-update.yaml
  15. 8
      tekton/pipeline.yaml

25
bootc/Containerfile

@ -1,7 +1,8 @@
FROM quay.io/redhat-et/rhel-bootc-tegra:base
FROM registry.redhat.io/rhel9/rhel-bootc:9.6
ARG ADMIN_USERNAME=demo \
ADMIN_PASSWORD=redhat \
NVIDIA_KERNEL_VERSION=5.14.0-427.22.1.el9_4 \
ENABLE_DNF_CACHE=1 \
LOCAL_RPM_REPO=0
@ -18,12 +19,30 @@ if [[ "$LOCAL_RPM_REPO" == "1" ]]; then
echo -e "[main]\nenabled=0" > /etc/dnf/plugins/subscription-manager.conf
fi
if [ -n "$NVIDIA_KERNEL_VERSION" ]; then
echo "Replacing current kernel with a version compatible with the kernel modules shipped by Nvidia"
mkdir -p /tmp/rpms
dnf download -y --destdir /tmp/rpms kernel{,-core,-modules,-modules-core}-$NVIDIA_KERNEL_VERSION
rpm-ostree override replace /tmp/rpms/*.rpm
rm -rf /tmp/rpms
fi
if [[ "$LOCAL_RPM_REPO" != "1" ]]; then
#dnf config-manager --enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf config-manager --enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
fi
dnf install -y mkpasswd NetworkManager-wifi podman skopeo git
dnf install -y mkpasswd NetworkManager-wifi podman skopeo git mosquitto
if [[ "$(arch)" == "aarch64" ]]; then
echo "Installing the Nvidia stuff..." ; \
if [[ "$LOCAL_RPM_REPO" != "1" ]]; then
curl -sSfL -o /etc/yum.repos.d/nvidia-l4t.repo https://repo.download.nvidia.com/jetson/rhel-9.4/r36.3.1/nvidia-l4t.repo
curl -sSfL -o /etc/yum.repos.d/nvidia-container-toolkit.repo https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo
dnf config-manager --enable nvidia-container-toolkit-experimental
fi
dnf install -y nvidia-jetpack-kmod nvidia-jetpack-all nvidia-container-toolkit-base
fi
if [ -n "$ADMIN_USERNAME" ]; then
useradd -m -G wheel -p "$(echo -n "$ADMIN_PASSWORD" | mkpasswd -m bcrypt --stdin)" "$ADMIN_USERNAME"

37
bootc/Containerfile.rh

@ -0,0 +1,37 @@
FROM quay.io/redhat-et/rhel-bootc-tegra:base
ARG ADMIN_USERNAME=demo \
ADMIN_PASSWORD=redhat \
ENABLE_DNF_CACHE=1 \
LOCAL_RPM_REPO=0
RUN <<EOF
set -Eeuo pipefail
if [[ "$ENABLE_DNF_CACHE" == "1" ]] && ! grep -qxF 'keepcache=1' /etc/dnf/dnf.conf; then
echo "Enabling dnf cache..."
sed -i.bak '/^\[main\]$/a keepcache=1' /etc/dnf/dnf.conf
fi
if [[ "$LOCAL_RPM_REPO" == "1" ]]; then
echo "Disabling Subscription Manager because we have no internet connection and no satelite..."
echo -e "[main]\nenabled=0" > /etc/dnf/plugins/subscription-manager.conf
fi
if [[ "$LOCAL_RPM_REPO" != "1" ]]; then
#dnf config-manager --enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
fi
dnf install -y mkpasswd NetworkManager-wifi podman skopeo git
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 set -Eeuo pipefail ; \
systemctl enable nvidia-ctk-init.service ; \
systemctl enable git-repo.service

55
bootc/Containerfile.vanilla

@ -1,55 +0,0 @@
FROM registry.redhat.io/rhel9/rhel-bootc:9.4
ARG ADMIN_USERNAME=demo \
ADMIN_PASSWORD=redhat \
NVIDIA_KERNEL_VERSION=5.14.0-427.22.1.el9_4 \
ENABLE_DNF_CACHE=1 \
LOCAL_RPM_REPO=0
RUN <<EOF
set -Eeuo pipefail
if [[ "$ENABLE_DNF_CACHE" == "1" ]] && ! grep -qxF 'keepcache=1' /etc/dnf/dnf.conf; then
echo "Disabling dnf cache..."
sed -i.bak '/^\[main\]$/a keepcache=1' /etc/dnf/dnf.conf
fi
if [[ "$LOCAL_RPM_REPO" == "1" ]]; then
echo "Disabling Subscription Manager because we have no internet connection and no satelite..."
echo -e "[main]\nenabled=0" > /etc/dnf/plugins/subscription-manager.conf
fi
if [ -n "$NVIDIA_KERNEL_VERSION" ]; then
echo "Replacing current kernel with a version compatible with the kernel modules shipped by Nvidia"
mkdir -p /tmp/rpms
dnf download -y --destdir /tmp/rpms kernel{,-core,-modules,-modules-core}-$NVIDIA_KERNEL_VERSION
rpm-ostree override replace /tmp/rpms/*.rpm
rm -rf /tmp/rpms
fi
if [[ "$LOCAL_RPM_REPO" != "1" ]]; then
dnf config-manager --enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
fi
dnf install -y mkpasswd NetworkManager-wifi podman skopeo git
if [[ "$(arch)" == "aarch64" ]]; then
echo "Installing the Nvidia stuff..." ; \
if [[ "$LOCAL_RPM_REPO" != "1" ]]; then
curl -sSfL -o /etc/yum.repos.d/nvidia-l4t.repo https://repo.download.nvidia.com/jetson/rhel-9.4/r36.3.1/nvidia-l4t.repo
curl -sSfL -o /etc/yum.repos.d/nvidia-container-toolkit.repo https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo
dnf config-manager --enable nvidia-container-toolkit-experimental
fi
dnf install -y nvidia-jetpack-kmod nvidia-jetpack-all nvidia-container-toolkit-base
fi
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 set -Eeuo pipefail ; \
systemctl enable nvidia-ctk-init.service ; \
systemctl enable git-repo.service

6
bootc/artefacts-iso.sh

@ -23,11 +23,10 @@ declare -A ARCH_KERNEL_CMDLINE=(["aarch64"]="console=ttyTCU0 console=tty0" ["x86
# $(base32 -w 80 auth.json)
# EOB32
declare -a KICKSTART_ADDITIONAL_FILES_TAR_CMD_PRE=( )
declare -a KICKSTART_ADDITIONAL_FILES_TAR_CMD_POST=( tar -zc -C post --owner=root --group=root . )
declare -A KICKSTART_SNIPPETS=()
KICKSTART_SNIPPETS+=( ["restart networkmanager"]="
systemctl restart --no-block NetworkManager.service
/usr/bin/nm-online -s -q
" )
KICKSTART_SNIPPETS+=( ["bootc switch"]="
bootc switch --mutate-in-place --transport registry $TARGET_IMAGE
@ -41,7 +40,8 @@ chmod 600 /etc/ostree/auth.json
KICKSTART_SNIPPETS+=( ["/etc/containers/registries.conf.d/bootc-registry.conf"]="
cat > /etc/containers/registries.conf.d/bootc-registry.conf <<\"EOF\"
[[registry]]
location=\"${TARGET_IMAGE%%/*}\"
prefix=\"${TARGET_IMAGE%%/*}\"
location=\"${TARGET_IMAGE%%/*}:80\"
insecure=true
EOF
" )

2
bootc/artefacts-qcow2.sh

@ -19,7 +19,7 @@ function bootc_image_builder () {
-v "$config_file:/config.toml:ro" -v "$output:/output" -v "$rpmmd:/rpmmd" -v "$store:/store" \
-v /var/lib/containers/storage:/var/lib/containers/storage \
-v "$REGISTRY_AUTH_FILE:/auth.json:ro" -e "REGISTRY_AUTH_FILE=/auth.json" \
"$BOOTC_IMAGE:$RHEL_VERSION" --type "$type" --config /config.toml "$image" "${args[@]}"
"$BOOTC_IMAGE:$BOOTC_VERSION" --type "$type" --config /config.toml "$image" "${args[@]}"
}
arch="$(arch)"

1
bootc/build.sh

@ -9,7 +9,6 @@ source ./env.sh
./common.sh
# Build images
declare -A PODMAN_ARCH_OPTS=(["aarch64"]="--platform linux/arm64/v8" ["x86_64"]="--platform linux/amd64")
for arch in "${ARCHITECTURES[@]}"; do
echo "Building $NAME image for $arch..."
rm -rf etc

25
bootc/common.sh

@ -1,5 +1,12 @@
#!/bin/sh
set -Eeuo pipefail
if [[ "$UID" -ne 0 ]]; then
echo "This command must be run as root!"
exit 1
fi
# Source variables and environment
source ./env.sh
@ -20,18 +27,14 @@ fi
# Pull
echo "Pulling images..."
if ! podman image exists $BOOTC_IMAGE:$RHEL_VERSION; then
podman pull $BOOTC_IMAGE:$RHEL_VERSION
fi
if ! podman image exists $RHEL_IMAGE-x86_64:$RHEL_VERSION; then
podman rmi -i $RHEL_IMAGE:$RHEL_VERSION
podman pull --platform linux/amd64 $RHEL_IMAGE:$RHEL_VERSION
podman tag $RHEL_IMAGE:$RHEL_VERSION $RHEL_IMAGE-x86_64:$RHEL_VERSION
podman rmi $RHEL_IMAGE:$RHEL_VERSION
if ! podman image exists $BOOTC_IMAGE:$BOOTC_VERSION; then
podman pull $BOOTC_IMAGE:$BOOTC_VERSION
fi
if ! podman image exists $RHEL_IMAGE-aarch64:$RHEL_VERSION; then
for arch in "${ARCHITECTURES[@]}"; do
if ! podman image exists $RHEL_IMAGE-$arch:$RHEL_VERSION; then
podman rmi -i $RHEL_IMAGE:$RHEL_VERSION
podman pull --platform linux/arm64/v8 $RHEL_IMAGE:$RHEL_VERSION
podman tag $RHEL_IMAGE:$RHEL_VERSION $RHEL_IMAGE-aarch64:$RHEL_VERSION
podman pull ${PODMAN_ARCH_OPTS[$arch]} $RHEL_IMAGE:$RHEL_VERSION
podman tag $RHEL_IMAGE:$RHEL_VERSION $RHEL_IMAGE-$arch:$RHEL_VERSION
podman rmi $RHEL_IMAGE:$RHEL_VERSION
fi
done

7
bootc/env.sh

@ -2,14 +2,17 @@
### General
###
PODMAN_NETWORK="edge-ai"
RHEL_VERSION="9.4"
RHEL_VERSION="9.6"
RHEL_IMAGE="registry.redhat.io/rhel9/rhel-bootc"
BOOTC_IMAGE="registry.redhat.io/rhel9/bootc-image-builder"
BOOTC_IMAGE="registry.redhat.io/rhel10/bootc-image-builder"
BOOTC_VERSION="10.0"
NAME="bootc-edge-ai"
TARGET_IMAGE="quay.io/nmasse-redhat/$NAME:latest"
# All architectures to build for
declare -a ARCHITECTURES=("x86_64" "aarch64")
#declare -a ARCHITECTURES=("aarch64")
declare -A PODMAN_ARCH_OPTS=(["aarch64"]="--platform linux/arm64/v8" ["x86_64"]="--platform linux/amd64")
###
### Environment Variables

8
tekton/README.md

@ -52,6 +52,14 @@ EOF
oc create secret generic github-authentication --from-literal=.git-credentials=https://user:password@github.com --from-file=.gitconfig=gitconfig
```
## Authentication to MQTT
Set the tekton password in the mosquitto passwd file (**common/mosquitto.conf**) and then:
```sh
oc create secret generic mqtt-config --from-literal=OTA_MQTT_URL=mqtts://tekton:secret@mosquitto-build-multiarch.apps.nmasse-q2-2025.sandbox1038.opentlc.com:443/bootc/updates
```
## Rclone config for AWS S3
**rclone.conf**:

2
tekton/common/kustomization.yaml

@ -1,5 +1,7 @@
resources:
- serviceaccount-buildbot.yaml
- mosquitto.yaml
- task-ota-update.yaml
- task-buildah.yaml
- task-git-clone.yaml
- task-rclone.yaml

172
tekton/common/mosquitto.yaml

@ -0,0 +1,172 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mosquitto-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
volumeMode: Filesystem
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mosquitto
spec:
replicas: 1
serviceName: mosquitto
selector:
matchLabels:
name: mosquitto
template:
metadata:
labels:
name: mosquitto
spec:
containers:
- name: mosquitto
image: docker.io/library/eclipse-mosquitto:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8883
livenessProbe:
tcpSocket:
port: 1883
failureThreshold: 1
initialDelaySeconds: 5
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
exec:
command:
- mosquitto_pub
- -t
- _ping
- -m
- ping
failureThreshold: 1
initialDelaySeconds: 5
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: data
mountPath: /mosquitto/data
subPath: data
- name: data
mountPath: /mosquitto/log
subPath: log
- name: config
mountPath: /mosquitto/config
- name: tls
mountPath: /mosquitto/tls
readOnly: true
- name: ca
mountPath: /mosquitto/ca
readOnly: true
- name: mosquitto-subscriber
image: docker.io/library/eclipse-mosquitto:latest
imagePullPolicy: IfNotPresent
command:
- mosquitto_sub
args:
- -v
- -t
- '#'
volumeMounts:
- name: tls
mountPath: /mosquitto/tls
readOnly: true
- name: ca
mountPath: /mosquitto/ca
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: data
persistentVolumeClaim:
claimName: mosquitto-data
- name: config
configMap:
name: mosquitto-config
defaultMode: 0640
- name: ca
configMap:
name: openshift-service-ca.crt
- name: tls
secret:
secretName: mosquitto-tls
---
apiVersion: v1
kind: Service
metadata:
name: mosquitto
annotations:
service.beta.openshift.io/serving-cert-secret-name: mosquitto-tls
spec:
type: ClusterIP
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: mqtt
port: 1883
protocol: TCP
targetPort: 1883
- name: tls
port: 8883
protocol: TCP
targetPort: 8883
selector:
name: mosquitto
sessionAffinity: None
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mosquitto-config
data:
mosquitto.conf: |
autosave_interval 60
persistence true
persistence_file mosquitto.db
persistence_location /mosquitto/data
allow_anonymous true
password_file /mosquitto/config/pwfile
acl_file /mosquitto/config/aclfile
listener 1883 0.0.0.0
protocol mqtt
listener 8883 0.0.0.0
protocol mqtt
cafile /mosquitto/ca/service-ca.crt
certfile /mosquitto/tls/tls.crt
keyfile /mosquitto/tls/tls.key
aclfile: |
# This affects access control for clients with no username.
topic read $SYS/#
# Allow anonymous users to read all updates.
topic read #
# Allow the tekton user to write updates.
user tekton
topic readwrite #
# This affects all clients.
pattern write /broker/connection/%c/state
# pwfile is generated using "mosquitto_passwd -c /tmp/pwfile $username"
pwfile: |
tekton:REDACTED
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: mosquitto
spec:
to:
kind: Service
name: mosquitto
port:
targetPort: 8883
tls:
termination: passthrough
insecureEdgeTerminationPolicy: None

13
tekton/common/storage.yaml

@ -23,3 +23,16 @@ spec:
storage: 1Gi
volumeMode: Filesystem
storageClassName: efs-csi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: bootc-rpms
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
volumeMode: Filesystem
storageClassName: efs-csi

5
tekton/common/task-buildah.yaml

@ -23,6 +23,9 @@ spec:
- name: pypi-mirror-url
type: string
default: ""
results:
- name: image-digest
description: The digest of the built image
workspaces:
- name: source-workspace
description: Workspace containing source code
@ -140,7 +143,7 @@ spec:
# Push Manifest
echo "Pushing to $TARGET_IMAGE..."
buildah manifest push localhost/image docker://$TARGET_IMAGE
buildah manifest push "--digestfile=$(results.image-digest.path)" localhost/image docker://$TARGET_IMAGE
securityContext:
## Buildah needs privileges to use the "overlay" Storage Driver.
privileged: true

24
tekton/common/task-ota-update.yaml

@ -0,0 +1,24 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: ota-update
spec:
params:
- name: otaVersion
type: string
steps:
- name: ota-update
image: docker.io/library/eclipse-mosquitto:latest
env:
- name: OTA_MQTT_URL
valueFrom:
secretKeyRef:
name: "mqtt-config"
key: "OTA_MQTT_URL"
- name: OTA_VERSION
value: "$(params.otaVersion)"
script: |
#!/bin/bash
set -Eeuo pipefail
echo "Sending the OTA firmware udate notification for version $OTA_VERSION on $OTA_MQTT_TOPIC..."
mosquitto_pub -L "$OTA_MQTT_URL" -m "$OTA_VERSION" -d

8
tekton/pipeline.yaml

@ -118,3 +118,11 @@ spec:
workspace: caches
- name: entitlements
workspace: entitlements
- name: ota-update
runAfter: ["buildah-bootc"]
taskRef:
name: ota-update
params:
- name: otaVersion
value: $(tasks.buildah-bootc.results.image-digest)

Loading…
Cancel
Save