Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63c0599045 | ||
|
|
a399cde4d2 | ||
|
|
2ee4348598 | ||
|
|
d0c87455e5 | ||
|
|
3fec296130 | ||
|
|
be1780b3c0 | ||
|
|
b3475b403f | ||
|
|
3bf7d6e238 | ||
|
|
9a27f209fa | ||
|
|
8d9d4cc994 | ||
|
|
01ba8caefa | ||
|
|
c7afbd2465 | ||
|
|
6ea7fb1b99 | ||
|
|
c9052cca59 | ||
|
|
f1060caf62 |
@@ -34,11 +34,19 @@ jobs:
|
||||
zypper if python3-kiwi
|
||||
echo "========================"
|
||||
|
||||
zypper --non-interactive in nodejs libxml2-tools git
|
||||
zypper --non-interactive in nodejs libxml2-tools git curl
|
||||
|
||||
- name: Install Trivy
|
||||
run: |
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set Short SHA
|
||||
id: vars
|
||||
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Lint XML Configuration
|
||||
run: |
|
||||
echo "Validating config.xml against RNG schema..."
|
||||
@@ -56,31 +64,28 @@ jobs:
|
||||
kiwi-ng result bundle \
|
||||
--target-dir /tmp/build \
|
||||
--bundle-dir ./dist \
|
||||
--id gitea-build-${{ github.sha }}
|
||||
--id gitea-build-${{ steps.vars.outputs.sha_short }}
|
||||
|
||||
- name: Upload Image Artifact
|
||||
- name: Generate SBOM
|
||||
run: |
|
||||
trivy fs --format spdx-json --output ./dist/openSUSE-Leap-16.0-Minimal-gitea-build-${{ steps.vars.outputs.sha_short }}.spdx.json /tmp/build/build/image-root
|
||||
trivy fs --format cyclonedx --output ./dist/openSUSE-Leap-16.0-Minimal-gitea-build-${{ steps.vars.outputs.sha_short }}.cdx.json /tmp/build/build/image-root
|
||||
|
||||
- name: Upload Disk Image
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: kiwi-image-${{ github.sha }}
|
||||
path: ./dist/
|
||||
name: kiwi-disk-image-${{ steps.vars.outputs.sha_short }}
|
||||
path: ./dist/*.qcow2 # oder *.raw.xz
|
||||
retention-days: 7
|
||||
|
||||
# Step: Upload des gebauten KIWI-Images direkt in Harvester
|
||||
- name: Upload Image to Harvester Cluster
|
||||
env:
|
||||
HARVESTER_URL: "https://harvester.ui" # Oder IP deines VIP/LoadBalancers
|
||||
HARVESTER_TOKEN: ${{ secrets.HARVESTER_TOKEN }}
|
||||
NAMESPACE: "default" # Ziel-Namespace in Harvester
|
||||
IMAGE_NAME: "leap-16-minimal-${{ github.sha }}"
|
||||
run: |
|
||||
# 1. Pfad zur komprimierten Image-Datei ermitteln (z. B. .raw.xz oder .qcow2)
|
||||
IMAGE_FILE=$(find ./dist -name "*.raw.xz" -o -name "*.qcow2" -o -name "*.raw" | head -n 1)
|
||||
|
||||
echo "Uploading $IMAGE_FILE to Harvester as $IMAGE_NAME..."
|
||||
|
||||
# 2. Upload per cURL an die Harvester Image Upload API
|
||||
curl -k -f -X POST "${HARVESTER_URL}/v1/harvester/harvesterhci.io.virtualmachineimages/${NAMESPACE}/${IMAGE_NAME}?action=upload" \
|
||||
-H "Authorization: Bearer ${HARVESTER_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@${IMAGE_FILE}"
|
||||
|
||||
echo "Upload erfolgreich abgeschlossen!"
|
||||
- name: Upload Build Manifests & Logs
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: kiwi-build-manifests-${{ steps.vars.outputs.sha_short }}
|
||||
path: |
|
||||
./dist/*.packages
|
||||
./dist/*.changes
|
||||
./dist/*.verified
|
||||
./dist/*.spdx.json
|
||||
./dist/*.cdx.json
|
||||
retention-days: 7
|
||||
@@ -0,0 +1,85 @@
|
||||
name: KIWI-NG Release & Harvester Deployment
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: kiwi-builder
|
||||
container:
|
||||
image: registry.opensuse.org/opensuse/bci/kiwi:10
|
||||
options: --privileged
|
||||
|
||||
steps:
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
zypper --non-interactive in nodejs libxml2-tools git curl jq
|
||||
|
||||
- name: Install Trivy
|
||||
run: |
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set Short SHA
|
||||
id: vars
|
||||
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build Image for Release
|
||||
run: |
|
||||
kiwi-ng --profile Cloud system build --description ./opensuse-leap-16-minimal --target-dir /tmp/build
|
||||
kiwi-ng result bundle --target-dir /tmp/build --bundle-dir ./dist --id ${{ github.ref_name }}
|
||||
|
||||
- name: Generate SBOM
|
||||
run: |
|
||||
trivy fs --format spdx-json --output ./dist/openSUSE-Leap-16.0-Minimal-${{ github.ref_name }}.spdx.json /tmp/build/build/image-root
|
||||
trivy fs --format cyclonedx --output ./dist/openSUSE-Leap-16.0-Minimal-${{ github.ref_name }}.cdx.json /tmp/build/build/image-root
|
||||
|
||||
# 1. Gitea Release erstellen und Image-Datei als Asset anhängen
|
||||
- name: Create Gitea Release
|
||||
uses: akkuman/gitea-release-action@v1
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: Release ${{ github.ref_name }}
|
||||
body: "Official KIWI-NG Build for Tag ${{ github.ref_name }}"
|
||||
draft: false
|
||||
prerelease: false
|
||||
files: |-
|
||||
./dist/*.qcow2
|
||||
./dist/*.raw.xz
|
||||
./dist/*.spdx.json
|
||||
./dist/*.cdx.json
|
||||
|
||||
# 2. Harvester triggern (zieht sich die Datei aus dem Release)
|
||||
- name: Trigger Harvester Download
|
||||
env:
|
||||
HARVESTER_URL: ${{ secrets.HARVESTER_URL }}
|
||||
HARVESTER_TOKEN: ${{ secrets.HARVESTER_TOKEN }}
|
||||
NAMESPACE: "default"
|
||||
run: |
|
||||
IMAGE_FILENAME=$(basename $(find ./dist -name "*.qcow2" -o -name "*.raw" -o -name "*.raw.xz" | head -n 1))
|
||||
DOWNLOAD_URL="${{ github.server_url }}/${{ github.repository }}/releases/download/${{ github.ref_name }}/${IMAGE_FILENAME}"
|
||||
|
||||
RESOURCE_NAME="leap-16-minimal-${{ github.ref_name }}"
|
||||
RESOURCE_NAME=$(echo "$RESOURCE_NAME" | sed 's/\./-/g' | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
curl -k -f -X POST "${HARVESTER_URL}/apis/harvesterhci.io/v1beta1/namespaces/${NAMESPACE}/virtualmachineimages" \
|
||||
-H "Authorization: Bearer ${HARVESTER_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"apiVersion": "harvesterhci.io/v1beta1",
|
||||
"kind": "VirtualMachineImage",
|
||||
"metadata": {
|
||||
"name": "'"${RESOURCE_NAME}"'",
|
||||
"namespace": "'"${NAMESPACE}"'"
|
||||
},
|
||||
"spec": {
|
||||
"displayName": "openSUSE-Leap-16.0-Minimal-${{ github.ref_name }}",
|
||||
"description": "Gebaute KIWI-NG Vorlage aus Tag ${{ github.ref_name }}",
|
||||
"sourceType": "download",
|
||||
"url": "'"${DOWNLOAD_URL}"'"
|
||||
}
|
||||
}'
|
||||
@@ -0,0 +1,102 @@
|
||||
# KIWI Image Builder Configurations
|
||||
|
||||
Dieses Repository enthält Konfigurationen zur Erstellung von angepassten Betriebssystem-Images mit dem **KIWI Image Appliance Builder (KIWI-NG)**. Die fertigen Images werden automatisiert über eine CI/CD-Pipeline gebaut und direkt in ein Harvester-Cluster hochgeladen.
|
||||
|
||||
## Repository-Struktur
|
||||
|
||||
```text
|
||||
├── .gitea/
|
||||
│ └── workflows/
|
||||
│ └── kiwi-build.yaml # Gitea Actions Workflow für Linting, Build und Deploy
|
||||
├── opensuse-leap-16-minimal/
|
||||
│ ├── Minimal.kiwi # KIWI-Bildbeschreibung (XML) mit Profilen und Paketen
|
||||
│ └── config.sh # Konfigurationsskript für die Chroot-Phase des Builds
|
||||
├── renovate.json # Konfiguration für den Renovate Bot
|
||||
└── README.md # Dieses Dokument
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enthaltene Images
|
||||
|
||||
### 1. openSUSE Leap 16.0 Minimal (`opensuse-leap-16-minimal`)
|
||||
|
||||
Dieses Verzeichnis enthält die Konfiguration für ein minimales openSUSE Leap 16.0 Image. Es stehen zwei Profile zur Verfügung:
|
||||
|
||||
| Profil | Zielplattform | Dateisystem | Format | Firmware | Besonderheiten |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `kvm-and-xen` | KVM & Xen Hypervisoren | `btrfs` | `qcow2` | UEFI | Inklusive Snapper-Snapshots, Rollback-Helper, Firewalld und `jeos-firstboot` |
|
||||
| `Cloud` (Default in CI) | Cloud-Umgebungen (z. B. Harvester) | `xfs` | `qcow2` | UEFI | Inklusive `cloud-init`, `qemu-guest-agent` und optimierter serieller Konsole |
|
||||
|
||||
#### Wichtige Voreinstellungen in `config.sh`:
|
||||
- **Zeitzone & Keymap:** Standardmäßig auf `Europe/Zurich` und Tastaturlayout `us` konfiguriert.
|
||||
- **Hostname:** Voreingestellt auf `rke2-node`.
|
||||
- **Systemd Firstboot:** Die Datei `/etc/machine-id` wird auf `uninitialized` gesetzt, um systemd zu signalisieren, dass Firstboot-Presets ausgeführt werden sollen.
|
||||
- **Dienste:** `sshd`, `NetworkManager` (falls vorhanden) und `chronyd` werden automatisch aktiviert.
|
||||
- **Snapper (nur für `kvm-and-xen`):** Vorkonfiguriert ohne Timeline-Snapshots (`TIMELINE_CREATE="no"`) und mit optimierten Limits für automatische Aufräumarbeiten.
|
||||
- **Speicheroptimierung:** Deaktivierung der Installation von Dokumentationen (`rpm.install.excludedocs = yes`) sowie Deaktivierung von empfohlenen Paketen (`solver.onlyRequires = true`) in `/etc/zypp/zypp.conf`.
|
||||
|
||||
---
|
||||
|
||||
## Lokales Bauen der Images
|
||||
|
||||
Um die Images lokal auf einem Linux-Host zu bauen, wird `kiwi-ng` benötigt.
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
1. Installiere KIWI-NG auf deinem Host-System:
|
||||
```bash
|
||||
# Auf openSUSE/SUSE
|
||||
sudo zypper in python3-kiwi
|
||||
```
|
||||
2. Stelle sicher, dass Virtualisierungsunterstützung und KVM aktiviert sind (KIWI nutzt intern chroot und mountet loop devices).
|
||||
|
||||
### Build-Befehle
|
||||
|
||||
Führe den Build-Befehl im Root-Verzeichnis des Repositories aus:
|
||||
|
||||
#### KVM & Xen Profil (`btrfs`):
|
||||
```bash
|
||||
sudo kiwi-ng --profile kvm-and-xen system build \
|
||||
--description ./opensuse-leap-16-minimal \
|
||||
--target-dir ./build-kvm
|
||||
```
|
||||
|
||||
#### Cloud Profil (`xfs`):
|
||||
```bash
|
||||
sudo kiwi-ng --profile Cloud system build \
|
||||
--description ./opensuse-leap-16-minimal \
|
||||
--target-dir ./build-cloud
|
||||
```
|
||||
|
||||
Die fertigen `.qcow2`-Images und die Metadaten werden im angegebenen `--target-dir` abgelegt.
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Pipeline (Gitea Actions)
|
||||
|
||||
Das Repository ist für Gitea Actions vorkonfiguriert (`.gitea/workflows/kiwi-build.yaml`). Der Workflow läuft auf einem Runner mit dem Label `kiwi-builder` und wird bei Pushes/Pull-Requests auf `main` oder `master` sowie bei Tag-Pushes mit dem Muster `v*` gestartet. Er führt folgende Schritte aus:
|
||||
|
||||
1. **RNG Schema-Validierung (Linting):**
|
||||
Validiert die XML-Struktur von `Minimal.kiwi` gegen das offizielle KIWI-RNG-Schema (`kiwi.rng`), um Konfigurationsfehler vor dem Bauen zu vermeiden.
|
||||
2. **Build:**
|
||||
Baut das Image mit dem Profil `Cloud` im privilegierten Docker-Container (`registry.opensuse.org/opensuse/bci/kiwi:10`).
|
||||
3. **Bundling:**
|
||||
Paketiert die Ergebnisse und benennt sie passend zur kurzen Commit-SHA (Short-SHA).
|
||||
4. **Upload Image Artifact:**
|
||||
Archiviert das gebaute Image als Gitea-Artefakt mit der Short-SHA im Namen.
|
||||
5. **Harvester-Upload:**
|
||||
Lädt das fertige Image über die Harvester REST API direkt in den Ziel-Namespace des Harvester-Clusters hoch. Wenn die Pipeline durch einen Tag-Push gestartet wurde, entspricht der Image-Name dem Tag-Namen (z. B. `leap-16-minimal-v1.0.0`), ansonsten wird die Short-SHA verwendet.
|
||||
6. **Gitea-Release-Erstellung (nur bei Tag-Pushes):**
|
||||
Wenn der Push einen Git-Tag (z. B. `v1.0.0`) betrifft, wird automatisch ein Gitea-Release erstellt und das Image-File aus `./dist/*` als Release-Asset angehängt.
|
||||
|
||||
### Erforderliche Secrets für die Pipeline:
|
||||
- `HARVESTER_TOKEN`: API-Token zur Authentifizierung am Harvester-Cluster.
|
||||
|
||||
Die Gitea-Release-Erstellung nutzt das standardmäßig bereitgestellte `GITHUB_TOKEN`. Die Cluster-URL für Harvester ist im Workflow als `https://harvester.ui` hinterlegt.
|
||||
|
||||
---
|
||||
|
||||
## Updates & Dependency Management
|
||||
|
||||
Dieses Repository verwendet **Renovate**, um Paketquellen, Basis-Images und GitHub-Aktionen automatisch auf dem neuesten Stand zu halten. Die Steuerung erfolgt über die Datei `renovate.json`.
|
||||
@@ -6,13 +6,18 @@
|
||||
<contact>crc@suse.com</contact>
|
||||
<specification>openSUSE Leap 16.0 Minimal</specification>
|
||||
</description>
|
||||
|
||||
<profiles>
|
||||
<profile name="kvm-and-xen" description="Minimal for KVM and Xen" arch="x86_64"/>
|
||||
<profile name="Cloud" description="Minimal for Cloud" arch="aarch64,x86_64"/>
|
||||
</profiles>
|
||||
|
||||
<preferences profiles="kvm-and-xen">
|
||||
<version>16.0.0</version>
|
||||
<packagemanager>zypper</packagemanager>
|
||||
<locale>en_US</locale>
|
||||
<keytable>us</keytable>
|
||||
<timezone>Europe/Zurich</timezone>
|
||||
<bootsplash-theme>openSUSE</bootsplash-theme>
|
||||
<bootloader-theme>openSUSE</bootloader-theme>
|
||||
<rpm-excludedocs>true</rpm-excludedocs>
|
||||
@@ -32,9 +37,11 @@
|
||||
<size unit="G">24</size>
|
||||
</type>
|
||||
</preferences>
|
||||
|
||||
<preferences profiles="Cloud">
|
||||
<version>16.0.0</version>
|
||||
<packagemanager>zypper</packagemanager>
|
||||
<locale>en_US</locale>
|
||||
<keytable>us</keytable>
|
||||
<timezone>Europe/Zurich</timezone>
|
||||
<bootsplash-theme>openSUSE</bootsplash-theme>
|
||||
@@ -95,23 +102,17 @@
|
||||
<package name="snapper"/>
|
||||
<package name="jeos-firstboot"/>
|
||||
<package name="firewalld"/>
|
||||
<package name="grub2-snapper-plugin"/>
|
||||
<package name="xen-tools-domU" arch="x86_64"/>
|
||||
<package name="xen-libs" arch="x86_64"/>
|
||||
</packages>
|
||||
<packages type="image" profiles="kvm-and-xen,Cloud">
|
||||
<package name="shim" arch="aarch64,x86_64"/>
|
||||
<package name="grub2"/>
|
||||
<package name="grub2-branding-openSUSE" arch="aarch64,x86_64"/>
|
||||
<package name="grub2-arm64-efi" arch="aarch64"/>
|
||||
<package name="grub2-s390x-emu" arch="s390x"/>
|
||||
<package name="grub2-x86_64-efi" arch="x86_64"/>
|
||||
<package name="patterns-base-bootloader"/>
|
||||
<package name="grub2-powerpc-ieee1275" arch="ppc64le"/>
|
||||
</packages>
|
||||
<packages type="image" profiles="kvm-and-xen">
|
||||
<package name="grub2-snapper-plugin"/>
|
||||
<package name="xen-tools-domU" arch="x86_64"/>
|
||||
<package name="xen-libs" arch="x86_64"/>
|
||||
</packages>
|
||||
<packages type="image" profiles="kvm-and-xen,Cloud">
|
||||
<package name="kernel-default-base"/>
|
||||
<package name="qemu-guest-agent"/>
|
||||
</packages>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
#======================================
|
||||
# Functions...
|
||||
#--------------------------------------
|
||||
@@ -64,19 +64,10 @@ baseSetRunlevel 3
|
||||
#--------------------------------------
|
||||
suseImportBuildKey
|
||||
|
||||
# 1. Alle Locale-Variablen (inkl. LC_MESSAGES) vollständig setzen
|
||||
cat <<'EOF' > /etc/locale.conf
|
||||
LANG=en_US.UTF-8
|
||||
LC_MESSAGES=en_US.UTF-8
|
||||
LC_ALL=en_US.UTF-8
|
||||
EOF
|
||||
|
||||
# 2. Keymap und Hostname vordefinieren
|
||||
echo "KEYMAP=us" > /etc/vconsole.conf
|
||||
# 1. Hostname vordefinieren
|
||||
echo "rke2-node" > /etc/hostname
|
||||
ln -sf /usr/share/zoneinfo/Europe/Zurich /etc/localtime
|
||||
|
||||
# 3. Der entscheidende Trick für systemd: "Preset" als initialisiert markieren
|
||||
# 2. Der entscheidende Trick für systemd: "Preset" als initialisiert markieren
|
||||
# Eine leere /etc/machine-id ODER /etc/machine-info signalisiert systemd,
|
||||
# dass Firstboot bereits gelaufen ist.
|
||||
echo "uninitialized" > /etc/machine-id
|
||||
|
||||
Reference in New Issue
Block a user