Compare commits
16 commits
ubuntu-220
...
main
Author | SHA1 | Date | |
---|---|---|---|
893514cbad | |||
5df3bdf743 | |||
01277e9159 | |||
f0e5a4f260 | |||
0578333f9d | |||
3d890d7e2f | |||
3cce76e206 | |||
8f54762625 | |||
cc6dcd8aa3 | |||
948294ae2f | |||
0fea8d3168 | |||
1646584afc | |||
35080fd3b0 | |||
8315904427 | |||
5b099f59e6 | |||
32ffc099d3 |
9 changed files with 246 additions and 76 deletions
|
@ -2,33 +2,59 @@ on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "*-v*"
|
- "*-v*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY_ENDPOINT: host.containers.internal:5000
|
REGISTRY_ENDPOINT: host.containers.internal:5000
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-images:
|
pre-run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: imagefactory-latest
|
||||||
strategy:
|
steps:
|
||||||
matrix:
|
- uses: https://forge.karnov.club/marc/push-status-to-discord-action@main
|
||||||
image-name: ['ubuntu-2204']
|
with:
|
||||||
|
webhook-url: ${{secrets.DISCORD_WEBHOOK_URL}}
|
||||||
|
status: "Started"
|
||||||
|
init: true
|
||||||
|
build-runner:
|
||||||
|
needs: [pre-run]
|
||||||
|
runs-on: imagefactory-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: 3.12
|
||||||
- name: Login to Registry
|
- name: Login to Registry
|
||||||
run: podman login -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_TOKEN }} ${{ env.REGISTRY_ENDPOINT }}
|
run: podman login -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_TOKEN }} ${{ env.REGISTRY_ENDPOINT }}
|
||||||
- name: Set image metadata
|
- name: Set image metadata
|
||||||
id: image-metadata
|
id: image-metadata
|
||||||
run: |
|
run: |
|
||||||
echo "image-tag=$(./script/get-tag.sh)" >> $GITHUB_OUTPUT
|
echo "image-tag=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
echo "full-image-name=${{ matrix.image-name }}:$(./script/get-tag.sh)" >> $GITHUB_OUTPUT
|
echo "full-image-name=debian-12.6-slim:$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: ./script/build-image.sh ${{ matrix.image-name }} ${{ steps.image-metadata.outputs.image-tag }}
|
run: python ./build_image.py ${{ steps.image-metadata.outputs.full-image-name }} ./images/debian-12.6-slim/Dockerfile
|
||||||
- name: Tag image as latest
|
- name: Tag image as latest
|
||||||
run: podman tag ${{ steps.image-metadata.outputs.full-image-name }} ${{ matrix.image-name }}:latest
|
run: podman tag ${{ steps.image-metadata.outputs.full-image-name }} debian-12.6-slim:latest
|
||||||
- name: List images
|
- name: List images
|
||||||
run: podman image ls
|
run: podman image ls
|
||||||
- name: Push tagged image to registry
|
- name: Push tagged image to registry
|
||||||
|
if: ${{ github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
podman push ${{ steps.image-metadata.outputs.full-image-name }} ${{ env.REGISTRY_ENDPOINT }}/forge-runners/${{ steps.image-metadata.outputs.full-image-name }}
|
podman push ${{ steps.image-metadata.outputs.full-image-name }} ${{ env.REGISTRY_ENDPOINT }}/forge-runners/${{ steps.image-metadata.outputs.full-image-name }}
|
||||||
podman push ${{ steps.image-metadata.outputs.full-image-name }} ${{ env.REGISTRY_ENDPOINT }}/forge-runners/${{ matrix.image-name }}:latest
|
podman push ${{ steps.image-metadata.outputs.full-image-name }} ${{ env.REGISTRY_ENDPOINT }}/forge-runners/debian-12.6-slim:latest
|
||||||
|
post-run:
|
||||||
|
runs-on: imagefactory-latest
|
||||||
|
needs: [build-runner]
|
||||||
|
steps:
|
||||||
|
- uses: https://forge.karnov.club/marc/push-status-to-discord-action@main
|
||||||
|
if: ${{success()}}
|
||||||
|
with:
|
||||||
|
webhook-url: ${{secrets.DISCORD_WEBHOOK_URL}}
|
||||||
|
status: "Success"
|
||||||
|
variant: "success"
|
||||||
|
- uses: https://forge.karnov.club/marc/push-status-to-discord-action@main
|
||||||
|
if: ${{failure()}}
|
||||||
|
with:
|
||||||
|
webhook-url: ${{secrets.DISCORD_WEBHOOK_URL}}
|
||||||
|
status: "Failure"
|
||||||
|
variant: "failure"
|
||||||
|
|
14
README.md
14
README.md
|
@ -1,3 +1,15 @@
|
||||||
# runner-images
|
# runner-images
|
||||||
|
|
||||||
Image factory for Forgejo action runners
|
Image factory for Forgejo Action runners
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Images can be build locally if needed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python build_image.py <image-name> <Dockerfile path>
|
||||||
|
```
|
||||||
|
|
||||||
|
CI will also build images when a tag of the format `v*` is pushed. The images built by CI are tagged as `:latest` and pushed to the registry at the run.
|
||||||
|
|
||||||
|
If CI workflows are triggered manually (i.e. via `workflow_dispatch`), then the image push is skipped.
|
||||||
|
|
95
build_image.py
Normal file
95
build_image.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
"""
|
||||||
|
Builds a container image with the provided image name and tag.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python build_image.py <image-name> <tag> [<image-path>]
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import pathlib
|
||||||
|
import logging
|
||||||
|
import typing
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
logger = logging.getLogger("build-image")
|
||||||
|
|
||||||
|
def get_tag(is_ci: bool) -> str:
|
||||||
|
"""
|
||||||
|
Gets an image tag composed of the short sha of the current commit
|
||||||
|
and, depending on the is_ci flag, a "-dev" suffix.
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
"git rev-parse --short HEAD", shell=True, capture_output=True, check=True
|
||||||
|
)
|
||||||
|
|
||||||
|
sha = re.sub(r"\n", "", str(result.stdout.decode('utf-8')))
|
||||||
|
|
||||||
|
if not is_ci:
|
||||||
|
return f"{sha}-dev"
|
||||||
|
|
||||||
|
return sha
|
||||||
|
|
||||||
|
|
||||||
|
def build_image(image_name: str, tag: str, image_path: typing.Optional[pathlib.Path]):
|
||||||
|
"""
|
||||||
|
Calls Podman to build the container image defined at image_path, which defaults to
|
||||||
|
the current directory.
|
||||||
|
|
||||||
|
The built image is named and tagged using image_name and tag.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if image_path is None:
|
||||||
|
image_path = pathlib.Path("./Dockerfile")
|
||||||
|
|
||||||
|
cwd = image_path.parent
|
||||||
|
image_path = image_path.relative_to(cwd)
|
||||||
|
|
||||||
|
subprocess.run(
|
||||||
|
f"podman build --no-cache -t {image_name}:{tag} -f {str(image_path)}",
|
||||||
|
shell=True,
|
||||||
|
check=True,
|
||||||
|
cwd=cwd,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run(args: list[str]):
|
||||||
|
"""
|
||||||
|
CLI entrypoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(args) < 1:
|
||||||
|
raise ValueError(
|
||||||
|
"There should be at least one argument. "
|
||||||
|
"Correct usage: python build_image.py <image-name:tag> [image-path]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(args) > 2:
|
||||||
|
raise ValueError(
|
||||||
|
"Unrecognized arguments. "
|
||||||
|
"Correct usage: python build_image.py <image-name:tag> [image-path]"
|
||||||
|
)
|
||||||
|
|
||||||
|
tagged_image_name = args[0]
|
||||||
|
image_name_parts = tagged_image_name.split(":")
|
||||||
|
|
||||||
|
name = image_name_parts[0]
|
||||||
|
tag = (
|
||||||
|
image_name_parts[1]
|
||||||
|
if len(image_name_parts) == 2
|
||||||
|
else get_tag(bool(os.environ.get("CI", False)))
|
||||||
|
)
|
||||||
|
|
||||||
|
image_path = args[1] if len(args) == 2 else None
|
||||||
|
|
||||||
|
build_image(name, tag, pathlib.Path(image_path))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
run(sys.argv[1:])
|
||||||
|
except Exception as e: # pylint: disable=broad-exception-caught
|
||||||
|
logger.error(e)
|
||||||
|
exit(1)
|
31
images/debian-12.6-slim/Dockerfile
Normal file
31
images/debian-12.6-slim/Dockerfile
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
FROM debian:12.6-slim as skeleton
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV TZ Etc/UTC
|
||||||
|
|
||||||
|
RUN apt update && \
|
||||||
|
apt upgrade -y && \
|
||||||
|
apt install -y \
|
||||||
|
curl \
|
||||||
|
unzip \
|
||||||
|
podman \
|
||||||
|
jq \
|
||||||
|
git \
|
||||||
|
xz-utils \
|
||||||
|
ca-certificates \
|
||||||
|
nodejs \
|
||||||
|
npm \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
pipx \
|
||||||
|
fuse-overlayfs \
|
||||||
|
--no-install-recommends \
|
||||||
|
--autoremove && \
|
||||||
|
apt-get clean
|
||||||
|
|
||||||
|
COPY ./files/registries.conf /etc/containers/registries.conf
|
||||||
|
COPY ./files/storage.conf /etc/containers/storage.conf
|
||||||
|
|
||||||
|
FROM skeleton as runner
|
||||||
|
|
||||||
|
WORKDIR /runner
|
|
@ -1,3 +1,5 @@
|
||||||
|
unqualified-search-registries = ["docker.io"]
|
||||||
|
|
||||||
[[registry]]
|
[[registry]]
|
||||||
insecure = true
|
insecure = true
|
||||||
location = "host.containers.internal:5000"
|
location = "host.containers.internal:5000"
|
68
images/debian-12.6-slim/files/storage.conf
Normal file
68
images/debian-12.6-slim/files/storage.conf
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
[storage]
|
||||||
|
driver = "overlay"
|
||||||
|
runroot = "/run/containers/storage"
|
||||||
|
graphroot = "/var/lib/containers/storage"
|
||||||
|
|
||||||
|
[storage.options.overlay]
|
||||||
|
# ignore_chown_errors can be set to allow a non privileged user running with
|
||||||
|
# a single UID within a user namespace to run containers. The user can pull
|
||||||
|
# and use any image even those with multiple uids. Note multiple UIDs will be
|
||||||
|
# squashed down to the default uid in the container. These images will have no
|
||||||
|
# separation between the users in the container. Only supported for the overlay
|
||||||
|
# and vfs drivers.
|
||||||
|
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||||
|
#ignore_chown_errors = "false"
|
||||||
|
|
||||||
|
# Inodes is used to set a maximum inodes of the container image.
|
||||||
|
# inodes = ""
|
||||||
|
|
||||||
|
# Path to an helper program to use for mounting the file system instead of mounting it
|
||||||
|
# directly.
|
||||||
|
mount_program = "/usr/bin/fuse-overlayfs"
|
||||||
|
|
||||||
|
# mountopt specifies comma separated list of extra mount options
|
||||||
|
mountopt = "nodev"
|
||||||
|
|
||||||
|
# Set to skip a PRIVATE bind mount on the storage home directory.
|
||||||
|
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||||
|
# skip_mount_home = "false"
|
||||||
|
|
||||||
|
# Set to use composefs to mount data layers with overlay.
|
||||||
|
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||||
|
# use_composefs = "false"
|
||||||
|
|
||||||
|
# Size is used to set a maximum size of the container image.
|
||||||
|
# size = ""
|
||||||
|
|
||||||
|
# ForceMask specifies the permissions mask that is used for new files and
|
||||||
|
# directories.
|
||||||
|
#
|
||||||
|
# The values "shared" and "private" are accepted.
|
||||||
|
# Octal permission masks are also accepted.
|
||||||
|
#
|
||||||
|
# "": No value specified.
|
||||||
|
# All files/directories, get set with the permissions identified within the
|
||||||
|
# image.
|
||||||
|
# "private": it is equivalent to 0700.
|
||||||
|
# All files/directories get set with 0700 permissions. The owner has rwx
|
||||||
|
# access to the files. No other users on the system can access the files.
|
||||||
|
# This setting could be used with networked based homedirs.
|
||||||
|
# "shared": it is equivalent to 0755.
|
||||||
|
# The owner has rwx access to the files and everyone else can read, access
|
||||||
|
# and execute them. This setting is useful for sharing containers storage
|
||||||
|
# with other users. For instance have a storage owned by root but shared
|
||||||
|
# to rootless users as an additional store.
|
||||||
|
# NOTE: All files within the image are made readable and executable by any
|
||||||
|
# user on the system. Even /etc/shadow within your image is now readable by
|
||||||
|
# any user.
|
||||||
|
#
|
||||||
|
# OCTAL: Users can experiment with other OCTAL Permissions.
|
||||||
|
#
|
||||||
|
# Note: The force_mask Flag is an experimental feature, it could change in the
|
||||||
|
# future. When "force_mask" is set the original permission mask is stored in
|
||||||
|
# the "user.containers.override_stat" xattr and the "mount_program" option must
|
||||||
|
# be specified. Mount programs like "/usr/bin/fuse-overlayfs" present the
|
||||||
|
# extended attribute permissions to processes within containers rather than the
|
||||||
|
# "force_mask" permissions.
|
||||||
|
#
|
||||||
|
# force_mask = ""
|
|
@ -1,33 +0,0 @@
|
||||||
FROM ubuntu:22.04 as skeleton
|
|
||||||
|
|
||||||
ENV NODE_VERSION="20.12.2"
|
|
||||||
|
|
||||||
RUN apt update && \
|
|
||||||
apt upgrade -y && \
|
|
||||||
apt install -y \
|
|
||||||
curl \
|
|
||||||
podman \
|
|
||||||
jq \
|
|
||||||
git \
|
|
||||||
xz-utils \
|
|
||||||
ca-certificates \
|
|
||||||
unzip \
|
|
||||||
--no-install-recommends \
|
|
||||||
--autoremove
|
|
||||||
|
|
||||||
FROM skeleton as build
|
|
||||||
|
|
||||||
WORKDIR tmp
|
|
||||||
|
|
||||||
RUN curl https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz \
|
|
||||||
--output /tmp/node-v$NODE_VERSION-linux-x64.tar.xz && \
|
|
||||||
tar -xf /tmp/node-v$NODE_VERSION-linux-x64.tar.xz
|
|
||||||
|
|
||||||
FROM skeleton as runner
|
|
||||||
|
|
||||||
WORKDIR /runner
|
|
||||||
|
|
||||||
COPY --from=build /tmp/node-v$NODE_VERSION-linux-x64/bin/* /bin/
|
|
||||||
COPY --from=build /tmp/node-v$NODE_VERSION-linux-x64/lib/* /lib/
|
|
||||||
|
|
||||||
COPY ./files/registries.conf /etc/containers/registries.conf
|
|
|
@ -1,19 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
image_name=$1
|
|
||||||
image_tag=$2
|
|
||||||
|
|
||||||
if [[ -z $image_name ]]; then
|
|
||||||
echo "An image name must be provided."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z $image_tag ]]; then
|
|
||||||
echo "An image tag must be provided."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
(
|
|
||||||
cd "images/$image_name"
|
|
||||||
podman build -t "$image_name:$image_tag" -f ./Dockerfile
|
|
||||||
) || exit 1
|
|
|
@ -1,12 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
has_changes=$(git status --short)
|
|
||||||
head_sha=$(git rev-parse --short HEAD)
|
|
||||||
|
|
||||||
tag=$head_sha
|
|
||||||
|
|
||||||
if [[ -n $has_changes ]]; then
|
|
||||||
tag="$tag-dev"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$tag"
|
|
Loading…
Reference in a new issue