diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fa3b59b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,71 @@ +# This image is the base image for all s2i configurable container images. +FROM registry.fedoraproject.org/fedora:32 + +ENV SUMMARY="Base image which allows using of source-to-image." \ + DESCRIPTION="The s2i-core image provides any images layered on top of it \ +with all the tools needed to use source-to-image functionality while keeping \ +the image size as small as possible." \ + NAME=s2i-core \ + VERSION=0 \ + ARCH=x86_64 + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="s2i core" \ + io.openshift.s2i.scripts-url=image:///usr/libexec/s2i \ + io.s2i.scripts-url=image:///usr/libexec/s2i \ + com.redhat.component="$NAME" \ + name="$FGC/$NAME" \ + version="$VERSION" \ + usage="This image is supposed to be used as a base image for other images that support source-to-image" \ + maintainer="SoftwareCollections.org " + +ENV \ + # DEPRECATED: Use above LABEL instead, because this will be removed in future versions. + STI_SCRIPTS_URL=image:///usr/libexec/s2i \ + # Path to be used in other layers to place s2i scripts into + STI_SCRIPTS_PATH=/usr/libexec/s2i \ + APP_ROOT=/opt/app-root \ + # The $HOME is not set by default, but some applications needs this variable + HOME=/opt/app-root/src \ + PATH=/opt/app-root/src/bin:/opt/app-root/bin:$PATH \ + PLATFORM="fedora" + +# This is the list of basic dependencies that all language container image can +# consume. +# Also setup the 'openshift' user that is used for the build execution and for the +# application runtime execution. +# TODO: Use better UID and GID values +RUN INSTALL_PKGS="bsdtar \ + findutils \ + gettext \ + glibc-langpack-en \ + groff-base \ + rsync \ + tar \ + unzip" && \ + mkdir -p ${HOME}/.pki/nssdb && \ + chown -R 1001:0 ${HOME}/.pki && \ + dnf install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + dnf clean all -y + +# Copy extra files to the image. +COPY ./root/ / + +# Create a platform-python symlink if it does not exist already +RUN [ -e /usr/libexec/platform-python ] || ln -s /usr/bin/python3 /usr/libexec/platform-python + +# Directory with the sources is set as the working directory so all STI scripts +# can execute relative to this path. +WORKDIR ${HOME} + +ENTRYPOINT ["container-entrypoint"] +CMD ["base-usage"] + +# Reset permissions of modified directories and add default user +RUN rpm-file-permissions && \ + useradd -u 1001 -r -g 0 -d ${HOME} -s /sbin/nologin \ + -c "Default Application User" default && \ + chown -R 1001:0 ${APP_ROOT} diff --git a/Dockerfile.fedora b/Dockerfile.fedora new file mode 120000 index 0000000..1d1fe94 --- /dev/null +++ b/Dockerfile.fedora @@ -0,0 +1 @@ +Dockerfile \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..14a94b0 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +OpenShift base images (core variant) +======================================== + +This repository contains Dockerfiles for images which can be used as base images +to add support for [source-to-image](https://github.com/openshift/source-to-image) +without installing several development libraries. + + +Description +-------------------------------- +OpenShift S2I images use [Software Collections](https://www.softwarecollections.org/en/) +packages to provide the latest versions of various software. +The SCL packages are released more frequently than the RHEL or CentOS systems, +which are unlikely to change for several years. +We rely on RHEL and CentOS for base images, on the other hand, +because those are stable, supported, and secure platforms. + +Normally, SCL requires manual operation to enable the collection you want to use. +This is burdensome and can be prone to error. +The OpenShift S2I approach is to set Bash environment variables that +serve to automatically enable the desired collection: + +* `BASH_ENV`: enables the collection for all non-interactive Bash sessions +* `ENV`: enables the collection for all invocations of `/bin/sh` +* `PROMPT_COMMAND`: enables the collection in interactive shell + +Two examples: +* If you specify `BASH_ENV`, then all your `#!/bin/bash` scripts +do not need to call `scl enable`. +* If you specify `PROMPT_COMMAND`, then on execution of the +`podman exec ... /bin/bash` command, the collection will be automatically enabled. + +*Note*: +Executables in Software Collections packages (e.g., `ruby`) +are not directly in a directory named in the `PATH` environment variable. +This means that you cannot do: + + $ podman exec ... ruby + +but must instead do: + + $ podman exec ... /bin/bash -c ruby + +The `/bin/bash -c`, along with the setting the appropriate environment variable, +ensures the correct `ruby` executable is found and invoked. + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments + +Usage +------------------------ +Choose either the CentOS7 or RHEL7 base image: +* **RHEL7 base image** + +To build a RHEL7 based image, you need to build it on properly subscribed RHEL machine. + +``` +$ git clone --recursive https://github.com/sclorg/s2i-base-container.git +$ cd s2i-base-container +$ make build VERSIONS=core TARGET=rhel7 +``` + +* **CentOS7 base image** + +This image is available on Quay.io. To download it run: + +```console +podman pull quay.io/centos7/s2i-core-centos7 +``` + +To build a Base image from scratch run: + +``` +$ git clone --recursive https://github.com/sclorg/s2i-base-container.git +$ cd s2i-base-container +$ make build VERSIONS=core +``` + +**Notice: By omitting the `VERSION` parameter, the build/test action will be performed +on all provided versions of s2i image.** + + +See also +-------- +Dockerfile and other sources are available on https://github.com/sclorg/s2i-base-container. +In that repository you also can find another variants of S2I Base Dockerfiles. +The Dockerfile for CentOS is called Dockerfile, the Dockerfile for RHEL7 is called Dockerfile.rhel7, +the Dockerfile for RHEL8 is called Dockerfile.rhel8 and the Dockerfile for Fedora is Dockerfile.fedora. diff --git a/bot-cfg.yml b/bot-cfg.yml new file mode 100644 index 0000000..a453e3f --- /dev/null +++ b/bot-cfg.yml @@ -0,0 +1,26 @@ +version: "1" + +betka: + # is betka enabled for this repository + # optional - defaults to false + enabled: true + + # optional + notifications: + email_addresses: [phracek@redhat.com] + + # Specify if master branch in upstream repository is synced + master_checker: true + # Should pull requests be synced? + # optional + pr_checker: false + # Either 'upstream_branch_name' or 'upstream_git_path' has to be specified + # Branch name which is used for sync + upstream_branch_name: master + # Path to directory with dockerfile withing upstream repository + upstream_git_path: "core" + # Github comment message to enforce sync of a pull request + # required if pr_checker is true otherwise optional + pr_comment_message: "[test]" + # optional + image_url: quay.io/rhscl/cwt-generator diff --git a/core b/core new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/core @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/dead.package b/dead.package deleted file mode 100644 index 7290702..0000000 --- a/dead.package +++ /dev/null @@ -1 +0,0 @@ -container sources not used for building fedora containers anymore diff --git a/help.md b/help.md new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/help.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/root/help.1 b/root/help.1 new file mode 100644 index 0000000..bc055a8 --- /dev/null +++ b/root/help.1 @@ -0,0 +1,128 @@ +.TH OpenShift base images (core variant) +.PP +This repository contains Dockerfiles for images which can be used as base images +to add support for source\-to\-image +\[la]https://github.com/openshift/source-to-image\[ra] +without installing several development libraries. + +.SH Description +.PP +OpenShift S2I images use Software Collections +\[la]https://www.softwarecollections.org/en/\[ra] +packages to provide the latest versions of various software. +The SCL packages are released more frequently than the RHEL or CentOS systems, +which are unlikely to change for several years. +We rely on RHEL and CentOS for base images, on the other hand, +because those are stable, supported, and secure platforms. + +.PP +Normally, SCL requires manual operation to enable the collection you want to use. +This is burdensome and can be prone to error. +The OpenShift S2I approach is to set Bash environment variables that +serve to automatically enable the desired collection: +.IP \(bu 2 +\fB\fCBASH\_ENV\fR: enables the collection for all non\-interactive Bash sessions +.IP \(bu 2 +\fB\fCENV\fR: enables the collection for all invocations of \fB\fC/bin/sh\fR +.IP \(bu 2 +\fB\fCPROMPT\_COMMAND\fR: enables the collection in interactive shell + +.PP +Two examples: +* If you specify \fB\fCBASH\_ENV\fR, then all your \fB\fC#!/bin/bash\fR scripts +do not need to call \fB\fCscl enable\fR\&. +* If you specify \fB\fCPROMPT\_COMMAND\fR, then on execution of the +\fB\fCpodman exec ... /bin/bash\fR command, the collection will be automatically enabled. + +.PP +\fINote\fP: +Executables in Software Collections packages (e.g., \fB\fCruby\fR) +are not directly in a directory named in the \fB\fCPATH\fR environment variable. +This means that you cannot do: + +.PP +.RS + +.nf +$ podman exec ... ruby + +.fi +.RE + +.PP +but must instead do: + +.PP +.RS + +.nf +$ podman exec ... /bin/bash \-c ruby + +.fi +.RE + +.PP +The \fB\fC/bin/bash \-c\fR, along with the setting the appropriate environment variable, +ensures the correct \fB\fCruby\fR executable is found and invoked. + +.PP +Note: while the examples in this README are calling \fB\fCpodman\fR, you can replace any such calls by \fB\fCdocker\fR with the same arguments + +.SH Usage +.PP +Choose either the CentOS7 or RHEL7 base image: +* \fBRHEL7 base image\fP + +.PP +To build a RHEL7 based image, you need to build it on properly subscribed RHEL machine. + +.PP +.RS + +.nf +$ git clone \-\-recursive https://github.com/sclorg/s2i\-base\-container.git +$ cd s2i\-base\-container +$ make build VERSIONS=core TARGET=rhel7 + +.fi +.RE +.IP \(bu 2 +\fBCentOS7 base image\fP + +.PP +This image is available on DockerHub. To download it run: + +.PP +.RS + +.nf +podman pull sclorg/s2i\-core\-centos7 + +.fi +.RE + +.PP +To build a Base image from scratch run: + +.PP +.RS + +.nf +$ git clone \-\-recursive https://github.com/sclorg/s2i\-base\-container.git +$ cd s2i\-base\-container +$ make build VERSIONS=core + +.fi +.RE + +.PP +\fBNotice: By omitting the \fB\fCVERSION\fR parameter, the build/test action will be performed +on all provided versions of s2i image.\fP + +.SH See also +.PP +Dockerfile and other sources are available on +\[la]https://github.com/sclorg/s2i-base-container\[ra]\&. +In that repository you also can find another variants of S2I Base Dockerfiles. +The Dockerfile for CentOS is called Dockerfile, the Dockerfile for RHEL7 is called Dockerfile.rhel7, +the Dockerfile for RHEL8 is called Dockerfile.rhel8 and the Dockerfile for Fedora is Dockerfile.fedora. diff --git a/root/opt/app-root/etc/scl_enable b/root/opt/app-root/etc/scl_enable new file mode 100644 index 0000000..8fca598 --- /dev/null +++ b/root/opt/app-root/etc/scl_enable @@ -0,0 +1,2 @@ +# This file contains automatic SCL enablement. +unset BASH_ENV PROMPT_COMMAND ENV diff --git a/root/usr/bin/base-usage b/root/usr/bin/base-usage new file mode 100755 index 0000000..154ccc4 --- /dev/null +++ b/root/usr/bin/base-usage @@ -0,0 +1,24 @@ +#!/bin/sh -e + +cat <= 92233720368547: + env_vars["NO_MEMORY_LIMIT"] = "true" + + for key, value in env_vars.items(): + print("{0}={1}".format(key, value)) diff --git a/root/usr/bin/container-entrypoint b/root/usr/bin/container-entrypoint new file mode 100755 index 0000000..9d8ad4d --- /dev/null +++ b/root/usr/bin/container-entrypoint @@ -0,0 +1,2 @@ +#!/bin/bash +exec "$@" diff --git a/root/usr/bin/fix-permissions b/root/usr/bin/fix-permissions new file mode 100755 index 0000000..ddd33ac --- /dev/null +++ b/root/usr/bin/fix-permissions @@ -0,0 +1,27 @@ +#!/bin/sh + +# Allow this script to fail without failing a build +set +e + +SYMLINK_OPT=${2:--L} + +# Fix permissions on the given directory or file to allow group read/write of +# regular files and execute of directories. + +[ $(id -u) -ne 0 ] && CHECK_OWNER=" -uid $(id -u)" + +# If argument does not exist, script will still exit with 0, +# but at least we'll see something went wrong in the log +if ! [ -e "$1" ] ; then + echo "ERROR: File or directory $1 does not exist." >&2 + # We still want to end successfully + exit 0 +fi + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -gid 0 -exec chgrp 0 {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -perm -g+rw -exec chmod g+rw {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -perm /u+x -a \! -perm /g+x -exec chmod g+x {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -type d \! -perm /g+x -exec chmod g+x {} + + +# Always end successfully +exit 0 diff --git a/root/usr/bin/prepare-yum-repositories b/root/usr/bin/prepare-yum-repositories new file mode 100755 index 0000000..3b28993 --- /dev/null +++ b/root/usr/bin/prepare-yum-repositories @@ -0,0 +1,59 @@ +#!/bin/bash + +# This script is used to prepare yum repositories, that are given as arguments. +# It is no-op if user also mounts the repo file(s) into the container during +# image build. This can be done by one of those commands: +# +# docker build -v /some/repo/file:/etc/yum.repos.d/sclorg_custom.repo +# docker build -v /some/repo/directory:/etc/yum.repos.d +# make CUSTOM_REPO=/some/repo/file/or/directory +# +# The last one works for projects where we have Makefile with the +# container-common-scripts support. + +set -ex + +# DEFAULT_REPOS and SKIP_REPOS_{ENABLE,DISABLE} are intentionally undocumented, +# but might be used if we need to change this behaviour. +# Once we realize there are real use cases for using those variables, we should +# document them properly. +DEFAULT_REPOS=${DEFAULT_REPOS:-"rhel-7-server-rpms rhel-7-server-optional-rpms"} +SKIP_REPOS_ENABLE=${SKIP_REPOS_ENABLE:-false} +SKIP_REPOS_DISABLE=${SKIP_REPOS_DISABLE:-false} + +function is_subscribed() { + for f in /run/secrets/etc-pki-entitlement/*.pem ; do + [ -e "$f" ] && return 0 + break + done + return 1 +} + +# DEBUGGING CASE! Mostly for 'make CUSTOM_REPO=/some/file/or/dir'. +test ! -f /etc/yum.repos.d/sclorg_custom.repo && \ +! mountpoint /etc/yum.repos.d \ + || exit 0 + +# install yum-utils for yum-config-manager +yum install -y yum-utils + +if [ "$SKIP_REPOS_DISABLE" = false ] && is_subscribed; then + # Disable only repos that might come from subscribed host, because there + # might be other repos provided by user or build system + + disable_repos= + # Lines look like: "Repo-id : dist-tag-override/x86_64" + while IFS=' /' read -r _ _ repo_id _; do + case $repo_id in rhel-*) + disable_repos+=" $repo_id" ;; + esac + done <<<"$(yum repolist -v 2>/dev/null | grep Repo-id)" + + if test -n "$disable_repos"; then + yum-config-manager --disable $disable_repos &> /dev/null + fi +fi + +if [ ${SKIP_REPOS_ENABLE} = false ] && [ -n "${DEFAULT_REPOS}" -o $# -gt 0 ] ; then + yum-config-manager --enable ${DEFAULT_REPOS} "$@" +fi diff --git a/root/usr/bin/rpm-file-permissions b/root/usr/bin/rpm-file-permissions new file mode 100755 index 0000000..8be1fb0 --- /dev/null +++ b/root/usr/bin/rpm-file-permissions @@ -0,0 +1,21 @@ +#!/bin/sh + +CHECK_DIRS="/ /opt /etc /usr /usr/bin /usr/lib /usr/lib64 /usr/share /usr/libexec" + +rpm_format="[%{FILESTATES:fstate} %7{FILEMODES:octal} %{FILENAMES:shescape}\n]" + +rpm -q --qf "$rpm_format" filesystem | while read line +do + eval "set -- $line" + + case $1 in + normal) ;; + *) continue ;; + esac + + case " $CHECK_DIRS " in + *" $3 "*) + chmod "${2: -4}" "$3" + ;; + esac +done diff --git a/test/run b/test/run new file mode 100755 index 0000000..6878bf3 --- /dev/null +++ b/test/run @@ -0,0 +1,90 @@ +#!/bin/bash +# +# The 'run' performs a simple test that verifies that S2I image. +# The main focus is that the image prints out the base-usage properly. +# +# IMAGE_NAME specifies a name of the candidate image used for testing. +# The image has to be available before this script is executed. +# +test -n "${IMAGE_NAME-}" || { echo 'make sure $IMAGE_NAME is defined'; exit 1; } + +test_docker_run_usage() { + echo "Testing 'docker run' usage..." + docker run --rm ${IMAGE_NAME} &>/dev/null +} + +test_cgroup_limits() { + echo "Testing 'cgroup limits' usage..." + if [ $EUID -eq 0 ]; then + echo " The test is running as root, all tests for cgroup limits will be run" + + # check memory limited (only works when running as root) + echo " Testing 'limited memory' usage..." + if ! ( eval $(docker run --rm --memory=512M ${IMAGE_NAME} /usr/bin/cgroup-limits) + echo "MEMORY_LIMIT_IN_BYTES=$MEMORY_LIMIT_IN_BYTES" + [ "$MEMORY_LIMIT_IN_BYTES" -eq 536870912 ] ); then + echo "MEMORY_LIMIT_IN_BYTES not set to 536870912." + return 1 + fi + + # check cores number (only works when running as root) + echo " Testing 'NUMBER_OF_CORES' value..." + if ! ( eval $(docker run --rm ${IMAGE_NAME} /usr/bin/cgroup-limits) + echo "NUMBER_OF_CORES=$NUMBER_OF_CORES" + [ "$NUMBER_OF_CORES" -gt 0 ] ); then + echo "NUMBER_OF_CORES not set." + return 1 + fi + + # check cores number (only works when running as root) + echo " Testing 'NUMBER_OF_CORES' value with --cpuset-cpus=0..." + if ! ( eval $(docker run --rm --cpuset-cpus=0 ${IMAGE_NAME} /usr/bin/cgroup-limits) + echo "NUMBER_OF_CORES=$NUMBER_OF_CORES" + [ "$NUMBER_OF_CORES" -eq 1 ] ); then + echo "NUMBER_OF_CORES not set to 1 when set --cpuset-cpus=0." + return 1 + fi + + else + echo " The test is running as non-root, some tests for cgroup limits are skipped" + fi + + # check NO_MEMORY_LIMIT when no limit is set + echo " Testing 'NO_MEMORY_LIMIT' value..." + if ! ( eval $(docker run --rm ${IMAGE_NAME} /usr/bin/cgroup-limits) + echo "NO_MEMORY_LIMIT=$NO_MEMORY_LIMIT" + [ "$NO_MEMORY_LIMIT" == 'true' ] ); then + echo "NO_MEMORY_LIMIT not set to true." + return 1 + fi + + # check default memory in bytes + echo " Testing 'MEMORY_LIMIT_IN_BYTES' value..." + if ! ( eval $(docker run --rm ${IMAGE_NAME} /usr/bin/cgroup-limits) + echo "MEMORY_LIMIT_IN_BYTES=$MEMORY_LIMIT_IN_BYTES" + # This value can be different, but it must be very big (comparing to 10TB) + [ "$MEMORY_LIMIT_IN_BYTES" -gt 10000000000000 ] ); then + echo "MEMORY_LIMIT_IN_BYTES not greater than 10000000000000." + return 1 + fi +} + +check_result() { + local result="$1" + if [[ "$result" != "0" ]]; then + echo "S2I image '${IMAGE_NAME}' test FAILED (exit code: ${result})" + exit $result + fi +} + +# Verify the 'usage' script is working properly when running the base image with 'docker run ...' +test_docker_run_usage +check_result $? + +# Verify the cgroup-limits script works as expected +test_cgroup_limits +check_result $? + +echo "Tests for '${IMAGE_NAME}' succeeded." + +# vim: set tabstop=2:shiftwidth=2:expandtab: