aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2019-09-05 14:13:32 +0200
committerGerd Hoffmann <kraxel@redhat.com>2019-09-05 14:13:32 +0200
commite9f965f775f5839f092b2578d5d861745ff69863 (patch)
tree8f7648bb33b15c77372e71ca2241c73155217b4e
downloads2i-jekyll-e9f965f775f5839f092b2578d5d861745ff69863.tar.gz
initial state, created by s2i create
-rw-r--r--Dockerfile38
-rw-r--r--Makefile10
-rw-r--r--README.md82
-rwxr-xr-xs2i/bin/assemble26
-rwxr-xr-xs2i/bin/run10
-rwxr-xr-xs2i/bin/save-artifacts10
-rwxr-xr-xs2i/bin/usage12
-rwxr-xr-xtest/run155
-rw-r--r--test/test-app/index.html10
9 files changed, 353 insertions, 0 deletions
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..4f0c00b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,38 @@
+# kraxel/s2i-jekyll
+FROM openshift/base-centos7
+
+# TODO: Put the maintainer name in the image metadata
+# LABEL maintainer="Your Name <your@email.com>"
+
+# TODO: Rename the builder environment variable to inform users about application you provide them
+# ENV BUILDER_VERSION 1.0
+
+# TODO: Set labels used in OpenShift to describe the builder image
+#LABEL io.k8s.description="Platform for building xyz" \
+# io.k8s.display-name="builder x.y.z" \
+# io.openshift.expose-services="8080:http" \
+# io.openshift.tags="builder,x.y.z,etc."
+
+# TODO: Install required packages here:
+# RUN yum install -y ... && yum clean all -y
+RUN yum install -y rubygems && yum clean all -y
+RUN gem install asdf
+
+# TODO (optional): Copy the builder files into /opt/app-root
+# COPY ./<builder_folder>/ /opt/app-root/
+
+# TODO: Copy the S2I scripts to /usr/libexec/s2i, since openshift/base-centos7 image
+# sets io.openshift.s2i.scripts-url label that way, or update that label
+COPY ./s2i/bin/ /usr/libexec/s2i
+
+# TODO: Drop the root user and make the content of /opt/app-root owned by user 1001
+# RUN chown -R 1001:1001 /opt/app-root
+
+# This default user is created in the openshift/base-centos7 image
+USER 1001
+
+# TODO: Set the default port for applications built using this image
+# EXPOSE 8080
+
+# TODO: Set the default CMD for the image
+# CMD ["/usr/libexec/s2i/usage"]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..201939a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+IMAGE_NAME = kraxel/s2i-jekyll
+
+.PHONY: build
+build:
+ docker build -t $(IMAGE_NAME) .
+
+.PHONY: test
+test:
+ docker build -t $(IMAGE_NAME)-candidate .
+ IMAGE_NAME=$(IMAGE_NAME)-candidate test/run
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8ebe17b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,82 @@
+
+# Creating a basic S2I builder image
+
+## Getting started
+
+### Files and Directories
+| File | Required? | Description |
+|------------------------|-----------|--------------------------------------------------------------|
+| Dockerfile | Yes | Defines the base builder image |
+| s2i/bin/assemble | Yes | Script that builds the application |
+| s2i/bin/usage | No | Script that prints the usage of the builder |
+| s2i/bin/run | Yes | Script that runs the application |
+| s2i/bin/save-artifacts | No | Script for incremental builds that saves the built artifacts |
+| test/run | No | Test script for the builder image |
+| test/test-app | Yes | Test application source code |
+
+#### Dockerfile
+Create a *Dockerfile* that installs all of the necessary tools and libraries that are needed to build and run our application. This file will also handle copying the s2i scripts into the created image.
+
+#### S2I scripts
+
+##### assemble
+Create an *assemble* script that will build our application, e.g.:
+- build python modules
+- bundle install ruby gems
+- setup application specific configuration
+
+The script can also specify a way to restore any saved artifacts from the previous image.
+
+##### run
+Create a *run* script that will start the application.
+
+##### save-artifacts (optional)
+Create a *save-artifacts* script which allows a new build to reuse content from a previous version of the application image.
+
+##### usage (optional)
+Create a *usage* script that will print out instructions on how to use the image.
+
+##### Make the scripts executable
+Make sure that all of the scripts are executable by running *chmod +x s2i/bin/**
+
+#### Create the builder image
+The following command will create a builder image named kraxel/s2i-jekyll based on the Dockerfile that was created previously.
+```
+docker build -t kraxel/s2i-jekyll .
+```
+The builder image can also be created by using the *make* command since a *Makefile* is included.
+
+Once the image has finished building, the command *s2i usage kraxel/s2i-jekyll* will print out the help info that was defined in the *usage* script.
+
+#### Testing the builder image
+The builder image can be tested using the following commands:
+```
+docker build -t kraxel/s2i-jekyll-candidate .
+IMAGE_NAME=kraxel/s2i-jekyll-candidate test/run
+```
+The builder image can also be tested by using the *make test* command since a *Makefile* is included.
+
+#### Creating the application image
+The application image combines the builder image with your applications source code, which is served using whatever application is installed via the *Dockerfile*, compiled using the *assemble* script, and run using the *run* script.
+The following command will create the application image:
+```
+s2i build test/test-app kraxel/s2i-jekyll kraxel/s2i-jekyll-app
+---> Building and installing application from source...
+```
+Using the logic defined in the *assemble* script, s2i will now create an application image using the builder image as a base and including the source code from the test/test-app directory.
+
+#### Running the application image
+Running the application image is as simple as invoking the docker run command:
+```
+docker run -d -p 8080:8080 kraxel/s2i-jekyll-app
+```
+The application, which consists of a simple static web page, should now be accessible at [http://localhost:8080](http://localhost:8080).
+
+#### Using the saved artifacts script
+Rebuilding the application using the saved artifacts can be accomplished using the following command:
+```
+s2i build --incremental=true test/test-app nginx-centos7 nginx-app
+---> Restoring build artifacts...
+---> Building and installing application from source...
+```
+This will run the *save-artifacts* script which includes the custom code to backup the currently running application source, rebuild the application image, and then re-deploy the previously saved source using the *assemble* script.
diff --git a/s2i/bin/assemble b/s2i/bin/assemble
new file mode 100755
index 0000000..918395e
--- /dev/null
+++ b/s2i/bin/assemble
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+#
+# S2I assemble script for the 'kraxel/s2i-jekyll' image.
+# The 'assemble' script builds your application source so that it is ready to run.
+#
+# For more information refer to the documentation:
+# https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
+#
+
+# If the 'kraxel/s2i-jekyll' assemble script is executed with the '-h' flag, print the usage.
+if [[ "$1" == "-h" ]]; then
+ exec /usr/libexec/s2i/usage
+fi
+
+# Restore artifacts from the previous build (if they exist).
+#
+if [ "$(ls /tmp/artifacts/ 2>/dev/null)" ]; then
+ echo "---> Restoring build artifacts..."
+ mv /tmp/artifacts/. ./
+fi
+
+echo "---> Installing application source..."
+cp -Rf /tmp/src/. ./
+
+echo "---> Building application from source..."
+# TODO: Add build steps for your application, eg npm install, bundle install, pip install, etc.
diff --git a/s2i/bin/run b/s2i/bin/run
new file mode 100755
index 0000000..f726e00
--- /dev/null
+++ b/s2i/bin/run
@@ -0,0 +1,10 @@
+#!/bin/bash -e
+#
+# S2I run script for the 'kraxel/s2i-jekyll' image.
+# The run script executes the server that runs your application.
+#
+# For more information see the documentation:
+# https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
+#
+
+exec asdf -p 8080
diff --git a/s2i/bin/save-artifacts b/s2i/bin/save-artifacts
new file mode 100755
index 0000000..d7b1239
--- /dev/null
+++ b/s2i/bin/save-artifacts
@@ -0,0 +1,10 @@
+#!/bin/sh -e
+#
+# S2I save-artifacts script for the 'kraxel/s2i-jekyll' image.
+# The save-artifacts script streams a tar archive to standard output.
+# The archive contains the files and folders you want to re-use in the next build.
+#
+# For more information see the documentation:
+# https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
+#
+# tar cf - <list of files and folders>
diff --git a/s2i/bin/usage b/s2i/bin/usage
new file mode 100755
index 0000000..831f690
--- /dev/null
+++ b/s2i/bin/usage
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+cat <<EOF
+This is the kraxel/s2i-jekyll S2I image:
+To use it, install S2I: https://github.com/openshift/source-to-image
+
+Sample invocation:
+
+s2i build <source code path/URL> kraxel/s2i-jekyll <application image>
+
+You can then run the resulting image via:
+docker run <application image>
+EOF
diff --git a/test/run b/test/run
new file mode 100755
index 0000000..7e6ed7a
--- /dev/null
+++ b/test/run
@@ -0,0 +1,155 @@
+#!/bin/bash
+#
+# The 'run' performs a simple test that verifies the S2I image.
+# The main focus here is to exercise the S2I scripts.
+#
+# For more information see the documentation:
+# https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
+#
+# IMAGE_NAME specifies a name of the candidate image used for testing.
+# The image has to be available before this script is executed.
+#
+IMAGE_NAME=${IMAGE_NAME-kraxel/s2i-jekyll-candidate}
+
+# Determining system utility executables (darwin compatibility check)
+READLINK_EXEC="readlink -zf"
+MKTEMP_EXEC="mktemp --suffix=.cid"
+if [[ "$OSTYPE" =~ 'darwin' ]]; then
+ READLINK_EXEC="readlink"
+ MKTEMP_EXEC="mktemp"
+ ! type -a "greadlink" &>"/dev/null" || READLINK_EXEC="greadlink"
+ ! type -a "gmktemp" &>"/dev/null" || MKTEMP_EXEC="gmktemp"
+fi
+
+_dir="$(dirname "${BASH_SOURCE[0]}")"
+test_dir="$($READLINK_EXEC ${_dir} || echo ${_dir})"
+image_dir=$($READLINK_EXEC ${test_dir}/.. || echo ${test_dir}/..)
+scripts_url="${image_dir}/.s2i/bin"
+cid_file=$($MKTEMP_EXEC -u)
+
+# Since we built the candidate image locally, we don't want S2I to attempt to pull
+# it from Docker hub
+s2i_args="--pull-policy=never --loglevel=2"
+
+# Port the image exposes service to be tested
+test_port=8080
+
+image_exists() {
+ docker inspect $1 &>/dev/null
+}
+
+container_exists() {
+ image_exists $(cat $cid_file)
+}
+
+container_ip() {
+ docker inspect --format="{{(index .NetworkSettings.Ports \"$test_port/tcp\" 0).HostIp }}" $(cat $cid_file) | sed 's/0.0.0.0/localhost/'
+}
+
+container_port() {
+ docker inspect --format="{{(index .NetworkSettings.Ports \"$test_port/tcp\" 0).HostPort }}" "$(cat "${cid_file}")"
+}
+
+run_s2i_build() {
+ s2i build --incremental=true ${s2i_args} ${test_dir}/test-app ${IMAGE_NAME} ${IMAGE_NAME}-testapp
+}
+
+prepare() {
+ if ! image_exists ${IMAGE_NAME}; then
+ echo "ERROR: The image ${IMAGE_NAME} must exist before this script is executed."
+ exit 1
+ fi
+ # s2i build requires the application is a valid 'Git' repository
+ pushd ${test_dir}/test-app >/dev/null
+ git init
+ git config user.email "build@localhost" && git config user.name "builder"
+ git add -A && git commit -m "Sample commit"
+ popd >/dev/null
+ run_s2i_build
+}
+
+run_test_application() {
+ docker run --rm --cidfile=${cid_file} -p ${test_port}:${test_port} ${IMAGE_NAME}-testapp
+}
+
+cleanup() {
+ if [ -f $cid_file ]; then
+ if container_exists; then
+ docker stop $(cat $cid_file)
+ fi
+ fi
+ if image_exists ${IMAGE_NAME}-testapp; then
+ docker rmi ${IMAGE_NAME}-testapp
+ fi
+}
+
+check_result() {
+ local result="$1"
+ if [[ "$result" != "0" ]]; then
+ echo "S2I image '${IMAGE_NAME}' test FAILED (exit code: ${result})"
+ cleanup
+ exit $result
+ fi
+}
+
+wait_for_cid() {
+ local max_attempts=10
+ local sleep_time=1
+ local attempt=1
+ local result=1
+ while [ $attempt -le $max_attempts ]; do
+ [ -f $cid_file ] && break
+ echo "Waiting for container to start..."
+ attempt=$(( $attempt + 1 ))
+ sleep $sleep_time
+ done
+}
+
+test_usage() {
+ echo "Testing 's2i usage'..."
+ s2i usage ${s2i_args} ${IMAGE_NAME} &>/dev/null
+}
+
+test_connection() {
+ echo "Testing HTTP connection (http://$(container_ip):$(container_port))"
+ local max_attempts=10
+ local sleep_time=1
+ local attempt=1
+ local result=1
+ while [ $attempt -le $max_attempts ]; do
+ echo "Sending GET request to http://$(container_ip):$(container_port)/"
+ response_code=$(curl -s -w %{http_code} -o /dev/null http://$(container_ip):$(container_port)/)
+ status=$?
+ if [ $status -eq 0 ]; then
+ if [ $response_code -eq 200 ]; then
+ result=0
+ fi
+ break
+ fi
+ attempt=$(( $attempt + 1 ))
+ sleep $sleep_time
+ done
+ return $result
+}
+
+# Build the application image twice to ensure the 'save-artifacts' and
+# 'restore-artifacts' scripts are working properly
+prepare
+run_s2i_build
+check_result $?
+
+# Verify the 'usage' script is working properly
+test_usage
+check_result $?
+
+# Verify that the HTTP connection can be established to test application container
+run_test_application &
+
+# Wait for the container to write its CID file
+wait_for_cid
+
+test_connection
+check_result $?
+
+cleanup
+
diff --git a/test/test-app/index.html b/test/test-app/index.html
new file mode 100644
index 0000000..7bca10c
--- /dev/null
+++ b/test/test-app/index.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Hello World!</title>
+ </head>
+ <body>
+ <h1>Hello World!</h1>
+ </body>
+</html>
+ \ No newline at end of file