diff --git a/.github/workflows/_build-bootc.yaml b/.github/workflows/_build-bootc.yaml index c0982fc..c554175 100644 --- a/.github/workflows/_build-bootc.yaml +++ b/.github/workflows/_build-bootc.yaml @@ -4,66 +4,59 @@ run-name: "Build OCI container - ${{ github.actor }}" on: workflow_call: inputs: - runner-group: - description: 'Type the runner group' - required: true - default: 'private-runners-yuntae' - type: string - runner-label: - description: 'Type label of runner' - required: true - default: 'ytminipc001' - type: string oci_registry: - description: 'Type the OCI registry you want to use. e.g. `ghcr.io`, `quay.io`,`docker.io`' + description: 'OCI registry you want to use. e.g. `ghcr.io`, `quay.io`,`docker.io`' required: true default: 'quay.io' type: string oci_image_repo: description: 'Type the image repository path in OCI registry you want to push (`{tenancy-namespace}/{repo-name}`)' required: true - default: 'teamthepioneers/immutable-os-bootc' + default: 'yuntae/yob' type: string oci_image_tag: description: 'Type the image tag you want to use' required: true default: 'latest' type: string + target-interface: + description: 'Type the target interface you want to build (e.g. `core`, `desktop`, `all`)' + required: true + default: 'all' + type: string workflow_dispatch: inputs: - runner-group: - description: 'Type the runner group' - required: true - default: 'private-runners-yuntae' - type: string - runner-label: - description: 'Type label of runner' - required: true - default: 'ytminipc001' - type: string oci_registry: - description: 'Type the OCI registry you want to use. e.g. `ghcr.io`, `quay.io`,`docker.io`' + description: 'Choose the OCI registry you want to use.' required: true + options: + - ghcr.io + - quay.io + - docker.io default: 'quay.io' - type: string + type: choice oci_image_repo: description: 'Type the image repository path in OCI registry you want to push (`{tenancy-namespace}/{repo-name}`)' required: true - default: 'teamthepioneers/immutable-os-bootc' + default: 'yuntae/yob' type: string oci_image_tag: description: 'Type the image tag you want to use' required: true default: 'latest' type: string + target-interface: + description: 'Type the target interface you want to build (e.g. `core`, `desktop`, `all`)' + required: true + default: 'all' + type: string jobs: - build-oci-bootc-image: + build-bootc: runs-on: - group: ${{ inputs.runner-group }} labels: - - ${{ inputs.runner-label }} + - bootc-builder steps: - name: Verify prerequisites @@ -82,23 +75,28 @@ jobs: OCI_REGISTRY_USERNAME: ${{ secrets.OCI_REGISTRY_BOT_USERNAME }} OCI_REGISTRY_PASSWORD: ${{ secrets.OCI_REGISTRY_BOT_PASSWORD }} - - name: Build OCI image + - name: Build bootc run: | - echo "::group::Build OCI image:" - make build-oci-bootc-image + echo "::group::Build bootc:" + make build-bootc echo "::endgroup::" env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} GIT_COMMIT_HASH: ${{ github.sha }} + TARGET_INTERFACE: ${{ inputs.target-interface }} - - name: Push OCI image to registry + - name: Push bootc image to registry + if: ${{ github.event_name == 'workflow_dispatch' }} run: | - echo "::group::Push OCI image to registry:" - make push-oci-image + echo "::group::Push bootc image to registry:" + make push-bootc echo "::endgroup::" + echo "## Image path" | tee -a $GITHUB_STEP_SUMMARY + echo "\`${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-${TARGET_INTERFACE}\` (all: It creates both core and desktop)" | tee -a $GITHUB_STEP_SUMMARY env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} + TARGET_INTERFACE: ${{ inputs.target-interface }} diff --git a/.github/workflows/_convert-to-disk.yaml b/.github/workflows/_convert-to-disk.yaml index 343ffc1..620d6e5 100644 --- a/.github/workflows/_convert-to-disk.yaml +++ b/.github/workflows/_convert-to-disk.yaml @@ -4,60 +4,68 @@ run-name: "Convert OCI Container to Disk Image - ${{ github.actor }}" on: workflow_dispatch: inputs: - runner-group: - description: 'Type the runner group' - required: true - default: 'private-runners-yuntae' - type: string - runner-label: - description: 'Type label of runner' - required: true - default: 'ytminipc001' - type: string oci_registry: - description: 'Type the OCI registry you want to use. e.g. `ghcr.io`, `quay.io`,`docker.io`' + description: 'Choose the OCI registry you want to use.' required: true + options: + - ghcr.io + - quay.io + - docker.io default: 'quay.io' - type: string + type: choice oci_image_repo: description: 'Type the image repository path in OCI registry you want to push (`{tenancy-namespace}/{repo-name}`)' required: true - default: 'teamthepioneers/immutable-os-bootc' + default: 'yuntae/yob' type: string oci_image_tag: description: 'Type the image tag you want to use' required: true default: 'latest' type: string + target-interface: + description: 'Type the target interface you want to build (e.g. `core`, `desktop`, `all`)' + required: true + default: 'all' + type: string default_disk: description: 'Type disk name you want to use as rootfs (e.g `sda`, `nvme0n1`)' required: true default: 'sda' type: string disk_format: - description: 'Type the disk format you want to convert the OCI image into (e.g. `qcow2`, `iso`, `raw`)' + description: 'Choose disk format you want to convert the OCI image into' required: true + options: + - iso + - ami default: 'iso' - type: string + type: choice rootfs: - description: 'Type the root filesystem you want to use (e.g. `ext4`, `xfs`, `btrfs`)' - required: false + description: 'Choose root filesystem you want to use' + required: true + options: + - btrfs + - ext4 + - xfs default: 'btrfs' + type: choice + aws_s3_bucket: + description: '(Only for `ami` disk format) Type the AWS S3 bucket name you want to use' + required: false + default: 'none' type: string jobs: convert-to-disk-image: runs-on: - group: ${{ inputs.runner-group }} labels: - - ${{ inputs.runner-label }} + - bootc-builder steps: - name: Verify prerequisites run: | make --version &> /dev/null || { echo "Make is not installed"; exit 1; } - [[ -d /var/lib/containers/storage ]] || \ - { echo "no /var/lib/containers/storage found. Please install Podman or Buildah and pull any container"; exit 1; } docker --version &> /dev/null || { echo "Docker is not installed"; exit 1; } - name: Checkout Repository @@ -71,54 +79,63 @@ jobs: OCI_REGISTRY_PASSWORD: ${{ secrets.OCI_REGISTRY_BOT_PASSWORD }} OCI_REGISTRY: ${{ inputs.oci_registry }} - - name: Pull OCI image + - name: Configure AWS credentials + if: ${{ inputs.disk_format == 'ami' }} + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ vars.AWS_REGION }} + + - name: Pull bootc image from OCI registry run: | - echo "::group::Pull OCI image:" - make pull-oci-image + echo "::group::Pull bootc image from OCI registry:" + make pull-bootc echo "::endgroup::" env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} + TARGET_INTERFACE: ${{ inputs.target-interface }} - - name: Save image as tar + - name: Save image as tgz run: | - make save-image-as-tar + echo "::group::Save image as tgz:" + make save-image-as-tgz + echo "::endgroup::" env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} + TARGET_INTERFACE: ${{ inputs.target-interface }} - name: Convert OCI image into specified disk format run: | echo "::group::Convert OCI image into specified disk format:" - make convert-to-disk-image + make convert-to-${DISK_FORMAT} echo "::endgroup::" env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} + TARGET_INTERFACE: ${{ inputs.target-interface }} DISK_FORMAT: ${{ inputs.disk_format }} DEFAULT_DISK: ${{ inputs.default_disk }} - DEFAULT_USER_NAME: ${{ secrets.DEFAULT_USER_NAME }} - DEFAULT_USER_PASSWD: ${{ secrets.DEFAULT_USER_PASSWD }} ROOTFS: ${{ inputs.rootfs }} + AWS_S3_BUCKET: ${{ inputs.aws_s3_bucket }} + AWS_REGION: ${{ vars.AWS_REGION }} + AWS_ACCESS_KEY_ID: ${{ vars.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - name: Save disk format image + - name: Save iso format image + if: ${{ inputs.disk_format == 'iso' }} run: | sudo chown -R $USER:$USER ./image-builder-output - IMAGE_DIGEST=$(docker inspect ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG} -f json | \ - jq -r .[0].Digest | cut -d ':' -f2) - [ -z "${IMAGE_DIGEST}" ] || [ "${IMAGE_DIGEST}" == "null" ] && \ - IMAGE_DIGEST=$( - docker buildx imagetools inspect ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG} \ - --format '{{ json .Manifest}}' | \ - jq -r .digest | cut -d ':' -f2) - sudo mkdir -p /opt/bootc-os-disk-images/${IMAGE_DIGEST:0:12} - sudo mv image-builder-output /opt/bootc-os-disk-images/${IMAGE_DIGEST:0:12}/${DISK_FORMAT} + sudo mkdir -p /opt/bootc-os-disk-images/${{ github.run_number }} + sudo mv image-builder-output /opt/bootc-os-disk-images/${{ github.run_number }} sudo rm -rf ./image-builder-output env: OCI_REGISTRY: ${{ inputs.oci_registry }} OCI_IMAGE_REPO: ${{ inputs.oci_image_repo }} OCI_IMAGE_TAG: ${{ inputs.oci_image_tag }} - DISK_FORMAT: ${{ inputs.disk_format }} + TARGET_INTERFACE: ${{ inputs.target-interface }} diff --git a/.github/workflows/dev-debug.yaml b/.github/workflows/dev-debug.yaml index a3dae57..4cbdf72 100644 --- a/.github/workflows/dev-debug.yaml +++ b/.github/workflows/dev-debug.yaml @@ -2,18 +2,11 @@ name: "Workflow for Development & Debugging" run-name: "Dev & Debug Workflow - ${{ github.ref }}" on: - workflow_dispatch: - inputs: - runner-group: - description: 'Select the runner group' - required: true - default: 'Default' - type: string + workflow_dispatch: {} jobs: test: - runs-on: - group: ${{ inputs.runner-group }} + runs-on: ubuntu-latest steps: - name: template run: | diff --git a/.github/workflows/merge_queue.yaml b/.github/workflows/merge_queue.yaml index 4d8e272..3fc274a 100644 --- a/.github/workflows/merge_queue.yaml +++ b/.github/workflows/merge_queue.yaml @@ -49,14 +49,13 @@ jobs: body: commentBody }); - build-oci: + build-bootc: needs: lint-dockerfile if: ${{ github.event.pull_request.draft == false }} - uses: ./.github/workflows/_build-oci-container.yaml + uses: ./.github/workflows/_build-bootc.yaml secrets: inherit with: - runner-group: 'private-runners-yuntae' - runner-label: 'ytminipc001' oci_registry: 'quay.io' - oci_image_repo: 'teamthepioneers/immutable-os-bootc' + oci_image_repo: 'yuntae/yob' oci_image_tag: 'merge-queue-${{ github.event_name }}' + target-interface: 'core' diff --git a/.gitignore b/.gitignore index f9efc54..7868bee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ **/.DS_Store dockerfile-lint.json +*.tar +config.toml +image-builder-output/* diff --git a/Dockerfile b/Dockerfile index 027fe9b..f7b96bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,14 @@ -ARG DEFAULT_BASE="quay.io/fedora/fedora-bootc:42" +ARG BASE_CONTAINER -FROM ${DEFAULT_BASE} AS step-scratch +FROM ${BASE_CONTAINER} AS downloader SHELL ["/bin/bash", "-o", "pipefail", "-c"] -ADD https://download.docker.com/linux/fedora/docker-ce.repo /etc/yum.repos.d/docker-ce.repo - -# See https://docs.fedoraproject.org/en-US/bootc/home-directories -RUN mkdir -p /var/roothome - -RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc \ - && printf "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" \ - | tee /etc/yum.repos.d/vscode.repo > /dev/null - -# Add RPM Fusion repositories -## Refer to https://rpmfusion.org/ RUN dnf install -y \ - https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-"$(rpm -E %fedora)".noarch.rpm \ - https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-"$(rpm -E %fedora)".noarch.rpm - -RUN dnf install -y unzip && \ + unzip && \ dnf clean all && \ rm -rf /var/cache/libdnf5 -FROM step-scratch AS step-external - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - # Install packages from source OCI image # e.g. COPY --from=ghcr.io/astral-sh/uv:0.8.13 /uv /uvx /usr/bin/ @@ -45,35 +27,42 @@ RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/ COPY ./filesystem /tmp/filesystem -FROM step-scratch AS step-final +FROM ${BASE_CONTAINER} AS base + +# See https://docs.fedoraproject.org/en-US/bootc/home-directories +RUN mkdir -p /var/roothome + +RUN curl -fsSL https://download.docker.com/linux/fedora/docker-ce.repo > /etc/yum.repos.d/docker-ce.repo +RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc \ + && printf "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" \ + > /etc/yum.repos.d/vscode.repo + +# Add RPM Fusion repositories (https://rpmfusion.org/) +RUN dnf install -y \ + https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-"$(rpm -E %fedora)".noarch.rpm \ + https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-"$(rpm -E %fedora)".noarch.rpm -# dnf package installation ## See also https://fedoraproject.org/wiki/Changes/UnprivilegedUpdatesAtomicDesktops RUN dnf install -y \ @core \ - @gnome-desktop \ - @firefox \ - @fonts \ - @guest-desktop-agents \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin \ - tailscale \ - systemd-networkd \ - netplan.io \ - vim \ - wireshark \ bash-completion \ code \ - rsync \ fedora-release-ostree-desktop \ + netplan.io \ + rsync \ + tailscale \ + unzip \ + vim \ + wireshark \ && dnf clean all && \ rm -rf /var/cache/libdnf5 -COPY --from=step-external /tmp /tmp - +COPY --from=downloader /tmp /tmp RUN /tmp/external/aws/install && rm -rf /tmp/external/aws # sync {filesystem,external} @@ -81,19 +70,18 @@ RUN cp -a /tmp/filesystem/. / && \ cp -a /tmp/external/. /usr/bin/ && \ rm -rf /tmp/* -RUN dconf update - # systemd settings -# RUN systemctl enable systemd-networkd -# RUN systemctl enable netplan-apply.service # RUN systemctl disable NetworkManager # RUN systemctl disable NetworkManager-wait-online RUN systemctl mask bootc-fetch-apply-updates.timer && \ + systemctl mask firewalld && \ systemctl enable tailscaled && \ systemctl enable docker && \ systemctl enable sshd && \ systemctl set-default graphical.target +FROM base AS core + # static analysis checks RUN bootc container lint @@ -101,9 +89,32 @@ RUN bootc container lint LABEL containers.bootc=1 # See https://specs.opencontainers.org/image-spec/annotations/#pre-defined-annotation-keys ARG GIT_COMMIT_HASH -LABEL org.opencontainers.image.source="https://github.com/teamthepioneers/immutable-os-bootc" -LABEL org.opencontainers.image.url="https://github.com/teamthepioneers/immutable-os-bootc" -LABEL org.opencontainers.image.title="immutable-os-bootc" -LABEL org.opencontainers.image.description="Immutable OS image based on bootc project made by teamthepioneers" +LABEL org.opencontainers.image.source="https://github.com/yureutaejin/yob" +LABEL org.opencontainers.image.url="https://github.com/yureutaejin/yob" +LABEL org.opencontainers.image.title="yob-core" +LABEL org.opencontainers.image.description="YOB Core image based on bootc project made by yureutaejin" +LABEL org.opencontainers.image.authors="github: yureutaejin, linktree: https://linktr.ee/yureutaejin" +LABEL org.opencontainers.image.revision=${GIT_COMMIT_HASH} + +FROM base AS desktop + +RUN dnf install -y \ + @gnome-desktop \ + @firefox \ + @fonts \ + @guest-desktop-agents \ + && dnf clean all && \ + rm -rf /var/cache/libdnf5 + +RUN dconf update + +RUN bootc container lint + +LABEL containers.bootc=1 +ARG GIT_COMMIT_HASH +LABEL org.opencontainers.image.source="https://github.com/yureutaejin/yob" +LABEL org.opencontainers.image.url="https://github.com/yureutaejin/yob" +LABEL org.opencontainers.image.title="yob-gnome" +LABEL org.opencontainers.image.description="YOB GNOME image based on bootc project made by yureutaejin" LABEL org.opencontainers.image.authors="github: yureutaejin, linktree: https://linktr.ee/yureutaejin" LABEL org.opencontainers.image.revision=${GIT_COMMIT_HASH} diff --git a/Makefile b/Makefile index 477edc7..4832e1d 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,25 @@ OCI_REGISTRY ?= quay.io -OCI_IMAGE_REPO ?= teamthepioneers/immutable-os-bootc +OCI_IMAGE_REPO ?= yuntae/yob OCI_IMAGE_TAG ?= latest +TARGET_INTERFACE ?= core OCI_REGISTRY_USERNAME ?= your_username OCI_REGISTRY_PASSWORD ?= your_password -DISK_FORMAT ?= iso DEFAULT_DISK ?= nvme0n1 -DEFAULT_USER_NAME ?= pioneers -DEFAULT_USER_PASSWD ?= pioneers1234 +DEFAULT_USER_NAME ?= yob +DEFAULT_USER_PASSWD ?= yob1234 ROOTFS ?= btrfs ARCH ?= amd64 BIB_CONTAINER ?= quay.io/centos-bootc/bootc-image-builder@sha256:ba8c4bee758b4b816ce0c3a605f55389412edab034918f56982e7893e0b08532 GIT_COMMIT_HASH ?= $(shell git rev-parse HEAD) +SHORT_COMMIT_HASH := $(shell echo ${GIT_COMMIT_HASH} | cut -c1-8) +AWS_ACCESS_KEY_ID ?= your_aws_access_key_id +AWS_SECRET_ACCESS_KEY ?= your_aws_secret_access_key +AWS_S3_BUCKET ?= yob +AWS_REGION ?= us-east-1 -.PHONY: build-oci-bootc-image -build-oci-bootc-image: - docker build \ - --build-arg GIT_COMMIT_HASH=$(GIT_COMMIT_HASH) \ - -t ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG} \ - . +.PHONY: login-public-oci-registry +login-public-oci-registry: + docker login -u=${OCI_REGISTRY_USERNAME} -p=${OCI_REGISTRY_PASSWORD} ${OCI_REGISTRY} .PHONY: lint-dockerfile lint-dockerfile: @@ -25,37 +27,99 @@ lint-dockerfile: jq -r '.' | \ tee dockerfile-lint.json -.PHONY: login-public-oci-registry -login-public-oci-registry: - docker login -u=$(OCI_REGISTRY_USERNAME) -p=$(OCI_REGISTRY_PASSWORD) $(OCI_REGISTRY) +.PHONY: build-bootc +build-bootc: + OCI_REGISTRY=${OCI_REGISTRY} \ + OCI_IMAGE_REPO=${OCI_IMAGE_REPO} \ + OCI_IMAGE_TAG=${OCI_IMAGE_TAG} \ + GIT_COMMIT_HASH=${GIT_COMMIT_HASH} \ + docker buildx bake ${TARGET_INTERFACE} -.PHONY: save-image-as-tar -save-image-as-tar: - docker save -o image-${GIT_COMMIT_HASH:0:8}.tar ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG} +.PHONY: login-public-oci-registry push-bootc +push-bootc: + [[ "${TARGET_INTERFACE}" == "all" ]] && TARGETS="core desktop" || TARGETS="${TARGET_INTERFACE}"; \ + for target in $${TARGETS}; do \ + docker push ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-$${target}; \ + done -.PHONY: push-oci-image -push-oci-image: - docker push $(OCI_REGISTRY)/$(OCI_IMAGE_REPO):${OCI_IMAGE_TAG} +.PHONY: login-public-oci-registry pull-bootc +pull-bootc: + [[ "${TARGET_INTERFACE}" == "all" ]] && TARGETS="core desktop" || TARGETS="${TARGET_INTERFACE}"; \ + for target in $${TARGETS}; do \ + docker pull ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-$${target}; \ + done -.PHONY: pull-oci-image -pull-oci-image: - docker pull $(OCI_REGISTRY)/$(OCI_IMAGE_REPO):${OCI_IMAGE_TAG} +.PHONY: save-image-as-tgz +save-image-as-tgz: + [[ "${TARGET_INTERFACE}" == "all" ]] && TARGETS="core desktop" || TARGETS="${TARGET_INTERFACE}"; \ + for target in $${TARGETS}; do \ + docker save ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-$${target} | \ + pigz > container-tarbells/image-${SHORT_COMMIT_HASH}-$${target}.tar.gz; \ + done # See https://github.com/osbuild/bootc-image-builder -.PHONY: convert-to-disk-image -convert-to-disk-image: - sudo podman load -i image-${GIT_COMMIT_HASH:0:8}.tar +.PHONY: convert-to-iso +convert-to-iso: bib-dind-down bib-dind-up + cp -rf template-iso.toml config.toml sed -i "s|{DEFAULT_DISK}|${DEFAULT_DISK}|g" config.toml - sed -i "s|{DEFAULT_USER_NAME}|${DEFAULT_USER_NAME}|g" config.toml && \ - sed -i "s|{DEFAULT_USER_PASSWD}|${DEFAULT_USER_PASSWD}|g" config.toml && \ - sudo docker run --rm \ - --privileged \ - --security-opt label=type:unconfined_t \ - -v ./image-builder-output:/output \ - -v /var/lib/containers/storage:/var/lib/containers/storage \ - -v ./config.toml:/config.toml:ro \ - $(BIB_CONTAINER) \ - --type $(DISK_FORMAT) \ - --use-librepo=True \ - --rootfs $(ROOTFS) \ - $(OCI_REGISTRY)/$(OCI_IMAGE_REPO):${OCI_IMAGE_TAG} + sed -i "s|{DEFAULT_USER_NAME}|${DEFAULT_USER_NAME}|g" config.toml + sed -i "s|{DEFAULT_USER_PASSWD}|${DEFAULT_USER_PASSWD}|g" config.toml + docker cp config.toml bib-dind:/config.toml + [[ "${TARGET_INTERFACE}" == "all" ]] && TARGETS="core desktop" || TARGETS="${TARGET_INTERFACE}"; \ + for target in $${TARGETS}; do \ + mkdir -p image-builder-output/$${target}; \ + docker exec bib-dind /bin/bash -c " \ + podman load -i container-tarbells/image-${SHORT_COMMIT_HASH}-$${target}.tar.gz; \ + podman run --rm \ + --privileged \ + --security-opt label=type:unconfined_t \ + -v ./image-builder-output/$${target}:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + -v ./config.toml:/config.toml:ro \ + ${BIB_CONTAINER} \ + --type iso \ + --use-librepo=True \ + --rootfs ${ROOTFS} \ + ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-$${target}"; \ + done + $(MAKE) bib-dind-down + +# See https://github.com/osbuild/bootc-image-builder?tab=readme-ov-file#amazon-machine-images-amis +.PHONY: convert-to-ami +convert-to-ami: bib-dind-down bib-dind-up + cp -rf template-ami.toml config.toml + sed -i "s|{DEFAULT_USER_NAME}|${DEFAULT_USER_NAME}|g" config.toml + sed -i "s|{DEFAULT_USER_PASSWD}|${DEFAULT_USER_PASSWD}|g" config.toml + docker cp config.toml bib-dind:/config.toml + AWS_AMI_NAME=${SHORT_COMMIT_HASH}-core; \ + docker exec bib-dind /bin/bash -c " \ + podman load -i container-tarbells/image-${SHORT_COMMIT_HASH}-core.tar.gz; \ + podman run --rm \ + --privileged \ + --security-opt label=type:unconfined_t \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + -v ./config.toml:/config.toml:ro \ + --env AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ + --env AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ + ${BIB_CONTAINER} \ + --type ami \ + --rootfs ${ROOTFS} \ + --aws-ami-name $${AWS_AMI_NAME} \ + --aws-bucket ${AWS_S3_BUCKET} \ + --aws-region ${AWS_REGION} \ + ${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-core" + $(MAKE) bib-dind-down + +.PHONY: bib-dind-up +bib-dind-up: + docker run \ + -itd \ + --privileged \ + --name bib-dind \ + -v ./container-tarbells:/container-tarbells \ + -v ./image-builder-output:/image-builder-output \ + quay.io/containers/podman:latest + +.PHONY: bib-dind-down +bib-dind-down: + docker rm -f bib-dind || true diff --git a/README.md b/README.md index 9c35a31..5a8f15f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Immutable OS - bootc +# YOB : Your own OS using bootc ## Index @@ -6,7 +6,7 @@ - [Contributors](#contributors) - [Introduction](#introduction) - [Overall pipeline workflows](#overall-pipeline-workflows) -- [Quick Start](#quick-start-for-local-hands-on) +- [Quick Start](#quick-start) ## Translation @@ -24,7 +24,9 @@ Chunsoo
## Introduction -Repository for building Immutable OS using [bootc](https://bootc-dev.github.io/) +Base project YOB referenced + +- [bootc](https://bootc-dev.github.io/) bootc container @@ -43,74 +45,40 @@ So we can create OS image using OCI container techniques which is familiar to mo ## Overall pipeline workflows -Currently, this project is configured by following diagram below. - -```mermaid - sequenceDiagram - autonumber - participant container_builder as Container Builder - participant disk_converter as Disk Converter - participant oci_registry as OCI Registry - participant disk_storage as Disk Storage - participant git_repo as Git Repository - participant production as Production Env - - container_builder ->> git_repo: Checkout source - container_builder ->> oci_registry: Pull base container - container_builder ->> container_builder: Build with Containerfile - container_builder ->> oci_registry: Push built container - - disk_converter ->> oci_registry: Pull container - disk_converter ->> disk_converter: Convert container to disk image - disk_converter ->> disk_storage: Store disk image - - production ->> disk_storage: Retrieve disk image - production ->> production: Deploy disk image -``` - -## Quick Start (for local Hands-on) +Currently, this project referred RHEL image mode pipeline diagram. + +- [what-image-mode-means-users-rhel-edge](https://www.redhat.com/en/blog/what-image-mode-means-users-rhel-edge) + +![Image mode pipeline for RHEL](https://www.redhat.com/rhdc/managed-files/image2_132.png) + +## Quick Start Quick start without editing few configurations. -This section targets that machine to deploy OS is Bare Metal (Laptop, Desktop, etc.) ### Prerequisites -- OS - - Linux (RHEL Family is recommended) -- Podman - - BIB(bootc-image-builder) uses `/var/lib/containers/storage` of host OS which podman, buildah, skopeo use. - - `[[ -d /var/lib/containers/storage ]] || echo "Please install podman/buildah and pull any container first"` - Docker - - `curl -fsSL https://get.docker.com | sh` - Make - - To use `make` command for defined [tasks](./Makefile) - OCI Registry - - Get your account of OCI Registry (e.g. DockerHub, Quay.io, etc.) - - Currently, Private Registry is not supported (will update guideline soon) + - Get your account of OCI Registry (e.g. Docker Hub, Quay.io, etc.) - Just define local variables in host shell without fixing Makefile (Refer to default value in [Makefile](./Makefile)) - - OCI_REGISTRY - - OCI_IMAGE_REPO - - OCI_IMAGE_TAG - - OCI_REGISTRY_USERNAME - - OCI_REGISTRY_PASSWORD - - DEFAULT_DISK (e.g. nvme0n1, sda...) -- Machine to run OS you will create - - Bare Metal (Laptop, Desktop, etc.) - - Virtual Machine - - Cloud -### 1. Build OCI Container +### 1. Build bootc + +It will build OCI container based on bootc project and push it to your OCI Registry. -1. `make login-public-oci-registry` -2. `make build-oci-bootc-image` -3. `make push-oci-bootc-image` +1. `make build-bootc` +2. `make push-bootc` -### 2. Convert OCI Container to Bootable Disk Image +### 2. (Just for first boot) Convert bootc to disk format -1. `make save-image-as-tar` -2. `make convert-to-disk-image` +- `make pull-bootc-image` + - Pull bootc image from OCI Registry (if you haven't yet) +- `make save-image-as-tgz` +- `make convert-to-{iso,ami,qcow2}` + - Currently, only iso and ami format is tested. -### 3. Make bootable Disk +### 3. Flash bootable disk There are too many ways to make bootable disk. Just leave Bare Metal case for now. @@ -124,17 +92,19 @@ Just leave Bare Metal case for now. Boot with created bootable disk Since we've set host's config with [config.toml](./config.toml) already, Just wait until first booting is done. -### 5. Rollback/Upgrade/Switch OS +### 5. (On target machine) Rollback/Upgrade/Switch OS + +> [!NOTE] +> No need to make bootable disk again after first boot. -No need to make bootable disk again. -If you push new image to OCI Registry, It will be available in next reboot. -Just choose command and run it on running OS and reboot. +Simply push the new image to the OCI Registry, and the OS switching will be complete after downloading and rebooting. - `sudo bootc upgrade` - Upgrade to latest pushed image with same tag you booted - `sudo bootc switch OCI_REGISTRY/OCI_IMAGE_REPO:OCI_IMAGE_TAG` - Switch to specified bootc image + - You can switch any bootc image if it is accessible - e.g. `sudo bootc switch quay.io/fedora/fedora-bootc:latest` - `sudo bootc rollback` - Rollback to previous image - - (Important) OS will keep 1 previous image + - (Important) OS will keep just 1 previous version of image for rollback diff --git a/container-tarbells/.gitkeep b/container-tarbells/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..f200f3e --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,45 @@ +variable "OCI_REGISTRY" { + default = "registry_name" +} + +variable "OCI_IMAGE_REPO" { + default = "namespace/repo" +} + +variable "OCI_IMAGE_TAG" { + default = "latest" +} + +variable "GIT_COMMIT_HASH" { + default = "sha-unknown" +} + +variable "BASE_CONTAINER" { + default = "quay.io/fedora/fedora-bootc:42" +} + +target "core" { + dockerfile = "Dockerfile" + context = "." + target = "core" + tags = ["${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-core"] + args = { + GIT_COMMIT_HASH = "${GIT_COMMIT_HASH}", + BASE_CONTAINER = "${BASE_CONTAINER}" + } +} + +target "desktop" { + dockerfile = "Dockerfile" + context = "." + target = "desktop" + tags = ["${OCI_REGISTRY}/${OCI_IMAGE_REPO}:${OCI_IMAGE_TAG}-desktop"] + args = { + GIT_COMMIT_HASH = "${GIT_COMMIT_HASH}", + BASE_CONTAINER = "${BASE_CONTAINER}" + } +} + +group "all" { + targets = ["core", "desktop"] +} diff --git a/docs/README-KO.md b/docs/README-KO.md index 772a3aa..0616c00 100644 --- a/docs/README-KO.md +++ b/docs/README-KO.md @@ -1,6 +1,4 @@ -# Immutable OS - bootc - -## Translation +# YOB : Your own OS using bootc ## Index @@ -8,7 +6,7 @@ - [Contributors](#contributors) - [Introduction](#introduction) - [Overall pipeline workflows](#overall-pipeline-workflows) -- [Quick Start](#quick-start-for-local-hands-on) +- [Quick Start](#quick-start) ## Contributors @@ -22,7 +20,9 @@ Chunsoo
## Introduction -[bootc](https://bootc-dev.github.io/)를 사용하여 Immutable OS를 구축하기 위한 저장소입니다. +Base project YOB referenced + +- [bootc](https://bootc-dev.github.io/) bootc container @@ -41,74 +41,37 @@ bootc 프로젝트는 이 방법을 역으로 사용하여 Linux 컨테이너 ## Overall pipeline workflows -현재 이 프로젝트는 아래 다이어그램과 같이 구성되어 있습니다. - -```mermaid - sequenceDiagram - autonumber - participant container_builder as Container Builder - participant disk_converter as Disk Converter - participant oci_registry as OCI Registry - participant disk_storage as Disk Storage - participant git_repo as Git Repository - participant production as Production Env - - container_builder ->> git_repo: Checkout source - container_builder ->> oci_registry: Pull base container - container_builder ->> container_builder: Build with Containerfile - container_builder ->> oci_registry: Push built container - - disk_converter ->> oci_registry: Pull container - disk_converter ->> disk_converter: Convert container to disk image - disk_converter ->> disk_storage: Store disk image - - production ->> disk_storage: Retrieve disk image - production ->> production: Deploy disk image -``` - -## Quick Start (for local hands-on) +현재 이 프로젝트는 RHEL 이미지 모드 파이프라인 다이어그램을 참조합니다. + +- [what-image-mode-means-users-rhel-edge](https://www.redhat.com/en/blog/what-image-mode-means-users-rhel-edge) + +![Image mode pipeline for RHEL](https://www.redhat.com/rhdc/managed-files/image2_132.png) + +## Quick Start 구성을 거의 편집하지 않고 빠르게 시작하는 방법입니다. -이 섹션은 OS를 배포할 머신이 베어 메탈(노트북, 데스크톱 등)인 경우를 대상으로 합니다. ### 사전 요구사항 -- OS - - Linux (RHEL 계열 권장) -- Podman - - BIB(bootc-image-builder)는 podman, buildah, skopeo가 사용하는 호스트 OS의 `/var/lib/containers/storage`를 사용합니다. - - `[[ -d /var/lib/containers/storage ]] || echo "Please install podman/buildah and pull any container first"` - Docker - - `curl -fsSL https://get.docker.com | sh` - Make - - 정의된 [작업](./Makefile)에 `make` 명령을 사용하기 위해 - OCI Registry - - OCI Registry 계정을 취득하세요 (예: DockerHub, Quay.io 등) - - 현재 Private Registry는 지원되지 않습니다 (곧 가이드라인을 업데이트할 예정) -- Makefile을 수정하지 않고 호스트 쉘에서 로컬 변수를 정의하기만 하면 됩니다 ([Makefile](./Makefile)의 기본값 참조) - - OCI_REGISTRY - - OCI_IMAGE_REPO - - OCI_IMAGE_TAG - - OCI_REGISTRY_USERNAME - - OCI_REGISTRY_PASSWORD - - DEFAULT_DISK (예: nvme0n1, sda...) -- 생성할 OS를 실행할 머신 - - Bare Metal (노트북, 데스크톱 등) - - Virtual Machine - - Cloud + - OCI Registry 계정을 취득하세요 (예: Docker Hub, Quay.io 등) +- 호스트 셸에서 로컬 변수를 정의하기만 하면 됩니다. Makefile을 수정할 필요는 없습니다 (기본값은 [Makefile](./Makefile) 참조). + +### 1. Build bootc -### 1. OCI 컨테이너 빌드 +bootc 프로젝트 기반 OCI 컨테이너를 빌드하고 이를 OCI Registry에 푸시합니다. -1. `make login-public-oci-registry` -2. `make build-oci-bootc-image` -3. `make push-oci-bootc-image` +1. `make build-bootc` +2. `make push-bootc` -### 2. OCI 컨테이너를 부팅 가능한 디스크 이미지로 변환 +### 2. (Just for first boot) Convert bootc to disk format -1. `make save-image-as-tar` -2. `make convert-to-disk-image` +- `make convert-to-{iso,ami,qcow2}` + - 현재는 iso, ami 포맷만 테스트되었습니다. -### 3. 부팅 가능한 디스크 만들기 +### 3. Flash bootable disk 부팅 가능한 디스크를 만드는 방법은 너무 많습니다. 지금은 베어 메탈 경우만 남겨두겠습니다. @@ -117,16 +80,17 @@ bootc 프로젝트는 이 방법을 역으로 사용하여 Linux 컨테이너 - [Ventoy](https://www.ventoy.net/en/index.html) - [BalenaEtcher](https://etcher.balena.io/) -### 4. OS 부팅 +### 4. Boot OS 생성된 부팅 가능한 디스크로 부팅합니다 이미 [config.toml](./config.toml)로 호스트 구성을 설정했으므로, 첫 번째 부팅이 완료될 때까지 기다리기만 하면 됩니다. -### 5. OS 롤백/업그레이드/전환 +### 5. (On target machine) Rollback/Upgrade/Switch OS + +> [!NOTE] +> 첫 부팅 이후라면 부팅 가능한 디스크를 다시 만들 필요가 없습니다. -부팅 가능한 디스크를 다시 만들 필요가 없습니다. -새 이미지를 OCI Registry에 푸시하면 다음 재부팅 시 사용할 수 있습니다. -명령을 선택하여 실행 중인 OS에서 실행하고 재부팅하기만 하면 됩니다. +새 이미지를 OCI Registry에 push하기만하면, 다운로드하고 재부팅하는 것으로 OS 전환이 완료됩니다. - `sudo bootc upgrade` - 부팅한 것과 동일한 태그의 최신 푸시된 이미지로 업그레이드 @@ -135,4 +99,4 @@ bootc 프로젝트는 이 방법을 역으로 사용하여 Linux 컨테이너 - 예: `sudo bootc switch quay.io/fedora/fedora-bootc:latest` - `sudo bootc rollback` - 이전 이미지로 롤백 - - (중요) OS는 1개의 이전 이미지를 유지합니다 + - (중요) OS는 단 1개의 이전 버전 이미지만을 유지합니다 diff --git a/filesystem/etc/selinux/config b/filesystem/etc/selinux/config new file mode 100644 index 0000000..583097b --- /dev/null +++ b/filesystem/etc/selinux/config @@ -0,0 +1,26 @@ +# This file controls the state of SELinux on the system. +# SELINUX= can take one of these three values: +# enforcing - SELinux security policy is enforced. +# permissive - SELinux prints warnings instead of enforcing. +# disabled - No SELinux policy is loaded. +# See also: +# https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-selinux/#getting-started-with-selinux-selinux-states-and-modes +# +# NOTE: In earlier Fedora kernel builds, SELINUX=disabled would also +# fully disable SELinux during boot. If you need a system with SELinux +# fully disabled instead of SELinux running with no policy loaded, you +# need to pass selinux=0 to the kernel command line. You can use grubby +# to persistently set the bootloader to boot with selinux=0: +# +# grubby --update-kernel ALL --args selinux=0 +# +# To revert back to SELinux enabled: +# +# grubby --update-kernel ALL --remove-args selinux +# +SELINUX=permissive +# SELINUXTYPE= can take one of these three values: +# targeted - Targeted processes are protected, +# minimum - Modification of targeted policy. Only selected processes are protected. +# mls - Multi Level Security protection. +SELINUXTYPE=targeted diff --git a/template-ami.toml b/template-ami.toml new file mode 100644 index 0000000..23ee5ed --- /dev/null +++ b/template-ami.toml @@ -0,0 +1,4 @@ +[[customizations.user]] +name = "{DEFAULT_USER_NAME}" +password = "{DEFAULT_USER_PASSWD}" +groups = ["wheel"] diff --git a/config.toml b/template-iso.toml similarity index 100% rename from config.toml rename to template-iso.toml